Introduction
The objective of this work is to create a model that can identify a number written by hand and recognize which is the number it represents. In order to tran the model I used the Mnist Dataset, more information is here: http://yann.lecun.com/exdb/mnist/.
The MNIST database of handwritten digits, has a training set of 60,000 examples, and a test set of 10,000 examples. It is a subset of a larger set available from NIST. The digits have been size-normalized and centered in a fixed-size image.
The model I used to recognize caracters is a prototype of a Digit Recognizer using a specific Fourier Transform, called Walsh Hadamard Transform, a connected component transform, some Kpi’s from each training image, principal component analysis and a feed forward Neural Nework with a hidden Layer that taes all the inputs and trains the weights of its connections to improve the predicted numbers.
In the following chunks I’ll describe step by step the process.
KPI Calculation
In the following lines I will explain all the inputs used for the Neural Network. Is important to clarify that the neural network cannot take as an input the raw images, we need to constract a set of key performance indicators, that differenciate each image from the rest and be different enough not to duplicate information.
Sums per row and per column
In these 2 kpi’s we generate per image (hich as 28 pixels by 28 pixels), the sum of pixels per column and per row. As an Example we can see the sum of columns and rows for an example. In the axes, the sum of rows and the sum of columns is represented, transformed into a vector of colors for better comprehension. When the color is closer to the white, the sum for that specific column or row is bigger, when the color is darker, the sum is lower.

Dual Images
In the following 2 KPI’s we take each number and we duplicate the a part of it, like making a mirror. This Kpi will help us identify characters which its first half is the same as the second half. For example, the 0 and the 8 in both directions or the 3 in the vertical mirror.
As an example we see the original picture and the dual picture of a character 3.

With this KPI’s already generated we are ready now to move into the Neural Network parameter generation process.
Parameters Generation
1: H30
For this parameter we generate the sum of pixels for the first 30% of rows of each number.

For this image the Row sum H30 is 34.
2. H50
For this parameter we generate the sum of pixels for the first 50% of rows of each number.

For this image the Row sum H50 is 48.
3. H80
For this parameter we generate the sum of pixels for the first 80% of rows of each number.

For this image the Row sum H80 is 117.
4. V30
For this parameter we generate the sum of pixels for the first 30% of columns of each number.

For this image the column sum V80 is 11.
5. V50
For this parameter we generate the sum of pixels for the first 50% of columns of each number.

For this image the column sum V50 is 46.
6. V80
For this parameter we generate the sum of pixels for the first 80% of columns of each number.

For this image the column sum V80 is 69.
7. Horizontal Similarity
Correlation between an input character sample ‘I’ with its horizontal mirror ‘X’. It should be noted that ‘X’ is generated from ‘I’ where lower half of ‘X’ is same as that of ‘I’ and upper half of ‘X’ is the mirror image of its lower half.

For example, here we plot 2 binarized imageS and its correspondant mirrorS. For the image in the top the correlation is 0.73 and for the image in the botton the correlation is 0.67.
8. Vertical Similarity
Correlation between an input character sample (I) and its Vertical mirror (X). It should be noted that ‘X’ is generated from ‘I’ where left half of ‘X’ is same as that of ‘I’ and right half of ‘X’ is the mirror image of its left half.

For example, here we plot 2 binarized images and its correspondant mirrors. For the image in the top the correlation is 0.75 and for the image in the botton the correlation is 0.5.
##9.Walsh-Hadamard transform##
WHT DataBase Generation
In order to be able to use the Walsh-Hadamard Transformation we need to compare each image with defailt number images. Because of this I created 10 default number images and generated the Walsh-Hadamard Transformation to each of them.

WHT Compare
I need to compare de correlation of the denoted image with the WHT DataBase. For example for a given image, I show the image and the 10 correlations to each of the default characters.

For this image the correlation to each character is:
0.41 |
0.13 |
0.32 |
0.22 |
0.3 |
0.28 |
0.44 |
0.14 |
0.29 |
0.27 |
As we can see the WHT get a good approximation to the number we are looking for. In tihs case it puts the zero as a second choice, but very close to the first place, where the number 6 is.
11.Principal Component Analysis
We have 28x28 pixels per image. Most of them are 0 for each image. So we can say that most of them give us no information regarding which number weneed to predict. We will enhage a Principal Component Analysis to try to figure out which are the principal Components of the dataset that absorb the maximum variance. After this we will add this prdictors to the Nnet Input.
We apply PCA to the coviariance matrix and check how many components should we keep.

Acording to the plot we keep the first 15 components, which represent almost 90% of the variance, to fit the model.
train_score <- as.matrix(training) %*% train_pc$rotation[,1:15]
Final Data Set
Data: Dataset of all the calculated kpi’s per photo.
We show the names of the variables of the Data set.
In the following graphs we can see a density plot per varable taking into account the number it represents.




Train and Test
In this step we scale all the variables and we center them so that there is no weight difference between them, so that all variables have the same initial importance. This is a key step for the neural network training to succeed. We also create train and test partitions of the data.
I show a couple of rows to see the final Data set in action.
Neural Network
In this step we train the Neural network.
For this specific training set, I’ve choosen a neural network with 1 hidden layer with 22 nodes. This election was done after testing the nnet with a several diferent numbers of nodes for the hidden layer. I’ve tried with 10 nodes, to 28 and the best accuracy for the model was obteined with 24 nodes.
Model Results:
my.grid6 <- expand.grid(.decay = c(0.5), .size = c(22))
train_control <- trainControl(method="repeatedcv", number=10, repeats=3)
numbers.fit6 <- train(label ~ ., data = numbers.traintotal,method = "nnet", maxit = 1000, trContor=train_control,tuneGrid = my.grid6, trace = F, linout = 1)
Plot Neural Network

Neural Network
42000 samples
34 predictor
10 classes: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
No pre-processing
Resampling: Bootstrapped (25 reps)
Summary of sample sizes: 42000, 42000, 42000, 42000, 42000, 42000, ...
Resampling results:
Accuracy Kappa
0.9566663 0.9518345
Tuning parameter 'size' was held constant at a value of 22
Tuning parameter 'decay'
was held constant at a value of 0.5
Test Set Predictions table
For the test set we have a 97.1 % prediction accuracy.
Here we show the confusion matrix for the test set.

Good preditions
I’ll like to show some images of good predictions:

Bad preditions
And also some pictures of bad predicted caracters with the predicted character in little black font.

