#include<iostream> // Allows input output operations
#include <iomanip>
#include<math.h>
using namespace std;
#define N 200
#define ARRAY_SIZE (N*N)
#define M 100
// Mapping is defined for [a-z] , [A-Z] , [0-9]
// {'A','6'} maps A to 6
//
char map[ M] [ 2 ] =
{
{ 'A' ,'6' } , { 'B' ,'b' } , { 'C' ,'c' } , { 'D' ,'d' } , { 'E' ,'2' } , { 'F' ,'1' } , { 'G' ,'g' } , { 'H' ,'h' } , { 'I' ,'9' } , { 'J' ,'j' } , { 'K' ,'k' } ,
{ 'L' ,'S' } , { 'M' ,'m' } , { 'N' ,'n' } , { 'O' ,'o' } , { 'P' ,'p' } , { 'Q' ,'q' } , { 'R' ,'r' } , { 'S' ,'s' } , { 'T' ,'t' } , { 'U' ,'u' } , { 'V' ,'v' } ,
{ 'W' ,'w' } , { 'X' ,'x' } , { 'Y' ,'y' } , { 'Z' ,'z' } , { 'a' ,'A' } , { 'b' ,'B' } , { 'c' ,'C' } , { 'd' ,'D' } , { 'e' ,'E' } , { 'f' ,'F' } , { 'g' ,'G' } ,
{ 'h' ,'H' } , { 'i' ,'I' } , { 'j' ,'J' } , { 'k' ,'K' } , { 'l' ,'L' } , { 'm' ,'M' } , { 'n' ,'N' } , { 'o' ,'O' } , { 'p' ,'P' } , { 'q' ,'Q' } , { 'r' ,'R' } ,
{ 's' ,'l' } , { 't' ,'T' } , { 'u' ,'U' } , { 'v' ,'V' } , { 'w' ,'W' } , { 'x' ,'X' } , { 'y' ,'Y' } , { 'z' ,'Z' } , { '0' ,'i' } , { '1' ,'8' } , { '2' ,'7' } ,
{ '3' ,'a' } , { '4' ,'5' } , { '5' ,'4' } , { '6' ,'3' } , { '7' ,'e' } , { '8' ,'f' } , { '9' ,'0' }
} ;
// Define functionality for the following functions
// And call them in main()
/*For calculating Determinant of the Matrix */
/*******************************************************************************
* Function Name : determinant
* Description : Given a square matrix array[][]. Calculates determinant.
* Input : array,order
* Output : Determinant
* Return : determinant value(type float)
* Example : Order = 2
Array [ 3 2 ] -> Returns 5.3000
[ 2 3.1 ]
*******************************************************************************/
float determinant( float array[ N] [ N] ,float order)
{
float sum= 0 ,c;
for ( int j= 1 ; j<= order; j++ )
{
for ( int i= j+ 1 ; i<= order; i++ )
{
c= ( array[ i] [ j] ) / array[ j] [ j] ;
for ( int k= j; k<= order; k++ )
{
array[ i] [ k] = array[ i] [ k] - c* array[ j] [ k] ;
}
}
}
for ( int l= 1 ; l<= order; l++ )
{
sum= sum+ array[ l] [ l] ;
}
return sum;
}
/*******************************************************************************
* Function Name : inverse
* Description : Given a square matrix array[][]. Calculates inverse_array.
* Input : array,order
* Output : inv
* Return : None
* Example : Order = 2
Array [ 3 2 ] -> inv [ (3/5) (-2/5) ]
[ 2 3 ] [ (-2/5) (3/5) ]
*******************************************************************************/
void inverse( float inv[ N] [ N] ,float array[ N] [ N] ,float order)
{
float c[ N] [ N] ;
int l,p,h,k,i,j;
for ( l= 0 ; l< order; l++ )
{
for ( p= 0 ; p< order; p++ )
{
h= 0 ,k= 0 ;
for ( i= 0 ; i< order; i++ )
{
if ( i== l)
continue ;
for ( j= 0 ; j< order; j++ )
{
if ( j== p)
continue ;
c[ h] [ k] = array[ i] [ j] ;
k++ ;
if ( k= ( order- 1 ) )
{
h++ ;
k= 0 ;
}
}
}
inv[ p] [ l] = ( pow ( - 1 ,l+ p) * determinant( c,order- 1 ) ) / determinant( array,order) ;
}
}
}
/*******************************************************************************
* Function Name : array_map
* Description : Maps plain_text_zero_padded to mapped_array using map array
* Input : plain_text_zero_padded
* Output : mapped_array
* Return : None
* Example : plain_text_zero_padded "ABCDE00" -> mapped_array "abcd2ii"
*******************************************************************************/
void array_map( char mapped_array[ ARRAY_SIZE] , char plain_text_zero_padded[ ARRAY_SIZE] )
{
for ( int i= 0 ; i< ARRAY_SIZE; i++ )
{
for ( int j= 0 ; j< M; j++ )
{
if ( plain_text_zero_padded[ i] ! = map[ j] [ 0 ] )
continue ;
else
{
mapped_array[ i] = map[ j] [ 1 ] ;
break ;
}
}
}
/*******************************************************************************
* Function Name : inv_array_map
* Description : Maps inv_mapped_array to decrypt_plain_text_zero_padded using map array
* Input : inv_mapped_array
* Output : decrypt_plain_text_zero_padded
* Return : None
* Example : inv_mapped_array "abcd2ii" -> decrypt_plain_text_zero_padded "ABCDE00"
*******************************************************************************/
void inv_array_map( char inv_mapped_array[ ARRAY_SIZE] , char decrypt_plain_text_zero_padded[ ARRAY_SIZE] )
{
for ( int i= 0 ; i< ARRAY_SIZE; i++ )
{
for ( int j= 0 ; j< M; j++ )
{
if ( inv_mapped_array[ i] ! = map[ j] [ 1 ] )
continue ;
else
{
decrypt_plain_text_zero_padded[ i] = map[ j] [ 0 ] ;
break ;
}
}
}
}
// Donot modify the functions below(upto main)
void keygen( float key[ N] [ N] , int marker)
{
int i,j;
for ( i= 0 ; i< marker; i++ ) {
for ( j= 0 ; j< marker; j++ ) {
if ( i ! = j)
key[ i] [ j] = marker;
else
key[ i] [ j] = marker + 1 ;
}
}
}
void print( char c[ N] [ N] , int row, int col)
{
int i,j;
for ( i= 0 ; i< row; i++ ) {
for ( j= 0 ; j< col; j++ ) {
cout << c[ i] [ j] << " " ;
}
cout << endl;
}
}
void print( float f[ N] [ N] , int row, int col)
{
int i,j;
for ( i= 0 ; i< row; i++ ) {
for ( j= 0 ; j< col; j++ ) {
std:: cout << std:: fixed << std:: setprecision ( 3 ) << setw( 15 ) << f[ i] [ j] ;
}
cout << endl;
}
}
void compare( char plain_text[ N] ,char decrypt_plain_text[ N] , int length_of_input)
{
int loi;
for ( loi = 0 ; ( plain_text[ loi] == decrypt_plain_text[ loi] && plain_text[ loi] ) ; loi++ ) ;
if ( loi == length_of_input)
cout << "SUCCESS" << endl;
}
int main( ) {
/*********** DO NOT CHANGE VARIABLE NAMES ************/
char plain_text[ ARRAY_SIZE] ;
int marker;
float key[ N] [ N] ;
float cipher_text[ N] [ N] ;
float invkey[ N] [ N] ;
char decrypt_plain_text[ ARRAY_SIZE] ;
char inv_mapped_array[ ARRAY_SIZE] ;
/***************Get User Input***************/
cout << "Enter the plain text" << endl;
cin >> plain_text;
cout << "Enter the marker" << endl;
cin >> marker;
// Creating a key matrix of size (marker x marker)
keygen( key,marker) ;
/***************End User Input***************/
/*---------------------------------------------*/
// Please add your code here
int length_of_input;
for ( length_of_input = 0 ; plain_text[ length_of_input] ; length_of_input++ ) ;
int r;
r= length_of_input% marker;
for ( int a= 0 ; a< ( length_of_input+ marker- r) ; a++ )
{
if ( a< length_of_input)
{
plain_text_zero_padded[ a] = plain_text[ a] ;
}
else {
plain_text_zero_padded[ a] = 0 ;
}
}
void array_map( mapped_array,plain_text_zero_padded) ;
char mapped[ ARRAY_SIZE] [ N] ;
int z= 0 ;
for ( int e= 0 ; e< ( length_of_input/ marker) + 1 ; e++ )
{
for ( int f= 0 ; f< marker; f++ )
{
mapped[ e] [ f] = mapped_array[ z] ;
z++ ;
}
}
for ( int b= 0 ; b< ( length_of_input/ marker) + 1 ; b++ )
{
for ( int c= 0 ; c< marker; c++ )
{
cipher_text[ b] [ c] = 0 ;
for ( int d= 0 ; d< marker; d++ )
cipher_text[ b] [ c] + = mapped[ b] [ d] * key[ d] [ c] ;
}
}
char rev_mapped[ ARRAY_SIZE] [ N] ;
void inverse( invkey,key,marker) ;
for ( int o= 0 ; o< ( length_of_input/ marker) + 1 ; o++ )
{
for ( int p= 0 ; p< marker; p++ )
{
rev_mapped[ o] [ p] = 0 ;
for ( int q= 0 ; q< marker; q++ )
rev_mapped[ o] [ p] + = cipher_text[ o] [ q] * invkey[ q] [ p] ;
}
}
int y= 0 ;
for ( int e= 0 ; e< ( length_of_input/ marker) + 1 ; e++ )
{
for ( int f= 0 ; f< marker; f++ )
{
inv_mapped_array[ y] = rev_mapped[ e] [ f] ;
y++ ;
}
}
void inv_array_map( inv_mapped_array, decrypt_plain_text_zero_padded) ;
/*---------------------------------------------*/
// Donot modify
//
cout << "Plain Text entered" << endl;
cout << plain_text<< "\n " ;
cout << "Key Used" << endl;
print( key,marker,marker) ;
cout << "Cipher Text " << endl;
print( cipher_text,( int ) ceil ( ( float ) length_of_input/ marker) ,marker) ;
cout << "Key Inverse" << endl;
print( invkey,marker,marker) ;
cout << "Decrypted Text" << endl;
cout << decrypt_plain_text << "\n " ;
compare( plain_text,decrypt_plain_text,length_of_input) ;
return 0 ;
}
I2luY2x1ZGU8aW9zdHJlYW0+IAkvLyBBbGxvd3MgaW5wdXQgb3V0cHV0IG9wZXJhdGlvbnMKI2luY2x1ZGUgPGlvbWFuaXA+CiNpbmNsdWRlPG1hdGguaD4KCnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgojZGVmaW5lIE4gICAgICAgICAgIDIwMAojZGVmaW5lIEFSUkFZX1NJWkUgIChOKk4pCiNkZWZpbmUgTSAgICAgICAgICAgMTAwIAoKLy8gIE1hcHBpbmcgaXMgZGVmaW5lZCBmb3IgW2Etel0gLCBbQS1aXSAsIFswLTldCi8vICB7J0EnLCc2J30gbWFwcyBBIHRvIDYgCi8vCmNoYXIgbWFwW01dWzJdID0gCnsKeydBJywnNid9LCB7J0InLCdiJ30sIHsnQycsJ2MnfSwgeydEJywnZCd9LCB7J0UnLCcyJ30sIHsnRicsJzEnfSwgeydHJywnZyd9LCB7J0gnLCdoJ30sIHsnSScsJzknfSwgeydKJywnaid9LCB7J0snLCdrJ30sIAp7J0wnLCdTJ30sIHsnTScsJ20nfSwgeydOJywnbid9LCB7J08nLCdvJ30sIHsnUCcsJ3AnfSwgeydRJywncSd9LCB7J1InLCdyJ30sIHsnUycsJ3MnfSwgeydUJywndCd9LCB7J1UnLCd1J30sIHsnVicsJ3YnfSwgCnsnVycsJ3cnfSwgeydYJywneCd9LCB7J1knLCd5J30sIHsnWicsJ3onfSwgeydhJywnQSd9LCB7J2InLCdCJ30sIHsnYycsJ0MnfSwgeydkJywnRCd9LCB7J2UnLCdFJ30sIHsnZicsJ0YnfSwgeydnJywnRyd9LCAKeydoJywnSCd9LCB7J2knLCdJJ30sIHsnaicsJ0onfSwgeydrJywnSyd9LCB7J2wnLCdMJ30sIHsnbScsJ00nfSwgeyduJywnTid9LCB7J28nLCdPJ30sIHsncCcsJ1AnfSwgeydxJywnUSd9LCB7J3InLCdSJ30sIAp7J3MnLCdsJ30sIHsndCcsJ1QnfSwgeyd1JywnVSd9LCB7J3YnLCdWJ30sIHsndycsJ1cnfSwgeyd4JywnWCd9LCB7J3knLCdZJ30sIHsneicsJ1onfSwgeycwJywnaSd9LCB7JzEnLCc4J30sIHsnMicsJzcnfSwgCnsnMycsJ2EnfSwgeyc0JywnNSd9LCB7JzUnLCc0J30sIHsnNicsJzMnfSwgeyc3JywnZSd9LCB7JzgnLCdmJ30sIHsnOScsJzAnfQp9OwoKCi8vIERlZmluZSBmdW5jdGlvbmFsaXR5IGZvciB0aGUgZm9sbG93aW5nIGZ1bmN0aW9ucwovLyBBbmQgY2FsbCB0aGVtIGluIG1haW4oKQoKLypGb3IgY2FsY3VsYXRpbmcgRGV0ZXJtaW5hbnQgb2YgdGhlIE1hdHJpeCAqLwoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKKiBGdW5jdGlvbiBOYW1lICA6IGRldGVybWluYW50CiogRGVzY3JpcHRpb24gICAgOiBHaXZlbiBhIHNxdWFyZSBtYXRyaXggYXJyYXlbXVtdLiBDYWxjdWxhdGVzIGRldGVybWluYW50LiAKKiBJbnB1dCAgICAgICAgICA6IGFycmF5LG9yZGVyCiogT3V0cHV0ICAgICAgICAgOiBEZXRlcm1pbmFudCAgCiogUmV0dXJuICAgICAgICAgOiBkZXRlcm1pbmFudCB2YWx1ZSh0eXBlIGZsb2F0KQoqIEV4YW1wbGUgICAgICAgIDogT3JkZXIgPSAyIApBcnJheSBbIDMgMiAgIF0gICAtPiBSZXR1cm5zIDUuMzAwMAogICAgICBbIDIgMy4xIF0gICAgIAoKICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCmZsb2F0IGRldGVybWluYW50KGZsb2F0IGFycmF5W05dW05dLGZsb2F0IG9yZGVyKQp7CmZsb2F0IHN1bT0wLGM7CmZvcihpbnQgaj0xO2o8PW9yZGVyO2orKykKewoJZm9yKGludCBpPWorMTtpPD1vcmRlcjtpKyspCgl7CgkJYz0oYXJyYXlbaV1bal0pL2FycmF5W2pdW2pdOwoJCWZvcihpbnQgaz1qO2s8PW9yZGVyO2srKykKCQl7CgkJCWFycmF5W2ldW2tdPWFycmF5W2ldW2tdLWMqYXJyYXlbal1ba107CgkJCQkJfQoJfQp9CmZvcihpbnQgbD0xO2w8PW9yZGVyO2wrKykKewpzdW09c3VtK2FycmF5W2xdW2xdOwp9CnJldHVybiBzdW07Cn0KCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiogRnVuY3Rpb24gTmFtZSAgOiBpbnZlcnNlCiogRGVzY3JpcHRpb24gICAgOiBHaXZlbiBhIHNxdWFyZSBtYXRyaXggYXJyYXlbXVtdLiBDYWxjdWxhdGVzIGludmVyc2VfYXJyYXkuIAoqIElucHV0ICAgICAgICAgIDogYXJyYXksb3JkZXIKKiBPdXRwdXQgICAgICAgICA6IGludgoqIFJldHVybiAgICAgICAgIDogTm9uZQoqIEV4YW1wbGUgICAgICAgIDogT3JkZXIgPSAyIAoKQXJyYXkgWyAzIDIgXSAgIC0+IGludiBbICAoMy81KSAgICgtMi81KSAgXQogICAgICBbIDIgMyBdICAgICAgICAgIFsgICgtMi81KSAgKDMvNSkgICBdCiAKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCgp2b2lkIGludmVyc2UoZmxvYXQgaW52W05dW05dLGZsb2F0IGFycmF5W05dW05dLGZsb2F0IG9yZGVyKQp7CmZsb2F0IGNbTl1bTl07CmludCBsLHAsaCxrLGksajsKZm9yKGw9MDtsPG9yZGVyO2wrKykKewoJZm9yKHA9MDtwPG9yZGVyO3ArKykKCXsKCQloPTAsaz0wOwoJCWZvcihpPTA7aTxvcmRlcjtpKyspCgkJewoJCQlpZihpPT1sKQoJCQljb250aW51ZTsKCQkJZm9yKGo9MDtqPG9yZGVyO2orKykKCQkJewoJCQkJaWYoaj09cCkKCQkJCWNvbnRpbnVlOwoJCQkJY1toXVtrXT1hcnJheVtpXVtqXTsKCQkJCWsrKzsKCQkJCWlmKGs9KG9yZGVyLTEpKQoJCQkJewoJCQkJCWgrKzsKCQkJCQlrPTA7CgkJCQl9CgkJCX0KCQkJCQl9CgkJCQkJCgkJCQkJaW52W3BdW2xdPShwb3coLTEsbCtwKSpkZXRlcm1pbmFudChjLG9yZGVyLTEpKS9kZXRlcm1pbmFudChhcnJheSxvcmRlcik7CgkJCQkJCgl9Cn0KfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKKiBGdW5jdGlvbiBOYW1lICA6IGFycmF5X21hcAoqIERlc2NyaXB0aW9uICAgIDogTWFwcyBwbGFpbl90ZXh0X3plcm9fcGFkZGVkIHRvIG1hcHBlZF9hcnJheSB1c2luZyBtYXAgYXJyYXkgCiogSW5wdXQgICAgICAgICAgOiBwbGFpbl90ZXh0X3plcm9fcGFkZGVkCiogT3V0cHV0ICAgICAgICAgOiBtYXBwZWRfYXJyYXkKKiBSZXR1cm4gICAgICAgICA6IE5vbmUKKiBFeGFtcGxlICAgICAgICA6IHBsYWluX3RleHRfemVyb19wYWRkZWQgIkFCQ0RFMDAiIC0+IG1hcHBlZF9hcnJheSAiYWJjZDJpaSIgCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgoKdm9pZCBhcnJheV9tYXAoY2hhciBtYXBwZWRfYXJyYXlbQVJSQVlfU0laRV0sIGNoYXIgcGxhaW5fdGV4dF96ZXJvX3BhZGRlZFtBUlJBWV9TSVpFXSkKewoJZm9yKGludCBpPTA7aTxBUlJBWV9TSVpFO2krKykKCXsKCWZvcihpbnQgaj0wO2o8TTtqKyspCgl7CgkJaWYocGxhaW5fdGV4dF96ZXJvX3BhZGRlZFtpXSE9bWFwW2pdWzBdKQoJCWNvbnRpbnVlOwoJCWVsc2UKCQl7CgkJCW1hcHBlZF9hcnJheVtpXT1tYXBbal1bMV07CgkJCWJyZWFrOwoJCX0KCX0KCQoKfQoKCgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgoqIEZ1bmN0aW9uIE5hbWUgIDogaW52X2FycmF5X21hcAoqIERlc2NyaXB0aW9uICAgIDogTWFwcyBpbnZfbWFwcGVkX2FycmF5IHRvIGRlY3J5cHRfcGxhaW5fdGV4dF96ZXJvX3BhZGRlZCB1c2luZyBtYXAgYXJyYXkgCiogSW5wdXQgICAgICAgICAgOiBpbnZfbWFwcGVkX2FycmF5CiogT3V0cHV0ICAgICAgICAgOiBkZWNyeXB0X3BsYWluX3RleHRfemVyb19wYWRkZWQKKiBSZXR1cm4gICAgICAgICA6IE5vbmUKKiBFeGFtcGxlICAgICAgICA6IGludl9tYXBwZWRfYXJyYXkgImFiY2QyaWkiIC0+IGRlY3J5cHRfcGxhaW5fdGV4dF96ZXJvX3BhZGRlZCAiQUJDREUwMCIgCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgp2b2lkIGludl9hcnJheV9tYXAoY2hhciBpbnZfbWFwcGVkX2FycmF5W0FSUkFZX1NJWkVdLCBjaGFyIGRlY3J5cHRfcGxhaW5fdGV4dF96ZXJvX3BhZGRlZFtBUlJBWV9TSVpFXSkKewpmb3IoaW50IGk9MDtpPEFSUkFZX1NJWkU7aSsrKQp7Cglmb3IoaW50IGo9MDtqPE07aisrKQoJewoJCWlmKGludl9tYXBwZWRfYXJyYXlbaV0hPW1hcFtqXVsxXSkKY29udGludWU7CmVsc2UKewoJZGVjcnlwdF9wbGFpbl90ZXh0X3plcm9fcGFkZGVkW2ldPW1hcFtqXVswXTsKCWJyZWFrOwoJCgl9CgkJfQp9Cn0KCgovLyBEb25vdCBtb2RpZnkgdGhlIGZ1bmN0aW9ucyBiZWxvdyh1cHRvIG1haW4pIAoKdm9pZCBrZXlnZW4oZmxvYXQga2V5W05dW05dLCBpbnQgbWFya2VyKQp7CiAgaW50IGksajsKCiBmb3IoaT0wO2k8bWFya2VyO2krKyl7ICAKICAgIGZvcihqPTA7ajxtYXJrZXI7aisrKXsKICAgICAgaWYoaSAhPSBqKQogICAgICAgIGtleVtpXVtqXSA9IG1hcmtlcjsKICAgICAgZWxzZQogICAgICAgIGtleVtpXVtqXSA9IG1hcmtlciArIDE7CiAgICB9CiAgfQoKfQoKdm9pZCBwcmludChjaGFyIGNbTl1bTl0sIGludCByb3csIGludCBjb2wpCnsKCiAgaW50IGksajsKCiAgZm9yKGk9MDtpPHJvdztpKyspeyAgCiAgICBmb3Ioaj0wO2o8Y29sO2orKyl7CiAgICAgY291dCA8PCBjW2ldW2pdPDwgIiAiOwogICAgfQogIGNvdXQgPDwgZW5kbDsKICB9Cgp9Cgp2b2lkIHByaW50KGZsb2F0IGZbTl1bTl0sIGludCByb3csIGludCBjb2wpCnsKCiAgaW50IGksajsKCiAgZm9yKGk9MDtpPHJvdztpKyspeyAgCiAgICBmb3Ioaj0wO2o8Y29sO2orKyl7CiAgICAgc3RkOjpjb3V0IDw8IHN0ZDo6Zml4ZWQgPDwgc3RkOjpzZXRwcmVjaXNpb24oMykgPDwgc2V0dygxNSkgPDwgZltpXVtqXSA7CiAgICB9CiAgY291dCA8PCBlbmRsOwogIH0KCn0KCnZvaWQgY29tcGFyZShjaGFyIHBsYWluX3RleHRbTl0sY2hhciBkZWNyeXB0X3BsYWluX3RleHRbTl0sIGludCBsZW5ndGhfb2ZfaW5wdXQpCnsKICBpbnQgbG9pOwogIGZvciAobG9pID0gMDsocGxhaW5fdGV4dFtsb2ldID09IGRlY3J5cHRfcGxhaW5fdGV4dFtsb2ldICYmIHBsYWluX3RleHRbbG9pXSk7bG9pKyspOwogIGlmKGxvaSA9PSBsZW5ndGhfb2ZfaW5wdXQpCiAgICBjb3V0IDw8ICJTVUNDRVNTIjw8ZW5kbDsKfQoKaW50IG1haW4oKSB7CgoJLyoqKioqKioqKioqIERPIE5PVCBDSEFOR0UgVkFSSUFCTEUgTkFNRVMgKioqKioqKioqKioqLwogICAgICAgIGNoYXIgcGxhaW5fdGV4dFtBUlJBWV9TSVpFXTsKICAgICAgICBpbnQgbWFya2VyOwoKICAgICAgICBmbG9hdCBrZXlbTl1bTl07CgogICAgICAgIGZsb2F0IGNpcGhlcl90ZXh0W05dW05dOwogICAgICAgIGZsb2F0IGludmtleVtOXVtOXTsKICAgICAgICBjaGFyIGRlY3J5cHRfcGxhaW5fdGV4dFtBUlJBWV9TSVpFXTsKICAgICAgICBjaGFyIGludl9tYXBwZWRfYXJyYXlbQVJSQVlfU0laRV07CgoJLyoqKioqKioqKioqKioqKkdldCBVc2VyIElucHV0KioqKioqKioqKioqKioqLwoKCiAgICAgICAgY291dCA8PCAiRW50ZXIgdGhlIHBsYWluIHRleHQiIDw8IGVuZGw7CiAgICAgICAgY2luID4+IHBsYWluX3RleHQ7CgogICAgICAgIGNvdXQgPDwgIkVudGVyIHRoZSBtYXJrZXIiIDw8IGVuZGw7CiAgICAgICAgY2luID4+IG1hcmtlcjsKICAgICAgICAKICAgICAgICAvLyBDcmVhdGluZyBhIGtleSBtYXRyaXggb2Ygc2l6ZSAobWFya2VyIHggbWFya2VyKQogICAgICAgIGtleWdlbihrZXksbWFya2VyKTsKCgogICAgICAgIC8qKioqKioqKioqKioqKipFbmQgVXNlciBJbnB1dCoqKioqKioqKioqKioqKi8JCgkKCQoJLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qLwoKCS8vIFBsZWFzZSBhZGQgeW91ciBjb2RlIGhlcmUgCiBpbnQgbGVuZ3RoX29mX2lucHV0OwogICAgICAgIGZvciAobGVuZ3RoX29mX2lucHV0ID0gMDtwbGFpbl90ZXh0W2xlbmd0aF9vZl9pbnB1dF07bGVuZ3RoX29mX2lucHV0KyspOwogICAgICAgaW50IHI7CiAgICAgICByPWxlbmd0aF9vZl9pbnB1dCVtYXJrZXI7CiAgICAgICBmb3IoaW50IGE9MDthPChsZW5ndGhfb2ZfaW5wdXQrbWFya2VyLXIpO2ErKykKICAgICAgIHsKICAgICAgIAlpZiAoYTxsZW5ndGhfb2ZfaW5wdXQpCiAgICAgICAJewoJCSAgIHBsYWluX3RleHRfemVyb19wYWRkZWRbYV09cGxhaW5fdGV4dFthXTsKCQkgICB9CgkJICAgZWxzZXsKCQkgICAKICAgICAgIAlwbGFpbl90ZXh0X3plcm9fcGFkZGVkW2FdPTA7CiAgICAgICB9CgkgICB9CnZvaWQgYXJyYXlfbWFwKG1hcHBlZF9hcnJheSxwbGFpbl90ZXh0X3plcm9fcGFkZGVkKTsKY2hhciBtYXBwZWRbQVJSQVlfU0laRV1bTl07CmludCB6PTA7CmZvciggaW50IGU9MDtlPChsZW5ndGhfb2ZfaW5wdXQvbWFya2VyKSsxO2UrKykKewoJZm9yKGludCBmPTA7ZjxtYXJrZXI7ZisrKQoJewoJCW1hcHBlZFtlXVtmXT1tYXBwZWRfYXJyYXlbel07CgkJeisrOwoJfQp9CgoKCmZvciAoaW50IGI9MDtiPChsZW5ndGhfb2ZfaW5wdXQvbWFya2VyKSsxO2IrKykKewoJZm9yKGludCBjPTA7YzxtYXJrZXI7YysrKQoJewoJCWNpcGhlcl90ZXh0W2JdW2NdPTA7CgkJZm9yKGludCBkPTA7ZDxtYXJrZXI7ZCsrKQoJCWNpcGhlcl90ZXh0W2JdW2NdKz1tYXBwZWRbYl1bZF0qa2V5W2RdW2NdOwoJfQp9CmNoYXIgcmV2X21hcHBlZFtBUlJBWV9TSVpFXVtOXTsKdm9pZCBpbnZlcnNlKGludmtleSxrZXksbWFya2VyKTsKZm9yKGludCBvPTA7bzwobGVuZ3RoX29mX2lucHV0L21hcmtlcikrMTtvKyspCnsKCWZvcihpbnQgcD0wO3A8bWFya2VyO3ArKykKCXsKCQlyZXZfbWFwcGVkW29dW3BdPTA7CgkJZm9yKGludCBxPTA7cTxtYXJrZXI7cSsrKQoJCXJldl9tYXBwZWRbb11bcF0rPWNpcGhlcl90ZXh0W29dW3FdKmludmtleVtxXVtwXTsKCX0KfQppbnQgeT0wOwpmb3IoIGludCBlPTA7ZTwobGVuZ3RoX29mX2lucHV0L21hcmtlcikrMTtlKyspCnsKCWZvcihpbnQgZj0wO2Y8bWFya2VyO2YrKykKCXsKCQlpbnZfbWFwcGVkX2FycmF5W3ldPXJldl9tYXBwZWRbZV1bZl07CgkJeSsrOwoJfQp9CnZvaWQgaW52X2FycmF5X21hcCggaW52X21hcHBlZF9hcnJheSwgIGRlY3J5cHRfcGxhaW5fdGV4dF96ZXJvX3BhZGRlZCk7CgoKCgoKCgoKCgoKICAgICAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovCiAgICAgICAgLy8gIERvbm90IG1vZGlmeSAKICAgICAgICAvLwogICAgICAgCiAgICAgICAgY291dCA8PCAiUGxhaW4gVGV4dCBlbnRlcmVkIiA8PCBlbmRsOwogICAgICAgIGNvdXQgPDwgcGxhaW5fdGV4dDw8ICJcbiI7CiAgICAgICAKICAgICAgICBjb3V0IDw8ICJLZXkgVXNlZCIgPDwgZW5kbDsKICAgICAgICBwcmludChrZXksbWFya2VyLG1hcmtlcik7CiAgICAgICAgCiAgICAgICAgY291dCA8PCAiQ2lwaGVyIFRleHQgIiA8PCBlbmRsOwogICAgICAgIHByaW50KGNpcGhlcl90ZXh0LChpbnQpY2VpbCgoZmxvYXQpbGVuZ3RoX29mX2lucHV0L21hcmtlciksbWFya2VyKTsKCiAgICAgICAgY291dCA8PCAiS2V5IEludmVyc2UiIDw8IGVuZGw7CiAgICAgICAgcHJpbnQoaW52a2V5LG1hcmtlcixtYXJrZXIpOwogICAgICAgIAogICAgICAgIGNvdXQgPDwgIkRlY3J5cHRlZCBUZXh0IiA8PCBlbmRsOwogICAgICAgIGNvdXQgPDwgZGVjcnlwdF9wbGFpbl90ZXh0IDw8ICJcbiI7CgogICAgICAgIGNvbXBhcmUocGxhaW5fdGV4dCxkZWNyeXB0X3BsYWluX3RleHQsbGVuZ3RoX29mX2lucHV0KTsKICAgICAgICAgICAgCglyZXR1cm4gMDsKfQoKCg==