Données, ACP
Dans cette premiere partie nous travaillons sur les données crabs,
afin d’illustrer le danger possible de l’utilisation de l’ACP.
Les données
Cet ensemble de données contient des mesures morphologiques sur les
crabes Leptograpsus.
Il contient 200 observations et 8 variables.
Appercu du jeu de données Crabs
| sp |
sex |
index |
FL |
RW |
CL |
CW |
BD |
| B |
M |
1 |
8.1 |
6.7 |
16.1 |
19.0 |
7.0 |
| B |
M |
2 |
8.8 |
7.7 |
18.1 |
20.8 |
7.4 |
| B |
M |
3 |
9.2 |
7.8 |
19.0 |
22.4 |
7.7 |
| B |
M |
4 |
9.6 |
7.9 |
20.1 |
23.1 |
8.2 |
| B |
M |
5 |
9.8 |
8.0 |
20.3 |
23.0 |
8.2 |
Ce jeu comptabilise 5 mesures morphologiques sur 200 crabes, de deux
couleurs et des deux sexes, de l’espèce Leptograpsus variegatus
collectée à Fremantle en Australie occidentale.
Nous avons deux variables qualitatives :
- sp = L’espèce : B pour Bleu ou O pour Orange
- sex = Le sexe : M pour Male ou F pour Femelle
Et six variables quantitatives :
- index = Un indice allant jusq’à 50 dans chacun des
quatre groupes
- FL = la taille du lobe frontal en mm
- RW = la largeur du dos en mm
- CL = la longueur de la carapace en mm
- CW = la largeur de la carapace en mm
- BD = la profondeur du corps en mm
Nous nous demandons quelles variables sont les plus
importantes?
Comment réduire ce jeu de données afin de le représenter de manière
simple sur 2 ou 3 axes par exemple?
Grace a l’Analyse en Composantes Principales nous allons pouvoir faire
une réduction de dimension, et transformer les variables très corrélées
en nouvelles variables décorrélées les unes des autres.
Évidemment, qui dit réduction de dimension dit perte
d’informations.
C’est là tout l’enjeu : il faut pouvoir réduire la dimension de nos
données tout en conservant un maximum d’informations.
Pour avoir une premiere idée sur ces données, on commence par tracer
un histogramme:
En déplaçant le curseur sur le graphique nous pouvons voir facilement
les valeurs de nos 5 variables d’interet.
Pour voir maintenant comment l’une de ces variable est affectée par
une autre, nous réalisons un scatter plot:
De même, le curseur nous permet d’obtenir facilement chaque
valeur.
Nous remarquons que les variables CL et CW s’alignent parfaitement sur
une même droite, elles sont fortement liées, elles sont corrélées. Leur
coeffcient de corrélation est proche de 1.
Les variables BD et RW sont les moins liées.
Les autres variables sont elles aussi correlées, mais un peu moins.
Leurs coefficients de corrélation est proche de 0.8.
Quoi qu’il en soit, on voit une très forte corrélation générale entre
les données. (dit “effet taille”)
Proportion de
variance expliquée par les deux premières composantes principales



Sur le deuxieme graphique “PCA graph of variables” les variables
corrélées positivement sont du même côté du graphique. Les variables
corrélées négativement sont sur des côtés opposés du graphique.
Nous voyons que nous avons 95,78% de la variance expliquée par le
premier axe principal, et seulement 3,03% par le deuxieme. Cela nous
laisse penser que nous pouvons exprimer nos données avec uniquement la
premiere composante principale.
Projection sur la
première composante principale

La ligne en pointillé rouge nous indique la contribution moyenne
attendue.
Si la contribution des variables était uniforme, la valeur attendue
serait 1/length(variables) = 1/10 = 10%.
Pour une composante donnée, une variable avec une contribution
supérieure à ce seuil pourrait être considérée comme importante pour
contribuer à la composante.
Nous remarquons que les varibales CL,FL,BD,CW sont legerement
importantes pour la contribution a cet axe, contrairement a la variable
RW qui se trouve en dessous de ce seuil.
Projection sur la
deuxième composante principale

Nous remarquons maintenant, a l’inverse, que la variable RW est celle
qui contribue le plus pour le deuxieme axe. (et de loin)
Projection sur les
deux premières composantes principales

Nous remarquons que les variables CW et CL sont les seules a
contribuer désormais.
Conclusion
Nous décidons de projeter les données sur ses composantes
principales, croisées entre elles. Tout d’abord, pour le sexe, nous
obtenons :
Puis, pour le type d’espece nous obtenons:
Nous concluons finalement que l’ACP nous pousse a retenir qu’un seul
axe principal, alors que dans les faits, toutes les variables
contribuent uniformement sur les deux premiers axes, et qu’il faut
garder les deux pour une meilleure interpetation!!
Kmeans et clustering
hiérarchique ascendant
Les données
Comme proposé, nous allons travailler sur les données Seeds.
Cet ensemble de données contient des mesures, correspondantes aux
propriétés géométriques de grains de blé.
Il contient 210 observations et 8 variables.
Appercu du jeu de données Seeds
| Variétés |
Surface |
Périmètre |
Compacité |
Longueur |
Largeur |
CoefAsym |
Rainure |
| Kama |
15.26 |
14.84 |
0.8710 |
5.763 |
3.312 |
2.221 |
5.220 |
| Kama |
14.88 |
14.57 |
0.8811 |
5.554 |
3.333 |
1.018 |
4.956 |
| Kama |
14.29 |
14.09 |
0.9050 |
5.291 |
3.337 |
2.699 |
4.825 |
| Kama |
13.84 |
13.94 |
0.8955 |
5.324 |
3.379 |
2.259 |
4.805 |
| Kama |
16.14 |
14.99 |
0.9034 |
5.658 |
3.562 |
1.355 |
5.175 |
Nous avons trois variétés de grains de blé différentes, de 70
éléments chacun, choisis au hasard :
- Variétés = Kama, Rosa et Canadian
Et sept paramètres géométriques (continus à valeur réelle) mesurés
:
- Surface = la surface A
- Périmètre = le périmètre P
- Compacité = la compacité \(C = \frac{4\pi A}{P^2}\)
- Longueur = la longueur du noyau
- Largeur = la largeur du noyau
- CoefAsym = le coefficient d’asymétrie
- Rainure = la longueur de la rainure du noyau
A partir de ces sept parametres, notre objectif de clustering sera
donc de regrouper les 210 grains en K classes,
les plus concentrées et disctinctes possibles.
Nous allons donc faire comme si nous ne savions pas a quelle variété
chaque grain appartenait, et essayer de retomber sur nos 3 clusters
:
Kama - Rosa - Canadian, tous distincts, de taille 70.
Pour avoir une premiere idée des données, réalisons quelques
graphiques.
On commence par tracer un histogramme de nos 7 paramètres
normalisés:

Ces histogrammes representent la fréquence en fonction des valeurs de
nos variables.
Nous voyons bien la symétrie, dû a la mise a l’echelle, mais c’est
tout…il nous est difficile de savoir combien de composantes nous seront
nécessaires pour décrire les données.
Nous décidons donc de faire une ACP sur nos 7 variables quantitatives
continues, afin de réduire la dimension de nos données tout en gardant
un maximum de l’information.

En jetant un coup d’oeil sur la variance cumulée, nous voyons qu’il
faudrait 5 composantes pour décrire la variance a 100%.
Nous réalisons tout d’abord un graphique en 3D des données projetées
sur les trois composantes principales :
A nouveau ici le curseur nous permet d’avoir directement les valeurs
de nos données. De plus l’aspect 3D nous permet de mieux visualiser leur
rapartition dans l’espace. Les trois premières composantes contiennent
99,48% de la variance, donc presque 100%!
Cependant, comme les deux premières composantes contiennent environ
90% de la variance, nous estimons qu’il nous est suffisant de se limiter
a celles-ci pour exprimer nos données.
Voici donc nos données projetées sur ces deux premieres composantes
principales:

Visuellement nous voyons bien nos 3 groupes, cependant certains
points se mélangent a d’autre variété, donc nous nous attendons a ne pas
obtenir une classification “parfaite” par la suite.
On trace en complément un biplot :

Une flèche est associée à chacun des 7 paramètres, elle pointe dans
la direction des valeurs croissantes du paramètre quelle
represente.
La première composante principale permet de bien séparer les variétés
Rosa et Canadian.
La variété Rosa sera le plus grand type de grain, la variété Canadian
sera le plus petit, et la variété Kama sera entre les deux.
La variété Kama a des valeurs d’ACP plus faibles que les deux autres
variétés, ce qui signifie qu’elle sera plus ronde.
De plus nous pouvons dire que les cinq paramètres Largeur, Longueur,
Périmètre, Rainure et Surface sont les contributions les plus
importantes pour la premiere composante principale. (ce sont les cinq
flèche qui pointent sur la gauche). Elles sont bien corréléées entre
elles.
Le paramètre CoefAsym est le plus important pour la deuxieme composante
principale. Il est moins corrélé avec les cinqs autres paramètre
Largeur, Longueur, Périmètre, Rainure et Surface.
Kmeans
Cette méthode consiste à regrouper des données dans des classes, les
plus homogènes possibles.
Pour ce faire, un nombre arbitraire de classes doit etre (bien)
choisi.
Ensuite, l’algorithme prend k points aléatoires (les centres) dans le
nuage de point des données,
et chaque donnée est affectée au centre le plus proche.
Puis le barycentre des points de chaque classe consitutée est calculé.
(donc les centres bougent)
Et une ré-affectation des individus au nouveau centre le plus proche a
lieu.
Ces deux dernieres étapes sont répètées jusqu’à ce que les barycentres
ne “bougent plus”. (convergence)
Il faut donc faire attention a la fois au nombre de cluster, et a la
fois au nombre de points initiaux.
Tout d’abord, pour déterminer le nombre optimal de clusters, nous
allons utiliser les trois méthodes suivantes:
Clustering k = 1,2,..., K.max (= 12): .. done
Bootstrapping, b = 1,2,..., B (= 100) [one "." per sample]:
.................................................. 50
.................................................. 100

La méthode Elbow permet de comparer le nombre
total de WSS pour chaque valeur de k.
Plus la valeur de k augmente, plus le WSS devrait être petit. Nous
voulons donc trouver le point sur le graphique où la courbe semble se
plier (indiquant une petite diminution du WSS par rapport aux valeurs
précédentes de k)
On remarque une plus forte diminution de k=1 a k=2, et de k=2 a
k=3.
Donc k=2 ou k=3 seraient de bons candidats à essayer.
La méthode Silhouette mesure la façon dont
chaque point de données s’intègre dans son cluster.
Une valeur de silhouette élevée, indique un bon clustering.
Cette méthode nous suggére donc de prendre k=2 comme nombre optimal de
clusters.
La statistique de GAP permet de comparer la
variation intra-clusters totale pour différentes valeurs de k, aux
valeurs attendues.
La valeur k=3 semble etre le bon chiffre!
Nous allons donc utiliser 3 clusters pour répartir nos données.
Pour comprendre maintenant comment l’algorithme des Kmeans
fonctionne, nous représentons graphiquement l’évolution des affectations
des classes et des centres de celles-ci, au cours des trois premieres
itérations, avec la même initialisation à chaque fois:



Nous indiquons les points qui changent d’appartenance à un groupe en
les colorant.
Malheureusement (ou heureusement) comme l’algorithme converge très vite,
cela s’arrete dès la deuxieme itération…
Maintenant, nous réalisons la méthode Kmeans afin d’obtenir 3
clusters:

L’agorithme des Kmeans affecte : 71 Kama - 67 Rosa - 72 Canadian
Nous avons représenté sur un même graphique :
Les résultats de la classification Kmeans : 1 - 2 - 3
superposés aux étiquettes réelles : Kama - Rosa - Canadian
Cette classfication n’est pas parfaite, mais relativement
correcte.
Clustering
Hiérarchique Ascendant
Nous gardons le même objectif de classification, mais nous appliquons
maintenant la méthode du clustering hiérarchique ascendant, avec
differentes fonctions de linkage.
- Methode 1: la fonction de linkage de Ward
Elle consiste a minimiser la variance totale au sein du cluster.
(clusters compacts)
À chaque étape, la paire de clusters ayant la plus petite distance
inter-clusters est fusionnée.
Regardons inertie et dendogramme:



Pour bien voir la classification faite , nous avons représenté les
sauts d’inertie en gardant que les 20 premieres valeurs du dendrogramme,
selon le nombre de classes retenues. Nous pouvons remarquer deux sauts
signifivatif en 2 et en 3 classes. nous les avons entouré ensuite en
bleu et rouge sur le dendrogramme. La meilleure classification avec la
méthode Ward est avec 3 classes.
Finalement, la classification ascendante hiérarchique avec la methode
Ward affecte :
61 Kama - 86 Rosa - 63 Canadian
- Methode 2: single linkage (min)
Elle consiste a calculer toutes les dissimilarités par paire entre les
éléments de deux clusters, et considère la plus petite de ces
dissimilarités comme un critère de liaison. (clusters longs) Nous allons
refaire exactement la meme analyse.
Regardons inertie et dendogramme:



On observe que le single linkage tend à créer des dendogrammes avec
de très fines parties/clusters.
Agissant comme un nearest neighbor, cette classification hierachique
assure une petite distance entre deux points voisins, mais des points de
parts et d’autres du cluster peuvent être éloignés.
Regardons les pertes relatives d’inertie:
[1] 4

La meilleure partition selon ce critère est représentée par un point
noir, et la seconde par un point gris. Cela nous indique de prendre 4
clusters…
- Methode 3: complete linkage (max)
Elle consiste a calculer toutes les dissimilarités par paire entre les
éléments de deux clusters, et considère la plus grande valeur de ces
dissimilarités comme la distance entre les deux clusters. (clusters
compacts)
Regardons inertie et dendogramme:



La methode Complete nous donne un partitionnement de 3 classes, mais
pas du tout equilibré, du coup la classification n’est pas bonne:
- Méthode 4: group average
Elle consiste a calculer toutes les dissimilarités par paire entre les
éléments de deux clusters, et considère la moyenne de ces dissimilarités
comme la distance entre les deux clusters.



[1] 3

