#!/usr/bin/python
import pygame
import serial
import time
import re
import Queue
import logging
from logging.handlers import WatchedFileHandler
import threading
import sys
import signal
import subprocess
import os
import websocket
from websocket import create_connection
FPS = 30
DRAW_WINDOW_SIZE = (1280, 1024)
pressed_queue = Queue.Queue(maxsize=20)
send_queue = Queue.Queue()
SERIAL_DEV = '/dev/ttyACM0'
stop_read
= threading.
Event()begin_draw
= threading.
Event()help_pressed
= threading.
Event()conn_ok
= threading.
Event()ok_get
= threading.
Event()stop_read.clear()
begin_draw.clear()
help_pressed.clear()
conn_ok.clear()
ok_get.clear()
threads = []
LOG_FORMAT = '[%(asctime)s] %(levelname)s: %(funcName)s: %(message)s'
log = logging.getLogger('main_log')
log.setLevel(logging.DEBUG)
log_handler = WatchedFileHandler('screen.log')
log_fmt = logging.Formatter(fmt=LOG_FORMAT)
log_handler.setFormatter(log_fmt)
log.addHandler(log_handler)
# workaround for wrong buttons numbering
btn_table = {
'0': '9',
'1': '8',
'2': '7',
'3': '6',
'4': '5',
'5': '4',
'6': '3',
'7': '2',
'8': '1',
'9': '0'
}
choose_imgs = {
'0': 'imgs/sim 0.png', # 0
'1': 'imgs/sim 1.png', # 1
'2': 'imgs/sim 2.png', # 2
'3': 'imgs/sim 3.png', # 3
'4': 'imgs/sim 4.png', # 4
'5': 'imgs/sim 5.png', # 5
'6': 'imgs/sim 6.png', # 6
'7': 'imgs/sim 7.png', # 7
'8': 'imgs/sim 8.png', # 8
'9': 'imgs/sim 9.png' # 9
}
choose_imgs_surf = {}
answer_img = {
(1, 1, 0): 'imgs/110-mercury2.jpg',
(1, 2, 0): 'imgs/120-venera2.jpg',
(1, 2, 3): 'imgs/123-1-hz2.jpg',
(1, 3, 1): 'imgs/131-earth2.jpg',
(1, 4, 2): 'imgs/142-mars2.jpg',
(1, 5, 1): 'imgs/151-jupiter2.jpg',
(1, 6, 0): 'imgs/160-saturn2.jpg',
(1, 7, 2): 'imgs/172-uran2.jpg',
(1, 8, 6): 'imgs/186-neptun2.jpg',
(1, 9, 1): 'imgs/191-pluton2.jpg',
(2, 3, 4): 'imgs/234-2-hz2.jpg',
(2, 4, 2): 'imgs/242-3-hz2.jpg',
(3, 3, 1): 'imgs/331-4-hz2.jpg',
(3, 4, 1): 'imgs/341-5-hz2.jpg',
(3, 4, 4): 'imgs/344-6-hz2.jpg',
(3, 4, 5): 'imgs/345-7-hz2.jpg',
(3, 5, 3): 'imgs/353-8-hz2.jpg',
(4, 5, 6): 'imgs/456-9-hz2.jpg',
(4, 6, 2): 'imgs/462-10-hz2.jpg',
(5, 6, 7): 'imgs/567-11-hz2.jpg',
(5, 7, 5): 'imgs/575-12-hz2.jpg',
(6, 7, 8): 'imgs/678-13-hz2.jpg',
(6, 8, 6): 'imgs/686-14-hz2.jpg',
(7, 7, 5): 'imgs/775-15-hz2.jpg',
(7, 8, 5): 'imgs/785-16-hz2.jpg',
(7, 8, 8): 'imgs/788-17-hz2.jpg',
(7, 8, 9): 'imgs/789-18-hz2.jpg',
(7, 9, 7): 'imgs/797-19-hz2.jpg',
(8, 8, 6): 'imgs/886-22-hz2.jpg',
(8, 9, 0): 'imgs/890-20-hz2.jpg',
(8, 9, 6): 'imgs/896-23-hz2.jpg',
(8, 9, 9): 'imgs/899-21-hz2.jpg',
(9, 1, 9): 'imgs/919-24-hz2.jpg'
}
not_found = False
class AskEntry(object):
def __init__(self, xval, yval, padding, img_path):
super(AskEntry, self).__init__()
self.coord = (xval, yval)
self.padding = padding
self.img = pygame.image.load(img_path).convert_alpha()
self.cent_img = pygame.image.load('imgs/sim D.png').convert_alpha()
self.x_size, _ = DRAW_WINDOW_SIZE
self.y_size = 200
self.surf = pygame.Surface(
(self.x_size, self.y_size),
flags=pygame.SRCALPHA,
depth=32
)
self.surf.blit(self.img, (self.padding, 0))
self.surf.blit(
self.cent_img,
(self.x_size / 2 - 70, self.y_size / 2 - 70)
)
self.answer = None
def draw_choosed(self, choose):
self.answer = choose
self.img_ok = choose_imgs_surf[choose]
self.append_answer()
def reset_answer(self):
self.answer = None
def append_answer(self):
self.surf.blit(
self.img_ok,
(self.x_size - self.padding - 200, 0)
)
def redraw(self):
self.surf.fill((0, 0, 0, 0))
self.surf.blit(self.img, (self.padding, 0))
self.surf.blit(
self.cent_img,
(self.x_size / 2 - 70, self.y_size / 2 - 70)
)
def full_reset(self):
self.reset_answer()
self.redraw()
class AskLayer(object):
def __init__(self, size):
super(AskLayer, self).__init__()
self.size = size
self.surf = pygame.Surface(size, flags=pygame.SRCALPHA, depth=32)
def draw(self, ask_entry):
self.surf.blit(
ask_entry.surf,
ask_entry.coord
)
def reset(self):
self.surf.fill((0, 0, 0, 0))
def answer_img_load(answers_list):
global not_found
if tuple(answers_list) in answer_img:
img_for_show = pygame.image.load(
answer_img[tuple(answers_list)]
).convert_alpha()
elif (answers_list[0] == 0) or (answers_list[1] == 0):
img_for_show = pygame.image.load(
'imgs/00-DeathStar2.jpg'
).convert_alpha()
else:
img_for_show = pygame.image.load(
'imgs/allother-asteroids2.jpg'
).convert_alpha()
not_found = True
return img_for_show
def preload_choose_imgs():
for key, path in choose_imgs.iteritems():
choose_imgs_surf[key] = pygame.image.load(path).convert_alpha()
def main():
global not_found
signal.signal(signal.SIGINT, ctrl_c_handler)
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode(
DRAW_WINDOW_SIZE,
pygame.NOFRAME
)
pygame.mouse.set_visible(False)
ask_layer = AskLayer(DRAW_WINDOW_SIZE)
barrel_test = pygame.image.load('imgs/barrel view.png').convert_alpha()
lines = pygame.image.load('imgs/Navig sreen.png').convert_alpha()
fin_img = pygame.image.load('fin.png').convert_alpha()
not_found_img = pygame.image.load('imgs/not_found2.jpg').convert_alpha()
preload_choose_imgs()
quest_list = []
quest_list.append(AskEntry(0, 127, 300, 'Ps1-sun.png'))
quest_list.append(AskEntry(0, 412, 230, 'Ps2-place.png'))
quest_list.append(AskEntry(0, 693, 300, 'Ps3-sputnik.png'))
target=mon_serial,
args=(SERIAL_DEV,)
)
ser_t.daemon = True
ser_t.start()
threads.append(ser_t)
conn_ok.wait(timeout=5)
if not conn_ok.isSet():
safe_quit()
send_queue.put('OK\n')
ok_get.wait(timeout=1)
if not ok_get.isSet():
safe_quit()
else:
ok_get.clear()
first_run = True
running = True
playing = True
ask = False
ask_update = True
quest_numb = 0
draw_answer = False
send_resume = False
repeat_cnt = 0
screen_update = True
show_answered = False
begin_draw.wait()
screen.fill((255, 255, 255))
screen.blit(barrel_test, (0, 0))
pygame.display.update()
screen.blit(lines, (0, 0))
while running:
begin_draw.wait()
for event in pygame.event.get():
if event.type == pygame.QUIT:
safe_quit()
if help_pressed.isSet():
playing = True
if playing:
log.debug('Start omxplayer')
subprocess.call([
'omxplayer',
'--no-keys',
'--layer', '2',
'video.avi'
])
log.debug('Video played')
playing = False
send_resume = True
help_pressed.clear()
continue
if send_resume:
if first_run:
ask = True
first_run = False
if not ok_get.isSet():
if repeat_cnt > 10:
safe_quit()
send_queue.put('RESUME')
time.sleep(0.2)
repeat_cnt += 1
else:
ok_get.clear()
help_pressed.clear()
send_resume = False
log.debug('Resuming after video played')
repeat_cnt = 0
continue
if ask:
try:
btn = pressed_queue.get(True, 0.1)
log.debug('Get from queue' + str(btn))
except Queue.Empty:
pass
else:
log.debug('Pressed BUTTON ' + btn)
quest_list[quest_numb].draw_choosed(
btn_table[btn.lstrip('B')]
)
ask_layer.draw(quest_list[quest_numb])
quest_numb += 1
ask_update = True
if quest_numb == 3:
ask = False
ask_update = False
draw_answer = True
show_answered = True
screen.blit(ask_layer.surf, (0, 0))
pygame.display.update()
if ask_update:
ask_update = False
ask_layer.draw(quest_list[quest_numb])
screen.blit(ask_layer.surf, (0, 0))
pygame.display.update()
if show_answered:
answers = map(lambda answ: int(answ.answer), quest_list)
log.debug(answers)
show_img = answer_img_load(answers)
# time.sleep(0.5)
show_answered = False
screen.blit(show_img, (0, 0))
pygame.display.update()
if draw_answer:
if not pressed_queue.empty():
btn = pressed_queue.get()
log.debug('Pressed BUTTON: ' + btn)
if btn == 'B_YES':
if not_found:
screen.blit(not_found_img, (0, 0))
else:
if tuple(answers) in answer_img:
fin_img_path = 'coord/' + answer_img[tuple(answers)]
fin_img = pygame.image.load(fin_img_path).convert_alpha()
screen.blit(fin_img, (0, 0))
elif (answers[0] == 0) or (answers[1] == 0):
fin_img_path = 'coord/imgs/00-DeathStar2.jpg'
fin_img = pygame.image.load(fin_img_path).convert_alpha()
screen.blit(fin_img, (0, 0))
ws = create_connection("ws://192.168.2.6:8080/ws")
ws.send('DEATH')
ws.close()
else:
screen.blit(not_found_img, (0, 0))
screen.blit(barrel_test, (0, 0))
screen_update = True
elif btn == 'B_NO' or btn == 'B_RES':
ask_layer.reset()
for x in quest_list:
x.full_reset()
quest_numb = 0
draw_answer = False
ask = True
ask_update = True
screen.fill((255, 255, 255))
screen.blit(lines, (0, 0))
screen.blit(barrel_test, (0, 0))
# screen_update = True
not_found = False
if screen_update:
pygame.display.update()
screen_update = False
clock.tick(FPS)
safe_quit()
def mon_serial(serial_dev):
ser = serial_connect(serial_dev, 115200)
button_patt = re.compile(r'B{1,1}[0-9]{1,2}')
yes_patt = re.compile(r'B_YES')
no_patt = re.compile(r'B_NO')
ask_patt = re.compile(r'B_ASK')
res_patt = re.compile(r'B_RES')
begin_patt = re.compile(r'CARD_PRESENT')
conn_patt = re.compile(r'CONNECTED')
ok_patt = re.compile(r'OK')
while not stop_read.is_set():
if not send_queue.empty():
try:
ser_wr = send_queue.get()
ser.write(ser_wr)
log.debug('Write to serial:' + ser_wr)
except serial.SerialException as e:
log.error('Serial write error: ' + str(e))
try:
curr = ser.readline().rstrip('\r\n')
except serial.SerialException as e:
log.error('Serial error: ' + str(e))
time.sleep(1)
ser = serial_connect(serial_dev, 115200)
continue
if len(curr) == 0:
continue
button_match = re.match(button_patt, curr)
yes_match = re.match(yes_patt, curr)
no_match = re.match(no_patt, curr)
ask_match = re.match(ask_patt, curr)
res_match = re.match(res_patt, curr)
begin_match = re.match(begin_patt, curr)
conn_match = re.match(conn_patt, curr)
ok_match = re.match(ok_patt, curr)
if button_match or yes_match or no_match or res_match:
pressed_queue.put(curr)
log.debug('Pressed ' + curr + ' button')
elif begin_match:
begin_draw.set()
log.debug('Begin DRAW')
elif ask_match:
help_pressed.set()
log.debug('B_ASK Pressed')
elif conn_match:
conn_ok.set()
log.debug('Connection established')
elif ok_match:
ok_get.set()
log.debug('Get OK msg')
else:
log.warning('Get unknown from serial: ' + curr)
ser.close()
def serial_connect(dev, speed):
try:
ser = serial.Serial(dev, speed, timeout=0.1)
except serial.SerialException as e:
log.error('Serial Connect Error: ' + str(e))
print 'Connection Error'
else:
log.info('Connected successfully')
ser.writeTimeout = 0.1
return ser
log.critical('FAIL to connect. Exit.')
safe_quit()
def ctrl_c_handler(signum, frame):
log.info('Get Ctrl-C.')
safe_quit()
def safe_quit():
print 'Exit.'
log.info('Exit.')
logging.shutdown()
pygame.quit()
stop_read.set()
for thr in threads:
thr.join(2)
sys.exit(0)
if __name__ == '__main__':
main()
IyEvdXNyL2Jpbi9weXRob24KCmltcG9ydCBweWdhbWUKaW1wb3J0IHNlcmlhbAppbXBvcnQgdGltZQppbXBvcnQgcmUKaW1wb3J0IFF1ZXVlCmltcG9ydCBsb2dnaW5nCmZyb20gbG9nZ2luZy5oYW5kbGVycyBpbXBvcnQgV2F0Y2hlZEZpbGVIYW5kbGVyCmltcG9ydCB0aHJlYWRpbmcKaW1wb3J0IHN5cwppbXBvcnQgc2lnbmFsCmltcG9ydCBzdWJwcm9jZXNzCmltcG9ydCBvcwppbXBvcnQgd2Vic29ja2V0CmZyb20gd2Vic29ja2V0IGltcG9ydCBjcmVhdGVfY29ubmVjdGlvbgoKRlBTID0gMzAKRFJBV19XSU5ET1dfU0laRSA9ICgxMjgwLCAxMDI0KQpwcmVzc2VkX3F1ZXVlID0gUXVldWUuUXVldWUobWF4c2l6ZT0yMCkKc2VuZF9xdWV1ZSA9IFF1ZXVlLlF1ZXVlKCkKU0VSSUFMX0RFViA9ICcvZGV2L3R0eUFDTTAnCnN0b3BfcmVhZCA9IHRocmVhZGluZy5FdmVudCgpCmJlZ2luX2RyYXcgPSB0aHJlYWRpbmcuRXZlbnQoKQpoZWxwX3ByZXNzZWQgPSB0aHJlYWRpbmcuRXZlbnQoKQpjb25uX29rID0gdGhyZWFkaW5nLkV2ZW50KCkKb2tfZ2V0ID0gdGhyZWFkaW5nLkV2ZW50KCkKc3RvcF9yZWFkLmNsZWFyKCkKYmVnaW5fZHJhdy5jbGVhcigpCmhlbHBfcHJlc3NlZC5jbGVhcigpCmNvbm5fb2suY2xlYXIoKQpva19nZXQuY2xlYXIoKQoKdGhyZWFkcyA9IFtdCgpMT0dfRk9STUFUID0gJ1slKGFzY3RpbWUpc10gJShsZXZlbG5hbWUpczogJShmdW5jTmFtZSlzOiAlKG1lc3NhZ2UpcycKbG9nID0gbG9nZ2luZy5nZXRMb2dnZXIoJ21haW5fbG9nJykKbG9nLnNldExldmVsKGxvZ2dpbmcuREVCVUcpCmxvZ19oYW5kbGVyID0gV2F0Y2hlZEZpbGVIYW5kbGVyKCdzY3JlZW4ubG9nJykKbG9nX2ZtdCA9IGxvZ2dpbmcuRm9ybWF0dGVyKGZtdD1MT0dfRk9STUFUKQpsb2dfaGFuZGxlci5zZXRGb3JtYXR0ZXIobG9nX2ZtdCkKbG9nLmFkZEhhbmRsZXIobG9nX2hhbmRsZXIpCgojIHdvcmthcm91bmQgZm9yIHdyb25nIGJ1dHRvbnMgbnVtYmVyaW5nCmJ0bl90YWJsZSA9IHsKICAgICcwJzogJzknLAogICAgJzEnOiAnOCcsCiAgICAnMic6ICc3JywKICAgICczJzogJzYnLAogICAgJzQnOiAnNScsCiAgICAnNSc6ICc0JywKICAgICc2JzogJzMnLAogICAgJzcnOiAnMicsCiAgICAnOCc6ICcxJywKICAgICc5JzogJzAnCn0KCmNob29zZV9pbWdzID0gewogICAgJzAnOiAnaW1ncy9zaW0gMC5wbmcnLCAgIyAwCiAgICAnMSc6ICdpbWdzL3NpbSAxLnBuZycsICAjIDEKICAgICcyJzogJ2ltZ3Mvc2ltIDIucG5nJywgICMgMgogICAgJzMnOiAnaW1ncy9zaW0gMy5wbmcnLCAgIyAzCiAgICAnNCc6ICdpbWdzL3NpbSA0LnBuZycsICAjIDQKICAgICc1JzogJ2ltZ3Mvc2ltIDUucG5nJywgICMgNQogICAgJzYnOiAnaW1ncy9zaW0gNi5wbmcnLCAgIyA2CiAgICAnNyc6ICdpbWdzL3NpbSA3LnBuZycsICAjIDcKICAgICc4JzogJ2ltZ3Mvc2ltIDgucG5nJywgICMgOAogICAgJzknOiAnaW1ncy9zaW0gOS5wbmcnICAjIDkKfQoKY2hvb3NlX2ltZ3Nfc3VyZiA9IHt9CgphbnN3ZXJfaW1nID0gewogICAgKDEsIDEsIDApOiAnaW1ncy8xMTAtbWVyY3VyeTIuanBnJywKICAgICgxLCAyLCAwKTogJ2ltZ3MvMTIwLXZlbmVyYTIuanBnJywKICAgICgxLCAyLCAzKTogJ2ltZ3MvMTIzLTEtaHoyLmpwZycsCiAgICAoMSwgMywgMSk6ICdpbWdzLzEzMS1lYXJ0aDIuanBnJywKICAgICgxLCA0LCAyKTogJ2ltZ3MvMTQyLW1hcnMyLmpwZycsCiAgICAoMSwgNSwgMSk6ICdpbWdzLzE1MS1qdXBpdGVyMi5qcGcnLAogICAgKDEsIDYsIDApOiAnaW1ncy8xNjAtc2F0dXJuMi5qcGcnLAogICAgKDEsIDcsIDIpOiAnaW1ncy8xNzItdXJhbjIuanBnJywKICAgICgxLCA4LCA2KTogJ2ltZ3MvMTg2LW5lcHR1bjIuanBnJywKICAgICgxLCA5LCAxKTogJ2ltZ3MvMTkxLXBsdXRvbjIuanBnJywKICAgICgyLCAzLCA0KTogJ2ltZ3MvMjM0LTItaHoyLmpwZycsCiAgICAoMiwgNCwgMik6ICdpbWdzLzI0Mi0zLWh6Mi5qcGcnLAogICAgKDMsIDMsIDEpOiAnaW1ncy8zMzEtNC1oejIuanBnJywKICAgICgzLCA0LCAxKTogJ2ltZ3MvMzQxLTUtaHoyLmpwZycsCiAgICAoMywgNCwgNCk6ICdpbWdzLzM0NC02LWh6Mi5qcGcnLAogICAgKDMsIDQsIDUpOiAnaW1ncy8zNDUtNy1oejIuanBnJywKICAgICgzLCA1LCAzKTogJ2ltZ3MvMzUzLTgtaHoyLmpwZycsCiAgICAoNCwgNSwgNik6ICdpbWdzLzQ1Ni05LWh6Mi5qcGcnLAogICAgKDQsIDYsIDIpOiAnaW1ncy80NjItMTAtaHoyLmpwZycsCiAgICAoNSwgNiwgNyk6ICdpbWdzLzU2Ny0xMS1oejIuanBnJywKICAgICg1LCA3LCA1KTogJ2ltZ3MvNTc1LTEyLWh6Mi5qcGcnLAogICAgKDYsIDcsIDgpOiAnaW1ncy82NzgtMTMtaHoyLmpwZycsCiAgICAoNiwgOCwgNik6ICdpbWdzLzY4Ni0xNC1oejIuanBnJywKICAgICg3LCA3LCA1KTogJ2ltZ3MvNzc1LTE1LWh6Mi5qcGcnLAogICAgKDcsIDgsIDUpOiAnaW1ncy83ODUtMTYtaHoyLmpwZycsCiAgICAoNywgOCwgOCk6ICdpbWdzLzc4OC0xNy1oejIuanBnJywKICAgICg3LCA4LCA5KTogJ2ltZ3MvNzg5LTE4LWh6Mi5qcGcnLAogICAgKDcsIDksIDcpOiAnaW1ncy83OTctMTktaHoyLmpwZycsCiAgICAoOCwgOCwgNik6ICdpbWdzLzg4Ni0yMi1oejIuanBnJywKICAgICg4LCA5LCAwKTogJ2ltZ3MvODkwLTIwLWh6Mi5qcGcnLAogICAgKDgsIDksIDYpOiAnaW1ncy84OTYtMjMtaHoyLmpwZycsCiAgICAoOCwgOSwgOSk6ICdpbWdzLzg5OS0yMS1oejIuanBnJywKICAgICg5LCAxLCA5KTogJ2ltZ3MvOTE5LTI0LWh6Mi5qcGcnCn0KCm5vdF9mb3VuZCA9IEZhbHNlCgoKY2xhc3MgQXNrRW50cnkob2JqZWN0KToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCB4dmFsLCB5dmFsLCBwYWRkaW5nLCBpbWdfcGF0aCk6CiAgICAgICAgc3VwZXIoQXNrRW50cnksIHNlbGYpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLmNvb3JkID0gKHh2YWwsIHl2YWwpCiAgICAgICAgc2VsZi5wYWRkaW5nID0gcGFkZGluZwogICAgICAgIHNlbGYuaW1nID0gcHlnYW1lLmltYWdlLmxvYWQoaW1nX3BhdGgpLmNvbnZlcnRfYWxwaGEoKQogICAgICAgIHNlbGYuY2VudF9pbWcgPSBweWdhbWUuaW1hZ2UubG9hZCgnaW1ncy9zaW0gRC5wbmcnKS5jb252ZXJ0X2FscGhhKCkKICAgICAgICBzZWxmLnhfc2l6ZSwgXyA9IERSQVdfV0lORE9XX1NJWkUKICAgICAgICBzZWxmLnlfc2l6ZSA9IDIwMAogICAgICAgIHNlbGYuc3VyZiA9IHB5Z2FtZS5TdXJmYWNlKAogICAgICAgICAgICAoc2VsZi54X3NpemUsIHNlbGYueV9zaXplKSwKICAgICAgICAgICAgZmxhZ3M9cHlnYW1lLlNSQ0FMUEhBLAogICAgICAgICAgICBkZXB0aD0zMgogICAgICAgICkKICAgICAgICBzZWxmLnN1cmYuYmxpdChzZWxmLmltZywgKHNlbGYucGFkZGluZywgMCkpCiAgICAgICAgc2VsZi5zdXJmLmJsaXQoCiAgICAgICAgICAgIHNlbGYuY2VudF9pbWcsCiAgICAgICAgICAgIChzZWxmLnhfc2l6ZSAvIDIgLSA3MCwgc2VsZi55X3NpemUgLyAyIC0gNzApCiAgICAgICAgKQogICAgICAgIHNlbGYuYW5zd2VyID0gTm9uZQoKICAgIGRlZiBkcmF3X2Nob29zZWQoc2VsZiwgY2hvb3NlKToKICAgICAgICBzZWxmLmFuc3dlciA9IGNob29zZQogICAgICAgIHNlbGYuaW1nX29rID0gY2hvb3NlX2ltZ3Nfc3VyZltjaG9vc2VdCiAgICAgICAgc2VsZi5hcHBlbmRfYW5zd2VyKCkKCiAgICBkZWYgcmVzZXRfYW5zd2VyKHNlbGYpOgogICAgICAgIHNlbGYuYW5zd2VyID0gTm9uZQoKICAgIGRlZiBhcHBlbmRfYW5zd2VyKHNlbGYpOgogICAgICAgIHNlbGYuc3VyZi5ibGl0KAogICAgICAgICAgICBzZWxmLmltZ19vaywKICAgICAgICAgICAgKHNlbGYueF9zaXplIC0gc2VsZi5wYWRkaW5nIC0gMjAwLCAwKQogICAgICAgICkKCiAgICBkZWYgcmVkcmF3KHNlbGYpOgogICAgICAgIHNlbGYuc3VyZi5maWxsKCgwLCAwLCAwLCAwKSkKICAgICAgICBzZWxmLnN1cmYuYmxpdChzZWxmLmltZywgKHNlbGYucGFkZGluZywgMCkpCiAgICAgICAgc2VsZi5zdXJmLmJsaXQoCiAgICAgICAgICAgIHNlbGYuY2VudF9pbWcsCiAgICAgICAgICAgIChzZWxmLnhfc2l6ZSAvIDIgLSA3MCwgc2VsZi55X3NpemUgLyAyIC0gNzApCiAgICAgICAgKQoKICAgIGRlZiBmdWxsX3Jlc2V0KHNlbGYpOgogICAgICAgIHNlbGYucmVzZXRfYW5zd2VyKCkKICAgICAgICBzZWxmLnJlZHJhdygpCgoKY2xhc3MgQXNrTGF5ZXIob2JqZWN0KToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBzaXplKToKICAgICAgICBzdXBlcihBc2tMYXllciwgc2VsZikuX19pbml0X18oKQogICAgICAgIHNlbGYuc2l6ZSA9IHNpemUKICAgICAgICBzZWxmLnN1cmYgPSBweWdhbWUuU3VyZmFjZShzaXplLCBmbGFncz1weWdhbWUuU1JDQUxQSEEsIGRlcHRoPTMyKQoKICAgIGRlZiBkcmF3KHNlbGYsIGFza19lbnRyeSk6CiAgICAgICAgc2VsZi5zdXJmLmJsaXQoCiAgICAgICAgICAgIGFza19lbnRyeS5zdXJmLAogICAgICAgICAgICBhc2tfZW50cnkuY29vcmQKICAgICAgICApCgogICAgZGVmIHJlc2V0KHNlbGYpOgogICAgICAgIHNlbGYuc3VyZi5maWxsKCgwLCAwLCAwLCAwKSkKCgpkZWYgYW5zd2VyX2ltZ19sb2FkKGFuc3dlcnNfbGlzdCk6CiAgICBnbG9iYWwgbm90X2ZvdW5kCiAgICBpZiB0dXBsZShhbnN3ZXJzX2xpc3QpIGluIGFuc3dlcl9pbWc6CiAgICAgICAgaW1nX2Zvcl9zaG93ID0gcHlnYW1lLmltYWdlLmxvYWQoCiAgICAgICAgICAgIGFuc3dlcl9pbWdbdHVwbGUoYW5zd2Vyc19saXN0KV0KICAgICAgICApLmNvbnZlcnRfYWxwaGEoKQogICAgZWxpZiAoYW5zd2Vyc19saXN0WzBdID09IDApIG9yIChhbnN3ZXJzX2xpc3RbMV0gPT0gMCk6CiAgICAgICAgaW1nX2Zvcl9zaG93ID0gcHlnYW1lLmltYWdlLmxvYWQoCiAgICAgICAgICAgICdpbWdzLzAwLURlYXRoU3RhcjIuanBnJwogICAgICAgICkuY29udmVydF9hbHBoYSgpCiAgICBlbHNlOgogICAgICAgIGltZ19mb3Jfc2hvdyA9IHB5Z2FtZS5pbWFnZS5sb2FkKAogICAgICAgICAgICAnaW1ncy9hbGxvdGhlci1hc3Rlcm9pZHMyLmpwZycKICAgICAgICApLmNvbnZlcnRfYWxwaGEoKQogICAgICAgIG5vdF9mb3VuZCA9IFRydWUKCiAgICByZXR1cm4gaW1nX2Zvcl9zaG93CgoKZGVmIHByZWxvYWRfY2hvb3NlX2ltZ3MoKToKICAgIGZvciBrZXksIHBhdGggaW4gY2hvb3NlX2ltZ3MuaXRlcml0ZW1zKCk6CiAgICAgICAgY2hvb3NlX2ltZ3Nfc3VyZltrZXldID0gcHlnYW1lLmltYWdlLmxvYWQocGF0aCkuY29udmVydF9hbHBoYSgpCgoKZGVmIG1haW4oKToKICAgIGdsb2JhbCBub3RfZm91bmQKICAgIHNpZ25hbC5zaWduYWwoc2lnbmFsLlNJR0lOVCwgY3RybF9jX2hhbmRsZXIpCiAgICBweWdhbWUuaW5pdCgpCiAgICBjbG9jayA9IHB5Z2FtZS50aW1lLkNsb2NrKCkKICAgIHNjcmVlbiA9IHB5Z2FtZS5kaXNwbGF5LnNldF9tb2RlKAogICAgICAgIERSQVdfV0lORE9XX1NJWkUsCiAgICAgICAgcHlnYW1lLk5PRlJBTUUKICAgICkKICAgIHB5Z2FtZS5tb3VzZS5zZXRfdmlzaWJsZShGYWxzZSkKICAgIGFza19sYXllciA9IEFza0xheWVyKERSQVdfV0lORE9XX1NJWkUpCiAgICBiYXJyZWxfdGVzdCA9IHB5Z2FtZS5pbWFnZS5sb2FkKCdpbWdzL2JhcnJlbCB2aWV3LnBuZycpLmNvbnZlcnRfYWxwaGEoKQogICAgbGluZXMgPSBweWdhbWUuaW1hZ2UubG9hZCgnaW1ncy9OYXZpZyBzcmVlbi5wbmcnKS5jb252ZXJ0X2FscGhhKCkKICAgIGZpbl9pbWcgPSBweWdhbWUuaW1hZ2UubG9hZCgnZmluLnBuZycpLmNvbnZlcnRfYWxwaGEoKQogICAgbm90X2ZvdW5kX2ltZyA9IHB5Z2FtZS5pbWFnZS5sb2FkKCdpbWdzL25vdF9mb3VuZDIuanBnJykuY29udmVydF9hbHBoYSgpCiAgICBwcmVsb2FkX2Nob29zZV9pbWdzKCkKICAgIHF1ZXN0X2xpc3QgPSBbXQogICAgcXVlc3RfbGlzdC5hcHBlbmQoQXNrRW50cnkoMCwgMTI3LCAzMDAsICdQczEtc3VuLnBuZycpKQogICAgcXVlc3RfbGlzdC5hcHBlbmQoQXNrRW50cnkoMCwgNDEyLCAyMzAsICdQczItcGxhY2UucG5nJykpCiAgICBxdWVzdF9saXN0LmFwcGVuZChBc2tFbnRyeSgwLCA2OTMsIDMwMCwgJ1BzMy1zcHV0bmlrLnBuZycpKQoKICAgIHNlcl90ID0gdGhyZWFkaW5nLlRocmVhZCgKICAgICAgICB0YXJnZXQ9bW9uX3NlcmlhbCwKICAgICAgICBhcmdzPShTRVJJQUxfREVWLCkKICAgICkKICAgIHNlcl90LmRhZW1vbiA9IFRydWUKICAgIHNlcl90LnN0YXJ0KCkKICAgIHRocmVhZHMuYXBwZW5kKHNlcl90KQoKICAgIGNvbm5fb2sud2FpdCh0aW1lb3V0PTUpCiAgICBpZiBub3QgY29ubl9vay5pc1NldCgpOgogICAgICAgIHNhZmVfcXVpdCgpCiAgICBzZW5kX3F1ZXVlLnB1dCgnT0tcbicpCiAgICBva19nZXQud2FpdCh0aW1lb3V0PTEpCiAgICBpZiBub3Qgb2tfZ2V0LmlzU2V0KCk6CiAgICAgICAgc2FmZV9xdWl0KCkKICAgIGVsc2U6CiAgICAgICAgb2tfZ2V0LmNsZWFyKCkKCiAgICBmaXJzdF9ydW4gPSBUcnVlCiAgICBydW5uaW5nID0gVHJ1ZQogICAgcGxheWluZyA9IFRydWUKICAgIGFzayA9IEZhbHNlCiAgICBhc2tfdXBkYXRlID0gVHJ1ZQogICAgcXVlc3RfbnVtYiA9IDAKICAgIGRyYXdfYW5zd2VyID0gRmFsc2UKICAgIHNlbmRfcmVzdW1lID0gRmFsc2UKICAgIHJlcGVhdF9jbnQgPSAwCiAgICBzY3JlZW5fdXBkYXRlID0gVHJ1ZQogICAgc2hvd19hbnN3ZXJlZCA9IEZhbHNlCgogICAgYmVnaW5fZHJhdy53YWl0KCkKICAgIHNjcmVlbi5maWxsKCgyNTUsIDI1NSwgMjU1KSkKICAgIHNjcmVlbi5ibGl0KGJhcnJlbF90ZXN0LCAoMCwgMCkpCiAgICBweWdhbWUuZGlzcGxheS51cGRhdGUoKQogICAgc2NyZWVuLmJsaXQobGluZXMsICgwLCAwKSkKCiAgICB3aGlsZSBydW5uaW5nOgogICAgICAgIGJlZ2luX2RyYXcud2FpdCgpCiAgICAgICAgZm9yIGV2ZW50IGluIHB5Z2FtZS5ldmVudC5nZXQoKToKICAgICAgICAgICAgaWYgZXZlbnQudHlwZSA9PSBweWdhbWUuUVVJVDoKICAgICAgICAgICAgICAgIHNhZmVfcXVpdCgpCgogICAgICAgIGlmIGhlbHBfcHJlc3NlZC5pc1NldCgpOgogICAgICAgICAgICBwbGF5aW5nID0gVHJ1ZQoKICAgICAgICBpZiBwbGF5aW5nOgogICAgICAgICAgICBsb2cuZGVidWcoJ1N0YXJ0IG9teHBsYXllcicpCiAgICAgICAgICAgIHN1YnByb2Nlc3MuY2FsbChbCiAgICAgICAgICAgICAgICAnb214cGxheWVyJywKICAgICAgICAgICAgICAgICctLW5vLWtleXMnLAogICAgICAgICAgICAgICAgJy0tbGF5ZXInLCAnMicsCiAgICAgICAgICAgICAgICAndmlkZW8uYXZpJwogICAgICAgICAgICBdKQogICAgICAgICAgICBsb2cuZGVidWcoJ1ZpZGVvIHBsYXllZCcpCiAgICAgICAgICAgIHBsYXlpbmcgPSBGYWxzZQogICAgICAgICAgICBzZW5kX3Jlc3VtZSA9IFRydWUKICAgICAgICAgICAgaGVscF9wcmVzc2VkLmNsZWFyKCkKICAgICAgICAgICAgY29udGludWUKCiAgICAgICAgaWYgc2VuZF9yZXN1bWU6CiAgICAgICAgICAgIGlmIGZpcnN0X3J1bjoKICAgICAgICAgICAgICAgIGFzayA9IFRydWUKICAgICAgICAgICAgICAgIGZpcnN0X3J1biA9IEZhbHNlCiAgICAgICAgICAgIGlmIG5vdCBva19nZXQuaXNTZXQoKToKICAgICAgICAgICAgICAgIGlmIHJlcGVhdF9jbnQgPiAxMDoKICAgICAgICAgICAgICAgICAgICBzYWZlX3F1aXQoKQogICAgICAgICAgICAgICAgc2VuZF9xdWV1ZS5wdXQoJ1JFU1VNRScpCiAgICAgICAgICAgICAgICB0aW1lLnNsZWVwKDAuMikKICAgICAgICAgICAgICAgIHJlcGVhdF9jbnQgKz0gMQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgb2tfZ2V0LmNsZWFyKCkKICAgICAgICAgICAgICAgIGhlbHBfcHJlc3NlZC5jbGVhcigpCiAgICAgICAgICAgICAgICBzZW5kX3Jlc3VtZSA9IEZhbHNlCiAgICAgICAgICAgICAgICBsb2cuZGVidWcoJ1Jlc3VtaW5nIGFmdGVyIHZpZGVvIHBsYXllZCcpCiAgICAgICAgICAgICAgICByZXBlYXRfY250ID0gMAogICAgICAgICAgICBjb250aW51ZQoKICAgICAgICBpZiBhc2s6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIGJ0biA9IHByZXNzZWRfcXVldWUuZ2V0KFRydWUsIDAuMSkKICAgICAgICAgICAgICAgIGxvZy5kZWJ1ZygnR2V0IGZyb20gcXVldWUnICsgc3RyKGJ0bikpCiAgICAgICAgICAgIGV4Y2VwdCBRdWV1ZS5FbXB0eToKICAgICAgICAgICAgICAgIHBhc3MKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGxvZy5kZWJ1ZygnUHJlc3NlZCBCVVRUT04gJyArIGJ0bikKICAgICAgICAgICAgICAgIHF1ZXN0X2xpc3RbcXVlc3RfbnVtYl0uZHJhd19jaG9vc2VkKAogICAgICAgICAgICAgICAgICAgIGJ0bl90YWJsZVtidG4ubHN0cmlwKCdCJyldCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBhc2tfbGF5ZXIuZHJhdyhxdWVzdF9saXN0W3F1ZXN0X251bWJdKQogICAgICAgICAgICAgICAgcXVlc3RfbnVtYiArPSAxCiAgICAgICAgICAgICAgICBhc2tfdXBkYXRlID0gVHJ1ZQoKICAgICAgICAgICAgaWYgcXVlc3RfbnVtYiA9PSAzOgogICAgICAgICAgICAgICAgYXNrID0gRmFsc2UKICAgICAgICAgICAgICAgIGFza191cGRhdGUgPSBGYWxzZQogICAgICAgICAgICAgICAgZHJhd19hbnN3ZXIgPSBUcnVlCiAgICAgICAgICAgICAgICBzaG93X2Fuc3dlcmVkID0gVHJ1ZQogICAgICAgICAgICAgICAgc2NyZWVuLmJsaXQoYXNrX2xheWVyLnN1cmYsICgwLCAwKSkKICAgICAgICAgICAgICAgIHB5Z2FtZS5kaXNwbGF5LnVwZGF0ZSgpCgogICAgICAgICAgICBpZiBhc2tfdXBkYXRlOgogICAgICAgICAgICAgICAgYXNrX3VwZGF0ZSA9IEZhbHNlCiAgICAgICAgICAgICAgICBhc2tfbGF5ZXIuZHJhdyhxdWVzdF9saXN0W3F1ZXN0X251bWJdKQogICAgICAgICAgICAgICAgc2NyZWVuLmJsaXQoYXNrX2xheWVyLnN1cmYsICgwLCAwKSkKICAgICAgICAgICAgICAgIHB5Z2FtZS5kaXNwbGF5LnVwZGF0ZSgpCgogICAgICAgIGlmIHNob3dfYW5zd2VyZWQ6CiAgICAgICAgICAgIGFuc3dlcnMgPSBtYXAobGFtYmRhIGFuc3c6IGludChhbnN3LmFuc3dlciksIHF1ZXN0X2xpc3QpCiAgICAgICAgICAgIGxvZy5kZWJ1ZyhhbnN3ZXJzKQogICAgICAgICAgICBzaG93X2ltZyA9IGFuc3dlcl9pbWdfbG9hZChhbnN3ZXJzKQogICAgICAgICAgICAjIHRpbWUuc2xlZXAoMC41KQogICAgICAgICAgICBzaG93X2Fuc3dlcmVkID0gRmFsc2UKICAgICAgICAgICAgc2NyZWVuLmJsaXQoc2hvd19pbWcsICgwLCAwKSkKICAgICAgICAgICAgcHlnYW1lLmRpc3BsYXkudXBkYXRlKCkKCiAgICAgICAgaWYgZHJhd19hbnN3ZXI6CiAgICAgICAgICAgIGlmIG5vdCBwcmVzc2VkX3F1ZXVlLmVtcHR5KCk6CiAgICAgICAgICAgICAgICBidG4gPSBwcmVzc2VkX3F1ZXVlLmdldCgpCiAgICAgICAgICAgICAgICBsb2cuZGVidWcoJ1ByZXNzZWQgQlVUVE9OOiAnICsgYnRuKQogICAgICAgICAgICAgICAgaWYgYnRuID09ICdCX1lFUyc6CiAgICAgICAgICAgICAgICAgICAgaWYgbm90X2ZvdW5kOgogICAgICAgICAgICAgICAgICAgICAgICBzY3JlZW4uYmxpdChub3RfZm91bmRfaW1nLCAoMCwgMCkpCiAgICAgICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgaWYgdHVwbGUoYW5zd2VycykgaW4gYW5zd2VyX2ltZzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbl9pbWdfcGF0aCA9ICdjb29yZC8nICsgYW5zd2VyX2ltZ1t0dXBsZShhbnN3ZXJzKV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbl9pbWcgPSBweWdhbWUuaW1hZ2UubG9hZChmaW5faW1nX3BhdGgpLmNvbnZlcnRfYWxwaGEoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NyZWVuLmJsaXQoZmluX2ltZywgKDAsIDApKQogICAgICAgICAgICAgICAgICAgICAgICBlbGlmIChhbnN3ZXJzWzBdID09IDApIG9yIChhbnN3ZXJzWzFdID09IDApOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmluX2ltZ19wYXRoID0gJ2Nvb3JkL2ltZ3MvMDAtRGVhdGhTdGFyMi5qcGcnCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaW5faW1nID0gcHlnYW1lLmltYWdlLmxvYWQoZmluX2ltZ19wYXRoKS5jb252ZXJ0X2FscGhhKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcmVlbi5ibGl0KGZpbl9pbWcsICgwLCAwKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdzID0gY3JlYXRlX2Nvbm5lY3Rpb24oIndzOi8vMTkyLjE2OC4yLjY6ODA4MC93cyIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3cy5zZW5kKCdERUFUSCcpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3cy5jbG9zZSgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcmVlbi5ibGl0KG5vdF9mb3VuZF9pbWcsICgwLCAwKSkKICAgICAgICAgICAgICAgICAgICBzY3JlZW4uYmxpdChiYXJyZWxfdGVzdCwgKDAsIDApKQogICAgICAgICAgICAgICAgICAgIHNjcmVlbl91cGRhdGUgPSBUcnVlCiAgICAgICAgICAgICAgICBlbGlmIGJ0biA9PSAnQl9OTycgb3IgYnRuID09ICdCX1JFUyc6CiAgICAgICAgICAgICAgICAgICAgYXNrX2xheWVyLnJlc2V0KCkKICAgICAgICAgICAgICAgICAgICBmb3IgeCBpbiBxdWVzdF9saXN0OgogICAgICAgICAgICAgICAgICAgICAgICB4LmZ1bGxfcmVzZXQoKQogICAgICAgICAgICAgICAgICAgIHF1ZXN0X251bWIgPSAwCiAgICAgICAgICAgICAgICAgICAgZHJhd19hbnN3ZXIgPSBGYWxzZQogICAgICAgICAgICAgICAgICAgIGFzayA9IFRydWUKICAgICAgICAgICAgICAgICAgICBhc2tfdXBkYXRlID0gVHJ1ZQogICAgICAgICAgICAgICAgICAgIHNjcmVlbi5maWxsKCgyNTUsIDI1NSwgMjU1KSkKICAgICAgICAgICAgICAgICAgICBzY3JlZW4uYmxpdChsaW5lcywgKDAsIDApKQogICAgICAgICAgICAgICAgICAgIHNjcmVlbi5ibGl0KGJhcnJlbF90ZXN0LCAoMCwgMCkpCiAgICAgICAgICAgICAgICAgICAgIyBzY3JlZW5fdXBkYXRlID0gVHJ1ZQogICAgICAgICAgICAgICAgbm90X2ZvdW5kID0gRmFsc2UKCiAgICAgICAgaWYgc2NyZWVuX3VwZGF0ZToKICAgICAgICAgICAgcHlnYW1lLmRpc3BsYXkudXBkYXRlKCkKICAgICAgICAgICAgc2NyZWVuX3VwZGF0ZSA9IEZhbHNlCgogICAgICAgIGNsb2NrLnRpY2soRlBTKQoKICAgIHNhZmVfcXVpdCgpCgoKZGVmIG1vbl9zZXJpYWwoc2VyaWFsX2Rldik6CiAgICBzZXIgPSBzZXJpYWxfY29ubmVjdChzZXJpYWxfZGV2LCAxMTUyMDApCgogICAgYnV0dG9uX3BhdHQgPSByZS5jb21waWxlKHInQnsxLDF9WzAtOV17MSwyfScpCiAgICB5ZXNfcGF0dCA9IHJlLmNvbXBpbGUocidCX1lFUycpCiAgICBub19wYXR0ID0gcmUuY29tcGlsZShyJ0JfTk8nKQogICAgYXNrX3BhdHQgPSByZS5jb21waWxlKHInQl9BU0snKQogICAgcmVzX3BhdHQgPSByZS5jb21waWxlKHInQl9SRVMnKQogICAgYmVnaW5fcGF0dCA9IHJlLmNvbXBpbGUocidDQVJEX1BSRVNFTlQnKQogICAgY29ubl9wYXR0ID0gcmUuY29tcGlsZShyJ0NPTk5FQ1RFRCcpCiAgICBva19wYXR0ID0gcmUuY29tcGlsZShyJ09LJykKCiAgICB3aGlsZSBub3Qgc3RvcF9yZWFkLmlzX3NldCgpOgogICAgICAgIGlmIG5vdCBzZW5kX3F1ZXVlLmVtcHR5KCk6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIHNlcl93ciA9IHNlbmRfcXVldWUuZ2V0KCkKICAgICAgICAgICAgICAgIHNlci53cml0ZShzZXJfd3IpCiAgICAgICAgICAgICAgICBsb2cuZGVidWcoJ1dyaXRlIHRvIHNlcmlhbDonICsgc2VyX3dyKQogICAgICAgICAgICBleGNlcHQgc2VyaWFsLlNlcmlhbEV4Y2VwdGlvbiBhcyBlOgogICAgICAgICAgICAgICAgbG9nLmVycm9yKCdTZXJpYWwgd3JpdGUgZXJyb3I6ICcgKyBzdHIoZSkpCgogICAgICAgIHRyeToKICAgICAgICAgICAgY3VyciA9IHNlci5yZWFkbGluZSgpLnJzdHJpcCgnXHJcbicpCiAgICAgICAgZXhjZXB0IHNlcmlhbC5TZXJpYWxFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgbG9nLmVycm9yKCdTZXJpYWwgZXJyb3I6ICcgKyBzdHIoZSkpCiAgICAgICAgICAgIHRpbWUuc2xlZXAoMSkKICAgICAgICAgICAgc2VyID0gc2VyaWFsX2Nvbm5lY3Qoc2VyaWFsX2RldiwgMTE1MjAwKQogICAgICAgICAgICBjb250aW51ZQoKICAgICAgICBpZiBsZW4oY3VycikgPT0gMDoKICAgICAgICAgICAgY29udGludWUKCiAgICAgICAgYnV0dG9uX21hdGNoID0gcmUubWF0Y2goYnV0dG9uX3BhdHQsIGN1cnIpCiAgICAgICAgeWVzX21hdGNoID0gcmUubWF0Y2goeWVzX3BhdHQsIGN1cnIpCiAgICAgICAgbm9fbWF0Y2ggPSByZS5tYXRjaChub19wYXR0LCBjdXJyKQogICAgICAgIGFza19tYXRjaCA9IHJlLm1hdGNoKGFza19wYXR0LCBjdXJyKQogICAgICAgIHJlc19tYXRjaCA9IHJlLm1hdGNoKHJlc19wYXR0LCBjdXJyKQogICAgICAgIGJlZ2luX21hdGNoID0gcmUubWF0Y2goYmVnaW5fcGF0dCwgY3VycikKICAgICAgICBjb25uX21hdGNoID0gcmUubWF0Y2goY29ubl9wYXR0LCBjdXJyKQogICAgICAgIG9rX21hdGNoID0gcmUubWF0Y2gob2tfcGF0dCwgY3VycikKCiAgICAgICAgaWYgYnV0dG9uX21hdGNoIG9yIHllc19tYXRjaCBvciBub19tYXRjaCBvciByZXNfbWF0Y2g6CiAgICAgICAgICAgIHByZXNzZWRfcXVldWUucHV0KGN1cnIpCiAgICAgICAgICAgIGxvZy5kZWJ1ZygnUHJlc3NlZCAnICsgY3VyciArICcgYnV0dG9uJykKICAgICAgICBlbGlmIGJlZ2luX21hdGNoOgogICAgICAgICAgICBiZWdpbl9kcmF3LnNldCgpCiAgICAgICAgICAgIGxvZy5kZWJ1ZygnQmVnaW4gRFJBVycpCiAgICAgICAgZWxpZiBhc2tfbWF0Y2g6CiAgICAgICAgICAgIGhlbHBfcHJlc3NlZC5zZXQoKQogICAgICAgICAgICBsb2cuZGVidWcoJ0JfQVNLIFByZXNzZWQnKQogICAgICAgIGVsaWYgY29ubl9tYXRjaDoKICAgICAgICAgICAgY29ubl9vay5zZXQoKQogICAgICAgICAgICBsb2cuZGVidWcoJ0Nvbm5lY3Rpb24gZXN0YWJsaXNoZWQnKQogICAgICAgIGVsaWYgb2tfbWF0Y2g6CiAgICAgICAgICAgIG9rX2dldC5zZXQoKQogICAgICAgICAgICBsb2cuZGVidWcoJ0dldCBPSyBtc2cnKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIGxvZy53YXJuaW5nKCdHZXQgdW5rbm93biBmcm9tIHNlcmlhbDogJyArIGN1cnIpCgogICAgc2VyLmNsb3NlKCkKCgpkZWYgc2VyaWFsX2Nvbm5lY3QoZGV2LCBzcGVlZCk6CiAgICB0cnk6CiAgICAgICAgc2VyID0gc2VyaWFsLlNlcmlhbChkZXYsIHNwZWVkLCB0aW1lb3V0PTAuMSkKICAgIGV4Y2VwdCBzZXJpYWwuU2VyaWFsRXhjZXB0aW9uIGFzIGU6CiAgICAgICAgbG9nLmVycm9yKCdTZXJpYWwgQ29ubmVjdCBFcnJvcjogJyArIHN0cihlKSkKICAgICAgICBwcmludCAnQ29ubmVjdGlvbiBFcnJvcicKICAgIGVsc2U6CiAgICAgICAgbG9nLmluZm8oJ0Nvbm5lY3RlZCBzdWNjZXNzZnVsbHknKQogICAgICAgIHNlci53cml0ZVRpbWVvdXQgPSAwLjEKICAgICAgICByZXR1cm4gc2VyCgogICAgbG9nLmNyaXRpY2FsKCdGQUlMIHRvIGNvbm5lY3QuIEV4aXQuJykKICAgIHNhZmVfcXVpdCgpCgoKZGVmIGN0cmxfY19oYW5kbGVyKHNpZ251bSwgZnJhbWUpOgogICAgbG9nLmluZm8oJ0dldCBDdHJsLUMuJykKICAgIHNhZmVfcXVpdCgpCgoKZGVmIHNhZmVfcXVpdCgpOgogICAgcHJpbnQgJ0V4aXQuJwogICAgbG9nLmluZm8oJ0V4aXQuJykKICAgIGxvZ2dpbmcuc2h1dGRvd24oKQogICAgcHlnYW1lLnF1aXQoKQogICAgc3RvcF9yZWFkLnNldCgpCiAgICBmb3IgdGhyIGluIHRocmVhZHM6CiAgICAgICAgdGhyLmpvaW4oMikKICAgIHN5cy5leGl0KDApCgoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIG1haW4oKQ==
Main.java:1: error: illegal character: '#'
#!/usr/bin/python
^
Main.java:1: error: class, interface, or enum expected
#!/usr/bin/python
^
Main.java:3: error: '.' expected
import pygame
^
Main.java:4: error: ';' expected
import serial
^
Main.java:5: error: '.' expected
import time
^
Main.java:6: error: ';' expected
import re
^
Main.java:7: error: '.' expected
import Queue
^
Main.java:8: error: ';' expected
import logging
^
Main.java:9: error: class, interface, or enum expected
from logging.handlers import WatchedFileHandler
^
Main.java:9: error: '.' expected
from logging.handlers import WatchedFileHandler
^
Main.java:10: error: ';' expected
import threading
^
Main.java:11: error: '.' expected
import sys
^
Main.java:12: error: ';' expected
import signal
^
Main.java:13: error: '.' expected
import subprocess
^
Main.java:14: error: ';' expected
import os
^
Main.java:15: error: '.' expected
import websocket
^
Main.java:16: error: ';' expected
from websocket import create_connection
^
Main.java:16: error: '.' expected
from websocket import create_connection
^
Main.java:18: error: ';' expected
FPS = 30
^
Main.java:22: error: unclosed character literal
SERIAL_DEV = '/dev/ttyACM0'
^
Main.java:22: error: illegal line end in character literal
SERIAL_DEV = '/dev/ttyACM0'
^
Main.java:36: error: unclosed character literal
LOG_FORMAT = '[%(asctime)s] %(levelname)s: %(funcName)s: %(message)s'
^
Main.java:36: error: illegal line end in character literal
LOG_FORMAT = '[%(asctime)s] %(levelname)s: %(funcName)s: %(message)s'
^
Main.java:37: error: unclosed character literal
log = logging.getLogger('main_log')
^
Main.java:37: error: unclosed character literal
log = logging.getLogger('main_log')
^
Main.java:39: error: unclosed character literal
log_handler = WatchedFileHandler('screen.log')
^
Main.java:39: error: unclosed character literal
log_handler = WatchedFileHandler('screen.log')
^
Main.java:44: error: illegal character: '#'
# workaround for wrong buttons numbering
^
Main.java:59: error: unclosed character literal
'0': 'imgs/sim 0.png', # 0
^
Main.java:59: error: unclosed character literal
'0': 'imgs/sim 0.png', # 0
^
Main.java:59: error: illegal character: '#'
'0': 'imgs/sim 0.png', # 0
^
Main.java:60: error: unclosed character literal
'1': 'imgs/sim 1.png', # 1
^
Main.java:60: error: unclosed character literal
'1': 'imgs/sim 1.png', # 1
^
Main.java:60: error: illegal character: '#'
'1': 'imgs/sim 1.png', # 1
^
Main.java:61: error: unclosed character literal
'2': 'imgs/sim 2.png', # 2
^
Main.java:61: error: unclosed character literal
'2': 'imgs/sim 2.png', # 2
^
Main.java:61: error: illegal character: '#'
'2': 'imgs/sim 2.png', # 2
^
Main.java:62: error: unclosed character literal
'3': 'imgs/sim 3.png', # 3
^
Main.java:62: error: unclosed character literal
'3': 'imgs/sim 3.png', # 3
^
Main.java:62: error: illegal character: '#'
'3': 'imgs/sim 3.png', # 3
^
Main.java:63: error: unclosed character literal
'4': 'imgs/sim 4.png', # 4
^
Main.java:63: error: unclosed character literal
'4': 'imgs/sim 4.png', # 4
^
Main.java:63: error: illegal character: '#'
'4': 'imgs/sim 4.png', # 4
^
Main.java:64: error: unclosed character literal
'5': 'imgs/sim 5.png', # 5
^
Main.java:64: error: unclosed character literal
'5': 'imgs/sim 5.png', # 5
^
Main.java:64: error: illegal character: '#'
'5': 'imgs/sim 5.png', # 5
^
Main.java:65: error: unclosed character literal
'6': 'imgs/sim 6.png', # 6
^
Main.java:65: error: unclosed character literal
'6': 'imgs/sim 6.png', # 6
^
Main.java:65: error: illegal character: '#'
'6': 'imgs/sim 6.png', # 6
^
Main.java:66: error: unclosed character literal
'7': 'imgs/sim 7.png', # 7
^
Main.java:66: error: unclosed character literal
'7': 'imgs/sim 7.png', # 7
^
Main.java:66: error: illegal character: '#'
'7': 'imgs/sim 7.png', # 7
^
Main.java:67: error: unclosed character literal
'8': 'imgs/sim 8.png', # 8
^
Main.java:67: error: unclosed character literal
'8': 'imgs/sim 8.png', # 8
^
Main.java:67: error: illegal character: '#'
'8': 'imgs/sim 8.png', # 8
^
Main.java:68: error: unclosed character literal
'9': 'imgs/sim 9.png' # 9
^
Main.java:68: error: unclosed character literal
'9': 'imgs/sim 9.png' # 9
^
Main.java:68: error: illegal character: '#'
'9': 'imgs/sim 9.png' # 9
^
Main.java:74: error: unclosed character literal
(1, 1, 0): 'imgs/110-mercury2.jpg',
^
Main.java:74: error: unclosed character literal
(1, 1, 0): 'imgs/110-mercury2.jpg',
^
Main.java:75: error: unclosed character literal
(1, 2, 0): 'imgs/120-venera2.jpg',
^
Main.java:75: error: unclosed character literal
(1, 2, 0): 'imgs/120-venera2.jpg',
^
Main.java:76: error: unclosed character literal
(1, 2, 3): 'imgs/123-1-hz2.jpg',
^
Main.java:76: error: unclosed character literal
(1, 2, 3): 'imgs/123-1-hz2.jpg',
^
Main.java:77: error: unclosed character literal
(1, 3, 1): 'imgs/131-earth2.jpg',
^
Main.java:77: error: unclosed character literal
(1, 3, 1): 'imgs/131-earth2.jpg',
^
Main.java:78: error: unclosed character literal
(1, 4, 2): 'imgs/142-mars2.jpg',
^
Main.java:78: error: unclosed character literal
(1, 4, 2): 'imgs/142-mars2.jpg',
^
Main.java:79: error: unclosed character literal
(1, 5, 1): 'imgs/151-jupiter2.jpg',
^
Main.java:79: error: unclosed character literal
(1, 5, 1): 'imgs/151-jupiter2.jpg',
^
Main.java:80: error: unclosed character literal
(1, 6, 0): 'imgs/160-saturn2.jpg',
^
Main.java:80: error: unclosed character literal
(1, 6, 0): 'imgs/160-saturn2.jpg',
^
Main.java:81: error: unclosed character literal
(1, 7, 2): 'imgs/172-uran2.jpg',
^
Main.java:81: error: unclosed character literal
(1, 7, 2): 'imgs/172-uran2.jpg',
^
Main.java:82: error: unclosed character literal
(1, 8, 6): 'imgs/186-neptun2.jpg',
^
Main.java:82: error: unclosed character literal
(1, 8, 6): 'imgs/186-neptun2.jpg',
^
Main.java:83: error: unclosed character literal
(1, 9, 1): 'imgs/191-pluton2.jpg',
^
Main.java:83: error: unclosed character literal
(1, 9, 1): 'imgs/191-pluton2.jpg',
^
Main.java:84: error: unclosed character literal
(2, 3, 4): 'imgs/234-2-hz2.jpg',
^
Main.java:84: error: unclosed character literal
(2, 3, 4): 'imgs/234-2-hz2.jpg',
^
Main.java:85: error: unclosed character literal
(2, 4, 2): 'imgs/242-3-hz2.jpg',
^
Main.java:85: error: unclosed character literal
(2, 4, 2): 'imgs/242-3-hz2.jpg',
^
Main.java:86: error: unclosed character literal
(3, 3, 1): 'imgs/331-4-hz2.jpg',
^
Main.java:86: error: unclosed character literal
(3, 3, 1): 'imgs/331-4-hz2.jpg',
^
Main.java:87: error: unclosed character literal
(3, 4, 1): 'imgs/341-5-hz2.jpg',
^
Main.java:87: error: unclosed character literal
(3, 4, 1): 'imgs/341-5-hz2.jpg',
^
Main.java:88: error: unclosed character literal
(3, 4, 4): 'imgs/344-6-hz2.jpg',
^
Main.java:88: error: unclosed character literal
(3, 4, 4): 'imgs/344-6-hz2.jpg',
^
Main.java:89: error: unclosed character literal
(3, 4, 5): 'imgs/345-7-hz2.jpg',
^
Main.java:89: error: unclosed character literal
(3, 4, 5): 'imgs/345-7-hz2.jpg',
^
Main.java:90: error: unclosed character literal
(3, 5, 3): 'imgs/353-8-hz2.jpg',
^
Main.java:90: error: unclosed character literal
(3, 5, 3): 'imgs/353-8-hz2.jpg',
^
Main.java:91: error: unclosed character literal
(4, 5, 6): 'imgs/456-9-hz2.jpg',
^
Main.java:91: error: unclosed character literal
(4, 5, 6): 'imgs/456-9-hz2.jpg',
^
Main.java:92: error: unclosed character literal
(4, 6, 2): 'imgs/462-10-hz2.jpg',
^
Main.java:92: error: unclosed character literal
(4, 6, 2): 'imgs/462-10-hz2.jpg',
^
Main.java:93: error: unclosed character literal
(5, 6, 7): 'imgs/567-11-hz2.jpg',
^
Main.java:93: error: unclosed character literal
(5, 6, 7): 'imgs/567-11-hz2.jpg',
^
Main.java:94: error: unclosed character literal
(5, 7, 5): 'imgs/575-12-hz2.jpg',
^
Main.java:94: error: unclosed character literal
(5, 7, 5): 'imgs/575-12-hz2.jpg',
^
100 errors