1 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.

1.1 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”)

1.2 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.

1.3 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.

1.4 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)

1.5 Projection sur les deux premières composantes principales

Nous remarquons que les variables CW et CL sont les seules a contribuer désormais.

1.6 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!!

2 Kmeans et clustering hiérarchique ascendant

2.1 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.

2.2 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.

2.3 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!!

2.4 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.

2.5 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