gr = love. graphics
win = love. window
lk = love. keyboard
require ( "button" )
require ( "t" )
function love. load( )
local loading = { }
loading = serialize. load( "records.lua" )
font = gr. newFont( "NotoSans.ttf" , 14 )
mini = gr. newFont( "NotoSans.ttf" , 10 )
big = gr. newFont( "NotoSans.ttf" , 30 )
flag = nil --Flag = nil -menu, Flag = 1 -records, Flag = 2 -type game, Flag = 3 -type game standart, Flag = 4 -type game impulse, Flag = 5 -type game Invers, Flag = 6 -type game Unreal
kube = { x = 96 , y = 196 , colx = 8 , coly = 8 }
speed = 1
timer = 0
umber = { }
records = { { "Standart" , 0 } , { "Impulse" , 0 } , { "Invers" , 0 } , { "Unreal" , 0 } , { "XY diagonal" , 0 } , { "Perpendiculars" , 0 } }
if loading and # loading > 0 then
for i = 1 , # loading do
records[ i] [ 2 ] = loading[ i]
end
end
score = 0
mb = { utton: create( 200 - font: getWidth( ">Play<" ) / 2 , 125 , ">Play<" ) , utton: create( 200 - font: getWidth( ">Records<" ) / 2 , 160 , ">Records<" ) , utton: create( 200 - font: getWidth( ">Exit<" ) / 2 , 195 , ">Exit<" ) }
tgb = { utton: create( 200 - font: getWidth( ">Standart<" ) / 2 , 60 , ">Standart<" ) , utton: create( 200 - font: getWidth( ">Impulse<" ) / 2 , 90 , ">Impulse<" ) , utton: create( 200 - font: getWidth( ">Invers<" ) / 2 , 120 , ">Invers<" ) , utton: create( 200 - font: getWidth( ">Unreal<" ) / 2 , 150 , ">Unreal<" ) , utton: create( 200 - font: getWidth( ">XY diagonal<" ) / 2 , 180 , ">XY diagonal<" ) , utton: create( 200 - font: getWidth( ">Perpendiculars<" ) / 2 , 210 , ">Perpendiculars<" ) }
back = utton: create( 200 - font: getWidth( " >Back< " ) / 2 , 300 , " >Back< " )
r = utton: create( 200 - font: getWidth( " >Restart< " ) / 2 , 250 , " >Restart< " )
end
local function restart( )
kube = { x = 96 , y = 196 , colx = 8 , coly = 8 , speed = 350 }
speed = 1
timer = 0
umber = { }
score = 0
toch = nil
end
function love. update( dt)
math.randomseed ( math.random ( os.time ( ) , os.time ( ) * 100 ) )
if toch then
r: update( dt)
back: update( dt)
end
if not flag then
for i = 1 , # mb do
mb[ i] : update( dt)
end
elseif flag == 1 then
back: update( dt)
elseif flag == 2 then
for i = 1 , # tgb do
tgb[ i] : update( dt)
end
elseif flag == 3 then
if toch then
if records[ 1 ] [ 2 ] < score then
records[ 1 ] [ 2 ] = score
end
end
timer = timer+ 10 * dt
if # umber > 0 and not toch then
for i = 1 , # umber do
if umber[ i] and umber[ i] [ 2 ] > 400 then
table.remove ( umber, i)
end
if umber[ i] then
umber[ i] [ 2 ] = umber[ i] [ 2 ] + umber[ i] [ 5 ] * dt* speed
end
end
end
if timer >= 4 / ( speed/ 2 ) and not toch then
timer = 0
speed = speed + 0.01
score = score + 1
table.insert ( umber, { math.random ( 0 , 99 ) , 0 , 4 , 4 , 50 } ) --x,y,w,h,speed
end
if lk. isDown( "d" ) and not toch then
kube. x = kube. x+ 400 * dt
end
if lk. isDown( "a" ) and not toch then
kube. x = kube. x- 400 * dt
end
if kube. x >= 191 then
kube. x = 191
elseif kube. x <= 8 then
kube. x = 8
end
elseif flag == 4 then
if toch then
if records[ 2 ] [ 2 ] < score then
records[ 2 ] [ 2 ] = score
end
end
timer = timer+ 10 * dt
if # umber > 0 and not toch then
for i = 1 , # umber do
if umber[ i] and umber[ i] [ 2 ] > 400 then
table.remove ( umber, i)
end
if umber[ i] then
umber[ i] [ 2 ] = umber[ i] [ 2 ] + umber[ i] [ 5 ] * dt* speed
end
end
end
if timer >= 15 / ( speed/ 2 ) and not toch then
timer = 0
for x = 0 , 5 do
table.insert ( umber, { math.random ( 0 , 99 ) , 0 , 4 , 4 , 50 } ) --x,y,w,h,speed
speed = speed + 0.01
score = score + 1
end
end
if lk. isDown( "d" ) and not toch then
kube. x = kube. x+ 400 * dt
end
if lk. isDown( "a" ) and not toch then
kube. x = kube. x- 400 * dt
end
if kube. x >= 191 then
kube. x = 191
elseif kube. x <= 8 then
kube. x = 8
end
elseif flag == 5 then
if toch then
if records[ 3 ] [ 2 ] < score then
records[ 3 ] [ 2 ] = score
end
end
timer = timer+ 10 * dt
if # umber > 0 and not toch then
for i = 1 , # umber do
if umber[ i] and ( umber[ i] [ 2 ] > 400 or umber[ i] [ 2 ] < - 10 ) then
table.remove ( umber, i)
end
if umber[ i] then
if umber[ i] [ 6 ] == "d" then
umber[ i] [ 2 ] = umber[ i] [ 2 ] + umber[ i] [ 5 ] * dt* speed
else
umber[ i] [ 2 ] = umber[ i] [ 2 ] - umber[ i] [ 5 ] * dt* speed
end
end
end
end
if timer >= 8 / ( speed/ 2 ) and not toch then
timer = 0
table.insert ( umber, { math.random ( 0 , 99 ) , 0 , 4 , 4 , 50 , "d" } ) --x,y,w,h,speed
table.insert ( umber, { math.random ( 0 , 99 ) , 400 , 4 , 4 , 50 , "u" } )
speed = speed + 0.02
score = score + 2
end
if lk. isDown( "d" ) and not toch then
kube. x = kube. x+ 400 * dt
end
if lk. isDown( "a" ) and not toch then
kube. x = kube. x- 400 * dt
end
if kube. x >= 191 then
kube. x = 191
elseif kube. x <= 8 then
kube. x = 8
end
elseif flag == 6 then
if toch then
if records[ 4 ] [ 2 ] < score then
records[ 4 ] [ 2 ] = score
end
end
timer = timer+ 10 * dt
if # umber > 0 and not toch then
for i = 1 , # umber do
if umber[ i] and umber[ i] [ 2 ] > 400 then
table.remove ( umber, i)
end
if umber[ i] then
umber[ i] [ 2 ] = umber[ i] [ 2 ] + umber[ i] [ 5 ] * dt* speed
end
end
end
if timer >= 1 / ( speed/ 2 ) and not toch then
timer = 0
speed = speed + 0.01
score = score + 1
table.insert ( umber, { math.random ( 0 , 99 ) , 0 , 4 , 4 , 50 } ) --x,y,w,h,speed
end
if lk. isDown( "d" ) and not toch then
kube. x = kube. x+ 400 * dt
end
if lk. isDown( "a" ) and not toch then
kube. x = kube. x- 400 * dt
end
if kube. x >= 191 then
kube. x = 191
elseif kube. x <= 8 then
kube. x = 8
end
elseif flag == 7 then
if toch then
if records[ 5 ] [ 2 ] < score then
records[ 5 ] [ 2 ] = score
end
end
timer = timer+ 10 * dt
if # umber > 0 and not toch then
for i = 1 , # umber do
if umber[ i] and ( umber[ i] [ 2 ] > 400 or umber[ i] [ 2 ] < - 10 ) then
table.remove ( umber, i)
end
if umber[ i] then
if umber[ i] [ 6 ] == "d" then
umber[ i] [ 2 ] = umber[ i] [ 2 ] + umber[ i] [ 5 ] * dt* speed
umber[ i] [ 1 ] = umber[ i] [ 1 ] + umber[ i] [ 5 ] * dt* speed/ 5
elseif umber[ i] [ 6 ] == "u" then
umber[ i] [ 2 ] = umber[ i] [ 2 ] - umber[ i] [ 5 ] * dt* speed
umber[ i] [ 1 ] = umber[ i] [ 1 ] - umber[ i] [ 5 ] * dt* speed/ 5
end
end
end
end
if timer >= 8 / ( speed/ 2 ) and not toch then
timer = 0
table.insert ( umber, { math.random ( 0 , 99 ) , 0 , 4 , 4 , 50 , "d" } ) --x,y,w,h,speed
table.insert ( umber, { math.random ( 0 , 99 ) , 400 , 4 , 4 , 50 , "u" } )
speed = speed + 0.02
score = score + 2
end
if lk. isDown( "d" ) and not toch then
kube. x = kube. x+ 400 * dt
end
if lk. isDown( "a" ) and not toch then
kube. x = kube. x- 400 * dt
end
if kube. x >= 191 then
kube. x = 191
elseif kube. x <= 8 then
kube. x = 8
end
elseif flag == 8 then
if toch then
if records[ 6 ] [ 2 ] < score then
records[ 6 ] [ 2 ] = score
end
end
timer = timer+ 10 * dt
if # umber > 0 and not toch then
for i = 1 , # umber do
if umber[ i] and ( umber[ i] [ 2 ] > 400 or umber[ i] [ 2 ] < - 10 or umber[ i] [ 1 ] > 420 or umber[ i] [ 1 ] < - 10 ) then
table.remove ( umber, i)
end
if umber[ i] then
if umber[ i] [ 6 ] == "d" then
umber[ i] [ 2 ] = umber[ i] [ 2 ] + umber[ i] [ 5 ] * dt* speed
elseif umber[ i] [ 6 ] == "u" then
umber[ i] [ 2 ] = umber[ i] [ 2 ] - umber[ i] [ 5 ] * dt* speed
elseif umber[ i] [ 6 ] == "l" then
umber[ i] [ 1 ] = umber[ i] [ 1 ] + umber[ i] [ 5 ] * dt* speed
elseif umber[ i] [ 6 ] == "r" then
umber[ i] [ 1 ] = umber[ i] [ 1 ] - umber[ i] [ 5 ] * dt* speed
end
end
end
end
if timer >= 16 / ( speed/ 2 ) and not toch then
timer = 0
table.insert ( umber, { math.random ( 0 , 99 ) , 0 , 4 , 4 , 50 , "d" } ) --x,y,w,h,speed
table.insert ( umber, { math.random ( 0 , 99 ) , 400 , 4 , 4 , 50 , "u" } )
table.insert ( umber, { 0 , math.random ( 0 , 99 ) * 4 , 4 , 4 , 25 , "l" } )
table.insert ( umber, { 100 , math.random ( 0 , 99 ) * 4 , 4 , 4 , 25 , "r" } )
speed = speed + 0.04
score = score + 4
end
if lk. isDown( "d" ) and not toch then
kube. x = kube. x+ 400 * dt
end
if lk. isDown( "a" ) and not toch then
kube. x = kube. x- 400 * dt
end
if lk. isDown( "w" ) and not toch then
kube. y = kube. y- 400 * dt
end
if lk. isDown( "s" ) and not toch then
kube. y = kube. y+ 400 * dt
end
if kube. x >= 191 then
kube. x = 191
elseif kube. x <= 8 then
kube. x = 8
end
if kube. y <= 0 then
kube. y = 0
elseif kube. y >= 384 then
kube. y = 384
end
end
end
function love. draw( )
gr. setFont( font)
if not flag then
for i = 1 , # mb do
mb[ i] : draw( )
end
elseif flag == 1 then
back: draw( )
for i = 1 , # records do
gr. setColor( 255 , 255 , 255 )
gr. print ( records[ i] [ 1 ] .. " ---------- score: " .. records[ i] [ 2 ] , win. getWidth( ) / 2 - font: getWidth( records[ i] [ 1 ] .. " ---------- score: " .. records[ i] [ 2 ] ) / 2 , i* 20 + 70 )
end
elseif flag == 2 then
gr. setColor( 0 , 255 , 0 )
gr. print ( "Select the type of game" , win. getWidth( ) / 2 - font: getWidth( "Select the type of game" ) / 2 )
gr. setColor( 255 , 255 , 255 )
for i = 1 , # tgb do
tgb[ i] : draw( )
end
elseif flag >= 3 then
if # umber > 0 then
gr. setColor( 255 , 0 , 0 )
for i = 1 , # umber do
if ( umber[ i] [ 1 ] * 4 >= math.floor ( kube. x- 12 ) and umber[ i] [ 1 ] * 4 <= math.floor ( kube. x+ 8 ) and umber[ i] [ 2 ] >= kube. y- 4 and umber[ i] [ 2 ] <= kube. y+ 16 ) or ( umber[ i] [ 1 ] * 4 >= math.floor ( 400 - kube. x- 12 ) and umber[ i] [ 1 ] * 4 <= math.floor ( 400 - kube. x+ 8 ) and umber[ i] [ 2 ] >= kube. y- 4 and umber[ i] [ 2 ] <= kube. y+ 16 ) then
toch = true
end
gr. rectangle( "fill" , umber[ i] [ 1 ] * 4 , umber[ i] [ 2 ] , umber[ i] [ 3 ] , umber[ i] [ 4 ] )
end
end
if toch then
gr. setColor( 100 , 0 , 0 )
else
gr. setColor( 255 , 255 , 255 )
end
gr. rectangle( "fill" , math.floor ( kube. x- 8 ) , math.floor ( kube. y) , 16 , 16 )
gr. rectangle( "fill" , math.floor ( 400 - kube. x- 8 ) , math.floor ( kube. y) , 16 , 16 )
gr. setColor( 255 , 255 , 255 )
gr. line( 200 , 0 , 200 , 400 )
if not toch then
gr. print ( "Score: " .. score.. " Speed:" .. string.format ( " %.1f" , speed) , 0 , 380 )
else
gr. setFont( big)
gr. print ( "Score: " .. score.. "\n Record: " .. records[ flag- 2 ] [ 2 ] , 100 , 145 )
end
end
if toch then
gr. setColor( 0 , 0 , 0 )
gr. rectangle( "fill" , 100 , 240 , 200 , 100 )
r: draw( )
back: draw( )
end
gr. setColor( 255 , 255 , 255 )
gr. setFont( mini)
gr. print ( "By Sfabrikan" )
end
function love. mousepressed( x, y, button) --это клик мыши
if flag == 2 then
for i = 1 , # tgb do
if tgb[ i] : mpress( x, y, button) then
if i == 1 then
flag = 3
elseif i == 2 then
flag = 4
elseif i == 3 then
flag = 5
elseif i == 4 then
flag = 6
elseif i == 5 then
flag = 7
elseif i == 6 then
flag = 8
end
end
end
elseif flag == 1 then
if back: mpress( x, y, button) then
flag = nil
end
elseif not flag then
for i = 1 , # mb do
if mb[ i] : mpress( x, y, button) then
if i == 1 then
flag = 2
elseif i == 2 then
flag = 1
elseif i == 3 then
love. event. quit( )
end
end
end
end
if toch then
if r: mpress( x, y, button) then
restart( )
elseif back: mpress( x, y, button) then
restart( )
flag = nil
end
end
end
function love. keypressed( key)
if key == "escape" and flag then
if flag > 2 and toch then
restart( )
flag = nil
elseif flag <= 2 then
flag = nil
end
elseif key == "r" and flag and flag > 2 and toch then
toch = nil
kube = { x = 96 , y = 196 , colx = 8 , coly = 8 }
speed = 1
timer = 0
score = 0
umber = { }
end
end
function love. textinput ( t)
end
function love. quit( )
local s = { }
for i = 1 , # records do
table.insert ( s, records[ i] [ 2 ] )
end
serialize. save( s, "records.lua" )
end
--button
utton = { }
function utton: create( x, y, text) --Собсвтенно положение и текст внутри кнопки
local t = { }
t. toch = false --Завел этот булерн для косания
t. x = x
t. y = y
t. text = text
self. __index = self
return setmetatable ( t, self)
end
function utton: update( dt) --обновляем
self. toch = false --карочи касание фалс
local x = love. mouse. getX( ) --Воруем положение мышки х
local y = love. mouse. getY( ) --Воруем положение мышки y
if x > self. x
and x < self. x + font: getWidth( self. text) --К положению кнопки + ширина текста self.text
and y < self. y + font: getHeight( )
and y > self. y then --вот такое вот ограменное условие!
self. toch = true --Если условие выполнено, до все гуд тру
end
end
function utton: draw( ) --рисуем
love. graphics. setColor( 255 , 255 , 255 )
if self. toch then --если true то
love. graphics. setColor( 255 , 0 , 0 )
end
love. graphics. setFont( font)
love. graphics. rectangle( "line" , self. x- 2 , self. y- 2 , font: getWidth( self. text) + 4 , font: getHeight( ) + 4 )
love. graphics. print ( self. text, self. x, self. y)
end
function utton: mpress( x, y, button)
if self. toch then
return true
end
return false
end
--[[
**Modified for LOVE**
Save Table to File
Load Table from File
v 1.0
Lua 5.2 compatible
Only Saves Tables, Numbers, Strings, and Booleans
Insides Table References are saved
Does not save Userdata, Metatables, Functions and indices of these
----------------------------------------------------
successful,errmsg = save( table,filename )
----------------------------------------------------
table = load( filename )
----------------------------------------------------
Licensed under the same terms as Lua itself.
]] --
-- declare local variables
--// exportstring( string )
--// returns a "Lua" portable version of the string
local function exportstring( s )
return string.format ( "%q" , s)
end
local function createSubDir( path)
local dir, name, ext = path: match( '^(.-)([^\\ /]-)%.?([^\\ /%.]*)$' )
if # name == 0 then name = ext; ext = '' end
local dirpath = ''
for subfolder in dir: gmatch( '([^\\ /]-[\\ /])' ) do
dirpath = dirpath.. subfolder
if love. filesystem. isFile( dirpath) then
return 'Cannot save table, ' .. dirpath.. ' is a file'
end
if not love. filesystem. exists( dirpath) then
love. filesystem. mkdir( dirpath)
end
end
end
local insert = function ( t, v)
if t. len then
t. len = t. len+ 1
t[ t. len] = v
return
end
table.insert ( t, v)
end
serialize = { }
--// The Save Function
function serialize. save( tbl, filename )
local charS, charE = "\t " , "\n "
local err = createSubDir( filename)
if err then return false , err end
local file = love. filesystem. newFile( filename)
file: open( 'w' )
-- initiate variables for save procedure
local tables, lookup = { tbl; len = 1 } , { [ tbl] = 1 }
file: write ( "return {" .. charE )
for idx, t in ipairs ( tables ) do
file: write ( "-- Table: {" .. idx.. "}" .. charE )
file: write ( "{" .. charE )
local thandled = { }
for i, v in ipairs ( t ) do
thandled[ i] = true
local stype = type ( v )
-- only handle value
if stype == "table" then
if not lookup[ v] then
insert( tables, v )
lookup[ v] = # tables
end
file: write ( charS.. "{" .. lookup[ v] .. "}," .. charE )
elseif stype == "string" then
file: write ( charS.. exportstring( v ) .. "," .. charE )
elseif stype == "number" or stype == 'boolean' then
file: write ( charS.. tostring ( v ) .. "," .. charE )
end
end
for i, v in pairs ( t ) do
-- escape handled values
if ( not thandled[ i] ) then
local str = ""
local stype = type ( i )
-- handle index
-- if stype == "table" then
-- if not lookup[i] then
-- insert( tables,i )
-- lookup[i] = #tables
-- end
-- str = charS.."[{"..lookup[i].."}]="
if stype == "string" then
-- elseif stype == "string" then
str = charS.. "[" .. exportstring( i ) .. "]="
elseif stype == "number" or stype == 'boolean' then
str = charS.. "[" .. tostring ( i ) .. "]="
end
if str ~= "" then
stype = type ( v )
-- handle value
if stype == "table" then
if not lookup[ v] then
insert( tables, v )
lookup[ v] = # tables
end
file: write ( str.. "{" .. lookup[ v] .. "}," .. charE )
elseif stype == "string" then
file: write ( str.. exportstring( v ) .. "," .. charE )
elseif stype == "number" or stype == 'boolean' then
file: write ( str.. tostring ( v ) .. "," .. charE )
end
end
end
end
file: write ( "}," .. charE )
end
file: write ( "}" )
file: close( )
return true
end
--// The Load Function
function serialize. load( filename )
if not love. filesystem. exists( filename) then return end
local tables = love. filesystem. load( filename) ( )
for idx = 1 ,# tables do
local tolinki = { }
for i, v in pairs ( tables[ idx] ) do
if type ( v ) == "table" then
tables[ idx] [ i] = tables[ v[ 1 ] ]
end
if type ( i ) == "table" and tables[ i[ 1 ] ] then
insert( tolinki, { i, tables[ i[ 1 ] ] } )
end
end
-- link indices
for _, v in ipairs ( tolinki ) do
tables[ idx] [ v[ 2 ] ] , tables[ idx] [ v[ 1 ] ] = tables[ idx] [ v[ 1 ] ] , nil
end
end
return tables[ 1 ]
end
-- ChillCode
Z3IgPSBsb3ZlLmdyYXBoaWNzCndpbiA9IGxvdmUud2luZG93CmxrID0gbG92ZS5rZXlib2FyZApyZXF1aXJlKCJidXR0b24iKQpyZXF1aXJlKCJ0IikKCmZ1bmN0aW9uIGxvdmUubG9hZCgpCmxvY2FsIGxvYWRpbmcgPSB7fQpsb2FkaW5nID0gc2VyaWFsaXplLmxvYWQoInJlY29yZHMubHVhIikKZm9udCA9IGdyLm5ld0ZvbnQoIk5vdG9TYW5zLnR0ZiIsMTQpCm1pbmkgPSBnci5uZXdGb250KCJOb3RvU2Fucy50dGYiLDEwKQpiaWcgPSBnci5uZXdGb250KCJOb3RvU2Fucy50dGYiLDMwKQpmbGFnID0gbmlsIC0tRmxhZyA9IG5pbCAtbWVudSwgRmxhZyA9IDEgLXJlY29yZHMsIEZsYWcgPSAyIC10eXBlIGdhbWUsIEZsYWcgPSAzIC10eXBlIGdhbWUgc3RhbmRhcnQsIEZsYWcgPSA0IC10eXBlIGdhbWUgaW1wdWxzZSwgRmxhZyA9IDUgLXR5cGUgZ2FtZSBJbnZlcnMsIEZsYWcgPSA2IC10eXBlIGdhbWUgVW5yZWFsCmt1YmUgPSB7eCA9IDk2LCB5ID0gMTk2LCBjb2x4ID0gOCwgY29seSA9IDh9CnNwZWVkID0gMQp0aW1lciA9IDAKdW1iZXIgPSB7fQpyZWNvcmRzID0ge3siU3RhbmRhcnQiLCAwfSx7IkltcHVsc2UiLCAwfSx7IkludmVycyIsIDB9LHsiVW5yZWFsIiwgMH0seyJYWSBkaWFnb25hbCIsIDB9LHsiUGVycGVuZGljdWxhcnMiLCAwfX0KaWYgbG9hZGluZyBhbmQgI2xvYWRpbmcgPiAwIHRoZW4KCWZvciBpID0gMSwgI2xvYWRpbmcgZG8KCQlyZWNvcmRzW2ldWzJdID0gbG9hZGluZ1tpXQoJZW5kCmVuZApzY29yZSA9IDAKCW1iID0ge3V0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiPlBsYXk8IikvMiwxMjUsIj5QbGF5PCIpLHV0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiPlJlY29yZHM8IikvMiwxNjAsIj5SZWNvcmRzPCIpLHV0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiPkV4aXQ8IikvMiwxOTUsIj5FeGl0PCIpfQoJdGdiID0ge3V0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiPlN0YW5kYXJ0PCIpLzIsNjAsIj5TdGFuZGFydDwiKSx1dHRvbjpjcmVhdGUoMjAwLWZvbnQ6Z2V0V2lkdGgoIj5JbXB1bHNlPCIpLzIsOTAsIj5JbXB1bHNlPCIpLHV0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiPkludmVyczwiKS8yLDEyMCwiPkludmVyczwiKSx1dHRvbjpjcmVhdGUoMjAwLWZvbnQ6Z2V0V2lkdGgoIj5VbnJlYWw8IikvMiwxNTAsIj5VbnJlYWw8IiksdXR0b246Y3JlYXRlKDIwMC1mb250OmdldFdpZHRoKCI+WFkgZGlhZ29uYWw8IikvMiwxODAsIj5YWSBkaWFnb25hbDwiKSx1dHRvbjpjcmVhdGUoMjAwLWZvbnQ6Z2V0V2lkdGgoIj5QZXJwZW5kaWN1bGFyczwiKS8yLDIxMCwiPlBlcnBlbmRpY3VsYXJzPCIpfQoJYmFjayA9IHV0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiID5CYWNrPCAiKS8yLDMwMCwiID5CYWNrPCAiKQoJciA9IHV0dG9uOmNyZWF0ZSgyMDAtZm9udDpnZXRXaWR0aCgiID5SZXN0YXJ0PCAiKS8yLDI1MCwiID5SZXN0YXJ0PCAiKQplbmQKCmxvY2FsIGZ1bmN0aW9uIHJlc3RhcnQoKQoJa3ViZSA9IHt4ID0gOTYsIHkgPSAxOTYsIGNvbHggPSA4LCBjb2x5ID0gOCwgc3BlZWQgPSAzNTB9CglzcGVlZCA9IDEKCXRpbWVyID0gMAoJdW1iZXIgPSB7fQkKCXNjb3JlID0gMAoJdG9jaCA9IG5pbAplbmQKCmZ1bmN0aW9uIGxvdmUudXBkYXRlKGR0KQptYXRoLnJhbmRvbXNlZWQobWF0aC5yYW5kb20ob3MudGltZSgpLCBvcy50aW1lKCkqMTAwKSkKCWlmIHRvY2ggdGhlbgoJCXI6dXBkYXRlKGR0KQoJCWJhY2s6dXBkYXRlKGR0KQoJZW5kCglpZiBub3QgZmxhZyB0aGVuCgkJZm9yIGkgPSAxLCAjbWIgZG8KCQkJbWJbaV06dXBkYXRlKGR0KQoJCWVuZAoJZWxzZWlmIGZsYWcgPT0gMSB0aGVuCgkJYmFjazp1cGRhdGUoZHQpCgllbHNlaWYgZmxhZyA9PSAyIHRoZW4KCQlmb3IgaSA9IDEsICN0Z2IgZG8KCQkJdGdiW2ldOnVwZGF0ZShkdCkKCQllbmQJCgllbHNlaWYgZmxhZyA9PSAzIHRoZW4KCQlpZiB0b2NoIHRoZW4KCQkJaWYgcmVjb3Jkc1sxXVsyXSA8IHNjb3JlIHRoZW4KCQkJCXJlY29yZHNbMV1bMl0gPSBzY29yZQoJCQllbmQKCQllbmQKCQl0aW1lciA9IHRpbWVyKzEwKmR0CgkJaWYgI3VtYmVyID4gMCBhbmQgbm90IHRvY2ggdGhlbgoJCQlmb3IgaSA9IDEsICN1bWJlciBkbwoJCQkJaWYgdW1iZXJbaV0gYW5kIHVtYmVyW2ldWzJdID4gNDAwIHRoZW4KCQkJCQl0YWJsZS5yZW1vdmUodW1iZXIsaSkKCQkJCWVuZAoJCQkJaWYgdW1iZXJbaV0gdGhlbgoJCQkJCXVtYmVyW2ldWzJdID0gdW1iZXJbaV1bMl0gKyB1bWJlcltpXVs1XSpkdCpzcGVlZAoJCQkJZW5kCgkJCWVuZAoJCWVuZAoJCWlmIHRpbWVyID49IDQvKHNwZWVkLzIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCXRpbWVyID0gMAoJCQlzcGVlZCA9IHNwZWVkICsgMC4wMQoJCQlzY29yZSA9IHNjb3JlICsgMQoJCQl0YWJsZS5pbnNlcnQodW1iZXIsIHttYXRoLnJhbmRvbSgwLDk5KSwgMCwgNCwgNCwgNTB9KS0teCx5LHcsaCxzcGVlZAoJCWVuZAoJCWlmIGxrLmlzRG93bigiZCIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCWt1YmUueCA9IGt1YmUueCsgNDAwKmR0CgkJZW5kCgkJaWYgbGsuaXNEb3duKCJhIikgYW5kIG5vdCB0b2NoIHRoZW4KCQkJa3ViZS54ID0ga3ViZS54LSA0MDAqZHQKCQllbmQKCQlpZiBrdWJlLnggPj0gMTkxIHRoZW4KCQkJa3ViZS54ID0gMTkxCgkJZWxzZWlmIGt1YmUueCA8PSA4IHRoZW4KCQkJa3ViZS54ID0gOAoJCWVuZAoJZWxzZWlmIGZsYWcgPT0gNCB0aGVuCgkJaWYgdG9jaCB0aGVuCgkJCWlmIHJlY29yZHNbMl1bMl0gPCBzY29yZSB0aGVuCgkJCQlyZWNvcmRzWzJdWzJdID0gc2NvcmUKCQkJZW5kCgkJZW5kCgkJdGltZXIgPSB0aW1lcisxMCpkdAoJCWlmICN1bWJlciA+IDAgYW5kIG5vdCB0b2NoIHRoZW4KCQkJZm9yIGkgPSAxLCAjdW1iZXIgZG8KCQkJCQlpZiB1bWJlcltpXSBhbmQgdW1iZXJbaV1bMl0gPiA0MDAgdGhlbgoJCQkJCQl0YWJsZS5yZW1vdmUodW1iZXIsaSkKCQkJCQllbmQKCQkJCWlmIHVtYmVyW2ldIHRoZW4KCQkJCQl1bWJlcltpXVsyXSA9IHVtYmVyW2ldWzJdICsgdW1iZXJbaV1bNV0qZHQqc3BlZWQKCQkJCWVuZAoJCQllbmQKCQllbmQKCQlpZiB0aW1lciA+PSAxNS8oc3BlZWQvMikgYW5kIG5vdCB0b2NoIHRoZW4KCQkJdGltZXIgPSAwCgkJCWZvciB4ID0gMCwgNSBkbwoJCQkJdGFibGUuaW5zZXJ0KHVtYmVyLCB7bWF0aC5yYW5kb20oMCw5OSksIDAsIDQsIDQsIDUwfSktLXgseSx3LGgsc3BlZWQKCQkJCXNwZWVkID0gc3BlZWQgKyAwLjAxCgkJCQlzY29yZSA9IHNjb3JlICsgMQoJCQllbmQKCQllbmQKCQlpZiBsay5pc0Rvd24oImQiKSBhbmQgbm90IHRvY2ggdGhlbgoJCQlrdWJlLnggPSBrdWJlLngrIDQwMCpkdAoJCWVuZAoJCWlmIGxrLmlzRG93bigiYSIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCWt1YmUueCA9IGt1YmUueC0gNDAwKmR0CgkJZW5kCgkJaWYga3ViZS54ID49IDE5MSB0aGVuCgkJCWt1YmUueCA9IDE5MQoJCWVsc2VpZiBrdWJlLnggPD0gOCB0aGVuCgkJCWt1YmUueCA9IDgKCQllbmQKCWVsc2VpZiBmbGFnID09IDUgdGhlbgoJCWlmIHRvY2ggdGhlbgoJCQlpZiByZWNvcmRzWzNdWzJdIDwgc2NvcmUgdGhlbgoJCQkJcmVjb3Jkc1szXVsyXSA9IHNjb3JlCgkJCWVuZAoJCWVuZAoJCXRpbWVyID0gdGltZXIrMTAqZHQKCQlpZiAjdW1iZXIgPiAwIGFuZCBub3QgdG9jaCB0aGVuCgkJCWZvciBpID0gMSwgI3VtYmVyIGRvCgkJCQkJaWYgdW1iZXJbaV0gYW5kICh1bWJlcltpXVsyXSA+IDQwMCBvciB1bWJlcltpXVsyXSA8IC0xMCkgdGhlbgoJCQkJCQl0YWJsZS5yZW1vdmUodW1iZXIsaSkKCQkJCQllbmQKCQkJCWlmIHVtYmVyW2ldIHRoZW4KCQkJCQlpZiB1bWJlcltpXVs2XSA9PSAiZCIgdGhlbgoJCQkJCXVtYmVyW2ldWzJdID0gdW1iZXJbaV1bMl0gKyB1bWJlcltpXVs1XSpkdCpzcGVlZAoJCQkJCWVsc2UKCQkJCQl1bWJlcltpXVsyXSA9IHVtYmVyW2ldWzJdIC0gdW1iZXJbaV1bNV0qZHQqc3BlZWQKCQkJCQllbmQKCQkJCWVuZAoJCQllbmQKCQllbmQKCQlpZiB0aW1lciA+PSA4LyhzcGVlZC8yKSBhbmQgbm90IHRvY2ggdGhlbgoJCQl0aW1lciA9IDAKCQkJdGFibGUuaW5zZXJ0KHVtYmVyLCB7bWF0aC5yYW5kb20oMCw5OSksIDAsIDQsIDQsIDUwLCAiZCJ9KS0teCx5LHcsaCxzcGVlZAoJCQl0YWJsZS5pbnNlcnQodW1iZXIsIHttYXRoLnJhbmRvbSgwLDk5KSwgNDAwLCA0LCA0LCA1MCwgInUifSkKCQkJc3BlZWQgPSBzcGVlZCArIDAuMDIKCQkJc2NvcmUgPSBzY29yZSArIDIKCQllbmQKCQlpZiBsay5pc0Rvd24oImQiKSBhbmQgbm90IHRvY2ggdGhlbgoJCQlrdWJlLnggPSBrdWJlLngrIDQwMCpkdAoJCWVuZAoJCWlmIGxrLmlzRG93bigiYSIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCWt1YmUueCA9IGt1YmUueC0gNDAwKmR0CgkJZW5kCgkJaWYga3ViZS54ID49IDE5MSB0aGVuCgkJCWt1YmUueCA9IDE5MQoJCWVsc2VpZiBrdWJlLnggPD0gOCB0aGVuCgkJCWt1YmUueCA9IDgKCQllbmQKCWVsc2VpZiBmbGFnID09IDYgdGhlbgoJCWlmIHRvY2ggdGhlbgoJCQlpZiByZWNvcmRzWzRdWzJdIDwgc2NvcmUgdGhlbgoJCQkJcmVjb3Jkc1s0XVsyXSA9IHNjb3JlCgkJCWVuZAoJCWVuZAoJdGltZXIgPSB0aW1lcisxMCpkdAoJCWlmICN1bWJlciA+IDAgYW5kIG5vdCB0b2NoIHRoZW4KCQkJZm9yIGkgPSAxLCAjdW1iZXIgZG8KCQkJCWlmIHVtYmVyW2ldIGFuZCB1bWJlcltpXVsyXSA+IDQwMCB0aGVuCgkJCQkJdGFibGUucmVtb3ZlKHVtYmVyLGkpCgkJCQllbmQKCQkJCWlmIHVtYmVyW2ldIHRoZW4KCQkJCQl1bWJlcltpXVsyXSA9IHVtYmVyW2ldWzJdICsgdW1iZXJbaV1bNV0qZHQqc3BlZWQKCQkJCWVuZAoJCQllbmQKCQllbmQKCQlpZiB0aW1lciA+PSAxLyhzcGVlZC8yKSBhbmQgbm90IHRvY2ggdGhlbgoJCQl0aW1lciA9IDAKCQkJc3BlZWQgPSBzcGVlZCArIDAuMDEKCQkJc2NvcmUgPSBzY29yZSArIDEKCQkJdGFibGUuaW5zZXJ0KHVtYmVyLCB7bWF0aC5yYW5kb20oMCw5OSksIDAsIDQsIDQsIDUwfSktLXgseSx3LGgsc3BlZWQKCQllbmQKCQlpZiBsay5pc0Rvd24oImQiKSBhbmQgbm90IHRvY2ggdGhlbgoJCQlrdWJlLnggPSBrdWJlLngrIDQwMCpkdAoJCWVuZAoJCWlmIGxrLmlzRG93bigiYSIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCWt1YmUueCA9IGt1YmUueC0gNDAwKmR0CgkJZW5kCgkJaWYga3ViZS54ID49IDE5MSB0aGVuCgkJCWt1YmUueCA9IDE5MQoJCWVsc2VpZiBrdWJlLnggPD0gOCB0aGVuCgkJCWt1YmUueCA9IDgKCQllbmQJCgllbHNlaWYgZmxhZyA9PSA3IHRoZW4KCQlpZiB0b2NoIHRoZW4KCQkJaWYgcmVjb3Jkc1s1XVsyXSA8IHNjb3JlIHRoZW4KCQkJCXJlY29yZHNbNV1bMl0gPSBzY29yZQoJCQllbmQKCQllbmQKCQl0aW1lciA9IHRpbWVyKzEwKmR0CgkJaWYgI3VtYmVyID4gMCBhbmQgbm90IHRvY2ggdGhlbgoJCQlmb3IgaSA9IDEsICN1bWJlciBkbwoJCQkJaWYgdW1iZXJbaV0gYW5kICh1bWJlcltpXVsyXSA+IDQwMCBvciB1bWJlcltpXVsyXSA8IC0xMCkgdGhlbgoJCQkJCXRhYmxlLnJlbW92ZSh1bWJlcixpKQoJCQkJZW5kCgkJCQlpZiB1bWJlcltpXSB0aGVuCgkJCQkJaWYgdW1iZXJbaV1bNl0gPT0gImQiIHRoZW4KCQkJCQkJdW1iZXJbaV1bMl0gPSB1bWJlcltpXVsyXSArIHVtYmVyW2ldWzVdKmR0KnNwZWVkCgkJCQkJCXVtYmVyW2ldWzFdID0gdW1iZXJbaV1bMV0gKyB1bWJlcltpXVs1XSpkdCpzcGVlZC81CgkJCQkJZWxzZWlmIHVtYmVyW2ldWzZdID09ICJ1IiB0aGVuCgkJCQkJCXVtYmVyW2ldWzJdID0gdW1iZXJbaV1bMl0gLSB1bWJlcltpXVs1XSpkdCpzcGVlZAoJCQkJCQl1bWJlcltpXVsxXSA9IHVtYmVyW2ldWzFdIC0gdW1iZXJbaV1bNV0qZHQqc3BlZWQvNQoJCQkJCWVuZAoJCQkJZW5kCgkJCWVuZAoJCWVuZAoJCWlmIHRpbWVyID49IDgvKHNwZWVkLzIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCXRpbWVyID0gMAoJCQl0YWJsZS5pbnNlcnQodW1iZXIsIHttYXRoLnJhbmRvbSgwLDk5KSwgMCwgNCwgNCwgNTAsICJkIn0pLS14LHksdyxoLHNwZWVkCgkJCXRhYmxlLmluc2VydCh1bWJlciwge21hdGgucmFuZG9tKDAsOTkpLCA0MDAsIDQsIDQsIDUwLCAidSJ9KQoJCQlzcGVlZCA9IHNwZWVkICsgMC4wMgoJCQlzY29yZSA9IHNjb3JlICsgMgoJCWVuZAoJCWlmIGxrLmlzRG93bigiZCIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCWt1YmUueCA9IGt1YmUueCsgNDAwKmR0CgkJZW5kCgkJaWYgbGsuaXNEb3duKCJhIikgYW5kIG5vdCB0b2NoIHRoZW4KCQkJa3ViZS54ID0ga3ViZS54LSA0MDAqZHQKCQllbmQKCQlpZiBrdWJlLnggPj0gMTkxIHRoZW4KCQkJa3ViZS54ID0gMTkxCgkJZWxzZWlmIGt1YmUueCA8PSA4IHRoZW4KCQkJa3ViZS54ID0gOAoJCWVuZAoJZWxzZWlmIGZsYWcgPT0gOCB0aGVuCgkJaWYgdG9jaCB0aGVuCgkJCWlmIHJlY29yZHNbNl1bMl0gPCBzY29yZSB0aGVuCgkJCQlyZWNvcmRzWzZdWzJdID0gc2NvcmUKCQkJZW5kCgkJZW5kCgkJdGltZXIgPSB0aW1lcisxMCpkdAoJCWlmICN1bWJlciA+IDAgYW5kIG5vdCB0b2NoIHRoZW4KCQkJZm9yIGkgPSAxLCAjdW1iZXIgZG8KCQkJCWlmIHVtYmVyW2ldIGFuZCAodW1iZXJbaV1bMl0gPiA0MDAgb3IgdW1iZXJbaV1bMl0gPCAtMTAgb3IgdW1iZXJbaV1bMV0gPiA0MjAgb3IgdW1iZXJbaV1bMV0gPCAtMTApIHRoZW4KCQkJCQl0YWJsZS5yZW1vdmUodW1iZXIsaSkKCQkJCWVuZAoJCQkJaWYgdW1iZXJbaV0gdGhlbgoJCQkJCWlmIHVtYmVyW2ldWzZdID09ICJkIiB0aGVuCgkJCQkJCXVtYmVyW2ldWzJdID0gdW1iZXJbaV1bMl0gKyB1bWJlcltpXVs1XSpkdCpzcGVlZAoJCQkJCWVsc2VpZiB1bWJlcltpXVs2XSA9PSAidSIgdGhlbgoJCQkJCQl1bWJlcltpXVsyXSA9IHVtYmVyW2ldWzJdIC0gdW1iZXJbaV1bNV0qZHQqc3BlZWQKCQkJCQllbHNlaWYgdW1iZXJbaV1bNl0gPT0gImwiIHRoZW4KCQkJCQkJdW1iZXJbaV1bMV0gPSB1bWJlcltpXVsxXSArIHVtYmVyW2ldWzVdKmR0KnNwZWVkCgkJCQkJZWxzZWlmIHVtYmVyW2ldWzZdID09ICJyIiB0aGVuCgkJCQkJCXVtYmVyW2ldWzFdID0gdW1iZXJbaV1bMV0gLSB1bWJlcltpXVs1XSpkdCpzcGVlZAoJCQkJCWVuZAoJCQkJZW5kCgkJCWVuZAoJCWVuZAoJCWlmIHRpbWVyID49IDE2LyhzcGVlZC8yKSBhbmQgbm90IHRvY2ggdGhlbgoJCQl0aW1lciA9IDAKCQkJdGFibGUuaW5zZXJ0KHVtYmVyLCB7bWF0aC5yYW5kb20oMCw5OSksIDAsIDQsIDQsIDUwLCAiZCJ9KS0teCx5LHcsaCxzcGVlZAoJCQl0YWJsZS5pbnNlcnQodW1iZXIsIHttYXRoLnJhbmRvbSgwLDk5KSwgNDAwLCA0LCA0LCA1MCwgInUifSkKCQkJdGFibGUuaW5zZXJ0KHVtYmVyLCB7MCwgbWF0aC5yYW5kb20oMCw5OSkqNCwgNCwgNCwgMjUsICJsIn0pCgkJCXRhYmxlLmluc2VydCh1bWJlciwgezEwMCwgbWF0aC5yYW5kb20oMCw5OSkqNCwgNCwgNCwgMjUsICJyIn0pCgkJCXNwZWVkID0gc3BlZWQgKyAwLjA0CgkJCXNjb3JlID0gc2NvcmUgKyA0CgkJZW5kCgkJaWYgbGsuaXNEb3duKCJkIikgYW5kIG5vdCB0b2NoIHRoZW4KCQkJa3ViZS54ID0ga3ViZS54KyA0MDAqZHQKCQllbmQKCQlpZiBsay5pc0Rvd24oImEiKSBhbmQgbm90IHRvY2ggdGhlbgoJCQlrdWJlLnggPSBrdWJlLngtIDQwMCpkdAoJCWVuZAoJCWlmIGxrLmlzRG93bigidyIpIGFuZCBub3QgdG9jaCB0aGVuCgkJCWt1YmUueSA9IGt1YmUueS0gNDAwKmR0CgkJZW5kCgkJaWYgbGsuaXNEb3duKCJzIikgYW5kIG5vdCB0b2NoIHRoZW4KCQkJa3ViZS55ID0ga3ViZS55KyA0MDAqZHQKCQllbmQKCQlpZiBrdWJlLnggPj0gMTkxIHRoZW4KCQkJa3ViZS54ID0gMTkxCgkJZWxzZWlmIGt1YmUueCA8PSA4IHRoZW4KCQkJa3ViZS54ID0gOAoJCWVuZAoJCWlmIGt1YmUueSA8PSAwIHRoZW4KCQkJa3ViZS55ID0gMAoJCWVsc2VpZiBrdWJlLnkgPj0gMzg0IHRoZW4KCQkJa3ViZS55ID0gMzg0CgkJZW5kCgllbmQKZW5kCgoKCmZ1bmN0aW9uIGxvdmUuZHJhdygpCglnci5zZXRGb250KGZvbnQpCglpZiBub3QgZmxhZyB0aGVuCgkJZm9yIGkgPSAxLCAjbWIgZG8KCQkJbWJbaV06ZHJhdygpCgkJZW5kCgllbHNlaWYgZmxhZyA9PSAxIHRoZW4KCQliYWNrOmRyYXcoKQoJCWZvciBpID0gMSwgI3JlY29yZHMgZG8KCQkJZ3Iuc2V0Q29sb3IoMjU1LDI1NSwyNTUpCgkJCWdyLnByaW50KHJlY29yZHNbaV1bMV0uLiIgLS0tLS0tLS0tLSBzY29yZTogIi4ucmVjb3Jkc1tpXVsyXSx3aW4uZ2V0V2lkdGgoKS8yIC0gZm9udDpnZXRXaWR0aChyZWNvcmRzW2ldWzFdLi4iIC0tLS0tLS0tLS0gc2NvcmU6ICIuLnJlY29yZHNbaV1bMl0pLzIsIGkqMjArNzApCgkJZW5kCgllbHNlaWYgZmxhZyA9PSAyIHRoZW4KCQlnci5zZXRDb2xvcigwLDI1NSwwKQoJCWdyLnByaW50KCJTZWxlY3QgdGhlIHR5cGUgb2YgZ2FtZSIsd2luLmdldFdpZHRoKCkvMiAtIGZvbnQ6Z2V0V2lkdGgoIlNlbGVjdCB0aGUgdHlwZSBvZiBnYW1lIikvMikKCQlnci5zZXRDb2xvcigyNTUsMjU1LDI1NSkKCQlmb3IgaSA9IDEsICN0Z2IgZG8KCQkJdGdiW2ldOmRyYXcoKQoJCWVuZAoJZWxzZWlmIGZsYWcgPj0gMyB0aGVuCgkJaWYgI3VtYmVyID4gMCB0aGVuCQoJCQlnci5zZXRDb2xvcigyNTUsMCwwKQoJCQlmb3IgaSA9IDEsICN1bWJlciBkbwoJCQkJaWYgKHVtYmVyW2ldWzFdKjQgPj0gbWF0aC5mbG9vcihrdWJlLngtMTIpIGFuZCB1bWJlcltpXVsxXSo0IDw9IG1hdGguZmxvb3Ioa3ViZS54KzgpIGFuZCB1bWJlcltpXVsyXSA+PSBrdWJlLnktNCBhbmQgdW1iZXJbaV1bMl0gPD0ga3ViZS55KzE2KSBvciAodW1iZXJbaV1bMV0qNCA+PSBtYXRoLmZsb29yKDQwMC1rdWJlLngtMTIpIGFuZCB1bWJlcltpXVsxXSo0IDw9IG1hdGguZmxvb3IoNDAwLWt1YmUueCs4KSBhbmQgdW1iZXJbaV1bMl0gPj0ga3ViZS55LTQgYW5kIHVtYmVyW2ldWzJdIDw9IGt1YmUueSsxNil0aGVuCgkJCQkJdG9jaCA9IHRydWUKCQkJCWVuZAoJCQkJZ3IucmVjdGFuZ2xlKCJmaWxsIix1bWJlcltpXVsxXSo0LHVtYmVyW2ldWzJdLHVtYmVyW2ldWzNdLHVtYmVyW2ldWzRdKQoJCQllbmQKCQllbmQKCQlpZiB0b2NoIHRoZW4KCQkJZ3Iuc2V0Q29sb3IoMTAwLDAsMCkKCQllbHNlCgkJCWdyLnNldENvbG9yKDI1NSwyNTUsMjU1KQoJCWVuZAoJCWdyLnJlY3RhbmdsZSgiZmlsbCIsbWF0aC5mbG9vcihrdWJlLngtOCksbWF0aC5mbG9vcihrdWJlLnkpLDE2LDE2KQoJCWdyLnJlY3RhbmdsZSgiZmlsbCIsbWF0aC5mbG9vcig0MDAta3ViZS54LTgpLG1hdGguZmxvb3Ioa3ViZS55KSwxNiwxNikKCQlnci5zZXRDb2xvcigyNTUsMjU1LDI1NSkKCQlnci5saW5lKDIwMCwwLDIwMCw0MDApCgkJaWYgbm90IHRvY2ggdGhlbgoJCQlnci5wcmludCgiU2NvcmU6ICIuLnNjb3JlLi4iIFNwZWVkOiIuLnN0cmluZy5mb3JtYXQoIiAlLjFmIixzcGVlZCksMCwzODApCgkJZWxzZQoJCQlnci5zZXRGb250KGJpZykKCQkJZ3IucHJpbnQoIlNjb3JlOiAiLi5zY29yZS4uIlxuUmVjb3JkOiAiLi5yZWNvcmRzW2ZsYWctMl1bMl0sMTAwLDE0NSkKCQllbmQKCWVuZAoJaWYgdG9jaCB0aGVuCgkJZ3Iuc2V0Q29sb3IoMCwwLDApCgkJZ3IucmVjdGFuZ2xlKCJmaWxsIiwxMDAsMjQwLDIwMCwxMDApCgkJcjpkcmF3KCkKCQliYWNrOmRyYXcoKQoJZW5kCmdyLnNldENvbG9yKDI1NSwyNTUsMjU1KQpnci5zZXRGb250KG1pbmkpCmdyLnByaW50KCJCeSBTZmFicmlrYW4iKQplbmQKCgoKCgpmdW5jdGlvbiBsb3ZlLm1vdXNlcHJlc3NlZCh4LCB5LCBidXR0b24pIC0t0Y3RgtC+INC60LvQuNC6INC80YvRiNC4CglpZiBmbGFnID09IDIgdGhlbgoJCWZvciBpID0gMSwgI3RnYiBkbwoJCQlpZiB0Z2JbaV06bXByZXNzKHgseSxidXR0b24pIHRoZW4KCQkJCWlmIGkgPT0gMSB0aGVuCgkJCQkJZmxhZyA9IDMKCQkJCWVsc2VpZiBpID09IDIgdGhlbgoJCQkJCWZsYWcgPSA0CgkJCQllbHNlaWYgaSA9PSAzIHRoZW4KCQkJCQlmbGFnID0gNQoJCQkJZWxzZWlmIGkgPT0gNCB0aGVuCgkJCQkJZmxhZyA9IDYKCQkJCWVsc2VpZiBpID09IDUgdGhlbgoJCQkJCWZsYWcgPSA3CgkJCQllbHNlaWYgaSA9PSA2IHRoZW4KCQkJCQlmbGFnID0gOAoJCQkJZW5kCgkJCWVuZAoJCWVuZAoJZWxzZWlmIGZsYWcgPT0gMSB0aGVuCgkJaWYgYmFjazptcHJlc3MoeCx5LGJ1dHRvbikgdGhlbgoJCQlmbGFnID0gbmlsCgkJZW5kCgllbHNlaWYgbm90IGZsYWcgdGhlbgoJCWZvciBpID0gMSwgI21iIGRvCgkJCWlmIG1iW2ldOm1wcmVzcyh4LHksYnV0dG9uKSB0aGVuCgkJCQlpZiBpID09IDEgdGhlbgoJCQkJCWZsYWcgPSAyCgkJCQllbHNlaWYgaSA9PSAyIHRoZW4KCQkJCQlmbGFnID0gMQoJCQkJZWxzZWlmIGkgPT0gMyB0aGVuCgkJCQkJbG92ZS5ldmVudC5xdWl0KCkKCQkJCWVuZAoJCQllbmQKCQllbmQJCQkKCWVuZAoJaWYgdG9jaCB0aGVuCgkJaWYgcjptcHJlc3MoeCx5LGJ1dHRvbikgdGhlbgoJCQlyZXN0YXJ0KCkKCQllbHNlaWYgYmFjazptcHJlc3MoeCx5LGJ1dHRvbikgdGhlbgoJCQlyZXN0YXJ0KCkKCQkJZmxhZyA9IG5pbAoJCWVuZAoJZW5kCmVuZAoKZnVuY3Rpb24gbG92ZS5rZXlwcmVzc2VkKGtleSkKCWlmIGtleSA9PSAiZXNjYXBlIiBhbmQgZmxhZyB0aGVuCgkJaWYgZmxhZyA+IDIgYW5kIHRvY2ggdGhlbgoJCQlyZXN0YXJ0KCkKCQkJZmxhZyA9IG5pbAoJCWVsc2VpZiBmbGFnIDw9IDIgdGhlbgoJCQlmbGFnID0gbmlsCgkJZW5kCgllbHNlaWYga2V5ID09ICJyIiBhbmQgZmxhZyBhbmQgZmxhZyA+IDIgYW5kIHRvY2ggdGhlbgoJCXRvY2ggPSBuaWwKCQlrdWJlID0ge3ggPSA5NiwgeSA9IDE5NiwgY29seCA9IDgsIGNvbHkgPSA4fQoJCXNwZWVkID0gMQoJCXRpbWVyID0gMAoJCXNjb3JlID0gMAoJCXVtYmVyID0ge30JCgllbmQKZW5kCgpmdW5jdGlvbiBsb3ZlLnRleHRpbnB1dCAodCkKCmVuZAoKZnVuY3Rpb24gbG92ZS5xdWl0KCkKbG9jYWwgcyA9IHt9CmZvciBpID0gMSwgI3JlY29yZHMgZG8KCXRhYmxlLmluc2VydChzLCByZWNvcmRzW2ldWzJdKQplbmQKc2VyaWFsaXplLnNhdmUocywgInJlY29yZHMubHVhIikKZW5kCgotLWJ1dHRvbgoKdXR0b24gPSB7fQoKZnVuY3Rpb24gdXR0b246Y3JlYXRlKHgseSx0ZXh0KSAtLdCh0L7QsdGB0LLRgtC10L3QvdC+INC/0L7Qu9C+0LbQtdC90LjQtSDQuCDRgtC10LrRgdGCINCy0L3Rg9GC0YDQuCDQutC90L7Qv9C60LgKbG9jYWwgdCA9IHt9CnQudG9jaCA9IGZhbHNlIC0t0JfQsNCy0LXQuyDRjdGC0L7RgiDQsdGD0LvQtdGA0L0g0LTQu9GPINC60L7RgdCw0L3QuNGPCnQueCA9IHgKdC55ID0geQp0LnRleHQgPSB0ZXh0CnNlbGYuX19pbmRleCA9IHNlbGYKcmV0dXJuIHNldG1ldGF0YWJsZSh0LHNlbGYpCmVuZAoKZnVuY3Rpb24gdXR0b246dXBkYXRlKGR0KSAtLdC+0LHQvdC+0LLQu9GP0LXQvAoJc2VsZi50b2NoID0gZmFsc2UgLS3QutCw0YDQvtGH0Lgg0LrQsNGB0LDQvdC40LUg0YTQsNC70YEKCWxvY2FsIHggPSBsb3ZlLm1vdXNlLmdldFgoKSAtLdCS0L7RgNGD0LXQvCDQv9C+0LvQvtC20LXQvdC40LUg0LzRi9GI0LrQuCDRhQoJbG9jYWwgeSA9IGxvdmUubW91c2UuZ2V0WSgpIC0t0JLQvtGA0YPQtdC8INC/0L7Qu9C+0LbQtdC90LjQtSDQvNGL0YjQutC4IHkKCWlmIHggPiBzZWxmLngKCQlhbmQgeCA8IHNlbGYueCArIGZvbnQ6Z2V0V2lkdGgoc2VsZi50ZXh0KSAtLdCaINC/0L7Qu9C+0LbQtdC90LjRjiDQutC90L7Qv9C60LggKyDRiNC40YDQuNC90LAg0YLQtdC60YHRgtCwIHNlbGYudGV4dAoJCWFuZCB5IDwgc2VsZi55ICsgZm9udDpnZXRIZWlnaHQoKQoJCWFuZCB5ID4gc2VsZi55IHRoZW4gLS3QstC+0YIg0YLQsNC60L7QtSDQstC+0YIg0L7Qs9GA0LDQvNC10L3QvdC+0LUg0YPRgdC70L7QstC40LUhCgkJc2VsZi50b2NoID0gdHJ1ZSAtLdCV0YHQu9C4INGD0YHQu9C+0LLQuNC1INCy0YvQv9C+0LvQvdC10L3Qviwg0LTQviDQstGB0LUg0LPRg9C0INGC0YDRgwoJZW5kCmVuZAoKZnVuY3Rpb24gdXR0b246ZHJhdygpIC0t0YDQuNGB0YPQtdC8CmxvdmUuZ3JhcGhpY3Muc2V0Q29sb3IoMjU1LDI1NSwyNTUpCQppZiBzZWxmLnRvY2ggdGhlbiAtLdC10YHQu9C4IHRydWUg0YLQvgoJbG92ZS5ncmFwaGljcy5zZXRDb2xvcigyNTUsMCwwKQplbmQKbG92ZS5ncmFwaGljcy5zZXRGb250KGZvbnQpCmxvdmUuZ3JhcGhpY3MucmVjdGFuZ2xlKCJsaW5lIixzZWxmLngtMixzZWxmLnktMixmb250OmdldFdpZHRoKHNlbGYudGV4dCkrNCxmb250OmdldEhlaWdodCgpKzQpCmxvdmUuZ3JhcGhpY3MucHJpbnQoc2VsZi50ZXh0LHNlbGYueCxzZWxmLnkpCmVuZAoKZnVuY3Rpb24gdXR0b246bXByZXNzKHgseSxidXR0b24pCglpZiBzZWxmLnRvY2ggdGhlbgoJCXJldHVybiB0cnVlCgllbmQKcmV0dXJuIGZhbHNlCmVuZAoKLS1bWwoqKk1vZGlmaWVkIGZvciBMT1ZFKioKCVNhdmUgVGFibGUgdG8gRmlsZQoJTG9hZCBUYWJsZSBmcm9tIEZpbGUKCXYgMS4wCgkKCUx1YSA1LjIgY29tcGF0aWJsZQoJCglPbmx5IFNhdmVzIFRhYmxlcywgTnVtYmVycywgU3RyaW5ncywgYW5kIEJvb2xlYW5zCglJbnNpZGVzIFRhYmxlIFJlZmVyZW5jZXMgYXJlIHNhdmVkCglEb2VzIG5vdCBzYXZlIFVzZXJkYXRhLCBNZXRhdGFibGVzLCBGdW5jdGlvbnMgYW5kIGluZGljZXMgb2YgdGhlc2UKCS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCXN1Y2Nlc3NmdWwsZXJybXNnID0gc2F2ZSggdGFibGUsZmlsZW5hbWUgKQoJCgktLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgl0YWJsZSA9IGxvYWQoIGZpbGVuYW1lICkKCQoJLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoJCglMaWNlbnNlZCB1bmRlciB0aGUgc2FtZSB0ZXJtcyBhcyBMdWEgaXRzZWxmLgpdXS0tCi0tIGRlY2xhcmUgbG9jYWwgdmFyaWFibGVzCi0tLy8gZXhwb3J0c3RyaW5nKCBzdHJpbmcgKQotLS8vIHJldHVybnMgYSAiTHVhIiBwb3J0YWJsZSB2ZXJzaW9uIG9mIHRoZSBzdHJpbmcKbG9jYWwgZnVuY3Rpb24gZXhwb3J0c3RyaW5nKCBzICkKCXJldHVybiBzdHJpbmcuZm9ybWF0KCIlcSIsIHMpCmVuZAoKbG9jYWwgZnVuY3Rpb24gY3JlYXRlU3ViRGlyKHBhdGgpCglsb2NhbCBkaXIsbmFtZSxleHQgPSBwYXRoOm1hdGNoKCdeKC4tKShbXlxcL10tKSUuPyhbXlxcLyUuXSopJCcpCglpZiAjbmFtZSA9PSAwIHRoZW4gbmFtZSA9IGV4dDsgZXh0ID0gJycgZW5kCglsb2NhbCBkaXJwYXRoID0gJycKCWZvciBzdWJmb2xkZXIgaW4gZGlyOmdtYXRjaCgnKFteXFwvXS1bXFwvXSknKSBkbwoJCWRpcnBhdGggPSBkaXJwYXRoLi5zdWJmb2xkZXIKCQlpZiBsb3ZlLmZpbGVzeXN0ZW0uaXNGaWxlKGRpcnBhdGgpIHRoZW4KCQkJcmV0dXJuICdDYW5ub3Qgc2F2ZSB0YWJsZSwgJy4uZGlycGF0aC4uJyBpcyBhIGZpbGUnCgkJZW5kCgkJaWYgbm90IGxvdmUuZmlsZXN5c3RlbS5leGlzdHMoZGlycGF0aCkgdGhlbgoJCQlsb3ZlLmZpbGVzeXN0ZW0ubWtkaXIoZGlycGF0aCkKCQllbmQKCWVuZAplbmQKCmxvY2FsIGluc2VydCA9IGZ1bmN0aW9uKHQsdikKCWlmIHQubGVuIHRoZW4KCQl0LmxlbiA9IHQubGVuKzEKCQl0W3QubGVuXSA9IHYKCQlyZXR1cm4KCWVuZAoJdGFibGUuaW5zZXJ0KHQsdikKZW5kCgpzZXJpYWxpemUgPSB7fQoKLS0vLyBUaGUgU2F2ZSBGdW5jdGlvbgpmdW5jdGlvbiBzZXJpYWxpemUuc2F2ZSggdGJsLGZpbGVuYW1lICkKCWxvY2FsIGNoYXJTLGNoYXJFID0gIlx0IiwiXG4iCgkKCWxvY2FsIGVyciA9IGNyZWF0ZVN1YkRpcihmaWxlbmFtZSkKCWlmIGVyciB0aGVuIHJldHVybiBmYWxzZSxlcnIgZW5kCgkKCWxvY2FsIGZpbGUgPSBsb3ZlLmZpbGVzeXN0ZW0ubmV3RmlsZShmaWxlbmFtZSkKCWZpbGU6b3BlbigndycpCgoJLS0gaW5pdGlhdGUgdmFyaWFibGVzIGZvciBzYXZlIHByb2NlZHVyZQoJbG9jYWwgdGFibGVzLGxvb2t1cCA9IHsgdGJsOyBsZW4gPSAxIH0seyBbdGJsXSA9IDEgfQoJZmlsZTp3cml0ZSggInJldHVybiB7Ii4uY2hhckUgKQoKCWZvciBpZHgsdCBpbiBpcGFpcnMoIHRhYmxlcyApIGRvCgkJZmlsZTp3cml0ZSggIi0tIFRhYmxlOiB7Ii4uaWR4Li4ifSIuLmNoYXJFICkKCQlmaWxlOndyaXRlKCAieyIuLmNoYXJFICkKCQlsb2NhbCB0aGFuZGxlZCA9IHt9CgoJCWZvciBpLHYgaW4gaXBhaXJzKCB0ICkgZG8KCQkJdGhhbmRsZWRbaV0gPSB0cnVlCgkJCWxvY2FsIHN0eXBlID0gdHlwZSggdiApCgkJCS0tIG9ubHkgaGFuZGxlIHZhbHVlCgkJCWlmIHN0eXBlID09ICJ0YWJsZSIgdGhlbgoJCQkJaWYgbm90IGxvb2t1cFt2XSB0aGVuCgkJCQkJaW5zZXJ0KCB0YWJsZXMsIHYgKQoJCQkJCWxvb2t1cFt2XSA9ICN0YWJsZXMKCQkJCWVuZAoJCQkJZmlsZTp3cml0ZSggY2hhclMuLiJ7Ii4ubG9va3VwW3ZdLi4ifSwiLi5jaGFyRSApCgkJCWVsc2VpZiBzdHlwZSA9PSAic3RyaW5nIiB0aGVuCgkJCQlmaWxlOndyaXRlKCAgY2hhclMuLmV4cG9ydHN0cmluZyggdiApLi4iLCIuLmNoYXJFICkKCQkJZWxzZWlmIHN0eXBlID09ICJudW1iZXIiIG9yIHN0eXBlID09ICdib29sZWFuJyB0aGVuCgkJCQlmaWxlOndyaXRlKCAgY2hhclMuLnRvc3RyaW5nKCB2ICkuLiIsIi4uY2hhckUgKQoJCQllbmQKCQllbmQKCgkJZm9yIGksdiBpbiBwYWlycyggdCApIGRvCgkJCS0tIGVzY2FwZSBoYW5kbGVkIHZhbHVlcwoJCQlpZiAobm90IHRoYW5kbGVkW2ldKSB0aGVuCgkJCQoJCQkJbG9jYWwgc3RyID0gIiIKCQkJCWxvY2FsIHN0eXBlID0gdHlwZSggaSApCgkJCQktLSBoYW5kbGUgaW5kZXgKCQkJCS0tIGlmIHN0eXBlID09ICJ0YWJsZSIgdGhlbgoJCQkJCS0tIGlmIG5vdCBsb29rdXBbaV0gdGhlbgoJCQkJCQktLSBpbnNlcnQoIHRhYmxlcyxpICkKCQkJCQkJLS0gbG9va3VwW2ldID0gI3RhYmxlcwoJCQkJCS0tIGVuZAoJCQkJCS0tIHN0ciA9IGNoYXJTLi4iW3siLi5sb29rdXBbaV0uLiJ9XT0iCgkJCQlpZiBzdHlwZSA9PSAic3RyaW5nIiB0aGVuCgkJCQktLSBlbHNlaWYgc3R5cGUgPT0gInN0cmluZyIgdGhlbgoJCQkJCXN0ciA9IGNoYXJTLi4iWyIuLmV4cG9ydHN0cmluZyggaSApLi4iXT0iCgkJCQllbHNlaWYgc3R5cGUgPT0gIm51bWJlciIgb3Igc3R5cGUgPT0gJ2Jvb2xlYW4nIHRoZW4KCQkJCQlzdHIgPSBjaGFyUy4uIlsiLi50b3N0cmluZyggaSApLi4iXT0iCgkJCQllbmQKCQkJCgkJCQlpZiBzdHIgfj0gIiIgdGhlbgoJCQkJCXN0eXBlID0gdHlwZSggdiApCgkJCQkJLS0gaGFuZGxlIHZhbHVlCgkJCQkJaWYgc3R5cGUgPT0gInRhYmxlIiB0aGVuCgkJCQkJCWlmIG5vdCBsb29rdXBbdl0gdGhlbgoJCQkJCQkJaW5zZXJ0KCB0YWJsZXMsdiApCgkJCQkJCQlsb29rdXBbdl0gPSAjdGFibGVzCgkJCQkJCWVuZAoJCQkJCQlmaWxlOndyaXRlKCBzdHIuLiJ7Ii4ubG9va3VwW3ZdLi4ifSwiLi5jaGFyRSApCgkJCQkJZWxzZWlmIHN0eXBlID09ICJzdHJpbmciIHRoZW4KCQkJCQkJZmlsZTp3cml0ZSggc3RyLi5leHBvcnRzdHJpbmcoIHYgKS4uIiwiLi5jaGFyRSApCgkJCQkJZWxzZWlmIHN0eXBlID09ICJudW1iZXIiIG9yIHN0eXBlID09ICdib29sZWFuJyB0aGVuCgkJCQkJCWZpbGU6d3JpdGUoIHN0ci4udG9zdHJpbmcoIHYgKS4uIiwiLi5jaGFyRSApCgkJCQkJZW5kCgkJCQllbmQKCQkJZW5kCgkJZW5kCgkJZmlsZTp3cml0ZSggIn0sIi4uY2hhckUgKQoJZW5kCglmaWxlOndyaXRlKCAifSIgKQoJZmlsZTpjbG9zZSgpCgkKCXJldHVybiB0cnVlCmVuZAoKLS0vLyBUaGUgTG9hZCBGdW5jdGlvbgpmdW5jdGlvbiBzZXJpYWxpemUubG9hZCggZmlsZW5hbWUgKQoJaWYgbm90IGxvdmUuZmlsZXN5c3RlbS5leGlzdHMoZmlsZW5hbWUpIHRoZW4gcmV0dXJuIGVuZAoJbG9jYWwgdGFibGVzID0gbG92ZS5maWxlc3lzdGVtLmxvYWQoZmlsZW5hbWUpKCkKCWZvciBpZHggPSAxLCN0YWJsZXMgZG8KCQlsb2NhbCB0b2xpbmtpID0ge30KCQlmb3IgaSx2IGluIHBhaXJzKCB0YWJsZXNbaWR4XSApIGRvCgkJCWlmIHR5cGUoIHYgKSA9PSAidGFibGUiIHRoZW4KCQkJCXRhYmxlc1tpZHhdW2ldID0gdGFibGVzW3ZbMV1dCgkJCWVuZAoJCQlpZiB0eXBlKCBpICkgPT0gInRhYmxlIiBhbmQgdGFibGVzW2lbMV1dIHRoZW4KCQkJCWluc2VydCggdG9saW5raSx7IGksdGFibGVzW2lbMV1dIH0gKQoJCQllbmQKCQllbmQKCQktLSBsaW5rIGluZGljZXMKCQlmb3IgXyx2IGluIGlwYWlycyggdG9saW5raSApIGRvCgkJCXRhYmxlc1tpZHhdW3ZbMl1dLHRhYmxlc1tpZHhdW3ZbMV1dID0gIHRhYmxlc1tpZHhdW3ZbMV1dLG5pbAoJCWVuZAoJZW5kCglyZXR1cm4gdGFibGVzWzFdCmVuZAoKLS0gQ2hpbGxDb2Rl