//Project: V-plotter
//Homepage: www.HomoFaciens.de
//Author Norbert Heinz
//Version: 0.1
//Creation date: 24.06.2015
//This program is free software you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 3 of the License.
//This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//For a copy of the GNU General Public License see http://w...content-available-to-author-only...u.org/licenses/
//
//compile with gcc v-plotter.c -o v-plotter -I/usr/local/include -L/usr/local/lib -lwiringPi -lm
//For details see:
//http://w...content-available-to-author-only...s.de/technics-machines-v-plotter_en_navion.htm
#include <stdio.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <dirent.h>
#include <math.h>
#include <wiringPi.h>
#include <unistd.h>
#define PI 3.1415927
#define SERVOUP 10
#define SERVODOWN 20
#define LEFT_STEPPER01 11
#define LEFT_STEPPER02 10
#define LEFT_STEPPER03 6
#define LEFT_STEPPER04 14
#define RIGHT_STEPPER01 2
#define RIGHT_STEPPER02 3
#define RIGHT_STEPPER03 12
#define RIGHT_STEPPER04 13
#define STEP_PAUSE 1500
#define STEP_MAX 220.0
#define Z_SERVO 0
#define BUFFERSIZE 120
//Lengths given in millimiters
#define BASELENGTH 845
#define CORDLENGTH_LEFT 220
#define CORDLENGTH_RIGHT 667
//#define BASELENGTH 840
//#define CORDLENGTH_LEFT 266
//#define CORDLENGTH_RIGHT 685
//Correction for errors caused by flexibility of the cord 0.0 = OFF (experimental)
#define CORDFLEXFACTOR 0.0f
int MaxRows = 24 ;
int MaxCols = 80 ;
int MessageX = 1 ;
int MessageY = 24 ;
unsigned char MoveBuffer[ BUFFERSIZE] ;
long currentX = 0 , currentY = 0 ;
long CordLengthLeft = 0 ;
long CordLengthRight = 0 ;
long BaseLength = 0 ;
long X0, Y0;
int FilesFound = 0 ;
int currentPlotDown = 0 ;
int BoldLineWidth = 0 ;
int BoldLineGap = 0 ;
long BoldLineX = 0 , BoldLineY = 0 ;
int StepX = 0 ;
int StepY = 0 ;
//Steps per mm (with gear)
double StepsPermm = 2000.0 / 98.0 ;
//Steps per mm (without gear)
//double StepsPermm = 2000.0 / 199.0;
char PicturePath[ 1000 ] ;
//+++++++++++++++++++++++ Start gotoxy ++++++++++++++++++++++++++
//Thanks to 'Stack Overflow', found on http://w...content-available-to-author-only...b.com/software-development/c/code/216326
int gotoxy( int x, int y) {
char essq[ 100 ] ; // String variable to hold the escape sequence
char xstr[ 100 ] ; // Strings to hold the x and y coordinates
char ystr[ 100 ] ; // Escape sequences must be built with characters
//Convert the screen coordinates to strings.
//Build the escape sequence (vertical move).
essq[ 0 ] = '\0 ' ;
//Described in man terminfo as vpa=\E[%p1%dd. Vertical position absolute.
//Horizontal move. Horizontal position absolute
// Described in man terminfo as hpa=\E[%p1%dG
//Execute the escape sequence. This will move the cursor to x, y
return 0 ;
}
//------------------------ End gotoxy ----------------------------------
//+++++++++++++++++++++++ Start clrscr ++++++++++++++++++++++++++
void clrscr( int StartRow, int EndRow) {
int i, i2;
if ( EndRow < StartRow) {
i = EndRow;
EndRow = StartRow;
StartRow = i;
}
gotoxy( 1 , StartRow) ;
for ( i = 0 ; i <= EndRow - StartRow; i++ ) {
for ( i2 = 0 ; i2 < MaxCols; i2++ ) {
}
}
}
//----------------------- End clrscr ----------------------------
//+++++++++++++++++++++++ Start kbhit ++++++++++++++++++++++++++++++++++
//Thanks to Undertech Blog, http://w...content-available-to-author-only...c.de/blog/2009/05/kbhit_und_getch_fur_linux.html
int kbhit( void ) {
struct termios term, oterm;
int fd = 0 ;
int c = 0 ;
tcgetattr( fd, & oterm) ;
memcpy ( & term
, & oterm
, sizeof ( term
) ) ; term.c_lflag = term.c_lflag & ( ! ICANON) ;
term.c_cc [ VMIN] = 0 ;
term.c_cc [ VTIME] = 1 ;
tcsetattr( fd, TCSANOW, & term) ;
tcsetattr( fd, TCSANOW, & oterm) ;
if ( c != - 1 )
return ( ( c != - 1 ) ? 1 : 0 ) ;
}
//------------------------ End kbhit -----------------------------------
//+++++++++++++++++++++++ Start getch ++++++++++++++++++++++++++++++++++
//Thanks to Undertech Blog, http://w...content-available-to-author-only...c.de/blog/2009/05/kbhit_und_getch_fur_linux.html
static int ch = - 1 , fd = 0 ;
struct termios new, old;
fd = fileno( stdin) ;
tcgetattr( fd, & old) ;
new = old;
new.c_lflag &= ~( ICANON| ECHO) ;
tcsetattr( fd, TCSANOW, & new) ;
tcsetattr( fd, TCSANOW, & old) ;
// printf("ch=%d ", ch);
return ch;
}
//------------------------ End getch -----------------------------------
//++++++++++++++++++++++ Start MessageText +++++++++++++++++++++++++++++
void MessageText( char * message, int x, int y, int alignment) {
int i;
char TextLine[ 300 ] ;
clrscr( y, y) ;
gotoxy ( x, y) ;
TextLine[ 0 ] = '\0 ' ;
if ( alignment == 1 ) {
for ( i
= 0 ; i
< ( MaxCols
- strlen ( message
) ) / 2 ; i
++ ) { }
}
}
//-------------------------- End MessageText ---------------------------
//++++++++++++++++++++++ Start PrintRow ++++++++++++++++++++++++++++++++
void PrintRow( char character, int y) {
int i;
gotoxy ( 1 , y) ;
for ( i= 0 ; i< MaxCols; i++ ) {
}
}
//-------------------------- End PrintRow ------------------------------
//+++++++++++++++++++++++++ ErrorText +++++++++++++++++++++++++++++
void ErrorText( char * message) {
clrscr( MessageY + 2 , MessageY + 2 ) ;
gotoxy ( 1 , MessageY + 2 ) ;
printf ( "Last error: %s" , message
) ; }
//----------------------------- ErrorText ---------------------------
//+++++++++++++++++++++++++ PrintMenue_01 ++++++++++++++++++++++++++++++
void PrintMenue_01( char * PlotFile, double scale, double width, double height, long MoveLength) {
char TextLine[ 300 ] ;
clrscr( 1 , MessageY- 2 ) ;
MessageText( "*** Main menu plotter ***" , 1 , 1 , 1 ) ;
sprintf ( TextLine
, "M - toggle move length, current value = %ld step(s)" , MoveLength
) ; MessageText( TextLine, 10 , 3 , 0 ) ;
MessageText( "Cursor right - move plotter in positive X direction" , 10 , 4 , 0 ) ;
MessageText( "Cursor left - move plotter in negative X direction" , 10 , 5 , 0 ) ;
MessageText( "Cursor up - move plotter in positive Y direction" , 10 , 6 , 0 ) ;
MessageText( "Cursor down - move plotter in negative Y direction" , 10 , 7 , 0 ) ;
MessageText( "Page up - lift pen" , 10 , 8 , 0 ) ;
MessageText( "Page down - touch down pen" , 10 , 9 , 0 ) ;
sprintf ( TextLine
, "F - choose file. Current file = \" %s\" " , PlotFile
) ; MessageText( TextLine, 10 , 10 , 0 ) ;
MessageText( "0 - move plotter to 0/0" , 10 , 11 , 0 ) ;
sprintf ( TextLine
, "S - Scale set to = %0.4f. W = %0.2fcm, H = %0.2fcm" , scale
, width
* scale
/ 1000.0 , height
* scale
/ 1000.0 ) ; MessageText( TextLine, 10 , 12 , 0 ) ;
sprintf ( TextLine
, "B - Bold line = %d steps" , BoldLineWidth
) ; MessageText( TextLine, 10 , 13 , 0 ) ;
MessageText( "P - plot file" , 10 , 14 , 0 ) ;
MessageText( "Esc - leave program" , 10 , 16 , 0 ) ;
}
//------------------------- PrintMenue_01 ------------------------------
//+++++++++++++++++++++++++ PrintMenue_02 ++++++++++++++++++++++++++++++
char * PrintMenue_02( int StartRow, int selected) {
char TextLine[ 300 ] ;
char FilePattern[ 5 ] ;
char OpenDirName[ 1000 ] ;
static char FileName[ 101 ] ;
DIR * pDIR;
struct dirent * pDirEnt;
int i = 0 ;
int Discard = 0 ;
clrscr( 1 , MessageY- 2 ) ;
MessageText( "*** Choose plotter file ***" , 1 , 1 , 1 ) ;
strcpy ( OpenDirName
, PicturePath
) ;
pDIR = opendir( OpenDirName) ;
if ( pDIR == NULL ) {
sprintf ( TextLine
, "Could not open directory '%s'!" , OpenDirName
) ; MessageText( TextLine, 1 , 4 , 1 ) ;
return ( "" ) ;
}
FilesFound = 0 ;
pDirEnt = readdir( pDIR ) ;
while ( pDirEnt != NULL && i < 10 ) {
if ( strlen ( pDirEnt
-> d_name
) > 4 ) { if ( memcmp ( pDirEnt
-> d_name
+ strlen ( pDirEnt
-> d_name
) - 4 , ".svg" , 4 ) == 0 ) { FilesFound++;
if ( Discard >= StartRow) {
if ( i + StartRow == selected) {
sprintf ( TextLine
, ">%s<" , pDirEnt
-> d_name
) ; strcpy ( FileName
, pDirEnt
-> d_name
) ; }
else {
sprintf ( TextLine
, " %s " , pDirEnt
-> d_name
) ; }
MessageText( TextLine, 1 , 3 + i, 0 ) ;
i++;
}
Discard++;
}
}
pDirEnt = readdir( pDIR ) ;
}
gotoxy( MessageX, MessageY + 1 ) ;
printf ( "Choose file using up/down keys and confirm with 'Enter' or press 'Esc' to cancel." ) ;
return ( FileName) ;
}
//------------------------- PrintMenue_02 ------------------------------
//+++++++++++++++++++++++++ PrintMenue_03 ++++++++++++++++++++++++++++++
void PrintMenue_03( char * FullFileName, long NumberOfLines, long CurrentLine, long CurrentX, long CurrentY, long StartTime) {
char TextLine[ 300 ] ;
long CurrentTime, ProcessHours = 0 , ProcessMinutes = 0 , ProcessSeconds = 0 ;
CurrentTime -= StartTime;
while ( CurrentTime > 3600 ) {
ProcessHours++;
CurrentTime -= 3600 ;
}
while ( CurrentTime > 60 ) {
ProcessMinutes++;
CurrentTime -= 60 ;
}
ProcessSeconds = CurrentTime;
clrscr( 1 , MessageY - 2 ) ;
MessageText( "*** Plotting file ***" , 1 , 1 , 1 ) ;
sprintf ( TextLine
, "File name: %s" , FullFileName
) ; MessageText( TextLine, 10 , 3 , 0 ) ;
sprintf ( TextLine
, "Number of lines: %ld" , NumberOfLines
) ; MessageText( TextLine, 10 , 4 , 0 ) ;
sprintf ( TextLine
, "Current Position(%ld): X = %ld, Y = %ld " , CurrentLine
, CurrentX
, CurrentY
) ; MessageText( TextLine, 10 , 5 , 0 ) ;
sprintf ( TextLine
, "Process time: %02ld:%02ld:%02ld" , ProcessHours
, ProcessMinutes
, ProcessSeconds
) ; MessageText( TextLine, 10 , 6 , 0 ) ;
}
//------------------------- PrintMenue_03 ------------------------------
//++++++++++++++++++++++++++++++ MakeStepLeft ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void MakeStepLeft( int direction) {
StepX += direction;
if ( StepX > 3 ) {
StepX = 0 ;
}
if ( StepX < 0 ) {
StepX = 3 ;
}
if ( StepX == 0 ) {
digitalWrite( LEFT_STEPPER01, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( LEFT_STEPPER02, 0 ) ;
digitalWrite( LEFT_STEPPER03, 0 ) ;
digitalWrite( LEFT_STEPPER04, 0 ) ;
}
if ( StepX == 1 ) {
digitalWrite( LEFT_STEPPER03, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( LEFT_STEPPER01, 0 ) ;
digitalWrite( LEFT_STEPPER02, 0 ) ;
digitalWrite( LEFT_STEPPER04, 0 ) ;
}
if ( StepX == 2 ) {
digitalWrite( LEFT_STEPPER02, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( LEFT_STEPPER01, 0 ) ;
digitalWrite( LEFT_STEPPER03, 0 ) ;
digitalWrite( LEFT_STEPPER04, 0 ) ;
}
if ( StepX == 3 ) {
digitalWrite( LEFT_STEPPER04, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( LEFT_STEPPER01, 0 ) ;
digitalWrite( LEFT_STEPPER02, 0 ) ;
digitalWrite( LEFT_STEPPER03, 0 ) ;
}
usleep( STEP_PAUSE) ;
}
//++++++++++++++++++++++++++++++ MakeStepRight ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void MakeStepRight( int direction) {
StepY += direction;
if ( StepY > 3 ) {
StepY = 0 ;
}
if ( StepY < 0 ) {
StepY = 3 ;
}
if ( StepY == 0 ) {
digitalWrite( RIGHT_STEPPER01, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( RIGHT_STEPPER02, 0 ) ;
digitalWrite( RIGHT_STEPPER03, 0 ) ;
digitalWrite( RIGHT_STEPPER04, 0 ) ;
}
if ( StepY == 1 ) {
digitalWrite( RIGHT_STEPPER03, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( RIGHT_STEPPER01, 0 ) ;
digitalWrite( RIGHT_STEPPER02, 0 ) ;
digitalWrite( RIGHT_STEPPER04, 0 ) ;
}
if ( StepY == 2 ) {
digitalWrite( RIGHT_STEPPER02, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( RIGHT_STEPPER01, 0 ) ;
digitalWrite( RIGHT_STEPPER03, 0 ) ;
digitalWrite( RIGHT_STEPPER04, 0 ) ;
}
if ( StepY == 3 ) {
digitalWrite( RIGHT_STEPPER04, 1 ) ;
usleep( STEP_PAUSE) ;
digitalWrite( RIGHT_STEPPER01, 0 ) ;
digitalWrite( RIGHT_STEPPER02, 0 ) ;
digitalWrite( RIGHT_STEPPER03, 0 ) ;
}
// printf("StepY\n");
usleep( STEP_PAUSE) ;
}
//++++++++++++++++++++++++++++++++++++++ moveXY +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void moveXY( long X, long Y) {
long newCordLengthLeft;
long newCordLengthRight;
double forceLeft, forceRight;
double deltaCordLeft, deltaCordRight;
double deltaCordLeft0, deltaCordRight0;
double alpha;
char TextLine[ 1000 ] ;
//calculate initial stretch of cords (experimental)
alpha
= atan ( ( double ) ( X0
) / ( double ) ( Y0
) ) ; forceLeft
= 1.0 * cos ( alpha
) ; forceRight
= 1.0 * sin ( alpha
) ;
deltaCordLeft0 = ( double ) ( CORDLENGTH_LEFT * StepsPermm) * forceLeft * CORDFLEXFACTOR;
deltaCordRight0 = ( double ) ( CORDLENGTH_RIGHT * StepsPermm) * forceRight * CORDFLEXFACTOR;
//forces at current coordinates (experimental)
alpha
= atan ( ( double ) ( X
+ X0
) / ( double ) ( Y
+ Y0
) ) ; forceLeft
= 1.0 * cos ( alpha
) ; forceRight
= 1.0 * sin ( alpha
) ;
X += X0;
Y += Y0;
newCordLengthLeft
= sqrt ( ( double ) ( X
* X
) + ( double ) ( Y
* Y
) ) ; newCordLengthRight
= sqrt ( ( double ) ( ( BaseLength
- X
) * ( BaseLength
- X
) ) + ( double ) ( Y
* Y
) ) ;
deltaCordLeft = ( double ) ( newCordLengthLeft) * forceLeft * CORDFLEXFACTOR - deltaCordLeft0;
deltaCordRight = ( double ) ( newCordLengthRight) * forceRight * CORDFLEXFACTOR - deltaCordRight0;
newCordLengthLeft -= deltaCordLeft;
newCordLengthRight -= deltaCordRight;
while ( newCordLengthLeft > CordLengthLeft) {
MakeStepLeft( 1 ) ;
CordLengthLeft++;
}
while ( newCordLengthLeft < CordLengthLeft) {
MakeStepLeft( - 1 ) ;
CordLengthLeft--;
}
while ( newCordLengthRight > CordLengthRight) {
MakeStepRight( 1 ) ;
CordLengthRight++;
}
while ( newCordLengthRight < CordLengthRight) {
MakeStepRight( - 1 ) ;
CordLengthRight--;
}
}
//++++++++++++++++++++++++++++++++++++++ BoldLinePattern ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void BoldLinePattern( long X, long Y) {
int i;
long xDiff, yDiff;
double alpha = 0.0 ;
long xCircle, yCircle;
xDiff = BoldLineX - X;
yDiff = BoldLineY - Y;
if ( BoldLineWidth > 0 ) {
if ( currentPlotDown == 1 ) {
if ( sqrt ( xDiff
* xDiff
+ yDiff
* yDiff
) > BoldLineGap
) { BoldLineX = X;
BoldLineY = Y;
for ( alpha = 0.0 ; alpha < 2.0 * PI; alpha += PI / 2500.0 ) {
xCircle
= cos ( alpha
) * BoldLineWidth
+ X
; yCircle
= sin ( alpha
) * BoldLineWidth
+ Y
; moveXY( xCircle, yCircle) ;
}
moveXY( X, Y) ;
}
} //if(currentPlotDown == 1){
}
}
//++++++++++++++++++++++++++++++++++++++ CalculateLine ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int CalculateLine( long moveToX, long moveToY) {
char TextLine[ 1000 ] = "" ;
long tempX = 0 , tempY = 0 ;
int i = 0 ;
sprintf ( TextLine
, "Moving X: %ld, Moving Y: %ld" , moveToX
, moveToY
) ; MessageText( TextLine, MessageX, MessageY, 0 ) ;
// getch();
if ( moveToX - currentX != 0 && moveToY - currentY != 0 ) {
tempX = currentX;
tempY = currentY;
if ( abs ( moveToX
- currentX
) > abs ( moveToY
- currentY
) ) { while ( currentX < moveToX) {
currentX++;
moveXY( currentX, currentY) ;
currentY = tempY + ( currentX - tempX) * ( moveToY - tempY) / ( moveToX - tempX) ;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
while ( currentX > moveToX) {
currentX--;
moveXY( currentX, currentY) ;
currentY = tempY + ( currentX - tempX) * ( moveToY - tempY) / ( moveToX - tempX) ;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
}
else {
while ( currentY < moveToY) {
currentY++;
moveXY( currentX, currentY) ;
currentX = tempX + ( currentY - tempY) * ( moveToX - tempX) / ( moveToY - tempY) ;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
while ( currentY > moveToY) {
currentY--;
moveXY( currentX, currentY) ;
currentX = tempX + ( currentY - tempY) * ( moveToX - tempX) / ( moveToY - tempY) ;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
}
}
while ( moveToY > currentY) {
currentY++;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
while ( moveToY < currentY) {
currentY--;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
while ( moveToX > currentX) {
currentX++;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
while ( moveToX < currentX) {
currentX--;
moveXY( currentX, currentY) ;
BoldLinePattern( currentX, currentY) ;
}
return 0 ;
}
//-------------------------------------- CalculateLine --------------------------------------------------------
//######################################################################
//################## Main ##############################################
//######################################################################
int main( int argc, char ** argv) {
int MenueLevel = 0 ;
int KeyHit = 0 ;
int KeyCode[ 5 ] ;
char FileInfo[ 3 ] ;
char FileName[ 200 ] = "" ;
char FullFileName[ 200 ] = "" ;
char FileNameOld[ 200 ] = "" ;
struct winsize terminal;
double Scale = 1.0 ;
double OldScale = 1.0 ;
long MoveLength = 1 ;
int i;
int SingleKey= 0 ;
long currentPlotX = 0 , currentPlotY = 0 ;
int FileSelected = 0 ;
int FileStartRow = 0 ;
char * pEnd;
FILE * PlotFile;
char TextLine[ 10000 ] ;
long xMin = 1000000 , xMax = - 1000000 ;
long yMin = 1000000 , yMax = - 1000000 ;
long coordinateCount = 0 ;
char a;
int ReadState = 0 ;
long xNow = 0 , yNow = 0 ;
long xNow1 = 0 , yNow1 = 0 ;
long xNow2 = 0 , yNow2 = 0 ;
struct timeval StartTime, EndTime;
long coordinatePlot = 0 ;
int stopPlot = 0 ;
long PlotStartTime = 0 ;
int MaxFileRows = 0 ;
FileInfo[ 2 ] = '\0 ' ;
getcwd( PicturePath, 1000 ) ;
strcat ( PicturePath
, "/pictures" ) ; printf ( "PicturePath=>%s<" , PicturePath
) ;
if ( wiringPiSetup ( ) == - 1 ) {
printf ( "Could not run wiringPiSetup!" ) ; }
softPwmCreate( Z_SERVO, SERVOUP, 200 ) ;
softPwmWrite( Z_SERVO, SERVOUP) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
pinMode ( LEFT_STEPPER01, OUTPUT) ;
pinMode ( LEFT_STEPPER02, OUTPUT) ;
pinMode ( LEFT_STEPPER03, OUTPUT) ;
pinMode ( LEFT_STEPPER04, OUTPUT) ;
digitalWrite( LEFT_STEPPER01, 1 ) ;
digitalWrite( LEFT_STEPPER02, 0 ) ;
digitalWrite( LEFT_STEPPER03, 0 ) ;
digitalWrite( LEFT_STEPPER04, 0 ) ;
pinMode ( RIGHT_STEPPER01, OUTPUT) ;
pinMode ( RIGHT_STEPPER02, OUTPUT) ;
pinMode ( RIGHT_STEPPER03, OUTPUT) ;
pinMode ( RIGHT_STEPPER04, OUTPUT) ;
digitalWrite( RIGHT_STEPPER01, 1 ) ;
digitalWrite( RIGHT_STEPPER02, 0 ) ;
digitalWrite( RIGHT_STEPPER03, 0 ) ;
digitalWrite( RIGHT_STEPPER04, 0 ) ;
if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, & terminal) < 0 ) {
printf ( "Can't get size of terminal window" ) ; }
else {
MaxRows = terminal.ws_row ;
MaxCols = terminal.ws_col ;
MessageY = MaxRows- 3 ;
}
MaxFileRows = MaxRows - 10 ;
BaseLength = BASELENGTH * StepsPermm;
CordLengthLeft = CORDLENGTH_LEFT * StepsPermm;
CordLengthRight = CORDLENGTH_RIGHT * StepsPermm;
X0 = ( CordLengthLeft * CordLengthLeft - CordLengthRight * CordLengthRight + BaseLength * BaseLength) / ( 2.0 * BaseLength) ;
Y0
= sqrt ( CordLengthRight
* CordLengthRight
- ( BaseLength
- X0
) * ( BaseLength
- X0
) ) ;
printf ( "X0=%ld, Y0=%ld, CL=%ld, CR=%ld StepsPermm=%lf\n " , X0
, Y0
, CordLengthLeft
, CordLengthRight
, StepsPermm
) ;
clrscr( 1 , MaxRows) ;
PrintRow( '-' , MessageY - 1 ) ;
PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
while ( 1 ) {
MessageText( "Waiting for key press." , MessageX, MessageY, 0 ) ;
i = 0 ;
SingleKey = 1 ;
KeyCode[ 0 ] = 0 ;
KeyCode[ 1 ] = 0 ;
KeyCode[ 2 ] = 0 ;
KeyCode[ 3 ] = 0 ;
KeyCode[ 4 ] = 0 ;
KeyHit = 0 ;
while ( kbhit( ) ) {
KeyCode[ i] = KeyHit;
i++;
if ( i == 5 ) {
i = 0 ;
}
if ( i > 1 ) {
SingleKey = 0 ;
}
}
if ( SingleKey == 0 ) {
KeyHit = 0 ;
}
if ( MenueLevel == 0 ) {
//Move left motor
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 68 && KeyCode[ 3 ] == 0 && KeyCode[ 4 ] == 0 ) {
for ( i= 0 ; i< MoveLength; i++ ) {
MakeStepLeft( - 1 ) ;
}
moveXY( 0 , 0 ) ;
}
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 67 && KeyCode[ 3 ] == 0 && KeyCode[ 4 ] == 0 ) {
for ( i= 0 ; i< MoveLength; i++ ) {
MakeStepLeft( 1 ) ;
}
moveXY( 0 , 0 ) ;
}
//Move right motor
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 65 && KeyCode[ 3 ] == 0 && KeyCode[ 4 ] == 0 ) {
for ( i= 0 ; i< MoveLength; i++ ) {
MakeStepRight( - 1 ) ;
}
moveXY( 0 , 0 ) ;
}
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 66 && KeyCode[ 3 ] == 0 && KeyCode[ 4 ] == 0 ) {
for ( i= 0 ; i< MoveLength; i++ ) {
MakeStepRight( 1 ) ;
}
moveXY( 0 , 0 ) ;
}
//Pen UP/DOWN
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 53 && KeyCode[ 3 ] == 126 && KeyCode[ 4 ] == 0 ) {
softPwmWrite( Z_SERVO, SERVOUP) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
currentPlotDown = 0 ;
}
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 54 && KeyCode[ 3 ] == 126 && KeyCode[ 4 ] == 0 ) {
softPwmWrite( Z_SERVO, SERVODOWN) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
currentPlotDown = 1 ;
}
if ( KeyHit == 'm' ) {
MoveLength *= 10 ;
if ( MoveLength == 10000 ) {
MoveLength = 1 ;
}
PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
}
if ( KeyHit == 'f' ) {
FileStartRow = 0 ;
FileSelected = 0 ;
strcpy ( FileNameOld
, FileName
) ; strcpy ( FileName
, PrintMenue_02
( FileStartRow
, 0 ) ) ; MenueLevel = 1 ;
}
if ( KeyHit == 's' ) {
OldScale = Scale;
MessageText( "Type new scale value: " , 1 , MessageY, 0 ) ;
gotoxy( 23 , MessageY) ;
if ( Scale == 0 ) {
Scale = OldScale;
}
else {
PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
}
}
if ( KeyHit == 'b' ) {
OldScale = Scale;
MessageText( "Type new bold line value: " , 1 , MessageY, 0 ) ;
gotoxy( 27 , MessageY) ;
scanf ( "%d" , & BoldLineWidth
) ; BoldLineGap = BoldLineWidth;
PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
}
if ( KeyHit == 'p' ) { //Plot file
MessageText( "3 seconds until plotting starts !!!!!!!!!!!!!!!!!" , 1 , 20 , 0 ) ;
sleep( 3 ) ;
if ( strcmp ( FileName
, "noFiLE" ) != 0 ) { if ( ( PlotFile
= fopen ( FullFileName
, "rb" ) ) == NULL
) { sprintf ( TextLine
, "Can't open file '%s'!\n " , FullFileName
) ; ErrorText( TextLine) ;
}
}
if ( strcmp ( FileName
, "noFiLE" ) != 0 ) { BoldLineX = 0 , BoldLineY = 0 ;
xNow1 = - 1 ;
xNow2 = - 1 ;
yNow1 = - 1 ;
yNow2 = - 1 ;
currentPlotX = 0 ;
currentPlotY = 0 ;
PrintMenue_03( FullFileName, coordinateCount, 0 , 0 , 0 , PlotStartTime) ;
coordinatePlot = 0 ;
stopPlot = 0 ;
if ( currentPlotDown == 1 ) {
softPwmWrite( Z_SERVO, SERVOUP) ;
currentPlotDown = 0 ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
}
while ( ! ( feof ( PlotFile
) ) && stopPlot
== 0 ) {
fread ( & a
, 1 , 1 , PlotFile
) ; i= 0 ;
TextLine[ 0 ] = '\0 ' ;
while ( ! ( feof ( PlotFile
) ) && a
!= ' ' && a
!= '<' && a
!= '>' && a
!= '\" ' && a
!= '=' && a
!= ',' && a
!= ':' && a
!= 10 ) { TextLine[ i] = a;
TextLine[ i+ 1 ] = '\0 ' ;
i++;
fread ( & a
, 1 , 1 , PlotFile
) ; }
if ( a == '<' ) { //Init
if ( xNow2 > - 1 && yNow2 > - 1 && ( xNow2 != xNow1 || yNow2 != yNow1) ) {
stopPlot = CalculateLine( xNow2, yNow2) ;
if ( currentPlotDown == 0 ) {
softPwmWrite( Z_SERVO, SERVODOWN) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
currentPlotDown = 1 ;
}
currentPlotX = xNow2;
currentPlotY = yNow2;
stopPlot = CalculateLine( xNow1, yNow1) ;
currentPlotX = xNow1;
currentPlotY = yNow1;
stopPlot = CalculateLine( xNow, yNow) ;
currentPlotX = xNow;
currentPlotY = yNow;
}
ReadState = 0 ;
xNow1 = - 1 ;
xNow2 = - 1 ;
yNow1 = - 1 ;
yNow2 = - 1 ;
}
if ( strcmp ( TextLine
, "path" ) == 0 ) { if ( currentPlotDown == 1 ) {
softPwmWrite( Z_SERVO, SERVOUP) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
currentPlotDown = 0 ;
}
ReadState = 1 ; //path found
}
if ( ReadState
== 1 && strcmp ( TextLine
, "fill" ) == 0 ) { ReadState = 2 ; //fill found
}
if ( ReadState
== 2 && strcmp ( TextLine
, "none" ) == 0 ) { ReadState = 3 ; //none found
}
if ( ReadState
== 2 && strcmp ( TextLine
, "stroke" ) == 0 ) { ReadState = 0 ; //stroke found, fill isn't "none"
}
if ( ReadState
== 3 && strcmp ( TextLine
, "d" ) == 0 && a
== '=' ) { ReadState = 4 ; //d= found
}
if ( ReadState
== 4 && strcmp ( TextLine
, "M" ) == 0 && a
== ' ' ) { ReadState = 5 ; //M found
}
if ( ReadState == 6 ) { //Y value
yNow
= ( double ) ( strtol ( TextLine
, & pEnd
, 10 ) - yMin
) * StepsPermm
* Scale
/ 100.0 ; ReadState = 7 ;
coordinatePlot++;
}
if ( ReadState == 5 && a == ',' ) { //X value
//xNow = ((xMax - strtol(TextLine, &pEnd, 10))) * Scale;//swap X
xNow
= ( double ) ( strtol ( TextLine
, & pEnd
, 10 ) - xMin
) * StepsPermm
* Scale
/ 100.0 ; ReadState = 6 ;
}
if ( ReadState == 7 ) {
if ( xNow2 > - 1 && yNow2 > - 1 && ( xNow2 != xNow1 || yNow2 != yNow1) ) {
stopPlot = CalculateLine( xNow2, yNow2) ;
if ( currentPlotDown == 0 ) {
softPwmWrite( Z_SERVO, SERVODOWN) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
currentPlotDown = 1 ;
}
currentPlotX = xNow2;
currentPlotY = yNow2;
}
xNow2 = xNow1;
yNow2 = yNow1;
xNow1 = xNow;
yNow1 = yNow;
ReadState = 5 ;
}
//PrintMenue_03(FullFileName, coordinateCount, coordinatePlot, 0, 0, PlotStartTime);
} //while(!(feof(PlotFile)) && stopPlot == 0){
if ( currentPlotDown == 1 ) {
softPwmWrite( Z_SERVO, SERVOUP) ;
usleep( 500000 ) ;
softPwmWrite( Z_SERVO, 0 ) ;
currentPlotDown = 0 ;
}
PrintMenue_03( FullFileName, coordinateCount, coordinatePlot, 0 , 0 , PlotStartTime) ;
CalculateLine( 0 , 0 ) ;
currentPlotX = 0 ;
currentPlotY = 0 ;
while ( kbhit( ) ) {
}
MessageText( "Finished! Press any key to return to main menu." , MessageX, MessageY, 0 ) ;
PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
} //if(strcmp(FileName, "noFiLE") != 0){
} //if(KeyHit == 'p'){
} //if(MenueLevel == 0){
if ( MenueLevel == 1 ) { //Select file
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 66 && KeyCode[ 3 ] == 0 && KeyCode[ 4 ] == 0 ) {
if ( FileSelected < FilesFound - 1 ) {
FileSelected++;
if ( FileSelected > MaxFileRows - 2 ) {
FileStartRow = FileSelected - MaxFileRows + 2 ;
}
strcpy ( FileName
, PrintMenue_02
( FileStartRow
, FileSelected
) ) ; }
}
if ( KeyCode[ 0 ] == 27 && KeyCode[ 1 ] == 91 && KeyCode[ 2 ] == 65 && KeyCode[ 3 ] == 0 && KeyCode[ 4 ] == 0 ) {
if ( FileSelected > 0 ) {
if ( FileSelected == FileStartRow + 1 ) {
if ( FileStartRow > 0 ) {
FileStartRow--;
}
}
FileSelected--;
strcpy ( FileName
, PrintMenue_02
( FileStartRow
, FileSelected
) ) ; }
}
if ( KeyHit == 10 ) { //Read file and store values
MenueLevel = 0 ;
clrscr( MessageY + 1 , MessageY + 1 ) ;
strcpy ( FullFileName
, PicturePath
) ; strcat ( FullFileName
, FileName
) ; if ( ( PlotFile
= fopen ( FullFileName
, "rb" ) ) == NULL
) { sprintf ( TextLine
, "Can't open file '%s'!\n " , FullFileName
) ; ErrorText( TextLine) ;
}
else {
xMin= 1000000 ;
xMax=- 1000000 ;
yMin= 1000000 ;
yMax=- 1000000 ;
coordinateCount = 0 ;
while ( ! ( feof ( PlotFile
) ) && stopPlot
== 0 ) {
fread ( & a
, 1 , 1 , PlotFile
) ; i= 0 ;
TextLine[ 0 ] = '\0 ' ;
while ( ! ( feof ( PlotFile
) ) && a
!= ' ' && a
!= '<' && a
!= '>' && a
!= '\" ' && a
!= '=' && a
!= ',' && a
!= ':' && a
!= 10 ) { TextLine[ i] = a;
TextLine[ i+ 1 ] = '\0 ' ;
i++;
fread ( & a
, 1 , 1 , PlotFile
) ; }
if ( a == '<' ) { //Init
ReadState = 0 ;
}
if ( strcmp ( TextLine
, "path" ) == 0 ) { ReadState = 1 ; //path found
}
if ( ReadState
== 1 && strcmp ( TextLine
, "fill" ) == 0 ) { //ReadState = 2;//fill found
ReadState = 3 ; //paths without line are also considered when calculating max values
}
if ( ReadState
== 2 && strcmp ( TextLine
, "none" ) == 0 ) { ReadState = 3 ; //none found
}
if ( ReadState
== 2 && strcmp ( TextLine
, "stroke" ) == 0 ) { ReadState = 0 ; //stroke found, fill isn't "none"
}
if ( ReadState
== 3 && strcmp ( TextLine
, "d" ) == 0 && a
== '=' ) { ReadState = 4 ; //d= found
}
if ( ReadState
== 4 && strcmp ( TextLine
, "M" ) == 0 && a
== ' ' ) { ReadState = 5 ; //M found
}
if ( ReadState
== 5 && strcmp ( TextLine
, "C" ) == 0 && a
== ' ' ) { ReadState = 5 ; //C found
}
if ( ReadState == 6 ) { //Y value
yNow
= strtol ( TextLine
, & pEnd
, 10 ) ; //printf("String='%s' y=%ld\n", TextLine, yNow);
if ( yNow > yMax) {
yMax = yNow;
}
if ( yNow < yMin) {
yMin = yNow;
}
ReadState = 7 ;
coordinateCount++;
}
if ( ReadState == 5 && a == ',' ) { //X value
xNow
= strtol ( TextLine
, & pEnd
, 10 ) ; if ( xNow > xMax) {
xMax = xNow;
}
if ( xNow < xMin) {
xMin = xNow;
}
ReadState = 6 ;
}
if ( ReadState == 7 ) {
//printf("Found coordinates %ld, %ld\n", xNow, yNow);
ReadState = 5 ;
}
gotoxy
( 1 , MessageY
) ; printf ( "ReadState=% 3d, xNow=% 10ld, xMin=% 10ld, xMax=% 10ld, yMin=% 10ld, yMax=% 10ld " , ReadState
, xNow
, xMin
, xMax
, yMin
, yMax
) ;
} //while(!(feof(PlotFile)) && stopPlot == 0){
Scale = 1.0 ;
}
PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
} //if(KeyHit == 10){
} //if(MenueLevel == 1){
if ( KeyHit == 27 ) {
if ( MenueLevel == 0 ) {
clrscr( MessageY + 1 , MessageY + 1 ) ;
MessageText( "Exit program (y/n)?" , MessageX, MessageY + 1 , 0 ) ;
while ( KeyHit != 'y' && KeyHit != 'n' ) {
if ( KeyHit == 'y' ) {
digitalWrite( LEFT_STEPPER01, 0 ) ;
digitalWrite( LEFT_STEPPER02, 0 ) ;
digitalWrite( LEFT_STEPPER03, 0 ) ;
digitalWrite( LEFT_STEPPER04, 0 ) ;
digitalWrite( RIGHT_STEPPER01, 0 ) ;
digitalWrite( RIGHT_STEPPER02, 0 ) ;
digitalWrite( RIGHT_STEPPER03, 0 ) ;
digitalWrite( RIGHT_STEPPER04, 0 ) ;
}
}
}
if ( MenueLevel == 1 ) {
MenueLevel = 0 ;
strcpy ( FileName
, FileNameOld
) ; PrintMenue_01( FileName, Scale, xMax - xMin, yMax - yMin, MoveLength) ;
}
clrscr( MessageY + 1 , MessageY + 1 ) ;
}
}
return 0 ;
}
Ly9Qcm9qZWN0OiBWLXBsb3R0ZXIKLy9Ib21lcGFnZTogd3d3LkhvbW9GYWNpZW5zLmRlCi8vQXV0aG9yIE5vcmJlcnQgSGVpbnoKLy9WZXJzaW9uOiAwLjEKLy9DcmVhdGlvbiBkYXRlOiAyNC4wNi4yMDE1Ci8vVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmUgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZS4KLy9UaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZIHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KLy9Gb3IgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBzZWUgaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnUub3JnL2xpY2Vuc2VzLwovLwovL2NvbXBpbGUgd2l0aCBnY2Mgdi1wbG90dGVyLmMgLW8gdi1wbG90dGVyIC1JL3Vzci9sb2NhbC9pbmNsdWRlIC1ML3Vzci9sb2NhbC9saWIgLWx3aXJpbmdQaSAtbG0KLy9Gb3IgZGV0YWlscyBzZWU6Ci8vaHR0cDovL3cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnMuZGUvdGVjaG5pY3MtbWFjaGluZXMtdi1wbG90dGVyX2VuX25hdmlvbi5odG0KCiNpbmNsdWRlIDxzdGRpby5oPgojaW5jbHVkZSA8dGVybWlvcy5oPgojaW5jbHVkZSA8c3lzL2lvY3RsLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8dGltZS5oPgojaW5jbHVkZSA8c3lzL3RpbWUuaD4KI2luY2x1ZGUgPGRpcmVudC5oPgojaW5jbHVkZSA8bWF0aC5oPgojaW5jbHVkZSA8d2lyaW5nUGkuaD4KI2luY2x1ZGUgPHVuaXN0ZC5oPgoKCiNkZWZpbmUgUEkgMy4xNDE1OTI3CiNkZWZpbmUgU0VSVk9VUCAgICAgICAgMTAKI2RlZmluZSBTRVJWT0RPV04gICAgICAyMAojZGVmaW5lIExFRlRfU1RFUFBFUjAxIDExCiNkZWZpbmUgTEVGVF9TVEVQUEVSMDIgMTAKCiNkZWZpbmUgTEVGVF9TVEVQUEVSMDMgIDYKI2RlZmluZSBMRUZUX1NURVBQRVIwNCAxNAoKCiNkZWZpbmUgUklHSFRfU1RFUFBFUjAxICAyCiNkZWZpbmUgUklHSFRfU1RFUFBFUjAyICAzCgojZGVmaW5lIFJJR0hUX1NURVBQRVIwMyAxMgojZGVmaW5lIFJJR0hUX1NURVBQRVIwNCAxMwoKI2RlZmluZSBTVEVQX1BBVVNFIDE1MDAKCiNkZWZpbmUgU1RFUF9NQVggMjIwLjAKCiNkZWZpbmUgWl9TRVJWTyAwCgojZGVmaW5lIEJVRkZFUlNJWkUgICAgICAgICAxMjAKCi8vTGVuZ3RocyBnaXZlbiBpbiBtaWxsaW1pdGVycwojZGVmaW5lIEJBU0VMRU5HVEggICAgICAgICAgICAgIDg0NQojZGVmaW5lIENPUkRMRU5HVEhfTEVGVCAgICAgICAgIDIyMAojZGVmaW5lIENPUkRMRU5HVEhfUklHSFQgICAgICAgIDY2NwoKLy8jZGVmaW5lIEJBU0VMRU5HVEggICAgICAgICAgICAgIDg0MAovLyNkZWZpbmUgQ09SRExFTkdUSF9MRUZUICAgICAgICAgMjY2Ci8vI2RlZmluZSBDT1JETEVOR1RIX1JJR0hUICAgICAgICA2ODUKCi8vQ29ycmVjdGlvbiBmb3IgZXJyb3JzIGNhdXNlZCBieSBmbGV4aWJpbGl0eSBvZiB0aGUgY29yZCAwLjAgPSBPRkYgKGV4cGVyaW1lbnRhbCkKI2RlZmluZSBDT1JERkxFWEZBQ1RPUiAgICAwLjBmCgppbnQgIE1heFJvd3MgPSAyNDsKaW50ICBNYXhDb2xzID0gODA7CmludCAgTWVzc2FnZVggPSAxOwppbnQgIE1lc3NhZ2VZID0gMjQ7CnVuc2lnbmVkIGNoYXIgTW92ZUJ1ZmZlcltCVUZGRVJTSVpFXTsKbG9uZyBjdXJyZW50WCA9IDAsIGN1cnJlbnRZID0gMDsKbG9uZyBDb3JkTGVuZ3RoTGVmdCA9IDA7CmxvbmcgQ29yZExlbmd0aFJpZ2h0ID0gMDsKbG9uZyBCYXNlTGVuZ3RoID0gMDsKbG9uZyBYMCwgWTA7CmludCAgRmlsZXNGb3VuZCA9IDA7CmludCBjdXJyZW50UGxvdERvd24gPSAwOwppbnQgQm9sZExpbmVXaWR0aCA9IDA7CmludCBCb2xkTGluZUdhcCA9IDA7CmxvbmcgQm9sZExpbmVYID0gMCwgQm9sZExpbmVZID0gMDsKCmludCBTdGVwWCA9IDA7IAppbnQgU3RlcFkgPSAwOwoKLy9TdGVwcyBwZXIgbW0gKHdpdGggZ2VhcikKZG91YmxlIFN0ZXBzUGVybW0gPSAyMDAwLjAgLyA5OC4wOwoKLy9TdGVwcyBwZXIgbW0gKHdpdGhvdXQgZ2VhcikKLy9kb3VibGUgU3RlcHNQZXJtbSA9IDIwMDAuMCAvIDE5OS4wOwoKY2hhciBQaWN0dXJlUGF0aFsxMDAwXTsKCgovLysrKysrKysrKysrKysrKysrKysrKysrIFN0YXJ0IGdvdG94eSArKysrKysrKysrKysrKysrKysrKysrKysrKwovL1RoYW5rcyB0byAnU3RhY2sgT3ZlcmZsb3cnLCBmb3VuZCBvbiBodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYi5jb20vc29mdHdhcmUtZGV2ZWxvcG1lbnQvYy9jb2RlLzIxNjMyNgppbnQgZ290b3h5KGludCB4LCBpbnQgeSkgewogIGNoYXIgZXNzcVsxMDBdOyAvLyBTdHJpbmcgdmFyaWFibGUgdG8gaG9sZCB0aGUgZXNjYXBlIHNlcXVlbmNlCiAgY2hhciB4c3RyWzEwMF07IC8vIFN0cmluZ3MgdG8gaG9sZCB0aGUgeCBhbmQgeSBjb29yZGluYXRlcwogIGNoYXIgeXN0clsxMDBdOyAvLyBFc2NhcGUgc2VxdWVuY2VzIG11c3QgYmUgYnVpbHQgd2l0aCBjaGFyYWN0ZXJzCiAgIAogIC8vQ29udmVydCB0aGUgc2NyZWVuIGNvb3JkaW5hdGVzIHRvIHN0cmluZ3MuCiAgc3ByaW50Zih4c3RyLCAiJWQiLCB4KTsKICBzcHJpbnRmKHlzdHIsICIlZCIsIHkpOwogICAKICAvL0J1aWxkIHRoZSBlc2NhcGUgc2VxdWVuY2UgKHZlcnRpY2FsIG1vdmUpLgogIGVzc3FbMF0gPSAnXDAnOwogIHN0cmNhdChlc3NxLCAiXDAzM1siKTsKICBzdHJjYXQoZXNzcSwgeXN0cik7CiAgIAogIC8vRGVzY3JpYmVkIGluIG1hbiB0ZXJtaW5mbyBhcyB2cGE9XEVbJXAxJWRkLiBWZXJ0aWNhbCBwb3NpdGlvbiBhYnNvbHV0ZS4KICBzdHJjYXQoZXNzcSwgImQiKTsKICAgCiAgLy9Ib3Jpem9udGFsIG1vdmUuIEhvcml6b250YWwgcG9zaXRpb24gYWJzb2x1dGUKICBzdHJjYXQoZXNzcSwgIlwwMzNbIik7CiAgc3RyY2F0KGVzc3EsIHhzdHIpOwogIC8vIERlc2NyaWJlZCBpbiBtYW4gdGVybWluZm8gYXMgaHBhPVxFWyVwMSVkRwogIHN0cmNhdChlc3NxLCAiRyIpOwogICAKICAvL0V4ZWN1dGUgdGhlIGVzY2FwZSBzZXF1ZW5jZS4gVGhpcyB3aWxsIG1vdmUgdGhlIGN1cnNvciB0byB4LCB5CiAgcHJpbnRmKCIlcyIsIGVzc3EpOwogIHJldHVybiAwOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIEVuZCBnb3RveHkgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKLy8rKysrKysrKysrKysrKysrKysrKysrKyBTdGFydCBjbHJzY3IgKysrKysrKysrKysrKysrKysrKysrKysrKysKdm9pZCBjbHJzY3IoaW50IFN0YXJ0Um93LCBpbnQgRW5kUm93KSB7CiAgaW50IGksIGkyOwogIAogIGlmIChFbmRSb3cgPCBTdGFydFJvdyl7CiAgICBpID0gRW5kUm93OwogICAgRW5kUm93ID0gU3RhcnRSb3c7CiAgICBTdGFydFJvdyA9IGk7CiAgfQogIGdvdG94eSgxLCBTdGFydFJvdyk7CiAgZm9yIChpID0gMDsgaSA8PSBFbmRSb3cgLSBTdGFydFJvdzsgaSsrKXsKICAgIGZvcihpMiA9IDA7IGkyIDwgTWF4Q29sczsgaTIrKyl7CiAgICAgIHByaW50ZigiICIpOwogICAgfQogICAgcHJpbnRmKCJcbiIpOwogIH0KfQovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIEVuZCBjbHJzY3IgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKLy8rKysrKysrKysrKysrKysrKysrKysrKyBTdGFydCBrYmhpdCArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrCi8vVGhhbmtzIHRvIFVuZGVydGVjaCBCbG9nLCBodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYy5kZS9ibG9nLzIwMDkvMDUva2JoaXRfdW5kX2dldGNoX2Z1cl9saW51eC5odG1sCmludCBrYmhpdCh2b2lkKSB7CgogICBzdHJ1Y3QgdGVybWlvcyB0ZXJtLCBvdGVybTsKICAgaW50IGZkID0gMDsKICAgaW50IGMgPSAwOwogICAKICAgdGNnZXRhdHRyKGZkLCAmb3Rlcm0pOwogICBtZW1jcHkoJnRlcm0sICZvdGVybSwgc2l6ZW9mKHRlcm0pKTsKICAgdGVybS5jX2xmbGFnID0gdGVybS5jX2xmbGFnICYgKCFJQ0FOT04pOwogICB0ZXJtLmNfY2NbVk1JTl0gPSAwOwogICB0ZXJtLmNfY2NbVlRJTUVdID0gMTsKICAgdGNzZXRhdHRyKGZkLCBUQ1NBTk9XLCAmdGVybSk7CiAgIGMgPSBnZXRjaGFyKCk7CiAgIHRjc2V0YXR0cihmZCwgVENTQU5PVywgJm90ZXJtKTsKICAgaWYgKGMgIT0gLTEpCiAgIHVuZ2V0YyhjLCBzdGRpbik7CgogICByZXR1cm4gKChjICE9IC0xKSA/IDEgOiAwKTsKCn0KLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gRW5kIGtiaGl0IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgovLysrKysrKysrKysrKysrKysrKysrKysrIFN0YXJ0IGdldGNoICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKLy9UaGFua3MgdG8gVW5kZXJ0ZWNoIEJsb2csIGh0dHA6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5jLmRlL2Jsb2cvMjAwOS8wNS9rYmhpdF91bmRfZ2V0Y2hfZnVyX2xpbnV4Lmh0bWwKaW50IGdldGNoKCl7CiAgIHN0YXRpYyBpbnQgY2ggPSAtMSwgZmQgPSAwOwogICBzdHJ1Y3QgdGVybWlvcyBuZXcsIG9sZDsKCiAgIGZkID0gZmlsZW5vKHN0ZGluKTsKICAgdGNnZXRhdHRyKGZkLCAmb2xkKTsKICAgbmV3ID0gb2xkOwogICBuZXcuY19sZmxhZyAmPSB+KElDQU5PTnxFQ0hPKTsKICAgdGNzZXRhdHRyKGZkLCBUQ1NBTk9XLCAmbmV3KTsKICAgY2ggPSBnZXRjaGFyKCk7CiAgIHRjc2V0YXR0cihmZCwgVENTQU5PVywgJm9sZCk7CgovLyAgIHByaW50ZigiY2g9JWQgIiwgY2gpOwoKICAgcmV0dXJuIGNoOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIEVuZCBnZXRjaCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKLy8rKysrKysrKysrKysrKysrKysrKysrIFN0YXJ0IE1lc3NhZ2VUZXh0ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrCnZvaWQgTWVzc2FnZVRleHQoY2hhciAqbWVzc2FnZSwgaW50IHgsIGludCB5LCBpbnQgYWxpZ25tZW50KXsKICBpbnQgaTsKICBjaGFyIFRleHRMaW5lWzMwMF07CgogIGNscnNjcih5LCB5KTsKICBnb3RveHkgKHgsIHkpOwogIAogIFRleHRMaW5lWzBdID0gJ1wwJzsKICBpZihhbGlnbm1lbnQgPT0gMSl7CiAgICBmb3IoaT0wOyBpIDwgKE1heENvbHMgLSBzdHJsZW4obWVzc2FnZSkpIC8gMiA7IGkrKyl7CiAgICAgIHN0cmNhdChUZXh0TGluZSwgIiAiKTsKICAgIH0KICB9CiAgc3RyY2F0KFRleHRMaW5lLCBtZXNzYWdlKTsKICAKICBwcmludGYoIiVzXG4iLCBUZXh0TGluZSk7Cn0KLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBFbmQgTWVzc2FnZVRleHQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgovLysrKysrKysrKysrKysrKysrKysrKysgU3RhcnQgUHJpbnRSb3cgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKdm9pZCBQcmludFJvdyhjaGFyIGNoYXJhY3RlciwgaW50IHkpewogIGludCBpOwogIGdvdG94eSAoMSwgeSk7CiAgZm9yKGk9MDsgaTxNYXhDb2xzO2krKyl7CiAgICBwcmludGYoIiVjIiwgY2hhcmFjdGVyKTsKICB9Cn0KLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBFbmQgUHJpbnRSb3cgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgovLysrKysrKysrKysrKysrKysrKysrKysrKysgRXJyb3JUZXh0ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrCnZvaWQgRXJyb3JUZXh0KGNoYXIgKm1lc3NhZ2UpewogIGNscnNjcihNZXNzYWdlWSArIDIsIE1lc3NhZ2VZICsgMik7CiAgZ290b3h5ICgxLCBNZXNzYWdlWSArIDIpOyAgCiAgcHJpbnRmKCJMYXN0IGVycm9yOiAlcyIsIG1lc3NhZ2UpOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gRXJyb3JUZXh0IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKLy8rKysrKysrKysrKysrKysrKysrKysrKysrIFByaW50TWVudWVfMDEgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrCnZvaWQgUHJpbnRNZW51ZV8wMShjaGFyICogUGxvdEZpbGUsIGRvdWJsZSBzY2FsZSwgZG91YmxlIHdpZHRoLCBkb3VibGUgaGVpZ2h0LCBsb25nIE1vdmVMZW5ndGgpewogIGNoYXIgVGV4dExpbmVbMzAwXTsKICAKICAgY2xyc2NyKDEsIE1lc3NhZ2VZLTIpOwogICBNZXNzYWdlVGV4dCgiKioqIE1haW4gbWVudSBwbG90dGVyICoqKiIsIDEsIDEsIDEpOwogICBzcHJpbnRmKFRleHRMaW5lLCAiTSAgICAgICAgICAgIC0gdG9nZ2xlIG1vdmUgbGVuZ3RoLCBjdXJyZW50IHZhbHVlID0gJWxkIHN0ZXAocykiLCBNb3ZlTGVuZ3RoKTsKICAgTWVzc2FnZVRleHQoVGV4dExpbmUsIDEwLCAzLCAwKTsKICAgTWVzc2FnZVRleHQoIkN1cnNvciByaWdodCAtIG1vdmUgcGxvdHRlciBpbiBwb3NpdGl2ZSBYIGRpcmVjdGlvbiIsIDEwLCA0LCAwKTsKICAgTWVzc2FnZVRleHQoIkN1cnNvciBsZWZ0ICAtIG1vdmUgcGxvdHRlciBpbiBuZWdhdGl2ZSBYIGRpcmVjdGlvbiIsIDEwLCA1LCAwKTsKICAgTWVzc2FnZVRleHQoIkN1cnNvciB1cCAgICAtIG1vdmUgcGxvdHRlciBpbiBwb3NpdGl2ZSBZIGRpcmVjdGlvbiIsIDEwLCA2LCAwKTsKICAgTWVzc2FnZVRleHQoIkN1cnNvciBkb3duICAtIG1vdmUgcGxvdHRlciBpbiBuZWdhdGl2ZSBZIGRpcmVjdGlvbiIsIDEwLCA3LCAwKTsKICAgTWVzc2FnZVRleHQoIlBhZ2UgdXAgICAgICAtIGxpZnQgcGVuIiwgMTAsIDgsIDApOwogICBNZXNzYWdlVGV4dCgiUGFnZSBkb3duICAgIC0gdG91Y2ggZG93biBwZW4iLCAxMCwgOSwgMCk7CiAgIHNwcmludGYoVGV4dExpbmUsICJGICAgICAgICAgICAgLSBjaG9vc2UgZmlsZS4gQ3VycmVudCBmaWxlID0gXCIlc1wiIiwgUGxvdEZpbGUpOwogICBNZXNzYWdlVGV4dChUZXh0TGluZSwgMTAsIDEwLCAwKTsKICAgTWVzc2FnZVRleHQoIjAgICAgICAgICAgICAtIG1vdmUgcGxvdHRlciB0byAwLzAiLCAxMCwgMTEsIDApOwogICBzcHJpbnRmKFRleHRMaW5lLCAiUyAgICAgICAgICAgIC0gU2NhbGUgc2V0IHRvID0gJTAuNGYuIFcgPSAlMC4yZmNtLCBIID0gJTAuMmZjbSIsIHNjYWxlLCB3aWR0aCAqIHNjYWxlIC8gMTAwMC4wLCBoZWlnaHQgKiBzY2FsZSAvIDEwMDAuMCk7CiAgIE1lc3NhZ2VUZXh0KFRleHRMaW5lLCAxMCwgMTIsIDApOwogICBzcHJpbnRmKFRleHRMaW5lLCAiQiAgICAgICAgICAgIC0gQm9sZCBsaW5lID0gJWQgc3RlcHMiLCBCb2xkTGluZVdpZHRoKTsKICAgTWVzc2FnZVRleHQoVGV4dExpbmUsIDEwLCAxMywgMCk7CiAgIE1lc3NhZ2VUZXh0KCJQICAgICAgICAgICAgLSBwbG90IGZpbGUiLCAxMCwgMTQsIDApOwoKICAgTWVzc2FnZVRleHQoIkVzYyAgICAgICAgICAtIGxlYXZlIHByb2dyYW0iLCAxMCwgMTYsIDApOwogICAKfQovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gUHJpbnRNZW51ZV8wMSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCi8vKysrKysrKysrKysrKysrKysrKysrKysrKyBQcmludE1lbnVlXzAyICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwpjaGFyICpQcmludE1lbnVlXzAyKGludCBTdGFydFJvdywgaW50IHNlbGVjdGVkKXsKICBjaGFyIFRleHRMaW5lWzMwMF07CiAgY2hhciBGaWxlUGF0dGVybls1XTsKICBjaGFyIE9wZW5EaXJOYW1lWzEwMDBdOwogIHN0YXRpYyBjaGFyIEZpbGVOYW1lWzEwMV07CiAgRElSICpwRElSOwogIHN0cnVjdCBkaXJlbnQgKnBEaXJFbnQ7CiAgaW50IGkgPSAwOyAgCiAgaW50IERpc2NhcmQgPSAwOwogIAogIGNscnNjcigxLCBNZXNzYWdlWS0yKTsKICBNZXNzYWdlVGV4dCgiKioqIENob29zZSBwbG90dGVyIGZpbGUgKioqIiwgMSwgMSwgMSk7CiAgIAogIHN0cmNweShPcGVuRGlyTmFtZSwgUGljdHVyZVBhdGgpOwogIAoKICBwRElSID0gb3BlbmRpcihPcGVuRGlyTmFtZSk7CiAgaWYgKCBwRElSID09IE5VTEwgKSB7CiAgICBzcHJpbnRmKFRleHRMaW5lLCAiQ291bGQgbm90IG9wZW4gZGlyZWN0b3J5ICclcychIiwgT3BlbkRpck5hbWUpOwogICAgTWVzc2FnZVRleHQoVGV4dExpbmUsIDEsIDQsIDEpOwogICAgZ2V0Y2goKTsKICAgIHJldHVybiggIiIgKTsKICB9CiAgCiAgRmlsZXNGb3VuZCA9IDA7CiAgcERpckVudCA9IHJlYWRkaXIoIHBESVIgKTsKICB3aGlsZSAoIHBEaXJFbnQgIT0gTlVMTCAmJiBpIDwgMTApIHsKICAgIGlmKHN0cmxlbihwRGlyRW50LT5kX25hbWUpID4gNCl7CiAgICAgIGlmKG1lbWNtcChwRGlyRW50LT5kX25hbWUgKyBzdHJsZW4ocERpckVudC0+ZF9uYW1lKS00LCAiLnN2ZyIsNCkgPT0gMCl7CiAgICAgICAgRmlsZXNGb3VuZCsrOwogICAgICAgIGlmKERpc2NhcmQgPj0gU3RhcnRSb3cpewogICAgICAgICAgaWYoaSArIFN0YXJ0Um93ID09IHNlbGVjdGVkKXsKICAgICAgICAgICAgc3ByaW50ZihUZXh0TGluZSwgIj4lczwiLCBwRGlyRW50LT5kX25hbWUpOwogICAgICAgICAgICBzdHJjcHkoRmlsZU5hbWUsIHBEaXJFbnQtPmRfbmFtZSk7CiAgICAgICAgICB9CiAgICAgICAgICBlbHNlewogICAgICAgICAgICBzcHJpbnRmKFRleHRMaW5lLCAiICVzICIsIHBEaXJFbnQtPmRfbmFtZSk7IAogICAgICAgICAgfQogICAgICAgICAgTWVzc2FnZVRleHQoVGV4dExpbmUsIDEsIDMgKyBpLCAwKTsKICAgICAgICAgIGkrKzsKICAgICAgICB9CiAgICAgICAgRGlzY2FyZCsrOwoKICAgICAgfQogICAgfQogICAgcERpckVudCA9IHJlYWRkaXIoIHBESVIgKTsKICB9ICAKCiAgZ290b3h5KE1lc3NhZ2VYLCBNZXNzYWdlWSArIDEpOwogIHByaW50ZigiQ2hvb3NlIGZpbGUgdXNpbmcgdXAvZG93biBrZXlzIGFuZCBjb25maXJtIHdpdGggJ0VudGVyJyBvciBwcmVzcyAnRXNjJyB0byBjYW5jZWwuIik7CiAgCgogIHJldHVybiAoRmlsZU5hbWUpOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBQcmludE1lbnVlXzAyIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCi8vKysrKysrKysrKysrKysrKysrKysrKysrKyBQcmludE1lbnVlXzAzICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwp2b2lkIFByaW50TWVudWVfMDMoY2hhciAqRnVsbEZpbGVOYW1lLCBsb25nIE51bWJlck9mTGluZXMsIGxvbmcgQ3VycmVudExpbmUsIGxvbmcgQ3VycmVudFgsIGxvbmcgQ3VycmVudFksIGxvbmcgU3RhcnRUaW1lKXsKICBjaGFyIFRleHRMaW5lWzMwMF07CiAgbG9uZyBDdXJyZW50VGltZSwgUHJvY2Vzc0hvdXJzID0gMCwgUHJvY2Vzc01pbnV0ZXMgPSAwLCBQcm9jZXNzU2Vjb25kcyA9IDA7CiAgCiAgIEN1cnJlbnRUaW1lID0gdGltZSgwKTsKICAgCiAgIEN1cnJlbnRUaW1lIC09IFN0YXJ0VGltZTsKICAgCiAgIHdoaWxlIChDdXJyZW50VGltZSA+IDM2MDApewogICAgIFByb2Nlc3NIb3VycysrOwogICAgIEN1cnJlbnRUaW1lIC09IDM2MDA7CiAgIH0KICAgd2hpbGUgKEN1cnJlbnRUaW1lID4gNjApewogICAgIFByb2Nlc3NNaW51dGVzKys7CiAgICAgQ3VycmVudFRpbWUgLT0gNjA7CiAgIH0KICAgUHJvY2Vzc1NlY29uZHMgPSBDdXJyZW50VGltZTsKICAgCiAgIGNscnNjcigxLCBNZXNzYWdlWSAtIDIpOwogICBNZXNzYWdlVGV4dCgiKioqIFBsb3R0aW5nIGZpbGUgKioqIiwgMSwgMSwgMSk7CiAgIAogICBzcHJpbnRmKFRleHRMaW5lLCAiRmlsZSBuYW1lOiAlcyIsIEZ1bGxGaWxlTmFtZSk7CiAgIE1lc3NhZ2VUZXh0KFRleHRMaW5lLCAxMCwgMywgMCk7CiAgIHNwcmludGYoVGV4dExpbmUsICJOdW1iZXIgb2YgbGluZXM6ICVsZCIsIE51bWJlck9mTGluZXMpOwogICBNZXNzYWdlVGV4dChUZXh0TGluZSwgMTAsIDQsIDApOwogICBzcHJpbnRmKFRleHRMaW5lLCAiQ3VycmVudCBQb3NpdGlvbiglbGQpOiBYID0gJWxkLCBZID0gJWxkICAgICAiLCBDdXJyZW50TGluZSwgQ3VycmVudFgsIEN1cnJlbnRZKTsKICAgTWVzc2FnZVRleHQoVGV4dExpbmUsIDEwLCA1LCAwKTsKICAgc3ByaW50ZihUZXh0TGluZSwgIlByb2Nlc3MgdGltZTogJTAybGQ6JTAybGQ6JTAybGQiLCBQcm9jZXNzSG91cnMsIFByb2Nlc3NNaW51dGVzLCBQcm9jZXNzU2Vjb25kcyk7CiAgIE1lc3NhZ2VUZXh0KFRleHRMaW5lLCAxMCwgNiwgMCk7CiAgICAgCgp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBQcmludE1lbnVlXzAzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCgovLysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyBNYWtlU3RlcExlZnQgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKdm9pZCBNYWtlU3RlcExlZnQoaW50IGRpcmVjdGlvbil7CiAgU3RlcFggKz0gZGlyZWN0aW9uOwogIAogIGlmKFN0ZXBYID4gMyl7CiAgICBTdGVwWCA9IDA7CiAgfQogIGlmKFN0ZXBYIDwgMCl7CiAgICBTdGVwWCA9IDM7CiAgfSAgCiAgCiAgaWYoU3RlcFggPT0gMCl7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDEsIDEpOwogICAgdXNsZWVwKFNURVBfUEFVU0UpOwogICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAyLCAwKTsKICAgIGRpZ2l0YWxXcml0ZShMRUZUX1NURVBQRVIwMywgMCk7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDQsIDApOyAgICAKICB9CiAgaWYoU3RlcFggPT0gMSl7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDMsIDEpOwogICAgdXNsZWVwKFNURVBfUEFVU0UpOwogICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAxLCAwKTsKICAgIGRpZ2l0YWxXcml0ZShMRUZUX1NURVBQRVIwMiwgMCk7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDQsIDApOyAgICAKICB9CiAgaWYoU3RlcFggPT0gMil7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDIsIDEpOwogICAgdXNsZWVwKFNURVBfUEFVU0UpOwogICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAxLCAwKTsKICAgIGRpZ2l0YWxXcml0ZShMRUZUX1NURVBQRVIwMywgMCk7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDQsIDApOyAgICAKICB9CiAgaWYoU3RlcFggPT0gMyl7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDQsIDEpOyAgICAKICAgIHVzbGVlcChTVEVQX1BBVVNFKTsKICAgIGRpZ2l0YWxXcml0ZShMRUZUX1NURVBQRVIwMSwgMCk7CiAgICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDIsIDApOwogICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAzLCAwKTsKICB9CiAgCiAgdXNsZWVwKFNURVBfUEFVU0UpOwp9CgovLysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyBNYWtlU3RlcFJpZ2h0ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrCnZvaWQgTWFrZVN0ZXBSaWdodChpbnQgZGlyZWN0aW9uKXsKICBTdGVwWSArPSBkaXJlY3Rpb247CiAgCiAgaWYoU3RlcFkgPiAzKXsKICAgIFN0ZXBZID0gMDsKICB9CiAgaWYoU3RlcFkgPCAwKXsKICAgIFN0ZXBZID0gMzsKICB9ICAKICAKCiAgaWYoU3RlcFkgPT0gMCl7CiAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjAxLCAxKTsKICAgIHVzbGVlcChTVEVQX1BBVVNFKTsKICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDIsIDApOwogICAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwMywgMCk7CiAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjA0LCAwKTsgICAgCiAgfQogIGlmKFN0ZXBZID09IDEpewogICAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwMywgMSk7CiAgICB1c2xlZXAoU1RFUF9QQVVTRSk7CiAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjAxLCAwKTsKICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDIsIDApOwogICAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwNCwgMCk7ICAgIAogIH0KICBpZihTdGVwWSA9PSAyKXsKICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDIsIDEpOwogICAgdXNsZWVwKFNURVBfUEFVU0UpOwogICAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwMSwgMCk7CiAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjAzLCAwKTsKICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDQsIDApOyAgICAKICB9CiAgaWYoU3RlcFkgPT0gMyl7CiAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjA0LCAxKTsgICAgCiAgICB1c2xlZXAoU1RFUF9QQVVTRSk7CiAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjAxLCAwKTsKICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDIsIDApOwogICAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwMywgMCk7CiAgfQoKLy8gIHByaW50ZigiU3RlcFlcbiIpOwogIHVzbGVlcChTVEVQX1BBVVNFKTsKfQoKCi8vKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysgbW92ZVhZICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwp2b2lkIG1vdmVYWShsb25nIFgsIGxvbmcgWSl7CiAgbG9uZyBuZXdDb3JkTGVuZ3RoTGVmdDsKICBsb25nIG5ld0NvcmRMZW5ndGhSaWdodDsKICBkb3VibGUgZm9yY2VMZWZ0LCBmb3JjZVJpZ2h0OwogIGRvdWJsZSBkZWx0YUNvcmRMZWZ0LCBkZWx0YUNvcmRSaWdodDsKICBkb3VibGUgZGVsdGFDb3JkTGVmdDAsIGRlbHRhQ29yZFJpZ2h0MDsKICBkb3VibGUgYWxwaGE7CiAgY2hhciBUZXh0TGluZVsxMDAwXTsKCiAgLy9jYWxjdWxhdGUgaW5pdGlhbCBzdHJldGNoIG9mIGNvcmRzIChleHBlcmltZW50YWwpCiAgYWxwaGEgPSBhdGFuKChkb3VibGUpKFgwKSAvIChkb3VibGUpKFkwKSk7CiAgZm9yY2VMZWZ0ID0gMS4wICogY29zKGFscGhhKTsKICBmb3JjZVJpZ2h0ID0gMS4wICogc2luKGFscGhhKTsKCiAgZGVsdGFDb3JkTGVmdDAgPSAoZG91YmxlKShDT1JETEVOR1RIX0xFRlQgKiBTdGVwc1Blcm1tKSAqIGZvcmNlTGVmdCAqIENPUkRGTEVYRkFDVE9SOwogIGRlbHRhQ29yZFJpZ2h0MCA9IChkb3VibGUpKENPUkRMRU5HVEhfUklHSFQgKiBTdGVwc1Blcm1tKSAqIGZvcmNlUmlnaHQgKiBDT1JERkxFWEZBQ1RPUjsKICAKCiAgLy9mb3JjZXMgYXQgY3VycmVudCBjb29yZGluYXRlcyAoZXhwZXJpbWVudGFsKQogIGFscGhhID0gYXRhbigoZG91YmxlKShYICsgWDApIC8gKGRvdWJsZSkoWSArIFkwKSk7CiAgZm9yY2VMZWZ0ID0gMS4wICogY29zKGFscGhhKTsKICBmb3JjZVJpZ2h0ID0gMS4wICogc2luKGFscGhhKTsKICAKICBYICs9IFgwOwogIFkgKz0gWTA7CiAgICAKICBuZXdDb3JkTGVuZ3RoTGVmdCA9IHNxcnQoKGRvdWJsZSkoWCAqIFgpICsgKGRvdWJsZSkoWSAqIFkpKTsKICBuZXdDb3JkTGVuZ3RoUmlnaHQgPSBzcXJ0KChkb3VibGUpKChCYXNlTGVuZ3RoLVgpICogKEJhc2VMZW5ndGgtWCkpICsgKGRvdWJsZSkoWSAqIFkpKTsKICAKICBkZWx0YUNvcmRMZWZ0ID0gKGRvdWJsZSkobmV3Q29yZExlbmd0aExlZnQpICogZm9yY2VMZWZ0ICogQ09SREZMRVhGQUNUT1IgLSBkZWx0YUNvcmRMZWZ0MDsKICBkZWx0YUNvcmRSaWdodCA9IChkb3VibGUpKG5ld0NvcmRMZW5ndGhSaWdodCkgKiBmb3JjZVJpZ2h0ICogQ09SREZMRVhGQUNUT1IgLSBkZWx0YUNvcmRSaWdodDA7CiAgCgogIG5ld0NvcmRMZW5ndGhMZWZ0IC09IGRlbHRhQ29yZExlZnQ7CiAgbmV3Q29yZExlbmd0aFJpZ2h0IC09IGRlbHRhQ29yZFJpZ2h0OwogIAogIHdoaWxlKG5ld0NvcmRMZW5ndGhMZWZ0ID4gQ29yZExlbmd0aExlZnQpewogICAgTWFrZVN0ZXBMZWZ0KDEpOwogICAgQ29yZExlbmd0aExlZnQrKzsKICB9CiAgd2hpbGUobmV3Q29yZExlbmd0aExlZnQgPCBDb3JkTGVuZ3RoTGVmdCl7CiAgICBNYWtlU3RlcExlZnQoLTEpOwogICAgQ29yZExlbmd0aExlZnQtLTsKICB9CgogIHdoaWxlKG5ld0NvcmRMZW5ndGhSaWdodCA+IENvcmRMZW5ndGhSaWdodCl7CiAgICBNYWtlU3RlcFJpZ2h0KDEpOwogICAgQ29yZExlbmd0aFJpZ2h0Kys7CiAgfQogIHdoaWxlKG5ld0NvcmRMZW5ndGhSaWdodCA8IENvcmRMZW5ndGhSaWdodCl7CiAgICBNYWtlU3RlcFJpZ2h0KC0xKTsKICAgIENvcmRMZW5ndGhSaWdodC0tOwogIH0KCgp9CgovLysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrIEJvbGRMaW5lUGF0dGVybiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwp2b2lkIEJvbGRMaW5lUGF0dGVybihsb25nIFgsIGxvbmcgWSl7CiAgaW50IGk7CiAgbG9uZyB4RGlmZiwgeURpZmY7CiAgZG91YmxlIGFscGhhID0gMC4wOwogIGxvbmcgeENpcmNsZSwgeUNpcmNsZTsKICAKICB4RGlmZiA9IEJvbGRMaW5lWCAtIFg7CiAgeURpZmYgPSBCb2xkTGluZVkgLSBZOwogIAogIGlmKEJvbGRMaW5lV2lkdGggPiAwKXsKICAgIGlmKGN1cnJlbnRQbG90RG93biA9PSAxKXsgICAgCiAgICAgIGlmKHNxcnQoeERpZmYgKiB4RGlmZiArIHlEaWZmICogeURpZmYpID4gQm9sZExpbmVHYXApewogICAgICAgIEJvbGRMaW5lWCA9IFg7CiAgICAgICAgQm9sZExpbmVZID0gWTsKICAgICAgICAKICAgICAgICBmb3IoYWxwaGEgPSAwLjA7IGFscGhhIDwgMi4wICogUEk7IGFscGhhICs9IFBJIC8gMjUwMC4wKXsKICAgICAgICAgIHhDaXJjbGUgPSBjb3MoYWxwaGEpICogQm9sZExpbmVXaWR0aCArIFg7CiAgICAgICAgICB5Q2lyY2xlID0gc2luKGFscGhhKSAqIEJvbGRMaW5lV2lkdGggKyBZOwogICAgICAgICAgbW92ZVhZKHhDaXJjbGUsIHlDaXJjbGUpOwogICAgICAgIH0KICAgICAgICBtb3ZlWFkoWCwgWSk7CiAgICAgIH0KICAgIH0vL2lmKGN1cnJlbnRQbG90RG93biA9PSAxKXsKICB9Cn0KCi8vKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysgQ2FsY3VsYXRlTGluZSArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwppbnQgQ2FsY3VsYXRlTGluZShsb25nIG1vdmVUb1gsIGxvbmcgbW92ZVRvWSl7CiAgY2hhciBUZXh0TGluZVsxMDAwXSA9ICIiOwogIGxvbmcgIHRlbXBYID0gMCwgdGVtcFkgPSAwOwogIGludCBpID0gMDsKICAKICBzcHJpbnRmKFRleHRMaW5lLCAiTW92aW5nIFg6ICVsZCwgTW92aW5nIFk6ICVsZCIsIG1vdmVUb1gsIG1vdmVUb1kpOwogIE1lc3NhZ2VUZXh0KFRleHRMaW5lLCBNZXNzYWdlWCwgTWVzc2FnZVksIDApOwovLyAgZ2V0Y2goKTsKCgogIGlmKG1vdmVUb1ggLSBjdXJyZW50WCAhPSAwICYmIG1vdmVUb1kgLSBjdXJyZW50WSAhPSAwKXsKICAgIHRlbXBYID0gY3VycmVudFg7CiAgICB0ZW1wWSA9IGN1cnJlbnRZOwogICAgaWYoYWJzKG1vdmVUb1ggLSBjdXJyZW50WCkgPiBhYnMobW92ZVRvWSAtIGN1cnJlbnRZKSl7CiAgICAgIHdoaWxlKGN1cnJlbnRYIDwgbW92ZVRvWCl7CiAgICAgICAgY3VycmVudFgrKzsKICAgICAgICBtb3ZlWFkoY3VycmVudFgsIGN1cnJlbnRZKTsKICAgICAgICBjdXJyZW50WSA9IHRlbXBZICsgKGN1cnJlbnRYIC0gdGVtcFgpICogKG1vdmVUb1kgLSB0ZW1wWSkgLyAobW92ZVRvWCAtIHRlbXBYKTsKICAgICAgICBtb3ZlWFkoY3VycmVudFgsIGN1cnJlbnRZKTsKICAgICAgICBCb2xkTGluZVBhdHRlcm4oY3VycmVudFgsIGN1cnJlbnRZKTsKICAgICAgfQogICAgICB3aGlsZShjdXJyZW50WCA+IG1vdmVUb1gpewogICAgICAgIGN1cnJlbnRYLS07CiAgICAgICAgbW92ZVhZKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICAgICAgY3VycmVudFkgPSB0ZW1wWSArIChjdXJyZW50WCAtIHRlbXBYKSAqIChtb3ZlVG9ZIC0gdGVtcFkpIC8gKG1vdmVUb1ggLSB0ZW1wWCk7CiAgICAgICAgbW92ZVhZKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICAgICAgQm9sZExpbmVQYXR0ZXJuKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICAgIH0KICAgIH0KICAgIGVsc2V7CiAgICAgIHdoaWxlKGN1cnJlbnRZIDwgbW92ZVRvWSl7CiAgICAgICAgY3VycmVudFkrKzsKICAgICAgICBtb3ZlWFkoY3VycmVudFgsIGN1cnJlbnRZKTsKICAgICAgICBjdXJyZW50WCA9IHRlbXBYICsgKGN1cnJlbnRZIC0gdGVtcFkpICogKG1vdmVUb1ggLSB0ZW1wWCkgLyAobW92ZVRvWSAtIHRlbXBZKTsKICAgICAgICBtb3ZlWFkoY3VycmVudFgsIGN1cnJlbnRZKTsKICAgICAgICBCb2xkTGluZVBhdHRlcm4oY3VycmVudFgsIGN1cnJlbnRZKTsKICAgICAgfQogICAgICB3aGlsZShjdXJyZW50WSA+IG1vdmVUb1kpewogICAgICAgIGN1cnJlbnRZLS07CiAgICAgICAgbW92ZVhZKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICAgICAgY3VycmVudFggPSB0ZW1wWCArIChjdXJyZW50WSAtIHRlbXBZKSAqIChtb3ZlVG9YIC0gdGVtcFgpIC8gKG1vdmVUb1kgLSB0ZW1wWSk7CiAgICAgICAgbW92ZVhZKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICAgICAgQm9sZExpbmVQYXR0ZXJuKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICAgIH0KICAgIH0gICAgCiAgfQoKCiAgd2hpbGUobW92ZVRvWSA+IGN1cnJlbnRZKXsKICAgIGN1cnJlbnRZKys7CiAgICBtb3ZlWFkoY3VycmVudFgsIGN1cnJlbnRZKTsKICAgIEJvbGRMaW5lUGF0dGVybihjdXJyZW50WCwgY3VycmVudFkpOwogIH0KICB3aGlsZShtb3ZlVG9ZIDwgY3VycmVudFkpewogICAgY3VycmVudFktLTsKICAgIG1vdmVYWShjdXJyZW50WCwgY3VycmVudFkpOwogICAgQm9sZExpbmVQYXR0ZXJuKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgfQoKICB3aGlsZShtb3ZlVG9YID4gY3VycmVudFgpewogICAgY3VycmVudFgrKzsKICAgIG1vdmVYWShjdXJyZW50WCwgY3VycmVudFkpOwogICAgQm9sZExpbmVQYXR0ZXJuKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgfQogIHdoaWxlKG1vdmVUb1ggPCBjdXJyZW50WCl7CiAgICBjdXJyZW50WC0tOwogICAgbW92ZVhZKGN1cnJlbnRYLCBjdXJyZW50WSk7CiAgICBCb2xkTGluZVBhdHRlcm4oY3VycmVudFgsIGN1cnJlbnRZKTsKICB9CgogIHJldHVybiAwOyAKfQovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIENhbGN1bGF0ZUxpbmUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCi8vIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwovLyMjIyMjIyMjIyMjIyMjIyMjIyBNYWluICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKLy8jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgppbnQgbWFpbihpbnQgYXJnYywgY2hhciAqKmFyZ3YpewoKICBpbnQgTWVudWVMZXZlbCA9IDA7CiAgaW50IEtleUhpdCA9IDA7CiAgaW50IEtleUNvZGVbNV07CiAgY2hhciBGaWxlSW5mb1szXTsKICBjaGFyIEZpbGVOYW1lWzIwMF0gPSAiIjsKICBjaGFyIEZ1bGxGaWxlTmFtZVsyMDBdID0gIiI7CiAgY2hhciBGaWxlTmFtZU9sZFsyMDBdID0gIiI7CiAgc3RydWN0IHdpbnNpemUgdGVybWluYWw7CiAgZG91YmxlIFNjYWxlID0gMS4wOwogIGRvdWJsZSBPbGRTY2FsZSA9IDEuMDsKICBsb25nIE1vdmVMZW5ndGggPSAxOwogIGludCBpOwogIGludCBTaW5nbGVLZXk9MDsKICBsb25nIGN1cnJlbnRQbG90WCA9IDAsIGN1cnJlbnRQbG90WSA9IDA7CiAgaW50IEZpbGVTZWxlY3RlZCA9IDA7CiAgaW50IEZpbGVTdGFydFJvdyA9IDA7CiAgY2hhciAqcEVuZDsKICBGSUxFICpQbG90RmlsZTsKICBjaGFyIFRleHRMaW5lWzEwMDAwXTsKICBsb25nIHhNaW4gPSAxMDAwMDAwLCB4TWF4ID0gLTEwMDAwMDA7CiAgbG9uZyB5TWluID0gMTAwMDAwMCwgeU1heCA9IC0xMDAwMDAwOwogIGxvbmcgY29vcmRpbmF0ZUNvdW50ID0gMDsKICBjaGFyIGE7CiAgaW50IFJlYWRTdGF0ZSA9IDA7CiAgbG9uZyB4Tm93ID0gMCwgeU5vdyA9IDA7CiAgbG9uZyB4Tm93MSA9IDAsIHlOb3cxID0gMDsKICBsb25nIHhOb3cyID0gMCwgeU5vdzIgPSAwOwogIHN0cnVjdCB0aW1ldmFsIFN0YXJ0VGltZSwgRW5kVGltZTsKICBsb25nIGNvb3JkaW5hdGVQbG90ID0gMDsKICBpbnQgc3RvcFBsb3QgPSAwOwogIGxvbmcgUGxvdFN0YXJ0VGltZSA9IDA7CiAgaW50IE1heEZpbGVSb3dzID0gMDsKCgogIEZpbGVJbmZvWzJdPSdcMCc7CgogIHN0cmNweShGaWxlTmFtZSwgIm5vRmlMRSIpOwoKICBnZXRjd2QoUGljdHVyZVBhdGgsIDEwMDApOwogIHN0cmNhdChQaWN0dXJlUGF0aCwgIi9waWN0dXJlcyIpOwogIHByaW50ZigiUGljdHVyZVBhdGg9PiVzPCIsIFBpY3R1cmVQYXRoKTsKCiAgaWYgKHdpcmluZ1BpU2V0dXAgKCkgPT0gLTEpewogICAgcHJpbnRmKCJDb3VsZCBub3QgcnVuIHdpcmluZ1BpU2V0dXAhIik7CiAgICBleGl0KDEpOwogIH0KCiAgc29mdFB3bUNyZWF0ZShaX1NFUlZPLCBTRVJWT1VQLCAyMDApOwogIHNvZnRQd21Xcml0ZShaX1NFUlZPLCBTRVJWT1VQKTsKICB1c2xlZXAoNTAwMDAwKTsKICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgMCk7CgoKICBwaW5Nb2RlIChMRUZUX1NURVBQRVIwMSwgT1VUUFVUKTsKICBwaW5Nb2RlIChMRUZUX1NURVBQRVIwMiwgT1VUUFVUKTsKICBwaW5Nb2RlIChMRUZUX1NURVBQRVIwMywgT1VUUFVUKTsKICBwaW5Nb2RlIChMRUZUX1NURVBQRVIwNCwgT1VUUFVUKTsKCiAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAxLCAxKTsKICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDIsIDApOyAgICAKICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDMsIDApOyAgICAKICBkaWdpdGFsV3JpdGUoTEVGVF9TVEVQUEVSMDQsIDApOyAgICAKCiAgcGluTW9kZSAoUklHSFRfU1RFUFBFUjAxLCBPVVRQVVQpOwogIHBpbk1vZGUgKFJJR0hUX1NURVBQRVIwMiwgT1VUUFVUKTsKICBwaW5Nb2RlIChSSUdIVF9TVEVQUEVSMDMsIE9VVFBVVCk7CiAgcGluTW9kZSAoUklHSFRfU1RFUFBFUjA0LCBPVVRQVVQpOwogIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDEsIDEpOwogIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDIsIDApOyAgICAKICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjAzLCAwKTsgICAgCiAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwNCwgMCk7ICAgIAoKCgogIGlmKGlvY3RsKFNURE9VVF9GSUxFTk8sIFRJT0NHV0lOU1osICZ0ZXJtaW5hbCk8MCl7CiAgICBwcmludGYoIkNhbid0IGdldCBzaXplIG9mIHRlcm1pbmFsIHdpbmRvdyIpOwogIH0KICBlbHNlewogICAgTWF4Um93cyA9IHRlcm1pbmFsLndzX3JvdzsKICAgIE1heENvbHMgPSB0ZXJtaW5hbC53c19jb2w7CiAgICBNZXNzYWdlWSA9IE1heFJvd3MtMzsKICB9CgogIE1heEZpbGVSb3dzID0gTWF4Um93cyAtIDEwOwoKICBCYXNlTGVuZ3RoID0gQkFTRUxFTkdUSCAqIFN0ZXBzUGVybW07CiAgQ29yZExlbmd0aExlZnQgPSBDT1JETEVOR1RIX0xFRlQgKiBTdGVwc1Blcm1tOwogIENvcmRMZW5ndGhSaWdodCA9IENPUkRMRU5HVEhfUklHSFQgKiBTdGVwc1Blcm1tOwogIFgwID0gKENvcmRMZW5ndGhMZWZ0ICogQ29yZExlbmd0aExlZnQgLSBDb3JkTGVuZ3RoUmlnaHQgKiBDb3JkTGVuZ3RoUmlnaHQgKyBCYXNlTGVuZ3RoICogQmFzZUxlbmd0aCkgLyAoMi4wICogQmFzZUxlbmd0aCk7CiAgWTAgPSBzcXJ0KENvcmRMZW5ndGhSaWdodCAqIENvcmRMZW5ndGhSaWdodCAtIChCYXNlTGVuZ3RoIC0gWDApICogKEJhc2VMZW5ndGggLSBYMCkpOwogIAogIHByaW50ZigiWDA9JWxkLCBZMD0lbGQsIENMPSVsZCwgQ1I9JWxkIFN0ZXBzUGVybW09JWxmXG4iLCBYMCwgWTAsIENvcmRMZW5ndGhMZWZ0LCBDb3JkTGVuZ3RoUmlnaHQsIFN0ZXBzUGVybW0pOwogIAoKICBjbHJzY3IoMSwgTWF4Um93cyk7CiAgUHJpbnRSb3coJy0nLCBNZXNzYWdlWSAtIDEpOwogIFByaW50TWVudWVfMDEoRmlsZU5hbWUsIFNjYWxlLCB4TWF4IC0geE1pbiwgeU1heCAtIHlNaW4sIE1vdmVMZW5ndGgpOwoKCiAgd2hpbGUgKDEpewogICAgTWVzc2FnZVRleHQoIldhaXRpbmcgZm9yIGtleSBwcmVzcy4iLCBNZXNzYWdlWCwgTWVzc2FnZVksIDApOwoKICAgIGkgPSAwOwogICAgU2luZ2xlS2V5ID0gMTsKICAgIEtleUNvZGVbMF0gPSAwOwogICAgS2V5Q29kZVsxXSA9IDA7CiAgICBLZXlDb2RlWzJdID0gMDsKICAgIEtleUNvZGVbM10gPSAwOwogICAgS2V5Q29kZVs0XSA9IDA7CiAgICBLZXlIaXQgPSAwOwogICAgd2hpbGUgKGtiaGl0KCkpewogICAgICBLZXlIaXQgPSBnZXRjaCgpOwogICAgICBLZXlDb2RlW2ldID0gS2V5SGl0OwogICAgICBpKys7CiAgICAgIGlmKGkgPT0gNSl7CiAgICAgICAgaSA9IDA7CiAgICAgIH0KICAgICAgaWYoaSA+IDEpewogICAgICAgIFNpbmdsZUtleSA9IDA7CiAgICAgIH0KICAgIH0KICAgIGlmKFNpbmdsZUtleSA9PSAwKXsKICAgICAgS2V5SGl0ID0gMDsKICAgIH0KCiAgICBpZihNZW51ZUxldmVsID09IDApewogICAgCiAgICAgIC8vTW92ZSBsZWZ0IG1vdG9yCiAgICAgIGlmKEtleUNvZGVbMF0gPT0gMjcgJiYgS2V5Q29kZVsxXSA9PSA5MSAmJiBLZXlDb2RlWzJdID09IDY4ICYmIEtleUNvZGVbM10gPT0gMCAmJiBLZXlDb2RlWzRdID09IDApewogICAgICAgIGZvcihpPTA7IGk8TW92ZUxlbmd0aDsgaSsrKXsKICAgICAgICAgIE1ha2VTdGVwTGVmdCgtMSk7CiAgICAgICAgfQogICAgICAgIG1vdmVYWSgwLCAwKTsKICAgICAgfQoKICAgICAgaWYoS2V5Q29kZVswXSA9PSAyNyAmJiBLZXlDb2RlWzFdID09IDkxICYmIEtleUNvZGVbMl0gPT0gNjcgJiYgS2V5Q29kZVszXSA9PSAwICYmIEtleUNvZGVbNF0gPT0gMCl7CiAgICAgICAgZm9yKGk9MDsgaTxNb3ZlTGVuZ3RoOyBpKyspewogICAgICAgICAgTWFrZVN0ZXBMZWZ0KDEpOwogICAgICAgIH0KICAgICAgICBtb3ZlWFkoMCwgMCk7CiAgICAgIH0KCiAgICAgIC8vTW92ZSByaWdodCBtb3RvcgogICAgICBpZihLZXlDb2RlWzBdID09IDI3ICYmIEtleUNvZGVbMV0gPT0gOTEgJiYgS2V5Q29kZVsyXSA9PSA2NSAmJiBLZXlDb2RlWzNdID09IDAgJiYgS2V5Q29kZVs0XSA9PSAwKXsKICAgICAgICBmb3IoaT0wOyBpPE1vdmVMZW5ndGg7IGkrKyl7CiAgICAgICAgICBNYWtlU3RlcFJpZ2h0KC0xKTsKICAgICAgICB9CiAgICAgICAgbW92ZVhZKDAsIDApOwogICAgICB9CgogICAgICBpZihLZXlDb2RlWzBdID09IDI3ICYmIEtleUNvZGVbMV0gPT0gOTEgJiYgS2V5Q29kZVsyXSA9PSA2NiAmJiBLZXlDb2RlWzNdID09IDAgJiYgS2V5Q29kZVs0XSA9PSAwKXsKICAgICAgICBmb3IoaT0wOyBpPE1vdmVMZW5ndGg7IGkrKyl7CiAgICAgICAgICBNYWtlU3RlcFJpZ2h0KDEpOwogICAgICAgIH0KICAgICAgICBtb3ZlWFkoMCwgMCk7CiAgICAgIH0KCiAgICAgIC8vUGVuIFVQL0RPV04KICAgICAgaWYoS2V5Q29kZVswXSA9PSAyNyAmJiBLZXlDb2RlWzFdID09IDkxICYmIEtleUNvZGVbMl0gPT0gNTMgJiYgS2V5Q29kZVszXSA9PSAxMjYgJiYgS2V5Q29kZVs0XSA9PSAwKXsKICAgICAgICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgU0VSVk9VUCk7CiAgICAgICAgdXNsZWVwKDUwMDAwMCk7CiAgICAgICAgc29mdFB3bVdyaXRlKFpfU0VSVk8sIDApOwogICAgICAgIGN1cnJlbnRQbG90RG93biA9IDA7CiAgICAgIH0KCiAgICAgIGlmKEtleUNvZGVbMF0gPT0gMjcgJiYgS2V5Q29kZVsxXSA9PSA5MSAmJiBLZXlDb2RlWzJdID09IDU0ICYmIEtleUNvZGVbM10gPT0gMTI2ICYmIEtleUNvZGVbNF0gPT0gMCl7CiAgICAgICAgc29mdFB3bVdyaXRlKFpfU0VSVk8sIFNFUlZPRE9XTik7CiAgICAgICAgdXNsZWVwKDUwMDAwMCk7CiAgICAgICAgc29mdFB3bVdyaXRlKFpfU0VSVk8sIDApOwogICAgICAgIGN1cnJlbnRQbG90RG93biA9IDE7CiAgICAgIH0KCgogICAgICBpZihLZXlIaXQgPT0gJ20nKXsKICAgICAgICBNb3ZlTGVuZ3RoICo9IDEwOwogICAgICAgIGlmKE1vdmVMZW5ndGggPT0gMTAwMDApewogICAgICAgICAgTW92ZUxlbmd0aCA9IDE7CiAgICAgICAgfQogICAgICAgIFByaW50TWVudWVfMDEoRmlsZU5hbWUsIFNjYWxlLCB4TWF4IC0geE1pbiwgeU1heCAtIHlNaW4sIE1vdmVMZW5ndGgpOwogICAgICB9CgogICAgICBpZihLZXlIaXQgPT0gJ2YnKXsKICAgICAgICBGaWxlU3RhcnRSb3cgPSAwOwogICAgICAgIEZpbGVTZWxlY3RlZCA9IDA7CiAgICAgICAgc3RyY3B5KEZpbGVOYW1lT2xkLCBGaWxlTmFtZSk7CiAgICAgICAgc3RyY3B5KEZpbGVOYW1lLCBQcmludE1lbnVlXzAyKEZpbGVTdGFydFJvdywgMCkpOwogICAgICAgIE1lbnVlTGV2ZWwgPSAxOwogICAgICB9CgogICAgICBpZihLZXlIaXQgPT0gJ3MnKXsKICAgICAgICBPbGRTY2FsZSA9IFNjYWxlOwogICAgICAgIE1lc3NhZ2VUZXh0KCJUeXBlIG5ldyBzY2FsZSB2YWx1ZTogIiwgMSwgTWVzc2FnZVksIDApOwogICAgICAgIGdvdG94eSgyMywgTWVzc2FnZVkpOwogICAgICAgIHNjYW5mKCIlbGYiLCAmU2NhbGUpOwogICAgICAgIGlmKFNjYWxlID09IDApewogICAgICAgICAgU2NhbGUgPSBPbGRTY2FsZTsKICAgICAgICB9CiAgICAgICAgZWxzZXsKICAgICAgICAgIFByaW50TWVudWVfMDEoRmlsZU5hbWUsIFNjYWxlLCB4TWF4IC0geE1pbiwgeU1heCAtIHlNaW4sIE1vdmVMZW5ndGgpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgaWYoS2V5SGl0ID09ICdiJyl7CiAgICAgICAgT2xkU2NhbGUgPSBTY2FsZTsKICAgICAgICBNZXNzYWdlVGV4dCgiVHlwZSBuZXcgYm9sZCBsaW5lIHZhbHVlOiAiLCAxLCBNZXNzYWdlWSwgMCk7CiAgICAgICAgZ290b3h5KDI3LCBNZXNzYWdlWSk7CiAgICAgICAgc2NhbmYoIiVkIiwgJkJvbGRMaW5lV2lkdGgpOwogICAgICAgIEJvbGRMaW5lR2FwID0gQm9sZExpbmVXaWR0aDsKICAgICAgICBQcmludE1lbnVlXzAxKEZpbGVOYW1lLCBTY2FsZSwgeE1heCAtIHhNaW4sIHlNYXggLSB5TWluLCBNb3ZlTGVuZ3RoKTsKICAgICAgfQoKCiAgICAgIGlmKEtleUhpdCA9PSAncCcpey8vUGxvdCBmaWxlCiAgICAgICAgTWVzc2FnZVRleHQoIjMgc2Vjb25kcyB1bnRpbCBwbG90dGluZyBzdGFydHMgISEhISEhISEhISEhISEhISEiLCAxLCAyMCwgMCk7CiAgICAgICAgc2xlZXAoMyk7CiAgICAgICAgaWYoc3RyY21wKEZpbGVOYW1lLCAibm9GaUxFIikgIT0gMCl7CiAgICAgICAgICBpZigoUGxvdEZpbGU9Zm9wZW4oRnVsbEZpbGVOYW1lLCJyYiIpKT09TlVMTCl7CiAgICAgICAgICAgIHNwcmludGYoVGV4dExpbmUsICJDYW4ndCBvcGVuIGZpbGUgJyVzJyFcbiIsIEZ1bGxGaWxlTmFtZSk7CiAgICAgICAgICAgIHN0cmNweShGaWxlTmFtZSwgIk5vRmlMRSIpOwogICAgICAgICAgICBFcnJvclRleHQoVGV4dExpbmUpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZihzdHJjbXAoRmlsZU5hbWUsICJub0ZpTEUiKSAhPSAwKXsKICAgICAgICAgICAgQm9sZExpbmVYID0gMCwgQm9sZExpbmVZID0gMDsKICAgICAgICAgICAgeE5vdzEgPSAtMTsKICAgICAgICAgICAgeE5vdzIgPSAtMTsKICAgICAgICAgICAgeU5vdzEgPSAtMTsKICAgICAgICAgICAgeU5vdzIgPSAtMTsKICAgICAgICAgICAgY3VycmVudFBsb3RYID0gMDsKICAgICAgICAgICAgY3VycmVudFBsb3RZID0gMDsgICAgICAgIAogICAgICAgICAgICBQbG90U3RhcnRUaW1lID0gdGltZSgwKTsKICAgICAgICAgICAgUHJpbnRNZW51ZV8wMyhGdWxsRmlsZU5hbWUsIGNvb3JkaW5hdGVDb3VudCwgMCwgMCwgMCwgUGxvdFN0YXJ0VGltZSk7CiAgICAgICAgICAgIGNvb3JkaW5hdGVQbG90ID0gMDsKICAgICAgICAgICAgc3RvcFBsb3QgPSAwOwogICAgICAgICAgICBpZihjdXJyZW50UGxvdERvd24gPT0gMSl7CiAgICAgICAgICAgICAgc29mdFB3bVdyaXRlKFpfU0VSVk8sIFNFUlZPVVApOwogICAgICAgICAgICAgIGN1cnJlbnRQbG90RG93biA9IDA7CiAgICAgICAgICAgICAgdXNsZWVwKDUwMDAwMCk7CiAgICAgICAgICAgICAgc29mdFB3bVdyaXRlKFpfU0VSVk8sIDApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICB3aGlsZSghKGZlb2YoUGxvdEZpbGUpKSAmJiBzdG9wUGxvdCA9PSAwKXsKICAgICAgICAgICAgICAKICAgICAgICAgICAgICBmcmVhZCgmYSwgMSwgMSwgUGxvdEZpbGUpOwogICAgICAgICAgICAgIGk9MDsKICAgICAgICAgICAgICBUZXh0TGluZVswXSA9ICdcMCc7CiAgICAgICAgICAgICAgd2hpbGUoIShmZW9mKFBsb3RGaWxlKSkgJiYgYSAhPScgJyAmJiBhICE9ICc8JyAmJiBhICE9ICc+JyAmJiBhICE9ICdcIicgJiYgYSAhPSAnPScgJiYgYSAhPSAnLCcgJiYgYSAhPSAnOicgJiYgYSAhPSAxMCl7CiAgICAgICAgICAgICAgICBUZXh0TGluZVtpXSA9IGE7CiAgICAgICAgICAgICAgICBUZXh0TGluZVtpKzFdID0gJ1wwJzsKICAgICAgICAgICAgICAgIGkrKzsKICAgICAgICAgICAgICAgIGZyZWFkKCZhLCAxLCAxLCBQbG90RmlsZSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKGEgPT0gJzwnKXsvL0luaXQKICAgICAgICAgICAgICAgIGlmKHhOb3cyID4gLTEgJiYgeU5vdzIgPiAtMSAmJiAoeE5vdzIgIT0geE5vdzEgfHwgeU5vdzIgIT0geU5vdzEpKXsKICAgICAgICAgICAgICAgICAgc3RvcFBsb3QgPSBDYWxjdWxhdGVMaW5lKHhOb3cyLCB5Tm93Mik7CiAgICAgICAgICAgICAgICAgIGlmKGN1cnJlbnRQbG90RG93biA9PSAwKXsKICAgICAgICAgICAgICAgICAgICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgU0VSVk9ET1dOKTsKICAgICAgICAgICAgICAgICAgICB1c2xlZXAoNTAwMDAwKTsKICAgICAgICAgICAgICAgICAgICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgMCk7CiAgICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3REb3duID0gMTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBjdXJyZW50UGxvdFggPSB4Tm93MjsKICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3RZID0geU5vdzI7CgogICAgICAgICAgICAgICAgICBzdG9wUGxvdCA9IENhbGN1bGF0ZUxpbmUoeE5vdzEsIHlOb3cxKTsKICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3RYID0geE5vdzE7CiAgICAgICAgICAgICAgICAgIGN1cnJlbnRQbG90WSA9IHlOb3cxOwogCiAgICAgICAgICAgICAgICAgIHN0b3BQbG90ID0gQ2FsY3VsYXRlTGluZSh4Tm93LCB5Tm93KTsKICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3RYID0geE5vdzsKICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3RZID0geU5vdzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDA7CiAgICAgICAgICAgICAgICB4Tm93MSA9IC0xOwogICAgICAgICAgICAgICAgeE5vdzIgPSAtMTsKICAgICAgICAgICAgICAgIHlOb3cxID0gLTE7CiAgICAgICAgICAgICAgICB5Tm93MiA9IC0xOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZihzdHJjbXAoVGV4dExpbmUsICJwYXRoIikgPT0gMCl7CiAgICAgICAgICAgICAgICBpZihjdXJyZW50UGxvdERvd24gPT0gMSl7CiAgICAgICAgICAgICAgICAgIHNvZnRQd21Xcml0ZShaX1NFUlZPLCBTRVJWT1VQKTsKICAgICAgICAgICAgICAgICAgdXNsZWVwKDUwMDAwMCk7CiAgICAgICAgICAgICAgICAgIHNvZnRQd21Xcml0ZShaX1NFUlZPLCAwKTsKICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3REb3duID0gMDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDE7Ly9wYXRoIGZvdW5kCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSAxICYmIHN0cmNtcChUZXh0TGluZSwgImZpbGwiKSA9PSAwKXsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDI7Ly9maWxsIGZvdW5kCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSAyICYmIHN0cmNtcChUZXh0TGluZSwgIm5vbmUiKSA9PSAwKXsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDM7Ly9ub25lIGZvdW5kCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSAyICYmIHN0cmNtcChUZXh0TGluZSwgInN0cm9rZSIpID09IDApewogICAgICAgICAgICAgICAgUmVhZFN0YXRlID0gMDsvL3N0cm9rZSBmb3VuZCwgZmlsbCBpc24ndCAibm9uZSIKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYoUmVhZFN0YXRlID09IDMgJiYgc3RyY21wKFRleHRMaW5lLCAiZCIpID09IDAgJiYgYSA9PSAnPScpewogICAgICAgICAgICAgICAgUmVhZFN0YXRlID0gNDsvL2Q9IGZvdW5kCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSA0ICYmIHN0cmNtcChUZXh0TGluZSwgIk0iKSA9PSAwICYmIGEgPT0gJyAnKXsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDU7Ly9NIGZvdW5kCiAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICBpZihSZWFkU3RhdGUgPT0gNil7Ly9ZIHZhbHVlCiAgICAgICAgICAgICAgICB5Tm93ID0gKGRvdWJsZSkoc3RydG9sKFRleHRMaW5lLCAmcEVuZCwgMTApIC0geU1pbikgKiBTdGVwc1Blcm1tICogU2NhbGUgLyAxMDAuMDsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDc7CiAgICAgICAgICAgICAgICBjb29yZGluYXRlUGxvdCsrOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZihSZWFkU3RhdGUgPT0gNSAmJiBhID09ICcsJyl7Ly9YIHZhbHVlCiAgICAgICAgICAgICAgICAvL3hOb3cgPSAoKHhNYXggLSBzdHJ0b2woVGV4dExpbmUsICZwRW5kLCAxMCkpKSAqIFNjYWxlOy8vc3dhcCBYCiAgICAgICAgICAgICAgICB4Tm93ID0gKGRvdWJsZSkoc3RydG9sKFRleHRMaW5lLCAmcEVuZCwgMTApIC0geE1pbikgKiBTdGVwc1Blcm1tICogU2NhbGUgLyAxMDAuMDsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDY7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSA3KXsKICAgICAgICAgICAgICAgIGlmKHhOb3cyID4gLTEgJiYgeU5vdzIgPiAtMSAmJiAoeE5vdzIgIT0geE5vdzEgfHwgeU5vdzIgIT0geU5vdzEpKXsKICAgICAgICAgICAgICAgICAgc3RvcFBsb3QgPSBDYWxjdWxhdGVMaW5lKHhOb3cyLCB5Tm93Mik7CiAgICAgICAgICAgICAgICAgIGlmKGN1cnJlbnRQbG90RG93biA9PSAwKXsKICAgICAgICAgICAgICAgICAgICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgU0VSVk9ET1dOKTsKICAgICAgICAgICAgICAgICAgICB1c2xlZXAoNTAwMDAwKTsKICAgICAgICAgICAgICAgICAgICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgMCk7CiAgICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3REb3duID0gMTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBjdXJyZW50UGxvdFggPSB4Tm93MjsKICAgICAgICAgICAgICAgICAgY3VycmVudFBsb3RZID0geU5vdzI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB4Tm93MiA9IHhOb3cxOwogICAgICAgICAgICAgICAgeU5vdzIgPSB5Tm93MTsKICAgICAgICAgICAgICAgIHhOb3cxID0geE5vdzsKICAgICAgICAgICAgICAgIHlOb3cxID0geU5vdzsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIC8vUHJpbnRNZW51ZV8wMyhGdWxsRmlsZU5hbWUsIGNvb3JkaW5hdGVDb3VudCwgY29vcmRpbmF0ZVBsb3QsIDAsIDAsIFBsb3RTdGFydFRpbWUpOwogICAgICAgICAgICB9Ly93aGlsZSghKGZlb2YoUGxvdEZpbGUpKSAmJiBzdG9wUGxvdCA9PSAwKXsKICAgICAgICAgICAgZmNsb3NlKFBsb3RGaWxlKTsKICAgICAgICAgICAgaWYoY3VycmVudFBsb3REb3duID09IDEpewogICAgICAgICAgICAgIHNvZnRQd21Xcml0ZShaX1NFUlZPLCBTRVJWT1VQKTsKICAgICAgICAgICAgICB1c2xlZXAoNTAwMDAwKTsKICAgICAgICAgICAgICBzb2Z0UHdtV3JpdGUoWl9TRVJWTywgMCk7CiAgICAgICAgICAgICAgY3VycmVudFBsb3REb3duID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBQcmludE1lbnVlXzAzKEZ1bGxGaWxlTmFtZSwgY29vcmRpbmF0ZUNvdW50LCBjb29yZGluYXRlUGxvdCwgMCwgMCwgUGxvdFN0YXJ0VGltZSk7CiAgICAgICAgICAgIENhbGN1bGF0ZUxpbmUoMCwgMCk7CiAgICAgICAgICAgIGN1cnJlbnRQbG90WCA9IDA7CiAgICAgICAgICAgIGN1cnJlbnRQbG90WSA9IDA7CiAgICAgICAgICAgIHdoaWxlKGtiaGl0KCkpewogICAgICAgICAgICAgIGdldGNoKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgTWVzc2FnZVRleHQoIkZpbmlzaGVkISBQcmVzcyBhbnkga2V5IHRvIHJldHVybiB0byBtYWluIG1lbnUuIiwgTWVzc2FnZVgsIE1lc3NhZ2VZLCAwKTsKICAgICAgICAgICAgZ2V0Y2goKTsKICAgICAgICAgICAgUHJpbnRNZW51ZV8wMShGaWxlTmFtZSwgU2NhbGUsIHhNYXggLSB4TWluLCB5TWF4IC0geU1pbiwgTW92ZUxlbmd0aCk7CiAgICAgICAgfS8vaWYoc3RyY21wKEZpbGVOYW1lLCAibm9GaUxFIikgIT0gMCl7CiAgICAgIH0vL2lmKEtleUhpdCA9PSAncCcpewoKCgoKICAgIH0vL2lmKE1lbnVlTGV2ZWwgPT0gMCl7CgogICAgaWYoTWVudWVMZXZlbCA9PSAxKXsvL1NlbGVjdCBmaWxlCgogICAgICBpZihLZXlDb2RlWzBdID09IDI3ICYmIEtleUNvZGVbMV0gPT0gOTEgJiYgS2V5Q29kZVsyXSA9PSA2NiAmJiBLZXlDb2RlWzNdID09IDAgJiYgS2V5Q29kZVs0XSA9PSAwKXsKICAgICAgICBpZihGaWxlU2VsZWN0ZWQgPCBGaWxlc0ZvdW5kIC0gMSl7CiAgICAgICAgICBGaWxlU2VsZWN0ZWQrKzsKICAgICAgICAgIGlmKEZpbGVTZWxlY3RlZCA+IE1heEZpbGVSb3dzIC0gMil7CiAgICAgICAgICAgIEZpbGVTdGFydFJvdyA9IEZpbGVTZWxlY3RlZCAtIE1heEZpbGVSb3dzICsgMjsKICAgICAgICAgIH0KICAgICAgICAgIHN0cmNweShGaWxlTmFtZSwgUHJpbnRNZW51ZV8wMihGaWxlU3RhcnRSb3csIEZpbGVTZWxlY3RlZCkpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgaWYoS2V5Q29kZVswXSA9PSAyNyAmJiBLZXlDb2RlWzFdID09IDkxICYmIEtleUNvZGVbMl0gPT0gNjUgJiYgS2V5Q29kZVszXSA9PSAwICYmIEtleUNvZGVbNF0gPT0gMCl7CiAgICAgICAgaWYoRmlsZVNlbGVjdGVkID4gMCl7CiAgICAgICAgICBpZihGaWxlU2VsZWN0ZWQgPT0gRmlsZVN0YXJ0Um93ICsgMSl7CiAgICAgICAgICAgIGlmKEZpbGVTdGFydFJvdyA+IDApewogICAgICAgICAgICAgIEZpbGVTdGFydFJvdy0tOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBGaWxlU2VsZWN0ZWQtLTsKICAgICAgICAgIHN0cmNweShGaWxlTmFtZSwgUHJpbnRNZW51ZV8wMihGaWxlU3RhcnRSb3csIEZpbGVTZWxlY3RlZCkpOwogICAgICAgIH0KICAgICAgfQoKICAgICAgaWYoS2V5SGl0ID09IDEwKXsvL1JlYWQgZmlsZSBhbmQgc3RvcmUgdmFsdWVzCiAgICAgICAgTWVudWVMZXZlbCA9IDA7CiAgICAgICAgY2xyc2NyKE1lc3NhZ2VZICsgMSwgTWVzc2FnZVkgKyAxKTsKICAgICAgICBzdHJjcHkoRnVsbEZpbGVOYW1lLCBQaWN0dXJlUGF0aCk7CiAgICAgICAgc3RyY2F0KEZ1bGxGaWxlTmFtZSwgIi8iKTsKICAgICAgICBzdHJjYXQoRnVsbEZpbGVOYW1lLCBGaWxlTmFtZSk7CiAgICAgICAgaWYoKFBsb3RGaWxlPWZvcGVuKEZ1bGxGaWxlTmFtZSwicmIiKSk9PU5VTEwpewogICAgICAgICAgc3ByaW50ZihUZXh0TGluZSwgIkNhbid0IG9wZW4gZmlsZSAnJXMnIVxuIiwgRnVsbEZpbGVOYW1lKTsKICAgICAgICAgIEVycm9yVGV4dChUZXh0TGluZSk7CiAgICAgICAgICBzdHJjcHkoRmlsZU5hbWUsICJOb0ZpTEUiKTsKICAgICAgICB9CiAgICAgICAgZWxzZXsKICAgICAgICAgIHhNaW49MTAwMDAwMDsKICAgICAgICAgIHhNYXg9LTEwMDAwMDA7CiAgICAgICAgICB5TWluPTEwMDAwMDA7CiAgICAgICAgICB5TWF4PS0xMDAwMDAwOwogICAgICAgICAgY29vcmRpbmF0ZUNvdW50ID0gMDsKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICB3aGlsZSghKGZlb2YoUGxvdEZpbGUpKSAmJiBzdG9wUGxvdCA9PSAwKXsKICAgICAgICAgICAgICAKICAgICAgICAgICAgICBmcmVhZCgmYSwgMSwgMSwgUGxvdEZpbGUpOwogICAgICAgICAgICAgIGk9MDsKICAgICAgICAgICAgICBUZXh0TGluZVswXSA9ICdcMCc7CiAgICAgICAgICAgICAgd2hpbGUoIShmZW9mKFBsb3RGaWxlKSkgJiYgYSAhPScgJyAmJiBhICE9ICc8JyAmJiBhICE9ICc+JyAmJiBhICE9ICdcIicgJiYgYSAhPSAnPScgJiYgYSAhPSAnLCcgJiYgYSAhPSAnOicgJiYgYSAhPSAxMCl7CiAgICAgICAgICAgICAgICBUZXh0TGluZVtpXSA9IGE7CiAgICAgICAgICAgICAgICBUZXh0TGluZVtpKzFdID0gJ1wwJzsKICAgICAgICAgICAgICAgIGkrKzsKICAgICAgICAgICAgICAgIGZyZWFkKCZhLCAxLCAxLCBQbG90RmlsZSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKGEgPT0gJzwnKXsvL0luaXQKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDA7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKHN0cmNtcChUZXh0TGluZSwgInBhdGgiKSA9PSAwKXsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDE7Ly9wYXRoIGZvdW5kCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSAxICYmIHN0cmNtcChUZXh0TGluZSwgImZpbGwiKSA9PSAwKXsKICAgICAgICAgICAgICAgIC8vUmVhZFN0YXRlID0gMjsvL2ZpbGwgZm91bmQKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDM7Ly9wYXRocyB3aXRob3V0IGxpbmUgYXJlIGFsc28gY29uc2lkZXJlZCB3aGVuIGNhbGN1bGF0aW5nIG1heCB2YWx1ZXMKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYoUmVhZFN0YXRlID09IDIgJiYgc3RyY21wKFRleHRMaW5lLCAibm9uZSIpID09IDApewogICAgICAgICAgICAgICAgUmVhZFN0YXRlID0gMzsvL25vbmUgZm91bmQKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYoUmVhZFN0YXRlID09IDIgJiYgc3RyY21wKFRleHRMaW5lLCAic3Ryb2tlIikgPT0gMCl7CiAgICAgICAgICAgICAgICBSZWFkU3RhdGUgPSAwOy8vc3Ryb2tlIGZvdW5kLCBmaWxsIGlzbid0ICJub25lIgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZihSZWFkU3RhdGUgPT0gMyAmJiBzdHJjbXAoVGV4dExpbmUsICJkIikgPT0gMCAmJiBhID09ICc9Jyl7CiAgICAgICAgICAgICAgICBSZWFkU3RhdGUgPSA0Oy8vZD0gZm91bmQKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYoUmVhZFN0YXRlID09IDQgJiYgc3RyY21wKFRleHRMaW5lLCAiTSIpID09IDAgJiYgYSA9PSAnICcpewogICAgICAgICAgICAgICAgUmVhZFN0YXRlID0gNTsvL00gZm91bmQKICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgIGlmKFJlYWRTdGF0ZSA9PSA1ICYmIHN0cmNtcChUZXh0TGluZSwgIkMiKSA9PSAwICYmIGEgPT0gJyAnKXsKICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDU7Ly9DIGZvdW5kCiAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICBpZihSZWFkU3RhdGUgPT0gNil7Ly9ZIHZhbHVlCiAgICAgICAgICAgICAgICB5Tm93ID0gc3RydG9sKFRleHRMaW5lLCAmcEVuZCwgMTApOwogICAgICAgICAgICAgICAgLy9wcmludGYoIlN0cmluZz0nJXMnIHk9JWxkXG4iLCBUZXh0TGluZSwgeU5vdyk7CiAgICAgICAgICAgICAgICBpZih5Tm93ID4geU1heCl7CiAgICAgICAgICAgICAgICAgIHlNYXggPSB5Tm93OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYoeU5vdyA8IHlNaW4pewogICAgICAgICAgICAgICAgICB5TWluID0geU5vdzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIFJlYWRTdGF0ZSA9IDc7CiAgICAgICAgICAgICAgICBjb29yZGluYXRlQ291bnQrKzsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYoUmVhZFN0YXRlID09IDUgJiYgYSA9PSAnLCcpey8vWCB2YWx1ZQogICAgICAgICAgICAgICAgeE5vdyA9IHN0cnRvbChUZXh0TGluZSwgJnBFbmQsIDEwKTsKICAgICAgICAgICAgICAgIGlmKHhOb3cgPiB4TWF4KXsKICAgICAgICAgICAgICAgICAgeE1heCA9IHhOb3c7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZih4Tm93IDwgeE1pbil7CiAgICAgICAgICAgICAgICAgIHhNaW4gPSB4Tm93OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgUmVhZFN0YXRlID0gNjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYoUmVhZFN0YXRlID09IDcpeyAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAvL3ByaW50ZigiRm91bmQgY29vcmRpbmF0ZXMgJWxkLCAlbGRcbiIsIHhOb3csIHlOb3cpOwogICAgICAgICAgICAgICAgUmVhZFN0YXRlID0gNTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZ290b3h5KDEsIE1lc3NhZ2VZKTtwcmludGYoIlJlYWRTdGF0ZT0lIDNkLCB4Tm93PSUgMTBsZCwgeE1pbj0lIDEwbGQsIHhNYXg9JSAxMGxkLCB5TWluPSUgMTBsZCwgeU1heD0lIDEwbGQgICAiLCBSZWFkU3RhdGUsIHhOb3csIHhNaW4sIHhNYXgsIHlNaW4sIHlNYXgpOwoKICAgICAgICAgICAgfS8vd2hpbGUoIShmZW9mKFBsb3RGaWxlKSkgJiYgc3RvcFBsb3QgPT0gMCl7CiAgICAgICAgICAgIGZjbG9zZShQbG90RmlsZSk7CiAgICAgICAgICAgIFNjYWxlID0gMS4wOwogICAgICAgIH0KICAgICAgICBQcmludE1lbnVlXzAxKEZpbGVOYW1lLCBTY2FsZSwgeE1heCAtIHhNaW4sIHlNYXggLSB5TWluLCBNb3ZlTGVuZ3RoKTsKICAgICAgfS8vaWYoS2V5SGl0ID09IDEwKXsKICAgIAogICAgfS8vaWYoTWVudWVMZXZlbCA9PSAxKXsKICAgIAogICAgICAgIAogICAgaWYoS2V5SGl0ID09IDI3KXsKICAgICAgaWYoTWVudWVMZXZlbCA9PSAwKXsKICAgICAgICBjbHJzY3IoTWVzc2FnZVkgKyAxLCBNZXNzYWdlWSArIDEpOwogICAgICAgIE1lc3NhZ2VUZXh0KCJFeGl0IHByb2dyYW0gKHkvbik/IiwgTWVzc2FnZVgsIE1lc3NhZ2VZICsgMSwgMCk7CiAgICAgICAgd2hpbGUoS2V5SGl0ICE9ICd5JyAmJiBLZXlIaXQgIT0gJ24nKXsKICAgICAgICAgIEtleUhpdCA9IGdldGNoKCk7CiAgICAgICAgICBpZihLZXlIaXQgPT0gJ3knKXsKICAgICAgICAgICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAxLCAwKTsKICAgICAgICAgICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAyLCAwKTsKICAgICAgICAgICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjAzLCAwKTsKICAgICAgICAgICAgZGlnaXRhbFdyaXRlKExFRlRfU1RFUFBFUjA0LCAwKTsKCiAgICAgICAgICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDEsIDApOwogICAgICAgICAgICBkaWdpdGFsV3JpdGUoUklHSFRfU1RFUFBFUjAyLCAwKTsKICAgICAgICAgICAgZGlnaXRhbFdyaXRlKFJJR0hUX1NURVBQRVIwMywgMCk7CiAgICAgICAgICAgIGRpZ2l0YWxXcml0ZShSSUdIVF9TVEVQUEVSMDQsIDApOwogICAgICAgICAgICBleGl0KDApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICBpZihNZW51ZUxldmVsID09IDEpewogICAgICAgIE1lbnVlTGV2ZWwgPSAwOwogICAgICAgIHN0cmNweShGaWxlTmFtZSwgRmlsZU5hbWVPbGQpOwogICAgICAgIFByaW50TWVudWVfMDEoRmlsZU5hbWUsIFNjYWxlLCB4TWF4IC0geE1pbiwgeU1heCAtIHlNaW4sIE1vdmVMZW5ndGgpOwogICAgICB9CiAgICAgIGNscnNjcihNZXNzYWdlWSArIDEsIE1lc3NhZ2VZICsgMSk7CiAgICB9CiAgfQoKICByZXR1cm4gMDsKfQoKCg==