#! /usr/bin/python
#
"""
Problem: Please write a function in Python that takes an 8x8 grid of letters and a list of words and returns the longest word from the list (ignoring case) that can be produced from the grid using the following procedure:
1. Start at any position in the grid, and use the letter at that position as the first letter in the candidate word.
2. Move to a position in the grid that would be a valid move for a knight in a game of chess, and add the letter at that position to the candidate word.
3. Repeat step 2 any number of times.
For example, if the list of words is ["algol", "fortran", "simula"] and the grid is:
1 2 3 4 5 6 7 8
1 Q W E R T N U I
2 O P A A D F G H
3 T K L Z X C V B
4 N M R W F R T Y
5 U I O P A S D F
6 G H J O L Z X C
7 V B N M Q W E R
8 T Y U I O P A S
...then the longest word from the list that can be produced using the rules is “fortran”, by starting at the ‘F’ at position (5, 4), and moving to (4, 6), then (3, 4), (1, 3), back to (3, 4) and then (4, 2) and finally (6,1). Again, note that the match is case-insensitive, and that grid positions can be reused.
Create a list of words found in Shakespeare’s early comedy, Love’s Labour’s Lost (text available at http://s...content-available-to-author-only...t.edu/lll/full.html). Make sure to remove punctuation and ignore case when generating the word list. What is the output of your function using this word list on the grid below?
H A R R Y H A T
P A T T E R N S
Q I H A C I Q T
L F U N U R X B
B W D I L A T V
O S S Y N A C K
Q W O P M T C P
K I P A C K E T
"""
class Game:
def __init__ ( self ) :
self .width = 8
self .height = 8
self .Matrix = [ [ 'A' for x in range ( self .width ) ] for y in range ( self .height ) ]
"""
creates
1 2 3 4 5 6 7 8
1 Q W E R T N U I
2 O P A A D F G H
3 T K L Z X C V B
4 N M R W F R T Y
5 U I O P A S D F
6 G H J O L Z X C
7 V B N M Q W E R
8 T Y U I O P A S
"""
self .Matrix [ 0 ] [ 0 ] = 'Q'
self .Matrix [ 0 ] [ 1 ] = 'W'
self .Matrix [ 0 ] [ 2 ] = 'E'
self .Matrix [ 0 ] [ 3 ] = 'R'
self .Matrix [ 0 ] [ 4 ] = 'T'
self .Matrix [ 0 ] [ 5 ] = 'N'
self .Matrix [ 0 ] [ 6 ] = 'U'
self .Matrix [ 0 ] [ 7 ] = 'I'
self .Matrix [ 1 ] [ 0 ] = 'O'
self .Matrix [ 1 ] [ 1 ] = 'P'
self .Matrix [ 1 ] [ 2 ] = 'A'
self .Matrix [ 1 ] [ 3 ] = 'A'
self .Matrix [ 1 ] [ 4 ] = 'D'
self .Matrix [ 1 ] [ 5 ] = 'F'
self .Matrix [ 1 ] [ 6 ] = 'G'
self .Matrix [ 1 ] [ 7 ] = 'H'
self .Matrix [ 2 ] [ 0 ] = 'T'
self .Matrix [ 2 ] [ 1 ] = 'K'
self .Matrix [ 2 ] [ 2 ] = 'L'
self .Matrix [ 2 ] [ 3 ] = 'Z'
self .Matrix [ 2 ] [ 4 ] = 'X'
self .Matrix [ 2 ] [ 5 ] = 'C'
self .Matrix [ 2 ] [ 6 ] = 'V'
self .Matrix [ 2 ] [ 7 ] = 'B'
self .Matrix [ 3 ] [ 0 ] = 'N'
self .Matrix [ 3 ] [ 1 ] = 'M'
self .Matrix [ 3 ] [ 2 ] = 'R'
self .Matrix [ 3 ] [ 3 ] = 'W'
self .Matrix [ 3 ] [ 4 ] = 'F'
self .Matrix [ 3 ] [ 5 ] = 'R'
self .Matrix [ 3 ] [ 6 ] = 'T'
self .Matrix [ 3 ] [ 7 ] = 'Y'
self .Matrix [ 4 ] [ 0 ] = 'U'
self .Matrix [ 4 ] [ 1 ] = 'I'
self .Matrix [ 4 ] [ 2 ] = 'O'
self .Matrix [ 4 ] [ 3 ] = 'P'
self .Matrix [ 4 ] [ 4 ] = 'A'
self .Matrix [ 4 ] [ 5 ] = 'S'
self .Matrix [ 4 ] [ 6 ] = 'D'
self .Matrix [ 4 ] [ 7 ] = 'F'
self .Matrix [ 5 ] [ 0 ] = 'G'
self .Matrix [ 5 ] [ 1 ] = 'H'
self .Matrix [ 5 ] [ 2 ] = 'J'
self .Matrix [ 5 ] [ 3 ] = 'O'
self .Matrix [ 5 ] [ 4 ] = 'L'
self .Matrix [ 5 ] [ 5 ] = 'Z'
self .Matrix [ 5 ] [ 6 ] = 'X'
self .Matrix [ 5 ] [ 7 ] = 'C'
self .Matrix [ 6 ] [ 0 ] = 'V'
self .Matrix [ 6 ] [ 1 ] = 'B'
self .Matrix [ 6 ] [ 2 ] = 'N'
self .Matrix [ 6 ] [ 3 ] = 'M'
self .Matrix [ 6 ] [ 4 ] = 'Q'
self .Matrix [ 6 ] [ 5 ] = 'W'
self .Matrix [ 6 ] [ 6 ] = 'E'
self .Matrix [ 6 ] [ 7 ] = 'R'
self .Matrix [ 7 ] [ 0 ] = 'T'
self .Matrix [ 7 ] [ 1 ] = 'Y'
self .Matrix [ 7 ] [ 2 ] = 'U'
self .Matrix [ 7 ] [ 3 ] = 'I'
self .Matrix [ 7 ] [ 4 ] = 'O'
self .Matrix [ 7 ] [ 5 ] = 'P'
self .Matrix [ 7 ] [ 6 ] = 'A'
self .Matrix [ 7 ] [ 7 ] = 'S'
def isInMatrix( self , i, j) :
return ( ( 0 <= i) and ( i< self .height ) and ( 0 <= j) and ( j< self .width ) )
def FindX( self , X) :
locations = [ ]
for i in range ( self .height ) :
for j in range ( self .width ) :
if self .Matrix [ i] [ j] == X:
locations.append ( ( i, j) )
return locations
def IsWordInMatrix( self , word, i, j, pos, path) :
id = [ -2 , -1 , 1 , 2 , 2 , 1 , -1 , -2 ]
jd = [ -1 , -2 , -2 , -1 , 1 , 2 , 2 , 1 ]
if pos + 1 == len ( word) :
return True
path.append ( ( i, j) )
#print('path='+repr(path)+'&X='+repr(word[pos]))
X = word[ pos + 1 ]
for k in range ( len ( id ) ) :
ni = i + id [ k]
nj = j + jd[ k]
location = ( ni, nj)
#path.append(location)
#print('path='+repr(path)+'&X='+repr(word[pos]))
if ( self .isInMatrix ( ni, nj) and self .Matrix [ ni] [ nj] == X ) : #and ((ni, nj) not in path)):
if ( self .IsWordInMatrix ( word, ni, nj, pos + 1 , path) ) :
return True
#path.remove(location)
return False
def HasWord( self , word) :
locations = self .FindX ( word[ 0 ] )
for tup in locations:
path = [ ]
pos = 0
if self .IsWordInMatrix ( word, tup[ 0 ] , tup[ 1 ] , pos, path) :
return True
return False
def test1( self ) :
g = Game( )
#print(repr(g.Matrix))
locations = g.FindX ( 'F' )
print ( repr ( locations) )
for tup in locations:
path = [ ]
pos = 0
#path.append(tup)
if g.IsWordInMatrix ( "FORTRAN" , tup[ 0 ] , tup[ 1 ] , pos, path) :
print ( repr ( path) )
else :
print ( "NOT FOUND" )
#path.remove(tup)
def test2( self ) :
g = Game( )
"""
0 1 2 3 4 5 6 7
0 H E N R Y H A T
1 P A T T E R N S
2 Q I H A C I Q T
3 L F U N U R X B
4 B W D I L A T V
5 O S S Y N A C K
6 Q W O P M T C P
7 K I P A C K E T
"""
g.Matrix [ 0 ] [ 0 ] = 'H'
g.Matrix [ 0 ] [ 1 ] = 'E'
g.Matrix [ 0 ] [ 2 ] = 'N'
g.Matrix [ 0 ] [ 3 ] = 'R'
g.Matrix [ 0 ] [ 4 ] = 'Y'
g.Matrix [ 0 ] [ 5 ] = 'H'
g.Matrix [ 0 ] [ 6 ] = 'A'
g.Matrix [ 0 ] [ 7 ] = 'T'
g.Matrix [ 1 ] [ 0 ] = 'P'
g.Matrix [ 1 ] [ 1 ] = 'A'
g.Matrix [ 1 ] [ 2 ] = 'T'
g.Matrix [ 1 ] [ 3 ] = 'T'
g.Matrix [ 1 ] [ 4 ] = 'E'
g.Matrix [ 1 ] [ 5 ] = 'R'
g.Matrix [ 1 ] [ 6 ] = 'N'
g.Matrix [ 1 ] [ 7 ] = 'S'
g.Matrix [ 2 ] [ 0 ] = 'Q'
g.Matrix [ 2 ] [ 1 ] = 'I'
g.Matrix [ 2 ] [ 2 ] = 'H'
g.Matrix [ 2 ] [ 3 ] = 'A'
g.Matrix [ 2 ] [ 4 ] = 'C'
g.Matrix [ 2 ] [ 5 ] = 'I'
g.Matrix [ 2 ] [ 6 ] = 'Q'
g.Matrix [ 2 ] [ 7 ] = 'T'
g.Matrix [ 3 ] [ 0 ] = 'L'
g.Matrix [ 3 ] [ 1 ] = 'F'
g.Matrix [ 3 ] [ 2 ] = 'U'
g.Matrix [ 3 ] [ 3 ] = 'N'
g.Matrix [ 3 ] [ 4 ] = 'U'
g.Matrix [ 3 ] [ 5 ] = 'R'
g.Matrix [ 3 ] [ 6 ] = 'X'
g.Matrix [ 3 ] [ 7 ] = 'B'
g.Matrix [ 4 ] [ 0 ] = 'B'
g.Matrix [ 4 ] [ 1 ] = 'W'
g.Matrix [ 4 ] [ 2 ] = 'D'
g.Matrix [ 4 ] [ 3 ] = 'I'
g.Matrix [ 4 ] [ 4 ] = 'L'
g.Matrix [ 4 ] [ 5 ] = 'A'
g.Matrix [ 4 ] [ 6 ] = 'T'
g.Matrix [ 4 ] [ 7 ] = 'V'
g.Matrix [ 5 ] [ 0 ] = 'O'
g.Matrix [ 5 ] [ 1 ] = 'S'
g.Matrix [ 5 ] [ 2 ] = 'S'
g.Matrix [ 5 ] [ 3 ] = 'Y'
g.Matrix [ 5 ] [ 4 ] = 'N'
g.Matrix [ 5 ] [ 5 ] = 'A'
g.Matrix [ 5 ] [ 6 ] = 'C'
g.Matrix [ 5 ] [ 7 ] = 'K'
g.Matrix [ 6 ] [ 0 ] = 'Q'
g.Matrix [ 6 ] [ 1 ] = 'W'
g.Matrix [ 6 ] [ 2 ] = 'O'
g.Matrix [ 6 ] [ 3 ] = 'P'
g.Matrix [ 6 ] [ 4 ] = 'M'
g.Matrix [ 6 ] [ 5 ] = 'T'
g.Matrix [ 6 ] [ 6 ] = 'C'
g.Matrix [ 6 ] [ 7 ] = 'P'
g.Matrix [ 7 ] [ 0 ] = 'K'
g.Matrix [ 7 ] [ 1 ] = 'I'
g.Matrix [ 7 ] [ 2 ] = 'P'
g.Matrix [ 7 ] [ 3 ] = 'A'
g.Matrix [ 7 ] [ 4 ] = 'C'
g.Matrix [ 7 ] [ 5 ] = 'K'
g.Matrix [ 7 ] [ 6 ] = 'E'
g.Matrix [ 7 ] [ 7 ] = 'T'
words = self .wordlist ( ) #["TOO", "TIN", "POT"]
output = [ ]
for word in words:
if g.HasWord ( word) :
output += [ word]
return output
pass
def extract( self , url) :
import urllib
from bs4 import BeautifulSoup
html = urllib .urlopen ( url) .read ( )
soup = BeautifulSoup( html, "html.parser" )
# kill all script and style elements
for script in soup( [ "script" , "style" ] ) :
script.extract ( ) # rip it out
# get text
text = soup.get_text ( )
# break into lines and remove leading and trailing space on each
lines = ( line.strip ( ) for line in text.splitlines ( ) )
# break multi-headlines into a line each
chunks = ( phrase.strip ( ) for line in lines for phrase in line.split ( " " ) )
# drop blank lines
text = '\n ' .join ( chunk for chunk in chunks if chunk )
return text
def wordlist( self ) :
url = 'http://s...content-available-to-author-only...t.edu/lll/full.html'
text = self .extract ( url)
text = text.replace ( "," , "" )
text = text.replace ( "?" , "" )
text = text.replace ( "!" , "" )
text = text.replace ( "'" , "" )
text = text.replace ( "`" , "" )
text = text.replace ( "." , "" )
text = text.replace ( "-" , "" )
text = text.replace ( "-" , "" )
text = text.replace ( ":" , "" )
text = text.replace ( "|" , "" )
text = text.replace ( "[" , "" )
text = text.replace ( "]" , "" )
text = text.upper ( )
words = [ str ( x) for x in text.split ( ) ]
words = list ( set ( words) )
return words
g = Game( )
print ( repr ( g.test2 ( ) ) )
"""
g = Game()
locations = g.FindX('F')
print(repr(locations))
for tup in locations:
path = []
pos = 0
if g.IsWordInMatrix("FORTRAN", tup[0], tup[1], pos, path):
print(repr(path))
else:
print("NOT FOUND")
[(1, 5), (3, 4), (4, 7)]
path=[(1, 5)]&X='F'
NOT FOUND
path=[(3, 4)]&X='F'
path=[(3, 4), (4, 2)]&X='O'
path=[(3, 4), (4, 2), (5, 3)]&X='O'
path=[(3, 4), (4, 2), (5, 3), (3, 2)]&X='R'
path=[(3, 4), (4, 2), (5, 3), (3, 2), (2, 0)]&X='T'
path=[(3, 4), (4, 2), (5, 3), (3, 2), (2, 0), (3, 2)]&X='R'
path=[(3, 4), (4, 2), (5, 3), (3, 2), (2, 0), (3, 2), (4, 4)]&X='A'
path=[(3, 4), (4, 2), (5, 3), (3, 2), (2, 0), (3, 2), (4, 4), (1, 3)]&X='A'
[(3, 4), (4, 2), (5, 3), (3, 2), (2, 0), (3, 2), (4, 4), (1, 3)]
path=[(4, 7)]&X='F'
NOT FOUND
"""
"""
['MAY', 'NINTH', 'MAN', 'SIN', 'NON', 'NOW', 'V', 'FARE', 'LA', 'ONT', 'A', 'HEAT', 'CLUB', 'NINE', 'SAW', 'APT', 'TRIM', 'B', 'CAME', 'WONT', 'WHERE', 'SUCH', 'BUY', 'BUT', 'NAME', 'D', 'ON', 'WHICH', 'LAUS', 'OF', 'HE', 'SUB', 'RENT', 'FAR', 'EAT', 'PAP', 'LUTE', 'ME', 'INT', 'MI', 'INS', 'ANON', 'ERE', 'WOOD', 'RARE', 'DINE', 'ANNE', 'NIT', 'IMP', 'DO', 'MIRE', 'WAS', 'DID', 'AIR', 'I', 'IS', 'IT', 'IN', 'IF', 'NAY', 'E', 'SNAKE', 'NO', 'NE', 'WHEN', 'ISBUT', 'FIRE', 'SIR', 'SIT', 'RICH', 'KNOWN', 'CAP', 'CAN', 'MAKE', 'L', 'WOO', 'ET', 'ARE', 'BA', 'OFT', 'THIN', 'SAT', 'AND', 'ANT', 'HER', 'OWN', 'FAN', 'T', 'DART', 'DARE', 'FA', 'O', 'ACT', 'EQUAL', 'TH', 'TI', 'TE', 'AD', 'AM', 'AN', 'AS', 'AT', 'AY', 'MANS', 'LAY', 'KNOW', 'LINEN', 'HIS', 'HID', 'HIM', 'HIT', 'TRUTH', 'WON', 'HERE', 'BID', 'FIFTY', 'CONTINENT', 'FIFTH', 'THINE', 'WANT', 'RE', 'ART', 'ACUTE', 'TIS', 'UT', 'US', 'U', 'CUT', 'DAN', 'DAY', 'PLAY']
"""
IyEgL3Vzci9iaW4vcHl0aG9uCiMKIiIiClByb2JsZW06IFBsZWFzZSB3cml0ZSBhIGZ1bmN0aW9uIGluIFB5dGhvbiB0aGF0IHRha2VzIGFuIDh4OCBncmlkIG9mIGxldHRlcnMgYW5kIGEgbGlzdCBvZiB3b3JkcyBhbmQgcmV0dXJucyB0aGUgbG9uZ2VzdCB3b3JkIGZyb20gdGhlIGxpc3QgKGlnbm9yaW5nIGNhc2UpIHRoYXQgY2FuIGJlIHByb2R1Y2VkIGZyb20gdGhlIGdyaWQgdXNpbmcgdGhlIGZvbGxvd2luZyBwcm9jZWR1cmU6CgoxLglTdGFydCBhdCBhbnkgcG9zaXRpb24gaW4gdGhlIGdyaWQsIGFuZCB1c2UgdGhlIGxldHRlciBhdCB0aGF0IHBvc2l0aW9uIGFzIHRoZSBmaXJzdCBsZXR0ZXIgaW4gdGhlIGNhbmRpZGF0ZSB3b3JkLgoyLglNb3ZlIHRvIGEgcG9zaXRpb24gaW4gdGhlIGdyaWQgdGhhdCB3b3VsZCBiZSBhIHZhbGlkIG1vdmUgZm9yIGEga25pZ2h0IGluIGEgZ2FtZSBvZiBjaGVzcywgYW5kIGFkZCB0aGUgbGV0dGVyIGF0IHRoYXQgcG9zaXRpb24gdG8gdGhlIGNhbmRpZGF0ZSB3b3JkLgozLglSZXBlYXQgc3RlcCAyIGFueSBudW1iZXIgb2YgdGltZXMuCgpGb3IgZXhhbXBsZSwgaWYgdGhlIGxpc3Qgb2Ygd29yZHMgaXMgWyJhbGdvbCIsICJmb3J0cmFuIiwgInNpbXVsYSJdIGFuZCB0aGUgZ3JpZCBpczoKCiAgMSAyIDMgNCA1IDYgNyA4CjEgUSBXIEUgUiBUIE4gVSBJCjIgTyBQIEEgQSBEIEYgRyBICjMgVCBLIEwgWiBYIEMgViBCCjQgTiBNIFIgVyBGIFIgVCBZCjUgVSBJIE8gUCBBIFMgRCBGCjYgRyBIIEogTyBMIFogWCBDCjcgViBCIE4gTSBRIFcgRSBSCjggVCBZIFUgSSBPIFAgQSBTCgouLi50aGVuIHRoZSBsb25nZXN0IHdvcmQgZnJvbSB0aGUgbGlzdCB0aGF0IGNhbiBiZSBwcm9kdWNlZCB1c2luZyB0aGUgcnVsZXMgaXMg4oCcZm9ydHJhbuKAnSwgYnkgc3RhcnRpbmcgYXQgdGhlIOKAmEbigJkgYXQgcG9zaXRpb24gKDUsIDQpLCBhbmQgbW92aW5nIHRvICg0LCA2KSwgdGhlbiAoMywgNCksICgxLCAzKSwgYmFjayB0byAoMywgNCkgYW5kIHRoZW4gKDQsIDIpIGFuZCBmaW5hbGx5ICg2LDEpLiBBZ2Fpbiwgbm90ZSB0aGF0IHRoZSBtYXRjaCBpcyBjYXNlLWluc2Vuc2l0aXZlLCBhbmQgdGhhdCBncmlkIHBvc2l0aW9ucyBjYW4gYmUgcmV1c2VkLgoKQ3JlYXRlIGEgbGlzdCBvZiB3b3JkcyBmb3VuZCBpbiBTaGFrZXNwZWFyZeKAmXMgZWFybHkgY29tZWR5LCBMb3Zl4oCZcyBMYWJvdXLigJlzIExvc3QgKHRleHQgYXZhaWxhYmxlIGF0IGh0dHA6Ly9zLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi50LmVkdS9sbGwvZnVsbC5odG1sKS4gTWFrZSBzdXJlIHRvIHJlbW92ZSBwdW5jdHVhdGlvbiBhbmQgaWdub3JlIGNhc2Ugd2hlbiBnZW5lcmF0aW5nIHRoZSB3b3JkIGxpc3QuIFdoYXQgaXMgdGhlIG91dHB1dCBvZiB5b3VyIGZ1bmN0aW9uIHVzaW5nIHRoaXMgd29yZCBsaXN0IG9uIHRoZSBncmlkIGJlbG93PwoKICAgICAgICBIIEEgUiBSIFkgSCBBIFQKICAgICAgICBQIEEgVCBUIEUgUiBOIFMKICAgICAgICBRIEkgSCBBIEMgSSBRIFQKICAgICAgICBMIEYgVSBOIFUgUiBYIEIKICAgICAgICBCIFcgRCBJIEwgQSBUIFYKICAgICAgICBPIFMgUyBZIE4gQSBDIEsKICAgICAgICBRIFcgTyBQIE0gVCBDIFAKICAgICAgICBLIEkgUCBBIEMgSyBFIFQKCgoiIiIKY2xhc3MgR2FtZToKICBkZWYgX19pbml0X18oc2VsZik6CiAgICBzZWxmLndpZHRoID0gOAogICAgc2VsZi5oZWlnaHQgPSA4CiAgICBzZWxmLk1hdHJpeCA9IFtbJ0EnIGZvciB4IGluIHJhbmdlKHNlbGYud2lkdGgpXSBmb3IgeSBpbiByYW5nZShzZWxmLmhlaWdodCldCiAgICAiIiIKICAgIGNyZWF0ZXMKICAgICAgMSAyIDMgNCA1IDYgNyA4CiAgICAxIFEgVyBFIFIgVCBOIFUgSQogICAgMiBPIFAgQSBBIEQgRiBHIEgKICAgIDMgVCBLIEwgWiBYIEMgViBCCiAgICA0IE4gTSBSIFcgRiBSIFQgWQogICAgNSBVIEkgTyBQIEEgUyBEIEYKICAgIDYgRyBIIEogTyBMIFogWCBDCiAgICA3IFYgQiBOIE0gUSBXIEUgUgogICAgOCBUIFkgVSBJIE8gUCBBIFMKICAgICIiIgogICAgc2VsZi5NYXRyaXhbMF1bMF09ICdRJwogICAgc2VsZi5NYXRyaXhbMF1bMV09ICdXJwogICAgc2VsZi5NYXRyaXhbMF1bMl09ICdFJwogICAgc2VsZi5NYXRyaXhbMF1bM109ICdSJwogICAgc2VsZi5NYXRyaXhbMF1bNF09ICdUJwogICAgc2VsZi5NYXRyaXhbMF1bNV09ICdOJwogICAgc2VsZi5NYXRyaXhbMF1bNl09ICdVJwogICAgc2VsZi5NYXRyaXhbMF1bN109ICdJJwoKICAgIHNlbGYuTWF0cml4WzFdWzBdPSAnTycKICAgIHNlbGYuTWF0cml4WzFdWzFdPSAnUCcKICAgIHNlbGYuTWF0cml4WzFdWzJdPSAnQScKICAgIHNlbGYuTWF0cml4WzFdWzNdPSAnQScKICAgIHNlbGYuTWF0cml4WzFdWzRdPSAnRCcKICAgIHNlbGYuTWF0cml4WzFdWzVdPSAnRicKICAgIHNlbGYuTWF0cml4WzFdWzZdPSAnRycKICAgIHNlbGYuTWF0cml4WzFdWzddPSAnSCcKCiAgICBzZWxmLk1hdHJpeFsyXVswXT0gJ1QnCiAgICBzZWxmLk1hdHJpeFsyXVsxXT0gJ0snCiAgICBzZWxmLk1hdHJpeFsyXVsyXT0gJ0wnCiAgICBzZWxmLk1hdHJpeFsyXVszXT0gJ1onCiAgICBzZWxmLk1hdHJpeFsyXVs0XT0gJ1gnCiAgICBzZWxmLk1hdHJpeFsyXVs1XT0gJ0MnCiAgICBzZWxmLk1hdHJpeFsyXVs2XT0gJ1YnCiAgICBzZWxmLk1hdHJpeFsyXVs3XT0gJ0InCgogICAgc2VsZi5NYXRyaXhbM11bMF09ICdOJwogICAgc2VsZi5NYXRyaXhbM11bMV09ICdNJwogICAgc2VsZi5NYXRyaXhbM11bMl09ICdSJwogICAgc2VsZi5NYXRyaXhbM11bM109ICdXJwogICAgc2VsZi5NYXRyaXhbM11bNF09ICdGJwogICAgc2VsZi5NYXRyaXhbM11bNV09ICdSJwogICAgc2VsZi5NYXRyaXhbM11bNl09ICdUJwogICAgc2VsZi5NYXRyaXhbM11bN109ICdZJwoKICAgIHNlbGYuTWF0cml4WzRdWzBdPSAnVScKICAgIHNlbGYuTWF0cml4WzRdWzFdPSAnSScKICAgIHNlbGYuTWF0cml4WzRdWzJdPSAnTycKICAgIHNlbGYuTWF0cml4WzRdWzNdPSAnUCcKICAgIHNlbGYuTWF0cml4WzRdWzRdPSAnQScKICAgIHNlbGYuTWF0cml4WzRdWzVdPSAnUycKICAgIHNlbGYuTWF0cml4WzRdWzZdPSAnRCcKICAgIHNlbGYuTWF0cml4WzRdWzddPSAnRicKCiAgICBzZWxmLk1hdHJpeFs1XVswXT0gJ0cnCiAgICBzZWxmLk1hdHJpeFs1XVsxXT0gJ0gnCiAgICBzZWxmLk1hdHJpeFs1XVsyXT0gJ0onCiAgICBzZWxmLk1hdHJpeFs1XVszXT0gJ08nCiAgICBzZWxmLk1hdHJpeFs1XVs0XT0gJ0wnCiAgICBzZWxmLk1hdHJpeFs1XVs1XT0gJ1onCiAgICBzZWxmLk1hdHJpeFs1XVs2XT0gJ1gnCiAgICBzZWxmLk1hdHJpeFs1XVs3XT0gJ0MnCgogICAgc2VsZi5NYXRyaXhbNl1bMF09ICdWJwogICAgc2VsZi5NYXRyaXhbNl1bMV09ICdCJwogICAgc2VsZi5NYXRyaXhbNl1bMl09ICdOJwogICAgc2VsZi5NYXRyaXhbNl1bM109ICdNJwogICAgc2VsZi5NYXRyaXhbNl1bNF09ICdRJwogICAgc2VsZi5NYXRyaXhbNl1bNV09ICdXJwogICAgc2VsZi5NYXRyaXhbNl1bNl09ICdFJwogICAgc2VsZi5NYXRyaXhbNl1bN109ICdSJwoKICAgIHNlbGYuTWF0cml4WzddWzBdPSAnVCcKICAgIHNlbGYuTWF0cml4WzddWzFdPSAnWScKICAgIHNlbGYuTWF0cml4WzddWzJdPSAnVScKICAgIHNlbGYuTWF0cml4WzddWzNdPSAnSScKICAgIHNlbGYuTWF0cml4WzddWzRdPSAnTycKICAgIHNlbGYuTWF0cml4WzddWzVdPSAnUCcKICAgIHNlbGYuTWF0cml4WzddWzZdPSAnQScKICAgIHNlbGYuTWF0cml4WzddWzddPSAnUycKCiAgZGVmIGlzSW5NYXRyaXgoc2VsZiwgaSxqKToKICAgICAgcmV0dXJuICgoMDw9aSkgYW5kIChpPHNlbGYuaGVpZ2h0KSBhbmQgKDA8PWopIGFuZCAoajxzZWxmLndpZHRoKSkKCiAgZGVmIEZpbmRYKHNlbGYsIFgpOgogICAgICBsb2NhdGlvbnMgPSBbXQogICAgICBmb3IgaSBpbiByYW5nZShzZWxmLmhlaWdodCk6CiAgICAgICAgICBmb3IgaiBpbiByYW5nZShzZWxmLndpZHRoKToKICAgICAgICAgICAgICBpZiBzZWxmLk1hdHJpeFtpXVtqXSA9PSBYOgogICAgICAgICAgICAgICAgIGxvY2F0aW9ucy5hcHBlbmQoKGksaikpCiAgICAgIHJldHVybiBsb2NhdGlvbnMKCgogIGRlZiBJc1dvcmRJbk1hdHJpeChzZWxmLCB3b3JkLCBpLGosIHBvcywgcGF0aCk6CiAgICAgIGlkID0gWyAtMiwgLTEsICAxLCAgMiwgMiwgMSwgLTEsIC0yIF0KICAgICAgamQgPSBbIC0xLCAtMiwgLTIsIC0xLCAxLCAyLCAgMiwgIDEgXQogICAgICBpZiBwb3MgKyAxID09IGxlbih3b3JkKToKICAgICAgICAgcmV0dXJuIFRydWUKICAgICAgcGF0aC5hcHBlbmQoKGksaikpCiAgICAgICNwcmludCgncGF0aD0nK3JlcHIocGF0aCkrJyZYPScrcmVwcih3b3JkW3Bvc10pKQogICAgICBYID0gd29yZFtwb3MgKyAxXQogICAgICBmb3IgayBpbiByYW5nZShsZW4oaWQpKToKICAgICAgICAgbmkgPSBpICsgaWRba10KICAgICAgICAgbmogPSBqICsgamRba10KICAgICAgICAgbG9jYXRpb24gPSAobmksbmopCiAgICAgICAgICNwYXRoLmFwcGVuZChsb2NhdGlvbikKICAgICAgICAgI3ByaW50KCdwYXRoPScrcmVwcihwYXRoKSsnJlg9JytyZXByKHdvcmRbcG9zXSkpCiAgICAgICAgIGlmIChzZWxmLmlzSW5NYXRyaXgobmksIG5qKSBhbmQgc2VsZi5NYXRyaXhbbmldW25qXSA9PSBYICk6ICNhbmQgKChuaSwgbmopIG5vdCBpbiBwYXRoKSk6CiAgICAgICAgICAgICBpZiAoc2VsZi5Jc1dvcmRJbk1hdHJpeCh3b3JkLCBuaSwgbmosIHBvcyArIDEgLCBwYXRoKSk6CiAgICAgICAgICAgICAgICByZXR1cm4gVHJ1ZQogICAgICAgICAjcGF0aC5yZW1vdmUobG9jYXRpb24pCiAgICAgIHJldHVybiBGYWxzZQoKICBkZWYgSGFzV29yZChzZWxmLCB3b3JkKToKICAgICAgbG9jYXRpb25zID0gc2VsZi5GaW5kWCh3b3JkWzBdKQogICAgICBmb3IgdHVwIGluIGxvY2F0aW9uczoKICAgICAgICAgIHBhdGggPSBbXQogICAgICAgICAgcG9zID0gMAogICAgICAgICAgaWYgc2VsZi5Jc1dvcmRJbk1hdHJpeCh3b3JkLCB0dXBbMF0sIHR1cFsxXSwgcG9zLCBwYXRoKToKICAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgIHJldHVybiBGYWxzZQoKICBkZWYgdGVzdDEoc2VsZik6CiAgICAgIGcgPSBHYW1lKCkKICAgICAgI3ByaW50KHJlcHIoZy5NYXRyaXgpKQogICAgICBsb2NhdGlvbnMgPSBnLkZpbmRYKCdGJykKICAgICAgcHJpbnQocmVwcihsb2NhdGlvbnMpKQogICAgICBmb3IgdHVwIGluIGxvY2F0aW9uczoKICAgICAgICAgIHBhdGggPSBbXQogICAgICAgICAgcG9zICA9IDAKICAgICAgICAgICNwYXRoLmFwcGVuZCh0dXApCiAgICAgICAgICBpZiBnLklzV29yZEluTWF0cml4KCJGT1JUUkFOIiwgdHVwWzBdLCB0dXBbMV0sIHBvcywgcGF0aCk6CiAgICAgICAgICAgICBwcmludChyZXByKHBhdGgpKQogICAgICAgICAgZWxzZToKICAgICAgICAgICBwcmludCgiTk9UIEZPVU5EIikKICAgICAgICAgICNwYXRoLnJlbW92ZSh0dXApCgoKICBkZWYgdGVzdDIoc2VsZik6CiAgICAgIGcgPSBHYW1lKCkKICAgICAgIiIiCiAgICAgIDAgMSAyIDMgNCA1IDYgNwogICAgMCBIIEUgTiBSIFkgSCBBIFQKICAgIDEgUCBBIFQgVCBFIFIgTiBTCiAgICAyIFEgSSBIIEEgQyBJIFEgVAogICAgMyBMIEYgVSBOIFUgUiBYIEIKICAgIDQgQiBXIEQgSSBMIEEgVCBWCiAgICA1IE8gUyBTIFkgTiBBIEMgSwogICAgNiBRIFcgTyBQIE0gVCBDIFAKICAgIDcgSyBJIFAgQSBDIEsgRSBUCiAgICAgICIiIgogICAgICBnLk1hdHJpeFswXVswXT0gJ0gnCiAgICAgIGcuTWF0cml4WzBdWzFdPSAnRScKICAgICAgZy5NYXRyaXhbMF1bMl09ICdOJwogICAgICBnLk1hdHJpeFswXVszXT0gJ1InCiAgICAgIGcuTWF0cml4WzBdWzRdPSAnWScKICAgICAgZy5NYXRyaXhbMF1bNV09ICdIJwogICAgICBnLk1hdHJpeFswXVs2XT0gJ0EnCiAgICAgIGcuTWF0cml4WzBdWzddPSAnVCcKCiAgICAgIGcuTWF0cml4WzFdWzBdPSAnUCcKICAgICAgZy5NYXRyaXhbMV1bMV09ICdBJwogICAgICBnLk1hdHJpeFsxXVsyXT0gJ1QnCiAgICAgIGcuTWF0cml4WzFdWzNdPSAnVCcKICAgICAgZy5NYXRyaXhbMV1bNF09ICdFJwogICAgICBnLk1hdHJpeFsxXVs1XT0gJ1InCiAgICAgIGcuTWF0cml4WzFdWzZdPSAnTicKICAgICAgZy5NYXRyaXhbMV1bN109ICdTJwoKICAgICAgZy5NYXRyaXhbMl1bMF09ICdRJwogICAgICBnLk1hdHJpeFsyXVsxXT0gJ0knCiAgICAgIGcuTWF0cml4WzJdWzJdPSAnSCcKICAgICAgZy5NYXRyaXhbMl1bM109ICdBJwogICAgICBnLk1hdHJpeFsyXVs0XT0gJ0MnCiAgICAgIGcuTWF0cml4WzJdWzVdPSAnSScKICAgICAgZy5NYXRyaXhbMl1bNl09ICdRJwogICAgICBnLk1hdHJpeFsyXVs3XT0gJ1QnCgogICAgICBnLk1hdHJpeFszXVswXT0gJ0wnCiAgICAgIGcuTWF0cml4WzNdWzFdPSAnRicKICAgICAgZy5NYXRyaXhbM11bMl09ICdVJwogICAgICBnLk1hdHJpeFszXVszXT0gJ04nCiAgICAgIGcuTWF0cml4WzNdWzRdPSAnVScKICAgICAgZy5NYXRyaXhbM11bNV09ICdSJwogICAgICBnLk1hdHJpeFszXVs2XT0gJ1gnCiAgICAgIGcuTWF0cml4WzNdWzddPSAnQicKCiAgICAgIGcuTWF0cml4WzRdWzBdPSAnQicKICAgICAgZy5NYXRyaXhbNF1bMV09ICdXJwogICAgICBnLk1hdHJpeFs0XVsyXT0gJ0QnCiAgICAgIGcuTWF0cml4WzRdWzNdPSAnSScKICAgICAgZy5NYXRyaXhbNF1bNF09ICdMJwogICAgICBnLk1hdHJpeFs0XVs1XT0gJ0EnCiAgICAgIGcuTWF0cml4WzRdWzZdPSAnVCcKICAgICAgZy5NYXRyaXhbNF1bN109ICdWJwoKICAgICAgZy5NYXRyaXhbNV1bMF09ICdPJwogICAgICBnLk1hdHJpeFs1XVsxXT0gJ1MnCiAgICAgIGcuTWF0cml4WzVdWzJdPSAnUycKICAgICAgZy5NYXRyaXhbNV1bM109ICdZJwogICAgICBnLk1hdHJpeFs1XVs0XT0gJ04nCiAgICAgIGcuTWF0cml4WzVdWzVdPSAnQScKICAgICAgZy5NYXRyaXhbNV1bNl09ICdDJwogICAgICBnLk1hdHJpeFs1XVs3XT0gJ0snCgogICAgICBnLk1hdHJpeFs2XVswXT0gJ1EnCiAgICAgIGcuTWF0cml4WzZdWzFdPSAnVycKICAgICAgZy5NYXRyaXhbNl1bMl09ICdPJwogICAgICBnLk1hdHJpeFs2XVszXT0gJ1AnCiAgICAgIGcuTWF0cml4WzZdWzRdPSAnTScKICAgICAgZy5NYXRyaXhbNl1bNV09ICdUJwogICAgICBnLk1hdHJpeFs2XVs2XT0gJ0MnCiAgICAgIGcuTWF0cml4WzZdWzddPSAnUCcKCiAgICAgIGcuTWF0cml4WzddWzBdPSAnSycKICAgICAgZy5NYXRyaXhbN11bMV09ICdJJwogICAgICBnLk1hdHJpeFs3XVsyXT0gJ1AnCiAgICAgIGcuTWF0cml4WzddWzNdPSAnQScKICAgICAgZy5NYXRyaXhbN11bNF09ICdDJwogICAgICBnLk1hdHJpeFs3XVs1XT0gJ0snCiAgICAgIGcuTWF0cml4WzddWzZdPSAnRScKICAgICAgZy5NYXRyaXhbN11bN109ICdUJwogICAgICB3b3JkcyA9IHNlbGYud29yZGxpc3QoKSAjWyJUT08iLCAiVElOIiwgIlBPVCJdCiAgICAgIG91dHB1dCA9IFtdCiAgICAgIGZvciB3b3JkIGluIHdvcmRzOgogICAgICAgICAgaWYgZy5IYXNXb3JkKHdvcmQpOgogICAgICAgICAgICAgb3V0cHV0ICs9IFt3b3JkXQogICAgICByZXR1cm4gb3V0cHV0CiAgICAgIHBhc3MKCiAgZGVmIGV4dHJhY3Qoc2VsZiwgdXJsKToKICAgICAgaW1wb3J0IHVybGxpYgogICAgICBmcm9tIGJzNCBpbXBvcnQgQmVhdXRpZnVsU291cAoKICAgICAgaHRtbCA9IHVybGxpYi51cmxvcGVuKHVybCkucmVhZCgpCiAgICAgIHNvdXAgPSBCZWF1dGlmdWxTb3VwKGh0bWwsICJodG1sLnBhcnNlciIpCgogICAgICAjIGtpbGwgYWxsIHNjcmlwdCBhbmQgc3R5bGUgZWxlbWVudHMKICAgICAgZm9yIHNjcmlwdCBpbiBzb3VwKFsic2NyaXB0IiwgInN0eWxlIl0pOgogICAgICAgICAgc2NyaXB0LmV4dHJhY3QoKSAgICAjIHJpcCBpdCBvdXQKCiAgICAgICMgZ2V0IHRleHQKICAgICAgdGV4dCA9IHNvdXAuZ2V0X3RleHQoKQoKICAgICAgIyBicmVhayBpbnRvIGxpbmVzIGFuZCByZW1vdmUgbGVhZGluZyBhbmQgdHJhaWxpbmcgc3BhY2Ugb24gZWFjaAogICAgICBsaW5lcyA9IChsaW5lLnN0cmlwKCkgZm9yIGxpbmUgaW4gdGV4dC5zcGxpdGxpbmVzKCkpCiAgICAgICMgYnJlYWsgbXVsdGktaGVhZGxpbmVzIGludG8gYSBsaW5lIGVhY2gKICAgICAgY2h1bmtzID0gKHBocmFzZS5zdHJpcCgpIGZvciBsaW5lIGluIGxpbmVzIGZvciBwaHJhc2UgaW4gbGluZS5zcGxpdCgiICAiKSkKICAgICAgIyBkcm9wIGJsYW5rIGxpbmVzCiAgICAgIHRleHQgPSAnXG4nLmpvaW4oY2h1bmsgZm9yIGNodW5rIGluIGNodW5rcyBpZiBjaHVuaykKCiAgICAgIHJldHVybiB0ZXh0CgoKICBkZWYgd29yZGxpc3Qoc2VsZik6CiAgICAgIHVybCA9ICdodHRwOi8vcy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4udC5lZHUvbGxsL2Z1bGwuaHRtbCcKICAgICAgdGV4dCA9IHNlbGYuZXh0cmFjdCh1cmwpCiAgICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoIiwiLCIiKQogICAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKCI/IiwiIikKICAgICAgdGV4dCA9IHRleHQucmVwbGFjZSgiISIsIiIpCiAgICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoIiciLCIiKQogICAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKCJgIiwiIikKICAgICAgdGV4dCA9IHRleHQucmVwbGFjZSgiLiIsIiIpCiAgICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoIi0iLCIiKQogICAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKCItIiwiIikKICAgICAgdGV4dCA9IHRleHQucmVwbGFjZSgiOiIsIiIpCiAgICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoInwiLCIiKQogICAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKCJbIiwiIikKICAgICAgdGV4dCA9IHRleHQucmVwbGFjZSgiXSIsIiIpCiAgICAgIHRleHQgPSB0ZXh0LnVwcGVyKCkKICAgICAgd29yZHMgPSBbc3RyKHgpIGZvciB4IGluIHRleHQuc3BsaXQoKV0KICAgICAgd29yZHMgPSBsaXN0KHNldCh3b3JkcykpCiAgICAgIHJldHVybiB3b3JkcwpnID0gR2FtZSgpCnByaW50KHJlcHIoZy50ZXN0MigpKSkKIiIiCmcgPSBHYW1lKCkKbG9jYXRpb25zID0gZy5GaW5kWCgnRicpCnByaW50KHJlcHIobG9jYXRpb25zKSkKZm9yIHR1cCBpbiBsb2NhdGlvbnM6CnBhdGggPSBbXQpwb3MgPSAwCmlmIGcuSXNXb3JkSW5NYXRyaXgoIkZPUlRSQU4iLCB0dXBbMF0sIHR1cFsxXSwgcG9zLCBwYXRoKToKcHJpbnQocmVwcihwYXRoKSkKZWxzZToKcHJpbnQoIk5PVCBGT1VORCIpCiAKWygxLCA1KSwgKDMsIDQpLCAoNCwgNyldCnBhdGg9WygxLCA1KV0mWD0nRicKTk9UIEZPVU5ECnBhdGg9WygzLCA0KV0mWD0nRicKcGF0aD1bKDMsIDQpLCAoNCwgMildJlg9J08nCnBhdGg9WygzLCA0KSwgKDQsIDIpLCAoNSwgMyldJlg9J08nCnBhdGg9WygzLCA0KSwgKDQsIDIpLCAoNSwgMyksICgzLCAyKV0mWD0nUicKcGF0aD1bKDMsIDQpLCAoNCwgMiksICg1LCAzKSwgKDMsIDIpLCAoMiwgMCldJlg9J1QnCnBhdGg9WygzLCA0KSwgKDQsIDIpLCAoNSwgMyksICgzLCAyKSwgKDIsIDApLCAoMywgMildJlg9J1InCnBhdGg9WygzLCA0KSwgKDQsIDIpLCAoNSwgMyksICgzLCAyKSwgKDIsIDApLCAoMywgMiksICg0LCA0KV0mWD0nQScKcGF0aD1bKDMsIDQpLCAoNCwgMiksICg1LCAzKSwgKDMsIDIpLCAoMiwgMCksICgzLCAyKSwgKDQsIDQpLCAoMSwgMyldJlg9J0EnClsoMywgNCksICg0LCAyKSwgKDUsIDMpLCAoMywgMiksICgyLCAwKSwgKDMsIDIpLCAoNCwgNCksICgxLCAzKV0KcGF0aD1bKDQsIDcpXSZYPSdGJwpOT1QgRk9VTkQKIiIiCiIiIgpbJ01BWScsICdOSU5USCcsICdNQU4nLCAnU0lOJywgJ05PTicsICdOT1cnLCAnVicsICdGQVJFJywgJ0xBJywgJ09OVCcsICdBJywgJ0hFQVQnLCAnQ0xVQicsICdOSU5FJywgJ1NBVycsICdBUFQnLCAnVFJJTScsICdCJywgJ0NBTUUnLCAnV09OVCcsICdXSEVSRScsICdTVUNIJywgJ0JVWScsICdCVVQnLCAnTkFNRScsICdEJywgJ09OJywgJ1dISUNIJywgJ0xBVVMnLCAnT0YnLCAnSEUnLCAnU1VCJywgJ1JFTlQnLCAnRkFSJywgJ0VBVCcsICdQQVAnLCAnTFVURScsICdNRScsICdJTlQnLCAnTUknLCAnSU5TJywgJ0FOT04nLCAnRVJFJywgJ1dPT0QnLCAnUkFSRScsICdESU5FJywgJ0FOTkUnLCAnTklUJywgJ0lNUCcsICdETycsICdNSVJFJywgJ1dBUycsICdESUQnLCAnQUlSJywgJ0knLCAnSVMnLCAnSVQnLCAnSU4nLCAnSUYnLCAnTkFZJywgJ0UnLCAnU05BS0UnLCAnTk8nLCAnTkUnLCAnV0hFTicsICdJU0JVVCcsICdGSVJFJywgJ1NJUicsICdTSVQnLCAnUklDSCcsICdLTk9XTicsICdDQVAnLCAnQ0FOJywgJ01BS0UnLCAnTCcsICdXT08nLCAnRVQnLCAnQVJFJywgJ0JBJywgJ09GVCcsICdUSElOJywgJ1NBVCcsICdBTkQnLCAnQU5UJywgJ0hFUicsICdPV04nLCAnRkFOJywgJ1QnLCAnREFSVCcsICdEQVJFJywgJ0ZBJywgJ08nLCAnQUNUJywgJ0VRVUFMJywgJ1RIJywgJ1RJJywgJ1RFJywgJ0FEJywgJ0FNJywgJ0FOJywgJ0FTJywgJ0FUJywgJ0FZJywgJ01BTlMnLCAnTEFZJywgJ0tOT1cnLCAnTElORU4nLCAnSElTJywgJ0hJRCcsICdISU0nLCAnSElUJywgJ1RSVVRIJywgJ1dPTicsICdIRVJFJywgJ0JJRCcsICdGSUZUWScsICdDT05USU5FTlQnLCAnRklGVEgnLCAnVEhJTkUnLCAnV0FOVCcsICdSRScsICdBUlQnLCAnQUNVVEUnLCAnVElTJywgJ1VUJywgJ1VTJywgJ1UnLCAnQ1VUJywgJ0RBTicsICdEQVknLCAnUExBWSddCiIiIgo=