#include "Rectangle.hpp"
#include "Engine.hpp"
#include "Line.hpp"
#include "Image.hpp"
#include <unistd.h>
#include "Scene.hpp"
#include "Text.hpp"
#include "Timer.hpp"
#include <time.h>
#include "ResourcesManager.hpp"
#include <string>
#include <stdlib.h>
#include "VertexBuffer.hpp"
#include "GLState.hpp"
#include "Scissors.hpp"
#include <kst/Logger.hpp>
#include "VertexBuffer.hpp"
#include <set>
#include <vector>
#include <SDL/SDL.h>
#include "kst/File.hpp"
using namespace glider;
const int CELL_SIZE= 15 ;
struct AngleRange{
int sa,ea;
bool closed;
static const int SCALED_PI_2 = 90000000 ;
static const int SCALED_PI = 180000000 ;
static const int SCALED_PIx2= 360000000 ;
AngleRange( int argSa= 0 ,int argEa= 0 ) : sa( argSa) ,ea( argEa) ,closed( false ) { }
void setSa( int argSa)
{
if ( ! closed && ( ( sa< ea && argSa> ea) || ( sa> ea && argSa< sa && argSa> ea) ) ) closed= true ;
sa= argSa;
}
void setEa( int argEa)
{
if ( ! closed && ( ( sa< ea && sa> argEa) || ( sa> ea && argEa> ea && argEa< sa) ) ) closed= true ;
ea= argEa;
}
bool operator< ( const AngleRange& other) const
{
return ea< other.ea ;
}
double saScaled( )
{
return sa/ 1000000.0 ;
}
double eaScaled( )
{
return ea/ 1000000.0 ;
}
int middle( )
{
if ( sa< ea) return ( sa+ ea) / 2 ;
return ( sa+ ea+ SCALED_PIx2) % SCALED_PIx2;
}
void shrinkCorners( int saPrc,int eaPrc)
{
if ( sa> ea)
{
ea+ = AngleRange:: SCALED_PIx2 ;
}
uint64_t mid= middle( ) ;
uint64_t val= mid- sa;
val* = saPrc;
val/ = 100 ;
sa= ( mid- val) % AngleRange:: SCALED_PIx2 ;
val= ea- mid;
val* = eaPrc;
val/ = 100 ;
ea= ( mid+ val) % AngleRange:: SCALED_PIx2 ;
}
int diff( )
{
if ( sa< ea) return ea- sa;
return ( ea+ SCALED_PIx2- sa) % SCALED_PIx2;
}
bool inRange( int a)
{
if ( closed) return false ;
if ( sa< ea) return a>= sa && a<= ea;
return a>= sa || a<= ea;
}
void mirror45( )
{
sa= ( SCALED_PI* 2 + SCALED_PI/ 2 - sa) % ( SCALED_PI* 2 ) ;
ea= ( SCALED_PI* 2 + SCALED_PI/ 2 - ea) % ( SCALED_PI* 2 ) ;
std:: swap ( sa,ea) ;
}
void mirror90( )
{
sa= ( SCALED_PI* 3 - sa) % ( SCALED_PI* 2 ) ;
ea= ( SCALED_PI* 3 - ea) % ( SCALED_PI* 2 ) ;
std:: swap ( sa,ea) ;
}
void mirror180( )
{
sa= ( SCALED_PI* 4 - sa) % ( SCALED_PI* 2 ) ;
ea= ( SCALED_PI* 4 - ea) % ( SCALED_PI* 2 ) ;
std:: swap ( sa,ea) ;
}
} ;
struct FovCell{
AngleRange r;
uint8_t sac,eac;
uint8_t o1,o2;
Posi< int > p;
bool tempBlock;
bool delayBlock;
int range;
bool operator< ( const FovCell& other) const
{
return r< other.r ;
}
void swapp( )
{
std:: swap ( p.x ,p.y ) ;
}
void swapc( )
{
std:: swap ( sac,eac) ;
}
} ;
struct Cell{
bool block;
bool vis;
bool tempBlock;
bool delayBlock;
int corners[ 4 ] ;
FovCell fc;
int r;
std:: string log ;
} ;
typedef std:: vector < Cell> Row;
typedef std:: vector < Row> Matrix;
/*const char* testmap[]={
"########################################",
"#......................................#",
"#......................................#",
"#........................#########.....#",
"#......########..........#.......#.....#",
"#......#......############.......#.....#",
"#......#.........................|.....#",
"#......#......###########........|.....#",
"#......###--###.........#........#.....#",
"#.......................###.######.....#",
"#.........................#.#..........#",
"#......................####.####.......#",
"#.......#.#.#.#.#......................#",
"#........#.#.#.#.......#########.......#",
"#.......#.#.#.#.#......................#",
"#........#.#.#.#.......................#",
"#...........................#..........#",
"#.......#...................#..........#",
"#...........................###........#",
"#....#.................................#",
"#.............#........................#",
"#....................#.................#",
"#..#......#.........#..................#",
"#............###.####..................#",
"#.......#...........#.........##.......#",
"#............###.####.........##.......#",
"#......#.......#.#.....................#",
"#..............###.....................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#.........*****........##--##..........#",
"#....**.......*........#....#..........#",
"#.............*........|....|..........#",
"#.............*........|....|..........#",
"#.............*........#....#..........#",
"#......................##..##..........#",
"#......................................#",
"#......................................#",
"########################################",
};*/
int px;
int py;
int sightRadius= 15 ;
VertexBuffer* vb;
Line* lsa;
Line* lea;
Text* info;
void drawMap( Matrix& m)
{
int H= m.size ( ) ;
int W= m[ 0 ] .size ( ) ;
Color clr;
ClrVector& c= vb- > getCBuf( ) ;
for ( int y= 0 ; y< H; ++ y)
{
for ( int x= 0 ; x< W; ++ x)
{
if ( m[ y] [ x] .block ) clr= Color:: white ; else clr= Color:: blue ;
if ( x== px && y== py) clr= Color:: red ;
if ( m[ y] [ x] .tempBlock )
{
clr= Color:: green ;
}
if ( m[ y] [ x] .delayBlock )
{
clr= Color:: gray ;
}
if ( ! m[ y] [ x] .vis )
{
clr= clr/ 2 ;
}
for ( int i= 0 ; i< 4 ; ++ i)
{
c[ ( x+ y* W) * 4 + i] = clr;
}
}
}
vb- > update( ) ;
}
namespace kst{
void customformat( kst:: FormatBuffer & buf,double v,int w,int p)
{
char buf2[ 64 ] ;
size_t len= sprintf ( buf2,"%*.*lf" ,w,p,v) ;
buf.Append ( buf2,len) ;
}
}
class CircularFov{
public :
CircularFov( ) : debug( true )
{
}
static int getAngle( double x,double y,double quadrant)
{
return ( atan ( y/ x) + quadrant) * ( AngleRange:: SCALED_PI_2 ) / M_PI_2;
}
void prepare( int maxRadius)
{
if ( fov.empty ( ) ) fov.push_back ( Ring( ) ) ;
for ( int r= fov.size ( ) ; r<= maxRadius; ++ r)
{
fov.push_back ( Ring( ) ) ;
Ring& ring= fov.back ( ) ;
//double rr=r*r;//(r+0.5)*(r+0.5);
for ( int y= 0 ; y<= r; ++ y)
{
for ( int x= y; x<= r; ++ x)
{
if ( x== 0 && y== 0 ) continue ;
double dx= x; //-0.5;
double dy= y; //-0.5;
if ( floor ( sqrt ( dx* dx+ dy* dy) ) <= r)
{
Pos p( x,y) ;
if ( processed.find ( p) ! = processed.end ( ) ) continue ;
processed.insert ( p) ;
int sa,ea,sac,eac,o1,o2;
/*if(x==0)
{
sa=getAngle(0.5,y-0.5,0);
ea=getAngle(-0.5,y-0.5,M_PI_2);
}else
{*/
if ( y== 0 )
{
sa= getAngle( x- 0.5 ,- 0.5 ,M_PI* 2 ) ;
ea= getAngle( x- 0.5 ,0.5 ,0 ) - 1 ;
sac= 3 ;
eac= 0 ;
o1= 0 ;
o2= 7 ;
} else if ( x== y)
{
sa= getAngle( x+ 0.5 ,y- 0.5 ,0 ) ;
ea= getAngle( x- 0.5 ,y+ 0.5 ,0 ) ;
sac= 2 ;
eac= 0 ;
o1= 0 ;
o2= 1 ;
} else
{
sa= getAngle( x+ 0.5 ,y- 0.5 ,0 ) ;
ea= getAngle( x- 0.5 ,y+ 0.5 ,0 ) ;
sac= 2 ;
eac= 0 ;
o1= o2= 0 ;
}
//}
ring.push_back ( FovCell( ) ) ;
FovCell& fc= ring.back ( ) ;
fc.r .sa = sa+ 5 ;
fc.r .ea = ea- 5 ;
fc.sac = sac;
fc.eac = eac;
fc.o1 = o1;
fc.o2 = o2;
fc.p = p;
}
}
}
size_t end= ring.size ( ) ;
for ( size_t i= 0 ; i< end; ++ i)
{
FovCell fc= ring[ i] ;
if ( fc.p .x == fc.p .y ) continue ;
fc.swapp ( ) ;
fc.r .mirror45 ( ) ;
fc.sac = fc.sac == 0 ? 2 : fc.sac == 2 ? 0 : fc.sac ;
fc.eac = fc.eac == 0 ? 2 : fc.eac == 2 ? 0 : fc.eac ;
fc.swapc ( ) ;
fc.o1 = 1 ;
fc.o2 = fc.o2 == 7 ? 2 : 1 ;
ring.push_back ( fc) ;
}
end= ring.size ( ) ;
int ct[ 4 ] = { 1 ,0 ,3 ,2 } ;
for ( size_t i= 0 ; i< end; ++ i)
{
FovCell fc= ring[ i] ;
if ( fc.p .x == 0 ) continue ;
fc.p .x = - fc.p .x ;
fc.r .mirror90 ( ) ;
fc.sac = ct[ fc.sac ] ;
fc.eac = ct[ fc.eac ] ;
fc.swapc ( ) ;
fc.o1 = fc.o1 == 0 ? 3 : 2 ;
fc.o2 = fc.o2 == 7 ? 4 : fc.o2 == 0 ? 3 : 2 ;
ring.push_back ( fc) ;
}
end= ring.size ( ) ;
int ct2[ 4 ] = { 3 ,2 ,1 ,0 } ;
for ( size_t i= 0 ; i< end; ++ i)
{
FovCell fc= ring[ i] ;
if ( fc.p .y == 0 ) continue ;
fc.p .y = - fc.p .y ;
fc.r .mirror180 ( ) ;
fc.sac = ct2[ fc.sac ] ;
fc.eac = ct2[ fc.eac ] ;
fc.swapc ( ) ;
fc.o1 = 7 - fc.o1 ;
fc.o2 = 7 - fc.o2 ;
ring.push_back ( fc) ;
}
//std::sort(ring.begin(),ring.end());
}
}
void generateFov( Matrix& m,int maxRadius)
{
if ( fov.size ( ) < maxRadius+ 1 )
{
prepare( maxRadius) ;
}
int H= m.size ( ) ;
int W= m[ 0 ] .size ( ) ;
for ( int y= 0 ; y< H; ++ y)
{
for ( int x= 0 ; x< W; ++ x)
{
m[ y] [ x] .vis = false ;
}
}
for ( int i= 0 ; i< 8 ; ++ i) b[ i] .clear ( ) ;
for ( int ri= 1 ; ri<= maxRadius; ++ ri)
{
Ring& ring= fov[ ri] ;
for ( Ring:: iterator it= ring.begin ( ) ,end= ring.end ( ) ; it! = end; ++ it)
{
FovCell fc= * it;
int x= px+ fc.p .x ;
int y= py+ fc.p .y ;
if ( x< 0 || x>= W || y< 0 || y>= H) continue ;
Cell& c= m[ y] [ x] ;
fc.delayBlock = c.delayBlock ;
fc.tempBlock = c.tempBlock ;
fc.range = ri+ 2 ;
c.fc = fc;
c.r = ri;
c.log = "" ;
AngleRange r= fc.r ;
bool totalBlock= false ;
bool saBlock;
int bso= - 1 ,bsi= - 1 ;
int beo= - 1 ,bei= - 1 ;
bool usedTempBlock= false ;
for ( int k= 0 ; k< 2 ; ++ k)
{
int o= fc.o1 ;
if ( k== 1 )
{
if ( fc.o1 == fc.o2 ) break ;
o= fc.o2 ;
}
for ( size_t i= 0 ; i< b[ o] .size ( ) ; ++ i)
{
FovCell bc= b[ o] [ i] ;
if ( bc.delayBlock && bc.range >= ri) continue ;
if ( bc.tempBlock && bc.range < ri) continue ;
saBlock= false ;
if ( ! c.block && r.inRange ( bc.r .sa ) && r.inRange ( bc.r .ea ) )
{
if ( debug)
{
c.log + = FORMAT( "sa=%{:,3},ea=%{:,3} totally blocked by %d,%d:%{:,3},%{:,3}\n " ,r.saScaled ( ) ,r.eaScaled ( ) ,px+ bc.p .x ,py+ bc.p .y ,bc.r .saScaled ( ) ,bc.r .eaScaled ( ) ) ;;
}
totalBlock= true ;
usedTempBlock= usedTempBlock || bc.tempBlock ;
break ;
}
if ( bc.r .inRange ( r.sa ) /* && bc.ea>sa*/ )
{
if ( debug)
{
c.log + = FORMAT( "sa=%{:,3} blocked by %d,%d:%{:,3},%{:,3}\n " ,r.saScaled ( ) ,px+ bc.p .x ,py+ bc.p .y ,bc.r .saScaled ( ) ,bc.r .eaScaled ( ) ) ;
}
r.setSa ( bc.r .ea ) ;
saBlock= true ;
bso= o; bsi= i;
usedTempBlock= usedTempBlock || bc.tempBlock ;
}
if ( bc.r .inRange ( r.ea ) /* && bc.sa<ea*/ )
{
if ( debug)
{
c.log + = FORMAT( "ea=%{:,3} blocked by %d,%d:%{:,3},%{:,3}\n " ,r.eaScaled ( ) ,px+ bc.p .x ,py+ bc.p .y ,bc.r .saScaled ( ) ,bc.r .eaScaled ( ) ) ;
}
r.setEa ( bc.r .sa ) ;
beo= o; bei= i;
usedTempBlock= usedTempBlock || bc.tempBlock ;
if ( saBlock)
{
totalBlock= true ;
break ;
}
}
if ( r.closed ) break ;
}
if ( r.closed || totalBlock) break ;
}
if ( c.block )
{
c.vis = usedTempBlock || ( ! totalBlock && ! r.closed ) ;
if ( debug)
{
c.log + = FORMAT( "vis r.sa=%{:,3},r.ea=%{:,3} %{}\n " ,r.saScaled ( ) ,r.eaScaled ( ) ,r.closed ? "closed" : "" ) ;
}
} else
{
if ( ! totalBlock)
{
int r1= r.diff ( ) ;
int r2= fc.r .diff ( ) ;
if ( debug)
{
c.log + = FORMAT( "vis r.sa=%{:,3},r.ea=%{:,3}\n diff=%d, fc.diff=%d\n mid=%d\n " ,r.saScaled ( ) ,r.eaScaled ( ) ,r1,r2,fc.r .middle ( ) ) ;
}
c.vis = r1>= r2/ 2 || ( r1>= r2/ 5 && r.inRange ( fc.r .middle ( ) ) ) ;
}
}
if ( c.vis && c.block )
{
if ( c.corners [ fc.sac ] ! = 100 || c.corners [ fc.eac ] ! = 100 )
{
fc.r .shrinkCorners ( c.corners [ fc.sac ] ,c.corners [ fc.eac ] ) ;
c.fc = fc;
}
int used= 0 ;
/*if(bso!=-1 && !fc.delayBlock && !fc.tempBlock)
{
FovCell& bfc=b[bso][bsi];
if(!bfc.tempBlock && !bfc.delayBlock)
{
used++;
if(debug)
{
c.log+=FORMAT("extended ea of %d,%d from %{:,3} to %{:,3}\n",bfc.p.x+px,bfc.p.y+py,bfc.r.eaScaled(),fc.r.eaScaled());
}
bfc.r.ea=fc.r.ea;
}
}
if(beo!=-1 && !fc.delayBlock && !fc.tempBlock)
{
FovCell& bfc=b[beo][bei];
if(!bfc.tempBlock && !bfc.delayBlock)
{
used++;
if(debug)
{
c.log+=FORMAT("extended sa of %d,%d from %{:,3} to %{:,3}\n",bfc.p.x+px,bfc.p.y+py,bfc.r.saScaled(),fc.r.saScaled());
}
bfc.r.sa=fc.r.sa;
}
}*/
if ( used== 0 )
{
b[ fc.o1 ] .push_back ( fc) ;
}
if ( fc.o1 ! = fc.o2 )
{
b[ fc.o2 ] .push_back ( fc) ;
}
}
}
for ( int i= 0 ; i< 8 ; ++ i)
{
b[ i] .insert ( b[ i] .end ( ) ,t[ i] .begin ( ) ,t[ i] .end ( ) ) ;
t[ i] .clear ( ) ;
}
}
info- > setText( FORMAT( "bc[]={%{},%{},%{},%{},%{},%{},%{},%{}}" ,
b[ 0 ] .size ( ) ,b[ 1 ] .size ( ) ,b[ 2 ] .size ( ) ,b[ 3 ] .size ( ) ,b[ 4 ] .size ( ) ,b[ 5 ] .size ( ) ,b[ 6 ] .size ( ) ,b[ 7 ] .size ( ) ) ) ;
drawMap( m) ;
}
//protected:
typedef std:: vector < FovCell> Ring;
typedef std:: vector < Ring> Circle;
Circle fov;
std:: set < Posi< int > > processed;
std:: vector < FovCell> b[ 8 ] ,t[ 8 ] ;
bool debug;
} ;
CircularFov cf;
class MyEventHandler: public EventHandler{
public :
MyEventHandler( Matrix& argM) : m( argM)
{
viewAt.x = - 1 ;
viewAt.y = - 1 ;
}
void onActiveChange( bool active)
{
}
void onMouseEvent( MouseEvent& argEvent)
{
if ( argEvent.eventType == metButtonPress && argEvent.eventButton == 1 )
{
int x= argEvent.x / CELL_SIZE;
int y= argEvent.y / CELL_SIZE;
if ( x< 0 || x>= ( int ) m[ 0 ] .size ( ) || y< 0 || y>= ( int ) m.size ( ) ) return ;
viewAt.x = x;
viewAt.y = y;
updateViewAt( ) ;
}
if ( argEvent.eventType == metButtonPress && argEvent.eventButton == 3 )
{
viewAt.x = - 1 ; viewAt.y = - 1 ;
lsa- > setSource( Pos( 0 ,0 ) ) ;
lsa- > setDestination( Pos( 10 ,0 ) ) ;
lea- > setSource( Pos( 0 ,0 ) ) ;
lea- > setDestination( Pos( 0 ,10 ) ) ;
}
}
void updateViewAt( )
{
int x= viewAt.x ;
int y= viewAt.y ;
if ( x== - 1 || y== - 1 ) return ;
//printf("select %d,%d\n",x,y);
char buf[ 256 ] ;
sprintf ( buf,"x=%d,y=%d,r=%d,sa=%.3lf,ea=%.3lf\n sac=%d,eac=%d\n " ,x,y,m[ y] [ x] .r ,m[ y] [ x] .fc .r .saScaled ( ) ,m[ y] [ x] .fc .r .eaScaled ( ) ,m[ y] [ x] .fc .sac ,m[ y] [ x] .fc .eac ) ;
std:: string txt= buf;
txt+ = m[ y] [ x] .log ;
//if(!m[y][x].vis)
//{
//Posi<int> bp=m[y][x].;
//sprintf(buf+len,"\nbsa=%.3lf,bea=%.3lf",m[y][x].bfc.sa/1000000.0,m[y][x].bfc.ea/1000000.0);
/*
m[bp.y][bp.x].mark=true;
m[lastMark.y][lastMark.x].mark=false;
lastMark=bp;*/
//}
info- > setText( txt.c_str ( ) ) ;
Pos src= Pos( px* CELL_SIZE+ CELL_SIZE/ 2.0 ,py* CELL_SIZE+ CELL_SIZE/ 2.0 ) ;
lsa- > setSource( src) ;
lea- > setSource( src) ;
Pos p;
int mr= ( sightRadius+ 1 ) * CELL_SIZE;
double sa= m[ y] [ x] .fc .r .sa * M_PI/ AngleRange:: SCALED_PI ;
p.x = src.x + mr* cos ( sa) ;
p.y = src.y + mr* sin ( sa) ;
lsa- > setDestination( p) ;
double ea= m[ y] [ x] .fc .r .ea * M_PI/ AngleRange:: SCALED_PI ;
p.x = src.x + mr* cos ( ea) ;
p.y = src.y + mr* sin ( ea) ;
lea- > setDestination( p) ;
}
void onKeyboardEvent( KeyboardEvent& argEvent)
{
if ( argEvent.keySym == keyboard:: GK_ESCAPE )
{
engine.exitApp ( ) ;
}
if ( argEvent.eventType == ketPress)
{
int ox= px;
int oy= py;
if ( argEvent.keySym == keyboard:: GK_UP || argEvent.keySym == keyboard:: GK_w ) py-- ;
if ( argEvent.keySym == keyboard:: GK_DOWN || argEvent.keySym == keyboard:: GK_s ) py++ ;
if ( argEvent.keySym == keyboard:: GK_LEFT || argEvent.keySym == keyboard:: GK_a ) px-- ;
if ( argEvent.keySym == keyboard:: GK_RIGHT || argEvent.keySym == keyboard:: GK_d ) px++ ;
if ( argEvent.keySym == keyboard:: GK_KP_PLUS ) { sightRadius++ ; ox= - 1 ; }
if ( argEvent.keySym == keyboard:: GK_KP_MINUS && sightRadius> 2 ) { sightRadius-- ; ox= - 1 ; }
if ( px< 0 || px>= ( int ) m[ 0 ] .size ( ) || py< 0 || py>= ( int ) m.size ( ) || m[ py] [ px] .block )
{
px= ox;
py= oy;
}
if ( ox! = px || oy! = py)
{
cf.generateFov ( m,sightRadius) ;
updateViewAt( ) ;
}
if ( argEvent.keySym == keyboard:: GK_t )
{
uint32_t start= SDL_GetTicks( ) ;
cf.debug = false ;
for ( int i= 0 ; i< 1000 ; ++ i)
{
cf.generateFov ( m,sightRadius) ;
}
cf.debug = true ;
uint32_t duration= SDL_GetTicks( ) - start;
info- > setText( FORMAT( "time=%d" ,duration) ) ;
}
}
}
void onResize( ) { } ;
void onQuit( )
{
engine.exitApp ( ) ;
}
void onFrameUpdate( int mcsec)
{
}
Matrix& m;
Posi< int > viewAt;
} ;
int GliderAppMain( int argc,char * argv[ ] )
{
kst:: Logger :: Init ( "simple.log" ) ;
engine.setVSync ( false ) ;
engine.selectResolution ( 1024 ,768 ,false ) ;
//engine.selectResolution(800,480,false);
engine.setResolution ( ) ;
engine.setFpsLimit ( 60 ) ;
//const int W=strlen(testmap[0]);
//const int H=sizeof(testmap)/sizeof(testmap[0]);
kst:: File f;
kst:: Logger * lg= kst:: Logger :: getLogger ( "init" ) ;
try {
f.ROpen ( "testmap.txt" ) ;
} catch ( std:: exception & e)
{
LOGERROR( lg,"exception:%s" ,e.what ( ) ) ;
return 0 ;
}
Matrix m;
//m.resize(H,Row(W,Cell()));
//for(int y=0;y<H;++y)
size_t y= 0 ;
std:: string line;
while ( f.ReadLine ( line) )
{
m.push_back ( Row( line.size ( ) ,Cell( ) ) ) ;
if ( line.size ( ) ! = m[ 0 ] .size ( ) )
{
LOGERROR( lg,"invalid line[%d] length=%d in testmap.txt, expected %d" ,y,line.size ( ) ,m[ 0 ] .size ( ) ) ;
return 0 ;
}
for ( size_t x= 0 ; x< line.size ( ) ; ++ x)
{
Cell& c= m[ y] [ x] ;
c.tempBlock = line[ x] == '*' ;
c.delayBlock = line[ x] == '|' || line[ x] == '-' ;
c.block = line[ x] == '#' || c.tempBlock || c.delayBlock ;
c.vis = true ;
c.corners [ 0 ] = 100 ;
c.corners [ 1 ] = 100 ;
c.corners [ 2 ] = 100 ;
c.corners [ 3 ] = 100 ;
}
++ y;
}
int W= m[ 0 ] .size ( ) ;
int H= m.size ( ) ;
int cornAngle= 60 ;
for ( int y= 0 ; y< H; ++ y)
{
for ( int x= 0 ; x< W; ++ x)
{
if ( m[ y] [ x] .block )
{
if ( y> 0 && x> 0 && ! m[ y- 1 ] [ x] .block && ! m[ y] [ x- 1 ] .block )
{
m[ y] [ x] .corners [ 3 ] = cornAngle;
}
if ( y> 0 && x< W- 1 && ! m[ y- 1 ] [ x] .block && ! m[ y] [ x+ 1 ] .block )
{
m[ y] [ x] .corners [ 2 ] = cornAngle;
}
if ( y< H- 1 && x< W- 1 && ! m[ y+ 1 ] [ x] .block && ! m[ y] [ x+ 1 ] .block )
{
m[ y] [ x] .corners [ 1 ] = cornAngle;
}
if ( y< H- 1 && x> 0 && ! m[ y+ 1 ] [ x] .block && ! m[ y] [ x- 1 ] .block )
{
m[ y] [ x] .corners [ 0 ] = cornAngle;
}
}
}
}
px= W/ 2 ;
py= H/ 2 ;
MyEventHandler meh( m) ;
engine.assignHandler ( & meh) ;
engine.enableKeyboardRepeat ( ) ;
Scene sc;
FontRef fnt1= manager.getFont ( "FSEX300.ttf" ,16 ) ;
Text* txt= new Text( fnt1,"hello" ) ;
txt- > setPosition( Pos( 10 ,10 ) ) ;
vb= new VertexBuffer;
lsa= new Line( Pos( 0 ,0 ) ,Pos( 10 ,0 ) ) ;
lea= new Line( Pos( 0 ,0 ) ,Pos( 0 ,10 ) ) ;
info= new Text( fnt1,"Info" ) ;
info- > setPosition( Pos( W* CELL_SIZE,0 ) ) ;
VxVector& v= vb- > getVBuf( ) ;
ClrVector& c= vb- > getCBuf( ) ;
for ( int y= 0 ; y< H; ++ y)
{
for ( int x= 0 ; x< W; ++ x)
{
//glider::Rectangle* r=new glider::Rectangle(Rect(x*15,y*15,10,10),Color(1,0.1+x/20+y/20,0.1));
//sc.addObject(r);
Rect( x* CELL_SIZE+ 1 ,y* CELL_SIZE+ 1 ,CELL_SIZE- 2 ,CELL_SIZE- 2 ) .pushQuad ( v) ;
c.push4 ( Color:: gray ) ;
}
}
vb- > update( ) ;
cf.prepare ( sightRadius) ;
cf.generateFov ( m,sightRadius) ;
drawMap( m) ;
sc.addObject ( vb) ;
sc.addObject ( lsa) ;
sc.addObject ( lea) ;
sc.addObject ( info) ;
//sc.addObject(txt);
engine.loop ( & sc) ;
// for(CircularFov::Ring::iterator it=cf.fov[2].begin(),end=cf.fov[2].end();it!=end;++it)
// {
// FovCell& fc=*it;
// printf("%d,%d:%.3lf-%.3lf\n",fc.p.x,fc.p.y,fc.sa/1000000.0,fc.ea/1000000.0);
// }
// for(CircularFov::Ring::iterator it=cf.fov[3].begin(),end=cf.fov[3].end();it!=end;++it)
// {
// FovCell& fc=*it;
// printf("%d,%d:%.3lf-%.3lf\n",fc.p.x,fc.p.y,fc.sa/1000000.0,fc.ea/1000000.0);
// }
return 0 ;
}
I2luY2x1ZGUgIlJlY3RhbmdsZS5ocHAiCiNpbmNsdWRlICJFbmdpbmUuaHBwIgojaW5jbHVkZSAiTGluZS5ocHAiCiNpbmNsdWRlICJJbWFnZS5ocHAiCiNpbmNsdWRlIDx1bmlzdGQuaD4KI2luY2x1ZGUgIlNjZW5lLmhwcCIKI2luY2x1ZGUgIlRleHQuaHBwIgojaW5jbHVkZSAiVGltZXIuaHBwIgojaW5jbHVkZSA8dGltZS5oPgojaW5jbHVkZSAiUmVzb3VyY2VzTWFuYWdlci5ocHAiCiNpbmNsdWRlIDxzdHJpbmc+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgIlZlcnRleEJ1ZmZlci5ocHAiCiNpbmNsdWRlICJHTFN0YXRlLmhwcCIKI2luY2x1ZGUgIlNjaXNzb3JzLmhwcCIKI2luY2x1ZGUgPGtzdC9Mb2dnZXIuaHBwPgojaW5jbHVkZSAiVmVydGV4QnVmZmVyLmhwcCIKI2luY2x1ZGUgPHNldD4KI2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPFNETC9TREwuaD4KI2luY2x1ZGUgImtzdC9GaWxlLmhwcCIKCnVzaW5nIG5hbWVzcGFjZSBnbGlkZXI7Cgpjb25zdCBpbnQgQ0VMTF9TSVpFPTE1OwoKc3RydWN0IEFuZ2xlUmFuZ2V7CiAgaW50IHNhLGVhOwogIGJvb2wgY2xvc2VkOwogIHN0YXRpYyBjb25zdCBpbnQgU0NBTEVEX1BJXzIgPTkwMDAwMDAwOwogIHN0YXRpYyBjb25zdCBpbnQgU0NBTEVEX1BJICA9MTgwMDAwMDAwOwogIHN0YXRpYyBjb25zdCBpbnQgU0NBTEVEX1BJeDI9MzYwMDAwMDAwOwogIEFuZ2xlUmFuZ2UoaW50IGFyZ1NhPTAsaW50IGFyZ0VhPTApOnNhKGFyZ1NhKSxlYShhcmdFYSksY2xvc2VkKGZhbHNlKXt9CiAgdm9pZCBzZXRTYShpbnQgYXJnU2EpCiAgewogICAgaWYoIWNsb3NlZCAmJiAoKHNhPGVhICYmIGFyZ1NhPmVhKXx8KHNhPmVhICYmIGFyZ1NhPHNhICYmIGFyZ1NhPmVhKSkpY2xvc2VkPXRydWU7CiAgICBzYT1hcmdTYTsKICB9CiAgdm9pZCBzZXRFYShpbnQgYXJnRWEpCiAgewogICAgaWYoIWNsb3NlZCAmJiAoKHNhPGVhICYmIHNhPmFyZ0VhKXx8KHNhPmVhICYmIGFyZ0VhPmVhICYmIGFyZ0VhPHNhKSkpY2xvc2VkPXRydWU7CiAgICBlYT1hcmdFYTsKICB9CiAgYm9vbCBvcGVyYXRvcjwoY29uc3QgQW5nbGVSYW5nZSYgb3RoZXIpY29uc3QKICB7CiAgICByZXR1cm4gZWE8b3RoZXIuZWE7CiAgfQogIGRvdWJsZSBzYVNjYWxlZCgpCiAgewogICAgcmV0dXJuIHNhLzEwMDAwMDAuMDsKICB9CiAgZG91YmxlIGVhU2NhbGVkKCkKICB7CiAgICByZXR1cm4gZWEvMTAwMDAwMC4wOwogIH0KICBpbnQgbWlkZGxlKCkKICB7CiAgICBpZihzYTxlYSlyZXR1cm4gKHNhK2VhKS8yOwogICAgcmV0dXJuIChzYStlYStTQ0FMRURfUEl4MiklU0NBTEVEX1BJeDI7CiAgfQogIHZvaWQgc2hyaW5rQ29ybmVycyhpbnQgc2FQcmMsaW50IGVhUHJjKQogIHsKICAgIGlmKHNhPmVhKQogICAgewogICAgICBlYSs9QW5nbGVSYW5nZTo6U0NBTEVEX1BJeDI7CiAgICB9CiAgICB1aW50NjRfdCBtaWQ9bWlkZGxlKCk7CiAgICB1aW50NjRfdCB2YWw9bWlkLXNhOwogICAgdmFsKj1zYVByYzsKICAgIHZhbC89MTAwOwogICAgc2E9KG1pZC12YWwpJUFuZ2xlUmFuZ2U6OlNDQUxFRF9QSXgyOwogICAgdmFsPWVhLW1pZDsKICAgIHZhbCo9ZWFQcmM7CiAgICB2YWwvPTEwMDsKICAgIGVhPShtaWQrdmFsKSVBbmdsZVJhbmdlOjpTQ0FMRURfUEl4MjsKICB9CiAgaW50IGRpZmYoKQogIHsKICAgIGlmKHNhPGVhKXJldHVybiBlYS1zYTsKICAgIHJldHVybiAoZWErU0NBTEVEX1BJeDItc2EpJVNDQUxFRF9QSXgyOwogIH0KICBib29sIGluUmFuZ2UoaW50IGEpCiAgewogICAgaWYoY2xvc2VkKXJldHVybiBmYWxzZTsKICAgIGlmKHNhPGVhKXJldHVybiBhPj1zYSAmJiBhPD1lYTsKICAgIHJldHVybiBhPj1zYSB8fCBhPD1lYTsKICB9CiAgdm9pZCBtaXJyb3I0NSgpCiAgewogICAgc2E9KFNDQUxFRF9QSSoyK1NDQUxFRF9QSS8yLXNhKSUoU0NBTEVEX1BJKjIpOwogICAgZWE9KFNDQUxFRF9QSSoyK1NDQUxFRF9QSS8yLWVhKSUoU0NBTEVEX1BJKjIpOwogICAgc3RkOjpzd2FwKHNhLGVhKTsKICB9CiAgdm9pZCBtaXJyb3I5MCgpCiAgewogICAgc2E9KFNDQUxFRF9QSSozLXNhKSUoU0NBTEVEX1BJKjIpOwogICAgZWE9KFNDQUxFRF9QSSozLWVhKSUoU0NBTEVEX1BJKjIpOwogICAgc3RkOjpzd2FwKHNhLGVhKTsKICB9CiAgdm9pZCBtaXJyb3IxODAoKQogIHsKICAgIHNhPShTQ0FMRURfUEkqNC1zYSklKFNDQUxFRF9QSSoyKTsKICAgIGVhPShTQ0FMRURfUEkqNC1lYSklKFNDQUxFRF9QSSoyKTsKICAgIHN0ZDo6c3dhcChzYSxlYSk7CiAgfQp9OwoKc3RydWN0IEZvdkNlbGx7CiAgQW5nbGVSYW5nZSByOwogIHVpbnQ4X3Qgc2FjLGVhYzsKICB1aW50OF90IG8xLG8yOwogIFBvc2k8aW50PiBwOwogIGJvb2wgdGVtcEJsb2NrOwogIGJvb2wgZGVsYXlCbG9jazsKICBpbnQgcmFuZ2U7CiAgYm9vbCBvcGVyYXRvcjwoY29uc3QgRm92Q2VsbCYgb3RoZXIpY29uc3QKICB7CiAgICByZXR1cm4gcjxvdGhlci5yOwogIH0KICB2b2lkIHN3YXBwKCkKICB7CiAgICBzdGQ6OnN3YXAocC54LHAueSk7CiAgfQogIHZvaWQgc3dhcGMoKQogIHsKICAgIHN0ZDo6c3dhcChzYWMsZWFjKTsKICB9Cn07CgoKc3RydWN0IENlbGx7CiAgYm9vbCBibG9jazsKICBib29sIHZpczsKICBib29sIHRlbXBCbG9jazsKICBib29sIGRlbGF5QmxvY2s7CiAgaW50IGNvcm5lcnNbNF07CiAgRm92Q2VsbCBmYzsKICBpbnQgcjsKICBzdGQ6OnN0cmluZyBsb2c7Cn07Cgp0eXBlZGVmIHN0ZDo6dmVjdG9yPENlbGw+IFJvdzsKdHlwZWRlZiBzdGQ6OnZlY3RvcjxSb3c+IE1hdHJpeDsKCi8qY29uc3QgY2hhciogdGVzdG1hcFtdPXsKIiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMiLAoiIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIyMjIyMjIyMuLi4uLiMiLAoiIy4uLi4uLiMjIyMjIyMjLi4uLi4uLi4uLiMuLi4uLi4uIy4uLi4uIyIsCiIjLi4uLi4uIy4uLi4uLiMjIyMjIyMjIyMjIy4uLi4uLi4jLi4uLi4jIiwKIiMuLi4uLi4jLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLnwuLi4uLiMiLAoiIy4uLi4uLiMuLi4uLi4jIyMjIyMjIyMjIy4uLi4uLi4ufC4uLi4uIyIsCiIjLi4uLi4uIyMjLS0jIyMuLi4uLi4uLi4jLi4uLi4uLi4jLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiMjIy4jIyMjIyMuLi4uLiMiLAoiIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jLiMuLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiMjIyMuIyMjIy4uLi4uLi4jIiwKIiMuLi4uLi4uIy4jLiMuIy4jLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiMiLAoiIy4uLi4uLi4uIy4jLiMuIy4uLi4uLi4jIyMjIyMjIyMuLi4uLi4uIyIsCiIjLi4uLi4uLiMuIy4jLiMuIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLiMuIy4jLiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiMiLAoiIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiMuLi4uLi4uLi4uIyIsCiIjLi4uLi4uLiMuLi4uLi4uLi4uLi4uLi4uLi4uIy4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIyMuLi4uLi4uLiMiLAoiIy4uLi4jLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uLiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLi4uLi4uLiMuLi4uLi4uLi4uLi4uLi4uLiMiLAoiIy4uIy4uLi4uLiMuLi4uLi4uLi4jLi4uLi4uLi4uLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uIyMjLiMjIyMuLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uIy4uLi4uLi4uLi4uIy4uLi4uLi4uLiMjLi4uLi4uLiMiLAoiIy4uLi4uLi4uLi4uLiMjIy4jIyMjLi4uLi4uLi4uIyMuLi4uLi4uIyIsCiIjLi4uLi4uIy4uLi4uLi4jLiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLiMjIy4uLi4uLi4uLi4uLi4uLi4uLi4uLiMiLAoiIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLiMiLAoiIy4uLi4uLi4uLioqKioqLi4uLi4uLi4jIy0tIyMuLi4uLi4uLi4uIyIsCiIjLi4uLioqLi4uLi4uLiouLi4uLi4uLiMuLi4uIy4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uKi4uLi4uLi4ufC4uLi58Li4uLi4uLi4uLiMiLAoiIy4uLi4uLi4uLi4uLi4qLi4uLi4uLi58Li4uLnwuLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uLiouLi4uLi4uLiMuLi4uIy4uLi4uLi4uLi4jIiwKIiMuLi4uLi4uLi4uLi4uLi4uLi4uLi4uIyMuLiMjLi4uLi4uLi4uLiMiLAoiIy4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uIyIsCiIjLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4jIiwKIiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMiLAp9OyovCgoKCgppbnQgcHg7CmludCBweTsKaW50IHNpZ2h0UmFkaXVzPTE1OwpWZXJ0ZXhCdWZmZXIqIHZiOwpMaW5lKiBsc2E7CkxpbmUqIGxlYTsKVGV4dCogaW5mbzsKCnZvaWQgZHJhd01hcChNYXRyaXgmIG0pCnsKICBpbnQgSD1tLnNpemUoKTsKICBpbnQgVz1tWzBdLnNpemUoKTsKICBDb2xvciBjbHI7CiAgQ2xyVmVjdG9yJiBjPXZiLT5nZXRDQnVmKCk7CiAgZm9yKGludCB5PTA7eTxIOysreSkKICB7CiAgICBmb3IoaW50IHg9MDt4PFc7Kyt4KQogICAgewogICAgICBpZihtW3ldW3hdLmJsb2NrKWNscj1Db2xvcjo6d2hpdGU7ZWxzZSBjbHI9Q29sb3I6OmJsdWU7CiAgICAgIGlmKHg9PXB4ICYmIHk9PXB5KWNscj1Db2xvcjo6cmVkOwogICAgICBpZihtW3ldW3hdLnRlbXBCbG9jaykKICAgICAgewogICAgICAgIGNscj1Db2xvcjo6Z3JlZW47CiAgICAgIH0KICAgICAgaWYobVt5XVt4XS5kZWxheUJsb2NrKQogICAgICB7CiAgICAgICAgY2xyPUNvbG9yOjpncmF5OwogICAgICB9CiAgICAgIGlmKCFtW3ldW3hdLnZpcykKICAgICAgewogICAgICAgIGNscj1jbHIvMjsKICAgICAgfQogICAgICBmb3IoaW50IGk9MDtpPDQ7KytpKQogICAgICB7CiAgICAgICAgY1soeCt5KlcpKjQraV09Y2xyOwogICAgICB9CiAgICB9CiAgfQogIHZiLT51cGRhdGUoKTsKfQoKbmFtZXNwYWNlIGtzdHsKdm9pZCBjdXN0b21mb3JtYXQoa3N0OjpGb3JtYXRCdWZmZXImIGJ1Zixkb3VibGUgdixpbnQgdyxpbnQgcCkKewogIGNoYXIgYnVmMls2NF07CiAgc2l6ZV90IGxlbj1zcHJpbnRmKGJ1ZjIsIiUqLipsZiIsdyxwLHYpOwogIGJ1Zi5BcHBlbmQoYnVmMixsZW4pOwp9Cn0KCmNsYXNzIENpcmN1bGFyRm92ewpwdWJsaWM6CgogIENpcmN1bGFyRm92KCk6ZGVidWcodHJ1ZSkKICB7CiAgfQoKICBzdGF0aWMgaW50IGdldEFuZ2xlKGRvdWJsZSB4LGRvdWJsZSB5LGRvdWJsZSBxdWFkcmFudCkKICB7CiAgICByZXR1cm4gKGF0YW4oeS94KStxdWFkcmFudCkqKEFuZ2xlUmFuZ2U6OlNDQUxFRF9QSV8yKS9NX1BJXzI7CiAgfQoKICB2b2lkIHByZXBhcmUoaW50IG1heFJhZGl1cykKICB7CiAgICBpZihmb3YuZW1wdHkoKSlmb3YucHVzaF9iYWNrKFJpbmcoKSk7CiAgICBmb3IoaW50IHI9Zm92LnNpemUoKTtyPD1tYXhSYWRpdXM7KytyKQogICAgewogICAgICBmb3YucHVzaF9iYWNrKFJpbmcoKSk7CiAgICAgIFJpbmcmIHJpbmc9Zm92LmJhY2soKTsKICAgICAgLy9kb3VibGUgcnI9cipyOy8vKHIrMC41KSoociswLjUpOwogICAgICBmb3IoaW50IHk9MDt5PD1yOysreSkKICAgICAgewogICAgICAgIGZvcihpbnQgeD15O3g8PXI7Kyt4KQogICAgICAgIHsKICAgICAgICAgIGlmKHg9PTAgJiYgeT09MCljb250aW51ZTsKICAgICAgICAgIGRvdWJsZSBkeD14Oy8vLTAuNTsKICAgICAgICAgIGRvdWJsZSBkeT15Oy8vLTAuNTsKICAgICAgICAgIGlmKGZsb29yKHNxcnQoZHgqZHgrZHkqZHkpKTw9cikKICAgICAgICAgIHsKICAgICAgICAgICAgUG9zIHAoeCx5KTsKICAgICAgICAgICAgaWYocHJvY2Vzc2VkLmZpbmQocCkhPXByb2Nlc3NlZC5lbmQoKSljb250aW51ZTsKICAgICAgICAgICAgcHJvY2Vzc2VkLmluc2VydChwKTsKICAgICAgICAgICAgaW50IHNhLGVhLHNhYyxlYWMsbzEsbzI7CiAgICAgICAgICAgIC8qaWYoeD09MCkKICAgICAgICAgICAgewogICAgICAgICAgICAgIHNhPWdldEFuZ2xlKDAuNSx5LTAuNSwwKTsKICAgICAgICAgICAgICBlYT1nZXRBbmdsZSgtMC41LHktMC41LE1fUElfMik7CiAgICAgICAgICAgIH1lbHNlCiAgICAgICAgICAgIHsqLwogICAgICAgICAgICBpZih5PT0wKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgc2E9Z2V0QW5nbGUoeC0wLjUsLTAuNSxNX1BJKjIpOwogICAgICAgICAgICAgIGVhPWdldEFuZ2xlKHgtMC41LDAuNSwwKS0xOwogICAgICAgICAgICAgIHNhYz0zOwogICAgICAgICAgICAgIGVhYz0wOwogICAgICAgICAgICAgIG8xPTA7CiAgICAgICAgICAgICAgbzI9NzsKICAgICAgICAgICAgfWVsc2UgaWYoeD09eSkKICAgICAgICAgICAgewogICAgICAgICAgICAgIHNhPWdldEFuZ2xlKHgrMC41LHktMC41LDApOwogICAgICAgICAgICAgIGVhPWdldEFuZ2xlKHgtMC41LHkrMC41LDApOwogICAgICAgICAgICAgIHNhYz0yOwogICAgICAgICAgICAgIGVhYz0wOwogICAgICAgICAgICAgIG8xPTA7CiAgICAgICAgICAgICAgbzI9MTsKICAgICAgICAgICAgfWVsc2UKICAgICAgICAgICAgewogICAgICAgICAgICAgIHNhPWdldEFuZ2xlKHgrMC41LHktMC41LDApOwogICAgICAgICAgICAgIGVhPWdldEFuZ2xlKHgtMC41LHkrMC41LDApOwogICAgICAgICAgICAgIHNhYz0yOwogICAgICAgICAgICAgIGVhYz0wOwogICAgICAgICAgICAgIG8xPW8yPTA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy99CiAgICAgICAgICAgIHJpbmcucHVzaF9iYWNrKEZvdkNlbGwoKSk7CiAgICAgICAgICAgIEZvdkNlbGwmIGZjPXJpbmcuYmFjaygpOwogICAgICAgICAgICBmYy5yLnNhPXNhKzU7CiAgICAgICAgICAgIGZjLnIuZWE9ZWEtNTsKICAgICAgICAgICAgZmMuc2FjPXNhYzsKICAgICAgICAgICAgZmMuZWFjPWVhYzsKICAgICAgICAgICAgZmMubzE9bzE7CiAgICAgICAgICAgIGZjLm8yPW8yOwogICAgICAgICAgICBmYy5wPXA7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIHNpemVfdCBlbmQ9cmluZy5zaXplKCk7CiAgICAgIGZvcihzaXplX3QgaT0wO2k8ZW5kOysraSkKICAgICAgewogICAgICAgIEZvdkNlbGwgZmM9cmluZ1tpXTsKICAgICAgICBpZihmYy5wLng9PWZjLnAueSljb250aW51ZTsKICAgICAgICBmYy5zd2FwcCgpOwogICAgICAgIGZjLnIubWlycm9yNDUoKTsKICAgICAgICBmYy5zYWM9ZmMuc2FjPT0wPzI6ZmMuc2FjPT0yPzA6ZmMuc2FjOwogICAgICAgIGZjLmVhYz1mYy5lYWM9PTA/MjpmYy5lYWM9PTI/MDpmYy5lYWM7CiAgICAgICAgZmMuc3dhcGMoKTsKICAgICAgICBmYy5vMT0xOwogICAgICAgIGZjLm8yPWZjLm8yPT03PzI6MTsKICAgICAgICByaW5nLnB1c2hfYmFjayhmYyk7CiAgICAgIH0KICAgICAgZW5kPXJpbmcuc2l6ZSgpOwogICAgICBpbnQgY3RbNF09ezEsMCwzLDJ9OwogICAgICBmb3Ioc2l6ZV90IGk9MDtpPGVuZDsrK2kpCiAgICAgIHsKICAgICAgICBGb3ZDZWxsIGZjPXJpbmdbaV07CiAgICAgICAgaWYoZmMucC54PT0wKWNvbnRpbnVlOwogICAgICAgIGZjLnAueD0tZmMucC54OwogICAgICAgIGZjLnIubWlycm9yOTAoKTsKICAgICAgICBmYy5zYWM9Y3RbZmMuc2FjXTsKICAgICAgICBmYy5lYWM9Y3RbZmMuZWFjXTsKICAgICAgICBmYy5zd2FwYygpOwogICAgICAgIGZjLm8xPWZjLm8xPT0wPzM6MjsKICAgICAgICBmYy5vMj1mYy5vMj09Nz80OmZjLm8yPT0wPzM6MjsKICAgICAgICByaW5nLnB1c2hfYmFjayhmYyk7CiAgICAgIH0KICAgICAgZW5kPXJpbmcuc2l6ZSgpOwogICAgICBpbnQgY3QyWzRdPXszLDIsMSwwfTsKICAgICAgZm9yKHNpemVfdCBpPTA7aTxlbmQ7KytpKQogICAgICB7CiAgICAgICAgRm92Q2VsbCBmYz1yaW5nW2ldOwogICAgICAgIGlmKGZjLnAueT09MCljb250aW51ZTsKICAgICAgICBmYy5wLnk9LWZjLnAueTsKICAgICAgICBmYy5yLm1pcnJvcjE4MCgpOwogICAgICAgIGZjLnNhYz1jdDJbZmMuc2FjXTsKICAgICAgICBmYy5lYWM9Y3QyW2ZjLmVhY107CiAgICAgICAgZmMuc3dhcGMoKTsKICAgICAgICBmYy5vMT03LWZjLm8xOwogICAgICAgIGZjLm8yPTctZmMubzI7CiAgICAgICAgcmluZy5wdXNoX2JhY2soZmMpOwogICAgICB9CiAgICAgIC8vc3RkOjpzb3J0KHJpbmcuYmVnaW4oKSxyaW5nLmVuZCgpKTsKICAgIH0KICB9CgogIHZvaWQgZ2VuZXJhdGVGb3YoTWF0cml4JiBtLGludCBtYXhSYWRpdXMpCiAgewogICAgaWYoZm92LnNpemUoKTxtYXhSYWRpdXMrMSkKICAgIHsKICAgICAgcHJlcGFyZShtYXhSYWRpdXMpOwogICAgfQogICAgaW50IEg9bS5zaXplKCk7CiAgICBpbnQgVz1tWzBdLnNpemUoKTsKICAgIGZvcihpbnQgeT0wO3k8SDsrK3kpCiAgICB7CiAgICAgIGZvcihpbnQgeD0wO3g8VzsrK3gpCiAgICAgIHsKICAgICAgICBtW3ldW3hdLnZpcz1mYWxzZTsKICAgICAgfQogICAgfQogICAgZm9yKGludCBpPTA7aTw4OysraSliW2ldLmNsZWFyKCk7CiAgICBmb3IoaW50IHJpPTE7cmk8PW1heFJhZGl1czsrK3JpKQogICAgewogICAgICBSaW5nJiByaW5nPWZvdltyaV07CiAgICAgIGZvcihSaW5nOjppdGVyYXRvciBpdD1yaW5nLmJlZ2luKCksZW5kPXJpbmcuZW5kKCk7aXQhPWVuZDsrK2l0KQogICAgICB7CiAgICAgICAgRm92Q2VsbCBmYz0qaXQ7CiAgICAgICAgaW50IHg9cHgrZmMucC54OwogICAgICAgIGludCB5PXB5K2ZjLnAueTsKICAgICAgICBpZih4PDAgfHwgeD49VyB8fCB5PDAgfHwgeT49SCljb250aW51ZTsKICAgICAgICBDZWxsJiBjPW1beV1beF07CiAgICAgICAgZmMuZGVsYXlCbG9jaz1jLmRlbGF5QmxvY2s7CiAgICAgICAgZmMudGVtcEJsb2NrPWMudGVtcEJsb2NrOwogICAgICAgIGZjLnJhbmdlPXJpKzI7CiAgICAgICAgYy5mYz1mYzsKICAgICAgICBjLnI9cmk7CiAgICAgICAgYy5sb2c9IiI7CiAgICAgICAgQW5nbGVSYW5nZSByPWZjLnI7CiAgICAgICAgYm9vbCB0b3RhbEJsb2NrPWZhbHNlOwogICAgICAgIGJvb2wgc2FCbG9jazsKICAgICAgICBpbnQgYnNvPS0xLGJzaT0tMTsKICAgICAgICBpbnQgYmVvPS0xLGJlaT0tMTsKICAgICAgICBib29sIHVzZWRUZW1wQmxvY2s9ZmFsc2U7CiAgICAgICAgZm9yKGludCBrPTA7azwyOysraykKICAgICAgICB7CiAgICAgICAgICBpbnQgbz1mYy5vMTsKICAgICAgICAgIGlmKGs9PTEpCiAgICAgICAgICB7CiAgICAgICAgICAgIGlmKGZjLm8xPT1mYy5vMilicmVhazsKICAgICAgICAgICAgbz1mYy5vMjsKICAgICAgICAgIH0KCiAgICAgICAgICBmb3Ioc2l6ZV90IGk9MDtpPGJbb10uc2l6ZSgpOysraSkKICAgICAgICAgIHsKICAgICAgICAgICAgRm92Q2VsbCBiYz1iW29dW2ldOwogICAgICAgICAgICBpZihiYy5kZWxheUJsb2NrICYmIGJjLnJhbmdlPj1yaSljb250aW51ZTsKICAgICAgICAgICAgaWYoYmMudGVtcEJsb2NrICYmIGJjLnJhbmdlPHJpKWNvbnRpbnVlOwogICAgICAgICAgICBzYUJsb2NrPWZhbHNlOwogICAgICAgICAgICBpZighYy5ibG9jayAmJiByLmluUmFuZ2UoYmMuci5zYSkgJiYgci5pblJhbmdlKGJjLnIuZWEpKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgaWYoZGVidWcpCiAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgYy5sb2crPUZPUk1BVCgic2E9JXs6LDN9LGVhPSV7OiwzfSB0b3RhbGx5IGJsb2NrZWQgYnkgJWQsJWQ6JXs6LDN9LCV7OiwzfVxuIixyLnNhU2NhbGVkKCksci5lYVNjYWxlZCgpLHB4K2JjLnAueCxweStiYy5wLnksYmMuci5zYVNjYWxlZCgpLGJjLnIuZWFTY2FsZWQoKSk7OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB0b3RhbEJsb2NrPXRydWU7CiAgICAgICAgICAgICAgdXNlZFRlbXBCbG9jaz11c2VkVGVtcEJsb2NrIHx8IGJjLnRlbXBCbG9jazsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZihiYy5yLmluUmFuZ2Uoci5zYSkvKiAgJiYgYmMuZWE+c2EqLykKICAgICAgICAgICAgewogICAgICAgICAgICAgIGlmKGRlYnVnKQogICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGMubG9nKz1GT1JNQVQoInNhPSV7OiwzfSBibG9ja2VkIGJ5ICVkLCVkOiV7OiwzfSwlezosM31cbiIsci5zYVNjYWxlZCgpLHB4K2JjLnAueCxweStiYy5wLnksYmMuci5zYVNjYWxlZCgpLGJjLnIuZWFTY2FsZWQoKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHIuc2V0U2EoYmMuci5lYSk7CiAgICAgICAgICAgICAgc2FCbG9jaz10cnVlOwogICAgICAgICAgICAgIGJzbz1vO2JzaT1pOwogICAgICAgICAgICAgIHVzZWRUZW1wQmxvY2s9dXNlZFRlbXBCbG9jayB8fCBiYy50ZW1wQmxvY2s7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYoYmMuci5pblJhbmdlKHIuZWEpLyogJiYgYmMuc2E8ZWEqLykKICAgICAgICAgICAgewogICAgICAgICAgICAgIGlmKGRlYnVnKQogICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGMubG9nKz1GT1JNQVQoImVhPSV7OiwzfSBibG9ja2VkIGJ5ICVkLCVkOiV7OiwzfSwlezosM31cbiIsci5lYVNjYWxlZCgpLHB4K2JjLnAueCxweStiYy5wLnksYmMuci5zYVNjYWxlZCgpLGJjLnIuZWFTY2FsZWQoKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHIuc2V0RWEoYmMuci5zYSk7CiAgICAgICAgICAgICAgYmVvPW87YmVpPWk7CiAgICAgICAgICAgICAgdXNlZFRlbXBCbG9jaz11c2VkVGVtcEJsb2NrIHx8IGJjLnRlbXBCbG9jazsKICAgICAgICAgICAgICBpZihzYUJsb2NrKQogICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHRvdGFsQmxvY2s9dHJ1ZTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZihyLmNsb3NlZClicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGlmKHIuY2xvc2VkIHx8IHRvdGFsQmxvY2spYnJlYWs7CiAgICAgICAgfQogICAgICAgIGlmKGMuYmxvY2spCiAgICAgICAgewogICAgICAgICAgYy52aXM9dXNlZFRlbXBCbG9jayB8fCAoIXRvdGFsQmxvY2sgJiYgIXIuY2xvc2VkKTsKICAgICAgICAgIGlmKGRlYnVnKQogICAgICAgICAgewogICAgICAgICAgICBjLmxvZys9Rk9STUFUKCJ2aXMgci5zYT0lezosM30sci5lYT0lezosM30gJXt9XG4iLHIuc2FTY2FsZWQoKSxyLmVhU2NhbGVkKCksci5jbG9zZWQ/ImNsb3NlZCI6IiIpOwogICAgICAgICAgfQogICAgICAgIH1lbHNlCiAgICAgICAgewogICAgICAgICAgaWYoIXRvdGFsQmxvY2spCiAgICAgICAgICB7CiAgICAgICAgICAgIGludCByMT1yLmRpZmYoKTsKICAgICAgICAgICAgaW50IHIyPWZjLnIuZGlmZigpOwogICAgICAgICAgICBpZihkZWJ1ZykKICAgICAgICAgICAgewogICAgICAgICAgICAgIGMubG9nKz1GT1JNQVQoInZpcyByLnNhPSV7OiwzfSxyLmVhPSV7OiwzfVxuZGlmZj0lZCwgZmMuZGlmZj0lZFxubWlkPSVkXG4iLHIuc2FTY2FsZWQoKSxyLmVhU2NhbGVkKCkscjEscjIsZmMuci5taWRkbGUoKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYy52aXM9cjE+PXIyLzIgfHwgKHIxPj1yMi81ICYmIHIuaW5SYW5nZShmYy5yLm1pZGRsZSgpKSk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBpZihjLnZpcyAmJiBjLmJsb2NrKQogICAgICAgIHsKICAgICAgICAgIGlmKGMuY29ybmVyc1tmYy5zYWNdIT0xMDAgfHwgYy5jb3JuZXJzW2ZjLmVhY10hPTEwMCkKICAgICAgICAgIHsKICAgICAgICAgICAgZmMuci5zaHJpbmtDb3JuZXJzKGMuY29ybmVyc1tmYy5zYWNdLGMuY29ybmVyc1tmYy5lYWNdKTsKICAgICAgICAgICAgYy5mYz1mYzsKICAgICAgICAgIH0KICAgICAgICAgIGludCB1c2VkPTA7CgogICAgICAgICAgLyppZihic28hPS0xICYmICFmYy5kZWxheUJsb2NrICYmICFmYy50ZW1wQmxvY2spCiAgICAgICAgICB7CiAgICAgICAgICAgIEZvdkNlbGwmIGJmYz1iW2Jzb11bYnNpXTsKICAgICAgICAgICAgaWYoIWJmYy50ZW1wQmxvY2sgJiYgIWJmYy5kZWxheUJsb2NrKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgdXNlZCsrOwogICAgICAgICAgICAgIGlmKGRlYnVnKQogICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGMubG9nKz1GT1JNQVQoImV4dGVuZGVkIGVhIG9mICVkLCVkIGZyb20gJXs6LDN9IHRvICV7OiwzfVxuIixiZmMucC54K3B4LGJmYy5wLnkrcHksYmZjLnIuZWFTY2FsZWQoKSxmYy5yLmVhU2NhbGVkKCkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBiZmMuci5lYT1mYy5yLmVhOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZihiZW8hPS0xICYmICFmYy5kZWxheUJsb2NrICYmICFmYy50ZW1wQmxvY2spCiAgICAgICAgICB7CiAgICAgICAgICAgIEZvdkNlbGwmIGJmYz1iW2Jlb11bYmVpXTsKICAgICAgICAgICAgaWYoIWJmYy50ZW1wQmxvY2sgJiYgIWJmYy5kZWxheUJsb2NrKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgdXNlZCsrOwogICAgICAgICAgICAgIGlmKGRlYnVnKQogICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGMubG9nKz1GT1JNQVQoImV4dGVuZGVkIHNhIG9mICVkLCVkIGZyb20gJXs6LDN9IHRvICV7OiwzfVxuIixiZmMucC54K3B4LGJmYy5wLnkrcHksYmZjLnIuc2FTY2FsZWQoKSxmYy5yLnNhU2NhbGVkKCkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBiZmMuci5zYT1mYy5yLnNhOwogICAgICAgICAgICB9CiAgICAgICAgICB9Ki8KICAgICAgICAgIGlmKHVzZWQ9PTApCiAgICAgICAgICB7CiAgICAgICAgICAgIGJbZmMubzFdLnB1c2hfYmFjayhmYyk7CiAgICAgICAgICB9CiAgICAgICAgICBpZihmYy5vMSE9ZmMubzIpCiAgICAgICAgICB7CiAgICAgICAgICAgIGJbZmMubzJdLnB1c2hfYmFjayhmYyk7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgfQogICAgICBmb3IoaW50IGk9MDtpPDg7KytpKQogICAgICB7CiAgICAgICAgYltpXS5pbnNlcnQoYltpXS5lbmQoKSx0W2ldLmJlZ2luKCksdFtpXS5lbmQoKSk7CiAgICAgICAgdFtpXS5jbGVhcigpOwogICAgICB9CiAgICB9CiAgICBpbmZvLT5zZXRUZXh0KEZPUk1BVCgiYmNbXT17JXt9LCV7fSwle30sJXt9LCV7fSwle30sJXt9LCV7fX0iLAogICAgICAgIGJbMF0uc2l6ZSgpLGJbMV0uc2l6ZSgpLGJbMl0uc2l6ZSgpLGJbM10uc2l6ZSgpLGJbNF0uc2l6ZSgpLGJbNV0uc2l6ZSgpLGJbNl0uc2l6ZSgpLGJbN10uc2l6ZSgpKSk7CiAgICBkcmF3TWFwKG0pOwogIH0KCi8vcHJvdGVjdGVkOgogIHR5cGVkZWYgc3RkOjp2ZWN0b3I8Rm92Q2VsbD4gUmluZzsKICB0eXBlZGVmIHN0ZDo6dmVjdG9yPFJpbmc+IENpcmNsZTsKCiAgQ2lyY2xlIGZvdjsKICBzdGQ6OnNldDxQb3NpPGludD4gPiBwcm9jZXNzZWQ7CiBzdGQ6OnZlY3RvcjxGb3ZDZWxsPiBiWzhdLHRbOF07CiAgYm9vbCBkZWJ1ZzsKfTsKCkNpcmN1bGFyRm92IGNmOwoKY2xhc3MgTXlFdmVudEhhbmRsZXI6cHVibGljIEV2ZW50SGFuZGxlcnsKcHVibGljOgogIE15RXZlbnRIYW5kbGVyKE1hdHJpeCYgYXJnTSk6bShhcmdNKQogIHsKICAgIHZpZXdBdC54PS0xOwogICAgdmlld0F0Lnk9LTE7CiAgfQogIHZvaWQgb25BY3RpdmVDaGFuZ2UoYm9vbCBhY3RpdmUpCiAgewogIH0KICB2b2lkIG9uTW91c2VFdmVudChNb3VzZUV2ZW50JiBhcmdFdmVudCkKICB7CiAgICBpZihhcmdFdmVudC5ldmVudFR5cGU9PW1ldEJ1dHRvblByZXNzICYmIGFyZ0V2ZW50LmV2ZW50QnV0dG9uPT0xKQogICAgewogICAgICBpbnQgeD1hcmdFdmVudC54L0NFTExfU0laRTsKICAgICAgaW50IHk9YXJnRXZlbnQueS9DRUxMX1NJWkU7CiAgICAgIGlmKHg8MCB8fCB4Pj0oaW50KW1bMF0uc2l6ZSgpIHx8IHk8MCB8fCB5Pj0oaW50KW0uc2l6ZSgpKXJldHVybjsKICAgICAgdmlld0F0Lng9eDsKICAgICAgdmlld0F0Lnk9eTsKICAgICAgdXBkYXRlVmlld0F0KCk7CiAgICB9CiAgICBpZihhcmdFdmVudC5ldmVudFR5cGU9PW1ldEJ1dHRvblByZXNzICYmIGFyZ0V2ZW50LmV2ZW50QnV0dG9uPT0zKQogICAgewogICAgICB2aWV3QXQueD0tMTt2aWV3QXQueT0tMTsKICAgICAgbHNhLT5zZXRTb3VyY2UoUG9zKDAsMCkpOwogICAgICBsc2EtPnNldERlc3RpbmF0aW9uKFBvcygxMCwwKSk7CiAgICAgIGxlYS0+c2V0U291cmNlKFBvcygwLDApKTsKICAgICAgbGVhLT5zZXREZXN0aW5hdGlvbihQb3MoMCwxMCkpOwogICAgfQogIH0KICB2b2lkIHVwZGF0ZVZpZXdBdCgpCiAgewogICAgaW50IHg9dmlld0F0Lng7CiAgICBpbnQgeT12aWV3QXQueTsKICAgIGlmKHg9PS0xIHx8IHk9PS0xKXJldHVybjsKICAgIC8vcHJpbnRmKCJzZWxlY3QgJWQsJWRcbiIseCx5KTsKICAgIGNoYXIgYnVmWzI1Nl07CiAgICBzcHJpbnRmKGJ1ZiwieD0lZCx5PSVkLHI9JWQsc2E9JS4zbGYsZWE9JS4zbGZcbnNhYz0lZCxlYWM9JWRcbiIseCx5LG1beV1beF0ucixtW3ldW3hdLmZjLnIuc2FTY2FsZWQoKSxtW3ldW3hdLmZjLnIuZWFTY2FsZWQoKSxtW3ldW3hdLmZjLnNhYyxtW3ldW3hdLmZjLmVhYyk7CiAgICBzdGQ6OnN0cmluZyB0eHQ9YnVmOwogICAgdHh0Kz1tW3ldW3hdLmxvZzsKICAgIC8vaWYoIW1beV1beF0udmlzKQogICAgLy97CiAgICAgIC8vUG9zaTxpbnQ+IGJwPW1beV1beF0uOwogICAgICAvL3NwcmludGYoYnVmK2xlbiwiXG5ic2E9JS4zbGYsYmVhPSUuM2xmIixtW3ldW3hdLmJmYy5zYS8xMDAwMDAwLjAsbVt5XVt4XS5iZmMuZWEvMTAwMDAwMC4wKTsKICAgICAgLyoKICAgICAgbVticC55XVticC54XS5tYXJrPXRydWU7CiAgICAgIG1bbGFzdE1hcmsueV1bbGFzdE1hcmsueF0ubWFyaz1mYWxzZTsKICAgICAgbGFzdE1hcms9YnA7Ki8KICAgIC8vfQogICAgaW5mby0+c2V0VGV4dCh0eHQuY19zdHIoKSk7CiAgICBQb3Mgc3JjPVBvcyhweCpDRUxMX1NJWkUrQ0VMTF9TSVpFLzIuMCxweSpDRUxMX1NJWkUrQ0VMTF9TSVpFLzIuMCk7CiAgICBsc2EtPnNldFNvdXJjZShzcmMpOwogICAgbGVhLT5zZXRTb3VyY2Uoc3JjKTsKICAgIFBvcyBwOwogICAgaW50IG1yPShzaWdodFJhZGl1cysxKSpDRUxMX1NJWkU7CiAgICBkb3VibGUgc2E9bVt5XVt4XS5mYy5yLnNhKk1fUEkvQW5nbGVSYW5nZTo6U0NBTEVEX1BJOwogICAgcC54PXNyYy54K21yKmNvcyhzYSk7CiAgICBwLnk9c3JjLnkrbXIqc2luKHNhKTsKICAgIGxzYS0+c2V0RGVzdGluYXRpb24ocCk7CiAgICBkb3VibGUgZWE9bVt5XVt4XS5mYy5yLmVhKk1fUEkvQW5nbGVSYW5nZTo6U0NBTEVEX1BJOwogICAgcC54PXNyYy54K21yKmNvcyhlYSk7CiAgICBwLnk9c3JjLnkrbXIqc2luKGVhKTsKICAgIGxlYS0+c2V0RGVzdGluYXRpb24ocCk7CiAgfQogIHZvaWQgb25LZXlib2FyZEV2ZW50KEtleWJvYXJkRXZlbnQmIGFyZ0V2ZW50KQogIHsKICAgIGlmKGFyZ0V2ZW50LmtleVN5bT09a2V5Ym9hcmQ6OkdLX0VTQ0FQRSkKICAgIHsKICAgICAgZW5naW5lLmV4aXRBcHAoKTsKICAgIH0KICAgIGlmKGFyZ0V2ZW50LmV2ZW50VHlwZT09a2V0UHJlc3MpCiAgICB7CiAgICAgIGludCBveD1weDsKICAgICAgaW50IG95PXB5OwogICAgICBpZihhcmdFdmVudC5rZXlTeW09PWtleWJvYXJkOjpHS19VUCB8fCBhcmdFdmVudC5rZXlTeW09PWtleWJvYXJkOjpHS193KXB5LS07CiAgICAgIGlmKGFyZ0V2ZW50LmtleVN5bT09a2V5Ym9hcmQ6OkdLX0RPV04gfHwgYXJnRXZlbnQua2V5U3ltPT1rZXlib2FyZDo6R0tfcylweSsrOwogICAgICBpZihhcmdFdmVudC5rZXlTeW09PWtleWJvYXJkOjpHS19MRUZUIHx8IGFyZ0V2ZW50LmtleVN5bT09a2V5Ym9hcmQ6OkdLX2EpcHgtLTsKICAgICAgaWYoYXJnRXZlbnQua2V5U3ltPT1rZXlib2FyZDo6R0tfUklHSFQgfHwgYXJnRXZlbnQua2V5U3ltPT1rZXlib2FyZDo6R0tfZClweCsrOwogICAgICBpZihhcmdFdmVudC5rZXlTeW09PWtleWJvYXJkOjpHS19LUF9QTFVTKXtzaWdodFJhZGl1cysrO294PS0xO30KICAgICAgaWYoYXJnRXZlbnQua2V5U3ltPT1rZXlib2FyZDo6R0tfS1BfTUlOVVMgJiYgc2lnaHRSYWRpdXM+Mil7c2lnaHRSYWRpdXMtLTtveD0tMTt9CiAgICAgIGlmKHB4PDAgfHwgcHg+PShpbnQpbVswXS5zaXplKCkgfHwgcHk8MCB8fCBweT49KGludCltLnNpemUoKSB8fCBtW3B5XVtweF0uYmxvY2spCiAgICAgIHsKICAgICAgICBweD1veDsKICAgICAgICBweT1veTsKICAgICAgfQogICAgICBpZihveCE9cHggfHwgb3khPXB5KQogICAgICB7CiAgICAgICAgY2YuZ2VuZXJhdGVGb3YobSxzaWdodFJhZGl1cyk7CiAgICAgICAgdXBkYXRlVmlld0F0KCk7CiAgICAgIH0KICAgICAgaWYoYXJnRXZlbnQua2V5U3ltPT1rZXlib2FyZDo6R0tfdCkKICAgICAgewogICAgICAgIHVpbnQzMl90IHN0YXJ0PVNETF9HZXRUaWNrcygpOwogICAgICAgIGNmLmRlYnVnPWZhbHNlOwogICAgICAgIGZvcihpbnQgaT0wO2k8MTAwMDsrK2kpCiAgICAgICAgewogICAgICAgICAgY2YuZ2VuZXJhdGVGb3YobSxzaWdodFJhZGl1cyk7CiAgICAgICAgfQogICAgICAgIGNmLmRlYnVnPXRydWU7CiAgICAgICAgdWludDMyX3QgZHVyYXRpb249U0RMX0dldFRpY2tzKCktc3RhcnQ7CiAgICAgICAgaW5mby0+c2V0VGV4dChGT1JNQVQoInRpbWU9JWQiLGR1cmF0aW9uKSk7CiAgICAgIH0KICAgIH0KICB9CiAgdm9pZCBvblJlc2l6ZSgpe307CiAgdm9pZCBvblF1aXQoKQogIHsKICAgIGVuZ2luZS5leGl0QXBwKCk7CiAgfQoKICB2b2lkIG9uRnJhbWVVcGRhdGUoaW50IG1jc2VjKQogIHsKICB9CiAgTWF0cml4JiBtOwogIFBvc2k8aW50PiB2aWV3QXQ7Cn07CgoKCmludCBHbGlkZXJBcHBNYWluKGludCBhcmdjLGNoYXIqIGFyZ3ZbXSkKewogIGtzdDo6TG9nZ2VyOjpJbml0KCJzaW1wbGUubG9nIik7CiAgZW5naW5lLnNldFZTeW5jKGZhbHNlKTsKICBlbmdpbmUuc2VsZWN0UmVzb2x1dGlvbigxMDI0LDc2OCxmYWxzZSk7CiAgLy9lbmdpbmUuc2VsZWN0UmVzb2x1dGlvbig4MDAsNDgwLGZhbHNlKTsKICBlbmdpbmUuc2V0UmVzb2x1dGlvbigpOwogIGVuZ2luZS5zZXRGcHNMaW1pdCg2MCk7CgoKICAvL2NvbnN0IGludCBXPXN0cmxlbih0ZXN0bWFwWzBdKTsKICAvL2NvbnN0IGludCBIPXNpemVvZih0ZXN0bWFwKS9zaXplb2YodGVzdG1hcFswXSk7CiAga3N0OjpGaWxlIGY7CiAga3N0OjpMb2dnZXIqIGxnPWtzdDo6TG9nZ2VyOjpnZXRMb2dnZXIoImluaXQiKTsKICB0cnl7CiAgICBmLlJPcGVuKCJ0ZXN0bWFwLnR4dCIpOwogIH1jYXRjaChzdGQ6OmV4Y2VwdGlvbiYgZSkKICB7CiAgICBMT0dFUlJPUihsZywiZXhjZXB0aW9uOiVzIixlLndoYXQoKSk7CiAgICByZXR1cm4gMDsKICB9CiAgTWF0cml4IG07CiAgLy9tLnJlc2l6ZShILFJvdyhXLENlbGwoKSkpOwoKICAvL2ZvcihpbnQgeT0wO3k8SDsrK3kpCiAgc2l6ZV90IHk9MDsKICBzdGQ6OnN0cmluZyBsaW5lOwogIHdoaWxlKGYuUmVhZExpbmUobGluZSkpCiAgewogICAgbS5wdXNoX2JhY2soUm93KGxpbmUuc2l6ZSgpLENlbGwoKSkpOwogICAgaWYobGluZS5zaXplKCkhPW1bMF0uc2l6ZSgpKQogICAgewogICAgICBMT0dFUlJPUihsZywiaW52YWxpZCBsaW5lWyVkXSBsZW5ndGg9JWQgaW4gdGVzdG1hcC50eHQsIGV4cGVjdGVkICVkIix5LGxpbmUuc2l6ZSgpLG1bMF0uc2l6ZSgpKTsKICAgICAgcmV0dXJuIDA7CiAgICB9CiAgICBmb3Ioc2l6ZV90IHg9MDt4PGxpbmUuc2l6ZSgpOysreCkKICAgIHsKICAgICAgQ2VsbCYgYz1tW3ldW3hdOwogICAgICBjLnRlbXBCbG9jaz1saW5lW3hdPT0nKic7CiAgICAgIGMuZGVsYXlCbG9jaz1saW5lW3hdPT0nfCcgfHwgbGluZVt4XT09Jy0nOwogICAgICBjLmJsb2NrPWxpbmVbeF09PScjJyB8fCBjLnRlbXBCbG9jayB8fCBjLmRlbGF5QmxvY2s7CiAgICAgIGMudmlzPXRydWU7CiAgICAgIGMuY29ybmVyc1swXT0xMDA7CiAgICAgIGMuY29ybmVyc1sxXT0xMDA7CiAgICAgIGMuY29ybmVyc1syXT0xMDA7CiAgICAgIGMuY29ybmVyc1szXT0xMDA7CiAgICB9CiAgICArK3k7CiAgfQogIGludCBXPW1bMF0uc2l6ZSgpOwogIGludCBIPW0uc2l6ZSgpOwogIGludCBjb3JuQW5nbGU9NjA7CiAgZm9yKGludCB5PTA7eTxIOysreSkKICB7CiAgICBmb3IoaW50IHg9MDt4PFc7Kyt4KQogICAgewogICAgICBpZihtW3ldW3hdLmJsb2NrKQogICAgICB7CiAgICAgICAgaWYoeT4wICYmIHg+MCAmJiAhbVt5LTFdW3hdLmJsb2NrICYmICFtW3ldW3gtMV0uYmxvY2spCiAgICAgICAgewogICAgICAgICAgbVt5XVt4XS5jb3JuZXJzWzNdPWNvcm5BbmdsZTsKICAgICAgICB9CiAgICAgICAgaWYoeT4wICYmIHg8Vy0xICYmICFtW3ktMV1beF0uYmxvY2sgJiYgIW1beV1beCsxXS5ibG9jaykKICAgICAgICB7CiAgICAgICAgICBtW3ldW3hdLmNvcm5lcnNbMl09Y29ybkFuZ2xlOwogICAgICAgIH0KICAgICAgICBpZih5PEgtMSAmJiB4PFctMSAmJiAhbVt5KzFdW3hdLmJsb2NrICYmICFtW3ldW3grMV0uYmxvY2spCiAgICAgICAgewogICAgICAgICAgbVt5XVt4XS5jb3JuZXJzWzFdPWNvcm5BbmdsZTsKICAgICAgICB9CiAgICAgICAgaWYoeTxILTEgJiYgeD4wICYmICFtW3krMV1beF0uYmxvY2sgJiYgIW1beV1beC0xXS5ibG9jaykKICAgICAgICB7CiAgICAgICAgICBtW3ldW3hdLmNvcm5lcnNbMF09Y29ybkFuZ2xlOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KICBweD1XLzI7CiAgcHk9SC8yOwoKICBNeUV2ZW50SGFuZGxlciBtZWgobSk7CiAgZW5naW5lLmFzc2lnbkhhbmRsZXIoJm1laCk7CgoKICBlbmdpbmUuZW5hYmxlS2V5Ym9hcmRSZXBlYXQoKTsKICBTY2VuZSBzYzsKICBGb250UmVmIGZudDE9bWFuYWdlci5nZXRGb250KCJGU0VYMzAwLnR0ZiIsMTYpOwogIFRleHQqIHR4dD1uZXcgVGV4dChmbnQxLCJoZWxsbyIpOwogIHR4dC0+c2V0UG9zaXRpb24oUG9zKDEwLDEwKSk7CiAgdmI9bmV3IFZlcnRleEJ1ZmZlcjsKICBsc2E9bmV3IExpbmUoUG9zKDAsMCksUG9zKDEwLDApKTsKICBsZWE9bmV3IExpbmUoUG9zKDAsMCksUG9zKDAsMTApKTsKICBpbmZvPW5ldyBUZXh0KGZudDEsIkluZm8iKTsKICBpbmZvLT5zZXRQb3NpdGlvbihQb3MoVypDRUxMX1NJWkUsMCkpOwogIFZ4VmVjdG9yJiB2PXZiLT5nZXRWQnVmKCk7CiAgQ2xyVmVjdG9yJiBjPXZiLT5nZXRDQnVmKCk7CiAgZm9yKGludCB5PTA7eTxIOysreSkKICB7CiAgICBmb3IoaW50IHg9MDt4PFc7Kyt4KQogICAgewogICAgICAvL2dsaWRlcjo6UmVjdGFuZ2xlKiByPW5ldyBnbGlkZXI6OlJlY3RhbmdsZShSZWN0KHgqMTUseSoxNSwxMCwxMCksQ29sb3IoMSwwLjEreC8yMCt5LzIwLDAuMSkpOwogICAgICAvL3NjLmFkZE9iamVjdChyKTsKICAgICAgUmVjdCh4KkNFTExfU0laRSsxLHkqQ0VMTF9TSVpFKzEsQ0VMTF9TSVpFLTIsQ0VMTF9TSVpFLTIpLnB1c2hRdWFkKHYpOwogICAgICBjLnB1c2g0KENvbG9yOjpncmF5KTsKICAgIH0KICB9CiAgdmItPnVwZGF0ZSgpOwogIGNmLnByZXBhcmUoc2lnaHRSYWRpdXMpOwogIGNmLmdlbmVyYXRlRm92KG0sc2lnaHRSYWRpdXMpOwogIGRyYXdNYXAobSk7CiAgc2MuYWRkT2JqZWN0KHZiKTsKICBzYy5hZGRPYmplY3QobHNhKTsKICBzYy5hZGRPYmplY3QobGVhKTsKICBzYy5hZGRPYmplY3QoaW5mbyk7CiAgLy9zYy5hZGRPYmplY3QodHh0KTsKICBlbmdpbmUubG9vcCgmc2MpOwoKLy8gIGZvcihDaXJjdWxhckZvdjo6UmluZzo6aXRlcmF0b3IgaXQ9Y2YuZm92WzJdLmJlZ2luKCksZW5kPWNmLmZvdlsyXS5lbmQoKTtpdCE9ZW5kOysraXQpCi8vICB7Ci8vICAgIEZvdkNlbGwmIGZjPSppdDsKLy8gICAgcHJpbnRmKCIlZCwlZDolLjNsZi0lLjNsZlxuIixmYy5wLngsZmMucC55LGZjLnNhLzEwMDAwMDAuMCxmYy5lYS8xMDAwMDAwLjApOwovLyAgfQovLyAgZm9yKENpcmN1bGFyRm92OjpSaW5nOjppdGVyYXRvciBpdD1jZi5mb3ZbM10uYmVnaW4oKSxlbmQ9Y2YuZm92WzNdLmVuZCgpO2l0IT1lbmQ7KytpdCkKLy8gIHsKLy8gICAgRm92Q2VsbCYgZmM9Kml0OwovLyAgICBwcmludGYoIiVkLCVkOiUuM2xmLSUuM2xmXG4iLGZjLnAueCxmYy5wLnksZmMuc2EvMTAwMDAwMC4wLGZjLmVhLzEwMDAwMDAuMCk7Ci8vICB9CgogIHJldHVybiAwOwp9Cg==