Exercice 3.1 : Tracé d’une fonction
- Définissons une grille de variation pour x puis traçons la courbe sinus:
x <- seq(0,2*pi,length=1000)
plot(sin(x)~x,type="l")
- Pour rajouter le titre, on utilise la fonction title (on aurait pu directement utiliser l’argument main dans la fonction plot):
Exercice 3.2 : Comparaison de distributions
- Pour tracer une loi normale, il suffit de tracer la densité en utilisant la fonction dnorm. On peut ensuite améliorer le graphique en traçant l’axe des abscisses puis un segment entre 0 et le maximum de la loi normale:
plot(dnorm,-4,4)
abline(h=0)
segments(0,0,0,dnorm(0),lty=2)
- Pour tracer de nouvelles courbes nous utilisons la fonction curve avec l’argument add=TRUE. Pour différencier les courbes, on utilise une couleur différentes pour chaque distribution.
curve(dt(x,5),add=TRUE,col=2)
curve(dt(x,30),add=TRUE,col=3)
- Il suffit d’utiliser la fonction legend et de la positionner en haut à gauche:
Exercice 3.3 : Tracé de points
- L’importation et la construction du nuage de points sont immédiates:
ozone <- read.table("https://r-stat-sc-donnees.github.io/ozone.txt",header=TRUE)
plot(maxO3~T12,data=ozone)
- Pour relier les points, il suffit d’utiliser l’argument type=“l”; ce graphe n’est pas lisible car il faut préalablement trier les données par abscisses croissantes.
- C’est ce que permet la fonction order:
Exercice 3.4 : Loi des grands nombres
- On crée un vecteur \(X\) de longueur 1000:
- La fonction cumsum permet de construire un vecteur de sommes cumulées:
Le graphique obtenu illustre la loi des grands nombres.
Exercice 3.5 : Théorème central limite
- S_N suit une loi binomiale de paramètres N et p, de moyenne N p* et d’écart-type racine(Np/(1-p)*.
- On fixe la graine du générateur aléatoire avant de simuler un vecteur de 1000 réalisations d’une loi binomiale de paramètres N et p :
- Afin de dessiner la courbe de la loi normale centrée-réduite, on crée une grille de \(x\) variant entre -4 et 4. On découpe alors la fenêtre graphique en 1 ligne et 3 colonnes puis on trace un histogramme et on superpose la courbe de la loi normale.
Exercice 3.6 : Tracé des taches solaires
- Le séparateur de décimale est ici la virgule, ce qu’il est important de préciser, sinon la variable nbe_tach est considérée comme qualitative.
- Créons la variable qualitative trenteans:
- Vérifions que les couleurs citées appartiennent bien à la palette de couleur
- Pour tracer la série chronologique de la figure, on construit d’abord le graphe sans courbe et sans point (argument type=“n”) ce qui permet de définir les plages de variation de x et y ainsi que les libellés des axes. On dessine alors les morceaux de courbe un par un en changeant de couleur à chaque modalité de trenteans:
Exercice 3.7 : Tracé d’une densité
- Pour tracer la courbe de la loi normale, on définit d’abord l’intervalle de variation de x:
x <- seq(-3.5,3.5,length=1000)
plot(x,dnorm(x),type="l",ylab="Densité")
- Pour tracer une droite horizontale, on utilise abline et l’argument h:
abline(h=0)
- à 5. Pour les questions 3 à 5, on utilise les fonctions polygon, arrows et text. Pour pouvoir écrire des mathématiques avec la fonction text, on utilise expression:
Exercice 3.8 : Plusieurs graphiques
- Pour générer le graphique, on est amené à redéfinir les marges de chaque graphique à l’aide de la fonction par. On utilise également la fonction layout pour définir la disposition des trois graphiques:
- L’argument widths de layout permet de préciser la largeur de chaque colonne:
Exercice 3.9 : Nombre d’étudiants par ville universitaire
- L’importation avec séparateur ; la classe et le résumé sont donnés par:
- Le vecteur decoupe est créé avec
- Le découpage est obtenu avec la fonction cut en incluant les extrêmes:
- Le changement des modalités est effectué par:
- Après avoir chargé le package ggmap, la bounding box est obtenue avec
- La variable qualitative Xq est ajoutée à villes:
- Le téléchargement s’effectue simplement:
- Le tracé est alors (en enlevant la légende automatique pour “size” avec la fonction guides)
Exercice 3.10 : Chômage et élection régionale
- L’importation utilise la fonction read_sf du package sf et importe le contenu du répertoire grâce à:
- Le graphique (pour la première variable) est simplement
- Le résumé et la classe sont obtenues par
- Le résumé pécédent nous a affiché les noms de variables et nous pouvons lire que la variable NOM contient le nom des région et son contenu s’affiche bien avec
La première variable NOM donne l’intitulé de la région, la seconde son code. 5. Le graphique s’obtient comme suit:
- La région correspondante, le Limousin, est donnée par
- Nous sélectionnons dans l’objet regions les lignes qui correspondent à une valeur pour la variable NOM d’Alsace grâce à filter et nous traçons:
- L’importation se fait avec read_delim du package readr qui importe directement au format tibble:
Nous créons une variable de type caractère NUMERO et supprimons la variable CODGEO avec:
- Nous fusionnons selon NUMERO:
- Le graphique qui colorie par ordre décroissant (signe “-”) selon le taux de chômage 2011 est obtenu avec:
- La variable Majorite est ajoutee au tibble chomtot avec
Remarquons que les niveaux (et l’ordre) des facteurs est contrôlé avec l’argument levels de la fonction factor. Ensuite le graphique est obtenu par
Exercice 3.11 : Représentation graphique et projection
- Le package est chargé puis la carte est tracée avec la fonction map:
- L’objet de type map est en suite transformé en type sfc
- Transformons le en sfc
- Il est ensuite représenté:
- La projection en polyconique puis le graphique:
Exercice 3.12 : Représentation de tuiles
- Trouvons les coordonnées avec la projection de Mercator (à la main):
- Arrondissons pour trouver xtile et ytile
- Téléchargeons la tuile:
- dans un premier temps composons l’URL
- dans un second temps téléchargeons l’image
- dans un troisième temps importons l’image PNG dans R et transformons l’objet importé en type raster
- Changement de classe et premiers attributs declasse ggmap
- Dernier attribut de la classe ggmap: la bounding box, l’attribut bb
- programmons une fonction pour calculer la longitude latitude depuis les coordonnées de Mercator
- les 4 bords de la tuiles (en coordonnées de Mercator) sont obtenus en partant du bord xtile ytile (en bas à gauche) et en ajoutant 1 ou pas
- en utilisant la fonction lonlat transformons les 4 bords de Mercator vers lon/lat et calculons la bounding box
- ajustons le resultat au bon format: data-frame avec noms adequats dans le bon ordre et le tout devient l’attribut bb
- Trace de la tuile qui est maintenant au bon format
- Plusieurs tuiles: Le départ est identique
Le télechargement de plusieurs tuiles autour (2 couronnes d’où le vecteurs de -2 à +2)
L’agencement de ces tuiles (256x256) en une seule matrice raster
Les attributs basiques et la classe ggmap
Le calcul de la bounding box (en réutilisant la fonction lonlat du 5.a)
Le graphique final
LS0tDQp0aXRsZTogIkNvcnJlY3Rpb24gZGVzIGV4ZXJjaWNlcyBkdSBjaGFwaXRyZSAzIg0KYXV0aG9yOiAiSHVzc29uIGV0IGFsLiINCmRhdGU6ICIwOS8wOS8yMDE4Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzMnDQogICAgdG9jX2Zsb2F0OiB5ZXMNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgY2FjaGUgPSBUUlVFKQ0KYGBgDQoNCg0KIyMgRXhlcmNpY2UgMy4xIDogVHJhY8OpIGQndW5lIGZvbmN0aW9uDQoNCjEuIETDqWZpbmlzc29ucyB1bmUgZ3JpbGxlIGRlIHZhcmlhdGlvbiBwb3VyICp4KiBwdWlzIHRyYcOnb25zIGxhIGNvdXJiZSAqc2ludXMqOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFLGV2YWw9RkFMU0V9DQp4IDwtIHNlcSgwLDIqcGksbGVuZ3RoPTEwMDApDQpwbG90KHNpbih4KX54LHR5cGU9ImwiKQ0KYGBgDQoyLiBQb3VyIHJham91dGVyIGxlIHRpdHJlLCBvbiB1dGlsaXNlIGxhIGZvbmN0aW9uICp0aXRsZSogKG9uIGF1cmFpdCBwdSBkaXJlY3RlbWVudCB1dGlsaXNlciBsJ2FyZ3VtZW50ICptYWluKg0KZGFucyBsYSBmb25jdGlvbiAqcGxvdCopOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KcGxvdChzaW4oeCl+eCx0eXBlPSJsIikNCnRpdGxlKCJHcmFwaGUgZGUgbGEgZm9uY3Rpb24gc2ludXMiKQ0KYGBgDQoNCiMjIEV4ZXJjaWNlIDMuMiA6IENvbXBhcmFpc29uIGRlIGRpc3RyaWJ1dGlvbnMNCg0KMS4gUG91ciB0cmFjZXIgdW5lIGxvaSBub3JtYWxlLCBpbCBzdWZmaXQgZGUgdHJhY2VyIGxhIGRlbnNpdMOpIGVuIHV0aWxpc2FudCBsYSBmb25jdGlvbiAqZG5vcm0qLiBPbiBwZXV0IGVuc3VpdGUNCmFtw6lsaW9yZXIgbGUgZ3JhcGhpcXVlIGVuIHRyYcOnYW50IGwnYXhlIGRlcyBhYnNjaXNzZXMgcHVpcyB1biBzZWdtZW50IGVudHJlIDAgZXQgbGUgbWF4aW11bSBkZSBsYSBsb2kgbm9ybWFsZToNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxldmFsPUZBTFNFfQ0KcGxvdChkbm9ybSwtNCw0KQ0KYWJsaW5lKGg9MCkNCnNlZ21lbnRzKDAsMCwwLGRub3JtKDApLGx0eT0yKQ0KYGBgDQoyLiBQb3VyIHRyYWNlciBkZSBub3V2ZWxsZXMgY291cmJlcyBub3VzIHV0aWxpc29ucyBsYSBmb25jdGlvbiAqY3VydmUqIGF2ZWMgbCdhcmd1bWVudCAqYWRkPVRSVUUqLg0KUG91ciBkaWZmw6lyZW5jaWVyIGxlcyBjb3VyYmVzLCBvbiB1dGlsaXNlIHVuZSBjb3VsZXVyIGRpZmbDqXJlbnRlcyBwb3VyIGNoYXF1ZSBkaXN0cmlidXRpb24uDQpgYGB7cixldmFsPUZBTFNFfQ0KY3VydmUoZHQoeCw1KSxhZGQ9VFJVRSxjb2w9MikNCmN1cnZlKGR0KHgsMzApLGFkZD1UUlVFLGNvbD0zKQ0KYGBgDQozLiBJbCBzdWZmaXQgZCd1dGlsaXNlciBsYSBmb25jdGlvbiAqbGVnZW5kKiBldCBkZSBsYSBwb3NpdGlvbm5lciBlbiBoYXV0IMOgIGdhdWNoZToNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnBsb3QoZG5vcm0sLTQsNCkNCmFibGluZShoPTApDQpzZWdtZW50cygwLDAsMCxkbm9ybSgwKSxsdHk9MikNCmN1cnZlKGR0KHgsNSksYWRkPVRSVUUsY29sPTIpDQpjdXJ2ZShkdCh4LDMwKSxhZGQ9VFJVRSxjb2w9MykNCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIm5vcm1hbGUiLCJTdHVkZW50KDUpIiwiU3R1ZGVudCgzMCkiKSwNCiAgICBjb2w9MTozLGx0eT0xKQ0KYGBgDQoNCiMjIEV4ZXJjaWNlIDMuMyA6IFRyYWPDqSBkZSBwb2ludHMNCg0KMS4gTCdpbXBvcnRhdGlvbiBldCBsYSBjb25zdHJ1Y3Rpb24gZHUgbnVhZ2UgZGUgcG9pbnRzIHNvbnQgaW1tw6lkaWF0ZXM6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsZXZhbD1GQUxTRX0NCm96b25lIDwtIHJlYWQudGFibGUoImh0dHBzOi8vci1zdGF0LXNjLWRvbm5lZXMuZ2l0aHViLmlvL296b25lLnR4dCIsaGVhZGVyPVRSVUUpDQpwbG90KG1heE8zflQxMixkYXRhPW96b25lKQ0KYGBgDQoyLiBQb3VyIHJlbGllciBsZXMgcG9pbnRzLCBpbCBzdWZmaXQgZCd1dGlsaXNlciBsJ2FyZ3VtZW50ICp0eXBlPSJsIio7IGNlIGdyYXBoZSBuJ2VzdCBwYXMgbGlzaWJsZSBjYXIgaWwgZmF1dCBwcsOpYWxhYmxlbWVudCB0cmllcg0KbGVzIGRvbm7DqWVzIHBhciBhYnNjaXNzZXMgY3JvaXNzYW50ZXMuDQozLiBDJ2VzdCBjZSBxdWUgcGVybWV0IGxhDQpmb25jdGlvbiAqb3JkZXIqOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0Kb3Jkb24gPC0gb3JkZXIob3pvbmVbLCJUMTIiXSkNCnBsb3QobWF4TzN+VDEyLGRhdGE9b3pvbmVbb3Jkb24sXSx0eXBlPSJiIikNCmBgYA0KDQojIyBFeGVyY2ljZSAzLjQgOiBMb2kgZGVzIGdyYW5kcyBub21icmVzDQoNCjEuIE9uIGNyw6llIHVuIHZlY3RldXIgJFgkIGRlIGxvbmd1ZXVyIDEwMDA6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpzZXQuc2VlZCgxMjMpDQpYIDwtIHJiaW5vbSgxMDAwLCBzaXplPTEsIHByb2I9MC42KQ0KYGBgDQoyLiBMYSBmb25jdGlvbiAqY3Vtc3VtKiBwZXJtZXQgZGUgY29uc3RydWlyZSB1biB2ZWN0ZXVyIGRlIHNvbW1lcyBjdW11bMOpZXM6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpTbCA8LSBjdW1zdW0oWCkNCk1sIDwtIFNsLygxOjEwMDApDQpwbG90KE1sLCB0eXBlPSJsIikNCmFibGluZShoPTAuNiwgY29sPTIpDQpgYGANCkxlIGdyYXBoaXF1ZSBvYnRlbnUgaWxsdXN0cmUgbGEgbG9pIGRlcyBncmFuZHMgbm9tYnJlcy4NCg0KIyMgRXhlcmNpY2UgMy41IDogVGjDqW9yw6htZSBjZW50cmFsIGxpbWl0ZQ0KDQoxLiAgU19OIHN1aXQgdW5lIGxvaSBiaW5vbWlhbGUgZGUgcGFyYW3DqHRyZXMgKk4qIGV0ICpwKiwgZGUgbW95ZW5uZSAqTiAqIHAqIGV0IGQnw6ljYXJ0LXR5cGUgKnJhY2luZShOKnAvKDEtcCkqLg0KMi4gT24gZml4ZSBsYSBncmFpbmUgZHUgZ8OpbsOpcmF0ZXVyIGFsw6lhdG9pcmUgYXZhbnQgZGUgc2ltdWxlciB1biB2ZWN0ZXVyIGRlIDEwMDAgcsOpYWxpc2F0aW9ucyBkJ3VuZSBsb2kgYmlub21pYWxlIGRlIHBhcmFtw6h0cmVzICpOKiBldCAqcCogOg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpzZXQuc2VlZCgxMjMpDQpwIDwtIDAuNQ0KTiA8LSAxMA0KVTEwIDwtIChyYmlub20oMTAwMCwgc2l6ZSA9IE4sIHA9cCkgLSBOKnApIC9zcXJ0KE4qcCooMS1wKSkNCk4gPC0gMzANClUzMCA8LSAocmJpbm9tKDEwMDAsIHNpemUgPSBOLCBwPXApIC0gTipwKSAvc3FydChOKnAqKDEtcCkpDQpOIDwtIDEwMDANClUxMDAwIDwtIChyYmlub20oMTAwMCwgc2l6ZSA9IE4sIHA9cCkgLSBOKnApL3NxcnQoTipwKigxLXApKQ0KYGBgDQoNCjMuIEFmaW4gZGUgZGVzc2luZXIgbGEgY291cmJlIGRlIGxhIGxvaSBub3JtYWxlIGNlbnRyw6llLXLDqWR1aXRlLCBvbiBjcsOpZSB1bmUgZ3JpbGxlIGRlICR4JCB2YXJpYW50IGVudHJlIC00IGV0IDQuIE9uIGTDqWNvdXBlIGFsb3JzIGxhIGZlbsOqdHJlIGdyYXBoaXF1ZSBlbiAxIGxpZ25lIGV0IDMgY29sb25uZXMgcHVpcyBvbiB0cmFjZSB1biBoaXN0b2dyYW1tZSBldCBvbiBzdXBlcnBvc2UgbGEgY291cmJlIGRlIGxhIGxvaSBub3JtYWxlLg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpncmlsbGV4IDwtIHNlcSgtNCwgNCwgYnkgPSAwLjAxKQ0KcGFyKG1mcm93PWMoMSwzKSkNCmhpc3QoVTEwLCB4bGltPWMoLTQsNCksIHlsaW09YygwLDAuNiksIHByb2I9VFJVRSkNCmxpbmVzKGdyaWxsZXgsIGRub3JtKGdyaWxsZXgpLCBjb2w9NCkNCmhpc3QoVTMwLCB4bGltPWMoLTQsNCksIHlsaW09YygwLDAuNiksIHByb2I9VFJVRSkNCmxpbmVzKGdyaWxsZXgsIGRub3JtKGdyaWxsZXgpLCBjb2w9NCkNCmhpc3QoVTEwMDAsIHhsaW09YygtNCw0KSwgeWxpbT1jKDAsMC42KSwgcHJvYj1UUlVFKQ0KbGluZXMoZ3JpbGxleCwgZG5vcm0oZ3JpbGxleCksIGNvbD00KQ0KYGBgDQoNCiMjIEV4ZXJjaWNlIDMuNiA6IFRyYWPDqSBkZXMgdGFjaGVzIHNvbGFpcmVzDQoNCjEuIExlIHPDqXBhcmF0ZXVyIGRlIGTDqWNpbWFsZSBlc3QgaWNpIGxhIHZpcmd1bGUsIGNlIHF1J2lsIGVzdCBpbXBvcnRhbnQgZGUgcHLDqWNpc2VyLCBzaW5vbiBsYQ0KdmFyaWFibGUgKm5iZV90YWNoKiBlc3QgY29uc2lkw6lyw6llIGNvbW1lIHF1YWxpdGF0aXZlLg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KdGFjaGVzPC1yZWFkLnRhYmxlKCJodHRwczovL3Itc3RhdC1zYy1kb25uZWVzLmdpdGh1Yi5pby90YWNoZXNfc29sYWlyZXNfZGF0ZS5jc3YiLHNlcD0iOyIsaGVhZGVyPVRSVUUsDQogICAgIGNvbENsYXNzZXM9YygibnVtZXJpYyIsIkRhdGUiKSkNCnN1bW1hcnkodGFjaGVzKQ0KYGBgDQoNCjIuIENyw6lvbnMgbGEgdmFyaWFibGUgcXVhbGl0YXRpdmUgdHJlbnRlYW5zOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KdHJlbnRlYW5zIDwtIGN1dCh0YWNoZXNbLDJdLGJyZWFrcz0iMzAgeWVhcnMiKQ0KbGV2ZWxzKHRyZW50ZWFucykgPC0gMTpubGV2ZWxzKHRyZW50ZWFucykNCmBgYA0KMy4gVsOpcmlmaW9ucyBxdWUgbGVzIGNvdWxldXJzIGNpdMOpZXMgYXBwYXJ0aWVubmVudCBiaWVuIMOgIGxhIHBhbGV0dGUgZGUgY291bGV1cg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KY291bGV1cnM8LWMoInllbGxvdyIsIm1hZ2VudGEiLCJvcmFuZ2UiLCJjeWFuIiwiZ3JleSIsInJlZCIsDQogICAgImdyZWVuIiwiYmx1ZSIpDQphbGwoY291bGV1cnMlaW4lY29sb3JzKCkpDQpgYGANCjQuIFBvdXIgdHJhY2VyIGxhIHPDqXJpZSBjaHJvbm9sb2dpcXVlIGRlIGxhIGZpZ3VyZSwgb24gY29uc3RydWl0IGQnYWJvcmQgbGUgZ3JhcGhlIHNhbnMgY291cmJlIGV0IHNhbnMgcG9pbnQgKGFyZ3VtZW50ICp0eXBlPSJuIiopDQpjZSBxdWkgcGVybWV0IGRlIGTDqWZpbmlyIGxlcyBwbGFnZXMgZGUgdmFyaWF0aW9uIGRlICp4KiBldCAqeSogYWluc2kgcXVlIGxlcyBsaWJlbGzDqXMgZGVzIGF4ZXMuIE9uIGRlc3NpbmUgYWxvcnMgbGVzIG1vcmNlYXV4IGRlIGNvdXJiZSB1biBwYXIgdW4NCmVuIGNoYW5nZWFudCBkZSBjb3VsZXVyIMOgIGNoYXF1ZSBtb2RhbGl0w6kgZGUgKnRyZW50ZWFucyo6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpwYWxldHRlKGNvdWxldXJzKQ0KY29vcmR4IDwtIHNlcShhbG9uZz10YWNoZXNbLDFdKQ0KcGxvdChjb29yZHgsdGFjaGVzWywxXSx4bGFiPSJUZW1wcyIseWxhYj0iTmIgZGUgdGFjaGVzIix0eXBlPSJuIikNCmZvciAoaSBpbiBsZXZlbHModHJlbnRlYW5zKSl7DQogIHNlbGVjdGkgPC0gdHJlbnRlYW5zPT1pDQogIGxpbmVzKGNvb3JkeFtzZWxlY3RpXSx0YWNoZXNbc2VsZWN0aSwxXSxjb2w9aSkNCn0NCmBgYA0KDQojIyBFeGVyY2ljZSAzLjcgOiBUcmFjw6kgZCd1bmUgZGVuc2l0w6kNCg0KMS4gUG91ciB0cmFjZXIgbGEgY291cmJlIGRlIGxhIGxvaSBub3JtYWxlLCBvbiBkw6lmaW5pdCBkJ2Fib3JkIGwnaW50ZXJ2YWxsZSBkZSB2YXJpYXRpb24gZGUgKngqOg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsZXZhbD1GQUxTRX0NCnggPC0gc2VxKC0zLjUsMy41LGxlbmd0aD0xMDAwKQ0KcGxvdCh4LGRub3JtKHgpLHR5cGU9ImwiLHlsYWI9IkRlbnNpdMOpIikNCmBgYA0KDQoyLiBQb3VyIHRyYWNlciB1bmUgZHJvaXRlIGhvcml6b250YWxlLCBvbiB1dGlsaXNlICphYmxpbmUqIGV0IGwnYXJndW1lbnQgKmgqOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFLGV2YWw9RkFMU0V9DQphYmxpbmUoaD0wKQ0KYGBgDQozLiDDoCA1LiBQb3VyIGxlcyBxdWVzdGlvbnMgMyDDoCA1LCBvbiB1dGlsaXNlIGxlcyBmb25jdGlvbnMgKnBvbHlnb24qLCAqYXJyb3dzKiBldCAqdGV4dCouDQpQb3VyIHBvdXZvaXIgw6ljcmlyZSBkZXMgbWF0aMOpbWF0aXF1ZXMNCmF2ZWMgbGEgZm9uY3Rpb24gKnRleHQqLCBvbiB1dGlsaXNlICpleHByZXNzaW9uKjoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnggPC0gc2VxKC0zLjUsMy41LGxlbmd0aD0xMDAwKQ0KcGxvdCh4LGRub3JtKHgpLHR5cGU9ImwiLHlsYWI9IkRlbnNpdMOpIikNCmFibGluZShoPTApDQpzZWxlY3RpIDwtIHg+PXFub3JtKDAuOTUpDQphYnNjaSA8LSBjKHhbc2VsZWN0aV0scmV2KHhbc2VsZWN0aV0pKQ0Kb3Jkb24gPC0gYyhyZXAoMCxzdW0oc2VsZWN0aSkpLHJldihkbm9ybSh4W3NlbGVjdGldKSkpDQpwb2x5Z29uKGFic2NpLG9yZG9uLGNvbD0iYmx1ZSIpDQphcnJvd3MoMi43LDAuMiwyLGRub3JtKDIpLGxlbj0wLjEpDQp0ZXh0KDIuNywwLjIsZXhwcmVzc2lvbihwYXN0ZShhbHBoYT09NSwiJSIpKSxwb3M9MykNCmBgYA0KDQojIyBFeGVyY2ljZSAzLjggOiBQbHVzaWV1cnMgZ3JhcGhpcXVlcw0KDQoxLiBQb3VyIGfDqW7DqXJlciBsZSBncmFwaGlxdWUsIG9uIGVzdCBhbWVuw6kgw6AgcmVkw6lmaW5pciBsZXMgbWFyZ2VzIGRlIGNoYXF1ZSBncmFwaGlxdWUgw6AgbCdhaWRlIGRlIGxhIGZvbmN0aW9uICpwYXIqLiBPbiB1dGlsaXNlDQrDqWdhbGVtZW50IGxhIGZvbmN0aW9uICpsYXlvdXQqIHBvdXIgZMOpZmluaXIgbGEgZGlzcG9zaXRpb24gZGVzIHRyb2lzIGdyYXBoaXF1ZXM6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpwYXIobWFyPWMoMi4zLDIsMC41LDAuMykpDQpsYXlvdXQobWF0cml4KGMoMSwxLDIsMyksIDIsIDIsIGJ5cm93ID0gVFJVRSkpDQpwbG90KDE6MTAsMTA6MSxwY2g9MCkNCnBsb3QocmVwKDEsNCksdHlwZT0ibCIpDQpwbG90KGMoMiwzLC0xLDApLHR5cGU9ImIiKQ0KYGBgDQoyLiBMJ2FyZ3VtZW50ICp3aWR0aHMqIGRlICpsYXlvdXQqIHBlcm1ldCBkZSBwcsOpY2lzZXIgbGEgbGFyZ2V1ciBkZSBjaGFxdWUgY29sb25uZToNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnBhcihtYXI9YygyLjMsMiwwLjUsMC4zKSkNCmxheW91dChtYXRyaXgoYygxLDEsMiwzKSwgMiwgMiwgYnlyb3cgPSBUUlVFKSx3aWR0aHM9Yyg0LDEpKQ0KcGxvdCgxOjEwLDEwOjEscGNoPTApDQpwbG90KHJlcCgxLDQpLHR5cGU9ImwiKQ0KcGxvdChjKDIsMywtMSwwKSx0eXBlPSJiIikNCmBgYA0KDQojIyBFeGVyY2ljZSAzLjkgOiBOb21icmUgZCfDqXR1ZGlhbnRzIHBhciB2aWxsZSB1bml2ZXJzaXRhaXJlDQoNCjEuIEwnaW1wb3J0YXRpb24gYXZlYyBzw6lwYXJhdGV1ciAqOyogbGEgY2xhc3NlIGV0IGxlIHLDqXN1bcOpIHNvbnQgZG9ubsOpcyBwYXI6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQp2aWxsZXMgPC0gcmVhZC50YWJsZSgiaHR0cHM6Ly9yLXN0YXQtc2MtZG9ubmVlcy5naXRodWIuaW8vdmlsbGVzLmNzdiIsaGVhZGVyPVRSVUUsc2VwPSI7IikNCmNsYXNzKHZpbGxlcykNCnN1bW1hcnkodmlsbGVzKQ0KYGBgDQoyLiBMZSB2ZWN0ZXVyICpkZWNvdXBlKiBlc3QgY3LDqcOpIGF2ZWMNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmRlY291cGUgPC0gYygwLDE1MDAwLDI1MDAwLDUwMDAwLDc1MDAwLDEwMDAwMCxtYXgodmlsbGVzJE5iLmV0dWRpYW50KSkNCmBgYA0KDQozLiBMZSBkw6ljb3VwYWdlIGVzdCBvYnRlbnUgYXZlYyBsYSBmb25jdGlvbiAqY3V0KiBlbiBpbmNsdWFudCBsZXMgZXh0csOqbWVzOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KWHEgPC0gY3V0KHZpbGxlcyROYi5ldHVkaWFudCxicmVha3M9ZGVjb3VwZSkNCmBgYA0KNC4gTGUgY2hhbmdlbWVudCBkZXMgbW9kYWxpdMOpcyBlc3QgZWZmZWN0dcOpIHBhcjoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmxldmVscyhYcSkgPC0gcGFzdGUoZm9ybWF0KGRlY291cGVbLWxlbmd0aChkZWNvdXBlKV0pLA0KICAgICAgICAgICAgIGZvcm1hdChkZWNvdXBlWy0xXSksc2VwPSItIikNCmBgYA0KNS4gQXByw6hzIGF2b2lyIGNoYXJnw6kgbGUgcGFja2FnZSAqZ2dtYXAqLCBsYSBib3VuZGluZyBib3ggZXN0IG9idGVudWUgYXZlYw0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ21hcCkNCmJib3ggPC0gbWFrZV9iYm94KGxvbmdpdHVkZSxsYXRpdHVkZSxkYXRhPXZpbGxlcykNCmBgYA0KNi4gTGEgdmFyaWFibGUgcXVhbGl0YXRpdmUgKlhxKiBlc3QgYWpvdXTDqWUgw6AgICp2aWxsZXMqOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KdmlsbGVzIDwtIGNiaW5kLmRhdGEuZnJhbWUodmlsbGVzLEVmZmVjdGlmPVhxKQ0KYGBgDQoNCjcuIExlIHTDqWzDqWNoYXJnZW1lbnQgcydlZmZlY3R1ZSBzaW1wbGVtZW50Og0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KTWFDYXJ0ZSA8LSBnZXRfbWFwKGJib3gpDQpgYGANCg0KOS4gTGUgdHJhY8OpIGVzdCBhbG9ycyAoZW4gZW5sZXZhbnQgbGEgbMOpZ2VuZGUgYXV0b21hdGlxdWUgcG91ciAic2l6ZSIgYXZlYyBsYSBmb25jdGlvbiAqZ3VpZGVzKikNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmdnbWFwKE1hQ2FydGUpICsgZ2VvbV9wb2ludChkYXRhID0gdmlsbGVzLCBhZXMoeD1sb25naXR1ZGUseT1sYXRpdHVkZSxjb2xvciA9IEVmZmVjdGlmLHNpemU9NTAwMCpsb2coTmIuZXR1ZGlhbnQpKSkrZ3VpZGVzKHNpemU9RkFMU0UpIA0KYGBgDQoNCiMjIEV4ZXJjaWNlIDMuMTAgOiBDaMO0bWFnZSAgZXQgw6lsZWN0aW9uIHLDqWdpb25hbGUNCg0KMS4gTCdpbXBvcnRhdGlvbiB1dGlsaXNlIGxhIGZvbmN0aW9uICpyZWFkX3NmKiBkdQ0KICBwYWNrYWdlICpzZiogZXQgaW1wb3J0ZSBsZSBjb250ZW51IGR1IHLDqXBlcnRvaXJlIGdyw6JjZSDDoDoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoc2YpDQpzZXR3ZCgiQzovVXNlcnMvaHVzc29uL0Ryb3Bib3gvUnBvdXJsYXN0YXRldGxhZGF0YXNjaWVuY2UvY2hhcGl0cmUvY2FydGVzL0RPTk5FRVMiKQ0KcmVnaW9ucyA8LSByZWFkX3NmKCJyZWdpb25zLW1ldHJvcG9sZS1jb21wbGV0IikNCmBgYA0KMi4gTGUgZ3JhcGhpcXVlIChwb3VyIGxhIHByZW1pw6hyZSB2YXJpYWJsZSkgZXN0IHNpbXBsZW1lbnQNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnBsb3QocmVnaW9uc1ssMV0pDQpgYGANCjMuIExlIHLDqXN1bcOpIGV0IGxhIGNsYXNzZSBzb250IG9idGVudWVzIHBhcg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShyZWdpb25zKQ0KY2xhc3MocmVnaW9ucykNCmBgYA0KNC4gTGUgcsOpc3Vtw6kgcMOpY8OpZGVudCBub3VzIGEgYWZmaWNow6kgbGVzIG5vbXMgZGUgdmFyaWFibGVzIGV0IG5vdXMgcG91dm9ucyBsaXJlIHF1ZSBsYSB2YXJpYWJsZSAqTk9NKiBjb250aWVudCBsZSBub20gZGVzIHLDqWdpb24gZXQgc29uIGNvbnRlbnUgcydhZmZpY2hlIGJpZW4gYXZlYw0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KcmVnaW9ucyROT00NCmBgYA0KICBMYSBwcmVtacOocmUgdmFyaWFibGUgKk5PTSogZG9ubmUgbCdpbnRpdHVsw6kgZGUgbGEgcsOpZ2lvbiwgbGENCiAgc2Vjb25kZSBzb24gY29kZS4NCjUuIExlIGdyYXBoaXF1ZSBzJ29idGllbnQgY29tbWUgc3VpdDoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnBsb3QocmVnaW9uc1sxLDFdKQ0KYGBgDQo2LiBMYSByw6lnaW9uIGNvcnJlc3BvbmRhbnRlLCBsZSBMaW1vdXNpbiwgZXN0IGRvbm7DqWUgcGFyDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpyZWdpb25zJE5PTVsxXQ0KYGBgDQo3LiBOb3VzIHPDqWxlY3Rpb25ub25zIGRhbnMgbCdvYmpldCAqcmVnaW9ucyogbGVzIGxpZ25lcyBxdWkgY29ycmVzcG9uZGVudCDDoCB1bmUgdmFsZXVyIHBvdXIgbGEgIHZhcmlhYmxlICpOT00qIGQnKkFsc2FjZSogZ3LDomNlIMOgICpmaWx0ZXIqIGV0IG5vdXMgdHJhw6dvbnM6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KZ2dwbG90KCkgKyBnZW9tX3NmKGRhdGE9cmVnaW9ucyAlPiUgZmlsdGVyKE5PTT09IkFsc2FjZSIpKQ0KYGBgDQo4LiBMJ2ltcG9ydGF0aW9uIHNlIGZhaXQgYXZlYyAqcmVhZF9kZWxpbSogZHUgcGFja2FnZSAqcmVhZHIqIHF1aSBpbXBvcnRlIGRpcmVjdGVtZW50IGF1IGZvcm1hdCAqdGliYmxlKjoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkocmVhZHIpDQpjaG9tcmVnaW9uIDwtIHJlYWRfZGVsaW0oImh0dHBzOi8vci1zdGF0LXNjLWRvbm5lZXMuZ2l0aHViLmlvL3R4Y2hvbV9yZWdpb24uY3N2IixkZWxpbT0iOyIpDQpgYGANCk5vdXMgY3LDqW9ucyB1bmUgdmFyaWFibGUgZGUgdHlwZSBjYXJhY3TDqHJlICpOVU1FUk8qIGV0IHN1cHByaW1vbnMgbGEgdmFyaWFibGUgKkNPREdFTyogYXZlYzoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmNob21yZWdpb24gPC0gbXV0YXRlKGNob21yZWdpb24sIE5VTUVSTz1hcy5jaGFyYWN0ZXIoQ09ER0VPKSwNCiAgICAgICAgICAgICAgICAgICAgIENPREdFTz1OVUxMKQ0KYGBgDQoNCjkuIE5vdXMgZnVzaW9ubm9ucyBzZWxvbiAqTlVNRVJPKjoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmNob210b3QgPC0gaW5uZXJfam9pbihyZWdpb25zLGNob21yZWdpb24sYnk9Ik5VTUVSTyIpDQpgYGANCjEwLiBMZSBncmFwaGlxdWUgcXVpIGNvbG9yaWUgcGFyIG9yZHJlIGTDqWNyb2lzc2FudCAoc2lnbmUgIi0iKSBzZWxvbiBsZSB0YXV4IGRlIGNow7RtYWdlIDIwMTEgZXN0IG9idGVudSBhdmVjOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KCkgKyBnZW9tX3NmKGRhdGE9Y2hvbXRvdCxhZXMoZmlsbD0tVENIT01CMVQxMSkpDQpgYGANCjExLiBMYSB2YXJpYWJsZSAqTWFqb3JpdGUqIGVzdCBham91dGVlIGF1IHRpYmJsZSAqY2hvbXRvdCogYXZlYw0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KY2hvbXRvdCA8LSBjaG9tdG90ICU+JSBtdXRhdGUobWFqb3JpdGU9IGZhY3RvcihNYWpvcml0ZSxsZXZlbHM9YygiVU1QIiwiUFJHIiwiUFMiLCJEVkciKSkpDQpgYGANClJlbWFycXVvbnMgcXVlIGxlcyBuaXZlYXV4IChldCBsJ29yZHJlKSBkZXMgZmFjdGV1cnMgZXN0IGNvbnRyw7Rsw6kgYXZlYyBsJ2FyZ3VtZW50ICpsZXZlbHMqIGRlIGxhIGZvbmN0aW9uICpmYWN0b3IqLiBFbnN1aXRlIGxlIGdyYXBoaXF1ZSBlc3Qgb2J0ZW51IHBhcg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KCkgKyBnZW9tX3NmKGRhdGE9Y2hvbXRvdCxhZXMoZmlsbD1tYWpvcml0ZSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImJsdWUiLCJzYWxtb24iLCJwaW5rIiwicGluazIiKSkNCmBgYA0KDQojIyBFeGVyY2ljZSAzLjExIDogUmVwcsOpc2VudGF0aW9uIGdyYXBoaXF1ZSBldCBwcm9qZWN0aW9uDQoNCjEuIExlIHBhY2thZ2UgZXN0IGNoYXJnw6kgcHVpcyBsYSBjYXJ0ZSBlc3QgdHJhY8OpZSBhdmVjIGxhIGZvbmN0aW9uDQogICptYXAqOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShtYXBzKQ0KbWFwKCJzdGF0ZSIscGxvdD1UUlVFKQ0KYGBgDQoyLiBMJ29iamV0IGRlIHR5cGUgKm1hcCogZXN0IGVuIHN1aXRlIHRyYW5zZm9ybcOpIGVuIHR5cGUgKnNmYyogDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQp1c2EgPC0gbWFwKCJzdGF0ZSIscGxvdD1GQUxTRSxmaWxsPVRSVUUpDQpgYGANCjMuIFRyYW5zZm9ybW9ucyBsZSBlbiBzZmMNCmBgYHtyfQ0KdXNhc2YgPC0gc3RfYXNfc2ZjKHVzYSkNCmNsYXNzKHVzYXNmKQ0KYGBgDQoNCjQuIElsIGVzdCBlbnN1aXRlIHJlcHLDqXNlbnTDqToNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCnBsb3QodXNhc2YpDQpgYGANCjQuIExhIHByb2plY3Rpb24gZW4gcG9seWNvbmlxdWUgcHVpcyBsZSBncmFwaGlxdWU6DQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQp1c2FzZjIgPC0gc3RfdHJhbnNmb3JtKHVzYXNmLDEwMjAwOCkNCnBsb3QodXNhc2YyKQ0KYGBgDQojIyBFeGVyY2ljZSAzLjEyIDogUmVwcsOpc2VudGF0aW9uIGRlIHR1aWxlcw0KMS4gVHJvdXZvbnMgbGVzIGNvb3Jkb25uw6llcyBhdmVjIGxhIHByb2plY3Rpb24gZGUgTWVyY2F0b3IgKMOgIGxhIG1haW4pOg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbG9uIDwtIDYuNjE1OTgyDQpsYXQgPC0gNDUuODUxNjENCnpvb20gPC0gMTMNCnh4IDwtIChsb24rMTgwKS8zNjAgKiAyXnpvb20NCnl5IDwtICgxLSBsb2codGFuKGxhdCpwaS8xODApKzEvY29zKGxhdCpwaS8xODApKSAvcGkpKjJeKHpvb20tMSkNCmBgYA0KDQoyLiBBcnJvbmRpc3NvbnMgcG91ciB0cm91dmVyICp4dGlsZSogZXQgKnl0aWxlKg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KeHRpbGUgPC0gZmxvb3IoeHgpDQp5dGlsZSA8LSBmbG9vcih5eSkNCmBgYA0KDQozLiBUw6lsw6ljaGFyZ2VvbnMgbGEgdHVpbGU6IA0KICAgYS4gZGFucyB1biBwcmVtaWVyIHRlbXBzIGNvbXBvc29ucyBsJ1VSTA0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KdXJsU3RyIDwtIHBhc3RlKCJodHRwczovL2IudGlsZS5vcGVuc3RyZWV0bWFwLm9yZy8iLHpvb20sIi8iLHh0aWxlLCIvIix5dGlsZSwiLnBuZyIsc2VwPSIiKQ0KYGBgDQogICBiLiBkYW5zIHVuIHNlY29uZCB0ZW1wcyB0w6lsw6ljaGFyZ2VvbnMgbCdpbWFnZQ0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KZG93bmxvYWQuZmlsZSh1cmxTdHIsIlJvY2hlYnJ1bmUucG5nIiwgbW9kZSA9ICJ3YiIsIHF1aWV0ID0gVFJVRSkNCmBgYA0KICAgYy4gZGFucyB1biB0cm9pc2nDqG1lIHRlbXBzIGltcG9ydG9ucyBsJ2ltYWdlIFBORyBkYW5zIFIgZXQgdHJhbnNmb3Jtb25zIGwnb2JqZXQgaW1wb3J0w6kgZW4gdHlwZSAqcmFzdGVyKg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShwbmcpDQpteVRpbGUgPC0gcmVhZFBORygiUm9jaGVicnVuZS5wbmciLCBuYXRpdmUgPSBGQUxTRSkNCm1hcGMgPC0gYXMucmFzdGVyKG15VGlsZSkNCmBgYA0KDQo0LiBDaGFuZ2VtZW50IGRlIGNsYXNzZSBldCBwcmVtaWVycyBhdHRyaWJ1dHMgZGVjbGFzc2UgZ2dtYXANCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmNsYXNzKG1hcGMpIDwtIGMoImdnbWFwIiwicmFzdGVyIikNCmF0dHIobWFwYywic291cmNlIikgPC0gIk9TTSINCmF0dHIobWFwYywibWFwdHlwZSIpIDwtICJ0ZXJyYWluIg0KYXR0cihtYXBjLCJ6b29tIikgPC0gem9vbQ0KYGBgDQoNCjUuIERlcm5pZXIgYXR0cmlidXQgZGUgbGEgY2xhc3NlIGdnbWFwOiBsYSBib3VuZGluZyBib3gsIGwnYXR0cmlidXQgKmJiKg0KICAgYS4gcHJvZ3JhbW1vbnMgdW5lIGZvbmN0aW9uIHBvdXIgY2FsY3VsZXIgbGEgbG9uZ2l0dWRlIGxhdGl0dWRlIGRlcHVpcyBsZXMgY29vcmRvbm7DqWVzIGRlIE1lcmNhdG9yDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpsb25sYXQgPC0gZnVuY3Rpb24oeCx5LHpvb20pIHsNCiAgICBsb24gPC0geC8yXnpvb20qMzYwLTE4MA0KICAgIGxhdCA8LSBhdGFuKHNpbmgocGkteS8oMl56b29tKSoyKnBpKSkqMTgwL3BpDQogICAgcmV0dXJuKGNiaW5kLmRhdGEuZnJhbWUobG9uPWxvbixsYXQ9bGF0KSkNCiAgICB9DQpgYGANCiAgYi4gbGVzIDQgYm9yZHMgZGUgbGEgdHVpbGVzIChlbiBjb29yZG9ubsOpZXMgZGUgTWVyY2F0b3IpIHNvbnQgb2J0ZW51cyBlbiBwYXJ0YW50IGR1IGJvcmQgKnh0aWxlKiAqeXRpbGUqIChlbiBiYXMgw6AgZ2F1Y2hlKSBldCBlbiBham91dGFudCAxIG91IHBhcw0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KaW50YmJ4IDwtIDA6MQ0KaW50YmJ5IDwtIDA6MQ0KYWpvdXRzIDwtIGV4cGFuZC5ncmlkKHh0aWxlK2ludGJieCx5dGlsZStpbnRiYnkpDQpgYGANCiAgYy4gZW4gdXRpbGlzYW50IGxhIGZvbmN0aW9uICpsb25sYXQqIHRyYW5zZm9ybW9ucyBsZXMgNCBib3JkcyBkZSBNZXJjYXRvciB2ZXJzIGxvbi9sYXQgZXQgY2FsY3Vsb25zIGxhIGJvdW5kaW5nIGJveCANCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZ2dtYXApDQptYWJiIDwtIG1ha2VfYmJveChsb24sbGF0LGxvbmxhdChham91dHNbLDFdLGFqb3V0c1ssMl0sem9vbSksZj0wKQ0KYGBgDQogIGQuIGFqdXN0b25zIGxlIHJlc3VsdGF0IGF1IGJvbiBmb3JtYXQ6IGRhdGEtZnJhbWUgYXZlYyBub21zIGFkZXF1YXRzIGRhbnMgbGUgYm9uIG9yZHJlIGV0IGxlIHRvdXQgZGV2aWVudCBsJ2F0dHJpYnV0ICpiYioNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCm1hYmIgPC0gZGF0YS5mcmFtZShtYXRyaXgobWFiYixucm93PTEpKQ0KbmFtZXMobWFiYikgPC0gYygibGwubG9uIiwibGwubGF0IiwidXIubG9uIiwidXIubGF0IikNCmF0dHIobWFwYywiYmIiKSA8LSBtYWJiWyxjKCJsbC5sYXQiLCJsbC5sb24iLCJ1ci5sYXQiLCJ1ci5sb24iKV0NCmBgYA0KNi4gVHJhY2UgZGUgbGEgdHVpbGUgcXVpIGVzdCBtYWludGVuYW50IGF1IGJvbiBmb3JtYXQNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmdnbWFwKG1hcGMpDQpgYGANCjcuIFBsdXNpZXVycyB0dWlsZXM6DQpMZSBkw6lwYXJ0IGVzdCBpZGVudGlxdWUNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmxvbiA8LSA2LjYxNTk4Mg0KbGF0IDwtIDQ1Ljg1MTYxDQp6b29tIDwtIDEzDQp4eCA8LSAobG9uKzE4MCkvMzYwICogMl56b29tDQp5eSA8LSAoMS0gbG9nKHRhbihsYXQqcGkvMTgwKSsxL2NvcyhsYXQqcGkvMTgwKSkgL3BpKSoyXih6b29tLTEpIA0KeHRpbGUgPC0gZmxvb3IoeHgpDQp5dGlsZSA8LSBmbG9vcih5eSkNCmBgYA0KTGUgdMOpbGVjaGFyZ2VtZW50IGRlIHBsdXNpZXVycyB0dWlsZXMgYXV0b3VyICgyIGNvdXJvbm5lcyBkJ2/DuSBsZSB2ZWN0ZXVycyBkZSAtMiDDoCArMikNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmludHRlbGV4IDwtIC0yOjINCmludHRlbGV5IDwtIC0yOjINCmFqb3V0cyA8LSBleHBhbmQuZ3JpZCh4dGlsZStpbnR0ZWxleCx5dGlsZStpbnR0ZWxleSkNCmJsb2NzIDwtIGV4cGFuZC5ncmlkKDE6NSwxOjUpDQpsaXN0ZVVybFN0ciA8LSBwYXN0ZSgiaHR0cHM6Ly9iLnRpbGUub3BlbnN0cmVldG1hcC5vcmcvIix6b29tLCIvIixham91dHNbLDFdLCIvIixham91dHNbLDJdLCIucG5nIixzZXA9IiIpDQpsaXN0ZURlc3QgPC0gcGFzdGUodGVtcGZpbGUoKSwxOm5yb3coYWpvdXRzKSxzZXA9IiIpDQppZiAoLlBsYXRmb3JtJE9TLnR5cGU9PSJ3aW5kb3dzIikgew0KICBmb3IgKGkgaW4gMTpsZW5ndGgobGlzdGVVcmxTdHIpKSB7DQogICAgZG93bmxvYWQuZmlsZShsaXN0ZVVybFN0cltpXSxsaXN0ZURlc3RbaV0sbWV0aG9kPSJ3aW5pbmV0Iixtb2RlPSJ3YiIscXVpZXQ9VFJVRSkgDQogIH0NCn0gZWxzZSB7DQpkb3dubG9hZC5maWxlKGxpc3RlVXJsU3RyLGxpc3RlRGVzdCxtZXRob2QgPSAibGliY3VybCIscXVpZXQ9VFJVRSkNCn0NCmBgYA0KDQoNCkwnYWdlbmNlbWVudCBkZSBjZXMgdHVpbGVzICgyNTZ4MjU2KSBlbiB1bmUgc2V1bGUgbWF0cmljZSAqcmFzdGVyKg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbWFwZiA8LSBtYXRyaXgoMCwyNTYqbGVuZ3RoKGludHRlbGV4KSwyNTYqbGVuZ3RoKGludHRlbGV5KSkNCmZvciAoaSBpbiAxOm5yb3coYWpvdXRzKSkgew0KICAgIG15VGlsZSA8LSByZWFkUE5HKGxpc3RlRGVzdFtpXSwgbmF0aXZlID0gRkFMU0UpDQogICAgIyMgcmFzdGVyDQogICAgbWFwYyA8LSBhcy5yYXN0ZXIobXlUaWxlKQ0KICAgICMjIGRlcG90IGRhbnMgbGEgbWF0cmljZQ0KICAgIG1hcGZbKChibG9jc1tpLDFdLTEpKjI1NisxKTooYmxvY3NbaSwxXSoyNTYpLA0KICAgICgoYmxvY3NbaSwyXS0xKSoyNTYrMSk6KGJsb2NzW2ksMl0qMjU2KV0gPC0gbWFwYw0KfQ0KYGBgDQoNCkxlcyBhdHRyaWJ1dHMgYmFzaXF1ZXMgZXQgbGEgY2xhc3NlICpnZ21hcCoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmNsYXNzKG1hcGYpIDwtIGMoImdnbWFwIiwicmFzdGVyIikNCmF0dHIobWFwZiwic291cmNlIikgPC0gIk9TTSINCmF0dHIobWFwZiwibWFwdHlwZSIpIDwtICJ0ZXJyYWluIg0KYXR0cihtYXBmLCJ6b29tIikgPC0gem9vbQ0KYGBgDQpMZSBjYWxjdWwgZGUgbGEgYm91bmRpbmcgYm94IChlbiByw6l1dGlsaXNhbnQgbGEgZm9uY3Rpb24gKmxvbmxhdCogZHUgNS5hKQ0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KaW50dGVsZXggPC0gLTI6Mw0KaW50dGVsZXkgPC0gLTI6Mw0KYWpvdXRzIDwtIGV4cGFuZC5ncmlkKHh0aWxlK2ludHRlbGV4LHl0aWxlK2ludHRlbGV5KQ0KbGlicmFyeShnZ21hcCkNCm1hYmIgPC0gbWFrZV9iYm94KGxvbixsYXQsbG9ubGF0KGFqb3V0c1ssMV0sYWpvdXRzWywyXSx6b29tKSkNCm1hYmIgPC0gZGF0YS5mcmFtZShtYXRyaXgobWFiYixucm93PTEpKQ0KbmFtZXMobWFiYikgPC0gYygibGwubG9uIiwibGwubGF0IiwidXIubG9uIiwidXIubGF0IikNCiMjIGF0dHJpYnV0IGJib3gNCmF0dHIobWFwZiwiYmIiKSA8LSBtYWJiWyxjKCJsbC5sYXQiLCJsbC5sb24iLCJ1ci5sYXQiLCJ1ci5sb24iKV0NCmBgYA0KTGUgZ3JhcGhpcXVlIGZpbmFsDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpnZ21hcChtYXBmKQ0KYGBgDQoNCg==