As we can see in the previuos graph, the badly predicted characters are not easy to distinguish and even for a person its hard to recognize.
LS0tDQp0aXRsZTogIkRpZ2l0IFJlY29nbml6ZXIiDQphdXRob3I6ICJGYWN1bmRvIENhbGNhZ25vIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiANCiAgICBoaWdobGlnaHQ6IGthdGUNCiAgICB0aGVtZTogY29zbW8NCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogMQ0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KI0ludHJvZHVjdGlvbiMNCg0KVGhlIG9iamVjdGl2ZSBvZiB0aGlzIHdvcmsgaXMgdG8gY3JlYXRlIGEgbW9kZWwgdGhhdCBjYW4gaWRlbnRpZnkgYSBudW1iZXIgd3JpdHRlbiBieSBoYW5kIGFuZCByZWNvZ25pemUgd2hpY2ggaXMgdGhlIG51bWJlciBpdCByZXByZXNlbnRzLiBJbiBvcmRlciB0byB0cmFuIHRoZSBtb2RlbCBJIHVzZWQgdGhlIE1uaXN0IERhdGFzZXQsIG1vcmUgaW5mb3JtYXRpb24gaXMgaGVyZTogaHR0cDovL3lhbm4ubGVjdW4uY29tL2V4ZGIvbW5pc3QvLg0KDQpUaGUgTU5JU1QgZGF0YWJhc2Ugb2YgaGFuZHdyaXR0ZW4gZGlnaXRzLCAgaGFzIGEgdHJhaW5pbmcgc2V0IG9mIDYwLDAwMCBleGFtcGxlcywgYW5kIGEgdGVzdCBzZXQgb2YgMTAsMDAwIGV4YW1wbGVzLiBJdCBpcyBhIHN1YnNldCBvZiBhIGxhcmdlciBzZXQgYXZhaWxhYmxlIGZyb20gTklTVC4gVGhlIGRpZ2l0cyBoYXZlIGJlZW4gc2l6ZS1ub3JtYWxpemVkIGFuZCBjZW50ZXJlZCBpbiBhIGZpeGVkLXNpemUgaW1hZ2UuIA0KDQpUaGUgbW9kZWwgSSB1c2VkIHRvIHJlY29nbml6ZSBjYXJhY3RlcnMgaXMgYSBwcm90b3R5cGUgb2YgYSBEaWdpdCBSZWNvZ25pemVyIHVzaW5nIGEgc3BlY2lmaWMgRm91cmllciBUcmFuc2Zvcm0sIGNhbGxlZCBXYWxzaCBIYWRhbWFyZCBUcmFuc2Zvcm0sIGEgY29ubmVjdGVkIGNvbXBvbmVudCB0cmFuc2Zvcm0sIHNvbWUgS3BpJ3MgZnJvbSBlYWNoIHRyYWluaW5nIGltYWdlLCBwcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIGFuZCBhIGZlZWQgZm9yd2FyZCBOZXVyYWwgTmV3b3JrIHdpdGggYSBoaWRkZW4gTGF5ZXIgdGhhdCB0YWVzIGFsbCB0aGUgaW5wdXRzIGFuZCB0cmFpbnMgdGhlIHdlaWdodHMgb2YgaXRzIGNvbm5lY3Rpb25zIHRvIGltcHJvdmUgdGhlIHByZWRpY3RlZCBudW1iZXJzLg0KDQpJbiB0aGUgZm9sbG93aW5nIGNodW5rcyBJJ2xsIGRlc2NyaWJlIHN0ZXAgYnkgc3RlcCB0aGUgcHJvY2Vzcy4NCg0KICANCmBgYHtyIGRhdGFpLCBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwcm90bykNCmxpYnJhcnkocmVhZHIpDQp0cmFpbiA8LSBkYXRhLmZyYW1lKHJlYWRfY3N2KCJkYXRhL3RyYWluLmNzdiIpKQ0KYGBgDQoNCiNCaW5hcml6YXRpb24gb2YgdGhlIGlucHV0DQoNCkVhY2ggaW1hZ2UgaW4gdGhlIGRhdGFzZXQgaXMgYSBidW5jaCBvZiBwaXhlbHMgam9pbnQgdG9nZXRoZXIgaW4gYSBtYXRyaXguIFRoaXMgbWF0cml4IGNhbiBiZSByZXByZXNlbnRlZCBieSAyOCByb3dzIHRvIDI4IGNvbHVtbnMgb2YgcGl4ZWxzLiBBcyB0aGUgdHJhaW5naW5nIHBpY3R1cmVzIGFyZSBibGFjayBhbmQgd2hpdGUsICBlYWNoIHBpeGVsIGlzIGEgbnVtYmVyIHRoYXQgZ29lcyBmcm9tIDAgdG8gMjU1LCBpdCBjb3VsZCBiZSBzYWlkIHRoYXQgZWFjaCBwaXhlbCBpcyBpbiB0aGUgZ3JleSBzcGFjZS4gSW4gb3JkZXIgdG8gYmUgYWJsZSB0byB3b3JrIHdpdGggdGhlIGRhdGEgd2UgbmVlZCB0byBiaW5hcml6ZSB0aGUgaW5wdXQsIGluIG90aGVyIHdvcmRzLCB0YWtlIHRob3NlIHZhbHVlcyBmcm9tIDAgdG8gMjU1IGFuZCBkZWNpZGUgcGl4ZWwgYnkgcGl4ZWwgaWYgaXQgaXMgYSAwIG9yIGEgMS4gICANCg0KYGBge3IgaW5wdXQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0UsIGNhY2hlPVRSVUV9DQojVmlzdWFsaXphdGlvbiANCnNldC5zZWVkKDcxKQ0KbjE9bnJvdyh0cmFpbikNCmRhdGE8LXRyYWluDQpwYXIobWZyb3c9YygxMCwxMCksbWFyPWMoMC4xLDAuMSwwLjEsMC4xKSkNCmRhdG9zPC1saXN0KCkNCm9yaWdpbmFsPC1saXN0KCkNCg0KbD0wDQpmb3IgKGsgaW4gMTpuMSkNCnsNCiAgICBsPWwrMQ0KICAgcm93IDwtIE5VTEwNCiAgICBmb3IgKG4gaW4gMjo3ODUpDQogICAgICAgIHJvd1tuLTFdIDwtIHRyYWluW2ssbi0xXQ0KICAgICBtYXRyaXgxIDwtIG1hdHJpeChyb3csMjgsMjgsYnlyb3c9RkFMU0UpDQogICAgIG1hdHJpeDIgPC0gbWF0cml4KHJlcCgwLDc4NCksMjgsMjgpDQogICAgIG1hdHJpeDMgPC0gbWF0cml4KHJlcCgwLDc4NCksMjgsMjgpDQogICANCiAgICBmb3IgKGkgaW4gMToyOCkNCiAgICAgICAgZm9yIChqIGluIDE6MjgpDQogICAgICAgIHsNCiAgICAgICAgICAgbWF0cml4M1tpLDI4LWorMV08LW1hdHJpeDFbaSxqXQ0KICAgICAgICAgIGlmIChtYXRyaXgxW2ksal0+MTAwKSBtYXRyaXgyW2ksMjgtaisxXTwtMSANCiAgICAgICAgfQ0KICAgICAgICAgZGF0b3NbW2xdXTwtbWF0cml4Mg0KICAgICAgICAgb3JpZ2luYWxbW2xdXTwtbWF0cml4Mw0KICAgIA0KDQp9DQoNCmBgYA0KDQpJbiB0aGlzIHR3byBzZXQgb2YgaW1hZ2VzIHdlIGNhbiBzZWUgYW5kIGV4YW1wbGUgb2YgaG93IHRoZSBiaW5hcml6YXRpb24gdGFrZXMgcGxhY2UuIEluIHRoZSB1cHBlciBpbWFnZXMgdGhlIHJhdyBkYXRhLCBhbmQgaW4gdGhlIHNlY29uZCBzZXQgb2YgcGl6ZWxzIHRoZSBiaW5hcml6ZWQgZGF0YS4NCg0KIyMjT3JpZ2luYWwgSW1hZ2VzIyMjDQpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBhcihtZnJvdz1jKDUsMTApLG1hcj1jKC4xLC4xLC4xLC4xKSkNCmZvciAoaSBpbiAxOjUwKSB7DQogIGltYWdlKG9yaWdpbmFsW1tpXV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygxMCkpDQp9DQpgYGANCiMjI0JpbmFyaXplZCBJbWFnZXMjIyMNCmBgYHtyIGJpbmFyZSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBhcihtZnJvdz1jKDUsMTApLG1hcj1jKC4xLC4xLC4xLC4xKSkNCmZvciAoaSBpbiAxOjUwKSB7DQogIGltYWdlKGRhdG9zW1tpXV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygxMCkpDQp9DQpgYGANCg0KDQpBcyB3ZSBjYW4gc2VlIEkgaGFkIHRvIGNob29zZSBhIHRocmVzaG9sZCAgZm9yIGV2ZXJ5IHBpeGVsIGluIG9yZGVyIHRvIGJlIGEgMSBvciBhIDAuIEFmdGVyIHNldmVyYWwgdHJ5b3V0cywgdGhlIGNob29zZW4gbnVtYmVyIHdhcyAxMDAgb3V0IG9mIDI1NS4gVGhpcyBudW1iZXIgZ2F2ZSBtZSBhIGdvb2Qgc3RhcnQgdG8gYmluYXJpemF0ZSBlYWNoIGltYWdlIHdpdGhvdXQgYSBtYWpvciBpbmZvcm1hdGlvbiBsb3NzLg0KDQojS1BJIENhbGN1bGF0aW9uIw0KDQpJbiB0aGUgZm9sbG93aW5nIGxpbmVzIEkgd2lsbCBleHBsYWluIGFsbCB0aGUgaW5wdXRzIHVzZWQgZm9yIHRoZSBOZXVyYWwgTmV0d29yay4gSXMgaW1wb3J0YW50IHRvIGNsYXJpZnkgdGhhdCB0aGUgbmV1cmFsIG5ldHdvcmsgY2Fubm90IHRha2UgYXMgYW4gaW5wdXQgdGhlIHJhdyBpbWFnZXMsIHdlIG5lZWQgdG8gY29uc3RyYWN0IGEgc2V0IG9mIGtleSBwZXJmb3JtYW5jZSBpbmRpY2F0b3JzLCB0aGF0IGRpZmZlcmVuY2lhdGUgZWFjaCBpbWFnZSBmcm9tIHRoZSByZXN0IGFuZCBiZSBkaWZmZXJlbnQgZW5vdWdoIG5vdCB0byBkdXBsaWNhdGUgaW5mb3JtYXRpb24uIA0KDQojI1N1bXMgcGVyIHJvdyBhbmQgcGVyIGNvbHVtbiMjDQpJbiB0aGVzZSAyIGtwaSdzIHdlIGdlbmVyYXRlIHBlciBpbWFnZSAoaGljaCBhcyAyOCBwaXhlbHMgYnkgMjggcGl4ZWxzKSwgdGhlIHN1bSBvZiBwaXhlbHMgcGVyIGNvbHVtbiBhbmQgcGVyIHJvdy4gQXMgYW4gRXhhbXBsZSB3ZSBjYW4gc2VlIHRoZSBzdW0gb2YgY29sdW1ucyBhbmQgcm93cyBmb3IgYW4gZXhhbXBsZS4NCkluIHRoZSBheGVzLCB0aGUgc3VtIG9mIHJvd3MgYW5kIHRoZSBzdW0gb2YgY29sdW1ucyBpcyByZXByZXNlbnRlZCwgdHJhbnNmb3JtZWQgaW50byBhIHZlY3RvciBvZiBjb2xvcnMgZm9yIGJldHRlciBjb21wcmVoZW5zaW9uLiANCldoZW4gdGhlIGNvbG9yIGlzIGNsb3NlciB0byB0aGUgd2hpdGUsIHRoZSBzdW0gZm9yIHRoYXQgc3BlY2lmaWMgY29sdW1uIG9yIHJvdyBpcyBiaWdnZXIsIHdoZW4gdGhlIGNvbG9yIGlzIGRhcmtlciwgdGhlIHN1bSAgaXMgbG93ZXIuDQoNCmBgYHtyIHN1bSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyNzdW0gcGVyIGNvbHVtbg0KDQpzdW0xPC1tYXRyaXgocmVwKDAsMjgpLDI4KQ0Kcm93czwtbGlzdCgpDQoNCmZvciAoayBpbiAxOm4xKQ0Kew0KICBpbWFnZTwtZGF0b3NbW2tdXQ0KICAgZm9yIChpIGluIDE6MjgpDQogIHsNCiAgICAgICAgICBzdW0xW2ldPC0wDQogICAgICAgICAgIGZvciAoaiBpbiAxOjI4KQ0KICAgICAgICAgIHsNCiAgICAgICAgICAgICBzdW0xW2ldPC1zdW0xW2ldK2ltYWdlW2ksal0NCiAgICAgICAgICANCiAgICAgICAgICB9DQogICB9DQogIHJvd3NbW2tdXTwtc3VtMQ0KfQ0KDQojI3N1bSBwZXIgUm93DQoNCnN1bTE8LW1hdHJpeChyZXAoMCwyOCksMjgpDQpjb2x1bW5zPC1saXN0KCkNCg0KZm9yIChrIGluIDE6bjEpDQp7DQogIGltYWdlPC1kYXRvc1tba11dDQogICBmb3IgKGkgaW4gMToyOCkNCiAgew0KICAgICAgICAgIHN1bTFbaV08LTANCiAgICAgICAgICAgZm9yIChqIGluIDE6MjgpDQogICAgICAgICAgew0KICAgICAgICAgICAgIHN1bTFbaV08LXN1bTFbaV0raW1hZ2VbaixpXQ0KICAgICAgICAgIA0KICAgICAgICAgIH0NCiAgIH0NCiAgY29sdW1uc1tba11dPC1zdW0xDQp9DQpwYXIobWZyb3c9YygyLDIpLG1hcj1jKC4xLC4xLC41LC41KSkNCmxheW91dChtYXRyaXgoYygxLDIsMyw0KSwgMiwgMiwgYnlyb3cgPSBUUlVFKSx3aWR0aHM9YygxLDYpLCBoZWlnaHRzPWMoMSw2KSkNCmltYWdlKG1hdHJpeChyZXAoMCwyKSksY29sPWdyZXkuY29sb3JzKDEwKSkNCmltYWdlKG1hdHJpeChyb3dzW1sxMF1dLCBuY29sPTEpLGNvbD1ncmV5LmNvbG9ycygxMCkpDQppbWFnZShtYXRyaXgoY29sdW1uc1tbMTBdXSwgbnJvdz0xKSxjb2w9Z3JleS5jb2xvcnMoMTApKQ0KaW1hZ2UoZGF0b3NbWzEwXV0sIGF4ZXM9VFJVRSwgY29sPWdyZXkuY29sb3JzKDEwKSkgDQoNCg0KYGBgDQoNCiMjIER1YWwgSW1hZ2VzIyMNCkluIHRoZSBmb2xsb3dpbmcgMiBLUEkncyB3ZSB0YWtlIGVhY2ggbnVtYmVyIGFuZCB3ZSBkdXBsaWNhdGUgdGhlIGEgcGFydCBvZiBpdCwgbGlrZSBtYWtpbmcgYSBtaXJyb3IuIA0KVGhpcyBLcGkgd2lsbCBoZWxwIHVzIGlkZW50aWZ5IGNoYXJhY3RlcnMgd2hpY2ggaXRzIGZpcnN0IGhhbGYgaXMgdGhlIHNhbWUgYXMgdGhlIHNlY29uZCBoYWxmLiBGb3IgZXhhbXBsZSwgdGhlIDAgYW5kIHRoZSA4IGluIGJvdGggZGlyZWN0aW9ucyBvciB0aGUgMyBpbiB0aGUgdmVydGljYWwgbWlycm9yLg0KDQpBcyBhbiBleGFtcGxlIHdlIHNlZSB0aGUgb3JpZ2luYWwgcGljdHVyZSBhbmQgdGhlIGR1YWwgcGljdHVyZSBvZiBhIGNoYXJhY3RlciAzLg0KDQpgYGB7ciBEdWFsLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojR2VuZXJhdGUgZHVhbCBpbWFnZSBieSByb3cNCmR1YWxfcm93PC1saXN0KCkNCmZvciAoayBpbiAxOm4xKQ0Kew0KICBpbWFnZTwtZGF0b3NbW2tdXQ0KICBkdWFsX2ltYWdlPC1pbWFnZQ0KICBmb3IgKGkgaW4gMToyOCkgew0KICAgIGZvciAoaiBpbiAxOjE0KSB7DQogICAgICBkdWFsX2ltYWdlW2ksal08LWltYWdlW2ksal0NCiAgICAgIGR1YWxfaW1hZ2VbaSwyOS1qXTwtaW1hZ2VbaSxqXQ0KICAgIH0NCiAgfQ0KICBkdWFsX3Jvd1tba11dPC1kdWFsX2ltYWdlDQp9DQoNCmR1YWxfY29sPC1saXN0KCkNCmZvciAoayBpbiAxOm4xKQ0Kew0KICBpbWFnZTwtZGF0b3NbW2tdXQ0KICBkdWFsX2ltYWdlPC1pbWFnZQ0KICBmb3IgKGogaW4gMToyOCkgew0KICAgIGZvciAoaSBpbiAxOjE0KSB7DQogICAgICBkdWFsX2ltYWdlW2ksal08LWltYWdlW2ksal0NCiAgICAgIGR1YWxfaW1hZ2VbMjktaSxqXTwtaW1hZ2VbaSxqXQ0KICAgIH0NCiAgfQ0KICBkdWFsX2NvbFtba11dPC1kdWFsX2ltYWdlDQp9DQpwYXIobWZyb3c9YygxLDMpKQ0KaW1hZ2UoZGF0b3NbWzhdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIk9yaWdpbmFsIiwgZm9udC5zdWIgPSAyLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmltYWdlKGR1YWxfY29sW1s4XV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJDb2x1bW4gbWlycm9yIiwgZm9udC5zdWIgPSAyICwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQppbWFnZShkdWFsX3Jvd1tbOF1dLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiUm93IG1pcnJvciIsIGZvbnQuc3ViID0gMiwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQpgYGANCg0KV2l0aCB0aGlzIEtQSSdzIGFscmVhZHkgZ2VuZXJhdGVkIHdlIGFyZSByZWFkeSBub3cgdG8gbW92ZSBpbnRvIHRoZSBOZXVyYWwgTmV0d29yayBwYXJhbWV0ZXIgZ2VuZXJhdGlvbiBwcm9jZXNzLg0KDQoNCiNQYXJhbWV0ZXJzIEdlbmVyYXRpb24jDQoNCiMjMTogSDMwIyMNCg0KRm9yIHRoaXMgcGFyYW1ldGVyIHdlIGdlbmVyYXRlIHRoZSBzdW0gb2YgcGl4ZWxzIGZvciB0aGUgZmlyc3QgMzAlIG9mIHJvd3Mgb2YgZWFjaCBudW1iZXIuDQoNCmBgYHtyIEgzMCwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkgzMDwtbGlzdCgpDQphPSByb3VuZCgyOC8zKQ0KZm9yIChrIGluIDE6bjEpDQp7DQogIHN1bT0wDQogIGZvciAoaiBpbiAxOmEpDQogIHsNCiAgIHN1bT1zdW0rY29sdW1uc1tba11dW2pdDQogIH0NCiAgSDMwW1trXV08LXN1bQ0KfQ0KcGFyKG1mcm93PWMoMSwyKSkNCmltYWdlKGRhdG9zW1s4XV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCiNsYXlvdXQobWF0cml4KGMoMSwyLDMsNCksIDIsIDIsIGJ5cm93ID0gVFJVRSksd2lkdGhzPWMoMSwxKSwgaGVpZ2h0cz1jKDMsMSkpDQp0aXRsZShzdWIgPSAiT3JpZ2luYWwiLCBmb250LnN1YiA9IDIsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KI2ltYWdlKG1hdHJpeChyZXAoMCwyKSksY29sPWdyZXkuY29sb3JzKDEwKSkNCmltYWdlKGRhdG9zW1s4XV1bLDE6YV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJSb3cgc3VtIEgzMCIsIGZvbnQuc3ViID0gMiAsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KYGBgDQpGb3IgdGhpcyBpbWFnZSB0aGUgUm93IHN1bSBIMzAgaXMgYHIgSDMwW1s4XV1gLg0KDQojIzIuIEg1MCMjDQoNCkZvciB0aGlzIHBhcmFtZXRlciB3ZSBnZW5lcmF0ZSB0aGUgc3VtIG9mIHBpeGVscyBmb3IgdGhlIGZpcnN0IDUwJSBvZiByb3dzIG9mIGVhY2ggbnVtYmVyLg0KYGBge3IgSDUwLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KSDUwPC1saXN0KCkNCmE9IHJvdW5kKDI4LzIpDQpmb3IgKGsgaW4gMTpuMSkNCnsNCiAgc3VtPTANCiAgZm9yIChqIGluIDE6YSkNCiAgew0KICAgc3VtPXN1bStjb2x1bW5zW1trXV1bal0NCiAgfQ0KICBINTBbW2tdXTwtc3VtDQp9DQoNCnBhcihtZnJvdz1jKDEsMikpDQppbWFnZShkYXRvc1tbMjBdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIk9yaWdpbmFsIiwgZm9udC5zdWIgPSAyLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmltYWdlKGRhdG9zW1syMF1dWywxOmFdLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiUm93IHN1bSBINTAiLCBmb250LnN1YiA9IDIgLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmBgYA0KRm9yIHRoaXMgaW1hZ2UgdGhlIFJvdyBzdW0gSDUwIGlzIGByIEg1MFtbOF1dYC4NCg0KIyMzLiBIODAjIw0KDQpGb3IgdGhpcyBwYXJhbWV0ZXIgd2UgZ2VuZXJhdGUgdGhlIHN1bSBvZiBwaXhlbHMgZm9yIHRoZSBmaXJzdCA4MCUgb2Ygcm93cyBvZiBlYWNoIG51bWJlci4NCmBgYHtyIEg4MCwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkg4MDwtbGlzdCgpDQphPSByb3VuZCgyOC8xLjI1KQ0KZm9yIChrIGluIDE6bjEpDQp7DQogIHN1bT0wDQogIGZvciAoaiBpbiAxOmEpDQogIHsNCiAgIHN1bT1zdW0rY29sdW1uc1tba11dW2pdDQogIH0NCiAgSDgwW1trXV08LXN1bQ0KfQ0KcGFyKG1mcm93PWMoMSwyKSkNCmltYWdlKGRhdG9zW1syNV1dLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiT3JpZ2luYWwiLCBmb250LnN1YiA9IDIsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KaW1hZ2UoZGF0b3NbWzI1XV1bLDE6YV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJSb3cgc3VtIEg4MCIsIGZvbnQuc3ViID0gMiAsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KDQpgYGANCkZvciB0aGlzIGltYWdlIHRoZSBSb3cgc3VtIEg4MCBpcyBgciBIODBbWzI1XV1gLg0KDQojIzQuIFYzMCMjDQoNCkZvciB0aGlzIHBhcmFtZXRlciB3ZSBnZW5lcmF0ZSB0aGUgc3VtIG9mIHBpeGVscyBmb3IgdGhlIGZpcnN0IDMwJSBvZiBjb2x1bW5zIG9mIGVhY2ggbnVtYmVyLg0KYGBge3IgVjMwLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KVjMwPC1saXN0KCkNCmE9IHJvdW5kKDI4LzMpDQpmb3IgKGsgaW4gMTpuMSkNCnsNCiAgc3VtPTANCiAgZm9yIChqIGluIDE6YSkNCiAgew0KICAgc3VtPXN1bStyb3dzW1trXV1bal0NCiAgfQ0KICBWMzBbW2tdXTwtc3VtDQp9DQpwYXIobWZyb3c9YygxLDIpKQ0KaW1hZ2UoZGF0b3NbWzI1XV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJPcmlnaW5hbCIsIGZvbnQuc3ViID0gMiwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQppbWFnZShkYXRvc1tbMjVdXVsxOmEsXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIkNvbHVtbiBzdW0gVjMwIiwgZm9udC5zdWIgPSAyICwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQoNCmBgYA0KRm9yIHRoaXMgaW1hZ2UgdGhlIGNvbHVtbiBzdW0gVjgwIGlzIGByIFYzMFtbMjVdXWAuDQoNCiMjNS4gVjUwIyMNCg0KRm9yIHRoaXMgcGFyYW1ldGVyIHdlIGdlbmVyYXRlIHRoZSBzdW0gb2YgcGl4ZWxzIGZvciB0aGUgZmlyc3QgNTAlIG9mIGNvbHVtbnMgb2YgZWFjaCBudW1iZXIuDQpgYGB7ciBWNTAsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpWNTA8LWxpc3QoKQ0KYT0gcm91bmQoMjgvMikNCmZvciAoayBpbiAxOm4xKQ0Kew0KICBzdW09MA0KICBmb3IgKGogaW4gMTphKQ0KICB7DQogICBzdW09c3VtK3Jvd3NbW2tdXVtqXQ0KICB9DQogIFY1MFtba11dPC1zdW0NCn0NCg0KcGFyKG1mcm93PWMoMSwyKSkNCmltYWdlKGRhdG9zW1szNV1dLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiT3JpZ2luYWwiLCBmb250LnN1YiA9IDIsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KaW1hZ2UoZGF0b3NbWzM1XV1bMTphLF0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJDb2x1bW4gc3VtIFY1MCIsIGZvbnQuc3ViID0gMiAsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KDQpgYGANCkZvciB0aGlzIGltYWdlIHRoZSBjb2x1bW4gc3VtIFY1MCBpcyBgciBWNTBbWzM1XV1gLg0KDQojIzYuIFY4MCMjDQoNCkZvciB0aGlzIHBhcmFtZXRlciB3ZSBnZW5lcmF0ZSB0aGUgc3VtIG9mIHBpeGVscyBmb3IgdGhlIGZpcnN0IDgwJSBvZiBjb2x1bW5zIG9mIGVhY2ggbnVtYmVyLg0KYGBge3IgVjgwLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KVjgwPC1saXN0KCkNCmE9IHJvdW5kKDI4LzEuMjUpDQpmb3IgKGsgaW4gMTpuMSkNCnsNCiAgc3VtPTANCiAgZm9yIChqIGluIDE6YSkNCiAgew0KICAgc3VtPXN1bStyb3dzW1trXV1bal0NCiAgfQ0KICBWODBbW2tdXTwtc3VtDQp9DQoNCnBhcihtZnJvdz1jKDEsMikpDQppbWFnZShkYXRvc1tbODFdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIk9yaWdpbmFsIiwgZm9udC5zdWIgPSAyLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmltYWdlKGRhdG9zW1s4MV1dWzE6YSxdLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiQ29sdW1uIHN1bSBWODAiLCBmb250LnN1YiA9IDIgLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCg0KYGBgDQpGb3IgdGhpcyBpbWFnZSB0aGUgY29sdW1uIHN1bSBWODAgaXMgYHIgVjgwW1s4MV1dYC4NCg0KDQojIzcuIEhvcml6b250YWwgU2ltaWxhcml0eSMjDQpDb3JyZWxhdGlvbiBiZXR3ZWVuIGFuIGlucHV0IGNoYXJhY3RlciBzYW1wbGUg4oCYSeKAmSB3aXRoIGl0cyBob3Jpem9udGFsIG1pcnJvciDigJhY4oCZLiBJdCBzaG91bGQgYmUgbm90ZWQgdGhhdCDigJhY4oCZIGlzIGdlbmVyYXRlZCBmcm9tIOKAmEnigJkgd2hlcmUgbG93ZXIgaGFsZiBvZiDigJhY4oCZIGlzIHNhbWUgYXMgdGhhdCBvZiDigJhJ4oCZIGFuZCB1cHBlciBoYWxmIG9mIOKAmFjigJkgaXMgdGhlIG1pcnJvciBpbWFnZSBvZiBpdHMgbG93ZXIgaGFsZi4NCg0KYGBge3IgSHN5bSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNXZSBoYXZlIHRvIGxvb2sgZm9yIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBtYXRyaXggZGF0b3MgYW5kIGR1YWxfcm93DQoNCkhzeW08LWxpc3QoKQ0KYT0gcm91bmQoMjgvMS4yNSkNCmZvciAoayBpbiAxOm4xKQ0Kew0KICBIc3ltW1trXV08LWNvcihjKGRhdG9zW1trXV0pLCBjKGR1YWxfcm93W1trXV0pKQ0KfQ0KYTwtZGF0YS5mcmFtZShkYXRvcz1jKGRhdG9zKSxkdWFsPWMoZHVhbF9yb3cpKQ0KDQpwYXIobWZyb3c9YygyLDIpKQ0KaW1hZ2UoZGF0b3NbWzE1XV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJPcmlnaW5hbCIsIGZvbnQuc3ViID0gMiwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQppbWFnZShkdWFsX3Jvd1tbMTVdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIlJvdyBtaXJyb3IiLCBmb250LnN1YiA9IDIgLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmltYWdlKGRhdG9zW1syMV1dLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiT3JpZ2luYWwiLCBmb250LnN1YiA9IDIsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KaW1hZ2UoZHVhbF9yb3dbWzIxXV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJSb3cgbWlycm9yIiwgZm9udC5zdWIgPSAyICwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQpgYGANCkZvciBleGFtcGxlLCBoZXJlIHdlIHBsb3QgMiBiaW5hcml6ZWQgaW1hZ2VTIGFuZCBpdHMgY29ycmVzcG9uZGFudCBtaXJyb3JTLiBGb3IgdGhlIGltYWdlIGluIHRoZSB0b3AgdGhlIGNvcnJlbGF0aW9uIGlzICBgciByb3VuZChIc3ltW1sxNV1dLDIpYCAgYW5kIGZvciB0aGUgaW1hZ2UgaW4gdGhlIGJvdHRvbiB0aGUgY29ycmVsYXRpb24gaXMgYHIgcm91bmQoSHN5bVtbMjFdXSwyKWAuDQoNCiMjOC4gVmVydGljYWwgU2ltaWxhcml0eSMjDQpDb3JyZWxhdGlvbiBiZXR3ZWVuIGFuIGlucHV0IGNoYXJhY3RlciBzYW1wbGUgKEkpIGFuZCBpdHMgVmVydGljYWwgbWlycm9yIChYKS4gIEl0IHNob3VsZCBiZSBub3RlZCB0aGF0IOKAmFjigJkgaXMgZ2VuZXJhdGVkIGZyb20g4oCYSeKAmSB3aGVyZSBsZWZ0IGhhbGYgb2Yg4oCYWOKAmSBpcyBzYW1lIGFzIHRoYXQgb2Yg4oCYSeKAmSBhbmQgcmlnaHQgaGFsZiBvZiDigJhY4oCZIGlzIHRoZSBtaXJyb3IgaW1hZ2Ugb2YgaXRzIGxlZnQgaGFsZi4NCg0KYGBge3IgdnN5bSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNXZSBoYXZlIHRvIGxvb2sgZm9yIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBtYXRyaXggZGF0b3MgYW5kIGR1YWxfcm93DQpWc3ltPC1saXN0KCkNCmZvciAoayBpbiAxOm4xKQ0Kew0KICBWc3ltW1trXV08LWNvcihjKGRhdG9zW1trXV0pLCBjKGR1YWxfY29sW1trXV0pKQ0KfQ0KDQpwYXIobWZyb3c9YygyLDIpKQ0KaW1hZ2UoZGF0b3NbWzVdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIk9yaWdpbmFsIiwgZm9udC5zdWIgPSAyLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmltYWdlKGR1YWxfY29sW1s1XV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKHN1YiA9ICJDb2x1bW4gbWlycm9yIiwgZm9udC5zdWIgPSAyICwgY29sLnN1YiA9ICJibGFjayIsY2V4LnN1YiA9IDIpDQppbWFnZShkYXRvc1tbMjFdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KdGl0bGUoc3ViID0gIk9yaWdpbmFsIiwgZm9udC5zdWIgPSAyLCBjb2wuc3ViID0gImJsYWNrIixjZXguc3ViID0gMikNCmltYWdlKGR1YWxfY29sW1syMV1dLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMikpDQp0aXRsZShzdWIgPSAiQ29sdW1uIG1pcnJvciIsIGZvbnQuc3ViID0gMiAsIGNvbC5zdWIgPSAiYmxhY2siLGNleC5zdWIgPSAyKQ0KYGBgDQpGb3IgZXhhbXBsZSwgaGVyZSB3ZSBwbG90IDIgYmluYXJpemVkIGltYWdlcyBhbmQgaXRzIGNvcnJlc3BvbmRhbnQgbWlycm9ycy4gRm9yIHRoZSBpbWFnZSBpbiB0aGUgdG9wIHRoZSBjb3JyZWxhdGlvbiBpcyAgYHIgcm91bmQoVnN5bVtbNV1dLDIpYCAgYW5kIGZvciB0aGUgaW1hZ2UgaW4gdGhlIGJvdHRvbiB0aGUgY29ycmVsYXRpb24gaXMgYHIgcm91bmQoVnN5bVtbMjFdXSwyKWAuDQoNCg0KICAjIzkuV2Fsc2gtSGFkYW1hcmQgdHJhbnNmb3JtIyMNCg0KIyMjV0hUIERhdGFCYXNlIEdlbmVyYXRpb24jIyMNCg0KSW4gb3JkZXIgdG8gYmUgYWJsZSB0byB1c2UgdGhlIFdhbHNoLUhhZGFtYXJkIFRyYW5zZm9ybWF0aW9uIHdlIG5lZWQgdG8gY29tcGFyZSBlYWNoIGltYWdlIHdpdGggZGVmYWlsdCBudW1iZXIgaW1hZ2VzLiBCZWNhdXNlIG9mIHRoaXMgSSBjcmVhdGVkIDEwIGRlZmF1bHQgbnVtYmVyIGltYWdlcyBhbmQgZ2VuZXJhdGVkIHRoZSBXYWxzaC1IYWRhbWFyZCBUcmFuc2Zvcm1hdGlvbiB0byBlYWNoIG9mIHRoZW0uDQoNCg0KYGBge3IgaG0sIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHJlYWRiaXRtYXApDQpsaWJyYXJ5KHByb3RvKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoYmljbHVzdCkNCmxpYnJhcnkoYm1wKQ0KDQpudW1lcm9zPC1saXN0KCkNCnJvdGF0ZSA8LSBmdW5jdGlvbih4KSB0KGFwcGx5KHgsIDIsIHJldikpDQpmb3IgKGsgaW4gMToxMCkgDQp7DQp0PWstMQ0KbnVtZXJvc1tba11dIDwtIHJvdGF0ZShhYnMoYmluYXJpemUocmVhZC5ibXAocGFzdGUocGFzdGUoJ251bWJlcnMvJyx0LHNlcCA9ICIiKSwnLmJtcCcsc2VwID0gIiIpKVssLDFdLHRocmVzaG9sZD0xMDApLTEpKQ0KfQ0KDQoNCmxpYnJhcnkocGhhbmdvcm4pDQpobTwtbGlzdCgpDQoNCmhtW1sxXV08LWZobShudW1lcm9zW1sxXV0pDQpobVtbMl1dPC1maG0obnVtZXJvc1tbMl1dKQ0KaG1bWzNdXTwtZmhtKG51bWVyb3NbWzNdXSkNCmhtW1s0XV08LWZobShudW1lcm9zW1s0XV0pDQpobVtbNV1dPC1maG0obnVtZXJvc1tbNV1dKQ0KaG1bWzZdXTwtZmhtKG51bWVyb3NbWzZdXSkNCmhtW1s3XV08LWZobShudW1lcm9zW1s3XV0pDQpobVtbOF1dPC1maG0obnVtZXJvc1tbOF1dKQ0KaG1bWzldXTwtZmhtKG51bWVyb3NbWzldXSkNCmhtW1sxMF1dPC1maG0obnVtZXJvc1tbMTBdXSkNCg0KcGFyKG1mcm93PWMoMiw1KSAsbWFyPWMoLjEsLjEsLjEsLjEpKQ0KZm9yIChrIGluIDE6MTApIGltYWdlKG51bWVyb3NbW2tdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KDQpgYGANCg0KIyMjV0hUIENvbXBhcmUjIyMNCkkgbmVlZCB0byBjb21wYXJlIGRlIGNvcnJlbGF0aW9uIG9mIHRoZSBkZW5vdGVkIGltYWdlIHdpdGggdGhlIFdIVCBEYXRhQmFzZS4NCkZvciBleGFtcGxlIGZvciBhIGdpdmVuIGltYWdlLCBJIHNob3cgdGhlIGltYWdlIGFuZCB0aGUgMTAgY29ycmVsYXRpb25zIHRvIGVhY2ggb2YgdGhlIGRlZmF1bHQgY2hhcmFjdGVycy4NCg0KYGBge3Igd2h0LCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQpsaWJyYXJ5KHBoYW5nb3JuKQ0KV0hUMDwtbGlzdCgpDQpXSFQxPC1saXN0KCkNCldIVDI8LWxpc3QoKQ0KV0hUMzwtbGlzdCgpDQpXSFQ0PC1saXN0KCkNCldIVDU8LWxpc3QoKQ0KV0hUNjwtbGlzdCgpDQpXSFQ3PC1saXN0KCkNCldIVDg8LWxpc3QoKQ0KV0hUOTwtbGlzdCgpDQoNCmNvcnJlbDwtbGlzdCgpDQpmb3IgKGsgaW4gMTpuMSkNCnsNCmhtX251bTwtZmhtKGRhdG9zW1trXV0pDQpXSFQwW1trXV08LWNvcihobV9udW0saG1bWzFdXSkNCldIVDFbW2tdXTwtY29yKGhtX251bSxobVtbMl1dKQ0KV0hUMltba11dPC1jb3IoaG1fbnVtLGhtW1szXV0pDQpXSFQzW1trXV08LWNvcihobV9udW0saG1bWzRdXSkNCldIVDRbW2tdXTwtY29yKGhtX251bSxobVtbNV1dKQ0KV0hUNVtba11dPC1jb3IoaG1fbnVtLGhtW1s2XV0pDQpXSFQ2W1trXV08LWNvcihobV9udW0saG1bWzddXSkNCldIVDdbW2tdXTwtY29yKGhtX251bSxobVtbOF1dKQ0KV0hUOFtba11dPC1jb3IoaG1fbnVtLGhtW1s5XV0pDQpXSFQ5W1trXV08LWNvcihobV9udW0saG1bWzEwXV0pDQogIH0gIA0KDQoNCiBXSFQwPC1jKGRvLmNhbGwoImNiaW5kIixXSFQwKSkgDQogV0hUMTwtYyhkby5jYWxsKCJjYmluZCIsV0hUMSkpIA0KIFdIVDI8LWMoZG8uY2FsbCgiY2JpbmQiLFdIVDIpKSANCiBXSFQzPC1jKGRvLmNhbGwoImNiaW5kIixXSFQzKSkgDQogV0hUNDwtYyhkby5jYWxsKCJjYmluZCIsV0hUNCkpIA0KIFdIVDU8LWMoZG8uY2FsbCgiY2JpbmQiLFdIVDUpKSANCiBXSFQ2PC1jKGRvLmNhbGwoImNiaW5kIixXSFQ2KSkgDQogV0hUNzwtYyhkby5jYWxsKCJjYmluZCIsV0hUNykpIA0KIFdIVDg8LWMoZG8uY2FsbCgiY2JpbmQiLFdIVDgpKQ0KIFdIVDk8LWMoZG8uY2FsbCgiY2JpbmQiLFdIVDkpKSANCiANCnBhcihtZnJvdz1jKDEsMSksbWFyPWMoLjEsLjEsLjEsLjEpKQ0KaW1hZ2UoZGF0b3NbWzJdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDIpKQ0KDQpgYGANCkZvciB0aGlzIGltYWdlIHRoZSBjb3JyZWxhdGlvbiB0byBlYWNoIGNoYXJhY3RlciBpczoNCg0KYGBge3IgY29ycmVsYXRpb25zLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTMwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Ka2FibGUoZGF0YS5mcmFtZSh6ZXJvPXJvdW5kKFdIVDBbWzJdXSwyKSxvbmU9cm91bmQoV0hUMVtbMl1dLDIpLHR3bz1yb3VuZChXSFQyW1syXV0sMiksdGhyZWU9cm91bmQoV0hUM1tbMl1dLDIpLGZvdXI9cm91bmQoV0hUNFtbMl1dLDIpLGZpdmU9cm91bmQoV0hUNVtbMl1dLDIpLHNpeD1yb3VuZChXSFQ2W1syXV0sMiksc2V2ZW49cm91bmQoV0hUN1tbMl1dLDIpLGVpZ2h0PXJvdW5kKFdIVDhbWzJdXSwyKSxuaW5lPXJvdW5kKFdIVDlbWzJdXSwyKSkpDQpgYGANCg0KDQpBcyB3ZSBjYW4gc2VlIHRoZSBXSFQgZ2V0IGEgZ29vZCBhcHByb3hpbWF0aW9uIHRvIHRoZSBudW1iZXIgd2UgYXJlIGxvb2tpbmcgZm9yLiBJbiB0aWhzIGNhc2UgaXQgcHV0cyB0aGUgemVybyBhcyBhIHNlY29uZCBjaG9pY2UsIGJ1dCB2ZXJ5IGNsb3NlIHRvIHRoZSBmaXJzdCBwbGFjZSwgd2hlcmUgdGhlIG51bWJlciA2IGlzLiANCg0KDQojIzEwLiBDb25uZWN0ZWQgQ29tcG9uZW50IFRyYW5zZm9ybSAjIw0KSXQgZ2l2ZXMgYSBtZWFzdXJlIG9mIHRoZSBudW1iZXIgb2YgY2xvc2VkIGFyZWFzIGluIGEgY2hhcmFjdGVyLiBJbiBhbiBpbWFnZSwgYWxsIHRoZQ0KY29ubmVjdGVkIHBpeGVscyBhcmUgZ2l2ZW4gc2FtZSBsYWJlbHMuIFRodXMgaWYgdGhlcmUgYXJlIHR3byBzZXRzIG9mIHN1Y2ggcGl4ZWxzLCBhcyBpbiDigJg44oCZLA0KdGhleSB3b3VsZCBiZSBsYWJlbGVkIGFzIOKAmDHigJkgYW5kIOKAmDLigJkuIFRodXMgdGhlIGhpZ2hlc3QgdmFsdWUgb2Yg4oCYbGFiZWzigJkgZ2l2ZXMgYW4gaWRlYSBvZg0KY2xvc2VkIGFyZWFzIHByZXNlbnQgaW4gdGhlIGNoYXJhY3Rlci4NCg0KV2UgdXNlIHRoZSBjb25uZWN0ZWQgY29tcG9uZW50IHRyYW5zZm9ybSAoUm9zZW5mZWxkIGFuZCBQZmFseiwgMTk2NikgYW5kIHdlIHNob3cgaXRzIHJlc3VsdCBmb3IgMTAgbnVtYmVycyBpbiBsaXR0bGUgYmxhY2sgbGV0dGVycyBpbiB0aGUgdG9wIG9mIGVhY2ggaW1hZ2UuDQoNCmBgYHtyIENOQ1AsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHNwYXRzdGF0KQ0KIA0KQ05DUDwtbGlzdCgpDQogDQpmb3IgKGsgaW4gMTpuMSkNCnsNCiAgeDIgPC0gaW0oZGF0b3NbW2tdXSwgeGNvbD1zZXEoMSxsZW5ndGg9MjgpLCB5cm93PXNlcSgxLGxlbmd0aD0yOCkpDQogIFggPC0gbGV2ZWxzZXQoeDIsIDAuMDYpDQogICNwbG90KFgpDQogIFogPC0gY29ubmVjdGVkKFgpDQogICNwbG90KFopDQogICMgbnVtYmVyIG9mIGNvbXBvbmVudHMNCiAgbmMgPC0gbGVuZ3RoKGxldmVscyhaKSkNCiAgIyBwbG90IHdpdGggcmFuZG9taXNlZCBjb2xvdXIgbWFwDQogICMgIHBsb3QoWiwgY29sPWhzdihoPXNhbXBsZShzZXEoMCwxLGxlbmd0aD1uYyksIG5jKSkpDQogIENOQ1BbW2tdXTwtbmMtMQ0KfQ0KDQpzYW08LXNhbXBsZShuMSw1MCkNCnBhcihtZnJvdz1jKDUsMTApLG1hcj1jKC4xLC4xLDEuNCwuMSkpDQpmb3IgKGkgaW4gc2FtKQ0Kew0KICAgIGltYWdlKGRhdG9zW1tpXV0sIGF4ZXM9RkFMU0UsIGNvbD1ncmV5LmNvbG9ycygyKSkNCnRpdGxlKG1haW4gPSBDTkNQW1tpXV0sIGZvbnQubWFpbiA9IDMgLCBjb2wubWFpbiA9ICJibGFjayIpDQp9DQoNCmBgYA0KDQpXaGljaCBpcyBhY3R1YWxseSB0aGUgbnVtYmVycyBvZiBjb21wb25lbnRzIGluc2lkZSB0aGUgbnVtYmVycy4NCg0KDQojIzExLlByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMjIw0KDQpXZSBoYXZlIDI4eDI4IHBpeGVscyBwZXIgaW1hZ2UuIE1vc3Qgb2YgdGhlbSBhcmUgMCBmb3IgZWFjaCBpbWFnZS4gU28gd2UgY2FuIHNheSB0aGF0IG1vc3Qgb2YgdGhlbSBnaXZlIHVzIG5vIGluZm9ybWF0aW9uIHJlZ2FyZGluZyB3aGljaCBudW1iZXIgd2VuZWVkIHRvIHByZWRpY3QuIFdlIHdpbGwgZW5oYWdlIGEgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyB0byB0cnkgdG8gZmlndXJlIG91dCB3aGljaCBhcmUgdGhlIHByaW5jaXBhbCBDb21wb25lbnRzIG9mIHRoZSBkYXRhc2V0IHRoYXQgYWJzb3JiIHRoZSBtYXhpbXVtIHZhcmlhbmNlLiBBZnRlciB0aGlzIHdlIHdpbGwgYWRkIHRoaXMgcHJkaWN0b3JzIHRvIHRoZSBObmV0IElucHV0Lg0KYGBge3IgUENBMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoY2FyZXQpDQpuenIgPC0gbmVhclplcm9WYXIodHJhaW5bLC0xXSxzYXZlTWV0cmljcz1ULGZyZXFDdXQ9MTAwMDAvMSx1bmlxdWVDdXQ9MS83KQ0KI3N1bShuenIkemVyb1ZhcikNCg0KI3N1bShuenIkbnp2KSAjMjA4IHByZWRpY3RvcnMgd2l0aCB6ZXJvIHZhcmlhbmNlDQoNCmN1dHZhciA8LSByb3duYW1lcyhuenJbbnpyJG56dj09VFJVRSxdKQ0KdmFyIDwtIHNldGRpZmYobmFtZXModHJhaW4pLGN1dHZhcikNCnRyYWluaW5nIDwtIHRyYWluWyx2YXJdDQoNCmxhYmVsIDwtIGFzLmZhY3Rvcih0cmFpbmluZ1tbMV1dKQ0KdHJhaW5pbmckbGFiZWwgPC0gTlVMTA0KdHJhaW5pbmcgPC0gdHJhaW5pbmcvMjU1DQpjb3Z0cmFpbiA8LSBjb3YodHJhaW5pbmcpDQpgYGANCldlIGFwcGx5IFBDQSB0byB0aGUgY292aWFyaWFuY2UgbWF0cml4IGFuZCBjaGVjayBob3cgbWFueSBjb21wb25lbnRzIHNob3VsZCB3ZSBrZWVwLg0KYGBge3IgUENBMiwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnRyYWluX3BjIDwtIHByY29tcChjb3Z0cmFpbikNCnZhcmV4IDwtIHRyYWluX3BjJHNkZXZeMi9zdW0odHJhaW5fcGMkc2Rldl4yKQ0KdmFyY3VtIDwtIGN1bXN1bSh2YXJleCkNCnJlc3VsdCA8LSBkYXRhLmZyYW1lKG51bT0xOmxlbmd0aCh0cmFpbl9wYyRzZGV2KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBleD12YXJleCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBjdW09dmFyY3VtKQ0KDQpwbG90KHJlc3VsdCRudW0scmVzdWx0JGN1bSx0eXBlPSJiIix4bGltPWMoMCwxMDApLA0KICAgICBtYWluPSJWYXJpYW5jZSBFeHBsYWluZWQgYnkgVG9wIDEwMCBDb21wb25lbnRzIiwNCiAgICAgeGxhYj0iTnVtYmVyIG9mIENvbXBvbmVudHMiLHlsYWI9IlZhcmlhbmNlIEV4cGxhaW5lZCIpDQphYmxpbmUodj0xNSxsdHk9MikNCmBgYA0KDQpBY29yZGluZyB0byB0aGUgcGxvdCB3ZSBrZWVwIHRoZSBmaXJzdCAxNSBjb21wb25lbnRzLCB3aGljaCByZXByZXNlbnQgYWxtb3N0IDkwJSBvZiB0aGUgdmFyaWFuY2UsIHRvIGZpdCB0aGUgbW9kZWwuIA0KDQpgYGB7ciBQQ0FGaW5hbCwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdHJhaW5fc2NvcmUgPC0gYXMubWF0cml4KHRyYWluaW5nKSAlKiUgdHJhaW5fcGMkcm90YXRpb25bLDE6MTVdDQpgYGANCg0KI0ZpbmFsIERhdGEgU2V0ICMNCkRhdGE6IERhdGFzZXQgb2YgYWxsIHRoZSBjYWxjdWxhdGVkIGtwaSdzIHBlciBwaG90by4gDQoNCldlIHNob3cgdGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgb2YgdGhlIERhdGEgc2V0Lg0KDQpgYGB7ciBmaW5hbGRhdGEsIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpIMzBfbSA8LSBtYXRyaXgodW5saXN0KEgzMCksIG5yb3c9bjEpDQpINTBfbSA8LSBtYXRyaXgodW5saXN0KEg1MCksIG5yb3c9bjEpDQpIODBfbSA8LSBtYXRyaXgodW5saXN0KEg4MCksIG5yb3c9bjEpDQpWMzBfbSA8LSBtYXRyaXgodW5saXN0KFYzMCksIG5yb3c9bjEpDQpWNTBfbSA8LSBtYXRyaXgodW5saXN0KFY1MCksIG5yb3c9bjEpDQpWODBfbSA8LSBtYXRyaXgodW5saXN0KFY4MCksIG5yb3c9bjEpDQpIc3ltX20gPC0gbWF0cml4KHVubGlzdChIc3ltKSwgbnJvdz1uMSkNClZzeW1fbSA8LSBtYXRyaXgodW5saXN0KFZzeW0pLCBucm93PW4xKQ0KVnN5bV9tW2lzLm5hKFZzeW1fbSldIDwtMA0KV0hUMF9tIDwtIG1hdHJpeChXSFQwLCBucm93PW4xKQ0KV0hUMV9tIDwtIG1hdHJpeChXSFQxLCBucm93PW4xKQ0KV0hUMl9tIDwtIG1hdHJpeChXSFQyLCBucm93PW4xKQ0KV0hUM19tIDwtIG1hdHJpeChXSFQzLCBucm93PW4xKQ0KV0hUNF9tIDwtIG1hdHJpeChXSFQ0LCBucm93PW4xKQ0KV0hUNV9tIDwtIG1hdHJpeChXSFQ1LCBucm93PW4xKQ0KV0hUNl9tIDwtIG1hdHJpeChXSFQ2LCBucm93PW4xKQ0KV0hUN19tIDwtIG1hdHJpeChXSFQ3LCBucm93PW4xKQ0KV0hUOF9tIDwtIG1hdHJpeChXSFQ4LCBucm93PW4xKQ0KV0hUOV9tIDwtIG1hdHJpeChXSFQ5LCBucm93PW4xKSANCkNOQ1BfbSA8LSBtYXRyaXgodW5saXN0KENOQ1ApLCBucm93PW4xKQ0KUEMxPC10cmFpbl9zY29yZVssMV0NClBDMjwtdHJhaW5fc2NvcmVbLDJdDQpQQzM8LXRyYWluX3Njb3JlWywzXQ0KUEM0PC10cmFpbl9zY29yZVssNF0NClBDNTwtdHJhaW5fc2NvcmVbLDVdDQpQQzY8LXRyYWluX3Njb3JlWyw2XQ0KUEM3PC10cmFpbl9zY29yZVssN10NClBDODwtdHJhaW5fc2NvcmVbLDhdDQpQQzk8LXRyYWluX3Njb3JlWyw5XQ0KUEMxMDwtdHJhaW5fc2NvcmVbLDEwXQ0KUEMxMTwtdHJhaW5fc2NvcmVbLDExXQ0KUEMxMjwtdHJhaW5fc2NvcmVbLDEyXQ0KUEMxMzwtdHJhaW5fc2NvcmVbLDEzXQ0KUEMxNDwtdHJhaW5fc2NvcmVbLDE0XQ0KUEMxNTwtdHJhaW5fc2NvcmVbLDE1XQ0KDQpsYWJlbDwtZmFjdG9yKGRhdGEkbGFiZWwpDQoNCiNOb3JtYWxpemUgdGhlIGlucHV0cw0KDQp0cmFpbl9maW5hbDwtZGF0YS5mcmFtZShIMzBfbSxINTBfbSxIODBfbSxWMzBfbSxWNTBfbSxWODBfbSxIc3ltX20sVnN5bV9tLFdIVDBfbSxXSFQxX20sV0hUMl9tLFdIVDNfbSxXSFQ0X20sV0hUNV9tLFdIVDZfbSxXSFQ3X20sV0hUOF9tLFdIVDlfbSxDTkNQX20sUEMxLFBDMixQQzMsUEM0LFBDNSxQQzYsUEM3LFBDOCxQQzksUEMxMCxQQzExLFBDMTIsUEMxMyxQQzE0LFBDMTUsbGFiZWwpDQoNCmBgYA0KDQpgYGB7ciBtdWx0aXBsb3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQptdWx0aXBsb3QgPC0gZnVuY3Rpb24oLi4uLCBwbG90bGlzdD1OVUxMLCBmaWxlLCBjb2xzPTEsIGxheW91dD1OVUxMKSB7DQogIGxpYnJhcnkoZ3JpZCkNCiAgDQogICMgTWFrZSBhIGxpc3QgZnJvbSB0aGUgLi4uIGFyZ3VtZW50cyBhbmQgcGxvdGxpc3QNCiAgcGxvdHMgPC0gYyhsaXN0KC4uLiksIHBsb3RsaXN0KQ0KICANCiAgbnVtUGxvdHMgPSBsZW5ndGgocGxvdHMpDQogIA0KICAjIElmIGxheW91dCBpcyBOVUxMLCB0aGVuIHVzZSAnY29scycgdG8gZGV0ZXJtaW5lIGxheW91dA0KICBpZiAoaXMubnVsbChsYXlvdXQpKSB7DQogICAgIyBNYWtlIHRoZSBwYW5lbA0KICAgICMgbmNvbDogTnVtYmVyIG9mIGNvbHVtbnMgb2YgcGxvdHMNCiAgICAjIG5yb3c6IE51bWJlciBvZiByb3dzIG5lZWRlZCwgY2FsY3VsYXRlZCBmcm9tICMgb2YgY29scw0KICAgIGxheW91dCA8LSBtYXRyaXgoc2VxKDEsIGNvbHMgKiBjZWlsaW5nKG51bVBsb3RzL2NvbHMpKSwNCiAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSBjb2xzLCBucm93ID0gY2VpbGluZyhudW1QbG90cy9jb2xzKSkNCiAgfQ0KICANCiAgaWYgKG51bVBsb3RzPT0xKSB7DQogICAgcHJpbnQocGxvdHNbWzFdXSkNCiAgICANCiAgfSBlbHNlIHsNCiAgICAjIFNldCB1cCB0aGUgcGFnZQ0KICAgIGdyaWQubmV3cGFnZSgpDQogICAgcHVzaFZpZXdwb3J0KHZpZXdwb3J0KGxheW91dCA9IGdyaWQubGF5b3V0KG5yb3cobGF5b3V0KSwgbmNvbChsYXlvdXQpKSkpDQogICAgDQogICAgIyBNYWtlIGVhY2ggcGxvdCwgaW4gdGhlIGNvcnJlY3QgbG9jYXRpb24NCiAgICBmb3IgKGkgaW4gMTpudW1QbG90cykgew0KICAgICAgIyBHZXQgdGhlIGksaiBtYXRyaXggcG9zaXRpb25zIG9mIHRoZSByZWdpb25zIHRoYXQgY29udGFpbiB0aGlzIHN1YnBsb3QNCiAgICAgIG1hdGNoaWR4IDwtIGFzLmRhdGEuZnJhbWUod2hpY2gobGF5b3V0ID09IGksIGFyci5pbmQgPSBUUlVFKSkNCiAgICAgIA0KICAgICAgcHJpbnQocGxvdHNbW2ldXSwgdnAgPSB2aWV3cG9ydChsYXlvdXQucG9zLnJvdyA9IG1hdGNoaWR4JHJvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0LnBvcy5jb2wgPSBtYXRjaGlkeCRjb2wpKQ0KICAgIH0NCiAgfQ0KfQ0KYGBgDQoNCg0KSW4gdGhlIGZvbGxvd2luZyBncmFwaHMgd2UgY2FuIHNlZSBhIGRlbnNpdHkgcGxvdCBwZXIgdmFyYWJsZSB0YWtpbmcgaW50byBhY2NvdW50IHRoZSBudW1iZXIgaXQgcmVwcmVzZW50cy4NCmBgYHtyIGdyYXBoLCBlY2hvPUZBTFNFLCBmaWcuc2hvdz0nYW5pbWF0ZScsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGFuaW9wdHM9ImNvbnRyb2xzIiwgaW50ZXJ2YWw9MC4yfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KcDE8LWdncGxvdChkYXRhPXRyYWluX2ZpbmFsLCBhZXMoeD1sYWJlbCwgeT1IMzBfbSwgZmlsbD1sYWJlbCkpICsgZ2VvbV9ib3hwbG90KCkrdGhlbWVfYncoKSsgZ3VpZGVzKGZpbGw9RkFMU0UpDQpwMjwtZ2dwbG90KGRhdGE9dHJhaW5fZmluYWwsIGFlcyh4PWxhYmVsLCB5PUg1MF9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnAzPC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9SDgwX20sIGZpbGw9bGFiZWwpKSArIGdlb21fYm94cGxvdCgpK3RoZW1lX2J3KCkrIGd1aWRlcyhmaWxsPUZBTFNFKQ0KcDQ8LWdncGxvdChkYXRhPXRyYWluX2ZpbmFsLCBhZXMoeD1sYWJlbCwgeT1WMzBfbSwgZmlsbD1sYWJlbCkpICsgZ2VvbV9ib3hwbG90KCkrdGhlbWVfYncoKSsgZ3VpZGVzKGZpbGw9RkFMU0UpDQpwNTwtZ2dwbG90KGRhdGE9dHJhaW5fZmluYWwsIGFlcyh4PWxhYmVsLCB5PVY1MF9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA2PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9VjgwX20sIGZpbGw9bGFiZWwpKSArIGdlb21fYm94cGxvdCgpK3RoZW1lX2J3KCkrIGd1aWRlcyhmaWxsPUZBTFNFKQ0KcDc8LWdncGxvdChkYXRhPXRyYWluX2ZpbmFsLCBhZXMoeD1sYWJlbCwgeT1Ic3ltX20sIGZpbGw9bGFiZWwpKSArIGdlb21fYm94cGxvdCgpK3RoZW1lX2J3KCkrIGd1aWRlcyhmaWxsPUZBTFNFKQ0KcDg8LWdncGxvdChkYXRhPXRyYWluX2ZpbmFsLCBhZXMoeD1sYWJlbCwgeT1Wc3ltX20sIGZpbGw9bGFiZWwpKSArIGdlb21fYm94cGxvdCgpK3RoZW1lX2J3KCkrIGd1aWRlcyhmaWxsPUZBTFNFKQ0KcDk8LWdncGxvdChkYXRhPXRyYWluX2ZpbmFsLCBhZXMoeD1sYWJlbCwgeT1DTkNQX20sIGZpbGw9bGFiZWwpKSArIGdlb21fYm94cGxvdCgpK3RoZW1lX2J3KCkrIGd1aWRlcyhmaWxsPUZBTFNFKQ0KcDEwPC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9UEMxLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnAxMTwtZ2dwbG90KGRhdGE9dHJhaW5fZmluYWwsIGFlcyh4PWxhYmVsLCB5PVBDMiwgZmlsbD1sYWJlbCkpICsgZ2VvbV9ib3hwbG90KCkrdGhlbWVfYncoKSsgZ3VpZGVzKGZpbGw9RkFMU0UpDQpwMTI8LWdncGxvdChkYXRhPXRyYWluX2ZpbmFsLCBhZXMoeD1sYWJlbCwgeT1QQzMsIGZpbGw9bGFiZWwpKSArIGdlb21fYm94cGxvdCgpK3RoZW1lX2J3KCkrIGd1aWRlcyhmaWxsPUZBTFNFKQ0KDQoNCmxheW91dCA8LSBtYXRyaXgoYygxLCAyLCAzLCA0LCA1LCA2KSwgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkNCg0KbXVsdGlwbG90KHAxLCBwMiwgcDMsIHA0LHA1LHA2LCBsYXlvdXQgPSBsYXlvdXQpDQoNCm11bHRpcGxvdChwNyxwOCxwOSxwMTAscDExLHAxMixsYXlvdXQgPSBsYXlvdXQpDQoNCnAwPC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUMF9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnAxPC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUMV9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnAyPC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUMl9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnAzPC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUM19tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA0PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUNF9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA1PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUNV9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA2PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUNl9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA3PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUN19tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA4PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUOF9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCnA5PC1nZ3Bsb3QoZGF0YT10cmFpbl9maW5hbCwgYWVzKHg9bGFiZWwsIHk9V0hUOV9tLCBmaWxsPWxhYmVsKSkgKyBnZW9tX2JveHBsb3QoKSt0aGVtZV9idygpKyBndWlkZXMoZmlsbD1GQUxTRSkNCmxheW91dCA8LSBtYXRyaXgoYygxLCAyLCAzLCA0LCA1LCA2ICksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpDQptdWx0aXBsb3QocDAscDEsIHAyLCBwMywgcDQscDUsIGxheW91dCA9IGxheW91dCkNCmxheW91dCA8LSBtYXRyaXgoYygxLCAyLCAzLCA0ICksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpDQptdWx0aXBsb3QocDYscDcscDgscDksbGF5b3V0PWxheW91dCkNCmBgYA0KDQoNCiNUcmFpbiBhbmQgVGVzdCMNCg0KSW4gdGhpcyBzdGVwIHdlIHNjYWxlIGFsbCB0aGUgdmFyaWFibGVzIGFuZCB3ZSBjZW50ZXIgdGhlbSBzbyB0aGF0IHRoZXJlIGlzIG5vIHdlaWdodCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlbSwgc28gdGhhdCBhbGwgdmFyaWFibGVzIGhhdmUgdGhlIHNhbWUgaW5pdGlhbCBpbXBvcnRhbmNlLiBUaGlzIGlzIGEga2V5IHN0ZXAgZm9yIHRoZSBuZXVyYWwgbmV0d29yayB0cmFpbmluZyB0byBzdWNjZWVkLiBXZSBhbHNvIGNyZWF0ZSB0cmFpbiBhbmQgdGVzdCBwYXJ0aXRpb25zIG9mIHRoZSBkYXRhLiANCg0KSSBzaG93IGEgY291cGxlIG9mIHJvd3MgdG8gc2VlIHRoZSBmaW5hbCBEYXRhIHNldCBpbiBhY3Rpb24uDQoNCmBgYHtyIHRyYWluLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShjYXJldCkNCg0KcHJlT2JqIDwtIHByZVByb2Nlc3MoeD10cmFpbl9maW5hbCwgbWV0aG9kPWMoImNlbnRlciIsICJzY2FsZSIpKQ0KdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKHRyYWluX2ZpbmFsJGxhYmVsLCBwPS43LCBsaXN0PUYpDQoNCm51bWJlcnMudHJhaW50b3RhbDwtcHJlZGljdChwcmVPYmosdHJhaW5fZmluYWwpDQpudW1iZXJzLnRyYWluPC0gcHJlZGljdChwcmVPYmosIHRyYWluX2ZpbmFsW3RyYWluSW5kZXgsIF0pDQpudW1iZXJzLnRlc3QgICAgIDwtIHByZWRpY3QocHJlT2JqLCB0cmFpbl9maW5hbFstdHJhaW5JbmRleCwgXSkNCg0KbnVtYmVycy50cmFpbnRvdGFsWzE6NSxdDQpgYGANCg0KI05ldXJhbCBOZXR3b3JrIw0KSW4gdGhpcyBzdGVwIHdlIHRyYWluIHRoZSBOZXVyYWwgbmV0d29yay4NCg0KRm9yIHRoaXMgc3BlY2lmaWMgdHJhaW5pbmcgc2V0LCBJJ3ZlIGNob29zZW4gYSBuZXVyYWwgbmV0d29yayB3aXRoIDEgaGlkZGVuIGxheWVyIHdpdGggMjIgbm9kZXMuDQpUaGlzIGVsZWN0aW9uIHdhcyBkb25lIGFmdGVyIHRlc3RpbmcgdGhlIG5uZXQgd2l0aCBhIHNldmVyYWwgZGlmZXJlbnQgbnVtYmVycyBvZiBub2RlcyBmb3IgdGhlIGhpZGRlbiBsYXllci4gSSd2ZSB0cmllZCB3aXRoIDEwIG5vZGVzLCB0byAyOCBhbmQgdGhlIGJlc3QgYWNjdXJhY3kgZm9yIHRoZSBtb2RlbCB3YXMgb2J0ZWluZWQgd2l0aCAyNCBub2Rlcy4NCg0KIyNNb2RlbCBSZXN1bHRzOiMjDQoNCmBgYHtyIE1vZGVsLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCm15LmdyaWQ2IDwtIGV4cGFuZC5ncmlkKC5kZWNheSA9IGMoMC41KSwgLnNpemUgPSBjKDIyKSkNCnRyYWluX2NvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZD0icmVwZWF0ZWRjdiIsIG51bWJlcj0xMCwgcmVwZWF0cz0zKQ0KbnVtYmVycy5maXQ2IDwtIHRyYWluKGxhYmVsIH4gLiwgZGF0YSA9IG51bWJlcnMudHJhaW50b3RhbCxtZXRob2QgPSAibm5ldCIsIG1heGl0ID0gMTAwMCwgdHJDb250b3I9dHJhaW5fY29udHJvbCx0dW5lR3JpZCA9IG15LmdyaWQ2LCB0cmFjZSA9IEYsIGxpbm91dCA9IDEpIA0KDQoja2FibGUobnVtYmVycy5maXQ2JHJlc3VsdHMpDQpgYGANClBsb3QgTmV1cmFsIE5ldHdvcmsNCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCmxpYnJhcnkoZGV2dG9vbHMpDQpzb3VyY2VfdXJsKCdodHRwczovL2dpc3QuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1BlcXVlLzQxYTllMjBkNjY4N2YyZjMxMDhkL3Jhdy84NWUxNGYzYTI5MmUxMjZmMTQ1NDg2NDQyN2UzYTE4OWMyZmUzM2YzL25uZXRfcGxvdF91cGRhdGUucicpDQoNCiNwbG90IGVhY2ggbW9kZWwNCg0KDQpwbG90Lm5uZXQobnVtYmVycy5maXQ2LGFsbC5vdXQgPSBGLCBhbHBoYS52YWwgPSAwLjMsIGNpcmNsZS5jb2wgPSBsaXN0KCdsaWdodGdyYXknLCAnd2hpdGUnKSwgYm9yZC5jb2wgPSAnYmxhY2snLGNpcmNsZS5jZXggPSAxLGxpbm91dD1ULGNleC52YWwgPSAwLjQscG9zLmNvbD0iYmx1ZSIsbmVnLmNvbD0ib3JhbmdlIixyZWwucnNjPTIsbWF4LnNwPTApDQoNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbnVtYmVycy5maXQ2DQpgYGANCg0KI1Rlc3QgU2V0IFByZWRpY3Rpb25zIHRhYmxlIw0KYGBge3IgcHJlZGljdGlvbnMsIGV2YWw9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQoNCg0KbGlicmFyeShrbml0cikNCmZpcnN0PC1wcmVkaWN0KG51bWJlcnMuZml0NixudW1iZXJzLnRlc3QpDQpkaTwtdGFibGUoZmlyc3QsbnVtYmVycy50ZXN0JGxhYmVsKQ0KYWNjdXJhY3k8LXN1bShkaWFnKGRpKSkvc3VtKG5yb3cobnVtYmVycy50ZXN0KSkNCmBgYA0KRm9yIHRoZSB0ZXN0IHNldCB3ZSBoYXZlIGEgX19gciByb3VuZChhY2N1cmFjeSw0KSAqMTAwYF9fICUgcHJlZGljdGlvbiBhY2N1cmFjeS4NCg0KSGVyZSB3ZSBzaG93IHRoZSBjb25mdXNpb24gbWF0cml4IGZvciB0aGUgdGVzdCBzZXQuDQpgYGB7ciBjb25mdXNpb24sIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCmNvbHVtIDwtIGMoJzAnLCAnMScsICcyJywgJzMnLCAnNCcsICc1JywgJzYnLCAnNycsICc4JywgJzknICkNCnJvIDwtIGMoJzAnLCAnMScsICcyJywgJzMnLCAnNCcsICc1JywgJzYnLCAnNycsICc4JywgJzknKQ0KZGYgPC0gZXhwYW5kLmdyaWQoY29sdW0sIHJvKQ0KZGYkdmFsdWUgPC0gYyh0YWJsZShmaXJzdCxudW1iZXJzLnRlc3QkbGFiZWwpICkNCg0KZyA8LSBnZ3Bsb3QoZGYsIGFlcyhWYXIxLCBWYXIyKSkgKyBnZW9tX3BvaW50KGFlcyhzaXplID0gdmFsdWUpLCBjb2xvdXIgPSAiZ3JleSIpICsgdGhlbWVfYncoKSArIHhsYWIoIlByZWRpY3RlZCIpICsgeWxhYigiT3JpZ2luYWwiKQ0KZyArIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZT1jKDIsMjApKSArIGdlb21fdGV4dChhZXMobGFiZWwgPSB2YWx1ZSkpDQpgYGANCg0KIyNHb29kIHByZWRpdGlvbnMjIw0KSSdsbCBsaWtlIHRvIHNob3cgc29tZSBpbWFnZXMgb2YgZ29vZCBwcmVkaWN0aW9uczoNCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpidWVuYXM8LW51bWJlcnMudGVzdCRsYWJlbD09Zmlyc3QNCnBhcihtZnJvdz1jKDUsMTApLG1hcj1jKC4xLC4xLC4xLC4xKSkNCmk9MA0Kaj0wDQpwcmVkaWN0aW9uPC1OVUxMDQp3aGlsZSAoaTw1MCkNCnsNCiAgajwtaisxDQogIGlmIChudW1iZXJzLnRyYWludG90YWxbaixdJGxhYmVsPT1maXJzdFtqXSkgew0KICAgICAgaW1hZ2Uob3JpZ2luYWxbW2pdXSwgYXhlcz1GQUxTRSwgY29sPWdyZXkuY29sb3JzKDEwKSkNCiAgICAgIGk8LWkrMQ0KICB9Ow0KfQ0KDQpgYGANCg0KIyNCYWQgcHJlZGl0aW9ucyMjDQpBbmQgYWxzbyBzb21lIHBpY3R1cmVzIG9mIGJhZCBwcmVkaWN0ZWQgY2FyYWN0ZXJzIHdpdGggdGhlIHByZWRpY3RlZCBjaGFyYWN0ZXIgaW4gbGl0dGxlIGJsYWNrIGZvbnQuDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFyKG1mcm93PWMoNSwxMCksbWFyPWMoLjEsMCwxLjQsLjEpKQ0KaT0wDQpqPTANCnByZWRpY3Rpb248LU5VTEwNCg0KI3N1bW1hcnkobnVtYmVycy50ZXN0WzEsXSRsYWJlbCkNCndoaWxlIChpPDUwKQ0Kew0KICBqPC1qKzENCiAgaWYgKG51bWJlcnMudHJhaW50b3RhbFtqLF0kbGFiZWwhPWZpcnN0W2pdKSB7DQogICAgICBpbWFnZShvcmlnaW5hbFtbal1dLCBheGVzPUZBTFNFLCBjb2w9Z3JleS5jb2xvcnMoMTApKQ0KICAgICAgdGl0bGUobWFpbiA9IGZpcnN0W2pdLCBmb250Lm1haW4gPSAzICwgY29sLm1haW4gPSAiYmxhY2siKQ0KICAgICAgDQogICAgICBpPC1pKzENCiAgfTsNCn0NCg0KDQpgYGANCkFzIHdlIGNhbiBzZWUgaW4gdGhlIHByZXZpdW9zIGdyYXBoLCB0aGUgYmFkbHkgcHJlZGljdGVkIGNoYXJhY3RlcnMgYXJlIG5vdCBlYXN5IHRvIGRpc3Rpbmd1aXNoIGFuZCBldmVuIGZvciBhIHBlcnNvbiBpdHMgaGFyZCB0byByZWNvZ25pemUuIA0K