#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
//midi event types
enum {
NOTE_OFF = 0x8 ,
NOTE_ON = 0x9 ,
NOTE_AFTERTOUCH = 0xA ,
CONTROLLER = 0xB ,
PROGRAM_CHANGE = 0xC ,
PROGRAM_AFTERTOUCH = 0xD ,
PITCH_BEND = 0xE ,
} ;
//meta event types
enum {
SEQUENCE_NUMBER = 0x00 ,
TEXT = 0x01 ,
COPYRIGHT_NOTICE = 0x02 ,
SEQUENCE_TRACK_NAME = 0x03 ,
INSTRUMENT_NAME = 0x04 ,
LYRICS = 0x05 ,
MARKER = 0x06 ,
CUE_POINT = 0x07 ,
//UNKNOWN_TEXT = 0x09;
MIDI_CHANNEL_PREFIX = 0x20 ,
END_OF_TRACK = 0x2F ,
SET_TEMPO = 0x51 ,
SMPTE_OFFSET = 0x54 ,
TIME_SIGNATURE = 0x58 ,
KEY_SIGNATURE = 0x59 ,
SEQUENCE_SPECIFIC = 0x7F ,
} ;
//system exclusive events
/*enum{
NORMAL = 0xF0;
DIVIDED = 0xF0;
DIVIDED = 0xF7;
};*/
typedef struct _MthdCD{
uint16_t format;
uint16_t tracks_count;
uint16_t time_division;
uint8_t time_divisionType;
} _MthdCD;
typedef struct _metaEventStruct{
uint8_t type;
uint64_t length;
uint8_t * data;
} _metaEventStruct;
typedef struct _midiEventStruct{
uint8_t type;
uint8_t channel;
uint8_t param1, param2;
} _midiEventStruct;
typedef struct _sysExEventStruct{
uint64_t length;
uint8_t * data;
} _sysExEventStruct;
typedef struct _MtrkCD{
uint32_t byteCount;
uint64_t elementCount;
uint64_t * deltaTime;
uint8_t * eventType;
_metaEventStruct * metaEventValues;
_midiEventStruct * midiEventValues;
_sysExEventStruct * sysExEventValues;
} _MtrkCD;
uint64_t _ReadVariableLength( FILE * file, int * l) ;
uint8_t _ReadByte( FILE * file) ;
uint16_t _ReadByte2( FILE * file) ;
uint32_t _ReadByte4( FILE * file) ;
uint8_t _firstBits4( int byte) ;
uint8_t _lastBits4( int byte) ;
uint8_t _firstByte( int bytes) ;
uint8_t _lastByte( int bytes) ;
int _ReadMthdChunk( FILE * file, _MthdCD * MthdChunkData, int print) ;
int _ReadMtrkChunk( FILE * file, _MtrkCD * MtrkChunkData, int trackID, int print) ;
int _ParseMidi( char * fileName, int print, int save) ;
uint64_t _ReadVariableLength( FILE * file, int * l) {
* l= 0 ;
uint64_t totalVal = 0 ;
uint8_t curVal= 0 , copyVal= 0 ;
do {
copyVal = curVal = _ReadByte( file) ;
copyVal &= ~( 1 << 7 ) ;
totalVal = ( totalVal << 7 ) + copyVal;
( * l) ++;
} while ( curVal& ( 1 << 7 ) ) ;
return totalVal;
}
uint8_t _ReadByte( FILE * file) {
}
uint16_t _ReadByte2( FILE * file) {
uint16_t res
= fgetc ( file
) ; res
= ( res
<< 8 ) + fgetc ( file
) ; return res;
}
uint32_t _ReadByte4( FILE * file) {
uint32_t res
= fgetc ( file
) ; res
= ( res
<< 8 ) + fgetc ( file
) ; res
= ( res
<< 8 ) + fgetc ( file
) ; res
= ( res
<< 8 ) + fgetc ( file
) ; return res;
}
uint8_t _firstBits4( int byte) {
return ( byte>> 4 ) ;
}
uint8_t _lastBits4( int byte) {
return byte- ( ( byte>> 4 ) << 4 ) ;
}
uint8_t _firstByte( int bytes) {
return ( bytes>> 8 ) ;
}
uint8_t _lastByte( int bytes) {
return bytes- ( ( bytes>> 8 ) << 8 ) ;
}
int _ReadMthdChunk( FILE * file, _MthdCD * MthdChunkData, int print) {
uint32_t chkName = _ReadByte4( file) ;
if ( chkName != 0x4D546864 ) {
return 0 ;
}
uint32_t chkLength = _ReadByte4( file) ;
if ( chkLength != 0x00000006 ) {
return 0 ;
}
MthdChunkData-> format = _ReadByte2( file) ;
MthdChunkData-> tracks_count = _ReadByte2( file) ;
MthdChunkData-> time_division = _ReadByte2( file) ;
if ( MthdChunkData-> time_divisionType & ( 1 << 16 ) ) {
MthdChunkData-> time_divisionType = 1 ;
}
else {
MthdChunkData-> time_divisionType = 0 ;
}
if ( print) {
printf ( "\n \n \n --------------------------------------------------------------------------------\n Parsed MThd:\n \n " ) ; printf ( "Chunk Name: %26s%c%c%c%c\n " , "" , ( char ) ( chkName
>> 24 ) , ( char ) ( ( chkName
>> 16 ) % 0x100 ) , ( char ) ( ( chkName
>> 8 ) % 0x100 ) , ( char ) ( ( chkName
) % 0x100 ) ) ; printf ( "Chunk Size: %24d bytes\n \n " , chkLength
) ; char str[ 25 ] ;
switch ( MthdChunkData-> format) {
case 0x00000000 :
break ;
case 0x00000001 :
break ;
case 0x00000002 :
break ;
default :
return 0 ;
}
printf ( "Midi Format: %29s\n " , str
) ; printf ( "Number of Tracks: %24d\n " , MthdChunkData
-> tracks_count
) ; switch ( MthdChunkData-> time_divisionType) {
case 0x00 :
strcpy ( str
, "Ticks per Quarter Note" ) ; break ;
case 0x01 :
strcpy ( str
, "Frames per Second" ) ; break ;
default :
return 0 ;
}
printf ( "Time Division Type: %22s\n Time Division Value: %21d\n " , str
, MthdChunkData
-> time_division
) ; }
return 1 ;
}
int _ReadMtrkChunk( FILE * file, _MtrkCD * MtrkChunkData, int trackID, int print) {
//static int trackID = 0;
int i, j;
uint32_t chkName = _ReadByte4( file) ;
if ( chkName != 0x4D54726B ) {
return 0 ;
}
MtrkChunkData-> byteCount = _ReadByte4( file) ;
uint32_t parsedLength = MtrkChunkData-> byteCount;
uint8_t midiEventType;
uint8_t midiChannel;
int l= 0 ;
MtrkChunkData-> elementCount= 0 ;
MtrkChunkData
-> deltaTime
= ( uint64_t * ) ( malloc ( sizeof ( uint64_t ) ) ) ; MtrkChunkData
-> eventType
= ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) ) ) ; MtrkChunkData
-> metaEventValues
= ( _metaEventStruct
* ) ( malloc ( sizeof ( _metaEventStruct
) ) ) ; MtrkChunkData
-> midiEventValues
= ( _midiEventStruct
* ) ( malloc ( sizeof ( _midiEventStruct
) ) ) ; MtrkChunkData
-> sysExEventValues
= ( _sysExEventStruct
* ) ( malloc ( sizeof ( _sysExEventStruct
) ) ) ;
while ( parsedLength > 0 ) {
MtrkChunkData
-> deltaTime
= ( realloc ( MtrkChunkData
-> deltaTime
, sizeof ( uint64_t ) * ( MtrkChunkData
-> elementCount
+ 1 ) ) ) ; MtrkChunkData
-> eventType
= ( realloc ( MtrkChunkData
-> eventType
, sizeof ( uint8_t ) * ( MtrkChunkData
-> elementCount
+ 1 ) ) ) ; MtrkChunkData
-> metaEventValues
= ( realloc ( MtrkChunkData
-> metaEventValues
, sizeof ( _metaEventStruct
) * ( MtrkChunkData
-> elementCount
+ 1 ) ) ) ; MtrkChunkData
-> midiEventValues
= ( realloc ( MtrkChunkData
-> midiEventValues
, sizeof ( _midiEventStruct
) * ( MtrkChunkData
-> elementCount
+ 1 ) ) ) ; MtrkChunkData
-> sysExEventValues
= ( realloc ( MtrkChunkData
-> sysExEventValues
, sizeof ( _sysExEventStruct
) * ( MtrkChunkData
-> elementCount
+ 1 ) ) ) ;
//getch();
//printf("looped... toBeParsedLength is %d \n",parsedLength);
( ( MtrkChunkData-> deltaTime) [ MtrkChunkData-> elementCount] ) = _ReadVariableLength( file,& l) ;
//printf("Variable length: %d\n",MtrkChunkData->deltaTime);
parsedLength-= l;
uint8_t nByte = _ReadByte( file) ;
//printf("nByte: 0x%X\n",nByte);
parsedLength-= 1 ;
//check nByte for event type
switch ( nByte) {
//meta event case
case 0xFF :
( ( MtrkChunkData-> eventType) [ MtrkChunkData-> elementCount] ) = 1 ;
//printf("Found META event\n");
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .type = _ReadByte( file) ;
//printf("Meta event 0x%X\n",metaEventType);
parsedLength-= 1 ;
switch ( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .type ) {
//might seem trivial to seperate types since all is scanned the same way but it is actually needed for separating conversion and track combination
case SEQUENCE_NUMBER:
case KEY_SIGNATURE:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadByte( file) ;
parsedLength-= 1 ;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
case SEQUENCE_SPECIFIC:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
case TEXT:
case COPYRIGHT_NOTICE:
case SEQUENCE_TRACK_NAME:
case INSTRUMENT_NAME:
case LYRICS:
case MARKER:
case CUE_POINT:
case 0x09 : //unknown text event
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = '\0 ' ;
break ;
case MIDI_CHANNEL_PREFIX:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
case SET_TEMPO:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
case SMPTE_OFFSET:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
case TIME_SIGNATURE:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
case END_OF_TRACK:
( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> metaEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> metaEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
default :
return 0 ;
}
break ;
//system exclusive event case
case 0xF0 :
case 0xF7 :
( ( MtrkChunkData-> eventType) [ MtrkChunkData-> elementCount] ) = 2 ;
//printf("Found System Exclusive event\n");
( ( MtrkChunkData-> sysExEventValues) [ MtrkChunkData-> elementCount] ) .length = _ReadVariableLength( file,& l) ;
parsedLength-= l;
( ( MtrkChunkData
-> sysExEventValues
) [ MtrkChunkData
-> elementCount
] ) .
data = ( uint8_t * ) ( malloc ( sizeof ( uint8_t ) * ( ( MtrkChunkData
-> sysExEventValues
) [ MtrkChunkData
-> elementCount
] ) .
length ) ) ; for ( i= 0 ; i< ( ( MtrkChunkData-> sysExEventValues) [ MtrkChunkData-> elementCount] ) .length ; i++ ) {
( ( ( MtrkChunkData-> sysExEventValues) [ MtrkChunkData-> elementCount] ) .data ) [ i] = _ReadByte( file) ;
parsedLength-= 1 ;
}
break ;
//midi event case
default :
( ( MtrkChunkData-> eventType) [ MtrkChunkData-> elementCount] ) = 0 ;
//printf("Found MIDI event\n");
midiEventType = _firstBits4( nByte) ;
midiChannel = _lastBits4( nByte) ;
//printf("MIDI event type: 0x%X\n",midiEventType);
switch ( midiEventType) {
case NOTE_OFF:
case NOTE_ON:
case NOTE_AFTERTOUCH:
case CONTROLLER:
case PITCH_BEND:
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] ) .type = midiEventType;
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] ) .channel = midiChannel;
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] ) .param1 = _ReadByte( file) ;
parsedLength-= 1 ;
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] .param2 ) = _ReadByte( file) ;
parsedLength-= 1 ;
break ;
case PROGRAM_CHANGE:
case PROGRAM_AFTERTOUCH:
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] ) .type = midiEventType;
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] ) .channel = midiChannel;
( ( MtrkChunkData-> midiEventValues) [ MtrkChunkData-> elementCount] ) .param1 = _ReadByte( file) ;
parsedLength-= 1 ;
break ;
default :
return 0 ;
}
break ;
}
( MtrkChunkData-> elementCount) ++;
}
if ( print) {
printf ( "\n \n \n --------------------------------------------------------------------------------\n " ) ; printf ( "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n " ) ; printf ( "--------------------------------------------------------------------------------\n Parsed MTrk[%d]:\n \n " , trackID
) ; printf ( "Chunk Name: %26s%c%c%c%c\n " , "" , ( char ) ( chkName
>> 24 ) , ( char ) ( ( chkName
>> 16 ) % 0x100 ) , ( char ) ( ( chkName
>> 8 ) % 0x100 ) , ( char ) ( ( chkName
) % 0x100 ) ) ; printf ( "Chunk Size: %24d bytes\n " , MtrkChunkData
-> byteCount
) ; printf ( "Number of Events: %24d\n " , MtrkChunkData
-> elementCount
) ; char str[ 40 ] = { '\0 ' } ;
for ( i= 0 ; i< MtrkChunkData-> elementCount; i++ ) {
printf ( "\n Delta Time Value: %18d ticks\n " , MtrkChunkData
-> deltaTime
[ i
] ) ; switch ( MtrkChunkData-> eventType[ i] ) {
case 2 :
strcpy ( str
, "System Exclusive Event" ) ; break ;
case 1 :
break ;
case 0 :
break ;
}
printf ( "Event Type: %30s\n " , str
) ; if ( MtrkChunkData-> eventType[ i] == 1 ) {
switch ( MtrkChunkData-> metaEventValues[ i] .type ) {
case SEQUENCE_NUMBER:
strcpy ( str
, "Sequence Number Event" ) ; break ;
case TEXT:
break ;
case COPYRIGHT_NOTICE:
strcpy ( str
, "Copyright Notice Event" ) ; break ;
case SEQUENCE_TRACK_NAME:
strcpy ( str
, "Sequence / Track Name Event" ) ; break ;
case INSTRUMENT_NAME:
strcpy ( str
, "Instrument Name Event" ) ; break ;
case LYRICS:
break ;
case MARKER:
break ;
case CUE_POINT:
strcpy ( str
, "Cue Point Event" ) ; break ;
case 0x09 :
strcpy ( str
, "Unknown Text Type Event" ) ; break ;
case MIDI_CHANNEL_PREFIX:
strcpy ( str
, "MIDI Channel Prefix Event" ) ; break ;
case END_OF_TRACK:
strcpy ( str
, "End of Track Event" ) ; break ;
case SET_TEMPO:
strcpy ( str
, "Set Tempo Event" ) ; break ;
case SMPTE_OFFSET:
strcpy ( str
, "SMPTE Offset Event" ) ; break ;
case TIME_SIGNATURE:
strcpy ( str
, "Time Signature Event" ) ; break ;
case KEY_SIGNATURE:
strcpy ( str
, "Key Signature Event" ) ; break ;
case SEQUENCE_SPECIFIC:
strcpy ( str
, "Sequencer Specific Event" ) ; break ;
default :
}
printf ( "Event Sub-Type: %26s\n " , str
) ; switch ( MtrkChunkData-> metaEventValues[ i] .type ) {
case SEQUENCE_NUMBER:
printf ( "Event Parameters:\n " ) ; printf ( "Value: %0x04X\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] << 8 + MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] ) ; break ;
case TEXT:
case COPYRIGHT_NOTICE:
case SEQUENCE_TRACK_NAME:
case INSTRUMENT_NAME:
case LYRICS:
case MARKER:
case CUE_POINT:
case 0x09 :
printf ( "Event Parameters:\n " ) ; printf ( "%s\n " , ( char * ) MtrkChunkData
-> metaEventValues
[ i
] .
data ) ; break ;
case MIDI_CHANNEL_PREFIX:
printf ( "Event Parameters:\n " ) ; printf ( "Channel: %d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] ) ; break ;
case SET_TEMPO:
printf ( "Event Parameters:\n " ) ; printf ( "Value: %8u Microseconds per Quarter Note\n " , ( MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] << 16 ) + ( MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] << 8 ) + MtrkChunkData
-> metaEventValues
[ i
] .
data [ 2 ] ) ; break ;
case SMPTE_OFFSET:
printf ( "Event Parameters:\n " ) ; printf ( "Hour: %-2d Min: %-2d Sec: %-2d Frames: %-2d Sub-Frames: %-2d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 2 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 3 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 4 ] ) ; break ;
case TIME_SIGNATURE:
printf ( "Event Parameters:\n " ) ; printf ( "Numerator: %-3d Denominator: %-3d Metronome: %-3d 1/32: %-3d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 2 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 3 ] ) ; break ;
case KEY_SIGNATURE:
printf ( "Event Parameters:\n " ) ; printf ( "Key: %+2d Scale: %d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] ) ; break ;
default :
break ;
}
}
else if ( MtrkChunkData-> eventType[ i] == 2 ) {
printf ( "Event Parameters:\n Value: 0x" ) ; for ( j= 0 ; j< MtrkChunkData-> sysExEventValues[ i] .length ; j++ ) {
printf ( "%02X" , MtrkChunkData
-> sysExEventValues
[ i
] .
data [ j
] ) ; }
}
else {
switch ( MtrkChunkData-> midiEventValues[ i] .type ) {
case NOTE_OFF:
break ;
case NOTE_ON:
break ;
case NOTE_AFTERTOUCH:
strcpy ( str
, "Note Aftertouch Event" ) ; break ;
case CONTROLLER:
strcpy ( str
, "Controller Event" ) ; break ;
case PROGRAM_CHANGE:
strcpy ( str
, "Program Change Event" ) ; break ;
case PROGRAM_AFTERTOUCH:
strcpy ( str
, "Program Aftertouch Event" ) ; break ;
case PITCH_BEND:
strcpy ( str
, "Pitch Bend Event" ) ; break ;
default :
}
printf ( "Event Sub-Type: %26s\n " , str
) ; switch ( MtrkChunkData-> midiEventValues[ i] .type ) {
case NOTE_OFF:
case NOTE_ON:
printf ( "Event Parameters:\n " ) ; printf ( "Note Number: %d Note Velocity: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 , MtrkChunkData
-> midiEventValues
[ i
] .
param2 ) ; break ;
case NOTE_AFTERTOUCH:
printf ( "Event Parameters:\n " ) ; printf ( "Note Number: %d Aftertouch Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 , MtrkChunkData
-> midiEventValues
[ i
] .
param2 ) ; break ;
case CONTROLLER:
printf ( "Event Parameters:\n " ) ; printf ( "Controller Number: %d Controller Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 , MtrkChunkData
-> midiEventValues
[ i
] .
param2 ) ; break ;
case PROGRAM_CHANGE:
printf ( "Event Parameters:\n " ) ; printf ( "Program Number: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 ) ; break ;
case PROGRAM_AFTERTOUCH:
printf ( "Event Parameters:\n " ) ; printf ( "Aftertouch Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 ) ; break ;
case PITCH_BEND:
printf ( "Event Parameters:\n " ) ; printf ( "Pitch Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 + ( MtrkChunkData
-> midiEventValues
[ i
] .
param2 >> 8 ) ) ; break ;
default :
break ;
}
}
printf ( "Press ANY key to continue...\n " ) ; }
}
return 1 ;
}
int _ParseMidi( char * fileName, int print, int save) {
FILE * midiFile;
_MthdCD
* MthdData
= ( _MthdCD
* ) ( malloc ( sizeof ( _MthdCD
) ) ) ; midiFile
= fopen ( fileName
, "rb" ) ; if ( midiFile == NULL) {
printf ( "Failed to open the file. Are you sure the file exists?\n " ) ; return 0 ;
}
if ( ! _ReadMthdChunk( midiFile, MthdData, print) ) {
printf ( "Error reading MThd Chunk. Bad MThd.\n " ) ; return 0 ;
}
_MtrkCD
** MtrkDatas
= ( _MtrkCD
** ) ( malloc ( sizeof ( _MtrkCD
* ) ) ) ; uint64_t i, j, k, p;
for ( p= 0 ; p< MthdData-> tracks_count; p++ ) {
MtrkDatas
[ p
] = ( _MtrkCD
* ) ( malloc ( sizeof ( _MtrkCD
) ) ) ; if ( ! _ReadMtrkChunk( midiFile, MtrkDatas[ p] , p, print) ) {
printf ( "Error reading MTrk Chunk. Bad MTrk.\n " ) ; return 0 ;
}
}
if ( save) {
char saveFileName[ 40 ] ;
strcpy ( saveFileName
, fileName
) ; FILE * saveFile;
//printf("saveFileName: %s.",saveFileName);
saveFile
= fopen ( saveFileName
, "w" ) ; if ( saveFile == NULL) {
printf ( "Failed to open save file.\n " ) ; return 0 ;
}
fprintf ( saveFile
, "\n \n \n --------------------------------------------------------------------------------\n \n \n \n Parsed MThd:\n \n " ) ; fprintf ( saveFile
, "Chunk Name: %26sMThd\n " , "" ) ; fprintf ( saveFile
, "Chunk Size: %23s6 bytes\n \n " , "" ) ; char str[ 40 ] ;
switch ( MthdData-> format) {
case 0x00000000 :
break ;
case 0x00000001 :
break ;
case 0x00000002 :
break ;
default :
return 0 ;
}
fprintf ( saveFile
, "Midi Format: %29s\n " , str
) ; fprintf ( saveFile
, "Number of Tracks: %24d\n " , MthdData
-> tracks_count
) ; switch ( MthdData-> time_divisionType) {
case 0x00 :
strcpy ( str
, "Ticks per Quarter Note" ) ; break ;
case 0x01 :
strcpy ( str
, "Frames per Second" ) ; break ;
default :
return 0 ;
}
fprintf ( saveFile
, "Time Division Type: %22s\n Time Division Value: %21d\n " , str
, MthdData
-> time_division
) ;
for ( k= 0 ; k< ( MthdData-> tracks_count) ; k++ ) {
_MtrkCD * MtrkChunkData = MtrkDatas[ k] ;
fprintf ( saveFile
, "\n \n \n --------------------------------------------------------------------------------\n " ) ; fprintf ( saveFile
, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n " ) ; fprintf ( saveFile
, "--------------------------------------------------------------------------------\n \n \n \n Parsed MTrk[%d]:\n \n " , k
) ; fprintf ( saveFile
, "Chunk Name: %26sMTrk\n " , "" ) ; fprintf ( saveFile
, "Chunk Size: %24d bytes\n " , MtrkChunkData
-> byteCount
) ; fprintf ( saveFile
, "Number of Events: %24d\n " , MtrkChunkData
-> elementCount
) ; for ( i= 0 ; i< MtrkChunkData-> elementCount; i++ ) {
fprintf ( saveFile
, "\n Delta Time Value: %18d ticks\n " , ( MtrkChunkData
-> deltaTime
) [ i
] ) ; switch ( ( MtrkChunkData-> eventType) [ i] ) {
case 2 :
strcpy ( str
, "System Exclusive Event" ) ; break ;
case 1 :
break ;
case 0 :
break ;
}
fprintf ( saveFile
, "Event Type: %30s\n " , str
) ; if ( MtrkChunkData-> eventType[ i] == 1 ) {
switch ( ( ( MtrkChunkData-> metaEventValues) [ i] ) .type ) {
case SEQUENCE_NUMBER:
strcpy ( str
, "Sequence Number Event" ) ; break ;
case TEXT:
break ;
case COPYRIGHT_NOTICE:
strcpy ( str
, "Copyright Notice Event" ) ; break ;
case SEQUENCE_TRACK_NAME:
strcpy ( str
, "Sequence / Track Name Event" ) ; break ;
case INSTRUMENT_NAME:
strcpy ( str
, "Instrument Name Event" ) ; break ;
case LYRICS:
break ;
case MARKER:
break ;
case CUE_POINT:
strcpy ( str
, "Cue Point Event" ) ; break ;
case 0x09 :
strcpy ( str
, "Unknown Text Type Event" ) ; break ;
case MIDI_CHANNEL_PREFIX:
strcpy ( str
, "MIDI Channel Prefix Event" ) ; break ;
case END_OF_TRACK:
strcpy ( str
, "End of Track Event" ) ; break ;
case SET_TEMPO:
strcpy ( str
, "Set Tempo Event" ) ; break ;
case SMPTE_OFFSET:
strcpy ( str
, "SMPTE Offset Event" ) ; break ;
case TIME_SIGNATURE:
strcpy ( str
, "Time Signature Event" ) ; break ;
case KEY_SIGNATURE:
strcpy ( str
, "Key Signature Event" ) ; break ;
case SEQUENCE_SPECIFIC:
strcpy ( str
, "Sequencer Specific Event" ) ; break ;
default :
}
fprintf ( saveFile
, "Event Sub-Type: %26s\n " , str
) ; switch ( MtrkChunkData-> metaEventValues[ i] .type ) {
case SEQUENCE_NUMBER:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Value: %0x04X\n " , ( ( ( ( ( MtrkChunkData
-> metaEventValues
) [ i
] ) .
data ) [ 0 ] ) << 8 ) + ( ( ( ( MtrkChunkData
-> metaEventValues
) [ i
] ) .
data ) [ 1 ] ) ) ; break ;
case TEXT:
case COPYRIGHT_NOTICE:
case SEQUENCE_TRACK_NAME:
case INSTRUMENT_NAME:
case LYRICS:
case MARKER:
case CUE_POINT:
case 0x09 :
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "%s\n " , ( char * ) ( ( ( MtrkChunkData
-> metaEventValues
) [ i
] ) .
data ) ) ; break ;
case MIDI_CHANNEL_PREFIX:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Channel: %d\n " , ( ( ( ( MtrkChunkData
-> metaEventValues
) [ i
] ) .
data ) [ 0 ] ) ) ; break ;
case SET_TEMPO:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Value: %8u Microseconds per Quarter Note\n " , ( ( MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] ) << 16 ) + ( ( MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] ) << 8 ) + ( MtrkChunkData
-> metaEventValues
[ i
] .
data [ 2 ] ) ) ; break ;
case SMPTE_OFFSET:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Hour: %-2d Min: %-2d Sec: %-2d Frames: %-2d Sub-Frames: %-2d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 2 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 3 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 4 ] ) ; break ;
case TIME_SIGNATURE:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Numerator: %-3d Denominator: %-3d Metronome: %-3d 1/32: %-3d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 2 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 3 ] ) ; break ;
case KEY_SIGNATURE:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Key: %+2d Scale: %d\n " , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 0 ] , MtrkChunkData
-> metaEventValues
[ i
] .
data [ 1 ] ) ; break ;
default :
break ;
}
}
else if ( MtrkChunkData-> eventType[ i] == 2 ) {
fprintf ( saveFile
, "Event Parameters:\n Value: 0x" ) ; for ( j= 0 ; j< ( ( ( MtrkChunkData-> sysExEventValues) [ i] ) .length ) ; j++ ) {
fprintf ( saveFile
, "%02X" , MtrkChunkData
-> sysExEventValues
[ i
] .
data [ j
] ) ; }
}
else {
switch ( MtrkChunkData-> midiEventValues[ i] .type ) {
case NOTE_OFF:
break ;
case NOTE_ON:
break ;
case NOTE_AFTERTOUCH:
strcpy ( str
, "Note Aftertouch Event" ) ; break ;
case CONTROLLER:
strcpy ( str
, "Controller Event" ) ; break ;
case PROGRAM_CHANGE:
strcpy ( str
, "Program Change Event" ) ; break ;
case PROGRAM_AFTERTOUCH:
strcpy ( str
, "Program Aftertouch Event" ) ; break ;
case PITCH_BEND:
strcpy ( str
, "Pitch Bend Event" ) ; break ;
default :
}
fprintf ( saveFile
, "Event Sub-Type: %26s\n " , str
) ; switch ( MtrkChunkData-> midiEventValues[ i] .type ) {
case NOTE_OFF:
case NOTE_ON:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Note Number: %d Note Velocity: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 , MtrkChunkData
-> midiEventValues
[ i
] .
param2 ) ; break ;
case NOTE_AFTERTOUCH:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Note Number: %d Aftertouch Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 , MtrkChunkData
-> midiEventValues
[ i
] .
param2 ) ; break ;
case CONTROLLER:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Controller Number: %d Controller Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 , MtrkChunkData
-> midiEventValues
[ i
] .
param2 ) ; break ;
case PROGRAM_CHANGE:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Program Number: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 ) ; break ;
case PROGRAM_AFTERTOUCH:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Aftertouch Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 ) ; break ;
case PITCH_BEND:
fprintf ( saveFile
, "Event Parameters:\n " ) ; fprintf ( saveFile
, "Pitch Value: %d\n " , MtrkChunkData
-> midiEventValues
[ i
] .
param1 + ( MtrkChunkData
-> midiEventValues
[ i
] .
param2 >> 8 ) ) ; break ;
default :
break ;
}
}
}
}
fprintf ( saveFile
, "\n \n \n --------------------------------------------------------------------------------\n \n \n " ) ; fprintf ( saveFile
, "Additional Information:\n " ) ; uint64_t totalSize= 0 ;
totalSize += 14 ; //MThd has fixed size of 14 bytes
for ( k= 0 ; k< MthdData-> tracks_count; k++ ) {
_MtrkCD * MtrkChunkData = MtrkDatas[ k] ;
totalSize += MtrkChunkData-> byteCount;
}
fprintf ( saveFile
, "\n File is OK!\n Total: %u bytes\n " , totalSize
) ; }
return 1 ;
}
int main( ) {
// use all variables as unsigned as long as it's feasible, otherwise you will risk wasting at least one bit of data os Sig
char fileName[ 40 ] ;
int opt;
int ret;
scanf ( "%[^\n ]39s" , fileName
) ; printf ( "1- Check File\n 2- Parse File\n 3- Save File\n " ) ; switch ( opt) {
case 1 :
ret = _ParseMidi( fileName, 0 , 0 ) ;
break ;
case 2 :
ret = _ParseMidi( fileName, 1 , 0 ) ;
break ;
case 3 :
ret = _ParseMidi( fileName, 0 , 1 ) ;
break ;
default :
break ;
}
if ( ! ret) {
printf ( "File has error(s).\n " ) ; }
else {
}
printf ( "Press ENTER to exit the application.\n " ) ; return 0 ;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0ZGJvb2wuaD4KI2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CgovL21pZGkgZXZlbnQgdHlwZXMKZW51bXsKCU5PVEVfT0ZGIAkJCQk9IDB4OCwKCU5PVEVfT04gCQkJCT0gMHg5LAoJTk9URV9BRlRFUlRPVUNIIAkJPSAweEEsCglDT05UUk9MTEVSIAkJCQk9IDB4QiwKCVBST0dSQU1fQ0hBTkdFIAkJCT0gMHhDLAoJUFJPR1JBTV9BRlRFUlRPVUNIIAkJPSAweEQsCglQSVRDSF9CRU5EIAkJCQk9IDB4RSwKfTsKCi8vbWV0YSBldmVudCB0eXBlcwplbnVtewoJU0VRVUVOQ0VfTlVNQkVSIAkJPSAweDAwLAoJVEVYVCAJCQkJCT0gMHgwMSwKCUNPUFlSSUdIVF9OT1RJQ0UgCQk9IDB4MDIsCglTRVFVRU5DRV9UUkFDS19OQU1FIAk9IDB4MDMsCglJTlNUUlVNRU5UX05BTUUgCQk9IDB4MDQsCglMWVJJQ1MgCQkJCQk9IDB4MDUsCglNQVJLRVIgCQkJCQk9IDB4MDYsCglDVUVfUE9JTlQgCQkJCT0gMHgwNywKCS8vVU5LTk9XTl9URVhUCQkJPSAweDA5OwoJTUlESV9DSEFOTkVMX1BSRUZJWCAJPSAweDIwLAoJRU5EX09GX1RSQUNLIAkJCT0gMHgyRiwKCVNFVF9URU1QTyAJCQkJPSAweDUxLAoJU01QVEVfT0ZGU0VUIAkJCT0gMHg1NCwKCVRJTUVfU0lHTkFUVVJFIAkJCT0gMHg1OCwKCUtFWV9TSUdOQVRVUkUJCQk9IDB4NTksCglTRVFVRU5DRV9TUEVDSUZJQyAJCT0gMHg3RiwKfTsKCi8vc3lzdGVtIGV4Y2x1c2l2ZSBldmVudHMKLyplbnVtewoJTk9STUFMID0gMHhGMDsKCURJVklERUQgPSAweEYwOwoJRElWSURFRCA9IDB4Rjc7Cn07Ki8KCnR5cGVkZWYgc3RydWN0IF9NdGhkQ0R7Cgl1aW50MTZfdCBmb3JtYXQ7Cgl1aW50MTZfdCB0cmFja3NfY291bnQ7Cgl1aW50MTZfdCB0aW1lX2RpdmlzaW9uOwoJdWludDhfdCB0aW1lX2RpdmlzaW9uVHlwZTsKfV9NdGhkQ0Q7Cgp0eXBlZGVmIHN0cnVjdCBfbWV0YUV2ZW50U3RydWN0ewoJdWludDhfdCB0eXBlOwoJdWludDY0X3QgbGVuZ3RoOwoJdWludDhfdCAqZGF0YTsKfV9tZXRhRXZlbnRTdHJ1Y3Q7Cgp0eXBlZGVmIHN0cnVjdCBfbWlkaUV2ZW50U3RydWN0ewoJdWludDhfdCB0eXBlOwoJdWludDhfdCBjaGFubmVsOwoJdWludDhfdCBwYXJhbTEsIHBhcmFtMjsKfV9taWRpRXZlbnRTdHJ1Y3Q7Cgp0eXBlZGVmIHN0cnVjdCBfc3lzRXhFdmVudFN0cnVjdHsKCXVpbnQ2NF90IGxlbmd0aDsKCXVpbnQ4X3QgKmRhdGE7Cn1fc3lzRXhFdmVudFN0cnVjdDsKCnR5cGVkZWYgc3RydWN0IF9NdHJrQ0R7Cgl1aW50MzJfdCBieXRlQ291bnQ7Cgl1aW50NjRfdCBlbGVtZW50Q291bnQ7Cgl1aW50NjRfdCAqZGVsdGFUaW1lOwoJdWludDhfdCAqZXZlbnRUeXBlOwoJX21ldGFFdmVudFN0cnVjdCAqbWV0YUV2ZW50VmFsdWVzOwoJX21pZGlFdmVudFN0cnVjdCAqbWlkaUV2ZW50VmFsdWVzOwoJX3N5c0V4RXZlbnRTdHJ1Y3QgKnN5c0V4RXZlbnRWYWx1ZXM7Cn1fTXRya0NEOwoKdWludDY0X3QgX1JlYWRWYXJpYWJsZUxlbmd0aChGSUxFICpmaWxlLGludCAqbCk7CnVpbnQ4X3QgX1JlYWRCeXRlKEZJTEUgKmZpbGUpOwp1aW50MTZfdCBfUmVhZEJ5dGUyKEZJTEUgKmZpbGUpOwp1aW50MzJfdCBfUmVhZEJ5dGU0KEZJTEUgKmZpbGUpOwoKdWludDhfdCBfZmlyc3RCaXRzNChpbnQgYnl0ZSk7CnVpbnQ4X3QgX2xhc3RCaXRzNChpbnQgYnl0ZSk7CnVpbnQ4X3QgX2ZpcnN0Qnl0ZShpbnQgYnl0ZXMpOwp1aW50OF90IF9sYXN0Qnl0ZShpbnQgYnl0ZXMpOwoKaW50IF9SZWFkTXRoZENodW5rKEZJTEUgKmZpbGUsIF9NdGhkQ0QgKk10aGRDaHVua0RhdGEsIGludCBwcmludCk7CmludCBfUmVhZE10cmtDaHVuayhGSUxFICpmaWxlLCBfTXRya0NEICpNdHJrQ2h1bmtEYXRhLCBpbnQgdHJhY2tJRCwgaW50IHByaW50KTsKCmludCBfUGFyc2VNaWRpKGNoYXIgKmZpbGVOYW1lLCBpbnQgcHJpbnQsIGludCBzYXZlKTsKCnVpbnQ2NF90IF9SZWFkVmFyaWFibGVMZW5ndGgoRklMRSAqZmlsZSwgaW50ICpsKXsKCSpsPTA7Cgl1aW50NjRfdCB0b3RhbFZhbCA9IDA7Cgl1aW50OF90IGN1clZhbD0wLCBjb3B5VmFsPTA7Cglkb3sKCQljb3B5VmFsID0gY3VyVmFsID0gX1JlYWRCeXRlKGZpbGUpOwoJCWNvcHlWYWwgJj0gfigxIDw8IDcpOwoJCXRvdGFsVmFsID0gKHRvdGFsVmFsIDw8IDcpICsgY29weVZhbDsKCQkoKmwpKys7Cgl9d2hpbGUoY3VyVmFsJigxPDw3KSk7CglyZXR1cm4gdG90YWxWYWw7Cn0KCnVpbnQ4X3QgX1JlYWRCeXRlKEZJTEUgKmZpbGUpewoJcmV0dXJuIChmZ2V0YyhmaWxlKSk7Cn0KCnVpbnQxNl90IF9SZWFkQnl0ZTIoRklMRSAqZmlsZSl7Cgl1aW50MTZfdCByZXMgPSBmZ2V0YyhmaWxlKTsKCXJlcyA9IChyZXM8PDgpICsgZmdldGMoZmlsZSk7CglyZXR1cm4gcmVzOwp9Cgp1aW50MzJfdCBfUmVhZEJ5dGU0KEZJTEUgKmZpbGUpewoJdWludDMyX3QgcmVzID0gZmdldGMoZmlsZSk7CglyZXMgPSAocmVzPDw4KSArIGZnZXRjKGZpbGUpOwoJcmVzID0gKHJlczw8OCkgKyBmZ2V0YyhmaWxlKTsKCXJlcyA9IChyZXM8PDgpICsgZmdldGMoZmlsZSk7CglyZXR1cm4gcmVzOwp9Cgp1aW50OF90IF9maXJzdEJpdHM0KGludCBieXRlKXsKCXJldHVybiAoYnl0ZT4+NCk7Cn0KCnVpbnQ4X3QgX2xhc3RCaXRzNChpbnQgYnl0ZSl7CglyZXR1cm4gYnl0ZS0oKGJ5dGU+PjQpPDw0KTsKfQp1aW50OF90IF9maXJzdEJ5dGUoaW50IGJ5dGVzKXsKCXJldHVybiAoYnl0ZXM+PjgpOwp9Cgp1aW50OF90IF9sYXN0Qnl0ZShpbnQgYnl0ZXMpewoJcmV0dXJuIGJ5dGVzLSgoYnl0ZXM+PjgpPDw4KTsKfQoKaW50IF9SZWFkTXRoZENodW5rKEZJTEUgKmZpbGUsIF9NdGhkQ0QgKk10aGRDaHVua0RhdGEsIGludCBwcmludCl7Cgl1aW50MzJfdCBjaGtOYW1lID0gX1JlYWRCeXRlNChmaWxlKTsKCWlmIChjaGtOYW1lICE9IDB4NEQ1NDY4NjQpewoJCXJldHVybiAwOwoJfQoJdWludDMyX3QgY2hrTGVuZ3RoID0gX1JlYWRCeXRlNChmaWxlKTsKCWlmIChjaGtMZW5ndGggIT0gMHgwMDAwMDAwNil7CgkJcmV0dXJuIDA7Cgl9CglNdGhkQ2h1bmtEYXRhLT5mb3JtYXQgPSBfUmVhZEJ5dGUyKGZpbGUpOwoJTXRoZENodW5rRGF0YS0+dHJhY2tzX2NvdW50ID0gX1JlYWRCeXRlMihmaWxlKTsKCU10aGRDaHVua0RhdGEtPnRpbWVfZGl2aXNpb24gPSBfUmVhZEJ5dGUyKGZpbGUpOwoJaWYgKE10aGRDaHVua0RhdGEtPnRpbWVfZGl2aXNpb25UeXBlICYgKDE8PDE2KSl7CgkJTXRoZENodW5rRGF0YS0+dGltZV9kaXZpc2lvblR5cGUgPSAxOwoJfQoJZWxzZXsKCQlNdGhkQ2h1bmtEYXRhLT50aW1lX2RpdmlzaW9uVHlwZSA9IDA7Cgl9CglpZiAocHJpbnQpewoJCXByaW50ZigiXG5cblxuLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblBhcnNlZCBNVGhkOlxuXG4iKTsKCQlwcmludGYoIkNodW5rIE5hbWU6ICUyNnMlYyVjJWMlY1xuIiwiIiwoY2hhcikoY2hrTmFtZT4+MjQpLChjaGFyKSgoY2hrTmFtZT4+MTYpJTB4MTAwKSwoY2hhcikoKGNoa05hbWU+PjgpJTB4MTAwKSwoY2hhcikoKGNoa05hbWUpJTB4MTAwKSk7CgkJcHJpbnRmKCJDaHVuayBTaXplOiAlMjRkIGJ5dGVzXG5cbiIsY2hrTGVuZ3RoKTsKCQljaGFyIHN0clsyNV07CgkJc3dpdGNoIChNdGhkQ2h1bmtEYXRhLT5mb3JtYXQpewoJCQljYXNlIDB4MDAwMDAwMDA6CgkJCQlzdHJjcHkoc3RyLCJTaW5nbGUgVHJhY2siKTsKCQkJCWJyZWFrOwoJCQljYXNlIDB4MDAwMDAwMDE6CgkJCQlzdHJjcHkoc3RyLCJNdWx0aXBsZSBUcmFjayIpOwoJCQkJYnJlYWs7CgkJCWNhc2UgMHgwMDAwMDAwMjoKCQkJCXN0cmNweShzdHIsIk11bHRpcGxlIFNvbmciKTsKCQkJCWJyZWFrOwoJCQlkZWZhdWx0OgoJCQkJcmV0dXJuIDA7CgkJfQoJCXByaW50ZigiTWlkaSBGb3JtYXQ6ICUyOXNcbiIsc3RyKTsKCQlwcmludGYoIk51bWJlciBvZiBUcmFja3M6ICUyNGRcbiIsTXRoZENodW5rRGF0YS0+dHJhY2tzX2NvdW50KTsKCQlzd2l0Y2goTXRoZENodW5rRGF0YS0+dGltZV9kaXZpc2lvblR5cGUpewoJCQljYXNlIDB4MDA6CgkJCQlzdHJjcHkoc3RyLCJUaWNrcyBwZXIgUXVhcnRlciBOb3RlIik7CgkJCQlicmVhazsKCQkJY2FzZSAweDAxOgoJCQkJc3RyY3B5KHN0ciwiRnJhbWVzIHBlciBTZWNvbmQiKTsKCQkJCWJyZWFrOwoJCQlkZWZhdWx0OgoJCQkJcmV0dXJuIDA7CgkJfQoJCXByaW50ZigiVGltZSBEaXZpc2lvbiBUeXBlOiAlMjJzXG5UaW1lIERpdmlzaW9uIFZhbHVlOiAlMjFkXG4iLHN0cixNdGhkQ2h1bmtEYXRhLT50aW1lX2RpdmlzaW9uKTsKCX0KCXJldHVybiAxOwp9CgppbnQgX1JlYWRNdHJrQ2h1bmsoRklMRSAqZmlsZSwgX010cmtDRCAqTXRya0NodW5rRGF0YSwgaW50IHRyYWNrSUQsIGludCBwcmludCl7CgkvL3N0YXRpYyBpbnQgdHJhY2tJRCA9IDA7CglpbnQgaSxqOwoJdWludDMyX3QgY2hrTmFtZSA9IF9SZWFkQnl0ZTQoZmlsZSk7CglpZiAoY2hrTmFtZSAhPSAweDRENTQ3MjZCKXsKCQlyZXR1cm4gMDsKCX0KCU10cmtDaHVua0RhdGEtPmJ5dGVDb3VudCA9IF9SZWFkQnl0ZTQoZmlsZSk7Cgl1aW50MzJfdCBwYXJzZWRMZW5ndGggPSBNdHJrQ2h1bmtEYXRhLT5ieXRlQ291bnQ7CgkKCXVpbnQ4X3QgbWlkaUV2ZW50VHlwZTsKCXVpbnQ4X3QgbWlkaUNoYW5uZWw7CgkKCWludCBsPTA7CgkKCU10cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudD0wOwoJTXRya0NodW5rRGF0YS0+ZGVsdGFUaW1lPSh1aW50NjRfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ2NF90KSkpOwoJTXRya0NodW5rRGF0YS0+ZXZlbnRUeXBlPSh1aW50OF90ICopKG1hbGxvYyhzaXplb2YodWludDhfdCkpKTsKCU10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcz0oX21ldGFFdmVudFN0cnVjdCAqKShtYWxsb2Moc2l6ZW9mKF9tZXRhRXZlbnRTdHJ1Y3QpKSk7CglNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXM9KF9taWRpRXZlbnRTdHJ1Y3QgKikobWFsbG9jKHNpemVvZihfbWlkaUV2ZW50U3RydWN0KSkpOwoJTXRya0NodW5rRGF0YS0+c3lzRXhFdmVudFZhbHVlcz0oX3N5c0V4RXZlbnRTdHJ1Y3QgKikobWFsbG9jKHNpemVvZihfc3lzRXhFdmVudFN0cnVjdCkpKTsKCQoJd2hpbGUgKHBhcnNlZExlbmd0aCA+IDApewoJCU10cmtDaHVua0RhdGEtPmRlbHRhVGltZT0ocmVhbGxvYyhNdHJrQ2h1bmtEYXRhLT5kZWx0YVRpbWUsc2l6ZW9mKHVpbnQ2NF90KSAqIChNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnQrMSkpKTsKCQlNdHJrQ2h1bmtEYXRhLT5ldmVudFR5cGU9KHJlYWxsb2MoTXRya0NodW5rRGF0YS0+ZXZlbnRUeXBlLHNpemVvZih1aW50OF90KSAqIChNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnQrMSkpKTsKCQlNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXM9KHJlYWxsb2MoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzLHNpemVvZihfbWV0YUV2ZW50U3RydWN0KSAqIChNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnQrMSkpKTsKCQlNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXM9KHJlYWxsb2MoTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzLHNpemVvZihfbWlkaUV2ZW50U3RydWN0KSAqIChNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnQrMSkpKTsKCQlNdHJrQ2h1bmtEYXRhLT5zeXNFeEV2ZW50VmFsdWVzPShyZWFsbG9jKE10cmtDaHVua0RhdGEtPnN5c0V4RXZlbnRWYWx1ZXMsc2l6ZW9mKF9zeXNFeEV2ZW50U3RydWN0KSAqIChNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnQrMSkpKTsKCQkKCQkvL2dldGNoKCk7CgkJLy9wcmludGYoImxvb3BlZC4uLiB0b0JlUGFyc2VkTGVuZ3RoIGlzICVkIFxuIixwYXJzZWRMZW5ndGgpOwoJCSgoTXRya0NodW5rRGF0YS0+ZGVsdGFUaW1lKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKSA9IF9SZWFkVmFyaWFibGVMZW5ndGgoZmlsZSwmbCk7CgkJLy9wcmludGYoIlZhcmlhYmxlIGxlbmd0aDogJWRcbiIsTXRya0NodW5rRGF0YS0+ZGVsdGFUaW1lKTsKCQlwYXJzZWRMZW5ndGgtPWw7CgkJdWludDhfdCBuQnl0ZSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkvL3ByaW50ZigibkJ5dGU6IDB4JVhcbiIsbkJ5dGUpOwoJCXBhcnNlZExlbmd0aC09MTsKCQkvL2NoZWNrIG5CeXRlIGZvciBldmVudCB0eXBlCgkJc3dpdGNoKG5CeXRlKXsKCQkJLy9tZXRhIGV2ZW50IGNhc2UKCQkJY2FzZSAweEZGOgoJCQkJKChNdHJrQ2h1bmtEYXRhLT5ldmVudFR5cGUpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pPTE7CgkJCQkvL3ByaW50ZigiRm91bmQgTUVUQSBldmVudFxuIik7CgkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkudHlwZSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkJCS8vcHJpbnRmKCJNZXRhIGV2ZW50IDB4JVhcbiIsbWV0YUV2ZW50VHlwZSk7CgkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQlzd2l0Y2goKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLnR5cGUpewoJCQkJCS8vbWlnaHQgc2VlbSB0cml2aWFsIHRvIHNlcGVyYXRlIHR5cGVzIHNpbmNlIGFsbCBpcyBzY2FubmVkIHRoZSBzYW1lIHdheSBidXQgaXQgaXMgYWN0dWFsbHkgbmVlZGVkIGZvciBzZXBhcmF0aW5nIGNvbnZlcnNpb24gYW5kIHRyYWNrIGNvbWJpbmF0aW9uCgkJCQkJY2FzZSBTRVFVRU5DRV9OVU1CRVI6CgkJCQkJY2FzZSBLRVlfU0lHTkFUVVJFOgoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkubGVuZ3RoPV9SZWFkQnl0ZShmaWxlKTsKCQkJCQkJcGFyc2VkTGVuZ3RoLT0xOwoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YT0odWludDhfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ4X3QpICogKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aCkpOwoJCQkJCQlmb3IgKGk9MDtpPCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg7aSsrKXsKCQkJCQkJCSgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YSlbaV0gPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQkJCX0KCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBTRVFVRU5DRV9TUEVDSUZJQzoKCQkJCQkJKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aD1fUmVhZFZhcmlhYmxlTGVuZ3RoKGZpbGUsJmwpOwoJCQkJCQlwYXJzZWRMZW5ndGgtPWw7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhPSh1aW50OF90ICopKG1hbGxvYyhzaXplb2YodWludDhfdCkgKiAoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkubGVuZ3RoKSk7CgkJCQkJCWZvciAoaT0wO2k8KChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aDtpKyspewoJCQkJCQkJKCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhKVtpXSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkJCQkJCXBhcnNlZExlbmd0aC09MTsKCQkJCQkJfQoJCQkJCQlicmVhazsKCQkJCQljYXNlIFRFWFQ6CgkJCQkJY2FzZSBDT1BZUklHSFRfTk9USUNFOgoJCQkJCWNhc2UgU0VRVUVOQ0VfVFJBQ0tfTkFNRToKCQkJCQljYXNlIElOU1RSVU1FTlRfTkFNRToKCQkJCQljYXNlIExZUklDUzoKCQkJCQljYXNlIE1BUktFUjoKCQkJCQljYXNlIENVRV9QT0lOVDoKCQkJCQljYXNlIDB4MDk6IC8vdW5rbm93biB0ZXh0IGV2ZW50CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg9X1JlYWRWYXJpYWJsZUxlbmd0aChmaWxlLCZsKTsKCQkJCQkJcGFyc2VkTGVuZ3RoLT1sOwoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YT0odWludDhfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ4X3QpICogKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aCkpOwoJCQkJCQlmb3IgKGk9MDtpPCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg7aSsrKXsKCQkJCQkJCSgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YSlbaV0gPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQkJCX0KCQkJCQkJKCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhKVtpXT0nXDAnOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIE1JRElfQ0hBTk5FTF9QUkVGSVg6CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg9X1JlYWRWYXJpYWJsZUxlbmd0aChmaWxlLCZsKTsKCQkJCQkJcGFyc2VkTGVuZ3RoLT1sOwoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YT0odWludDhfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ4X3QpICogKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aCkpOwoJCQkJCQlmb3IgKGk9MDtpPCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg7aSsrKXsKCQkJCQkJCSgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YSlbaV0gPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQkJCX0KCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBTRVRfVEVNUE86CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg9X1JlYWRWYXJpYWJsZUxlbmd0aChmaWxlLCZsKTsKCQkJCQkJcGFyc2VkTGVuZ3RoLT1sOwoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YT0odWludDhfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ4X3QpICogKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aCkpOwoJCQkJCQlmb3IgKGk9MDtpPCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg7aSsrKXsKCQkJCQkJCSgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YSlbaV0gPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQkJCX0KCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBTTVBURV9PRkZTRVQ6CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg9X1JlYWRWYXJpYWJsZUxlbmd0aChmaWxlLCZsKTsKCQkJCQkJcGFyc2VkTGVuZ3RoLT1sOwoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YT0odWludDhfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ4X3QpICogKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aCkpOwoJCQkJCQlmb3IgKGk9MDtpPCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg7aSsrKXsKCQkJCQkJCSgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YSlbaV0gPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQkJCX0KCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBUSU1FX1NJR05BVFVSRToKCQkJCQkJKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aD1fUmVhZFZhcmlhYmxlTGVuZ3RoKGZpbGUsJmwpOwoJCQkJCQlwYXJzZWRMZW5ndGgtPWw7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhPSh1aW50OF90ICopKG1hbGxvYyhzaXplb2YodWludDhfdCkgKiAoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkubGVuZ3RoKSk7CgkJCQkJCWZvciAoaT0wO2k8KChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aDtpKyspewoJCQkJCQkJKCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhKVtpXSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkJCQkJCXBhcnNlZExlbmd0aC09MTsKCQkJCQkJfQoJCQkJCQlicmVhazsKCQkJCQljYXNlIEVORF9PRl9UUkFDSzoKCQkJCQkJKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aD1fUmVhZFZhcmlhYmxlTGVuZ3RoKGZpbGUsJmwpOwoJCQkJCQlwYXJzZWRMZW5ndGgtPWw7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhPSh1aW50OF90ICopKG1hbGxvYyhzaXplb2YodWludDhfdCkgKiAoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkubGVuZ3RoKSk7CgkJCQkJCWZvciAoaT0wO2k8KChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0pLmxlbmd0aDtpKyspewoJCQkJCQkJKCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhKVtpXSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkJCQkJCXBhcnNlZExlbmd0aC09MTsKCQkJCQkJfQoJCQkJCQlicmVhazsKCQkJCQlkZWZhdWx0OgoJCQkJCQlyZXR1cm4gMDsKCQkJCX0KCQkJCWJyZWFrOwoJCQkvL3N5c3RlbSBleGNsdXNpdmUgZXZlbnQgY2FzZQoJCQljYXNlIDB4RjA6CgkJCWNhc2UgMHhGNzoKCQkJCSgoTXRya0NodW5rRGF0YS0+ZXZlbnRUeXBlKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKT0yOwoJCQkJLy9wcmludGYoIkZvdW5kIFN5c3RlbSBFeGNsdXNpdmUgZXZlbnRcbiIpOwoJCQkJKChNdHJrQ2h1bmtEYXRhLT5zeXNFeEV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg9X1JlYWRWYXJpYWJsZUxlbmd0aChmaWxlLCZsKTsKCQkJCXBhcnNlZExlbmd0aC09bDsKCQkJCSgoTXRya0NodW5rRGF0YS0+c3lzRXhFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkuZGF0YT0odWludDhfdCAqKShtYWxsb2Moc2l6ZW9mKHVpbnQ4X3QpICogKChNdHJrQ2h1bmtEYXRhLT5zeXNFeEV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGgpKTsKCQkJCWZvciAoaT0wO2k8KChNdHJrQ2h1bmtEYXRhLT5zeXNFeEV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5sZW5ndGg7aSsrKXsKCQkJCQkoKChNdHJrQ2h1bmtEYXRhLT5zeXNFeEV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5kYXRhKVtpXSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkJCQlwYXJzZWRMZW5ndGgtPTE7CgkJCQl9CgkJCQlicmVhazsKCQkJLy9taWRpIGV2ZW50IGNhc2UKCQkJZGVmYXVsdDoKCQkJCSgoTXRya0NodW5rRGF0YS0+ZXZlbnRUeXBlKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKT0wOwoJCQkJLy9wcmludGYoIkZvdW5kIE1JREkgZXZlbnRcbiIpOwoJCQkJbWlkaUV2ZW50VHlwZSA9IF9maXJzdEJpdHM0KG5CeXRlKTsKCQkJCW1pZGlDaGFubmVsID0gX2xhc3RCaXRzNChuQnl0ZSk7CgkJCQkvL3ByaW50ZigiTUlESSBldmVudCB0eXBlOiAweCVYXG4iLG1pZGlFdmVudFR5cGUpOwoJCQkJc3dpdGNoIChtaWRpRXZlbnRUeXBlKXsKCQkJCQljYXNlIE5PVEVfT0ZGOgoJCQkJCWNhc2UgTk9URV9PTjoKCQkJCQljYXNlIE5PVEVfQUZURVJUT1VDSDoKCQkJCQljYXNlIENPTlRST0xMRVI6CgkJCQkJY2FzZSBQSVRDSF9CRU5EOgoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkudHlwZSA9IG1pZGlFdmVudFR5cGU7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5jaGFubmVsID0gbWlkaUNoYW5uZWw7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5wYXJhbTEgPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCXBhcnNlZExlbmd0aC09MTsKCQkJCQkJKChNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXMpW010cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudF0ucGFyYW0yKSA9IF9SZWFkQnl0ZShmaWxlKTsKCQkJCQkJcGFyc2VkTGVuZ3RoLT0xOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIFBST0dSQU1fQ0hBTkdFOgoJCQkJCWNhc2UgUFJPR1JBTV9BRlRFUlRPVUNIOgoJCQkJCQkoKE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlcylbTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50XSkudHlwZSA9IG1pZGlFdmVudFR5cGU7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5jaGFubmVsID0gbWlkaUNoYW5uZWw7CgkJCQkJCSgoTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzKVtNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnRdKS5wYXJhbTEgPSBfUmVhZEJ5dGUoZmlsZSk7CgkJCQkJCXBhcnNlZExlbmd0aC09MTsKCQkJCQkJYnJlYWs7CgkJCQkJZGVmYXVsdDoKCQkJCQkJcmV0dXJuIDA7CgkJCQl9CgkJCQlicmVhazsKCQl9CgkJKE10cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudCkrKzsKCX0KCWlmIChwcmludCl7CgkJcHJpbnRmKCJcblxuXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuIik7CgkJcHJpbnRmKCIrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK1xuIik7CgkJcHJpbnRmKCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuUGFyc2VkIE1UcmtbJWRdOlxuXG4iLHRyYWNrSUQpOwoJCXByaW50ZigiQ2h1bmsgTmFtZTogJTI2cyVjJWMlYyVjXG4iLCIiLChjaGFyKShjaGtOYW1lPj4yNCksKGNoYXIpKChjaGtOYW1lPj4xNiklMHgxMDApLChjaGFyKSgoY2hrTmFtZT4+OCklMHgxMDApLChjaGFyKSgoY2hrTmFtZSklMHgxMDApKTsKCQlwcmludGYoIkNodW5rIFNpemU6ICUyNGQgYnl0ZXNcbiIsTXRya0NodW5rRGF0YS0+Ynl0ZUNvdW50KTsKCQlwcmludGYoIk51bWJlciBvZiBFdmVudHM6ICUyNGRcbiIsTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50KTsKCQlwcmludGYoIlxuRXZlbnRzOlxuIik7CgkJY2hhciBzdHJbNDBdPXsnXDAnfTsKCQlmb3IgKGk9MDtpPE10cmtDaHVua0RhdGEtPmVsZW1lbnRDb3VudDtpKyspewoJCQlwcmludGYoIlxuRGVsdGEgVGltZSBWYWx1ZTogJTE4ZCB0aWNrc1xuIixNdHJrQ2h1bmtEYXRhLT5kZWx0YVRpbWVbaV0pOwoJCQlzd2l0Y2goTXRya0NodW5rRGF0YS0+ZXZlbnRUeXBlW2ldKXsKCQkJCWNhc2UgMjoKCQkJCQlzdHJjcHkoc3RyLCJTeXN0ZW0gRXhjbHVzaXZlIEV2ZW50Iik7CgkJCQkJYnJlYWs7CgkJCQljYXNlIDE6CgkJCQkJc3RyY3B5KHN0ciwiTUVUQSBFdmVudCIpOwoJCQkJCWJyZWFrOwoJCQkJY2FzZSAwOgoJCQkJCXN0cmNweShzdHIsIk1JREkgRXZlbnQiKTsKCQkJCQlicmVhazsKCQkJfQoJCQlwcmludGYoIkV2ZW50IFR5cGU6ICUzMHNcbiIsc3RyKTsKCQkJaWYgKE10cmtDaHVua0RhdGEtPmV2ZW50VHlwZVtpXSA9PSAxKXsKCQkJCXN3aXRjaChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0udHlwZSl7CgkJCQkJY2FzZSBTRVFVRU5DRV9OVU1CRVI6CgkJCQkJCXN0cmNweShzdHIsIlNlcXVlbmNlIE51bWJlciBFdmVudCIpOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIFRFWFQ6CgkJCQkJCXN0cmNweShzdHIsIlRleHQgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBDT1BZUklHSFRfTk9USUNFOgoJCQkJCQlzdHJjcHkoc3RyLCJDb3B5cmlnaHQgTm90aWNlIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgU0VRVUVOQ0VfVFJBQ0tfTkFNRToKCQkJCQkJc3RyY3B5KHN0ciwiU2VxdWVuY2UgLyBUcmFjayBOYW1lIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgSU5TVFJVTUVOVF9OQU1FOgoJCQkJCQlzdHJjcHkoc3RyLCJJbnN0cnVtZW50IE5hbWUgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBMWVJJQ1M6CgkJCQkJCXN0cmNweShzdHIsIkx5cmljcyBFdmVudCIpOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIE1BUktFUjoKCQkJCQkJc3RyY3B5KHN0ciwiTWFya2VyIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgQ1VFX1BPSU5UOgoJCQkJCQlzdHJjcHkoc3RyLCJDdWUgUG9pbnQgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSAweDA5OgoJCQkJCQlzdHJjcHkoc3RyLCJVbmtub3duIFRleHQgVHlwZSBFdmVudCIpOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIE1JRElfQ0hBTk5FTF9QUkVGSVg6CgkJCQkJCXN0cmNweShzdHIsIk1JREkgQ2hhbm5lbCBQcmVmaXggRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBFTkRfT0ZfVFJBQ0s6CgkJCQkJCXN0cmNweShzdHIsIkVuZCBvZiBUcmFjayBFdmVudCIpOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIFNFVF9URU1QTzoKCQkJCQkJc3RyY3B5KHN0ciwiU2V0IFRlbXBvIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgU01QVEVfT0ZGU0VUOgoJCQkJCQlzdHJjcHkoc3RyLCJTTVBURSBPZmZzZXQgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBUSU1FX1NJR05BVFVSRToKCQkJCQkJc3RyY3B5KHN0ciwiVGltZSBTaWduYXR1cmUgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBLRVlfU0lHTkFUVVJFOgoJCQkJCQlzdHJjcHkoc3RyLCJLZXkgU2lnbmF0dXJlIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgU0VRVUVOQ0VfU1BFQ0lGSUM6CgkJCQkJCXN0cmNweShzdHIsIlNlcXVlbmNlciBTcGVjaWZpYyBFdmVudCIpOwoJCQkJCQlicmVhazsKCQkJCQlkZWZhdWx0OgoJCQkJCQlzdHJjcHkoc3RyLCJVTktOT1dOIEVWRU5UIik7CgkJCQl9CgkJCQlwcmludGYoIkV2ZW50IFN1Yi1UeXBlOiAlMjZzXG4iLHN0cik7CgkJCQlzd2l0Y2goTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLnR5cGUpewoJCQkJCWNhc2UgU0VRVUVOQ0VfTlVNQkVSOgoJCQkJCQlwcmludGYoIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJcHJpbnRmKCJWYWx1ZTogJTB4MDRYXG4iLE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlc1tpXS5kYXRhWzBdPDw4K010cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlc1tpXS5kYXRhWzFdKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBURVhUOgoJCQkJCWNhc2UgQ09QWVJJR0hUX05PVElDRToKCQkJCQljYXNlIFNFUVVFTkNFX1RSQUNLX05BTUU6CgkJCQkJY2FzZSBJTlNUUlVNRU5UX05BTUU6CgkJCQkJY2FzZSBMWVJJQ1M6CgkJCQkJY2FzZSBNQVJLRVI6CgkJCQkJY2FzZSBDVUVfUE9JTlQ6CgkJCQkJY2FzZSAweDA5OgoJCQkJCQlwcmludGYoIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJcHJpbnRmKCIlc1xuIiwoY2hhciAqKU10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlc1tpXS5kYXRhKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBNSURJX0NIQU5ORUxfUFJFRklYOgoJCQkJCQlwcmludGYoIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJcHJpbnRmKCJDaGFubmVsOiAlZFxuIixNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVswXSk7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgU0VUX1RFTVBPOgoJCQkJCQlwcmludGYoIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJcHJpbnRmKCJWYWx1ZTogJTh1IE1pY3Jvc2Vjb25kcyBwZXIgUXVhcnRlciBOb3RlXG4iLChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVswXTw8MTYpKyhNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVsxXTw8OCkrTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMl0pOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIFNNUFRFX09GRlNFVDoKCQkJCQkJcHJpbnRmKCJFdmVudCBQYXJhbWV0ZXJzOlxuIik7CgkJCQkJCXByaW50ZigiSG91cjogJS0yZCAgTWluOiAlLTJkICBTZWM6ICUtMmQgIEZyYW1lczogJS0yZCAgU3ViLUZyYW1lczogJS0yZFxuIixNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVswXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVsxXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVsyXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVszXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVs0XSk7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgVElNRV9TSUdOQVRVUkU6CgkJCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQlwcmludGYoIk51bWVyYXRvcjogJS0zZCAgRGVub21pbmF0b3I6ICUtM2QgIE1ldHJvbm9tZTogJS0zZCAgMS8zMjogJS0zZFxuIixNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVswXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVsxXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVsyXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVszXSk7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgS0VZX1NJR05BVFVSRToKCQkJCQkJcHJpbnRmKCJFdmVudCBQYXJhbWV0ZXJzOlxuIik7CgkJCQkJCXByaW50ZigiS2V5OiAlKzJkIFNjYWxlOiAlZFxuIixNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVswXSxNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0uZGF0YVsxXSk7CgkJCQkJCWJyZWFrOwoJCQkJCWRlZmF1bHQ6CgkJCQkJCWJyZWFrOwoJCQkJfQoJCQl9CgkJCWVsc2UgaWYgKE10cmtDaHVua0RhdGEtPmV2ZW50VHlwZVtpXSA9PSAyKXsKCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiBWYWx1ZTogMHgiKTsKCQkJCWZvciAoaj0wO2o8TXRya0NodW5rRGF0YS0+c3lzRXhFdmVudFZhbHVlc1tpXS5sZW5ndGg7aisrKXsKCQkJCQlwcmludGYoIiUwMlgiLE10cmtDaHVua0RhdGEtPnN5c0V4RXZlbnRWYWx1ZXNbaV0uZGF0YVtqXSk7CgkJCQl9CgkJCQlwcmludGYoIlxuIik7CgkJCX0KCQkJZWxzZXsKCQkJCXN3aXRjaChNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0udHlwZSl7CgkJCQkJY2FzZSBOT1RFX09GRjoKCQkJCQkJc3RyY3B5KHN0ciwiTm90ZS1PZmYgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBOT1RFX09OOgoJCQkJCQlzdHJjcHkoc3RyLCJOb3RlLU9uIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgTk9URV9BRlRFUlRPVUNIOgoJCQkJCQlzdHJjcHkoc3RyLCJOb3RlIEFmdGVydG91Y2ggRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBDT05UUk9MTEVSOgoJCQkJCQlzdHJjcHkoc3RyLCJDb250cm9sbGVyIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgUFJPR1JBTV9DSEFOR0U6CgkJCQkJCXN0cmNweShzdHIsIlByb2dyYW0gQ2hhbmdlIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgUFJPR1JBTV9BRlRFUlRPVUNIOgoJCQkJCQlzdHJjcHkoc3RyLCJQcm9ncmFtIEFmdGVydG91Y2ggRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBQSVRDSF9CRU5EOgoJCQkJCQlzdHJjcHkoc3RyLCJQaXRjaCBCZW5kIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJCWRlZmF1bHQ6CgkJCQkJCXN0cmNweShzdHIsIlVOS05PV04gRXZlbnQiKTsKCQkJCX0KCQkJCXByaW50ZigiRXZlbnQgU3ViLVR5cGU6ICUyNnNcbiIsc3RyKTsKCQkJCXN3aXRjaChNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0udHlwZSl7CgkJCQkJY2FzZSBOT1RFX09GRjoKCQkJCQljYXNlIE5PVEVfT046CgkJCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQlwcmludGYoIk5vdGUgTnVtYmVyOiAlZCAgTm90ZSBWZWxvY2l0eTogJWRcbiIsTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzW2ldLnBhcmFtMSxNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0yKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBOT1RFX0FGVEVSVE9VQ0g6CgkJCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQlwcmludGYoIk5vdGUgTnVtYmVyOiAlZCAgQWZ0ZXJ0b3VjaCBWYWx1ZTogJWRcbiIsTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzW2ldLnBhcmFtMSxNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0yKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBDT05UUk9MTEVSOgoJCQkJCQlwcmludGYoIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJcHJpbnRmKCJDb250cm9sbGVyIE51bWJlcjogJWQgIENvbnRyb2xsZXIgVmFsdWU6ICVkXG4iLE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlc1tpXS5wYXJhbTEsTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzW2ldLnBhcmFtMik7CgkJCQkJCWJyZWFrOwoJCQkJCWNhc2UgUFJPR1JBTV9DSEFOR0U6CgkJCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQlwcmludGYoIlByb2dyYW0gTnVtYmVyOiAlZFxuIixNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0xKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSBQUk9HUkFNX0FGVEVSVE9VQ0g6CgkJCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQlwcmludGYoIkFmdGVydG91Y2ggVmFsdWU6ICVkXG4iLE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlc1tpXS5wYXJhbTEpOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIFBJVENIX0JFTkQ6CgkJCQkJCXByaW50ZigiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQlwcmludGYoIlBpdGNoIFZhbHVlOiAlZFxuIixNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0xICsgKE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlc1tpXS5wYXJhbTI+PjgpKTsKCQkJCQkJYnJlYWs7CgkJCQkJZGVmYXVsdDoKCQkJCQkJYnJlYWs7CgkJCQl9CgkJCX0KCQkJcHJpbnRmKCJQcmVzcyBBTlkga2V5IHRvIGNvbnRpbnVlLi4uXG4iKTsKCQkJZ2V0Y2goKTsKCQl9Cgl9CglyZXR1cm4gMTsKfQoKaW50IF9QYXJzZU1pZGkoY2hhciAqZmlsZU5hbWUsIGludCBwcmludCwgaW50IHNhdmUpewoJRklMRSAqbWlkaUZpbGU7CglfTXRoZENEICpNdGhkRGF0YSA9IChfTXRoZENEICopKG1hbGxvYyhzaXplb2YoX010aGRDRCkpKTsKCW1pZGlGaWxlID0gZm9wZW4oZmlsZU5hbWUsICJyYiIpOwoJaWYgKG1pZGlGaWxlID09IE5VTEwpewoJCXByaW50ZigiRmFpbGVkIHRvIG9wZW4gdGhlIGZpbGUuIEFyZSB5b3Ugc3VyZSB0aGUgZmlsZSBleGlzdHM/XG4iKTsKCQlyZXR1cm4gMDsKCX0KCWlmICghX1JlYWRNdGhkQ2h1bmsobWlkaUZpbGUsTXRoZERhdGEsIHByaW50KSl7CgkJcHJpbnRmKCJFcnJvciByZWFkaW5nIE1UaGQgQ2h1bmsuIEJhZCBNVGhkLlxuIik7CgkJcmV0dXJuIDA7Cgl9CgkKCV9NdHJrQ0QgKipNdHJrRGF0YXMgPSAoX010cmtDRCAqKikobWFsbG9jKHNpemVvZihfTXRya0NEICopKSk7Cgl1aW50NjRfdCBpLGosayxwOwoJZm9yIChwPTA7cDxNdGhkRGF0YS0+dHJhY2tzX2NvdW50O3ArKyl7CgkJTXRya0RhdGFzW3BdID0gKF9NdHJrQ0QgKikobWFsbG9jKHNpemVvZihfTXRya0NEKSkpOwoJCWlmKCFfUmVhZE10cmtDaHVuayhtaWRpRmlsZSxNdHJrRGF0YXNbcF0scCxwcmludCkpewoJCQlwcmludGYoIkVycm9yIHJlYWRpbmcgTVRyayBDaHVuay4gQmFkIE1UcmsuXG4iKTsKCQkJcmV0dXJuIDA7CgkJfQoJfQoJCglmY2xvc2UobWlkaUZpbGUpOwoJCglpZiAoc2F2ZSl7CgkJY2hhciBzYXZlRmlsZU5hbWVbNDBdOwoJCXN0cmNweShzYXZlRmlsZU5hbWUsZmlsZU5hbWUpOwoJCXN0cmNweShzYXZlRmlsZU5hbWUrc3RybGVuKGZpbGVOYW1lKS00LCIgUGFyc2VkLnR4dCIpOwoJCUZJTEUgKnNhdmVGaWxlOwoJCS8vcHJpbnRmKCJzYXZlRmlsZU5hbWU6ICVzLiIsc2F2ZUZpbGVOYW1lKTsKCQkKCQlzYXZlRmlsZSA9IGZvcGVuKHNhdmVGaWxlTmFtZSwidyIpOwoJCWlmIChzYXZlRmlsZSA9PSBOVUxMKXsKCQkJcHJpbnRmKCJGYWlsZWQgdG8gb3BlbiBzYXZlIGZpbGUuXG4iKTsKCQkJcmV0dXJuIDA7CgkJfQoJCQoJCWZwcmludGYoc2F2ZUZpbGUsIlxuXG5cbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuXG5QYXJzZWQgTVRoZDpcblxuIik7CgkJZnByaW50ZihzYXZlRmlsZSwiQ2h1bmsgTmFtZTogJTI2c01UaGRcbiIsIiIpOwoJCWZwcmludGYoc2F2ZUZpbGUsIkNodW5rIFNpemU6ICUyM3M2IGJ5dGVzXG5cbiIsIiIpOwoJCWNoYXIgc3RyWzQwXTsKCQlzd2l0Y2ggKE10aGREYXRhLT5mb3JtYXQpewoJCQljYXNlIDB4MDAwMDAwMDA6CgkJCQlzdHJjcHkoc3RyLCJTaW5nbGUgVHJhY2siKTsKCQkJCWJyZWFrOwoJCQljYXNlIDB4MDAwMDAwMDE6CgkJCQlzdHJjcHkoc3RyLCJNdWx0aXBsZSBUcmFjayIpOwoJCQkJYnJlYWs7CgkJCWNhc2UgMHgwMDAwMDAwMjoKCQkJCXN0cmNweShzdHIsIk11bHRpcGxlIFNvbmciKTsKCQkJCWJyZWFrOwoJCQlkZWZhdWx0OgoJCQkJcmV0dXJuIDA7CgkJfQoJCWZwcmludGYoc2F2ZUZpbGUsIk1pZGkgRm9ybWF0OiAlMjlzXG4iLHN0cik7CgkJZnByaW50ZihzYXZlRmlsZSwiTnVtYmVyIG9mIFRyYWNrczogJTI0ZFxuIixNdGhkRGF0YS0+dHJhY2tzX2NvdW50KTsKCQlzd2l0Y2goTXRoZERhdGEtPnRpbWVfZGl2aXNpb25UeXBlKXsKCQkJY2FzZSAweDAwOgoJCQkJc3RyY3B5KHN0ciwiVGlja3MgcGVyIFF1YXJ0ZXIgTm90ZSIpOwoJCQkJYnJlYWs7CgkJCWNhc2UgMHgwMToKCQkJCXN0cmNweShzdHIsIkZyYW1lcyBwZXIgU2Vjb25kIik7CgkJCQlicmVhazsKCQkJZGVmYXVsdDoKCQkJCXJldHVybiAwOwoJCX0KCQlmcHJpbnRmKHNhdmVGaWxlLCJUaW1lIERpdmlzaW9uIFR5cGU6ICUyMnNcblRpbWUgRGl2aXNpb24gVmFsdWU6ICUyMWRcbiIsc3RyLE10aGREYXRhLT50aW1lX2RpdmlzaW9uKTsKCQkKCQlmb3IgKGs9MDtrPChNdGhkRGF0YS0+dHJhY2tzX2NvdW50KTtrKyspewoJCQlfTXRya0NEICpNdHJrQ2h1bmtEYXRhID0gTXRya0RhdGFzW2tdOwoJCQlmcHJpbnRmKHNhdmVGaWxlLCJcblxuXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuIik7CgkJCWZwcmludGYoc2F2ZUZpbGUsIisrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrXG4iKTsKCQkJZnByaW50ZihzYXZlRmlsZSwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG5cblBhcnNlZCBNVHJrWyVkXTpcblxuIixrKTsKCQkJZnByaW50ZihzYXZlRmlsZSwiQ2h1bmsgTmFtZTogJTI2c01UcmtcbiIsIiIpOwoJCQlmcHJpbnRmKHNhdmVGaWxlLCJDaHVuayBTaXplOiAlMjRkIGJ5dGVzXG4iLE10cmtDaHVua0RhdGEtPmJ5dGVDb3VudCk7CgkJCWZwcmludGYoc2F2ZUZpbGUsIk51bWJlciBvZiBFdmVudHM6ICUyNGRcbiIsTXRya0NodW5rRGF0YS0+ZWxlbWVudENvdW50KTsKCQkJZnByaW50ZihzYXZlRmlsZSwiXG5FdmVudHM6XG4iKTsKCQkJZm9yIChpPTA7aTxNdHJrQ2h1bmtEYXRhLT5lbGVtZW50Q291bnQ7aSsrKXsKCQkJCWZwcmludGYoc2F2ZUZpbGUsIlxuRGVsdGEgVGltZSBWYWx1ZTogJTE4ZCB0aWNrc1xuIiwoTXRya0NodW5rRGF0YS0+ZGVsdGFUaW1lKVtpXSk7CgkJCQlzd2l0Y2goKE10cmtDaHVua0RhdGEtPmV2ZW50VHlwZSlbaV0pewoJCQkJCWNhc2UgMjoKCQkJCQkJc3RyY3B5KHN0ciwiU3lzdGVtIEV4Y2x1c2l2ZSBFdmVudCIpOwoJCQkJCQlicmVhazsKCQkJCQljYXNlIDE6CgkJCQkJCXN0cmNweShzdHIsIk1FVEEgRXZlbnQiKTsKCQkJCQkJYnJlYWs7CgkJCQkJY2FzZSAwOgoJCQkJCQlzdHJjcHkoc3RyLCJNSURJIEV2ZW50Iik7CgkJCQkJCWJyZWFrOwoJCQkJfQoJCQkJZnByaW50ZihzYXZlRmlsZSwiRXZlbnQgVHlwZTogJTMwc1xuIixzdHIpOwoJCQkJaWYgKE10cmtDaHVua0RhdGEtPmV2ZW50VHlwZVtpXSA9PSAxKXsKCQkJCQlzd2l0Y2goKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW2ldKS50eXBlKXsKCQkJCQkJY2FzZSBTRVFVRU5DRV9OVU1CRVI6CgkJCQkJCQlzdHJjcHkoc3RyLCJTZXF1ZW5jZSBOdW1iZXIgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIFRFWFQ6CgkJCQkJCQlzdHJjcHkoc3RyLCJUZXh0IEV2ZW50Iik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBDT1BZUklHSFRfTk9USUNFOgoJCQkJCQkJc3RyY3B5KHN0ciwiQ29weXJpZ2h0IE5vdGljZSBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgU0VRVUVOQ0VfVFJBQ0tfTkFNRToKCQkJCQkJCXN0cmNweShzdHIsIlNlcXVlbmNlIC8gVHJhY2sgTmFtZSBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgSU5TVFJVTUVOVF9OQU1FOgoJCQkJCQkJc3RyY3B5KHN0ciwiSW5zdHJ1bWVudCBOYW1lIEV2ZW50Iik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBMWVJJQ1M6CgkJCQkJCQlzdHJjcHkoc3RyLCJMeXJpY3MgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIE1BUktFUjoKCQkJCQkJCXN0cmNweShzdHIsIk1hcmtlciBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgQ1VFX1BPSU5UOgoJCQkJCQkJc3RyY3B5KHN0ciwiQ3VlIFBvaW50IEV2ZW50Iik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSAweDA5OgoJCQkJCQkJc3RyY3B5KHN0ciwiVW5rbm93biBUZXh0IFR5cGUgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIE1JRElfQ0hBTk5FTF9QUkVGSVg6CgkJCQkJCQlzdHJjcHkoc3RyLCJNSURJIENoYW5uZWwgUHJlZml4IEV2ZW50Iik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBFTkRfT0ZfVFJBQ0s6CgkJCQkJCQlzdHJjcHkoc3RyLCJFbmQgb2YgVHJhY2sgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIFNFVF9URU1QTzoKCQkJCQkJCXN0cmNweShzdHIsIlNldCBUZW1wbyBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgU01QVEVfT0ZGU0VUOgoJCQkJCQkJc3RyY3B5KHN0ciwiU01QVEUgT2Zmc2V0IEV2ZW50Iik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBUSU1FX1NJR05BVFVSRToKCQkJCQkJCXN0cmNweShzdHIsIlRpbWUgU2lnbmF0dXJlIEV2ZW50Iik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBLRVlfU0lHTkFUVVJFOgoJCQkJCQkJc3RyY3B5KHN0ciwiS2V5IFNpZ25hdHVyZSBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgU0VRVUVOQ0VfU1BFQ0lGSUM6CgkJCQkJCQlzdHJjcHkoc3RyLCJTZXF1ZW5jZXIgU3BlY2lmaWMgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQlkZWZhdWx0OgoJCQkJCQkJc3RyY3B5KHN0ciwiVU5LTk9XTiBFVkVOVCIpOwoJCQkJCX0KCQkJCQlmcHJpbnRmKHNhdmVGaWxlLCJFdmVudCBTdWItVHlwZTogJTI2c1xuIixzdHIpOwoJCQkJCXN3aXRjaChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXNbaV0udHlwZSl7CgkJCQkJCWNhc2UgU0VRVUVOQ0VfTlVNQkVSOgoJCQkJCQkJZnByaW50ZihzYXZlRmlsZSwiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQkJZnByaW50ZihzYXZlRmlsZSwiVmFsdWU6ICUweDA0WFxuIiwoKCgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbaV0pLmRhdGEpWzBdKTw8OCkrKCgoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlcylbaV0pLmRhdGEpWzFdKSk7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBURVhUOgoJCQkJCQljYXNlIENPUFlSSUdIVF9OT1RJQ0U6CgkJCQkJCWNhc2UgU0VRVUVOQ0VfVFJBQ0tfTkFNRToKCQkJCQkJY2FzZSBJTlNUUlVNRU5UX05BTUU6CgkJCQkJCWNhc2UgTFlSSUNTOgoJCQkJCQljYXNlIE1BUktFUjoKCQkJCQkJY2FzZSBDVUVfUE9JTlQ6CgkJCQkJCWNhc2UgMHgwOToKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIiVzXG4iLChjaGFyICopKCgoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzKVtpXSkuZGF0YSkpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgTUlESV9DSEFOTkVMX1BSRUZJWDoKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkNoYW5uZWw6ICVkXG4iLCgoKChNdHJrQ2h1bmtEYXRhLT5tZXRhRXZlbnRWYWx1ZXMpW2ldKS5kYXRhKVswXSkpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgU0VUX1RFTVBPOgoJCQkJCQkJZnByaW50ZihzYXZlRmlsZSwiRXZlbnQgUGFyYW1ldGVyczpcbiIpOwoJCQkJCQkJZnByaW50ZihzYXZlRmlsZSwiVmFsdWU6ICU4dSBNaWNyb3NlY29uZHMgcGVyIFF1YXJ0ZXIgTm90ZVxuIiwoKE10cmtDaHVua0RhdGEtPm1ldGFFdmVudFZhbHVlc1tpXS5kYXRhWzBdKTw8MTYpKygoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMV0pPDw4KSsoTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMl0pKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIFNNUFRFX09GRlNFVDoKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkhvdXI6ICUtMmQgIE1pbjogJS0yZCAgU2VjOiAlLTJkICBGcmFtZXM6ICUtMmQgIFN1Yi1GcmFtZXM6ICUtMmRcbiIsTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMF0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMV0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMl0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbM10sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbNF0pOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgVElNRV9TSUdOQVRVUkU6CgkJCQkJCQlmcHJpbnRmKHNhdmVGaWxlLCJFdmVudCBQYXJhbWV0ZXJzOlxuIik7CgkJCQkJCQlmcHJpbnRmKHNhdmVGaWxlLCJOdW1lcmF0b3I6ICUtM2QgIERlbm9taW5hdG9yOiAlLTNkICBNZXRyb25vbWU6ICUtM2QgIDEvMzI6ICUtM2RcbiIsTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMF0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMV0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMl0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbM10pOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgS0VZX1NJR05BVFVSRToKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIktleTogJSsyZCBTY2FsZTogJWRcbiIsTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMF0sTXRya0NodW5rRGF0YS0+bWV0YUV2ZW50VmFsdWVzW2ldLmRhdGFbMV0pOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWRlZmF1bHQ6CgkJCQkJCQlicmVhazsKCQkJCQl9CgkJCQl9CgkJCQllbHNlIGlmIChNdHJrQ2h1bmtEYXRhLT5ldmVudFR5cGVbaV0gPT0gMil7CgkJCQkJZnByaW50ZihzYXZlRmlsZSwiRXZlbnQgUGFyYW1ldGVyczpcbiBWYWx1ZTogMHgiKTsKCQkJCQlmb3IgKGo9MDtqPCgoKE10cmtDaHVua0RhdGEtPnN5c0V4RXZlbnRWYWx1ZXMpW2ldKS5sZW5ndGgpO2orKyl7CgkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIiUwMlgiLE10cmtDaHVua0RhdGEtPnN5c0V4RXZlbnRWYWx1ZXNbaV0uZGF0YVtqXSk7CgkJCQkJfQoJCQkJCWZwcmludGYoc2F2ZUZpbGUsIlxuIik7CgkJCQl9CgkJCQllbHNlewoJCQkJCXN3aXRjaChNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0udHlwZSl7CgkJCQkJCWNhc2UgTk9URV9PRkY6CgkJCQkJCQlzdHJjcHkoc3RyLCJOb3RlLU9mZiBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgTk9URV9PTjoKCQkJCQkJCXN0cmNweShzdHIsIk5vdGUtT24gRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIE5PVEVfQUZURVJUT1VDSDoKCQkJCQkJCXN0cmNweShzdHIsIk5vdGUgQWZ0ZXJ0b3VjaCBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgQ09OVFJPTExFUjoKCQkJCQkJCXN0cmNweShzdHIsIkNvbnRyb2xsZXIgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIFBST0dSQU1fQ0hBTkdFOgoJCQkJCQkJc3RyY3B5KHN0ciwiUHJvZ3JhbSBDaGFuZ2UgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIFBST0dSQU1fQUZURVJUT1VDSDoKCQkJCQkJCXN0cmNweShzdHIsIlByb2dyYW0gQWZ0ZXJ0b3VjaCBFdmVudCIpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgUElUQ0hfQkVORDoKCQkJCQkJCXN0cmNweShzdHIsIlBpdGNoIEJlbmQgRXZlbnQiKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQlkZWZhdWx0OgoJCQkJCQkJc3RyY3B5KHN0ciwiVU5LTk9XTiBFdmVudCIpOwoJCQkJCX0KCQkJCQlmcHJpbnRmKHNhdmVGaWxlLCJFdmVudCBTdWItVHlwZTogJTI2c1xuIixzdHIpOwoJCQkJCXN3aXRjaChNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0udHlwZSl7CgkJCQkJCWNhc2UgTk9URV9PRkY6CgkJCQkJCWNhc2UgTk9URV9PTjoKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIk5vdGUgTnVtYmVyOiAlZCAgTm90ZSBWZWxvY2l0eTogJWRcbiIsTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzW2ldLnBhcmFtMSxNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0yKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIE5PVEVfQUZURVJUT1VDSDoKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIk5vdGUgTnVtYmVyOiAlZCAgQWZ0ZXJ0b3VjaCBWYWx1ZTogJWRcbiIsTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzW2ldLnBhcmFtMSxNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0yKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIENPTlRST0xMRVI6CgkJCQkJCQlmcHJpbnRmKHNhdmVGaWxlLCJFdmVudCBQYXJhbWV0ZXJzOlxuIik7CgkJCQkJCQlmcHJpbnRmKHNhdmVGaWxlLCJDb250cm9sbGVyIE51bWJlcjogJWQgIENvbnRyb2xsZXIgVmFsdWU6ICVkXG4iLE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlc1tpXS5wYXJhbTEsTXRya0NodW5rRGF0YS0+bWlkaUV2ZW50VmFsdWVzW2ldLnBhcmFtMik7CgkJCQkJCQlicmVhazsKCQkJCQkJY2FzZSBQUk9HUkFNX0NIQU5HRToKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIlByb2dyYW0gTnVtYmVyOiAlZFxuIixNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0xKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQljYXNlIFBST0dSQU1fQUZURVJUT1VDSDoKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkFmdGVydG91Y2ggVmFsdWU6ICVkXG4iLE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlc1tpXS5wYXJhbTEpOwoJCQkJCQkJYnJlYWs7CgkJCQkJCWNhc2UgUElUQ0hfQkVORDoKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIkV2ZW50IFBhcmFtZXRlcnM6XG4iKTsKCQkJCQkJCWZwcmludGYoc2F2ZUZpbGUsIlBpdGNoIFZhbHVlOiAlZFxuIixNdHJrQ2h1bmtEYXRhLT5taWRpRXZlbnRWYWx1ZXNbaV0ucGFyYW0xICsgKE10cmtDaHVua0RhdGEtPm1pZGlFdmVudFZhbHVlc1tpXS5wYXJhbTI+PjgpKTsKCQkJCQkJCWJyZWFrOwoJCQkJCQlkZWZhdWx0OgoJCQkJCQkJYnJlYWs7CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoJCQoJCWZwcmludGYoc2F2ZUZpbGUsIlxuXG5cbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxuIik7CgkJZnByaW50ZihzYXZlRmlsZSwiQWRkaXRpb25hbCBJbmZvcm1hdGlvbjpcbiIpOwoJCXVpbnQ2NF90IHRvdGFsU2l6ZT0wOwoJCXRvdGFsU2l6ZSArPSAxNDsgLy9NVGhkIGhhcyBmaXhlZCBzaXplIG9mIDE0IGJ5dGVzCgkJZm9yIChrPTA7azxNdGhkRGF0YS0+dHJhY2tzX2NvdW50O2srKyl7CgkJCV9NdHJrQ0QgKk10cmtDaHVua0RhdGEgPSBNdHJrRGF0YXNba107CgkJCXRvdGFsU2l6ZSArPSBNdHJrQ2h1bmtEYXRhLT5ieXRlQ291bnQ7CgkJfQoJCWZwcmludGYoc2F2ZUZpbGUsIlxuRmlsZSBpcyBPSyFcblRvdGFsOiAldSBieXRlc1xuIix0b3RhbFNpemUpOwoJCWZjbG9zZShzYXZlRmlsZSk7Cgl9CglyZXR1cm4gMTsKfQoKaW50IG1haW4oKXsKCS8vIHVzZSBhbGwgdmFyaWFibGVzIGFzIHVuc2lnbmVkIGFzIGxvbmcgYXMgaXQncyBmZWFzaWJsZSwgb3RoZXJ3aXNlIHlvdSB3aWxsIHJpc2sgd2FzdGluZyBhdCBsZWFzdCBvbmUgYml0IG9mIGRhdGEgb3MgU2lnCgljaGFyIGZpbGVOYW1lWzQwXTsKCWludCBvcHQ7CglpbnQgcmV0OwoJcHJpbnRmKCJFbnRlciBmaWxlbmFtZTogIik7CglmZmx1c2goc3RkaW4pOwoJc2NhbmYoIiVbXlxuXTM5cyIsZmlsZU5hbWUpOwoJcHJpbnRmKCIxLSBDaGVjayBGaWxlXG4yLSBQYXJzZSBGaWxlXG4zLSBTYXZlIEZpbGVcbiIpOwoJc2NhbmYoIiVkIiwmb3B0KTsKCXN3aXRjaChvcHQpewoJCWNhc2UgMToKCQkJcmV0ID0gX1BhcnNlTWlkaShmaWxlTmFtZSwwLDApOwoJCQlicmVhazsKCQljYXNlIDI6CgkJCXJldCA9IF9QYXJzZU1pZGkoZmlsZU5hbWUsMSwwKTsKCQkJYnJlYWs7CgkJY2FzZSAzOgoJCQlyZXQgPSBfUGFyc2VNaWRpKGZpbGVOYW1lLDAsMSk7CgkJCWJyZWFrOwoJCWRlZmF1bHQ6CgkJCXByaW50ZigiSW52YWxpZCBpbnB1dFxuIik7CgkJCWJyZWFrOwoJfQoJaWYgKCFyZXQpewoJCXByaW50ZigiRmlsZSBoYXMgZXJyb3IocykuXG4iKTsKCX0KCWVsc2V7CgkJcHJpbnRmKCJGaWxlIGlzIE9LIVxuIik7Cgl9CglwcmludGYoIlByZXNzIEVOVEVSIHRvIGV4aXQgdGhlIGFwcGxpY2F0aW9uLlxuIik7CglmZmx1c2goc3RkaW4pOwoJZ2V0cyhmaWxlTmFtZSk7CglyZXR1cm4gMDsKfQ==