Cela nous indique 3 clusters.
Finalement, la classification ascendante hiérarchique avec la methode
Average affecte :
81 Kama - 64 Rosa - 65 Canadian
C’est une classfication moins bonne que celle avec la methode Ward
mais elle reste correcte.
Nous en concluons que la méthode Ward est la meilleure!!
Caractérisation des
classifications obtenues
Les différences entre les deux methodes de classiffication sont:
La distance utilisée: Le clustering hiérarchique
peut gérer n’importe quelle mesure de distance, tandis que les Kmeans
reposent sur les distances euclidiennes.
La stabilité des résultats: La méthode Kmeans
nécessite une étape aléatoire lors de son initialisation qui peut donner
des résultats différents si le processus est réexécuté, ce qui n’est pas
le cas dans le clustering hiérarchique.
Le nombre de cluster: Même si on peut utiliser
des tracés de silhouette, ou d’autre moyens pour trouver le bon nombre
avant d’appliquer la méthode des Kmeans, Le clustering hiérarchique peut
en plus s’appuyer sur un dendrogramme.
Complexité de calcul: La méthode des Kmeans est
moins coûteuse en calcul que celle du clustering hiérarchique, et elle
peut être exécuté sur de grands ensembles de données assez rapidement,
ce pourquoi on la prèfere!
Categorie: Le Kmeans est de base centroide,
alors que la CHA est hiérarchical.
Methodes pour trouver différents clusters: Pour
le Kmeans nous avons Elbow, Silhouette, et Gap. Tandis que pour la CHA
nous avons en plus Dendrogramme et inertie.
Conclusion: Le Kmeans est fortement impacté par
les centroides initiaux, ce qui peut produire des resultats sous
optimaux. Mais il a l’avantage d’avoir une convergence garantie,
spécifiquement pour les clusters de differentes tailles et formes.
La CHA est plus flexible, plus facile en traitement de toute forme de
similarité et de distance. Elle est plus facile pour determiner le
nombre de clusters.
Par rapport a notre étude, nous en concluons qu’il y a bien une
différence spécifique de clusters dans les données (nous avons bien 3
variétés). Il est mieux pour nous de choisir la méthode des kmeans dans
l’ensemble. Mais particulierement, le nombre de clusters se fait mieux
avec la CHA, et le clustering avec les K-means.
Pour aller plus
loin
Nous pourrons comparer nos resultas avec plusieurs autres methodes de
clustering, il existe une large varieté d’algorithme de classification
non supervisé. Comme par exemple la methode MNIVAR (variance minimizing
hierarchical clustering) mais malheureusement n’avons trouvé que des
articles payants a ce sujet…
Nous avons alors decidé de tester d’autre methode, tel que
l’alghortime de CLARA. Au lieu de trouver des médoïdes pour l’ensemble
de données, CLARA considère un petit échantillon de données avec une
taille fixe (sampsize) et applique l’algorithme PAM pour générer un
ensemble optimal de médoïdes pour l’échantillon. La qualité des médoïdes
résultants est mesurée par la dissemblance moyenne entre chaque objet de
l’ensemble de données et le médoïde de son cluster, défini comme la
fonction de coût.
CLARA répète les processus d’échantillonnage et de regroupement un
nombre de fois prédéfini afin de minimiser le biais d’échantillonnage.
Les résultats de regroupement finaux correspondent à l’ensemble des
médoïdes avec le coût minimal.
size max_diss av_diss isolation
[1,] 74 2.953138 1.432597 1.4337330
[2,] 64 2.599767 1.355004 0.7086906
[3,] 72 2.809322 1.353406 1.3639109
Nous remarquons que l’alghorithme a classé : 74 kama, 64 Rosa et 72
Canadian…ce qui n’est toujours pas parfait…
size max_diss av_diss diameter separation
[1,] 77 2.769122 1.400510 4.601093 0.5747312
[2,] 62 2.334422 1.322603 3.954075 0.5747312
[3,] 71 3.168492 1.331149 5.155598 0.6125787
Nous remarquons que l’alghorithme a classé : 77 kama, 62 Rosa et 71
Canadian…ce qui n’est toujours pas parfait…
LS0tCnRpdGxlOiAiTW9kw6hsZXMgw6Agc3RydWN0dXJlIGxhdGVudGUiCnN1YnRpdGxlOiBUUDEgRG9ubsOpZXMsIEttZWFucywgQ0hBCmF1dGhvcjogIkhheXRoZW0gQm91Y2hhcmlmIC0gRmVyZGluYW5kIEdlbmFucyAtIEN5bnRoaWEgTGVwZXJlIC0gS2hvYSBBbmggTmdvIgpkYXRlOiAiTm92ZW1icmUgMjAyMiIKbGFuZzogImZyIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICBwZGZfZG9jdW1lbnQ6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCi0tLQoKYGBge3IgZ2xvYmFsX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249ImNlbnRlciIsIGZpZy5wb3M9IkgiLGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00KQpsaWJyYXJ5KGdncGxvdDIpICNwb3VyIGFtw6lsaW9yZXIgbGVzIGdyYXBoaXF1ZXMKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikgI3BvdXIgdXRpbGlzZXIgZ2F0aGVyCmxpYnJhcnkobWFncml0dHIpICNwb3VyIHV0aWxpc2VyIGwnb3DDqXJhdGV1ciBwaXBlCmxpYnJhcnkoa2FibGVFeHRyYSkgI3BvdXIgYW3DqWxpb3JlciBsZXMgdGFibGVhdXgKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZmFjdG9leHRyYSkgI3BvdXIgdmlzdWFsaXNlciBsZXMga21lYW5zCmxpYnJhcnkoZnBjKSAjcG91ciB1dGlsaXNlciBsYSBmb25jdGlvbiBjbHVzdGVyLnN0YXQoKQpsaWJyYXJ5KGdnZGVuZHJvKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkodmN0cnMpCmxpYnJhcnkoYWRlNCkKbGlicmFyeShGYWN0b01pbmVSKQpsaWJyYXJ5KHF1ZXN0aW9ucikKYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSkKYGBgCgojIERvbm7DqWVzLCBBQ1AKCkRhbnMgY2V0dGUgcHJlbWllcmUgcGFydGllIG5vdXMgdHJhdmFpbGxvbnMgc3VyIGxlcyBkb25uw6llcyBjcmFicywgYWZpbiBkJ2lsbHVzdHJlciBsZSBkYW5nZXIgcG9zc2libGUgZGUgbOKAmXV0aWxpc2F0aW9uIGRlIGzigJlBQ1AuCgojIyBMZXMgZG9ubsOpZXMKCkNldCBlbnNlbWJsZSBkZSBkb25uw6llcyBjb250aWVudCBkZXMgbWVzdXJlcyBtb3JwaG9sb2dpcXVlcyBzdXIgbGVzIGNyYWJlcyBMZXB0b2dyYXBzdXMuICAKSWwgY29udGllbnQgMjAwIG9ic2VydmF0aW9ucyBldCA4IHZhcmlhYmxlcy4gIAoKYGBge3IgY3JhYnMsIGVjaG89RkFMU0V9CmRhdGEgPSBjcmFicwojc3VtbWFyeShkYXRhKQojc3RyKGRhdGEpCgprYWJsZShkYXRhWzE6NSxdLCBjYXB0aW9uPSJBcHBlcmN1IGR1IGpldSBkZSBkb25uw6llcyBDcmFicyIsIGJvb2t0YWJzPVQpICU+JQprYWJsZV9zdHlsaW5nKGxhdGV4X29wdGlvbnM9Yygic3RyaXBlZCIsICJob2xkX3Bvc2l0aW9uIikpCmBgYApDZSBqZXUgY29tcHRhYmlsaXNlIDUgbWVzdXJlcyBtb3JwaG9sb2dpcXVlcyBzdXIgMjAwIGNyYWJlcywgZGUgZGV1eCBjb3VsZXVycyBldCBkZXMgZGV1eCBzZXhlcywgZGUgbCdlc3DDqGNlIExlcHRvZ3JhcHN1cyB2YXJpZWdhdHVzIGNvbGxlY3TDqWUgw6AgRnJlbWFudGxlIGVuIEF1c3RyYWxpZSBvY2NpZGVudGFsZS4KCk5vdXMgYXZvbnMgZGV1eCB2YXJpYWJsZXMgcXVhbGl0YXRpdmVzIDoKCiogKipzcCoqID0gTCdlc3DDqGNlIDogQiBwb3VyIEJsZXUgb3UgTyBwb3VyIE9yYW5nZQoqICoqc2V4KiogPSBMZSBzZXhlIDogTSBwb3VyIE1hbGUgb3UgRiBwb3VyIEZlbWVsbGUKCkV0IHNpeCB2YXJpYWJsZXMgcXVhbnRpdGF0aXZlcyA6ICAKCiogKippbmRleCoqID0gVW4gaW5kaWNlIGFsbGFudCBqdXNxJ8OgIDUwIGRhbnMgY2hhY3VuIGRlcyBxdWF0cmUgZ3JvdXBlcwoqICoqRkwqKiA9IGxhIHRhaWxsZSBkdSBsb2JlIGZyb250YWwgZW4gbW0KKiAqKlJXKiogPSBsYSBsYXJnZXVyIGR1IGRvcyBlbiBtbQoqICoqQ0wqKiA9IGxhIGxvbmd1ZXVyIGRlIGxhIGNhcmFwYWNlIGVuIG1tCiogKipDVyoqID0gbGEgbGFyZ2V1ciBkZSBsYSBjYXJhcGFjZSBlbiBtbQoqICoqQkQqKiA9IGxhIHByb2ZvbmRldXIgZHUgY29ycHMgZW4gbW0KCk5vdXMgbm91cyBkZW1hbmRvbnMgcXVlbGxlcyB2YXJpYWJsZXMgc29udCBsZXMgcGx1cyBpbXBvcnRhbnRlcz8gIApDb21tZW50IHLDqWR1aXJlIGNlIGpldSBkZSBkb25uw6llcyBhZmluIGRlIGxlIHJlcHLDqXNlbnRlciBkZSBtYW5pw6hyZSBzaW1wbGUgc3VyIDIgb3UgMyBheGVzIHBhciBleGVtcGxlPyAgCkdyYWNlIGEgbCdBbmFseXNlIGVuIENvbXBvc2FudGVzIFByaW5jaXBhbGVzIG5vdXMgYWxsb25zIHBvdXZvaXIgZmFpcmUgdW5lIHLDqWR1Y3Rpb24gZGUgZGltZW5zaW9uLCBldCB0cmFuc2Zvcm1lciBsZXMgdmFyaWFibGVzIHRyw6hzIGNvcnLDqWzDqWVzIGVuIG5vdXZlbGxlcyB2YXJpYWJsZXMgZMOpY29ycsOpbMOpZXMgbGVzIHVuZXMgZGVzIGF1dHJlcy4gIArDiXZpZGVtbWVudCwgcXVpIGRpdCByw6lkdWN0aW9uIGRlIGRpbWVuc2lvbiBkaXQgcGVydGUgZOKAmWluZm9ybWF0aW9ucy4gIApD4oCZZXN0IGzDoCB0b3V0IGzigJllbmpldSA6IGlsIGZhdXQgcG91dm9pciByw6lkdWlyZSBsYSBkaW1lbnNpb24gZGUgbm9zIGRvbm7DqWVzIHRvdXQgZW4gY29uc2VydmFudCB1biBtYXhpbXVtIGTigJlpbmZvcm1hdGlvbnMuICAKClBvdXIgYXZvaXIgdW5lIHByZW1pZXJlIGlkw6llIHN1ciBjZXMgZG9ubsOpZXMsIG9uIGNvbW1lbmNlIHBhciB0cmFjZXIgdW4gaGlzdG9ncmFtbWU6CgpgYGB7ciBjcmFic0hpc3RvLCBlY2hvPUZBTFNFfQojIEhpc3RvZ3JhbW1lcwpkYXRhX2FjcCA9IGRhdGFbLDQ6OF0KZmlnIDwtIHBsb3RfbHkodHlwZT0naGlzdG9ncmFtJyx4PX5kYXRhX2FjcCRGTCxiaW5ncm91cD0xKQpmaWcgPC0gZmlnICU+JSBhZGRfdHJhY2UodHlwZT0naGlzdG9ncmFtJyx4PX5kYXRhX2FjcCRSVyxiaW5ncm91cD0xKQpmaWcgPC0gZmlnICU+JSBhZGRfdHJhY2UodHlwZT0naGlzdG9ncmFtJyx4PX5kYXRhX2FjcCRDTCxiaW5ncm91cD0xKQpmaWcgPC0gZmlnICU+JSBhZGRfdHJhY2UodHlwZT0naGlzdG9ncmFtJyx4PX5kYXRhX2FjcCRDVyxiaW5ncm91cD0xKQpmaWcgPC0gZmlnICU+JSBhZGRfdHJhY2UodHlwZT0naGlzdG9ncmFtJyx4PX5kYXRhX2FjcCRCRCxiaW5ncm91cD0xKQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoYmFybW9kZT0ib3ZlcmxheSIsYmFyZ2FwPTAuMSkKZmlnCmBgYApFbiBkw6lwbGHDp2FudCBsZSBjdXJzZXVyIHN1ciBsZSBncmFwaGlxdWUgbm91cyBwb3V2b25zIHZvaXIgZmFjaWxlbWVudCBsZXMgdmFsZXVycyBkZSBub3MgNSB2YXJpYWJsZXMgZCdpbnRlcmV0LgoKUG91ciB2b2lyIG1haW50ZW5hbnQgY29tbWVudCBsJ3VuZSBkZSBjZXMgdmFyaWFibGUgZXN0IGFmZmVjdMOpZSBwYXIgdW5lIGF1dHJlLCBub3VzIHLDqWFsaXNvbnMgdW4gc2NhdHRlciBwbG90OgoKYGBge3IgY3JhYnNTY2F0dGVyLCBlY2hvPUZBTFNFfQojIFNjYXR0ZXIgcGxvdHMKYXhpcyA9IGxpc3Qoc2hvd2xpbmU9RkFMU0UsemVyb2xpbmU9RkFMU0UsZ3JpZGNvbG9yPScjZmZmZicsdGlja2xlbj00KQoKZmlnX3NjYXR0ZXIgPC0gZGF0YV9hY3AgJT4lIHBsb3RfbHkoKSAKZmlnX3NjYXR0ZXIgPC0gZmlnX3NjYXR0ZXIgJT4lIGFkZF90cmFjZSh0eXBlID0gJ3NwbG9tJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1lbnNpb25zID0gbGlzdChsaXN0KGxhYmVsPSdGTCcsIHZhbHVlcz1+ZGF0YV9hY3AkRkwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KGxhYmVsPSdSVycsdmFsdWVzPX5kYXRhX2FjcCRSVyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QobGFiZWw9J0NMJywgdmFsdWVzPX5kYXRhX2FjcCRDTCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QobGFiZWw9J0NXJyx2YWx1ZXM9fmRhdGFfYWNwJENXKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsYWJlbD0nQkQnLHZhbHVlcz1+ZGF0YV9hY3AkQkQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KHNpemUgPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZSA9IGxpc3Qod2lkdGggPSAxLGNvbG9yID0gJ3JnYigyMzAsMjMwLDIzMCknKSkpCmZpZ19zY2F0dGVyIDwtIGZpZ19zY2F0dGVyICU+JSBsYXlvdXQodGl0bGU9ICdDcmFicyBEYXRhIHNldCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG92ZXJtb2RlPSdjbG9zZXN0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcmFnbW9kZT0gJ3NlbGVjdCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9iZ2NvbG9yPSdyZ2JhKDI0MCwyNDAsMjQwLCAwLjk1KScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXM9bGlzdChkb21haW49TlVMTCxzaG93bGluZT1GLHplcm9saW5lPUYsZ3JpZGNvbG9yPScjZmZmZicsdGlja2xlbj03KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcz1saXN0KGRvbWFpbj1OVUxMLCBzaG93bGluZT1GLCB6ZXJvbGluZT1GLCBncmlkY29sb3I9JyNmZmZmJywgdGlja2xlbj03KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpczI9YXhpcyx4YXhpczM9YXhpcyx4YXhpczQ9YXhpcyx5YXhpczI9YXhpcyx5YXhpczM9YXhpcyx5YXhpczQ9YXhpcykKCmZpZ19zY2F0dGVyCmBgYApEZSBtw6ptZSwgbGUgY3Vyc2V1ciBub3VzIHBlcm1ldCBkJ29idGVuaXIgZmFjaWxlbWVudCBjaGFxdWUgdmFsZXVyLiAgCk5vdXMgcmVtYXJxdW9ucyBxdWUgbGVzIHZhcmlhYmxlcyBDTCBldCBDVyBzJ2FsaWduZW50IHBhcmZhaXRlbWVudCBzdXIgdW5lIG3Dqm1lIGRyb2l0ZSwgZWxsZXMgc29udCBmb3J0ZW1lbnQgbGnDqWVzLCBlbGxlcyBzb250IGNvcnLDqWzDqWVzLiBMZXVyIGNvZWZmY2llbnQgZGUgY29ycsOpbGF0aW9uIGVzdCBwcm9jaGUgZGUgMS4gIApMZXMgdmFyaWFibGVzIEJEIGV0IFJXIHNvbnQgbGVzIG1vaW5zIGxpw6llcy4gIApMZXMgYXV0cmVzIHZhcmlhYmxlcyBzb250IGVsbGVzIGF1c3NpIGNvcnJlbMOpZXMsIG1haXMgdW4gcGV1IG1vaW5zLiBMZXVycyBjb2VmZmljaWVudHMgZGUgY29ycsOpbGF0aW9uIGVzdCBwcm9jaGUgZGUgMC44LiAgClF1b2kgcXUnaWwgZW4gc29pdCwgb24gdm9pdCB1bmUgdHLDqHMgZm9ydGUgY29ycsOpbGF0aW9uIGfDqW7DqXJhbGUgZW50cmUgbGVzIGRvbm7DqWVzLiAoZGl0ICJlZmZldCB0YWlsbGUiKSAgCgojIyBQcm9wb3J0aW9uIGRlIHZhcmlhbmNlIGV4cGxpcXXDqWUgcGFyIGxlcyBkZXV4IHByZW1pw6hyZXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXMKCmBgYHtyIGNyYWJzQUNQLCBlY2hvPUZBTFNFfQphY3AgPSBQQ0EoZGF0YV9hY3AsIHNjYWxlLnVuaXQgPSBUUlVFLCBuY3AgPSAyLCBncmFwaCA9IFRSVUUpCgpmdml6X2VpZyhhY3AsIGFkZGxhYmVscyA9IFRSVUUsIGJhcmZpbGwgPSAibmF2eSIsIGJhcmNvbG9yID0gIm5hdnkiLCBsaW5lY29sb3IgPSAiZGVlcHBpbmsiLCBnZ3RoZW1lID0gdGhlbWVfZ3JleSgpKQoKI3ZhcmlhbmNlIGRlcyB2YWxldXJzIHByb3ByZXM6CiNlaWdfdmFsdWUgPSBnZXRfZWlnZW52YWx1ZShhY3ApCiNlaWdfdmFsdWUKCmBgYApTdXIgbGUgZGV1eGllbWUgZ3JhcGhpcXVlICJQQ0EgZ3JhcGggb2YgdmFyaWFibGVzIiBsZXMgdmFyaWFibGVzIGNvcnLDqWzDqWVzIHBvc2l0aXZlbWVudCBzb250IGR1IG3Dqm1lIGPDtHTDqSBkdSBncmFwaGlxdWUuIExlcyB2YXJpYWJsZXMgY29ycsOpbMOpZXMgbsOpZ2F0aXZlbWVudCBzb250IHN1ciBkZXMgY8O0dMOpcyBvcHBvc8OpcyBkdSBncmFwaGlxdWUuICAKTm91cyB2b3lvbnMgcXVlIG5vdXMgYXZvbnMgOTUsNzglIGRlIGxhIHZhcmlhbmNlIGV4cGxpcXXDqWUgcGFyIGxlIHByZW1pZXIgYXhlIHByaW5jaXBhbCwgZXQgc2V1bGVtZW50IDMsMDMlIHBhciBsZSBkZXV4aWVtZS4KQ2VsYSBub3VzIGxhaXNzZSBwZW5zZXIgcXVlIG5vdXMgcG91dm9ucyBleHByaW1lciBub3MgZG9ubsOpZXMgYXZlYyB1bmlxdWVtZW50IGxhIHByZW1pZXJlIGNvbXBvc2FudGUgcHJpbmNpcGFsZS4KCgojIyBQcm9qZWN0aW9uIHN1ciBsYSBwcmVtacOocmUgY29tcG9zYW50ZSBwcmluY2lwYWxlCgpgYGB7ciBjcmFic0NQMSwgZWNobz1GQUxTRX0KZnZpel9jb250cmliKGFjcCwgY2hvaWNlPSJ2YXIiLCBheGVzPTEsIHRvcD0xMCwgY29sb3I9Im5hdnkiLCBmaWxsPSJuYXZ5IiwgYWxwaGE9MC42LCBnZ3RoZW1lPXRoZW1lX2dyZXkoKSkKYGBgCkxhIGxpZ25lIGVuIHBvaW50aWxsw6kgcm91Z2Ugbm91cyBpbmRpcXVlIGxhIGNvbnRyaWJ1dGlvbiBtb3llbm5lIGF0dGVuZHVlLiAgClNpIGxhIGNvbnRyaWJ1dGlvbiBkZXMgdmFyaWFibGVzIMOpdGFpdCB1bmlmb3JtZSwgbGEgdmFsZXVyIGF0dGVuZHVlIHNlcmFpdCAxL2xlbmd0aCh2YXJpYWJsZXMpID0gMS8xMCA9IDEwJS4gIApQb3VyIHVuZSBjb21wb3NhbnRlIGRvbm7DqWUsIHVuZSB2YXJpYWJsZSBhdmVjIHVuZSBjb250cmlidXRpb24gc3Vww6lyaWV1cmUgw6AgY2Ugc2V1aWwgcG91cnJhaXQgw6p0cmUgY29uc2lkw6lyw6llCmNvbW1lIGltcG9ydGFudGUgcG91ciBjb250cmlidWVyIMOgIGxhIGNvbXBvc2FudGUuICAKTm91cyByZW1hcnF1b25zIHF1ZSBsZXMgdmFyaWJhbGVzIENMLEZMLEJELENXIHNvbnQgbGVnZXJlbWVudCBpbXBvcnRhbnRlcyBwb3VyIGxhIGNvbnRyaWJ1dGlvbiBhIGNldCBheGUsCmNvbnRyYWlyZW1lbnQgYSBsYSB2YXJpYWJsZSBSVyBxdWkgc2UgdHJvdXZlIGVuIGRlc3NvdXMgZGUgY2Ugc2V1aWwuCgojIyBQcm9qZWN0aW9uIHN1ciBsYSBkZXV4acOobWUgY29tcG9zYW50ZSBwcmluY2lwYWxlCgpgYGB7ciBjcmFic0NQMiwgZWNobz1GQUxTRX0KIyBDb250cmlidXRpb25zIGRlcyB2YXJpYWJsZXMgw6AgUEMyCmZ2aXpfY29udHJpYihhY3AsIGNob2ljZT0idmFyIiwgYXhlcz0yLCB0b3A9MTAsIGNvbG9yPSJuYXZ5IiwgZmlsbD0ibmF2eSIsIGFscGhhPTAuNiwgZ2d0aGVtZT10aGVtZV9ncmV5KCkpCmBgYApOb3VzIHJlbWFycXVvbnMgbWFpbnRlbmFudCwgYSBsJ2ludmVyc2UsIHF1ZSBsYSB2YXJpYWJsZSBSVyBlc3QgY2VsbGUgcXVpIGNvbnRyaWJ1ZSBsZSBwbHVzIHBvdXIgbGUgZGV1eGllbWUgYXhlLiAoZXQgZGUgbG9pbikKCiMjIFByb2plY3Rpb24gc3VyIGxlcyBkZXV4IHByZW1pw6hyZXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXMKCmBgYHtyIGNyYWJzQ1AxQ1AyLCBlY2hvPUZBTFNFfQpmdml6X2NvbnRyaWIoYWNwLCBjaG9pY2U9InZhciIsIGF4ZXM9MToyLCB0b3A9MTAsIGNvbG9yPSJuYXZ5IiwgZmlsbD0ibmF2eSIsIGFscGhhPTAuNiwgZ2d0aGVtZT10aGVtZV9ncmV5KCkpCmBgYApOb3VzIHJlbWFycXVvbnMgcXVlIGxlcyB2YXJpYWJsZXMgQ1cgZXQgQ0wgc29udCBsZXMgc2V1bGVzIGEgY29udHJpYnVlciBkw6lzb3JtYWlzLgoKCiMjIENvbmNsdXNpb24KCk5vdXMgZMOpY2lkb25zIGRlIHByb2pldGVyIGxlcyBkb25uw6llcyBzdXIgc2VzIGNvbXBvc2FudGVzIHByaW5jaXBhbGVzLCBjcm9pc8OpZXMgZW50cmUgZWxsZXMuClRvdXQgZCdhYm9yZCwgcG91ciBsZSBzZXhlLCBub3VzIG9idGVub25zIDoKCmBgYHtyIGNyYWJzU2V4ZSwgZWNobz1GQUxTRX0KYWNwID0gcHJjb21wKGRhdGFfYWNwKQoKIyBTY2F0dGVyIGFjcApleHBsYWluZWRfdmFyaWFuY2VfcmF0aW8gPC0gc3VtbWFyeShhY3ApW1siaW1wb3J0YW5jZSJdXVsnUHJvcG9ydGlvbiBvZiBWYXJpYW5jZScsXQpleHBsYWluZWRfdmFyaWFuY2VfcmF0aW8gPC0gMTAwICogZXhwbGFpbmVkX3ZhcmlhbmNlX3JhdGlvCmNvbXBvbmVudHMgPC0gYWNwW1sieCJdXQpjb21wb25lbnRzIDwtIGRhdGEuZnJhbWUoY29tcG9uZW50cykKY29tcG9uZW50cyA8LSBjYmluZChjb21wb25lbnRzLCBkYXRhJHNleCkKCmF4aXMgPSBsaXN0KHNob3dsaW5lPUZBTFNFLHplcm9saW5lPUZBTFNFLGdyaWRjb2xvcj0nI2ZmZmYnLHRpY2tsZW49NCx0aXRsZWZvbnQ9bGlzdChzaXplPTEzKSkKCmZpZ19hY3AgPC0gY29tcG9uZW50cyAlPiUKICBwbG90X2x5KCkgICU+JQogIGFkZF90cmFjZSh0eXBlID0gJ3NwbG9tJywKICAgICAgZGltZW5zaW9ucyA9IGxpc3QoCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgMSAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bMV0sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDMSksCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgMiAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bMl0sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDMiksCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgMyAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bM10sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDMyksCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgNCAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bNF0sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDNCkpLAogICAgICBjb2xvciA9IH5kYXRhJHNleCwgY29sb3JzID0gYygnIzYzNkVGQScsJyNFRjU1M0InKSkgJT4lCiAgc3R5bGUoZGlhZ29uYWwgPSBsaXN0KHZpc2libGUgPSBGQUxTRSkpICU+JQogIGxheW91dChsZWdlbmQ9bGlzdCh0aXRsZT1saXN0KHRleHQ9J2NvbG9yJykpLGhvdmVybW9kZT0nY2xvc2VzdCcsZHJhZ21vZGU9ICdzZWxlY3QnLAogICAgcGxvdF9iZ2NvbG9yPSdyZ2JhKDI0MCwyNDAsMjQwLCAwLjk1KScsCiAgICB4YXhpcz1saXN0KGRvbWFpbj1OVUxMLCBzaG93bGluZT1GLCB6ZXJvbGluZT1GLCBncmlkY29sb3I9JyNmZmZmJywgdGlja2xlbj00KSwKICAgIHlheGlzPWxpc3QoZG9tYWluPU5VTEwsIHNob3dsaW5lPUYsIHplcm9saW5lPUYsIGdyaWRjb2xvcj0nI2ZmZmYnLCB0aWNrbGVuPTQpLAogICAgeGF4aXMyPWF4aXMseGF4aXMzPWF4aXMseGF4aXM0PWF4aXMseWF4aXMyPWF4aXMseWF4aXMzPWF4aXMseWF4aXM0PWF4aXMpCmZpZ19hY3AKYGBgCgpQdWlzLCBwb3VyIGxlIHR5cGUgZCdlc3BlY2Ugbm91cyBvYnRlbm9uczoKCmBgYHtyIGNyYWJzRXNwZWNlcywgZWNobz1GQUxTRX0KZXhwbGFpbmVkX3ZhcmlhbmNlX3JhdGlvIDwtIHN1bW1hcnkoYWNwKVtbImltcG9ydGFuY2UiXV1bJ1Byb3BvcnRpb24gb2YgVmFyaWFuY2UnLF0KZXhwbGFpbmVkX3ZhcmlhbmNlX3JhdGlvIDwtIDEwMCAqIGV4cGxhaW5lZF92YXJpYW5jZV9yYXRpbwpjb21wb25lbnRzIDwtIGFjcFtbIngiXV0KY29tcG9uZW50cyA8LSBkYXRhLmZyYW1lKGNvbXBvbmVudHMpCmNvbXBvbmVudHMgPC0gY2JpbmQoY29tcG9uZW50cywgZGF0YSRzcCkKCmF4aXMgPSBsaXN0KHNob3dsaW5lPUZBTFNFLHplcm9saW5lPUZBTFNFLGdyaWRjb2xvcj0nI2ZmZmYnLHRpY2tsZW49NCx0aXRsZWZvbnQ9bGlzdChzaXplPTEzKSkKCmZpZ19hY3AgPC0gY29tcG9uZW50cyAlPiUKICBwbG90X2x5KCkgICU+JQogIGFkZF90cmFjZSh0eXBlID0gJ3NwbG9tJywKICAgICAgZGltZW5zaW9ucyA9IGxpc3QoCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgMSAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bMV0sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDMSksCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgMiAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bMl0sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDMiksCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgMyAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bM10sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDMyksCiAgICAgICAgbGlzdChsYWJlbD1wYXN0ZSgnUEMgNCAoJyx0b1N0cmluZyhyb3VuZChleHBsYWluZWRfdmFyaWFuY2VfcmF0aW9bNF0sMSkpLCclKScsc2VwID0gJycpLCB2YWx1ZXM9flBDNCkpLAogICAgICBjb2xvciA9IH5kYXRhJHNwLCBjb2xvcnMgPSBjKCcjNjM2RUZBJywnI0VGNTUzQicpKSAlPiUKICBzdHlsZShkaWFnb25hbCA9IGxpc3QodmlzaWJsZSA9IEZBTFNFKSkgJT4lCiAgbGF5b3V0KGxlZ2VuZD1saXN0KHRpdGxlPWxpc3QodGV4dD0nY29sb3InKSksaG92ZXJtb2RlPSdjbG9zZXN0JyxkcmFnbW9kZT0gJ3NlbGVjdCcsCiAgICBwbG90X2JnY29sb3I9J3JnYmEoMjQwLDI0MCwyNDAsIDAuOTUpJywKICAgIHhheGlzPWxpc3QoZG9tYWluPU5VTEwsIHNob3dsaW5lPUYsIHplcm9saW5lPUYsIGdyaWRjb2xvcj0nI2ZmZmYnLCB0aWNrbGVuPTQpLAogICAgeWF4aXM9bGlzdChkb21haW49TlVMTCwgc2hvd2xpbmU9RiwgemVyb2xpbmU9RiwgZ3JpZGNvbG9yPScjZmZmZicsIHRpY2tsZW49NCksCiAgICB4YXhpczI9YXhpcyx4YXhpczM9YXhpcyx4YXhpczQ9YXhpcyx5YXhpczI9YXhpcyx5YXhpczM9YXhpcyx5YXhpczQ9YXhpcykKZmlnX2FjcApgYGAKCk5vdXMgY29uY2x1b25zIGZpbmFsZW1lbnQgcXVlIGwnQUNQIG5vdXMgcG91c3NlIGEgcmV0ZW5pciBxdSd1biBzZXVsIGF4ZSBwcmluY2lwYWwsIGFsb3JzIHF1ZSBkYW5zIGxlcyBmYWl0cywgdG91dGVzIGxlcyB2YXJpYWJsZXMgY29udHJpYnVlbnQgdW5pZm9ybWVtZW50IHN1ciBsZXMgZGV1eCBwcmVtaWVycyBheGVzLCBldCBxdSdpbCBmYXV0IGdhcmRlciBsZXMgZGV1eCBwb3VyIHVuZSBtZWlsbGV1cmUgaW50ZXJwZXRhdGlvbiEhCgojIEttZWFucyBldCBjbHVzdGVyaW5nIGhpw6lyYXJjaGlxdWUgYXNjZW5kYW50CgojIyBMZXMgZG9ubsOpZXMKCkNvbW1lIHByb3Bvc8OpLCBub3VzIGFsbG9ucyB0cmF2YWlsbGVyIHN1ciBsZXMgZG9ubsOpZXMgU2VlZHMuICAKQ2V0IGVuc2VtYmxlIGRlIGRvbm7DqWVzIGNvbnRpZW50IGRlcyBtZXN1cmVzLCBjb3JyZXNwb25kYW50ZXMgYXV4IHByb3ByacOpdMOpcyBnw6lvbcOpdHJpcXVlcyBkZSBncmFpbnMgZGUgYmzDqS4gIApJbCBjb250aWVudCAyMTAgb2JzZXJ2YXRpb25zIGV0IDggdmFyaWFibGVzLiAgCgpgYGB7ciBzZWVkcywgZWNobz1GQUxTRX0Kc2VlZHMgPC0gcmVhZC50YWJsZSgic2VlZHNfZGF0YXNldC50eHQiKQoKY29sbmFtZXMoc2VlZHMpPSBjKCJTdXJmYWNlIiwgIlDDqXJpbcOodHJlIiwiQ29tcGFjaXTDqSIsICJMb25ndWV1ciIsICJMYXJnZXVyIiwgIkNvZWZBc3ltIiwgIlJhaW51cmUiLCAiVmFyacOpdMOpcyIpCnNlZWRzID0gbXV0YXRlKHNlZWRzLFZhcmnDqXTDqXMgPSBjYXNlX3doZW4oVmFyacOpdMOpcz09MX4iS2FtYSIsIFZhcmnDqXTDqXM9PTJ+IlJvc2EiLCBWYXJpw6l0w6lzPT0zfiJDYW5hZGlhbiIpKSAlPiUKICAgICAgICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBmYWN0b3IpCnNlZWRzIDwtIHNlZWRzWyxjKCJWYXJpw6l0w6lzIiwiU3VyZmFjZSIsICJQw6lyaW3DqHRyZSIsIkNvbXBhY2l0w6kiLCAiTG9uZ3VldXIiLCAiTGFyZ2V1ciIsICJDb2VmQXN5bSIsICJSYWludXJlIildCgprYWJsZShzZWVkc1sxOjUsXSwgY2FwdGlvbj0iQXBwZXJjdSBkdSBqZXUgZGUgZG9ubsOpZXMgU2VlZHMiLCBib29rdGFicz1UKSAlPiUKa2FibGVfc3R5bGluZyhsYXRleF9vcHRpb25zPWMoInN0cmlwZWQiLCAiaG9sZF9wb3NpdGlvbiIpKQpgYGAKCk5vdXMgYXZvbnMgdHJvaXMgdmFyacOpdMOpcyBkZSBncmFpbnMgZGUgYmzDqSBkaWZmw6lyZW50ZXMsIGRlIDcwIMOpbMOpbWVudHMgY2hhY3VuLCBjaG9pc2lzIGF1IGhhc2FyZCA6CgoqICoqVmFyacOpdMOpcyoqID0gS2FtYSwgUm9zYSBldCBDYW5hZGlhbiAgCgpFdCBzZXB0IHBhcmFtw6h0cmVzIGfDqW9tw6l0cmlxdWVzIChjb250aW51cyDDoCB2YWxldXIgcsOpZWxsZSkgbWVzdXLDqXMgOiAgCgoqICoqU3VyZmFjZSoqID0gbGEgc3VyZmFjZSBBCiogKipQw6lyaW3DqHRyZSoqID0gbGUgcMOpcmltw6h0cmUgUAoqICoqQ29tcGFjaXTDqSoqID0gbGEgY29tcGFjaXTDqSAkQyA9IFxmcmFjezRccGkgQX17UF4yfSQKKiAqKkxvbmd1ZXVyKiogPSBsYSBsb25ndWV1ciBkdSBub3lhdQoqICoqTGFyZ2V1cioqID0gbGEgbGFyZ2V1ciBkdSBub3lhdQoqICoqQ29lZkFzeW0qKiA9IGxlIGNvZWZmaWNpZW50IGQnYXN5bcOpdHJpZQoqICoqUmFpbnVyZSoqID0gbGEgbG9uZ3VldXIgZGUgbGEgcmFpbnVyZSBkdSBub3lhdQoKQSBwYXJ0aXIgZGUgY2VzIHNlcHQgcGFyYW1ldHJlcywgbm90cmUgb2JqZWN0aWYgZGUgY2x1c3RlcmluZyBzZXJhIGRvbmMgZGUgcmVncm91cGVyIGxlcyAyMTAgZ3JhaW5zIGVuIEsgY2xhc3NlcywgIApsZXMgcGx1cyBjb25jZW50csOpZXMgZXQgZGlzY3RpbmN0ZXMgcG9zc2libGVzLiAgIApOb3VzIGFsbG9ucyBkb25jIGZhaXJlIGNvbW1lIHNpIG5vdXMgbmUgc2F2aW9ucyBwYXMgYSBxdWVsbGUgdmFyacOpdMOpIGNoYXF1ZSBncmFpbiBhcHBhcnRlbmFpdCwgZXQgZXNzYXllciBkZSByZXRvbWJlciBzdXIgbm9zIDMgY2x1c3RlcnMgOiAgCkthbWEgLSBSb3NhIC0gQ2FuYWRpYW4sIHRvdXMgZGlzdGluY3RzLCBkZSB0YWlsbGUgNzAuCgpQb3VyIGF2b2lyIHVuZSBwcmVtaWVyZSBpZMOpZSBkZXMgZG9ubsOpZXMsIHLDqWFsaXNvbnMgcXVlbHF1ZXMgZ3JhcGhpcXVlcy4gIApPbiBjb21tZW5jZSBwYXIgdHJhY2VyIHVuIGhpc3RvZ3JhbW1lIGRlIG5vcyA3IHBhcmFtw6h0cmVzIG5vcm1hbGlzw6lzOgoKYGBge3Igc2VlZHNIaXN0bywgZWNobz1GQUxTRX0KI21pc2UgYSBsJ2VjaGVsbGUKc2NhbGVzZWVkcyA9IHNjYWxlKHNlZWRzWywyOjhdLCBjZW50ZXI9VFJVRSwgc2NhbGU9VFJVRSkKc2NhbGVzZWVkcyA9IGFzX3RpYmJsZShzY2FsZXNlZWRzKQpzY2FsZXNlZWRzJFZhcmnDqXTDqXMgPSBzZWVkcyRWYXJpw6l0w6lzCiNzdW1tYXJ5KHNjYWxlc2VlZHMpCgojSGlzdG9ncmFtbWVzCnNjYWxlc2VlZHMgJT4lCmdhdGhlcihhdHRyaWJ1dGVzLCB2YWx1ZSwgMTo3KSAlPiUKICAKZ2dwbG90KGFlcyh4PXZhbHVlKSkgKwpnZW9tX2hpc3RvZ3JhbShmaWxsPSduYXZ5JywgY29sb3I9J25hdnknLCBhbHBoYT0wLjUsIGJpbnM9MzApICsKZmFjZXRfd3JhcCh+YXR0cmlidXRlcywgc2NhbGVzPSdmcmVlX3gnKSArCmdndGl0bGUoIkhpc3RvZ3JhbW1lcyIpICsgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsgbGFicyh4PU5VTEwsIHk9TlVMTCkKYGBgCkNlcyBoaXN0b2dyYW1tZXMgcmVwcmVzZW50ZW50IGxhIGZyw6lxdWVuY2UgZW4gZm9uY3Rpb24gZGVzIHZhbGV1cnMgZGUgbm9zIHZhcmlhYmxlcy4gIApOb3VzIHZveW9ucyBiaWVuIGxhIHN5bcOpdHJpZSwgZMO7IGEgbGEgbWlzZSBhIGwnZWNoZWxsZSwgbWFpcyBjJ2VzdCB0b3V0Li4uaWwgbm91cyBlc3QgZGlmZmljaWxlIGRlIHNhdm9pciBjb21iaWVuIGRlIGNvbXBvc2FudGVzIG5vdXMgc2Vyb250IG7DqWNlc3NhaXJlcyBwb3VyIGTDqWNyaXJlIGxlcyBkb25uw6llcy4gIAoKTm91cyBkw6ljaWRvbnMgZG9uYyBkZSBmYWlyZSB1bmUgQUNQIHN1ciBub3MgNyB2YXJpYWJsZXMgcXVhbnRpdGF0aXZlcyBjb250aW51ZXMsIGFmaW4gZGUgcsOpZHVpcmUgbGEgZGltZW5zaW9uIGRlIG5vcyBkb25uw6llcyB0b3V0IGVuIGdhcmRhbnQgdW4gbWF4aW11bSBkZSBs4oCZaW5mb3JtYXRpb24uCgpgYGB7ciBzZWVkc0FDUCwgY29tbWVudD1OQSwgZWNobz1GQUxTRX0KYWNwID0gcHJjb21wKHNjYWxlc2VlZHNbLDE6N10pCiN2YXJpYW5jZSBjb21wb3NhbnRlcyBwcmluY2lwYWxlcwp0YWNwID0gIHRpYmJsZSh2YXJpYW5jZXByb3A9YWNwJHNkZXZeMi9zdW0oYWNwJHNkZXZeMikgLCBDUD1wYXN0ZTAoIkNQIiwxOjcpKQoKZ2dwbG90KHRhY3AsIGFlcyh4PTE6NywgeT1jdW1zdW0odmFyaWFuY2Vwcm9wKSkpICsKZ2VvbV9saW5lKGNvbG9yPSduYXZ5JykgKyBnZW9tX3BvaW50KGNvbG9yPSduYXZ5JywgYWxwaGE9MC40KSArIApzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPTE6NywgbGFiZWxzPXRhY3AkQ1AsIG5hbWU9IkNvbXBvc2FudGVzIFByaW5jaXBhbGVzIikgKwpzY2FsZV95X2NvbnRpbnVvdXMobmFtZT0iVmFyaWFuY2UgY3VtdWzDqWUiLCBicmVha3M9c2VxLmRlZmF1bHQoZnJvbT0wLjYsIHRvPTEsIGJ5PTAuMDUpLAogICAgICAgICAgICAgICAgICAgbGFiZWxzPXNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwpnZ3RpdGxlKCJWYXJpYW5jZSBjdW11bMOpZSBlbiBmb25jdGlvbiBkZXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXMiKSArCnRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpKQpgYGAKRW4gamV0YW50IHVuIGNvdXAgZCdvZWlsIHN1ciBsYSB2YXJpYW5jZSBjdW11bMOpZSwgbm91cyB2b3lvbnMgcXUnaWwgZmF1ZHJhaXQgNSBjb21wb3NhbnRlcyBwb3VyIGTDqWNyaXJlIGxhIHZhcmlhbmNlIGEgMTAwJS4KCk5vdXMgcsOpYWxpc29ucyB0b3V0IGQnYWJvcmQgdW4gZ3JhcGhpcXVlIGVuIDNEIGRlcyBkb25uw6llcyBwcm9qZXTDqWVzIHN1ciBsZXMgdHJvaXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXMgOgoKYGBge3Igc2VlZHMzRCwgZWNobz1GQUxTRX0KcHJpbl9jb21wIDwtIHByY29tcChzY2FsZXNlZWRzWywxOjddLCByYW5rLj0zKQpjb21wb25lbnRzIDwtIHByaW5fY29tcFtbIngiXV0KY29tcG9uZW50cyA8LSBkYXRhLmZyYW1lKGNvbXBvbmVudHMpCmNvbXBvbmVudHMkUEMyIDwtIC1jb21wb25lbnRzJFBDMgpjb21wb25lbnRzJFBDMyA8LSAtY29tcG9uZW50cyRQQzMKY29tcG9uZW50cyA9IGNiaW5kKGNvbXBvbmVudHMsIHNlZWRzJFZhcmnDqXTDqXMpCgp0b3RfZXhwbGFpbmVkX3ZhcmlhbmNlX3JhdGlvIDwtIHN1bW1hcnkocHJpbl9jb21wKVtbImltcG9ydGFuY2UiXV1bJ1Byb3BvcnRpb24gb2YgVmFyaWFuY2UnLF0KdG90X2V4cGxhaW5lZF92YXJpYW5jZV9yYXRpbyA8LSAxMDAgKiBzdW0odG90X2V4cGxhaW5lZF92YXJpYW5jZV9yYXRpbykKCnRpdCA9ICdUb3RhbCBFeHBsYWluZWQgVmFyaWFuY2UgPSA5OS40OCcKCmZpZyA8LSBwbG90X2x5KGNvbXBvbmVudHMsIHg9flBDMSwgeT1+UEMyLCB6PX5QQzMsIGNvbG9yPX5zZWVkcyRWYXJpw6l0w6lzLCBjb2xvcnM9YygnbmF2eScsJ3RhbjEnLCdkZWVwcGluaycpKSAlPiUgICAgICAgICBhZGRfbWFya2VycyhzaXplPTEyKQoKZmlnIDwtIGZpZyAlPiUgbGF5b3V0KHRpdGxlID0gdGl0LHNjZW5lID0gbGlzdChiZ2NvbG9yID0gIiNlNWVjZjYiKSkKZmlnCmBgYApBIG5vdXZlYXUgaWNpIGxlIGN1cnNldXIgbm91cyBwZXJtZXQgZCdhdm9pciBkaXJlY3RlbWVudCBsZXMgdmFsZXVycyBkZSBub3MgZG9ubsOpZXMuCkRlIHBsdXMgbCdhc3BlY3QgM0Qgbm91cyBwZXJtZXQgZGUgbWlldXggdmlzdWFsaXNlciBsZXVyIHJhcGFydGl0aW9uIGRhbnMgbCdlc3BhY2UuCkxlcyB0cm9pcyBwcmVtacOocmVzIGNvbXBvc2FudGVzIGNvbnRpZW5uZW50IDk5LDQ4JSBkZSBsYSB2YXJpYW5jZSwgZG9uYyBwcmVzcXVlIDEwMCUhCgpDZXBlbmRhbnQsIGNvbW1lIGxlcyBkZXV4IHByZW1pw6hyZXMgY29tcG9zYW50ZXMgY29udGllbm5lbnQgZW52aXJvbiA5MCUgZGUgbGEgdmFyaWFuY2UsIG5vdXMgZXN0aW1vbnMgcXUnaWwgbm91cyBlc3Qgc3VmZmlzYW50IGRlIHNlIGxpbWl0ZXIgYSBjZWxsZXMtY2kgcG91ciBleHByaW1lciBub3MgZG9ubsOpZXMuCgpWb2ljaSBkb25jIG5vcyBkb25uw6llcyBwcm9qZXTDqWVzIHN1ciBjZXMgZGV1eCBwcmVtaWVyZXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXM6CgpgYGB7ciBzZWVkczJELCBlY2hvPUZBTFNFfQpzY2FsZXNlZWRzWyxjKCJDUDEiLCAiQ1AyIildID0gYWNwJHhbLDE6Ml0KCmdncGxvdChzY2FsZXNlZWRzKSArIGFlcyh4PUNQMSwgeT1DUDIsIGNvbG9yPVZhcmnDqXTDqXMpICsKZ2VvbV9wb2ludChzaXplPTMsIGFscGhhPTAuNykgKwpnZ3RpdGxlKCJEb25uw6llcyBwcm9qZXTDqWVzIHN1ciBsZXMgZGV1eCBjb21wb3NhbnRlcyBwcmluY2lwYWxlcyBlbiAyRCIpICsKdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsKeGxhYignQ1AxJykgKyB5bGFiKCdDUDInKSArCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygibmF2eSIsICJ0YW4xIiwiZGVlcHBpbmsiKSkgKwpnZW9tX3BvbHlnb24oZGF0YT1zY2FsZXNlZWRzICU+JSBncm91cF9ieShWYXJpw6l0w6lzKSAlPiUgc2xpY2UoY2h1bGwoQ1AxLCBDUDIpKSwgYWxwaGEgPSAwKSAjZW52ZWxvcHBlIGNvbnZleGUKYGBgClZpc3VlbGxlbWVudCBub3VzIHZveW9ucyBiaWVuIG5vcyAzIGdyb3VwZXMsIGNlcGVuZGFudCBjZXJ0YWlucyBwb2ludHMgc2UgbcOpbGFuZ2VudCBhIGQnYXV0cmUgdmFyacOpdMOpLCBkb25jIG5vdXMgbm91cyBhdHRlbmRvbnMgYSBuZSBwYXMgb2J0ZW5pciB1bmUgY2xhc3NpZmljYXRpb24gInBhcmZhaXRlIiBwYXIgbGEgc3VpdGUuCgpPbiB0cmFjZSBlbiBjb21wbMOpbWVudCB1biBiaXBsb3QgOgoKYGBge3Igc2VlZHNBQ1BiaXBsb3QsIGVjaG89RkFMU0V9CmZ2aXpfcGNhX2JpcGxvdChhY3AsIAogICAgICAgICAgICAgICAgZ2VvbS5pbmQgPSBhcy5mYWN0b3IoInBvaW50IiksCiAgICAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsIGxhYmVsID0gInZhciIsCiAgICAgICAgICAgICAgICBwb2ludHNoYXBlID0gMjEsCiAgICAgICAgICAgICAgICBwb2ludHNpemUgPSAyLjUsCiAgICAgICAgICAgICAgICBmaWxsLmluZCA9IGFzLmZhY3RvcihzY2FsZXNlZWRzJFZhcmnDqXTDqXMpLAogICAgICAgICAgICAgICAgY29sLmluZCA9IGFzLmZhY3RvcigiYmxhY2siKSwKICAgICAgICAgICAgICAgIGNvbC52YXIgPSBmYWN0b3IoYygiU3VyZmFjZSIsICJQw6lyaW3DqHRyZSIsIkNvbXBhY2l0w6kiLCAiTG9uZ3VldXIiLCAiTGFyZ2V1ciIsICJDb2VmQXN5bSIsICJSYWludXJlIikpLAogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gbGlzdChmaWxsID0gIlZhcmnDqXTDqXMiLCBjb2xvciA9ICJQYXJhbcOodHJlcyIpLAogICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFKSArCmdncHVicjo6ZmlsbF9wYWxldHRlKGMoIm5hdnkiLCJ0YW4xIiwiZGVlcHBpbmsiKSkgKwpnZ3B1YnI6OmNvbG9yX3BhbGV0dGUoIm5wZyIpCgojIHJlcGVsID0gVFJVRSA6IHBvdXIgZXZpdGV6IGxlIHN1cnRyYcOnYWdlIGRlcyDDqXRpcXVldHRlcwpgYGAKVW5lIGZsw6hjaGUgZXN0IGFzc29jacOpZSDDoCBjaGFjdW4gZGVzIDcgcGFyYW3DqHRyZXMsIGVsbGUgcG9pbnRlIGRhbnMgbGEgZGlyZWN0aW9uIGRlcyB2YWxldXJzIGNyb2lzc2FudGVzIGR1IHBhcmFtw6h0cmUgcXVlbGxlIHJlcHJlc2VudGUuICAKTGEgcHJlbWnDqHJlIGNvbXBvc2FudGUgcHJpbmNpcGFsZSBwZXJtZXQgZGUgYmllbiBzw6lwYXJlciBsZXMgdmFyacOpdMOpcyBSb3NhIGV0IENhbmFkaWFuLiAgCkxhIHZhcmnDqXTDqSBSb3NhIHNlcmEgbGUgcGx1cyBncmFuZCB0eXBlIGRlIGdyYWluLCBsYSB2YXJpw6l0w6kgQ2FuYWRpYW4gc2VyYSBsZSBwbHVzIHBldGl0LCBldCBsYSB2YXJpw6l0w6kgS2FtYSBzZXJhIGVudHJlIGxlcyBkZXV4LiAgCkxhIHZhcmnDqXTDqSBLYW1hIGEgZGVzIHZhbGV1cnMgZCdBQ1AgcGx1cyBmYWlibGVzIHF1ZSBsZXMgZGV1eCBhdXRyZXMgdmFyacOpdMOpcywgY2UgcXVpIHNpZ25pZmllIHF1J2VsbGUgc2VyYSBwbHVzIHJvbmRlLiAgCgpEZSBwbHVzIG5vdXMgcG91dm9ucyBkaXJlIHF1ZSBsZXMgY2lucSBwYXJhbcOodHJlcyBMYXJnZXVyLCBMb25ndWV1ciwgUMOpcmltw6h0cmUsIFJhaW51cmUgZXQgU3VyZmFjZSBzb250IGxlcyBjb250cmlidXRpb25zIGxlcyBwbHVzIGltcG9ydGFudGVzIHBvdXIgbGEgcHJlbWllcmUgY29tcG9zYW50ZSBwcmluY2lwYWxlLiAoY2Ugc29udCBsZXMgY2lucSBmbMOoY2hlIHF1aSBwb2ludGVudCBzdXIgbGEgZ2F1Y2hlKS4gRWxsZXMgc29udCBiaWVuIGNvcnLDqWzDqcOpZXMgZW50cmUgZWxsZXMuICAgCkxlIHBhcmFtw6h0cmUgQ29lZkFzeW0gZXN0IGxlIHBsdXMgaW1wb3J0YW50IHBvdXIgbGEgZGV1eGllbWUgY29tcG9zYW50ZSBwcmluY2lwYWxlLiBJbCBlc3QgbW9pbnMgY29ycsOpbMOpIGF2ZWMgbGVzIGNpbnFzIGF1dHJlcyBwYXJhbcOodHJlIExhcmdldXIsIExvbmd1ZXVyLCBQw6lyaW3DqHRyZSwgUmFpbnVyZSBldCBTdXJmYWNlLiAgIAoKIyMgS21lYW5zCgpDZXR0ZSBtw6l0aG9kZSBjb25zaXN0ZSDDoCByZWdyb3VwZXIgZGVzIGRvbm7DqWVzIGRhbnMgZGVzIGNsYXNzZXMsIGxlcyBwbHVzIGhvbW9nw6huZXMgcG9zc2libGVzLiAgClBvdXIgY2UgZmFpcmUsIHVuIG5vbWJyZSBhcmJpdHJhaXJlIGRlIGNsYXNzZXMgZG9pdCBldHJlIChiaWVuKSBjaG9pc2kuICAKRW5zdWl0ZSwgbOKAmWFsZ29yaXRobWUgcHJlbmQgayBwb2ludHMgYWzDqWF0b2lyZXMgKGxlcyBjZW50cmVzKSBkYW5zIGxlIG51YWdlIGRlIHBvaW50IGRlcyBkb25uw6llcywgIApldCBjaGFxdWUgZG9ubsOpZSBlc3QgYWZmZWN0w6llIGF1IGNlbnRyZSBsZSBwbHVzIHByb2NoZS4gIApQdWlzIGxlIGJhcnljZW50cmUgZGVzIHBvaW50cyBkZSBjaGFxdWUgY2xhc3NlIGNvbnNpdHV0w6llIGVzdCBjYWxjdWzDqS4gKGRvbmMgbGVzIGNlbnRyZXMgYm91Z2VudCkgIApFdCB1bmUgcsOpLWFmZmVjdGF0aW9uIGRlcyBpbmRpdmlkdXMgYXUgbm91dmVhdSBjZW50cmUgbGUgcGx1cyBwcm9jaGUgYSBsaWV1LiAgCkNlcyBkZXV4IGRlcm5pZXJlcyDDqXRhcGVzIHNvbnQgcsOpcMOodMOpZXMganVzcXXigJnDoCBjZSBxdWUgbGVzIGJhcnljZW50cmVzIG5lIOKAnGJvdWdlbnQgcGx1c+KAnS4gKGNvbnZlcmdlbmNlKSAgCgpJbCBmYXV0IGRvbmMgZmFpcmUgYXR0ZW50aW9uIGEgbGEgZm9pcyBhdSBub21icmUgZGUgY2x1c3RlciwgZXQgYSBsYSBmb2lzIGF1IG5vbWJyZSBkZSBwb2ludHMgaW5pdGlhdXguCgpUb3V0IGQnYWJvcmQsIHBvdXIgZMOpdGVybWluZXIgbGUgbm9tYnJlIG9wdGltYWwgZGUgY2x1c3RlcnMsIG5vdXMgYWxsb25zIHV0aWxpc2VyIGxlcyB0cm9pcyBtw6l0aG9kZXMgc3VpdmFudGVzOgoKYGBge3Igc2VlZHNuYmNsdXN0ZXIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CnNldC5zZWVkKDMxKQoKI0VsYm93Cm0xIDwtIGZ2aXpfbmJjbHVzdChzY2FsZXNlZWRzWywxOjddLCBrbWVhbnMsIG1ldGhvZD0id3NzIiwgay5tYXg9MTIsIGxpbmVjb2xvcj0ibmF2eSIpICsKICAgICAgdGhlbWVfZ3JheSgpICsgZ2d0aXRsZSgiTcOpdGhvZGUgRWxib3ciKQojU2lsaG91ZXR0ZQptMiA8LSBmdml6X25iY2x1c3Qoc2NhbGVzZWVkc1ssMTo3XSwga21lYW5zLCBtZXRob2Q9InNpbGhvdWV0dGUiLCBrLm1heD0xMiwgbGluZWNvbG9yPSJuYXZ5IikgKwogICAgICB0aGVtZV9ncmF5KCkgKyBnZ3RpdGxlKCJNw6l0aG9kZSBTaWxob3VldHRlIikKI0dBUAptMyA8LSBmdml6X25iY2x1c3Qoc2NhbGVzZWVkc1ssMTo3XSwga21lYW5zLCBtZXRob2QgPSAiZ2FwX3N0YXQiLCBrLm1heCA9IDEyLCBsaW5lY29sb3I9Im5hdnkiKSArCiAgICAgIHRoZW1lX2dyYXkoKSArIGdndGl0bGUoIlN0YXRpc3RpcXVlIEdBUCIpCgpncmlkLmFycmFuZ2UobTEsIG0yLCBtMywgbnJvdyA9IDEsIG5jb2wgPSAzKQpgYGAKCiogKipMYSBtw6l0aG9kZSBFbGJvdyoqIHBlcm1ldCBkZSBjb21wYXJlciBsZSBub21icmUgdG90YWwgZGUgV1NTIHBvdXIgY2hhcXVlIHZhbGV1ciBkZSBrLiAgClBsdXMgbGEgdmFsZXVyIGRlIGsgYXVnbWVudGUsIHBsdXMgbGUgV1NTIGRldnJhaXQgw6p0cmUgcGV0aXQuIE5vdXMgdm91bG9ucyBkb25jIHRyb3V2ZXIgbGUgcG9pbnQgc3VyIGxlIGdyYXBoaXF1ZSBvw7kgbGEgY291cmJlIHNlbWJsZSBzZSBwbGllciAoaW5kaXF1YW50IHVuZSBwZXRpdGUgZGltaW51dGlvbiBkdSBXU1MgcGFyIHJhcHBvcnQgYXV4IHZhbGV1cnMgcHLDqWPDqWRlbnRlcyBkZSBrKSAgCk9uIHJlbWFycXVlIHVuZSBwbHVzIGZvcnRlIGRpbWludXRpb24gZGUgaz0xIGEgaz0yLCBldCBkZSBrPTIgYSBrPTMuICAKRG9uYyBrPTIgb3Ugaz0zIHNlcmFpZW50IGRlIGJvbnMgY2FuZGlkYXRzIMOgIGVzc2F5ZXIuCgoqICoqTGEgbcOpdGhvZGUgU2lsaG91ZXR0ZSoqIG1lc3VyZSBsYSBmYcOnb24gZG9udCBjaGFxdWUgcG9pbnQgZGUgZG9ubsOpZXMgcydpbnTDqGdyZSBkYW5zIHNvbiBjbHVzdGVyLiAgClVuZSB2YWxldXIgZGUgc2lsaG91ZXR0ZSDDqWxldsOpZSwgaW5kaXF1ZSB1biBib24gY2x1c3RlcmluZy4gIApDZXR0ZSBtw6l0aG9kZSBub3VzIHN1Z2fDqXJlIGRvbmMgZGUgcHJlbmRyZSBrPTIgY29tbWUgbm9tYnJlIG9wdGltYWwgZGUgY2x1c3RlcnMuCgoqICoqTGEgc3RhdGlzdGlxdWUgZGUgR0FQKiogcGVybWV0IGRlIGNvbXBhcmVyIGxhIHZhcmlhdGlvbiBpbnRyYS1jbHVzdGVycyB0b3RhbGUgcG91ciBkaWZmw6lyZW50ZXMgdmFsZXVycyBkZSBrLCBhdXggdmFsZXVycyBhdHRlbmR1ZXMuICAKTGEgdmFsZXVyIGs9MyBzZW1ibGUgZXRyZSBsZSBib24gY2hpZmZyZSEKCk5vdXMgYWxsb25zIGRvbmMgdXRpbGlzZXIgMyBjbHVzdGVycyBwb3VyIHLDqXBhcnRpciBub3MgZG9ubsOpZXMuCgpQb3VyIGNvbXByZW5kcmUgbWFpbnRlbmFudCBjb21tZW50IGwnYWxnb3JpdGhtZSBkZXMgS21lYW5zIGZvbmN0aW9ubmUsIG5vdXMgcmVwcsOpc2VudG9ucyBncmFwaGlxdWVtZW50IGzigJnDqXZvbHV0aW9uIGRlcyBhZmZlY3RhdGlvbnMgZGVzIGNsYXNzZXMgZXQgZGVzIGNlbnRyZXMgZGUgY2VsbGVzLWNpLCBhdSBjb3VycyBkZXMgdHJvaXMgcHJlbWllcmVzIGl0w6lyYXRpb25zLCBhdmVjIGxhIG3Dqm1lIGluaXRpYWxpc2F0aW9uIMOgIGNoYXF1ZSBmb2lzOgoKYGBge3Igc2VlZHNLbTAsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTZ9CiNsaW1pdGVyIGxlIG5vbWJyZSBk4oCZaXTDqXJhdGlvbnMgZGFucyB1bmUgZm9uY3Rpb24gZMOpZGnDqWUgZGUgUgpzZXQuc2VlZCgxKSAjb24gZml4ZSBsJ2Fsw6lhCmttMSA9IGttZWFucyhzY2FsZXNlZWRzWywxOjddLCBjZW50ZXJzPTUsIGl0ZXIubWF4PTEpCmttMiA9IGttZWFucyhzY2FsZXNlZWRzWywxOjddLCBjZW50ZXJzPWttMSRjZW50ZXJzLCBpdGVyLm1heD0xKQprbTMgPSBrbWVhbnMoc2NhbGVzZWVkc1ssMTo3XSwgY2VudGVycz1rbTIkY2VudGVycywgaXRlci5tYXg9MSkKa200ID0ga21lYW5zKHNjYWxlc2VlZHNbLDE6N10sIGNlbnRlcnM9a20zJGNlbnRlcnMsIGl0ZXIubWF4PTEpCgpzY2FsZXNlZWRzJENsdXN0ZXIgPSBrbTEkY2x1c3RlcgpnZ3Bsb3Qoc2NhbGVzZWVkcywgYWVzKHg9Q1AxLCB5PUNQMikpICsKICBnZW9tX3BvaW50KHNpemU9MywgYWxwaGE9MC44KSArCiMgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJ0YW4xIiwibmF2eSIsICJkZWVwcGluayIsIm5hdnkiLCAiI0VGRTNDOCIsIm5hdnkiLCAidGFuMSIsICJkZWVwcGluayIpKSArCiAgYWVzKGNvbG9yID0gZmFjdG9yKENsdXN0ZXIpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID1WYXJpw6l0w6lzKSwgc2l6ZT0yKSArCiAgbGFicyhjb2xvcj0iVmFyacOpdMOpcyIpICsKICBnZ3RpdGxlKCJJdMOpcmF0aW9uIDEiKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKQoKc2NhbGVzZWVkcyRDbHVzdGVyID0ga20yJGNsdXN0ZXIKZ2dwbG90KHNjYWxlc2VlZHMsIGFlcyh4PUNQMSwgeT1DUDIpKSArCiAgZ2VvbV9wb2ludChzaXplPTMsIGFscGhhPTAuOCkgKwojICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygidGFuMSIsIm5hdnkiLCAiZGVlcHBpbmsiLCJuYXZ5IiwgIiNFRkUzQzgiLCJuYXZ5IiwgInRhbjEiLCAiZGVlcHBpbmsiKSkgKwogIGFlcyhjb2xvciA9IGZhY3RvcihDbHVzdGVyKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1WYXJpw6l0w6lzKSwgc2l6ZT0yKSArCiAgbGFicyhjb2xvcj0iVmFyacOpdMOpcyIpICsKICBnZ3RpdGxlKCJJdMOpcmF0aW9uIDIiKSArCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsIGhqdXN0PTAuNSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKQoKc2NhbGVzZWVkcyRDbHVzdGVyID0ga20zJGNsdXN0ZXIKZ2dwbG90KHNjYWxlc2VlZHMsIGFlcyh4PUNQMSwgeT1DUDIpKSArCiAgZ2VvbV9wb2ludChzaXplPTMsIGFscGhhPTAuOCkgKwojICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygidGFuMSIsIm5hdnkiLCAiZGVlcHBpbmsiLCJuYXZ5IiwgIiNFRkUzQzgiLCJuYXZ5IiwgInRhbjEiLCAiZGVlcHBpbmsiKSkgKwogIGFlcyhjb2xvciA9IGZhY3RvcihDbHVzdGVyKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9VmFyacOpdMOpcyksIHNpemU9MikgKwogIGxhYnMoY29sb3I9IlZhcmnDqXTDqXMiKSArCiAgZ2d0aXRsZSgiSXTDqXJhdGlvbiAzIikgKwogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJykKCiNLTSBJVFRFUkFUSU9OIFZFUlNJT04gU0FOUyBHR1BMT1QKI2NoYW5naW5nIDwtIHdoaWNoKGFwcGx5KGNiaW5kKGttMSRjbHVzdGVyLGttMiRjbHVzdGVyLGttMyRjbHVzdGVyKSwxLHNkKT4wKQojY2hhbmdpbmcKI3Bsb3Qoc2NhbGVzZWVkc1ssYygiQ1AxIiwgIkNQMiIpXSxjb2w9a20xJGNsdXN0ZXIscGNoPTE5LG1haW49Ikl0ZXJhdGlvbiAxIikKIyAgcG9pbnRzKHNjYWxlc2VlZHNbY2hhbmdpbmcsYygiQ1AxIiwgIkNQMiIpXSxwY2g9MjEsY2V4PTIpCiNwbG90KHNjYWxlc2VlZHNbLGMoIkNQMSIsICJDUDIiKV0sY29sPWttMiRjbHVzdGVyLHBjaD0xOSxtYWluPSJJdGVyYXRpb24gMiIpCiMgIHBvaW50cyhzY2FsZXNlZWRzW2NoYW5naW5nLGMoIkNQMSIsICJDUDIiKV0scGNoPTIxLGNleD0yKQojcGxvdChzY2FsZXNlZWRzWyxjKCJDUDEiLCAiQ1AyIildLGNvbD1rbTMkY2x1c3RlcixwY2g9MTksbWFpbj0iSXRlcmF0aW9uIDMiKQojICBwb2ludHMoc2NhbGVzZWVkc1tjaGFuZ2luZyxjKCJDUDEiLCAiQ1AyIildLHBjaD0yMSxjZXg9MikKYGBgCgpOb3VzIGluZGlxdW9ucyBsZXMgcG9pbnRzIHF1aSBjaGFuZ2VudCBkJ2FwcGFydGVuYW5jZSDDoCB1biBncm91cGUgZW4gbGVzIGNvbG9yYW50LiAgCk1hbGhldXJldXNlbWVudCAob3UgaGV1cmV1c2VtZW50KSBjb21tZSBsJ2FsZ29yaXRobWUgY29udmVyZ2UgdHLDqHMgdml0ZSwgY2VsYSBzJ2FycmV0ZSBkw6hzIGxhIGRldXhpZW1lIGl0w6lyYXRpb24uLi4KCk1haW50ZW5hbnQsIG5vdXMgcsOpYWxpc29ucyBsYSBtw6l0aG9kZSBLbWVhbnMgYWZpbiBkJ29idGVuaXIgMyBjbHVzdGVyczoKCmBgYHtyIHNlZWRzS20xLCBjb21tZW50PU5BLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpzZXQuc2VlZCgxMjMpICNvbiBmaXhlIGwnYWzDqWEKa20gPSBrbWVhbnMoc2NhbGVzZWVkc1ssMTo3XSwgY2VudGVycz0zLCBpdGVyLm1heD0xMDAsIG5zdGFydD01KQpzY2FsZXNlZWRzJENsdXN0ZXIgPSBrbSRjbHVzdGVyCgpnZ3Bsb3Qoc2NhbGVzZWVkcywgYWVzKHg9Q1AxLCB5PUNQMikpICsKICBnZW9tX3BvaW50KHNpemU9NSwgYWxwaGE9MC44KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJ0YW4xIiwiZGVlcHBpbmsiLCAibmF2eSIsIiM1NkI0RTkiLCAiI0VGRTNDOCIsInBpbmsiKSkgKwogIGFlcyhjb2xvciA9IGZhY3RvcihDbHVzdGVyKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9VmFyacOpdMOpcyksIHNpemU9MikgKwogIGdlb21fcG9seWdvbihkYXRhPXNjYWxlc2VlZHMgJT4lIGdyb3VwX2J5KENsdXN0ZXIpICU+JSBzbGljZShjaHVsbChDUDEsIENQMikpLCBhbHBoYSA9IDApICsKICBsYWJzKGNvbG9yPSJWYXJpw6l0w6lzIikgKwogIGdndGl0bGUoIkNsYXNzaWZpY2F0aW9uIEttZWFucyIpICsKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiwgaGp1c3Q9MC41KSkKCmNvdW50KHNjYWxlc2VlZHMsIENsdXN0ZXIpCmBgYAoKTCdhZ29yaXRobWUgZGVzIEttZWFucyBhZmZlY3RlIDogNzEgS2FtYSAtIDY3IFJvc2EgLSA3MiBDYW5hZGlhbiAgCgpOb3VzIGF2b25zIHJlcHLDqXNlbnTDqSBzdXIgdW4gbcOqbWUgZ3JhcGhpcXVlIDogIApMZXMgcsOpc3VsdGF0cyBkZSBsYSBjbGFzc2lmaWNhdGlvbiBLbWVhbnMgOiAxIC0gMiAtIDMgIApzdXBlcnBvc8OpcyBhdXggw6l0aXF1ZXR0ZXMgcsOpZWxsZXMgOiBLYW1hIC0gUm9zYSAtIENhbmFkaWFuICAKCkNldHRlIGNsYXNzZmljYXRpb24gbidlc3QgcGFzIHBhcmZhaXRlLCBtYWlzIHJlbGF0aXZlbWVudCBjb3JyZWN0ZS4KCgojIyBDbHVzdGVyaW5nIEhpw6lyYXJjaGlxdWUgQXNjZW5kYW50CgpOb3VzIGdhcmRvbnMgbGUgbcOqbWUgb2JqZWN0aWYgZGUgY2xhc3NpZmljYXRpb24sIG1haXMgbm91cyBhcHBsaXF1b25zIG1haW50ZW5hbnQgbGEgbcOpdGhvZGUgZHUgY2x1c3RlcmluZyBoacOpcmFyY2hpcXVlIGFzY2VuZGFudCwgYXZlYyBkaWZmZXJlbnRlcyBmb25jdGlvbnMgZGUgbGlua2FnZS4KCiogTWV0aG9kZSAxOiBsYSBmb25jdGlvbiBkZSBsaW5rYWdlIGRlIFdhcmQgIApFbGxlIGNvbnNpc3RlIGEgbWluaW1pc2VyIGxhIHZhcmlhbmNlIHRvdGFsZSBhdSBzZWluIGR1IGNsdXN0ZXIuIChjbHVzdGVycyBjb21wYWN0cykgIArDgCBjaGFxdWUgw6l0YXBlLCBsYSBwYWlyZSBkZSBjbHVzdGVycyBheWFudCBsYSBwbHVzIHBldGl0ZSBkaXN0YW5jZSBpbnRlci1jbHVzdGVycyBlc3QgZnVzaW9ubsOpZS4gIAoKUmVnYXJkb25zIGluZXJ0aWUgZXQgZGVuZG9ncmFtbWU6CmBgYHtyIENIQTEuMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0KY2x1c3QxIDwtIHNlZWRzICU+JSBzZWxlY3QoLVZhcmnDqXTDqXMpICU+JSBkaXN0KCkgJT4lIGhjbHVzdChtZXRob2Q9IndhcmQuRDIiKQpmdml6X2RlbmQoY2x1c3QxLCBrPTMsIGNleD0wLjUsIGtfY29sb3JzPWMoInRhbjEiLCJkZWVwcGluayIsIm5hdnkiKSwKICAgICAgICAgIGNvbG9yX2xhYmVsc19ieV9rID0gVFJVRSwgZ2d0aGVtPXRoZW1lX2dyYXkoKSkKCmluZXJ0aWUgPSAgc29ydChjbHVzdDEkaGVpZ2h0LCBkZWNyZWFzaW5nID0gVFJVRSkKcGxvdChpbmVydGllWzE6MjBdLCB0eXBlID0gInMiLCB4bGFiID0gIk5vbWJyZSBkZSBjbGFzc2VzIiwgeWxhYiA9ICJJbmVydGllIikKcG9pbnRzKGMoMiwgMyksIGluZXJ0aWVbYygyLCAzKV0sIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQzIiksIGNleCA9IDIsIGx3ZCA9IDMpCgpwbG90KGNsdXN0MSwgbGFiZWxzPUZBTFNFLCBtYWluPSJQYXJ0aXRpb24gZW4gMiBvdSAzIGNsYXNzZXMiLCBheGVzID0gRkFMU0UsIGhhbmcgPSAtMSkKcmVjdC5oY2x1c3QoY2x1c3QxLCAyLCBib3JkZXIgPSAibGlnaHRibHVlIikKcmVjdC5oY2x1c3QoY2x1c3QxLCAzLCBib3JkZXIgPSAicmVkMyIpCmBgYApQb3VyIGJpZW4gdm9pciBsYSBjbGFzc2lmaWNhdGlvbiBmYWl0ZSAsIG5vdXMgYXZvbnMgcmVwcsOpc2VudMOpIGxlcyBzYXV0cyBk4oCZaW5lcnRpZSBlbiBnYXJkYW50IHF1ZSBsZXMgMjAgcHJlbWllcmVzIHZhbGV1cnMgZHUgZGVuZHJvZ3JhbW1lLCBzZWxvbiBsZSBub21icmUgZGUgY2xhc3NlcyByZXRlbnVlcy4gTm91cyBwb3V2b25zIHJlbWFycXVlciBkZXV4IHNhdXRzIHNpZ25pZml2YXRpZiBlbiAyIGV0IGVuIDMgY2xhc3Nlcy4gbm91cyBsZXMgYXZvbnMgZW50b3Vyw6kgZW5zdWl0ZSBlbiBibGV1IGV0IHJvdWdlIHN1ciBsZSBkZW5kcm9ncmFtbWUuCkxhIG1laWxsZXVyZSBjbGFzc2lmaWNhdGlvbiBhdmVjIGxhIG3DqXRob2RlIFdhcmQgZXN0IGF2ZWMgMyBjbGFzc2VzLgoKRmluYWxlbWVudCwgbGEgY2xhc3NpZmljYXRpb24gYXNjZW5kYW50ZSBoacOpcmFyY2hpcXVlIGF2ZWMgbGEgbWV0aG9kZSBXYXJkIGFmZmVjdGUgOiAgCjYxIEthbWEgLSA4NiBSb3NhIC0gNjMgQ2FuYWRpYW4gIApgYGB7ciBDSEExLjIsIGVjaG89RkFMU0V9CnR5cG8gPC0gY3V0cmVlKGNsdXN0MSwgMykKZnJlcSh0eXBvKQpgYGAKCiogTWV0aG9kZSAyOiBzaW5nbGUgbGlua2FnZSAobWluKSAgCkVsbGUgY29uc2lzdGUgYSBjYWxjdWxlciB0b3V0ZXMgbGVzIGRpc3NpbWlsYXJpdMOpcyBwYXIgcGFpcmUgZW50cmUgbGVzIMOpbMOpbWVudHMgZGUgZGV1eCBjbHVzdGVycywgZXQgY29uc2lkw6hyZSBsYSBwbHVzIHBldGl0ZSBkZSBjZXMgZGlzc2ltaWxhcml0w6lzIGNvbW1lIHVuIGNyaXTDqHJlIGRlIGxpYWlzb24uIChjbHVzdGVycyBsb25ncykKTm91cyBhbGxvbnMgcmVmYWlyZSBleGFjdGVtZW50IGxhIG1lbWUgYW5hbHlzZS4KClJlZ2FyZG9ucyBpbmVydGllIGV0IGRlbmRvZ3JhbW1lOgpgYGB7ciBDSEEyLjEsIGVjaG89RkFMU0V9CmNsdXN0MiA8LSBzZWVkcyAlPiUgc2VsZWN0KC1WYXJpw6l0w6lzKSAlPiUgZGlzdCgpICU+JSBoY2x1c3QobWV0aG9kPSJzaW5nbGUiKQpmdml6X2RlbmQoY2x1c3QyLCBrPTMsIGNleD0wLjUsIGtfY29sb3JzPWMoInRhbjEiLCJkZWVwcGluayIsIm5hdnkiKSwKICAgICAgICAgIGNvbG9yX2xhYmVsc19ieV9rID0gVFJVRSwgZ2d0aGVtPXRoZW1lX2dyYXkoKSkKCmluZXJ0aWVfc2luZ2xlID0gIHNvcnQoY2x1c3QyJGhlaWdodCwgZGVjcmVhc2luZyA9IFRSVUUpCnBsb3QoaW5lcnRpZV9zaW5nbGVbMToyMF0sIHR5cGUgPSAicyIsIHhsYWIgPSAiTm9tYnJlIGRlIGNsYXNzZXMiLCB5bGFiID0gIkluZXJ0aWUiKQpwb2ludHMoYygyLCAzKSwgaW5lcnRpZV9zaW5nbGVbYygyLCAzKV0sIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQzIiksIGNleCA9IDIsIGx3ZCA9IDMpCgpwbG90KGNsdXN0MiwgbGFiZWxzID0gRkFMU0UsIG1haW4gPSAiUGFydGl0aW9uIGVuIDIgb3UgMyBjbGFzc2VzIiwgYXhlcyA9IEZBTFNFLCBoYW5nID0gLTEpCnJlY3QuaGNsdXN0KGNsdXN0MiwgMiwgYm9yZGVyID0gImxpZ2h0Ymx1ZSIpCnJlY3QuaGNsdXN0KGNsdXN0MiwgMywgYm9yZGVyID0gInJlZDMiKQpgYGAKT24gb2JzZXJ2ZSBxdWUgbGUgc2luZ2xlIGxpbmthZ2UgdGVuZCDDoCBjcsOpZXIgZGVzIGRlbmRvZ3JhbW1lcyBhdmVjIGRlIHRyw6hzIGZpbmVzIHBhcnRpZXMvY2x1c3RlcnMuICAKQWdpc3NhbnQgY29tbWUgdW4gbmVhcmVzdCBuZWlnaGJvciwgY2V0dGUgY2xhc3NpZmljYXRpb24gaGllcmFjaGlxdWUgYXNzdXJlIHVuZSBwZXRpdGUgZGlzdGFuY2UgZW50cmUgZGV1eCBwb2ludHMgdm9pc2lucywgbWFpcyBkZXMgcG9pbnRzIGRlIHBhcnRzIGV0IGQnYXV0cmVzIGR1IGNsdXN0ZXIgcGV1dmVudCDDqnRyZSDDqWxvaWduw6lzLgoKUmVnYXJkb25zIGxlcyBwZXJ0ZXMgcmVsYXRpdmVzIGTigJlpbmVydGllOgpgYGB7ciBDSEEyLjIsIGVjaG89RkFMU0V9CmJlc3QuY3V0cmVlKGhjbHVzdF9zaW5nbGUsIGdyYXBoID0gVFJVRSwgeGxhYiA9ICJOb21icmUgZGUgY2xhc3NlcyIsIHlsYWIgPSAiSW5lcnRpZSByZWxhdGl2ZSIpCmBgYApMYSBtZWlsbGV1cmUgcGFydGl0aW9uIHNlbG9uIGNlIGNyaXTDqHJlIGVzdCByZXByw6lzZW50w6llIHBhciB1biBwb2ludCBub2lyLCBldCBsYSBzZWNvbmRlIHBhciB1biBwb2ludCBncmlzLgpDZWxhIG5vdXMgaW5kaXF1ZSBkZSBwcmVuZHJlIDQgY2x1c3RlcnMuLi4KCmBgYHtyIENIQTIuMywgZWNobz1GQUxTRX0KdHlwb19zaW5nbGUgPC0gY3V0cmVlKGNsdXN0MiwgNCkKZnJlcSh0eXBvX3NpbmdsZSkKYGBgCgoqIE1ldGhvZGUgMzogY29tcGxldGUgbGlua2FnZSAobWF4KSAgCkVsbGUgY29uc2lzdGUgYSBjYWxjdWxlciB0b3V0ZXMgbGVzIGRpc3NpbWlsYXJpdMOpcyBwYXIgcGFpcmUgZW50cmUgbGVzIMOpbMOpbWVudHMgZGUgZGV1eCBjbHVzdGVycywgZXQgY29uc2lkw6hyZSBsYSBwbHVzIGdyYW5kZSB2YWxldXIgZGUgY2VzIGRpc3NpbWlsYXJpdMOpcyBjb21tZSBsYSBkaXN0YW5jZSBlbnRyZSBsZXMgZGV1eCBjbHVzdGVycy4gKGNsdXN0ZXJzIGNvbXBhY3RzKQoKUmVnYXJkb25zIGluZXJ0aWUgZXQgZGVuZG9ncmFtbWU6CmBgYHtyIENIQTMuMSwgZWNobz1GQUxTRX0KY2x1c3QzIDwtIHNlZWRzICU+JSBzZWxlY3QoLVZhcmnDqXTDqXMpICU+JSBkaXN0KCkgJT4lIGhjbHVzdChtZXRob2Q9ImNvbXBsZXRlIikKZnZpel9kZW5kKGNsdXN0Mywgaz0zLCBjZXg9MC41LCBrX2NvbG9ycz1jKCJ0YW4xIiwiZGVlcHBpbmsiLCJuYXZ5IiksCiAgICAgICAgICBjb2xvcl9sYWJlbHNfYnlfayA9IFRSVUUsIGdndGhlbT10aGVtZV9ncmF5KCkpCgppbmVydGllX3NpbmdsZSA9ICBzb3J0KGNsdXN0MyRoZWlnaHQsIGRlY3JlYXNpbmcgPSBUUlVFKQpwbG90KGluZXJ0aWVfc2luZ2xlWzE6MjBdLCB0eXBlID0gInMiLCB4bGFiID0gIk5vbWJyZSBkZSBjbGFzc2VzIiwgeWxhYiA9ICJJbmVydGllIikKcG9pbnRzKGMoMiwgMyksIGluZXJ0aWVfc2luZ2xlW2MoMiwgMyldLCBjb2wgPSBjKCJsaWdodGJsdWUiLCAicmVkMyIpLCBjZXggPSAyLCBsd2QgPSAzKQoKaW5lcnRpZV9jb21wbGV0ZSA9ICBzb3J0KGNsdXN0MyRoZWlnaHQsIGRlY3JlYXNpbmcgPSBUUlVFKQpwbG90KGluZXJ0aWVfY29tcGxldGUsIHR5cGUgPSAicyIsIHhsYWIgPSAiTm9tYnJlIGRlIGNsYXNzZXMiLCB5bGFiID0gIkluZXJ0aWUiKQpyZWN0LmhjbHVzdChjbHVzdDMsIDIsIGJvcmRlciA9ICJsaWdodGJsdWUiKQpyZWN0LmhjbHVzdChjbHVzdDMsIDMsIGJvcmRlciA9ICJyZWQzIikKYGBgCkxhIG1ldGhvZGUgQ29tcGxldGUgbm91cyBkb25uZSB1biBwYXJ0aXRpb25uZW1lbnQgZGUgMyBjbGFzc2VzLCBtYWlzIHBhcyBkdSB0b3V0IGVxdWlsaWJyw6ksIGR1IGNvdXAgbGEgY2xhc3NpZmljYXRpb24gbidlc3QgcGFzIGJvbm5lOgoKYGBge3IgQ0hBMy4zLCBlY2hvPUZBTFNFfQp0eXBvX2NvbXBsZXRlIDwtIGN1dHJlZShjbHVzdDMsIDMpCmZyZXEodHlwb19jb21wbGV0ZSkKYGBgCgoqIE3DqXRob2RlIDQ6IGdyb3VwIGF2ZXJhZ2UgIApFbGxlIGNvbnNpc3RlIGEgY2FsY3VsZXIgdG91dGVzIGxlcyBkaXNzaW1pbGFyaXTDqXMgcGFyIHBhaXJlIGVudHJlIGxlcyDDqWzDqW1lbnRzIGRlIGRldXggY2x1c3RlcnMsIGV0IGNvbnNpZMOocmUgbGEgbW95ZW5uZSBkZSBjZXMgZGlzc2ltaWxhcml0w6lzIGNvbW1lIGxhIGRpc3RhbmNlIGVudHJlIGxlcyBkZXV4IGNsdXN0ZXJzLgoKYGBge3IgQ0hBNC4xLCBlY2hvPUZBTFNFfQpjbHVzdDQgPC0gc2VlZHMgJT4lIHNlbGVjdCgtVmFyacOpdMOpcykgJT4lIGRpc3QoKSAlPiUgaGNsdXN0KG1ldGhvZD0iYXZlcmFnZSIpCmZ2aXpfZGVuZChjbHVzdDIsIGs9MywgY2V4PTAuNSwga19jb2xvcnM9YygidGFuMSIsImRlZXBwaW5rIiwibmF2eSIpLAogICAgICAgICAgY29sb3JfbGFiZWxzX2J5X2sgPSBUUlVFLCBnZ3RoZW09dGhlbWVfZ3JheSgpKQoKaW5lcnRpZV9zaW5nbGUgPSAgc29ydChjbHVzdDQkaGVpZ2h0LCBkZWNyZWFzaW5nID0gVFJVRSkKcGxvdChpbmVydGllX3NpbmdsZVsxOjIwXSwgdHlwZSA9ICJzIiwgeGxhYiA9ICJOb21icmUgZGUgY2xhc3NlcyIsIHlsYWIgPSAiSW5lcnRpZSIpCnBvaW50cyhjKDIsIDMpLCBpbmVydGllX3NpbmdsZVtjKDIsIDMpXSwgY29sID0gYygibGlnaHRibHVlIiwgInJlZDMiKSwgY2V4ID0gMiwgbHdkID0gMykKCmluZXJ0aWVfYXZyZyA9ICBzb3J0KGNsdXN0NCRoZWlnaHQsIGRlY3JlYXNpbmcgPSBUUlVFKQpwbG90KGluZXJ0aWVfYXZyZywgdHlwZSA9ICJzIiwgeGxhYiA9ICJOb21icmUgZGUgY2xhc3NlcyIsIHlsYWIgPSAiSW5lcnRpZSIpCnJlY3QuaGNsdXN0KGNsdXN0NCwgMiwgYm9yZGVyID0gImxpZ2h0Ymx1ZSIpCnJlY3QuaGNsdXN0KGNsdXN0NCwgMywgYm9yZGVyID0gInJlZDMiKQpgYGAKCmBgYHtyIENIQTQuMiwgZWNobz1GQUxTRX0KYmVzdC5jdXRyZWUoaGNsdXN0X2F2cmcsIGdyYXBoID0gVFJVRSwgeGxhYiA9ICJOb21icmUgZGUgY2xhc3NlcyIsIHlsYWIgPSAiSW5lcnRpZSByZWxhdGl2ZSIpCmBgYApDZWxhIG5vdXMgaW5kaXF1ZSAzIGNsdXN0ZXJzLiAgCkZpbmFsZW1lbnQsIGxhIGNsYXNzaWZpY2F0aW9uIGFzY2VuZGFudGUgaGnDqXJhcmNoaXF1ZSBhdmVjIGxhIG1ldGhvZGUgQXZlcmFnZSBhZmZlY3RlIDogIAo4MSBLYW1hIC0gNjQgUm9zYSAtIDY1IENhbmFkaWFuIAoKYGBge3IgQ0hBNC4zLCBlY2hvPUZBTFNFfQp0eXBvX2F2cmcgPC0gY3V0cmVlKGNsdXN0NCwgMykKZnJlcSh0eXBvX2F2cmcpCmBgYAoKQydlc3QgdW5lIGNsYXNzZmljYXRpb24gbW9pbnMgYm9ubmUgcXVlIGNlbGxlIGF2ZWMgbGEgbWV0aG9kZSBXYXJkIG1haXMgZWxsZSByZXN0ZSBjb3JyZWN0ZS4KCk5vdXMgZW4gY29uY2x1b25zIHF1ZSBsYSBtw6l0aG9kZSBXYXJkIGVzdCBsYSBtZWlsbGV1cmUhISAgCgojIyBDYXJhY3TDqXJpc2F0aW9uIGRlcyBjbGFzc2lmaWNhdGlvbnMgb2J0ZW51ZXMKCkxlcyBkaWZmw6lyZW5jZXMgZW50cmUgbGVzIGRldXggbWV0aG9kZXMgZGUgY2xhc3NpZmZpY2F0aW9uIHNvbnQ6CgoqICoqTGEgZGlzdGFuY2UgdXRpbGlzw6llKio6IExlIGNsdXN0ZXJpbmcgaGnDqXJhcmNoaXF1ZSBwZXV0IGfDqXJlciBuJ2ltcG9ydGUgcXVlbGxlIG1lc3VyZSBkZSBkaXN0YW5jZSwgdGFuZGlzIHF1ZSBsZXMgS21lYW5zIHJlcG9zZW50IHN1ciBsZXMgZGlzdGFuY2VzIGV1Y2xpZGllbm5lcy4KCiogKipMYSBzdGFiaWxpdMOpIGRlcyByw6lzdWx0YXRzKio6IExhIG3DqXRob2RlIEttZWFucyBuw6ljZXNzaXRlIHVuZSDDqXRhcGUgYWzDqWF0b2lyZSBsb3JzIGRlIHNvbiBpbml0aWFsaXNhdGlvbiBxdWkgcGV1dCBkb25uZXIgZGVzIHLDqXN1bHRhdHMgZGlmZsOpcmVudHMgc2kgbGUgcHJvY2Vzc3VzIGVzdCByw6lleMOpY3V0w6ksIGNlIHF1aSBuJ2VzdCBwYXMgbGUgY2FzIGRhbnMgbGUgY2x1c3RlcmluZyBoacOpcmFyY2hpcXVlLgoKKiAqKkxlIG5vbWJyZSBkZSBjbHVzdGVyKio6IE3Dqm1lIHNpIG9uIHBldXQgdXRpbGlzZXIgZGVzIHRyYWPDqXMgZGUgc2lsaG91ZXR0ZSwgb3UgZCdhdXRyZSBtb3llbnMgcG91ciB0cm91dmVyIGxlIGJvbiBub21icmUgYXZhbnQgZCdhcHBsaXF1ZXIgbGEgbcOpdGhvZGUgZGVzIEttZWFucywgTGUgY2x1c3RlcmluZyBoacOpcmFyY2hpcXVlIHBldXQgZW4gcGx1cyBzJ2FwcHV5ZXIgc3VyIHVuIGRlbmRyb2dyYW1tZS4KCiogKipDb21wbGV4aXTDqSBkZSBjYWxjdWwqKjogTGEgbcOpdGhvZGUgZGVzIEttZWFucyBlc3QgbW9pbnMgY2/Du3RldXNlIGVuIGNhbGN1bCBxdWUgY2VsbGUgZHUgY2x1c3RlcmluZyBoacOpcmFyY2hpcXVlLCBldCBlbGxlIHBldXQgw6p0cmUgZXjDqWN1dMOpIHN1ciBkZSBncmFuZHMgZW5zZW1ibGVzIGRlIGRvbm7DqWVzIGFzc2V6IHJhcGlkZW1lbnQsIGNlIHBvdXJxdW9pIG9uIGxhIHByw6hmZXJlIQoKKiAqKkNhdGVnb3JpZSoqOiBMZSBLbWVhbnMgZXN0IGRlIGJhc2UgY2VudHJvaWRlLCBhbG9ycyBxdWUgbGEgQ0hBIGVzdCBoacOpcmFyY2hpY2FsLgoKKiAqKk1ldGhvZGVzIHBvdXIgdHJvdXZlciBkaWZmw6lyZW50cyBjbHVzdGVycyoqOiBQb3VyIGxlIEttZWFucyBub3VzIGF2b25zIEVsYm93LCBTaWxob3VldHRlLCBldCBHYXAuIFRhbmRpcyBxdWUgcG91ciBsYSBDSEEgbm91cyBhdm9ucyBlbiBwbHVzIERlbmRyb2dyYW1tZSBldCBpbmVydGllLgoKKiAqKkNvbmNsdXNpb24qKjogTGUgS21lYW5zIGVzdCBmb3J0ZW1lbnQgaW1wYWN0w6kgcGFyIGxlcyBjZW50cm9pZGVzIGluaXRpYXV4LCBjZSBxdWkgcGV1dCBwcm9kdWlyZSBkZXMgcmVzdWx0YXRzIHNvdXMgb3B0aW1hdXguIE1haXMgaWwgYSBsJ2F2YW50YWdlIGQnYXZvaXIgdW5lIGNvbnZlcmdlbmNlIGdhcmFudGllLCBzcMOpY2lmaXF1ZW1lbnQgcG91ciBsZXMgY2x1c3RlcnMgZGUgZGlmZmVyZW50ZXMgdGFpbGxlcyBldCBmb3JtZXMuICAKTGEgQ0hBIGVzdCBwbHVzIGZsZXhpYmxlLCBwbHVzIGZhY2lsZSBlbiB0cmFpdGVtZW50IGRlIHRvdXRlIGZvcm1lIGRlIHNpbWlsYXJpdMOpIGV0IGRlIGRpc3RhbmNlLiBFbGxlIGVzdCBwbHVzIGZhY2lsZSBwb3VyIGRldGVybWluZXIgbGUgbm9tYnJlIGRlIGNsdXN0ZXJzLiAgClBhciByYXBwb3J0IGEgbm90cmUgw6l0dWRlLCBub3VzIGVuIGNvbmNsdW9ucyBxdSdpbCB5IGEgYmllbiB1bmUgZGlmZsOpcmVuY2Ugc3DDqWNpZmlxdWUgZGUgY2x1c3RlcnMgZGFucyBsZXMgZG9ubsOpZXMgKG5vdXMgYXZvbnMgYmllbiAzIHZhcmnDqXTDqXMpLiBJbCBlc3QgbWlldXggcG91ciBub3VzIGRlIGNob2lzaXIgbGEgbcOpdGhvZGUgZGVzIGttZWFucyBkYW5zIGwnZW5zZW1ibGUuIE1haXMgcGFydGljdWxpZXJlbWVudCwgbGUgbm9tYnJlIGRlIGNsdXN0ZXJzIHNlIGZhaXQgbWlldXggYXZlYyBsYSBDSEEsIGV0IGxlIGNsdXN0ZXJpbmcgYXZlYyBsZXMgSy1tZWFucy4KCgojIyBQb3VyIGFsbGVyIHBsdXMgbG9pbgoKTm91cyBwb3Vycm9ucyBjb21wYXJlciBub3MgcmVzdWx0YXMgYXZlYyBwbHVzaWV1cnMgYXV0cmVzIG1ldGhvZGVzIGRlIGNsdXN0ZXJpbmcsIGlsIGV4aXN0ZSB1bmUgbGFyZ2UgdmFyaWV0w6kgZCdhbGdvcml0aG1lIGRlIGNsYXNzaWZpY2F0aW9uIG5vbiBzdXBlcnZpc8OpLiBDb21tZSBwYXIgZXhlbXBsZSBsYSBtZXRob2RlIE1OSVZBUiAodmFyaWFuY2UgbWluaW1pemluZyBoaWVyYXJjaGljYWwgY2x1c3RlcmluZykgbWFpcyBtYWxoZXVyZXVzZW1lbnQgbidhdm9ucyB0cm91dsOpIHF1ZSBkZXMgYXJ0aWNsZXMgcGF5YW50cyBhIGNlIHN1amV0Li4uCgpOb3VzIGF2b25zIGFsb3JzIGRlY2lkw6kgZGUgdGVzdGVyIGQnYXV0cmUgbWV0aG9kZSwgdGVsIHF1ZSBsJ2FsZ2hvcnRpbWUgZGUgQ0xBUkEuCkF1IGxpZXUgZGUgdHJvdXZlciBkZXMgbcOpZG/Dr2RlcyBwb3VyIGwnZW5zZW1ibGUgZGUgZG9ubsOpZXMsIENMQVJBIGNvbnNpZMOocmUgdW4gcGV0aXQgw6ljaGFudGlsbG9uIGRlIGRvbm7DqWVzIGF2ZWMgdW5lIHRhaWxsZSBmaXhlIChzYW1wc2l6ZSkgZXQgYXBwbGlxdWUgbCdhbGdvcml0aG1lIFBBTSBwb3VyIGfDqW7DqXJlciB1biBlbnNlbWJsZSBvcHRpbWFsIGRlIG3DqWRvw69kZXMgcG91ciBsJ8OpY2hhbnRpbGxvbi4gTGEgcXVhbGl0w6kgZGVzIG3DqWRvw69kZXMgcsOpc3VsdGFudHMgZXN0IG1lc3Vyw6llIHBhciBsYSBkaXNzZW1ibGFuY2UgbW95ZW5uZSBlbnRyZSBjaGFxdWUgb2JqZXQgZGUgbCdlbnNlbWJsZSBkZSBkb25uw6llcyBldCBsZSBtw6lkb8OvZGUgZGUgc29uIGNsdXN0ZXIsIGTDqWZpbmkgY29tbWUgbGEgZm9uY3Rpb24gZGUgY2/Du3QuICAKQ0xBUkEgcsOpcMOodGUgbGVzIHByb2Nlc3N1cyBkJ8OpY2hhbnRpbGxvbm5hZ2UgZXQgZGUgcmVncm91cGVtZW50IHVuIG5vbWJyZSBkZSBmb2lzIHByw6lkw6lmaW5pIGFmaW4gZGUgbWluaW1pc2VyIGxlIGJpYWlzIGQnw6ljaGFudGlsbG9ubmFnZS4gTGVzIHLDqXN1bHRhdHMgZGUgcmVncm91cGVtZW50IGZpbmF1eCBjb3JyZXNwb25kZW50IMOgIGwnZW5zZW1ibGUgZGVzIG3DqWRvw69kZXMgYXZlYyBsZSBjb8O7dCBtaW5pbWFsLiAgCgpgYGB7ciBzZWFyY2gxLCBlY2hvPUZBTFNFfQpsaWJyYXJ5KGNsdXN0ZXIpCmNsYXJhID0gY2xhcmEoc2VlZHNfc2NhbGVzLCAzLCBtZXRyaWMgPSAiZXVjbGlkZWFuIiwgc3RhbmQgPSBGQUxTRSwgCiAgICAgIHNhbXBsZXMgPSA1LCBwYW1MaWtlID0gRkFMU0UpCmNsYXJhJGNsdXNpbmZvCmBgYApOb3VzIHJlbWFycXVvbnMgcXVlIGwnYWxnaG9yaXRobWUgYSBjbGFzc8OpIDoKNzQga2FtYSwgNjQgUm9zYSBldCA3MiBDYW5hZGlhbi4uLmNlIHF1aSBuJ2VzdCB0b3Vqb3VycyBwYXMgcGFyZmFpdC4uLgoKYGBge3Igc2VhcmNoMiwgZWNobz1GQUxTRX0KbGlicmFyeShjbHVzdGVyKQpwYW0ucmVzID0gcGFtKHNlZWRzX3NjYWxlcyxrID0zICApCnBhbS5yZXMkY2x1c2luZm8KYGBgCk5vdXMgcmVtYXJxdW9ucyBxdWUgbCdhbGdob3JpdGhtZSBhIGNsYXNzw6kgOgo3NyBrYW1hLCA2MiBSb3NhIGV0IDcxIENhbmFkaWFuLi4uY2UgcXVpIG4nZXN0IHRvdWpvdXJzIHBhcyBwYXJmYWl0Li4uCgpgYGB7ciBzZWFyY2gzLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojbGlicmFyeShrZXJubGFiKQojbGlicmFyeSgnTU5WYXInKQpgYGAK