OpenRefine



Objectifs

  • Comprendre le fonctionnement du logiciel.
  • Importer et explorer un jeu de données.
  • Manipuler et transformer des données.
  • S’initier à l’usage du langage GREL et aux expressions régulières.





1. Préliminaires

Des données bien ordonnées commencent par soi-même!

  • Le nettoyage de fichiers de données est une tâche souvent longue et ennuyeuse mais incontournable avant toute analyse ou diffusion de données.

  • L’ampleur de cette tâche dépendra de l’état des données et du type de logiciel qui sera ensuite utilisé à des fins d’analyse ou de visualisation (R, SPSS, Stata, Tableau, ArcGIS…)


Problèmes courants relatifs à la forme et/ou au contenu d’un jeu de données:

  • Problèmes d’entêtes et de noms de variables.
  • Cellules fusionnées, qui contiennent différentes informations.
  • Variables qui ne sont pas clairement définies à la verticale.
  • Contenu textuel non structuré.
  • Problèmes de formats, de “petits caractères” -> séparateurs/délimiteurs de contenu et de colonnes, guillemets, encodage (’’ || | "" , . ; )
  • Présence de cellules vides, espaces…

A case study in messy data analysis: the Australian same-sex marriage survey



Avant d’utiliser un fichier de données dans son logiciel de choix, son nettoyage peut donc inclure de nombreuses tâches comme:

  • Modifier l’encodage.
  • Supprimer les doublons.
  • Diviser les cellules composées de valeurs multiples.
  • Recoder les valeurs manquantes.
  • Repérer les erreurs de saisie, les valeurs aberrantes…
  • Fusionner des fichiers.
  • Fusionner des colonnes.
  • Agréger des valeurs de variables.
  • Créer des variables.
  • Changer le format des variables.
  • Changer le format du fichier.
  • Transformer les colonnes en rangées (format “wide” en “long”).



2. Pourquoi OpenRefine?

  • Plusieurs langages de programmation et outils d’analyse ou de gestion de données peuvent être utilisés, mais OpenRefine a été créé spécifiquement pour faire le ménage.

  • Plus facile que R et plus efficace qu’Excel.

  • Permet de facilement identifier et de corriger en lot des données incomplètes, manquantes, erronées, incohérentes, non pertinentes, mal formatées, qu’elles soient numériques ou textuelles.


Fonctions spécialisées pour:

  • Explorer ses données sous tous ses angles (grâce à des filtres, tris, facettes, regroupements).
  • Nettoyer : repérer des erreurs, modifier le contenu des cellules…
  • Tranformer : changer formats de ses variables, créer de nouvelles variables sur la base des colonnes présentes…
  • Enrichir : fusionner des fichiers, importer des données en ligne (API, URLs), réconciliation (Wikidata et autres sources externes)…
  • Automatiser (réutiliser son historique de manipulations)


À noter

OpenRefine n’est pas un outil d’analyse ou de visualisation et ne permet pas de créer un jeu de données à partir de zéro. Ce n’est pas un outil de remplacement mais complémentaire.



2.1. Exemples d’utilisation

Harmoniser, standardiser, uniformiser…



2.2. Pour avoir de belles données tidy

Permet d’appliquer les principes du Tidydata

“Tidy datasets are all alike, but every messy dataset is messy in its own way.” –– Hadley Wickham


Trois principes de base:

  1. Chaque colonne est une variable.
  2. Chaque ligne est une observation.
  3. Chaque cellule à une seule valeur.



2.3. Principales caractéristiques

  • Logiciel gratuit et ouvert utilisé par une large communauté.

  • Créé en 2010 (Freebase Gridworks), racheté par Google en 2010 (Google Refine), puis ouverture du code en 2012 et repris par communauté qui le déplace sur Github et devient OpenRefine.

  • Multiplateformes: Windows, Mac, Linux.

  • Interface semblable à un tableur comme Excel, mais dont le fonctionnement s’apparente plus à une base de données (par exemple les traitements sont séparés des données, ie les formules ne sont pas enregistrées dans les cellules mais dans un script).

  • Associe la facilité d’usage d’un logiciel comme Excel à la puissance d’outils de programmation et d’algorithmes.

  • Usage de l’interface graphique et/ou de scripts GREL (Google Refine Expression Language) et d’expressions régulières: propose un ensemble de fonctions automatisées donc ne nécessite à la base aucune compétence en programmation, mais l’usage du langage permet d’aller beaucoup plus loin.

  • Particulièrement puissant pour le nettoyage de table de données avec du contenu textuel.

  • Reproductibilité! Permet de garder un historique de toutes les manipulations effectuées sur ses données afin de les partager, de les réutiliser sur d’autres données…



3. Installation et fonctionnement général

  • Le fonctionnement d’OpenRefine peut être un peu déroutant au départ car il n’y a pas d’installation en bonne et due forme comme pour un logiciel régulier.

  • Télécharger et dézipper le logiciel dans un dossier de son choix.

  • Créé en langage Java donc nécessite l’installation de Java (64 bits de préférence).

  • Navigateurs à privilégier: Chrome, Opera, Edge. Firefox peut poser problème (ne fonctionne pas dans IE).

  • Pour démarrer le logiciel, cliquer sur le fichier `openrefine.exe` ou refine.bat. Il est utile de faire un clic-droit sur le fichier .exe pour l’épingler dans sa barre de tâches (sur Mac, déplacer l’icône OpenRefine dans le dossier d’applications et double cliquer sur celle-ci).

  • Une fenêtre de commande noire s’ouvrira et lancera l’ouverture d’un onglet dans le navigateur web.

  • La fenêtre de commandes peut ensuite être ignorée mais NE PAS LA FERMER! Elle ne servira qu’à fermer la session de travail.

  • Si le navigateur ne s’ouvre pas automatiquement, saisir l’adresse http://127.0.0.1:3333/ ou http://localhost:3333 dans un onglet.



3.1. Travail local

  • Repose donc sur deux composantes: un serveur web local et un onglet de navigateur web pointant vers l’adresse du serveur sur son poste.

  • Le travail se fait dans un onglet de navigateur qui est une simple interface graphique pour interagir avec ce serveur local, mais les données ne sont pas sur le “nuage”.

  • Travail local donc pas d’environnement collaboratif.

  • Les fichiers programme se trouveront dans le dossier d’installation et les fichiers de projets dans le workspace directory.

  • OpenRefine ne modifie pas le fichier original, il travaille à partir d’une copie en mémoire stockée en archives dans le répertoire de travail.

  • Le projet est enregistré en format OpenRefine automatiquement dans le dossier de travail à toutes les 5 minutes (peut être modifié).

  • Le fichier de données une fois nettoyé pourra être exporté en différents formats et l’historique/syntaxe pourra être extrait en format JSON et enregistré dans un fichier .txt.

  • Pour fermer la session de travail correctement, faire Ctrl + c dans fenêtre de commande (peut être nécessaire de le faire plus d’une fois) = enregistre le projet et ferme le serveur.


À noter
- Permet de travailler sur de gros fichiers mais la taille possible est tout de même limitée, la performance peut devenir problématique à plusieurs centaines de milliers de lignes (tout dépendant du nombre de colonnes) donc pas vraiment développé pour faire du big data. - Travaille avec 1Go de mémoire par défaut. À plus de 100 000 lignes, il peut être préférable d’augmenter la mémoire de travail:
- Ouvrir le fichier refine.ini dans notepad et modifier la ligne REFINE_MEMORY = parametre.
- Par la suite lancer OR avec le fichier refine.bat et non openrefine.exe .



3.2. Écran d’accueil

  • À partir du menu de gauche, il est possible de Créer un projet, Ouvrir un projet (historique des projets enregistrés) ou Importer un projet (archives .zip se trouvant dans le dossier de travail).

  • Pour changer la langue de l’interface au français, cliquer sur l’onglet Langue dans le menu de gauche.

  • Le fichier peut être créé à partir de différentes sources: Cet ordinateur (poste local), Adresses web (URLs), Presse-papier (copié-collé), Google data (Google sheets)…) et en différents formats (.csv, .txt, .xml, .xls, .JSON, .zip… (certaines extensions permettent l’usage d’autres formats comme rdf).

  • Deux fichiers ou plus peuvent être importés en même temps. Les lignes seront importées une à la suite de l’autre selon l’ordre d’importation (une colonne permettant d’identifier le fichier source sera créée automatiquement).



3.3. Historique des projets

  • L’onglet Ouvrir un projet permet:
    • D’accéder et d’ouvrir tous les projets enregistrés localement.
    • D’éditer ses métadonnées (lien Détails).
    • D’accéder au dossier de travail (défini par défaut) où OpenRefine stocke les archives des projets enregistrés par le biais du lien Parcourir le dossier de l'espace de travail.



4. Créer un projet

  • Pour ouvrir un fichier à partir de son poste, cliquer sur Créer un projet - > Cet ordinateur - > sélectionner fichiers sur son poste -> Suivant.

  • Une fenêtre s’ouvre ensuite pour permettre de pré-visualiser son jeu de données et de modifier, si nécessaire, les options d’importation en fonction des caractéristiques du fichier de données: modification du format de fichier s’il n’a pas été identifié correctement [5], l’encodage des caractères [UTF-8] [6], le traitement des entêtes et premières lignes [9]…


Exercice

  • Créer un nouveau projet en important un fichier à partir de son emplacement sur Github: https://github.com/CRLNP/openrefine

    • Cliquer sur le fichier Incidents métro-mtl.csv -> Cliquer sur le bouton RAW -> copier l’adresse du navigateur.
    • Dans OpenRefine, Créer un projet -> Adresses web (URLs) -> coller le lien -> Suivant. (Le fichier est aussi disponible sur le site Données ouvertes Montréal).
  • Explorer les options d’importation -> Porter une attention particulière aux options: Supprimer les espaces (8 -> cocher), Utiliser le caractère " ... (10 -> cocher), Analyser le texte des cellules comme nombres , dates… (11 -> décocher)

  • Changer le Nom du projet [2] et cliquer sur Créer un projet [4] - En cas de problème, il est possible de recommencer le processus [1].



5. Explorer l’interface

  • L’interface est similaire à Excel mais on ne peut voir l’ensemble des lignes, la “logique” d’OpenRefine repose sur le travail en colonnes.

[1] Lien sous l’icône renvoi vers la page d’accueil/importation.
[2] Renommer le nom de son projet en tout temps.
[3] Permalien qui permet de revenir à une vue précise (affichage, tri, facettes…) du projet.
[4] Nombre de lignes/observations du fichier.
[5] Changement du mode lignes ou observations.
[6] Modifier le nombre de lignes affichées.
[7] Passer d’une page à l’autre.
[8] Ouvrir un nouvel onglet OpenRefine.
[9] Exporter le fichier en différents formats.



5.1 Deux vues des données

  • OpenRefine propose deux vues des données: lignes et entrées. Les données sont généralement présentées en mode lignes, c’est-à-dire chaque ligne représente une observation. Le mode entrées permet d’associer plusieurs lignes à une observation.

  • Il est donc possible de modifier la structure du fichier pour que plusieurs lignes soient associées à un seul cas en se basant sur la colonne clé (seule la ligne originale sera numérotée), mais doit se faire avec précautions. Pour les logiciels d’analyse, le format tidy (lignes) est à privilégier.


5.2. L’édition de cellules

  • Il est possible d’éditer manuellement le contenu de cellules individuelles en se plaçant sur chacune et en cliquant edit, mais OpenRefine privilégie le travail en lot par colonnes pour filtrer, trier, transformer.

  • L’édition directe peut s’appliquer individuellement ou sur toutes les cellules avec la même valeur dans cette colonne.

  • Permet également de modifier le format de la cellule.

Exercice

  • Dans la colonne Cause primaire cliquer dans une cellule Autres, éditer son contenu pour autre et appliquer à la cellule.

  • Dans la colonne Évacuation, modifier le contenu d’une cellule “#” par Non et appliquer à toutes les cellules identiques.



5.3. Format des données

  • À l’importation d’un fichier, chaque cellule se verra attribuer un format.
  • Par défaut, le contenu des cellules est de format chaînes.
  • Le contenu des cellules reconnu comme numérique et date sera de couleur verte.
  • Le format peut être modifié de différentes façons: edit, Transformations courantes, Fenêtre GREL.
  • Ce format aura un impact sur les actions possibles.

Trois formats de base:

  1. Chaîne de caractères
  2. Nombre
  3. Date (norme ISO-8601 YYYY-MM-DDTHH:MM:SSZ)*

Deux formats découlant d’actions:

  • Erreur (format attribué suite à une erreur de transformation)
  • Null**

Deux autres types particuliers découlant de manipulations

  • Booléen (valeur binaire T ou F)
  • Array (liste de valeurs séparées par une virgule entre crochets pouvant être transformées)


* Format date
  • Selon les besoins, les dates peuvent être traitées sous forme de texte, de nombre ou date (le format date est surtout nécessaire pour les calculs de dates).
  • Le format date repose sur une série d’outils et de standards pour reconnaitre et convertir les valeurs originales en date.
  • Pour qu’une cellule soit reconnue comme date, elle sera transformée au format ISO-8601-compliant.
  • Possible de modifier ce format pour qu’il soit plus facilement lisible à l’exportation.
** Format “manquant”
  • OpenRefine fait une distinction entre les cellules vides avec espaces blancs (qui ne sont pas vides!), les valeurs vides (chaine de longueur 0), et les valeurs “null” (type spécial qui n’est pas une chaine de caractères). Les vides et les null sont aussi considérés comme Blank.
  • Plusieurs fonctions automatisées sous Facettes et Éditer les cellules permettent de gérer ces types de valeurs.


Exercice

Transformer une colonne de format caractère en format date:
- Dans la colonne Jour calendaire: Menu -> Éditer les cellules -> Transformations courantes -> En date

Transformer une colonne de format caractère en format nombre:
- Dans la colonne Porte, cliquer dans une cellule, éditer le format à Nombre et appliquer à toutes les cellules identiques. - Recommencer la procédure avec le fonction Transformations courantes.


  • Le changement de format par édition directe d’une cellule est une opération distincte de la transformation du contenu. La première opération arrive parfois à changer des formats que la transformation ne peut faire. Pour plus d’information sur les formats, voir la documentation officielle.



5.4. La gestion des lignes et colonnes

La gestion des colonnes peut se faire:

  • Sur chaque colonne:
    • Fonctions sous Éditer la colonne -> Déplacer ... / Renommer / Supprimer
    • Fonctions sous Aperçu -> Masquer...
  • Sur la colonne Toutes:
    • Éditer les colonnes -> Retrier-supprimer, gestion des valeurs consécutives
    • Aperçu -> Afficher-masquer


La gestion des lignes:

  • La sélection de lignes peut se faire par le biais de filtres, facettes et autres manipulations personnalisées.
  • Il est aussi possible de marquer/étoiler des lignes en lot ou individuellement puis de créer une facette sur la colonne Toutes pour sélectionner les lignes marquées (true).
  • On peut ensuite supprimer les lignes filtrées: Toutes -> Éditer les lignes -> Supprimer les lignes correspondantes.


Exercice

Supprimer une colonne:
- Sur la colonne Type d’incident -> Éditer la colonne -> Supprimer cette colonne.

Supprimer plusieurs colonnes:
- Sur la colonne Toutes -> Éditer la colonne -> Éditer/Supprimer les colonnes -> KFS et CAT.


5.5. Historique (Undo/Redo)

  • Toutes les actions sont enregistrées (log de ses manipulations) et peuvent être annulées en reculant étape par étape dans l’historique.
  • La première action d’un historique est la création du projet.
  • Puisque l’historique fait partie du projet enregistré dans le dossier de travail, il ne disparait pas à la fermeture de la session.
  • L’historique peut être extrait en format JSON, copier/coller dans notepad et appliquer de nouveau.

Attention!

  • Si on recule dans le temps et qu’on fait une modification, les étapes qui suivent dans l’historique disparaissent pour de bon.

  • Les manipulations relatives à l’affichage ne sont pas enregistrées dans l’historique, seulement les transformations. L’enregistrement automatique ne comprend donc pas les facettes et filtres (vue de l’interface) - perd ce qui n’apparait pas dans le Défaire/Refaire.

  • L’édition directe dans les cellules apparait dans l’historique mais ne peut être exportée.

  • Facettes et filtres s’enregistrent grâce au permalien.



7. Les facettes

7.1 Caractéristiques

  • Les facettes constituent la marque de commerce d’OpenRefine, d’où le logo!

  • Fonctionnalité puissante qui permet d’explorer et de filtrer ses données en fonction de différentes conditions.

  • N’affectent pas directement les données, seulement la présentation.

  • À la base, une facette correspond à la liste des valeurs possibles d’une variable (et de leur occurrence) présentée selon le format (chaine, numérique, date).

  • Permettent une exploration et manipulation des valeurs possibles et de leurs cas correspondants plus élaborées que les filtres.

  • On peut ainsi identifier les tendances, les régularités, les erreurs, les écarts, les répétitions et cibler les valeurs de sous-groupes précis.

  • Ces sous-groupes peuvent ensuite être édités et exportés (bouton Exporter en haut à droite).


Types de facettes:

  • Les facettes automatisées [1].

  • Les facettes personnalisées [2].

  • Il est aussi possible de créer ses propres facettes grâce au langage GREL pour définir des conditions de sélection/filtre très précises [3] (on parle encore ici de facettes personnalisées, mais elles doivent être rédigées manuellement).


  • [8] Le lien changer permet d’ouvrir une fenêtre d’édition GREL pour modifier la syntaxe de la facette.
  • [9] Pour supprimer les facettes, cliquer sur le x de chaque fenêtre ou Tout supprimer.
  • Pour conserver les fenêtres mais supprimer les sélections qui y ont été faites, cliquer sur réintialiser sur chaque fenêtre ou Tout réinitialiser [9].
  • [10] Option Groupe: Outils proposant différents algorithmes de similarité permettant de regrouper des catégories semblables.

Formats de facettes:

On retrouve également différents formats de facettes -> une pour chaque format de données (Les facettes personnalisées proposent aussi des facettes booléennes).

1. Facette textuelle [4-5]

  • Type de facette le plus souvent utilisé.
  • Regroupent dans la fenêtre de gauche les valeurs distinctes (textuelles ou numériques) des colonnes voulues.
    • On peut faire une facette textuelle sur une colonne numérique mais pas l’inverse.
    • 2000 valeurs maximum par défaut mais peut être modifié dans les préférences. Si les valeurs sont trop nombreuses, elles ne seront pas listées (un filtre pourrait être utilisé).
  • Permettent de combiner différents filtres en sélectionnant différentes valeurs d’une ou plusieurs variables (et leurs cas correspondants).
    • Cliquer inclure ou exclure pour sélectionner ou supprimer des choix multiples [12].
    • Une fois la sélection faite, l’option inverser permet de sélectionner tout SAUF la sélection [11].
    • Peuvent être triées selon le nom ou le compte (nombre d’occurrences).
  • Permettent d’éditer les valeurs (contenu de chaque cellule correspondante) [13].

2. Facette numérique [7]

  • Visualiser et sélectionner les valeurs d’une variable numérique allant de la plus petite à la plus grande.

3. Facette chronologique [6]

  • Visualiser et sélectionner les valeurs d’une colonne date en ligne du temps.


Exercice

Filtrer

  • Explorer les valeurs de la variable Cause primaire. Quelle est la deuxième plus fréquente?
  • Quelles sont les catégories de Cause secondaire reliées à la Cause primaire “Clientèle”?
  • Quelle est la plus fréquente? Sélectionner cette valeur. Combien de cas correspondent à cette sélection?
  • À quel jour de la semaine cette cause est-elle survenue le plus souvent?2
  • Réinitialiser toutes les facettes.

Éditer

  • Dans la facette Cause primaire, renommer la valeur “autre” pour qu’elle soit fusionnée à la valeur “Autres”.
  • Supprimer toutes les facettes.


Filtrer

  • Quel est le symptome le plus fréquent? Sélectionner cette valeur.
  • Ces événements ont-ils nécessité une évacuation?3

Éditer

  • Éditer la variable évacuation de façon à ce qu’il n’y ait que deux valeurs possibles: Oui et Non.

7.2. Les regroupements (clustering)

  • Fonction qui permet d’identifier dans une colonne les valeurs distinctes qui pourraient avoir la même signification ou qui pourraient être regroupées dans une même catégorie = “variations sur le même thème” évaluées en fonction de différents algorithmes.

  • Chaque suggestion doit être approuvée individuellement pour que les modifications s’appliquent (les regroupements proposés ne sont pas nécessairement pertinents).

  • OpenRefine propose des clusters selon différentes méthodes plus ou moins élaborées (Proche voisin prend plus de mémoire) qui permettent de regrouper les valeurs similaires et proposent des matchs possibles (fuzzy matching): par exemple empreinte est plus conservateur (distingue casse, espaces, ordre, répétition, ponctuation…), ngram est plus flexible (mêmes caractères), Metaphone3 est le plus “libéral” (même prononciation).

Exercice

  • Créer une facette textuelle sur la colonne Code de lieu.
  • Cliquer sur Groupe et explorer les regroupements en fonction des différents algorithmes.

7.3. Les facettes personnalisées

  • Fonctionnent comme des facettes automatisées sauf qu’on ne peut éditer en fonction de ces résultats car elles présentent des données modifiées en mémoire.

  • Ont été développées et automatisées afin d’explorer des aspects précis des données sans avoir à les rédiger en syntaxe GREL:

    • Facette par mot : Divise chaque mot (séparé d’un espace) d’une colonne et les présente en liste de valeurs distinctes [value.split(" ")].

    • Facette doublons: valeurs booléennes indiquant si les valeurs sont uniques (false) ou non (true) [facetCount(value, ‘value’, ‘Symptome’) > 1].

    • Facettes logarithmiques: modification logarithmique de valeurs numériques [value.log()].

    • Facette longueur de texte: liste le nombre de caractères du contenu des cellules d’une colonne [value.length()].

    • Facettes permettant d’explorer les valeurs d’erreur, nulles, vides… [isEmptyString(value)]


8. Transformations

  • OpenRefine permet d’explorer mais aussi de modifier ses données sans avoir à toucher au contenu de cellules manuellement.

  • Comme pour les facettes, les fonctions de transformation peuvent se faire de deux façons:

    1. Transformations automatisées (Transformations courantes) [2]: fonctions permettant d’appliquer des modifications courantes sur le format et la structure des cellules/colonnes.

    2. Transformations manuelles dans la fenêtre GREL [1] afin d’aller beaucoup plus loin.

Pour voir la syntaxe correspondant à chaque fonction de transformations courantes, appliquer la fonction sur une colonne puis aller voir l’historique. Par exemple: value.toNumber(), value.toTitlecase(), value.toNumber(), value.toUppercase(), value.trim()

8.1. Diviser le contenu de cellules multivariées

  • Deux options:
    1. En divisant le contenu des cellules en plusieurs colonnes: Éditer la colonne -> Diviser en plusieurs colonnes
    2. En divisant le contenu sur plusieurs lignes: Éditer les cellules -> Diviser les cellules multivariées


  • La première option est la plus fréquente.
  • La deuxième option aura un effet important sur la structure des observations puisqu’elle multipliera le nombre de lignes par cas (ce qui nécessitera de passer à la vue par entrées).

Exercice

Uniformiser et diviser le contenu de la variable Ligne

Uniformiser le nom des lignes:

  • Créer une facette sur la colonne Ligne.

  • Deux problèmes se posent: 1) les noms de lignes non uniformes et 2) les valeurs multiples.

  • Nous choisissons d’uniformiser les valeurs en utilisant les numéros de lignes et en supprimant le mot Ligne.

  • Explorer et accepter les regroupements proposés avec la fonction Groupe.

  • Supprimer le mot ligne:

    • Éditer les cellules -> remplacer -> “Ligne” par: ne rien saisir dans l’encadré.
  • Cliquer ensuite directement sur edit sur une cellule de la colonne de Ligne -> remarquer la présence d’un espace, supprimer l’espace et fermer.

  • Rafraichir la facette et observer l’impact - les espaces peuvent être supprimés grâce à la fonction: Éditer les cellules -> Transformations courantes -> Supprimer les espaces de début et de fin.

  • Remplacer les couleurs de ligne par leur numéro directement dans la facette.

Diviser le contenu des cellules en créant des colonnes avec une seule valeur

  • Dans la facette, remplacer les “-” par des “,”.

  • Éditer la colonne -> Diviser en plusieurs colonnes:

    • Définir le séparateur “,” (celui-ci disparaitra).
    • Décocher les options “Deviner” et “Supprimer”.
  • Les nouvelles colonnes reprendront le nom de l’original numéroté. Les renommer: premiere, deuxieme, troisieme, quatrieme.


Diviser par les longueurs de champs la colonne Numéro d’incident pour en créer deux nouvelles:
1. Une colonne contenant le premier caractère indiquant le type d’incident, soit T (train) ou S (service).
2. Une colonne contenant l’ensemble des caractères numériques indiquant le numéro d’incident.

Vérifications préalables: 1. Vérifier qu’il n’y a pas de doublon dans cette colonne: Facettes personnalisées -> Facette doublon -> Quel est le problème? Cliquer sur Changer et analyser l’expression.
2. Vérifier la longueur de chaque cas: Facettes personnalisées -> Facette longueur du texte.

Diviser la colonne:
- Éditer la colonne -> Diviser en plusieurs colonnes selon les longueurs de champs : 1, 8.
- Décocher : deviner le type de cellule et Supprimer cette colonne.
- Renommer les colonnes : Type et ID.



8.2. Fusionner le contenu de plusieurs colonnes

Exercice

Nous souhaitons calculer la durée des incidents (nécessite l’utilisation de GREL). Pour ce faire nous créerons deux colonnes pour ensuite calculer la différence entre les deux:
- Transformation simple automatisée: Créer une nouvelle colonne fusionnant les colonnes: Année civile, Mois calendrier, jours du mois et Heure de l’incident.
- Transformation avancée GREL (peut être réalisée de façon automatisée): Créer une nouvelle colonne fusionnant les colonnes: Année civile, Mois calendrier, jours du mois et Heure de l’incident.


Lorsque l’on fusionne des colonnes, il faut porter une attention particulière au séparateur choisi. Ne pas utiliser un caractère qui pourrait faire partie du contenu (ex: ,) ou qui servira à diviser les colonnes (.csv)


  1. Fonction automatisée -> Fusionner les colonnes: Année civile, Mois calendrier, jours du mois et Heure de l’incident
  • Année civile -> Éditer la colonne -> Joindre les colonnes.

  • Joindre des colonnes -> Cocher les colonnes voulues et les trier selon l’ordre voulu dans la nouvelle valeur.

  • Séparateur entre le contenu de chaque colonne: “-”.

  • Écrire le résultat dans une nouvelle colonne nommée: Date.

  • Transformer en format date: Éditer les cellules -> Transformations courantes -> En date.


  1. Fenêtre GREL -> Fusionner les colonnes: Année civile, Mois calendrier, jours du mois et Heure de reprise
  • Année civile -> Éditer la colonne -> Ajouter une colonne en fonction de cette colonne:

cells["Année civile"].value + "-" + "0" + cells["Mois calendrier"].value + "-" + "0" + cells["Jour du mois"].value + " " + cells["Heure de l'incident"].value.

  • Vérifier la transformation avec une facette value.type().

  • Recommencer la jointure pour créer une colonne avec la date-heure de fin de l’incident cells["Année civile"].value + "-" + "0" + cells["Mois calendrier"].value + "-" + "0" + cells["Jour du mois"].value + " " + cells["Heure de l'incident"].value.

  • Transformer en format date: Éditer les cellules -> Transformations courantes -> En date.


Calculer la durée de l’incident

  • Créer une nouvelle colonne vide:
    Éditer la colonne > Ajouter une colonne en fonction de cette colonne -> Choisir un nouveau nom et le contenu: "".

  • Pour calculer une différence entre date: diff(date1, date2, "results format").

diff(cells['date2'].value,cells['date1'].value, 'minutes').



9. Le langage GREL

  • Google Refine Expression Language
  • Langage similaire à javascript et formules excel.
  • Permet la rédaction d’expressions visant à manipuler/transformer le contenu des cellules d’une colonne.
    (Voir la documentation officielle pour plus de détails)
  • Langage composé de fonctions et d’objets.


9.1. GREL - Principes de base

Utilise une syntaxe particulière pour cibler les objets (variables):

  • Contenu de colonne actuelle: value.
  • Contenu d’une autre colonne: cells['nom-colonne'].value.
  • Contenu textuel: “guillemet simple ou double”.


Deux formats de notation:

  • Imbriquée: (trim(toLowercase(value)).
  • Séquentielle: value.toLowercase().trim() (plus facile à lire).


Différents types de fonctions:


Différents types d’opérateurs:

Selon le format, différents types d’opérateurs peuvent être utilisés entre les valeurs:
- Opérateurs arithmétiques: +, -, *, /
- Opérateurs de comparaison: ==, >, <

Par exemple:

  • Le “+” entre deux contenus numériques = somme

  • Le “+” avec un contenu textuel = concaténation



9.2. GREL - L’indexation, la sélection et la manipulation d’éléments:

  • Chaque caractère composant la valeur d’une cellule est ordonné dans un index à partir de 0 (1er élément).
  • Chaque élément d’un array est ordonné dans un index à partir de 0 (1er élément) et peut être ciblé grâce aux [ ].
  • L’opérateur [ ] permet de cibler/sélectionner des chaines de caractères ou des sous-éléments spécifiques.


Exemple - Fonction split()

value[0,8] -> Montréal (Québec) = ?
value.split("(")[1] -> Montréal (Québec) = ?
value.split("(")[1].split(")")[0] -> Montréal (Québec) = ?
value[0] + value[3] + value[7] -> Montréal (Québec) = ?4


Exercice - Fonction replace()

ISBN: 978-2-13-082930-0

Conserver seulement le chiffre de l’ISBN sans les traits d’union?5

Indices :

  • Deux façons de faire: value[] OU value.split()
  • replace() (il faut remplacer “quelque chose”, “par le vide”)


Exemple - Fonction slice()

Martinolli, Pascal; Gabrielli, Nino; Fortier, Catherine; Bellemare, Pascale

Éditer les cellules -> Transformer -> value.split("; ").slice(1).join("\n")

  • split(): diviser la cellule en éléments distincts sur la base du séparateur ;
  • slice() : conserver les éléments à partir de l’élément 1 donc supprime le 0.
  • join(): joindre avec le séparateur ;


Exercice - Fonction sort()

Mettre les noms en ordre alphabétique et les joindre avec une virgule.6

Indices:

  • split(): diviser la cellule en éléments distincts sur la base du séparateur

  • sort(): trier les éléments (reste vide)

  • join(): joindre avec le séparateur


Exemple - Fonction reverse()

Éditer les cellules -> Transformer -> value.split("; ")[1].split(", ").reverse().join(" ") + " è fantastico!"

  • split(): divise la cellule en éléments distincts sur la base du séparateur ; et retient le deuxième élément
  • split(): divise cet élément sur le séparateur ,
  • reverse(): inverse l’ordre des deux éléments
  • join(): rattache les deux éléments divisé avec un espace



9.3. Créer des facettes avec GREL

Exercices

Créer une facette pour lister les cas selon l’heure de l’incident seulement, sans les minutes (2 premiers caractères). Comment faire afficher les minutes seulement?7

value[0,2]


Créer une facette sur la colonne Code de lieu pour identifier les cas dont la valeur commence par “Côte”

value.startsWith(“Côte”)


Créer une facette pour identifier les cas dont la valeur dans la colonne Cause primaire est la même que dans la colonne Cause secondaire

value == cells["Cause secondaire"].value



9.4. Rechercher/remplacer un caractère dans toutes les colonnes avec GREL

Exercice

Remplacer les valeurs “#” dans toute la base de données par “aucun”**

  • Quel problème ce remplacement peut-il provoquer?
  • Explorer l’impact des trois expressions de remplacement suivantes:
  1. value.replace("#", "aucun")
    (remplace le caractère #: aucun et aucunN/D )

  2. if(value.contains("#"),"aucun", value)
    (remplace les cellules des # et #ND par aucun)

  3. if(value==("#"),"aucun", value)
    (remplace seulement les cellules #, pas les #ND par aucun)



9.5. Créer et copier des colonnes


Éditer la colonne -> Ajouter une colonne en fonction de cette colonne

Exercice

Créer une nouvelle colonne sur la base de la colonne Jour de la semaine indiquant si le jour est en semaine ou fin de semaine.

if(value > 5,"fin de semaine","semaine")


Créer une colonne à partir de la colonne heure de l’incident en ne conservant que l’heure, sans les minutes, et rajouter la lettre h pour donner par exemple ceci: 15:12 -> 15h.

value.split(':')[0] + "h".

Ou

value.splitByLengths(2)[0] + "h".



10. Les expressions régulières

10.1. Caractéristiques

  • L’usage de GREL permet des manipulations de données beaucoup plus avancées que l’utilisation des fonctions automatisées, mais OpenRefine permet en plus de combiner l’utilisation des expressions régulières avec GREL pour en augmenter la puissance.
  • Les expressions régulières permettent, à partir d’une syntaxe spécifique, d’identifier des patterns dans un contenu.
  • Lorsqu’utilisées avec GREL, ces expressions permettent donc d’identifier et d’extraire des contenus très précis pour ensuite les manipuler selon les besoins.
  • Elles peuvent être utilisées à différents endroits dans OpenRefine et doivent toujours être entourées de / /: filtres, facettes, fenêtre GREL.
  • Certaines expressions peuvent s’écrire en GREL avec ou sans regex.
  • Les fonctions GREL qui acceptent les expressions régulières: replace, match, partition, rpartition, split.


  • Mais certaines fonctions (comme match) n’acceptent que ces expressions.

Les expressions régulières peuvent être utilisées avec plusieurs autres langages dont R et Python et dans des logiciels qui n’ont rien à voir avec les statistiques comme OpenOffice.

Pour en savoir plus:
- https://github.com/OpenRefine/OpenRefine/wiki/Understanding-Regular-Expressions
- https://regex101.com/



10.2. La syntaxe de base:

La syntaxe est composée d’éléments permettant de cibler des caractères précis et de définir leur emplacement et leur occurrence.

TYPES DE CARACTÈRES QUANTIFICATEURS ET EMPLACEMENT
. : N’importe quoi + : 1 ou plus
\w : n’importe quel mot, chiffre ou _ (\W : sauf) | * : 0 ou plus
\d : Chiffres (\D : sauf) ? : 0 ou un
\s : Espaces (\S : sauf) {2} : Nombre exact (ici 2)
[A-Z] : Majuscules ([^A-Z] : sauf) {,4} : Entre 0 et 4 incl.
[a-z] : Minuscules ([^a-z] : sauf) {4,} : 4 ou plus
[abd;] : les lettres a, b, c, d et le ; {1;3} : 1 OU 3
abcd : une ou plusieurs lettres exactes {1,3} : Entre 1 et 3 incl.
| : Ou
^ : Début d’une ligne
() : Grouper un contenu et le garder en mémoire
$ : Fin d’une ligne ou rappeler un groupe
\ : Chercher un caractère spécial littéralement Sans quantificateur, l’occurrence est de 1
Par exemple, je cherche un contenu correspondant au motif:

^\d{4} +[A-Z]\.

  • débute par 4 chiffres
  • suivi d’un espace ou plus
  • suivi d’une lettre majuscule avec un point


Autres exemples avec la syntaxe OpenRefine:
  • value.find(/[Cc]aroline/): Caroline et caroline

  • value.find(/ca+roline/): caroline et caaaaroline

  • value.find(/ca*roline/): caroline, caaaroline et croline

  • value.find(/ca?roline/): caroline et croline mais pas caaaroline

  • value.find(/ca{4}roline/): caaaaroline

  • value.find(/^Carol\b/): Carol en début d’expression, mais pas Caroline ( “boundary”)

  • value.find(/c[a-z]{6}e/): c + 6 minuscules + e

  • value.find(/C[a-zA-Z0-9]{6}e/): C + 6 minuscules, majuscules ou chiffres + e

  • value.find(/C\w{6}e/): C + [A-Za-z0-9_] + e

  • value.find(/C.{6}e/): C + 6 n’importe quoi + e


Exercice

Manipuler les éléments de références bibliographiques

  1. Aller sur le guide APA.

  2. Copier les deux références de Lemaire et Lebovici au point 2.1.

  3. Dans OpenRefine, cliquer sur le petit logo en haut à gauche -> Créer un projet -> Presse-papier: Coller les deux références en ajoutant un séparateur “;” à la fin de la première -> Suivant.

  4. Modifier les options:

  • Les colonnes sont séparées par - personnalisé “;”.
  • Décocher “Analyser la ou les 1 ligne(s) suivante(s) comme des entêtes de colonnes”.
  1. Créer projet.


  1. Éditer la colonne -> Ajouter une colonne en fonction de cette colonne

  2. Examiner l’impact de ces deux commandes GREL + regex. Qu’est-ce qui se passe?

  • Éditer les cellules -> Transformer:

value.find(/\(.*?\)/)

value.find(/\(.*?\)/).join(',').replace("("," ").replace(")", "")

-> Attention aux quantificateurs “gourmands” (vs paresseux).


Éditer la colonne -> Ajouter une colonne en fonction de cette colonne:

  • Créer la colonne Auteur : value.partition("(")[0] ou value.split("(")[0]
  • Créer la colonne Année: value.partition("(")[2].partition(")")[0] ou avec regex: value.match(/.*?(\d{4}).*?/)[0].
  • Créer la colonne titre: value.partition(").")[2].partition("(")[0].
  • Créer la colonne éditeur: value.partition(").")[2].partition(").")[2].
  • Créer la colonne édition: value.partition(").")[2].partition("(")[2].partition("éd")[0] ou avec regex: value.match(/.*(\d+). éd.*/)[0].
  • Créer la colonne volume: value.partition("vol.")[2].partition(")")[0] ou avec regex: value.match(/.*vol. (\d+).*/)[0].
    Mais encore avec regex:
  • Supprimer les lettres du prénom: value.replace(/(\s[A-Z].\s)|(\s[A-Z].,\s)/, " ").
  • Supprimer tout le contenu sauf les noms de famille: value.replace(/(\s[A-Z].\s)|(\s[A-Z].,\s)|(et)|(,)/, " ").



11. Transposition

Exercice: transposer un tableau d’indicateurs du WDI


Fichier original téléchargé de la Banque mondiale en format .csv composé de 5 pays et 4 indicateurs à l’horizontale et 3 années à la verticale

  • Pour ouvrir le fichier à partir de son emplacement sur Github: https://github.com/CRLNP/openrefine
    • Cliquer sur le fichier WDI_Data_Extract.csv -> Cliquer sur le bouton RAW -> copier l’adresse du navigateur.
    • Dans OpenRefine, Créer un projet -> Adresses web (URLs) -> coller le lien.


1. Transposer les dates à l’horizontale (format long)


Éditer les cellules -> Transposer -> Transposer les cellules de plusieurs colonnes en lignes…




2. Remplir automatiquement les cellules vides des deux colonnes à la verticale

Éditer les cellules -> Recopier les valeurs dans les cellules vides consécutives


3. Transposer les indicateurs en variables à la verticale

Transposer -> Convertir en liste les colonnes de clé/valeur…





12. Exporter un fichier et fermer OpenRefine

  • Fonction à utiliser lorsque l’on est prêt à exporter son fichier en différents formats pour travailler dans un autre logiciel (.csv, .xls…)
  • OR sauvegarde automatiquement les fichiers sous forme d’archives de projet dans un dossier sur le poste de travail auxquelles on peut accéder en cliquant sur Ouvrir un projet sur la page principale.
  • L’outil Exporteur tabulaire personnalisé est très utile pour paramétrer l’exportation (sélection de colonnes, format de dates, format de fichier…)
  • Fermer l’onglet ne ferme pas le serveur qui continuera à rouler en arrière-plan.
  • Aller à la fenêtre noire du terminal et utiliser les touches CTRL + C jusqu’à ce qu’elle se ferme d’elle-même (il est parfois nécessaire de répéter à plus d’une reprise). Le fichier sera enregistré une dernière fois et le logiciel sera maintenant bel et bien fermé.



13. Quelques recettes pour faire durer le plaisir

Extraire seulement certains caractères selon leur position

Extraire seulement les caractères de 5 à 7

  • value[5, 7]

Extraire les caractères à partir de 5

  • value.substring(5)


Savoir si une condition est vraie ou fausse?

Est-ce que le contenu des valeurs correspond à “2019-01-01”

  • value==“2019-01-01”


Connaître la longueur des valeurs d’une colonne

  • value.length()


Compter le nombre de mots dans des cellules (séparés par des espaces)

  • value.split(" ").length() ou value.split(//).length()


Calcul d’un pourcentage arrondi (ex d’un résultat sur 10)

  • round((value*100) / 10)


Transformer un format date en format texte plus lisible

  • value.toString(“dd MMMM yyyy”)


La création et manipulation de listes (array) - Diviser le contenu de cellules

Diviser le contenu de cellules en fonction d’un séparateur pour ne conserver que le premier élément

  • value.split(" ")[0]

Diviser le contenu d’une cellule pour le réordonner

  • value.split(“,”).reverse().join(“,”)

  • value.split(“,”).sort().join(“,”)

Diviser après les 3 premiers caractères et conserver le premier élément

  • value.splitByLengths(3)[0]

Diviser selon le type de caractères et retenir le deuxième élément

  • value.splitByCharType()[1]

Diviser le contenu d’une cellule sur un terme x et conserver le contenu précédent

  • value.partition(“terme”)[0]

  • value.partition(" to “)[2].partition(” on ")[0]


Inverser le contenu d’une cellule

Diviser le contenu d’une cellule et inverser l’ordre de présentation en ajoutant une virgule entre les deux

  • value.split(’ ‘)[1] + “,” + " " + value.split(’ ’)[0]

OU

  • value.match(/(.),(.)/).reverse().join(" ")


Ajouter un zéro pour avoir un nombre de caractères précis

Ajouter un zéro devant le contenu si donne une chaine de 0 à 2 caractères

  • “0”[0,2-length(value)] + value


Appliquer des conditions

Fonction if - même chose que dans excel

  • if(test, si test est vrai, si test est vrai)

Si la cellule contient x, écrire x, sinon y

  • if(value.contains(“x”), “x”, “y”)

  • if(value.contains(“1”), value, null)


Comparer deux colonnes

Identifier si le contenu des cellules d’une colonne est pareil à une autre

  • value == cells[‘autre-colonne’].value

Est-ce que le premier caractère de la colonne x est le même que la colonne y

  • cells[“colonne1”].value[0] == cells[“colonne2”].value[0]

Comparer le contenu de deux colonnes et modifier les valeurs selon le résultat de la condition

  • if(cells[“colonne1”].value == cells[“colonne2”].value, “Pareil”, “Pas pareil”)


Vérifier le format d’une colonne

  • value.type()


Faire des calculs simples (valeurs numériques)

Somme d’une colonne plus une autre

  • value + cells[‘Jour du mois’].value

Arrondir le contenu

  • round(value)


Reprendre et concaténer le contenu d’une autre colonne

Créer une nouvelle colonne en fusionnant le contenu de deux autres et ajouter du texte

  • cells[‘nom’].value + cells[‘nom’].value + “Bonjour!”

Créer une nouvelle colonne avec les trois premiers caractères seulement

  • cells[‘Symptome’].value[0,3]

Transformer le contenu d’une colonne en concaténant le contenu d’une autre

  • value + ’ ’ + cells[‘street-type’].value


Remplacer des caractères

Remplacer tout le contenu d’une colonne (ici, vider la colonne)

  • value.replace(value, "")

Remplacer une lettre par une autre

  • value.replaceChars(“o”, “a”)

Faire plusieurs remplacements d’un coup

  • value.replace(“1”, “un”).replace(“2”, “deux”).replace(“3”, “trois”)


Identifier des cellules qui commencent par… (résultat booléen)

  • value.startsWith(“Berri”)


Supprimer un caractère de début ou fin de valeur:

Supprime “S” du début de la cellule

  • value.replace(/^S/,"") [regex ^ indique le début d’une cellule]

Supprime “.” à la fin de la cellule

  • value.replace(/.$/,"") [regex $ indique la fin d’une cellule]


Modifier/supprimer la ponctuation

  • value.replace(//,’ ’)


Travailler avec un format date

Extraire seulement une partie d’une date

  • value.toDate().datePart(“year”)

  • diff(now(),value,‘weeks’)


14. Ressources


  1. 12: ou expression rationnelle ^12 / 48 cas↩︎

  2. Clientèle / Blessée ou malade, Méfait volontaire, Nuisance involontaire / Méfait volontaire 781/ 5↩︎

  3. Clientèle / Ligne orange / Oui 17↩︎

  4. Montréal / Québec) / Québec / Mtl↩︎

  5. value[5,24].replace(“-”, "")↩︎

  6. value.split(“;”).sort().join(“,”)↩︎

  7. value[3,5] ou value.substring(3)↩︎

LS0tDQp0aXRsZTogIk9wZW5SZWZpbmUiDQphdXRob3I6ICJDYXJvbGluZSBQYXRlbmF1ZGU8L2JyPkJpYmxpb3Row6hxdWUgZGVzIGxldHRyZXMgZXQgc2NpZW5jZXMgaHVtYWluZXMsIFVuaXZlcnNpdMOpIGRlIE1vbnRyw6lhbDwvYnI+Y2Fyb2xpbmUucGF0ZW5hdWRlQHVtb250cmVhbC5jYSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6cm9ib2Jvb2s6DQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBoaWdobGlnaHQ6IGthdGUNCiAgICB0aHVtYm5haWxzOiBmYWxzZQ0KICAgIGxpZ2h0Ym94OiB0cnVlDQogICAgZ2FsbGVyeTogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBtYXRoamF4OiBudWxsDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJtZGZvcm1hdHMpDQoNCiMjIEdsb2JhbCBvcHRpb25zDQpvcHRpb25zKG1heC5wcmludD0iNzUiKQ0Kb3B0c19jaHVuayRzZXQoZWNobz1GQUxTRSwNCgkgICAgICAgICAgICAgY2FjaGU9VFJVRSwNCiAgICAgICAgICAgICAgIHByb21wdD1GQUxTRSwNCiAgICAgICAgICAgICAgIHRpZHk9VFJVRSwNCiAgICAgICAgICAgICAgIGNvbW1lbnQ9TkEsDQogICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLA0KICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSkNCm9wdHNfa25pdCRzZXQod2lkdGg9NzUpDQpgYGANCg0KDQoNCiFbXShpbWFnZXMvT1ItbG9nby5qcGcpIA0KDQo8L2JyPg0KDQoqKioNCg0KDQojIE9iamVjdGlmcw0KDQo8ZGl2IGNsYXNzID0gInJpZ2h0Ij4NCjxpbWcgc3JjPSJpbWFnZXMvT1IxNi5qcGciIHdpZHRoPSIyNTBweCIgLz4NCjwvZGl2Pg0KDQotIENvbXByZW5kcmUgbGUgZm9uY3Rpb25uZW1lbnQgZHUgbG9naWNpZWwuDQotIEltcG9ydGVyIGV0IGV4cGxvcmVyIHVuIGpldSBkZSBkb25uw6llcy4gDQotIE1hbmlwdWxlciBldCB0cmFuc2Zvcm1lciBkZXMgZG9ubsOpZXMuDQotIFMnaW5pdGllciDDoCBsJ3VzYWdlIGR1IGxhbmdhZ2UgR1JFTCBldCBhdXggZXhwcmVzc2lvbnMgcsOpZ3VsacOocmVzLg0KPC9icj4NCjwvYnI+DQo8L2JyPg0KPC9icj4NCjwvYnI+DQoNCioqKg0KDQoNCiMgMS4gUHLDqWxpbWluYWlyZXMNCiMjIERlcyBkb25uw6llcyBiaWVuIG9yZG9ubsOpZXMgY29tbWVuY2VudCBwYXIgc29pLW3Dqm1lIQ0KDQoNCi0gTGUgbmV0dG95YWdlIGRlIGZpY2hpZXJzIGRlIGRvbm7DqWVzIGVzdCB1bmUgdMOiY2hlIHNvdXZlbnQgbG9uZ3VlIGV0IGVubnV5ZXVzZSBtYWlzIGluY29udG91cm5hYmxlIGF2YW50IHRvdXRlIGFuYWx5c2Ugb3UgZGlmZnVzaW9uIGRlIGRvbm7DqWVzLg0KDQotIEwnYW1wbGV1ciBkZSBjZXR0ZSB0w6JjaGUgZMOpcGVuZHJhIGRlIGwnw6l0YXQgZGVzIGRvbm7DqWVzIGV0IGR1IHR5cGUgZGUgbG9naWNpZWwgcXVpIHNlcmEgZW5zdWl0ZSB1dGlsaXPDqSDDoCBkZXMgZmlucyBkJ2FuYWx5c2Ugb3UgZGUgdmlzdWFsaXNhdGlvbiAoUiwgU1BTUywgU3RhdGEsIFRhYmxlYXUsIEFyY0dJUy4uLikNCg0KPC9icj4NCg0KIyMjIyBQcm9ibMOobWVzIGNvdXJhbnRzIHJlbGF0aWZzIMOgIGxhIGZvcm1lIGV0L291IGF1IGNvbnRlbnUgZCd1biBqZXUgZGUgZG9ubsOpZXM6DQoNCi0gUHJvYmzDqG1lcyBkJ2VudMOqdGVzIGV0IGRlIG5vbXMgZGUgdmFyaWFibGVzLg0KLSBDZWxsdWxlcyBmdXNpb25uw6llcywgcXVpIGNvbnRpZW5uZW50IGRpZmbDqXJlbnRlcyBpbmZvcm1hdGlvbnMuDQotIFZhcmlhYmxlcyBxdWkgbmUgc29udCBwYXMgY2xhaXJlbWVudCBkw6lmaW5pZXMgw6AgbGEgdmVydGljYWxlLg0KLSBDb250ZW51IHRleHR1ZWwgbm9uIHN0cnVjdHVyw6kuDQotIFByb2Jsw6htZXMgZGUgZm9ybWF0cywgZGUgInBldGl0cyBjYXJhY3TDqHJlcyIgLT4gc8OpcGFyYXRldXJzL2TDqWxpbWl0ZXVycyBkZSBjb250ZW51IGV0IGRlIGNvbG9ubmVzLCBndWlsbGVtZXRzLCBlbmNvZGFnZSAoJycgIHx8IHwgIiIgLCAuIDsgKQ0KLSBQcsOpc2VuY2UgZGUgY2VsbHVsZXMgdmlkZXMsIGVzcGFjZXMuLi4NCg0KW0EgY2FzZSBzdHVkeSBpbiBtZXNzeSBkYXRhIGFuYWx5c2lzOiB0aGUgQXVzdHJhbGlhbiBzYW1lLXNleCBtYXJyaWFnZSBzdXJ2ZXldKGh0dHBzOi8vYmxvZy5yZXZvbHV0aW9uYW5hbHl0aWNzLmNvbS8yMDE3LzEyL3NleC1tYXJyaWFnZS1zdXJ2ZXkuaHRtbCkNCg0KPGNlbnRlcj4NCg0KIVtdKGltYWdlcy9PUjkuanBnKXt3aWR0aD02MCV9ICANCg0KPC9jZW50ZXI+DQoNCjwvYnI+DQoNCioqKg0KDQoNCkF2YW50IGQndXRpbGlzZXIgdW4gZmljaGllciBkZSBkb25uw6llcyBkYW5zIHNvbiBsb2dpY2llbCBkZSBjaG9peCwgc29uIG5ldHRveWFnZSBwZXV0IGRvbmMgaW5jbHVyZSBkZSBub21icmV1c2VzIHTDomNoZXMgY29tbWU6DQoNCjxkaXYgY2xhc3MgPSAicmlnaHQiPg0KPGltZyBzcmM9ImltYWdlcy9ib3R0bGUucG5nIiB3aWR0aD0iMTc1cHgiIC8+DQo8L2Rpdj4NCi0gTW9kaWZpZXIgbCdlbmNvZGFnZS4NCi0gU3VwcHJpbWVyIGxlcyBkb3VibG9ucy4NCi0gRGl2aXNlciBsZXMgY2VsbHVsZXMgY29tcG9zw6llcyBkZSB2YWxldXJzIG11bHRpcGxlcy4gICANCi0gUmVjb2RlciBsZXMgdmFsZXVycyBtYW5xdWFudGVzLg0KLSBSZXDDqXJlciBsZXMgZXJyZXVycyBkZSBzYWlzaWUsIGxlcyB2YWxldXJzIGFiZXJyYW50ZXMuLi4NCi0gRnVzaW9ubmVyIGRlcyBmaWNoaWVycy4NCi0gRnVzaW9ubmVyIGRlcyBjb2xvbm5lcy4NCi0gQWdyw6lnZXIgZGVzIHZhbGV1cnMgZGUgdmFyaWFibGVzLg0KLSBDcsOpZXIgZGVzIHZhcmlhYmxlcy4NCi0gQ2hhbmdlciBsZSBmb3JtYXQgZGVzIHZhcmlhYmxlcy4NCi0gQ2hhbmdlciBsZSBmb3JtYXQgZHUgZmljaGllci4NCi0gVHJhbnNmb3JtZXIgbGVzIGNvbG9ubmVzIGVuIHJhbmfDqWVzIChmb3JtYXQgIndpZGUiIGVuICJsb25nIikuDQoNCjwvYnI+DQoNCioqKg0KDQoNCiMgMi4gUG91cnF1b2kgT3BlblJlZmluZT8NCg0KLSBQbHVzaWV1cnMgbGFuZ2FnZXMgZGUgcHJvZ3JhbW1hdGlvbiBldCBvdXRpbHMgZCdhbmFseXNlIG91IGRlIGdlc3Rpb24gZGUgZG9ubsOpZXMgcGV1dmVudCDDqnRyZSB1dGlsaXPDqXMsIG1haXMgT3BlblJlZmluZSBhIMOpdMOpIGNyw6nDqSBzcMOpY2lmaXF1ZW1lbnQgcG91ciBmYWlyZSBsZSBtw6luYWdlLg0KDQotIFBsdXMgZmFjaWxlIHF1ZSBSIGV0IHBsdXMgZWZmaWNhY2UgcXUnRXhjZWwuDQoNCi0gUGVybWV0IGRlIGZhY2lsZW1lbnQgaWRlbnRpZmllciBldCBkZSBjb3JyaWdlciBlbiBsb3QgZGVzIGRvbm7DqWVzIGluY29tcGzDqHRlcywgbWFucXVhbnRlcywgZXJyb27DqWVzLCBpbmNvaMOpcmVudGVzLCBub24gcGVydGluZW50ZXMsIG1hbCBmb3JtYXTDqWVzLCBxdSdlbGxlcyBzb2llbnQgbnVtw6lyaXF1ZXMgb3UgdGV4dHVlbGxlcy4NCg0KDQo8Y2VudGVyPiAgIA0KDQo8aW1nIHNyYz0iaW1hZ2VzLzE5MTgtQWQtODYwLTg2MHg1NzMuanBnIiB3aWR0aD0iNjAlIi8+DQoNCjwvY2VudGVyPiAgIA0KDQoNCjwvYnI+DQoNCiMjIyBGb25jdGlvbnMgc3DDqWNpYWxpc8OpZXMgcG91cjoNCg0KLSAqRXhwbG9yZXIqIHNlcyBkb25uw6llcyBzb3VzIHRvdXMgc2VzIGFuZ2xlcyAoZ3LDomNlIMOgIGRlcyBmaWx0cmVzLCB0cmlzLCBmYWNldHRlcywgcmVncm91cGVtZW50cykuICAgDQotICpOZXR0b3llciogOiByZXDDqXJlciBkZXMgZXJyZXVycywgbW9kaWZpZXIgbGUgY29udGVudSBkZXMgY2VsbHVsZXMuLi4NCi0gKlRyYW5mb3JtZXIqIDogY2hhbmdlciBmb3JtYXRzIGRlIHNlcyB2YXJpYWJsZXMsIGNyw6llciBkZSBub3V2ZWxsZXMgdmFyaWFibGVzIHN1ciBsYSBiYXNlIGRlcyBjb2xvbm5lcyBwcsOpc2VudGVzLi4uDQotICpFbnJpY2hpciogOiBmdXNpb25uZXIgZGVzIGZpY2hpZXJzLCBpbXBvcnRlciBkZXMgZG9ubsOpZXMgZW4gbGlnbmUgKEFQSSwgVVJMcyksIHLDqWNvbmNpbGlhdGlvbiAoV2lraWRhdGEgZXQgW2F1dHJlcyBzb3VyY2VzIGV4dGVybmVzXShodHRwczovL2dpdGh1Yi5jb20vT3BlblJlZmluZS9PcGVuUmVmaW5lL3dpa2kvUmVjb25jaWxhYmxlLURhdGEtU291cmNlcykpLi4uDQotICpBdXRvbWF0aXNlciogKHLDqXV0aWxpc2VyIHNvbiBoaXN0b3JpcXVlIGRlIG1hbmlwdWxhdGlvbnMpDQoNCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAibm90ZSI+DQoNCioqw4Agbm90ZXIqKiANCg0KT3BlblJlZmluZSBuJ2VzdCBwYXMgdW4gb3V0aWwgZCdhbmFseXNlIG91IGRlIHZpc3VhbGlzYXRpb24gZXQgbmUgcGVybWV0IHBhcyBkZSBjcsOpZXIgdW4gamV1IGRlIGRvbm7DqWVzIMOgIHBhcnRpciBkZSB6w6lyby4gQ2Ugbidlc3QgcGFzIHVuIG91dGlsIGRlIHJlbXBsYWNlbWVudCBtYWlzIGNvbXBsw6ltZW50YWlyZS4NCg0KPC9kaXY+DQoNCg0KPC9icj4NCg0KKioqDQoNCg0KIyMgMi4xLiBFeGVtcGxlcyBkJ3V0aWxpc2F0aW9uDQoNCkhhcm1vbmlzZXIsIHN0YW5kYXJkaXNlciwgdW5pZm9ybWlzZXIuLi4NCg0KPGNlbnRlcj4gIA0KDQohW10oaW1hZ2VzL09SOC5qcGcpICAgDQoNCjwvY2VudGVyPiAgDQoNCjwvYnI+DQoNCioqKg0KDQoNCiMjIDIuMi4gUG91ciBhdm9pciBkZSBiZWxsZXMgZG9ubsOpZXMgKnRpZHkqDQoNClBlcm1ldCBkJ2FwcGxpcXVlciBsZXMgcHJpbmNpcGVzIGR1IFtUaWR5ZGF0YV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei90aWR5LWRhdGEuaHRtbCkgDQoNCj4g4oCcVGlkeSBkYXRhc2V0cyBhcmUgYWxsIGFsaWtlLCBidXQgZXZlcnkgbWVzc3kgZGF0YXNldCBpcyBtZXNzeSBpbiBpdHMgb3duIHdheS7igJ0g4oCT4oCTIEhhZGxleSBXaWNraGFtDQoNCjwvYnI+DQoNCioqVHJvaXMgcHJpbmNpcGVzIGRlIGJhc2U6KioNCg0KMS4gQ2hhcXVlIGNvbG9ubmUgZXN0IHVuZSAqKnZhcmlhYmxlKiouDQoyLiBDaGFxdWUgbGlnbmUgZXN0IHVuZSAqKm9ic2VydmF0aW9uKiouDQozLiBDaGFxdWUgY2VsbHVsZSDDoCAqKnVuZSBzZXVsZSB2YWxldXIqKi4NCg0KPGNlbnRlcj4gIA0KDQohW10oaW1hZ2VzL09SMTAuanBnKSANCg0KPC9jZW50ZXI+ICANCg0KPC9icj4NCg0KKioqDQoNCg0KIyMgMi4zLiAgUHJpbmNpcGFsZXMgY2FyYWN0w6lyaXN0aXF1ZXMNCg0KLSBMb2dpY2llbCBncmF0dWl0IGV0IG91dmVydCB1dGlsaXPDqSBwYXIgdW5lIGxhcmdlIGNvbW11bmF1dMOpLg0KDQotIENyw6nDqSBlbiAyMDEwICgqRnJlZWJhc2UgR3JpZHdvcmtzKiksIHJhY2hldMOpIHBhciBHb29nbGUgZW4gMjAxMCAoKkdvb2dsZSBSZWZpbmUqKSwgcHVpcyBvdXZlcnR1cmUgZHUgY29kZSBlbiAyMDEyIGV0IHJlcHJpcyBwYXIgY29tbXVuYXV0w6kgcXVpIGxlIGTDqXBsYWNlIHN1ciBHaXRodWIgZXQgZGV2aWVudCAqT3BlblJlZmluZSouDQoNCi0gTXVsdGlwbGF0ZWZvcm1lczogV2luZG93cywgTWFjLCBMaW51eC4NCg0KLSBJbnRlcmZhY2Ugc2VtYmxhYmxlIMOgIHVuIHRhYmxldXIgY29tbWUgRXhjZWwsIG1haXMgZG9udCBsZSBmb25jdGlvbm5lbWVudCBzJ2FwcGFyZW50ZSBwbHVzIMOgIHVuZSBiYXNlIGRlIGRvbm7DqWVzIChwYXIgZXhlbXBsZSBsZXMgdHJhaXRlbWVudHMgc29udCBzw6lwYXLDqXMgZGVzIGRvbm7DqWVzLCBpZSBsZXMgZm9ybXVsZXMgbmUgc29udCBwYXMgZW5yZWdpc3Ryw6llcyBkYW5zIGxlcyBjZWxsdWxlcyBtYWlzIGRhbnMgdW4gc2NyaXB0KS4NCg0KLSBBc3NvY2llIGxhIGZhY2lsaXTDqSBkJ3VzYWdlIGQndW4gbG9naWNpZWwgY29tbWUgRXhjZWwgw6AgbGEgcHVpc3NhbmNlIGQnb3V0aWxzIGRlIHByb2dyYW1tYXRpb24gZXQgZCdhbGdvcml0aG1lcy4NCg0KLSBVc2FnZSBkZSBsJyoqaW50ZXJmYWNlIGdyYXBoaXF1ZSoqIGV0L291IGRlICoqc2NyaXB0cyBHUkVMKiogKCpHb29nbGUgUmVmaW5lIEV4cHJlc3Npb24gTGFuZ3VhZ2UqKSBldCBkJ2V4cHJlc3Npb25zIHLDqWd1bGnDqHJlczogcHJvcG9zZSB1biBlbnNlbWJsZSBkZSBmb25jdGlvbnMgYXV0b21hdGlzw6llcyBkb25jIG5lIG7DqWNlc3NpdGUgw6AgbGEgYmFzZSBhdWN1bmUgY29tcMOpdGVuY2UgZW4gcHJvZ3JhbW1hdGlvbiwgbWFpcyBsJ3VzYWdlIGR1IGxhbmdhZ2UgcGVybWV0IGQnYWxsZXIgYmVhdWNvdXAgcGx1cyBsb2luLg0KDQotIFBhcnRpY3VsacOocmVtZW50IHB1aXNzYW50IHBvdXIgbGUgbmV0dG95YWdlIGRlIHRhYmxlIGRlIGRvbm7DqWVzIGF2ZWMgZHUgY29udGVudSB0ZXh0dWVsLg0KDQotICoqUmVwcm9kdWN0aWJpbGl0w6kqKiEgUGVybWV0IGRlIGdhcmRlciB1biBoaXN0b3JpcXVlIGRlIHRvdXRlcyBsZXMgbWFuaXB1bGF0aW9ucyBlZmZlY3R1w6llcyBzdXIgc2VzIGRvbm7DqWVzIGFmaW4gZGUgbGVzIHBhcnRhZ2VyLCBkZSBsZXMgcsOpdXRpbGlzZXIgc3VyIGQnYXV0cmVzIGRvbm7DqWVzLi4uDQoNCjwvYnI+DQoNCg0KKioqDQoNCg0KIyAzLiBJbnN0YWxsYXRpb24gZXQgZm9uY3Rpb25uZW1lbnQgZ8OpbsOpcmFsDQoNCi0gTGUgZm9uY3Rpb25uZW1lbnQgZCdPcGVuUmVmaW5lIHBldXQgw6p0cmUgdW4gcGV1IGTDqXJvdXRhbnQgYXUgZMOpcGFydCBjYXIgaWwgbid5IGEgcGFzIGQnaW5zdGFsbGF0aW9uIGVuIGJvbm5lIGV0IGR1ZSBmb3JtZSBjb21tZSBwb3VyIHVuIGxvZ2ljaWVsIHLDqWd1bGllci4NCg0KLSBbVMOpbMOpY2hhcmdlciBldCBkw6l6aXBwZXJdKGh0dHBzOi8vb3BlbnJlZmluZS5vcmcvZG93bmxvYWQuaHRtbCkgbGUgbG9naWNpZWwgZGFucyB1biBkb3NzaWVyIGRlIHNvbiBjaG9peC4NCg0KLSBDcsOpw6kgZW4gbGFuZ2FnZSBKYXZhIFtkb25jIG7DqWNlc3NpdGUgbCdpbnN0YWxsYXRpb24gZGUgSmF2YSAoNjQgYml0cyBkZSBwcsOpZsOpcmVuY2UpXShodHRwczovL3d3dy5qYXZhLmNvbS9lbi9kb3dubG9hZC8pLg0KDQotIE5hdmlnYXRldXJzIMOgIHByaXZpbMOpZ2llcjogQ2hyb21lLCBPcGVyYSwgRWRnZS4gRmlyZWZveCBwZXV0IHBvc2VyIHByb2Jsw6htZSAobmUgZm9uY3Rpb25uZSBwYXMgZGFucyBJRSkuICANCg0KLSBQb3VyIGTDqW1hcnJlciBsZSBsb2dpY2llbCwgY2xpcXVlciBzdXIgbGUgZmljaGllciBgYCBgb3BlbnJlZmluZS5leGVgIGBgIG91IGByZWZpbmUuYmF0YC4gSWwgZXN0IHV0aWxlIGRlIGZhaXJlIHVuIGNsaWMtZHJvaXQgc3VyIGxlIGZpY2hpZXIgLmV4ZSBwb3VyIGwnw6lwaW5nbGVyIGRhbnMgc2EgYmFycmUgZGUgdMOiY2hlcyAoc3VyIE1hYywgZMOpcGxhY2VyIGwnaWPDtG5lIE9wZW5SZWZpbmUgZGFucyBsZSBkb3NzaWVyIGQnYXBwbGljYXRpb25zIGV0IGRvdWJsZSBjbGlxdWVyIHN1ciBjZWxsZS1jaSkuDQoNCi0gVW5lIGZlbsOqdHJlIGRlIGNvbW1hbmRlIG5vaXJlIHMnb3V2cmlyYSBldCBsYW5jZXJhIGwnb3V2ZXJ0dXJlIGQndW4gb25nbGV0IGRhbnMgbGUgbmF2aWdhdGV1ciB3ZWIuICANCg0KLSBMYSBmZW7DqnRyZSBkZSBjb21tYW5kZXMgcGV1dCBlbnN1aXRlIMOqdHJlIGlnbm9yw6llIG1haXMgTkUgUEFTIExBIEZFUk1FUiEgRWxsZSBuZSBzZXJ2aXJhIHF1J8OgIGZlcm1lciBsYSBzZXNzaW9uIGRlIHRyYXZhaWwuICANCg0KLSBTaSBsZSBuYXZpZ2F0ZXVyIG5lIHMnb3V2cmUgcGFzIGF1dG9tYXRpcXVlbWVudCwgc2Fpc2lyIGwnYWRyZXNzZSBodHRwOi8vMTI3LjAuMC4xOjMzMzMvIG91IGh0dHA6Ly9sb2NhbGhvc3Q6MzMzMyBkYW5zIHVuIG9uZ2xldC4gDQoNCjxjZW50ZXI+ICANCg0KIVtdKGltYWdlcy9PUjE3LmpwZyl7d2lkdGg9ODAlfQ0KDQo8L2NlbnRlcj4gIA0KDQo8L2JyPg0KDQoqKioNCg0KDQojIyAzLjEuIFRyYXZhaWwgbG9jYWwNCg0KLSBSZXBvc2UgZG9uYyBzdXIgZGV1eCBjb21wb3NhbnRlczogdW4gKipzZXJ2ZXVyIHdlYiBsb2NhbCoqIGV0IHVuICoqb25nbGV0IGRlIG5hdmlnYXRldXIgd2ViKiogcG9pbnRhbnQgdmVycyBsJ2FkcmVzc2UgZHUgc2VydmV1ciBzdXIgc29uIHBvc3RlLg0KDQotIExlIHRyYXZhaWwgc2UgZmFpdCBkYW5zIHVuIG9uZ2xldCBkZSBuYXZpZ2F0ZXVyIHF1aSBlc3QgdW5lIHNpbXBsZSBpbnRlcmZhY2UgZ3JhcGhpcXVlIHBvdXIgaW50ZXJhZ2lyIGF2ZWMgY2Ugc2VydmV1ciBsb2NhbCwgbWFpcyAqKmxlcyBkb25uw6llcyBuZSBzb250IHBhcyBzdXIgbGUgIm51YWdlIioqLg0KDQotIFRyYXZhaWwgbG9jYWwgZG9uYyBwYXMgZCdlbnZpcm9ubmVtZW50IGNvbGxhYm9yYXRpZi4gDQoNCi0gTGVzIGZpY2hpZXJzIHByb2dyYW1tZSBzZSB0cm91dmVyb250IGRhbnMgbGUgZG9zc2llciBkJ2luc3RhbGxhdGlvbiBldCBsZXMgZmljaGllcnMgZGUgcHJvamV0cyBkYW5zIGxlICp3b3Jrc3BhY2UgZGlyZWN0b3J5Ki4NCg0KLSBPcGVuUmVmaW5lIG5lIG1vZGlmaWUgcGFzIGxlIGZpY2hpZXIgb3JpZ2luYWwsIGlsIHRyYXZhaWxsZSDDoCBwYXJ0aXIgZCd1bmUgKipjb3BpZSBlbiBtw6ltb2lyZSBzdG9ja8OpZSBlbiBhcmNoaXZlcyoqIGRhbnMgbGUgcsOpcGVydG9pcmUgZGUgdHJhdmFpbC4NCg0KLSBMZSBwcm9qZXQgZXN0IGVucmVnaXN0csOpIGVuIGZvcm1hdCBPcGVuUmVmaW5lIGF1dG9tYXRpcXVlbWVudCBkYW5zIGxlIGRvc3NpZXIgZGUgdHJhdmFpbCDDoCB0b3V0ZXMgbGVzIDUgbWludXRlcyAoW3BldXQgw6p0cmUgbW9kaWZpw6ldKGh0dHBzOi8vZG9jcy5vcGVucmVmaW5lLm9yZy9tYW51YWwvcnVubmluZyNqdm0tcHJlZmVyZW5jZXMpKS4NCg0KLSBMZSBmaWNoaWVyIGRlIGRvbm7DqWVzIHVuZSBmb2lzIG5ldHRvecOpIHBvdXJyYSDDqnRyZSBleHBvcnTDqSBlbiBkaWZmw6lyZW50cyBmb3JtYXRzIGV0IGwnaGlzdG9yaXF1ZS9zeW50YXhlIHBvdXJyYSDDqnRyZSBleHRyYWl0IGVuIGZvcm1hdCBKU09OIGV0IGVucmVnaXN0csOpIGRhbnMgdW4gZmljaGllciAudHh0Lg0KDQotIFBvdXIgZmVybWVyIGxhIHNlc3Npb24gZGUgdHJhdmFpbCBjb3JyZWN0ZW1lbnQsIGZhaXJlIGBDdHJsICsgY2AgZGFucyBmZW7DqnRyZSBkZSBjb21tYW5kZSAocGV1dCDDqnRyZSBuw6ljZXNzYWlyZSBkZSBsZSBmYWlyZSBwbHVzIGQndW5lIGZvaXMpID0gZW5yZWdpc3RyZSBsZSBwcm9qZXQgZXQgZmVybWUgbGUgc2VydmV1ci4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJub3RlIj4NCioqw4Agbm90ZXIqKiAgDQotIFBlcm1ldCBkZSB0cmF2YWlsbGVyIHN1ciBkZSBncm9zIGZpY2hpZXJzIG1haXMgbGEgdGFpbGxlIHBvc3NpYmxlIGVzdCB0b3V0IGRlIG3Dqm1lIGxpbWl0w6llLCBsYSBwZXJmb3JtYW5jZSBwZXV0IGRldmVuaXIgcHJvYmzDqW1hdGlxdWUgw6AgcGx1c2lldXJzIGNlbnRhaW5lcyBkZSBtaWxsaWVycyBkZSBsaWduZXMgKHRvdXQgZMOpcGVuZGFudCBkdSBub21icmUgZGUgY29sb25uZXMpIGRvbmMgcGFzIHZyYWltZW50IGTDqXZlbG9wcMOpIHBvdXIgZmFpcmUgZHUgYmlnIGRhdGEuDQotIFRyYXZhaWxsZSBhdmVjIDFHbyBkZSBtw6ltb2lyZSBwYXIgZMOpZmF1dC4gw4AgcGx1cyBkZSAxMDAgMDAwIGxpZ25lcywgaWwgcGV1dCDDqnRyZSBwcsOpZsOpcmFibGUgZCdbYXVnbWVudGVyIGxhIG3DqW1vaXJlXShodHRwczovL2RvY3Mub3BlbnJlZmluZS5vcmcvbWFudWFsL2luc3RhbGxpbmcjaW5jcmVhc2luZy1tZW1vcnktYWxsb2NhdGlvbikgZGUgdHJhdmFpbDogIA0KICAtIE91dnJpciBsZSBmaWNoaWVyIHJlZmluZS5pbmkgZGFucyBub3RlcGFkIGV0IG1vZGlmaWVyIGxhIGxpZ25lIFJFRklORV9NRU1PUlkgPSBwYXJhbWV0cmUuICANCiAgLSBQYXIgbGEgc3VpdGUgbGFuY2VyIE9SIGF2ZWMgbGUgZmljaGllciAqcmVmaW5lLmJhdCogZXQgbm9uICpvcGVucmVmaW5lLmV4ZSAqLiAgIA0KDQo8L2Rpdj4NCjwvYnI+DQoNCioqKg0KDQoNCiMjIDMuMi4gw4ljcmFuIGQnYWNjdWVpbA0KDQotIMOAIHBhcnRpciBkdSBtZW51IGRlIGdhdWNoZSwgaWwgZXN0IHBvc3NpYmxlIGRlIGBDcsOpZXIgdW4gcHJvamV0YCwgYE91dnJpciB1biBwcm9qZXRgIChoaXN0b3JpcXVlIGRlcyBwcm9qZXRzIGVucmVnaXN0csOpcykgb3UgYEltcG9ydGVyIHVuIHByb2pldCBgIChhcmNoaXZlcyAuemlwIHNlIHRyb3V2YW50IGRhbnMgbGUgZG9zc2llciBkZSB0cmF2YWlsKS4gICANCg0KLSBQb3VyIGNoYW5nZXIgbGEgbGFuZ3VlIGRlIGwnaW50ZXJmYWNlIGF1IGZyYW7Dp2FpcywgY2xpcXVlciBzdXIgbCdvbmdsZXQgYExhbmd1ZWAgZGFucyBsZSBtZW51IGRlIGdhdWNoZS4gIA0KDQotIExlIGZpY2hpZXIgcGV1dCDDqnRyZSBjcsOpw6kgw6AgcGFydGlyIGRlIGRpZmbDqXJlbnRlcyBzb3VyY2VzOiBgQ2V0IG9yZGluYXRldXJgIChwb3N0ZSBsb2NhbCksIGBBZHJlc3NlcyB3ZWIgKFVSTHMpYCwgYFByZXNzZS1wYXBpZXJgIChjb3Bpw6ktY29sbMOpKSwgYEdvb2dsZSBkYXRhYCAoR29vZ2xlIHNoZWV0cykuLi4pIGV0IGVuIGRpZmbDqXJlbnRzIGZvcm1hdHMgKC5jc3YsIC50eHQsIC54bWwsIC54bHMsIC5KU09OLCAuemlwLi4uIChjZXJ0YWluZXMgZXh0ZW5zaW9ucyBwZXJtZXR0ZW50IGwndXNhZ2UgZCdhdXRyZXMgZm9ybWF0cyBjb21tZSByZGYpLiAgDQoNCjxjZW50ZXI+ICANCg0KIVtdKGltYWdlcy9PUjEuanBnKSAgDQoNCjwvY2VudGVyPiAgDQoNCi0gRGV1eCBmaWNoaWVycyBvdSBwbHVzIHBldXZlbnQgw6p0cmUgaW1wb3J0w6lzIGVuIG3Dqm1lIHRlbXBzLiBMZXMgbGlnbmVzIHNlcm9udCBpbXBvcnTDqWVzIHVuZSDDoCBsYSBzdWl0ZSBkZSBsJ2F1dHJlIHNlbG9uIGwnb3JkcmUgZCdpbXBvcnRhdGlvbiAodW5lIGNvbG9ubmUgcGVybWV0dGFudCBkJ2lkZW50aWZpZXIgbGUgZmljaGllciBzb3VyY2Ugc2VyYSBjcsOpw6llIGF1dG9tYXRpcXVlbWVudCkuIA0KDQo8L2JyPg0KDQoqKioNCg0KDQojIyAzLjMuIEhpc3RvcmlxdWUgZGVzIHByb2pldHMNCg0KLSBMJ29uZ2xldCBgT3V2cmlyIHVuIHByb2pldGAgcGVybWV0Og0KICAtIEQnYWNjw6lkZXIgZXQgZCdvdXZyaXIgdG91cyBsZXMgcHJvamV0cyBlbnJlZ2lzdHLDqXMgbG9jYWxlbWVudC4NCiAgLSBEJ8OpZGl0ZXIgc2VzIG3DqXRhZG9ubsOpZXMgKGxpZW4gYETDqXRhaWxzYCkuDQogIC0gRCdhY2PDqWRlciBhdSBkb3NzaWVyIGRlIHRyYXZhaWwgKGTDqWZpbmkgcGFyIGTDqWZhdXQpIG/DuSBPcGVuUmVmaW5lIHN0b2NrZSBsZXMgYXJjaGl2ZXMgZGVzIHByb2pldHMgZW5yZWdpc3Ryw6lzIHBhciBsZSBiaWFpcyBkdSBsaWVuIGBQYXJjb3VyaXIgbGUgZG9zc2llciBkZSBsJ2VzcGFjZSBkZSB0cmF2YWlsYC4NCg0KPGNlbnRlcj4gIA0KDQohW10oaW1hZ2VzL09SMy5qcGcpDQoNCjwvY2VudGVyPiAgDQoNCjwvYnI+DQoNCioqKg0KDQoNCiMgNC4gQ3LDqWVyIHVuIHByb2pldA0KDQotIFBvdXIgb3V2cmlyIHVuIGZpY2hpZXIgw6AgcGFydGlyIGRlIHNvbiBwb3N0ZSwgY2xpcXVlciBzdXIgYENyw6llciB1biBwcm9qZXRgIC0gPiBgQ2V0IG9yZGluYXRldXJgIC0gPiBgc8OpbGVjdGlvbm5lciBmaWNoaWVyc2Agc3VyIHNvbiAgcG9zdGUgLT4gYFN1aXZhbnRgLiAgDQoNCi0gVW5lIGZlbsOqdHJlIHMnb3V2cmUgZW5zdWl0ZSBwb3VyIHBlcm1ldHRyZSBkZSBwcsOpLXZpc3VhbGlzZXIgc29uIGpldSBkZSBkb25uw6llcyBldCBkZSBtb2RpZmllciwgc2kgbsOpY2Vzc2FpcmUsIGxlcyBvcHRpb25zIGQnaW1wb3J0YXRpb24gZW4gZm9uY3Rpb24gZGVzIGNhcmFjdMOpcmlzdGlxdWVzIGR1IGZpY2hpZXIgZGUgZG9ubsOpZXM6IG1vZGlmaWNhdGlvbiBkdSBmb3JtYXQgZGUgZmljaGllciBzJ2lsIG4nYSBwYXMgw6l0w6kgaWRlbnRpZmnDqSBjb3JyZWN0ZW1lbnQgWzVdLCBsJ2VuY29kYWdlIGRlcyBjYXJhY3TDqHJlcyBbVVRGLThdIFs2XSwgbGUgdHJhaXRlbWVudCBkZXMgZW50w6p0ZXMgZXQgcHJlbWnDqHJlcyBsaWduZXMgWzldLi4uDQoNCjwvYnI+DQoNCiFbXShpbWFnZXMvT1IyLmpwZykgIA0KDQoNCiMjIEV4ZXJjaWNlDQoNCjxkaXYgY2xhc3MgPSAiYm94MSI+DQotIENyw6llciB1biBub3V2ZWF1IHByb2pldCBlbiBpbXBvcnRhbnQgdW4gZmljaGllciDDoCBwYXJ0aXIgZGUgc29uIGVtcGxhY2VtZW50IHN1ciBHaXRodWI6IGh0dHBzOi8vZ2l0aHViLmNvbS9DUkxOUC9vcGVucmVmaW5lIA0KICAtIENsaXF1ZXIgc3VyIGxlIGZpY2hpZXIgKkluY2lkZW50cyBtw6l0cm8tbXRsLmNzdiogLT4gQ2xpcXVlciBzdXIgbGUgYm91dG9uIFJBVyAtPiBjb3BpZXIgbCdhZHJlc3NlIGR1IG5hdmlnYXRldXIuDQogIC0gRGFucyBPcGVuUmVmaW5lLCBDcsOpZXIgdW4gcHJvamV0IC0+IEFkcmVzc2VzIHdlYiAoVVJMcykgLT4gY29sbGVyIGxlIGxpZW4gLT4gU3VpdmFudC4NCihMZSBmaWNoaWVyIGVzdCBhdXNzaSBkaXNwb25pYmxlIHN1ciBsZSBzaXRlIFtEb25uw6llcyBvdXZlcnRlcyBNb250csOpYWxdKGh0dHBzOi8vZG9ubmVlcy5tb250cmVhbC5jYS9zb2NpZXRlLWRlLXRyYW5zcG9ydC1kZS1tb250cmVhbC9pbmNpZGVudHMtZHUtcmVzZWF1LWR1LW1ldHJvKSkuICAgICANCg0KLSBFeHBsb3JlciBsZXMgb3B0aW9ucyBkJ2ltcG9ydGF0aW9uIC0+IFBvcnRlciB1bmUgYXR0ZW50aW9uIHBhcnRpY3VsacOocmUgYXV4IG9wdGlvbnM6IGBTdXBwcmltZXIgbGVzIGVzcGFjZXNgICg4IC0+IGNvY2hlciksIAlgVXRpbGlzZXIgbGUgY2FyYWN0w6hyZQkiIC4uLmAgKDEwIC0+ICoqY29jaGVyKiopLCBgQW5hbHlzZXIgbGUgdGV4dGUgZGVzIGNlbGx1bGVzIGNvbW1lIG5vbWJyZXMgLCBkYXRlc+KApmAgKDExIC0+IGTDqWNvY2hlcikNCg0KLSBDaGFuZ2VyIGxlIGBOb20gZHUgcHJvamV0YCBbMl0gZXQgY2xpcXVlciBzdXIgYENyw6llciB1biBwcm9qZXRgIFs0XSAtIEVuIGNhcyBkZSBwcm9ibMOobWUsIGlsIGVzdCBwb3NzaWJsZSBkZSByZWNvbW1lbmNlciBsZSBwcm9jZXNzdXMgWzFdLg0KPC9kaXY+DQoNCjwvYnI+DQoNCioqKg0KDQoNCiMgNS4gRXhwbG9yZXIgbCdpbnRlcmZhY2UNCg0KLSBMJ2ludGVyZmFjZSBlc3Qgc2ltaWxhaXJlIMOgIEV4Y2VsIG1haXMgb24gbmUgcGV1dCB2b2lyIGwnZW5zZW1ibGUgZGVzIGxpZ25lcywgbGEgImxvZ2lxdWUiIGQnT3BlblJlZmluZSByZXBvc2Ugc3VyIGxlIHRyYXZhaWwgZW4gKipjb2xvbm5lcyoqLg0KDQo8Y2VudGVyPiAgDQoNCiFbXShpbWFnZXMvT1I0LmpwZykgDQoNCjwvY2VudGVyPiAgDQoNCjxkaXYgY2xhc3MgPSAibm90ZSI+ICANCg0KWzFdIExpZW4gc291cyBsJ2ljw7RuZSByZW52b2kgdmVycyBsYSBwYWdlIGQnYWNjdWVpbC9pbXBvcnRhdGlvbi4gIA0KWzJdIFJlbm9tbWVyIGxlIG5vbSBkZSBzb24gcHJvamV0IGVuIHRvdXQgdGVtcHMuICANClszXSBQZXJtYWxpZW4gcXVpIHBlcm1ldCBkZSByZXZlbmlyIMOgIHVuZSB2dWUgcHLDqWNpc2UgKGFmZmljaGFnZSwgdHJpLCBmYWNldHRlcy4uLikgZHUgcHJvamV0LiAgDQpbNF0gTm9tYnJlIGRlIGxpZ25lcy9vYnNlcnZhdGlvbnMgZHUgZmljaGllci4gIA0KWzVdIENoYW5nZW1lbnQgZHUgbW9kZSBsaWduZXMgb3Ugb2JzZXJ2YXRpb25zLiAgDQpbNl0gTW9kaWZpZXIgbGUgbm9tYnJlIGRlIGxpZ25lcyBhZmZpY2jDqWVzLiAgDQpbN10gUGFzc2VyIGQndW5lIHBhZ2Ugw6AgbCdhdXRyZS4gIA0KWzhdIE91dnJpciB1biBub3V2ZWwgb25nbGV0IE9wZW5SZWZpbmUuICANCls5XSBFeHBvcnRlciBsZSBmaWNoaWVyIGVuIGRpZmbDqXJlbnRzIGZvcm1hdHMuICANCg0KPC9kaXY+ICANCg0KPC9icj4gIA0KDQoqKioNCg0KIyMgNS4xIERldXggdnVlcyBkZXMgZG9ubsOpZXMNCg0KLSBPcGVuUmVmaW5lIHByb3Bvc2UgZGV1eCB2dWVzIGRlcyBkb25uw6llczogYGxpZ25lc2AgZXQgYGVudHLDqWVzLmAgTGVzIGRvbm7DqWVzIHNvbnQgZ8OpbsOpcmFsZW1lbnQgcHLDqXNlbnTDqWVzIGVuIG1vZGUgYGxpZ25lc2AsIGMnZXN0LcOgLWRpcmUgY2hhcXVlIGxpZ25lIHJlcHLDqXNlbnRlIHVuZSBvYnNlcnZhdGlvbi4gTGUgbW9kZSBgZW50csOpZXNgIHBlcm1ldCBkJ2Fzc29jaWVyIHBsdXNpZXVycyBsaWduZXMgw6AgdW5lIG9ic2VydmF0aW9uLg0KDQotIElsIGVzdCBkb25jIHBvc3NpYmxlIGRlIG1vZGlmaWVyIGxhIHN0cnVjdHVyZSBkdSBmaWNoaWVyIHBvdXIgcXVlIHBsdXNpZXVycyBsaWduZXMgc29pZW50IGFzc29jacOpZXMgw6AgdW4gc2V1bCBjYXMgZW4gc2UgYmFzYW50IHN1ciBsYSBjb2xvbm5lIGNsw6kgKCoqc2V1bGUgbGEgbGlnbmUgb3JpZ2luYWxlIHNlcmEgbnVtw6lyb3TDqWUqKiksIG1haXMgZG9pdCBzZSBmYWlyZSBhdmVjIHByw6ljYXV0aW9ucy4gUG91ciBsZXMgbG9naWNpZWxzIGQnYW5hbHlzZSwgbGUgZm9ybWF0ICp0aWR5KiAoYGxpZ25lc2ApIGVzdCDDoCBwcml2aWzDqWdpZXIuDQoNCjxjZW50ZXI+ICANCg0KIVtdKGltYWdlcy9PUjQwLmpwZykNCg0KPC9jZW50ZXI+ICANCg0KKioqDQoNCg0KIyMgNS4yLiBMJ8OpZGl0aW9uIGRlIGNlbGx1bGVzDQoNCi0gSWwgZXN0IHBvc3NpYmxlIGQnw6lkaXRlciBtYW51ZWxsZW1lbnQgbGUgY29udGVudSBkZSBjZWxsdWxlcyBpbmRpdmlkdWVsbGVzIGVuIHNlIHBsYcOnYW50IHN1ciBjaGFjdW5lIGV0IGVuIGNsaXF1YW50IGBlZGl0YCwgbWFpcyBPcGVuUmVmaW5lIHByaXZpbMOpZ2llIGxlICoqdHJhdmFpbCBlbiBsb3QgcGFyIGNvbG9ubmVzKiogcG91ciBmaWx0cmVyLCB0cmllciwgdHJhbnNmb3JtZXIuDQoNCi0gTCfDqWRpdGlvbiBkaXJlY3RlIHBldXQgcydhcHBsaXF1ZXIgaW5kaXZpZHVlbGxlbWVudCBvdSBzdXIgdG91dGVzIGxlcyBjZWxsdWxlcyBhdmVjIGxhIG3Dqm1lIHZhbGV1ciBkYW5zIGNldHRlIGNvbG9ubmUuDQoNCi0gUGVybWV0IMOpZ2FsZW1lbnQgZGUgbW9kaWZpZXIgbGUgZm9ybWF0IGRlIGxhIGNlbGx1bGUuDQoNCjxjZW50ZXI+ICANCg0KIVtdKGltYWdlcy9PUjIyLmpwZyl7d2lkdGg9ODAlfQ0KDQo8L2NlbnRlcj4gIA0KDQoNCg0KIyMgRXhlcmNpY2UNCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCi0gRGFucyBsYSBjb2xvbm5lICpDYXVzZSBwcmltYWlyZSogY2xpcXVlciBkYW5zIHVuZSBjZWxsdWxlICpBdXRyZXMqLCDDqWRpdGVyIHNvbiBjb250ZW51IHBvdXIgKmF1dHJlKiBldCBhcHBsaXF1ZXIgw6AgbGEgY2VsbHVsZS4gDQoNCi0gRGFucyBsYSBjb2xvbm5lICrDiXZhY3VhdGlvbiosIG1vZGlmaWVyIGxlIGNvbnRlbnUgZCd1bmUgY2VsbHVsZSAiIyIgcGFyICpOb24qIGV0IGFwcGxpcXVlciDDoCB0b3V0ZXMgbGVzIGNlbGx1bGVzIGlkZW50aXF1ZXMuDQo8L2Rpdj4NCg0KPC9icj4NCg0KKioqDQoNCg0KIyMgNS4zLiBGb3JtYXQgZGVzIGRvbm7DqWVzICANCg0KLSDDgCBsJ2ltcG9ydGF0aW9uIGQndW4gZmljaGllciwgY2hhcXVlIGNlbGx1bGUgc2UgdmVycmEgYXR0cmlidWVyIHVuIGZvcm1hdC4gIA0KLSBQYXIgZMOpZmF1dCwgbGUgY29udGVudSBkZXMgY2VsbHVsZXMgZXN0IGRlIGZvcm1hdCBjaGHDrm5lcy4gICANCi0gTGUgY29udGVudSBkZXMgY2VsbHVsZXMgcmVjb25udSBjb21tZSBudW3DqXJpcXVlIGV0IGRhdGUgc2VyYSBkZSBjb3VsZXVyIHZlcnRlLiAgIA0KLSBMZSBmb3JtYXQgcGV1dCDDqnRyZSBtb2RpZmnDqSBkZSBkaWZmw6lyZW50ZXMgZmHDp29uczogYGVkaXRgLCBgVHJhbnNmb3JtYXRpb25zIGNvdXJhbnRlc2AsIEZlbsOqdHJlIEdSRUwuICAgDQotIENlIGZvcm1hdCBhdXJhIHVuIGltcGFjdCBzdXIgbGVzIGFjdGlvbnMgcG9zc2libGVzLiAgIA0KDQojIyMjIFRyb2lzIGZvcm1hdHMgZGUgYmFzZTogDQogIDEuIENoYcOubmUgZGUgY2FyYWN0w6hyZXMNCiAgMi4gTm9tYnJlDQogIDMuIERhdGUgKG5vcm1lIElTTy04NjAxIFlZWVktTU0tRERUSEg6TU06U1NaKSoNCiAgDQogIA0KIyMjIyBEZXV4IGZvcm1hdHMgZMOpY291bGFudCBkJ2FjdGlvbnM6IA0KICAtIEVycmV1ciAoZm9ybWF0IGF0dHJpYnXDqSBzdWl0ZSDDoCB1bmUgZXJyZXVyIGRlIHRyYW5zZm9ybWF0aW9uKSAgDQogIC0gTnVsbCoqDQoNCg0KIyMjIyBEZXV4IGF1dHJlcyB0eXBlcyBwYXJ0aWN1bGllcnMgZMOpY291bGFudCBkZSBtYW5pcHVsYXRpb25zDQogIC0gQm9vbMOpZW4gKHZhbGV1ciBiaW5haXJlIFQgb3UgRikNCiAgLSAqQXJyYXkqIChsaXN0ZSBkZSB2YWxldXJzIHPDqXBhcsOpZXMgcGFyIHVuZSB2aXJndWxlIGVudHJlIGNyb2NoZXRzIHBvdXZhbnQgw6p0cmUgdHJhbnNmb3Jtw6llcykNCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJub3RlIj4gIA0KIyMjIyMgKiBGb3JtYXQgZGF0ZQ0KDQotIFNlbG9uIGxlcyBiZXNvaW5zLCBsZXMgZGF0ZXMgcGV1dmVudCDDqnRyZSB0cmFpdMOpZXMgc291cyBmb3JtZSBkZSBgdGV4dGVgLCBkZSBgbm9tYnJlYCBvdSBgZGF0ZWAgKGxlIGZvcm1hdCBkYXRlIGVzdCBzdXJ0b3V0IG7DqWNlc3NhaXJlIHBvdXIgbGVzIGNhbGN1bHMgZGUgZGF0ZXMpLg0KLSBMZSBmb3JtYXQgZGF0ZSByZXBvc2Ugc3VyIHVuZSBzw6lyaWUgZCdvdXRpbHMgZXQgZGUgIHN0YW5kYXJkcyBwb3VyIHJlY29ubmFpdHJlIGV0IGNvbnZlcnRpciBsZXMgdmFsZXVycyBvcmlnaW5hbGVzIGVuIGRhdGUuIA0KLSBQb3VyIHF1J3VuZSBjZWxsdWxlIHNvaXQgcmVjb25udWUgY29tbWUgZGF0ZSwgZWxsZSBzZXJhIHRyYW5zZm9ybcOpZSBhdSBmb3JtYXQgKklTTy04NjAxLWNvbXBsaWFudCouDQotIFBvc3NpYmxlIGRlIG1vZGlmaWVyIGNlIGZvcm1hdCBwb3VyIHF1J2lsIHNvaXQgcGx1cyBmYWNpbGVtZW50IGxpc2libGUgw6AgbCdleHBvcnRhdGlvbi4NCg0KDQojIyMjIyAqKiBGb3JtYXQgIm1hbnF1YW50Ig0KDQotIE9wZW5SZWZpbmUgZmFpdCB1bmUgZGlzdGluY3Rpb24gZW50cmUgbGVzICoqY2VsbHVsZXMgdmlkZXMgYXZlYyBlc3BhY2VzIGJsYW5jcyoqIChxdWkgbmUgc29udCBwYXMgdmlkZXMhKSwgbGVzICoqdmFsZXVycyB2aWRlcyoqIChjaGFpbmUgZGUgbG9uZ3VldXIgMCksIGV0IGxlcyAqKnZhbGV1cnMgIm51bGwiKiogKHR5cGUgc3DDqWNpYWwgcXVpIG4nZXN0IHBhcyB1bmUgY2hhaW5lIGRlIGNhcmFjdMOocmVzKS4gTGVzICp2aWRlcyogZXQgbGVzICpudWxsKiBzb250IGF1c3NpIGNvbnNpZMOpcsOpcyBjb21tZSAqQmxhbmsqLg0KLSBQbHVzaWV1cnMgZm9uY3Rpb25zIGF1dG9tYXRpc8OpZXMgc291cyBgRmFjZXR0ZXNgIGV0IGDDiWRpdGVyIGxlcyBjZWxsdWxlc2AgcGVybWV0dGVudCBkZSBnw6lyZXIgY2VzIHR5cGVzIGRlIHZhbGV1cnMuDQo8L2Rpdj4NCg0KPC9icj4NCg0KIyMgRXhlcmNpY2UNCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KKipUcmFuc2Zvcm1lciB1bmUgY29sb25uZSBkZSBmb3JtYXQgY2FyYWN0w6hyZSBlbiBmb3JtYXQgZGF0ZSoqOiAgDQotIERhbnMgbGEgY29sb25uZSAqSm91ciBjYWxlbmRhaXJlKjogYE1lbnUgLT4gw4lkaXRlciBsZXMgY2VsbHVsZXMgLT4gVHJhbnNmb3JtYXRpb25zIGNvdXJhbnRlcyAtPiBFbiBkYXRlYCAgICANCg0KKipUcmFuc2Zvcm1lciB1bmUgY29sb25uZSBkZSBmb3JtYXQgY2FyYWN0w6hyZSBlbiBmb3JtYXQgbm9tYnJlKio6ICAgDQotIERhbnMgbGEgY29sb25uZSAqUG9ydGUqLCBjbGlxdWVyIGRhbnMgdW5lIGNlbGx1bGUsIMOpZGl0ZXIgbGUgZm9ybWF0IMOgICpOb21icmUqIGV0IGFwcGxpcXVlciDDoCB0b3V0ZXMgbGVzIGNlbGx1bGVzIGlkZW50aXF1ZXMuDQotIFJlY29tbWVuY2VyIGxhIHByb2PDqWR1cmUgYXZlYyBsZSBmb25jdGlvbiAqVHJhbnNmb3JtYXRpb25zIGNvdXJhbnRlcyouDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gIm5vdGUiPg0KDQotIExlIGNoYW5nZW1lbnQgZGUgZm9ybWF0IHBhciDDqWRpdGlvbiBkaXJlY3RlIGQndW5lIGNlbGx1bGUgZXN0IHVuZSBvcMOpcmF0aW9uIGRpc3RpbmN0ZSBkZSBsYSB0cmFuc2Zvcm1hdGlvbiBkdSBjb250ZW51LiBMYSBwcmVtacOocmUgb3DDqXJhdGlvbiBhcnJpdmUgcGFyZm9pcyDDoCBjaGFuZ2VyIGRlcyBmb3JtYXRzIHF1ZSBsYSB0cmFuc2Zvcm1hdGlvbiBuZSBwZXV0IGZhaXJlLiBQb3VyIHBsdXMgZCdpbmZvcm1hdGlvbiBzdXIgbGVzIGZvcm1hdHMsIHZvaXIgbGEgW2RvY3VtZW50YXRpb24gb2ZmaWNpZWxsZV0oaHR0cHM6Ly9kb2NzLm9wZW5yZWZpbmUub3JnL21hbnVhbC9leHBsb3JpbmcpLiAgDQo8L2Rpdj4NCg0KPC9icj4NCg0KKioqDQoNCg0KIyMgNS40LiBMYSBnZXN0aW9uIGRlcyBsaWduZXMgZXQgY29sb25uZXMNCg0KIyMjIyBMYSBnZXN0aW9uIGRlcyBjb2xvbm5lcyBwZXV0IHNlIGZhaXJlOg0KDQotICoqU3VyIGNoYXF1ZSBjb2xvbm5lKio6IA0KICAtIEZvbmN0aW9ucyBzb3VzIGDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gRMOpcGxhY2VyIC4uLiAvIFJlbm9tbWVyIC8gU3VwcHJpbWVyYCAgIA0KICAtIEZvbmN0aW9ucyBzb3VzIGBBcGVyw6d1IC0+IE1hc3F1ZXIuLi4gYCAgIA0KDQoNCi0gKipTdXIgbGEgY29sb25uZSBgVG91dGVzYCoqOiAgICAgDQogIC0gYMOJZGl0ZXIgbGVzIGNvbG9ubmVzIC0+IFJldHJpZXItc3VwcHJpbWVyLCBnZXN0aW9uIGRlcyB2YWxldXJzIGNvbnPDqWN1dGl2ZXNgICAgIA0KICAtIGBBcGVyw6d1IC0+IEFmZmljaGVyLW1hc3F1ZXJgLi4uICANCg0KPC9icj4NCg0KIyMjIyBMYSBnZXN0aW9uIGRlcyBsaWduZXM6DQoNCi0gTGEgc8OpbGVjdGlvbiBkZSBsaWduZXMgcGV1dCBzZSBmYWlyZSBwYXIgbGUgYmlhaXMgZGUgZmlsdHJlcywgZmFjZXR0ZXMgZXQgYXV0cmVzIG1hbmlwdWxhdGlvbnMgcGVyc29ubmFsaXPDqWVzLiAgDQotIElsIGVzdCBhdXNzaSBwb3NzaWJsZSBkZSBtYXJxdWVyL8OpdG9pbGVyIGRlcyBsaWduZXMgZW4gbG90IG91IGluZGl2aWR1ZWxsZW1lbnQgcHVpcyBkZSBjcsOpZXIgdW5lIGZhY2V0dGUgc3VyIGxhIGNvbG9ubmUgYFRvdXRlc2AgcG91ciBzw6lsZWN0aW9ubmVyIGxlcyBsaWduZXMgbWFycXXDqWVzIChgdHJ1ZWApLiAgDQotIE9uIHBldXQgZW5zdWl0ZSBzdXBwcmltZXIgbGVzIGxpZ25lcyBmaWx0csOpZXM6IGBUb3V0ZXMgLT4gw4lkaXRlciBsZXMgbGlnbmVzIC0+IFN1cHByaW1lciBsZXMgbGlnbmVzIGNvcnJlc3BvbmRhbnRlc2AuICANCg0KPC9icj4NCg0KIyMgRXhlcmNpY2UNCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCioqU3VwcHJpbWVyIHVuZSBjb2xvbm5lOiAqKiAgDQotIFN1ciBsYSBjb2xvbm5lICpUeXBlIGQnaW5jaWRlbnQqIC0+IGDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gU3VwcHJpbWVyIGNldHRlIGNvbG9ubmVgLiAgDQoNCioqU3VwcHJpbWVyIHBsdXNpZXVycyBjb2xvbm5lczogKiogIA0KLSBTdXIgbGEgY29sb25uZSAqVG91dGVzKiAtPiBgw4lkaXRlciBsYSBjb2xvbm5lIC0+IMOJZGl0ZXIvU3VwcHJpbWVyIGxlcyBjb2xvbm5lc2AgLT4gKktGUyogZXQgKkNBVCouICANCg0KPC9kaXY+DQoNCioqKg0KDQoNCiMjIDUuNS4gSGlzdG9yaXF1ZSAoVW5kby9SZWRvKQ0KDQotIFRvdXRlcyBsZXMgYWN0aW9ucyBzb250IGVucmVnaXN0csOpZXMgKGxvZyBkZSBzZXMgbWFuaXB1bGF0aW9ucykgZXQgcGV1dmVudCDDqnRyZSBhbm51bMOpZXMgZW4gcmVjdWxhbnQgw6l0YXBlIHBhciDDqXRhcGUgZGFucyBsJ2hpc3RvcmlxdWUuICANCi0gTGEgcHJlbWnDqHJlIGFjdGlvbiBkJ3VuIGhpc3RvcmlxdWUgZXN0IGxhIGNyw6lhdGlvbiBkdSBwcm9qZXQuICANCi0gUHVpc3F1ZSBsJ2hpc3RvcmlxdWUgZmFpdCBwYXJ0aWUgZHUgcHJvamV0IGVucmVnaXN0csOpIGRhbnMgbGUgZG9zc2llciBkZSB0cmF2YWlsLCBpbCBuZSBkaXNwYXJhaXQgcGFzIMOgIGxhIGZlcm1ldHVyZSBkZSBsYSBzZXNzaW9uLiANCi0gTCdoaXN0b3JpcXVlIHBldXQgw6p0cmUgZXh0cmFpdCBlbiBmb3JtYXQgSlNPTiwgY29waWVyL2NvbGxlciBkYW5zIG5vdGVwYWQgZXQgYXBwbGlxdWVyIGRlIG5vdXZlYXUuICANCg0KPGNlbnRlcj4gIA0KDQohW10oaW1hZ2VzL09SMTkuanBnKXt3aWR0aD02MCV9DQoNCjwvY2VudGVyPiAgDQoNCioqQXR0ZW50aW9uISoqDQoNCi0gU2kgb24gcmVjdWxlIGRhbnMgbGUgdGVtcHMgZXQgcXUnb24gZmFpdCB1bmUgbW9kaWZpY2F0aW9uLCBsZXMgw6l0YXBlcyBxdWkgc3VpdmVudCBkYW5zIGwnaGlzdG9yaXF1ZSBkaXNwYXJhaXNzZW50IHBvdXIgZGUgYm9uLiAgDQoNCi0gTGVzIG1hbmlwdWxhdGlvbnMgcmVsYXRpdmVzIMOgIGwnYWZmaWNoYWdlIG5lIHNvbnQgcGFzIGVucmVnaXN0csOpZXMgZGFucyBsJ2hpc3RvcmlxdWUsIHNldWxlbWVudCBsZXMgdHJhbnNmb3JtYXRpb25zLiBMJ2VucmVnaXN0cmVtZW50IGF1dG9tYXRpcXVlIG5lIGNvbXByZW5kIGRvbmMgcGFzIGxlcyBmYWNldHRlcyBldCBmaWx0cmVzICh2dWUgZGUgbCdpbnRlcmZhY2UpIC0gcGVyZCBjZSBxdWkgbidhcHBhcmFpdCBwYXMgZGFucyBsZSBgRMOpZmFpcmUvUmVmYWlyZWAuDQoNCi0gTCfDqWRpdGlvbiBkaXJlY3RlIGRhbnMgbGVzIGNlbGx1bGVzIGFwcGFyYWl0IGRhbnMgbCdoaXN0b3JpcXVlIG1haXMgbmUgcGV1dCDDqnRyZSBleHBvcnTDqWUuICANCg0KLSBGYWNldHRlcyBldCBmaWx0cmVzIHMnZW5yZWdpc3RyZW50IGdyw6JjZSBhdSBgcGVybWFsaWVuYC4gIA0KDQo8L2JyPg0KDQoqKioNCg0KDQojIDYuIE1lbnUgZXQgZm9uY3Rpb25zDQoNCk9wZW4gUmVmaW5lIHBlcm1ldCBkZSB0cmF2YWlsbGVyIGRlICoqZGV1eCBmYcOnb25zKio6ICANCg0KDQoxLiBBdmVjIGwnZW5zZW1ibGUgZGVzICoqZm9uY3Rpb25zIGF1dG9tYXRpc8OpZXMqKiBxdWUgbCdvbiByZXRyb3V2ZSBkYW5zIGxlcyBtZW51cy4NCg0KMi4gRW4gcsOpZGlnZWFudCBzZXMgcHJvcHJlcyBbZXhwcmVzc2lvbnNdKGh0dHBzOi8vZG9jcy5vcGVucmVmaW5lLm9yZy9tYW51YWwvZXhwcmVzc2lvbnMpIGF2ZWMgbGUgKipsYW5nYWdlIEdSRUwqKi4gIA0KDQo8L2JyPg0KDQojIyA2LjEuIFV0aWxpc2VyIGxlcyBmb25jdGlvbnMgYXV0b21hdGlzw6llczoNCg0KLSBMZSBtZW51IGV0IGwnZW5zZW1ibGUgZGUgc2VzIGZvbmN0aW9ucyBhdXRvbWF0aXPDqWVzIGFwcGFyYWlzc2VudCBlbiBjbGlxdWFudCBzdXIgbGEgZmzDqGNoZSBkZSBsJ2ludGl0dWzDqSBkZSBjaGFxdWUgY29sb25uZS4NCg0KLSBMZXMgZm9uY3Rpb25zIGRpc3BvbmlibGVzIHNvdXMgbGUgbWVudSBkZSBsYSBwcmVtacOocmUgY29sb25uZSBgVG91dGVzYCBzZSBkaXN0aW5ndWVudCBkZXMgYXV0cmVzIHB1aXNxdSdlbGxlcyBwZXJtZXR0ZW50IGQnYXBwbGlxdWVyIGRlcyBmb25jdGlvbnMgw6AgbCdlbnNlbWJsZSBkZXMgY29sb25uZXMgZHUgZmljaGllcjogTWFycXVlciwgw6l0b2lsZXIsIHN1cHByaW1lciwgbWFzcXVlci4uLg0KDQo8L2JyPg0KDQoqKk1lbnUgZXQgZm9uY3Rpb25zIGRlIGNoYXF1ZSBjb2xvbm5lLXZhcmlhYmxlKioNCg0KDQohW10oaW1hZ2VzL09SMTIuanBnKXt3aWR0aD05MCV9DQoNCjwvYnI+DQoNCioqTWVudSBldCBmb25jdGlvbnMgZGUgbGEgY29sb25uZSBgVG91dGVzYCoqDQoNCiFbXShpbWFnZXMvT1IyMS5qcGcpe3dpZHRoPTkwJX0NCg0KPC9icj4NCg0KKioqDQoNCiMjIDYuMi4gw4ljcmlyZSBzZXMgZm9uY3Rpb25zIGF2ZWMgR1JFTA0KDQo8L2JyPg0KDQpFeHByZXNzaW9ucyBzaW1pbGFpcmVzIGF1eCBmb3JtdWxlcyBFeGNlbCBtYWlzIHF1aSBzJ2FwcGxpcXVlbnQgYXV4IGNvbG9ubmVzLCBub24gYXV4IGNlbGx1bGVzLCBldCBxdWkgbmUgc29udCBwYXMgc3RvY2vDqWVzIMOgIG3Dqm1lIGxlcyBkb25uw6llcyBtYWlzIGRhbnMgdW4gc2NyaXB0LiAgDQoNCjwvYnI+DQoNCiFbXShpbWFnZXMvT1IxNC5qcGcpDQoNCg0KDQoqKkxlIGxhbmdhZ2UgR1JFTCBzJ3V0aWxpc2UgZGFucyBkZXMgZmVuw6p0cmVzIGRlIHN5bnRheGUgYWNjZXNzaWJsZXMgw6AgcGFydGlyIGRlIGRpZmbDqXJlbnRlcyBmb25jdGlvbnMgc3VyIGwnaW50ZXJmYWNlIDoqKiAgDQoNCi0gRW4gY3LDqWFudCBkZXMgZmFjZXR0ZXMgcGVyc29ubmFsaXPDqWVzIDogYEZhY2V0dGUgLT4gRmFjZXR0ZSB0ZXh0dWVsbGUgcGVyc29ubmFsaXPDqWVgLiAgDQoNCi0gRW4gdHJhbnNmb3JtYW50IHVuZSBjb2xvbm5lOiBgw4lkaXRlciBsZXMgY2VsbHVsZXMgLT4gdHJhbnNmb3JtZXJgIChhdXNzaSBzb3VzIGBUb3V0ZXMgLT4gVHJhbnNmb3JtZXJgKS4gIA0KDQotIEVuIGNyw6lhbnQgdW5lIG5vdXZlbGxlIGNvbG9ubmU6IGDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gQWpvdXRlciB1bmUgY29sb25uZSBiYXPDqWUgc3VyIGNldHRlIGNvbG9ubmVgLiAgDQoNCi0gRW4gw6lkaXRhbnQgbGEgc3ludGF4ZSBkZXMgZm9uY3Rpb25zIGF1dG9tYXRpc8OpZXMgKGJvdXRvbiBgY2hhbmdlcmAgZGFucyBsZXMgZmFjZXR0ZXMpLiAgDQoNCjwvYnI+DQoNCi0+IFBvdXIgZGVzIGZpbHRyZXMgZXQgZGVzIHRyYW5zZm9ybWF0aW9ucyBwbHVzIGNvbXBsZXhlcywgR1JFTCBwZXJtZXQgbCd1dGlsaXNhdGlvbiBkJ1tleHByZXNzaW9ucyByw6lndWxpw6hyZXMgKHJlZ2V4KV0oaHR0cHM6Ly9yZWdleDEwMS5jb20vKSoqDQoNCjwvYnI+DQoNCioqKg0KDQoNCiMjIDYuMy4gVHJpZXIgdW4gZmljaGllcg0KDQotIExlcyBkb25uw6llcyBhcHBhcmFpc3NlbnQgZGFucyBsJ29yZHJlIGR1IGZpY2hpZXIgb3JpZ2luYWwuDQotIFBvdXIgbW9kaWZpZXIgbCdvcmRyZSBkJ2FwcGFyaXRpb24gZGVzIG9ic2VydmF0aW9ucywgYXBwbGlxdWVyIHVuIG91IGRlcyB0cmlzIHN1ciBsZXMgY29sb25uZXMgYXZlYyBgVHJpZXIuLi5gDQotIFBvdXIgY29tYmluZXIgcGx1c2lldXJzIHRyaXMgc3VyIGRpZmbDqXJlbnRlcyBjb2xvbm5lczogRmFpcmUgdW4gdHJpZSBzdXIgdW5lIGNvbG9ubmUgcHVpcyBzdXIgdW5lIGF1dHJlIGVuIG1vZGlmaWFudCBzaSBuw6ljZXNzYWlyZSBsJ29wdGlvbiBgVHJpZXIgc2Vsb24gY2V0dGUgc2V1bGUgY29sb25uZWAuDQotIExlcyB0cmlzIG5lIHNvbnQgcXVlIHRlbXBvcmFpcmVzIGV0IG4nYWZmZWN0ZW50IGRvbmMgcXVlIGwnYWZmaWNoYWdlLiBQb3VyIHF1J2lscyBzb2llbnQgcGVybWFuZW50cyAocmVudW3DqXJvdGF0aW9uIGRlcyBsaWduZXMpOiBgVHJpZXIgLT4gUmV0cmllciBsZXMgbGlnbmVzIGRlIGZhw6dvbiBwZXJtYW5lbnRlYCouICANCi0gSWwgZXN0IHBvc3NpYmxlIGRlIHN1cHByaW1lciBldCBkJ2ludmVyc2VyIGxlIHRyaSDDoCBwYXJ0aXIgZGVzIG9wdGlvbnMgc3VyIGNoYXF1ZSBjb2xvbm5lIG91IGdyw6JjZSDDoCBsYSBmb25jdGlvbiBgVHJpZXJgIGR1IGhhdXQuICANCg0KICpMZSB0cmkgcGVybWFuZW50IGFmZmVjdGUgdG91dCBsZSBmaWNoaWVyLCBwYXMgc2V1bGVtZW50IGxhIHZ1ZSBmaWx0csOpZS4gIA0KDQohW10oaW1hZ2VzL09SNi5qcGcpIA0KDQojIyBFeGVyY2ljZQ0KDQo8ZGl2IGNsYXNzID0gImJveDEiPg0KLSBUcmllciBsZXMgdmFsZXVycyBkZSBsYSBjb2xvbm5lIGBKb3VyIGNhbGVuZGFpcmVgIGVuIGZvcm1hdCBgZGF0ZSBhbnTDqWNocm9ub2xvZ2lxdWVgLiAgDQotIFF1ZWxsZSBlc3QgbGEgZGVybmnDqHJlIGRhdGUgZCdpbmNpZGVudCBlbnJlZ2lzdHLDqWUgZGFucyBsZSBmaWNoaWVyID8gIA0KLSBTdXBwcmltZXIgbGUgdHJpLiAgDQo8L2Rpdj4NCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAiYm94MSI+DQotIFRyaWVyIGxlcyB2YWxldXJzIGRlcyBjZWxsdWxlcyBjb21tZSB0ZXh0ZSBkZSBsYSBjb2xvbm5lIGBNb2lzIENhbGVuZHJpZXJgIC4gICANCi0gVHJpZXIgbGVzIHZhbGV1cnMgZGVzIGNlbGx1bGVzIGNvbW1lIHRleHRlIGRlIGxhIGNvbG9ubmUgYEpvdXIgZHUgbW9pc2AuICANCi0gRXhwbG9yZXIgbGUgcsOpc3VsdGF0Li4uICAgDQotIFN1cHByaW1lciBsZSB0cmkgZXQgcmVjb21tZW5jZXIgbGEgcHJvY8OpZHVyZSBhdmVjIHVuIHRyaSBkZSBmb3JtYXQgbm9tYnJlLiAgDQo8L2Rpdj4NCg0KPC9icj4NCg0KKioqDQoNCg0KIyMgNi40LiBGaWx0cmVyIGxlIHRleHRlDQoNCi0gTGEgZm9uY3Rpb24gYEZpbHRyZXIgbGUgdGV4dGVgIHBlcm1ldCBkZSBjaGVyY2hlciB1bmUgb3UgZGVzIGNoYWluZXMgZGUgY2FyYWN0w6hyZXMgZGFucyB1bmUgb3UgcGx1c2lldXJzIHZhcmlhYmxlcy4gIA0KLSBQZXJtZXQgZGUgcmVjaGVyY2hlciBkZXMgY2hhaW5lcyBkZSBjYXJhY3TDqHJlcyBkYW5zIHVuZSBjb2xvbm5lIGV0IGRlIGNvbWJpbmVyIGRlcyBmaWx0cmVzIGFwcGxpcXXDqXMgc3VyIHBsdXNpZXVycyBjb2xvbm5lcyBwb3VyIHJhZmZpbmVyIGxhIHJlY2hlcmNoZS4gIA0KLSBGb25jdGlvbiBwbHVzIGV4cMOpZGl0aXZlIHF1ZSBsZXMgZmFjZXR0ZXMgcXVhbmQgb24gbmUgdmV1dCBxdWUgY2hlcmNoZXIgdW5lIGNoYWluZSBkZSBjYXJhY3TDqHJlcy4gIA0KLSBMJ2FmZmljaGFnZSBkZXMgbGlnbmVzIHNlIGxpbWl0ZXJhIGF1IG5vbWJyZSBkZSBjYXMgY29ycmVzcG9uZGFudHMgYXV4IGNyaXTDqHJlcyBkZSByZWNoZXJjaGUgaW5zY3JpdHMgZGFucyBsZXMgYm9pdGVzIGRlIGZpbHRyZXMuICANCi0gKipUYW50IHF1ZSBsZXMgZmlsdHJlcyBzZXJvbnQgYWN0aWZzLCBsZXMgYWN0aW9ucyBzdWJzw6lxdWVudGVzIHNlIGxpbWl0ZXJvbnQgw6AgY2VzIGNhcyBmaWx0csOpcy4qKiAgDQoNCiFbXShpbWFnZXMvT1I3LmpwZykgDQoNCiMjIEV4ZXJjaWNlDQoNCjxkaXYgY2xhc3MgPSAiYm94MSI+DQoNCioqTGltaXRlciBsYSBsaXN0ZSBhdXggY2FzIHN1cnZlbnVzIMOgIGxhIHN0YXRpb24gQmVycmkgZW50cmUgbWlkaSBldCAxM2guKiogIA0KDQotIEZpbHRyZXIgbGUgdGV4dGUgc3VyIGxhIGNvbG9ubmUgKkNvZGUgZGUgbGlldSo6ICJiZXJyaSIgIA0KLSBGaWx0cmVyIGxlIHRleHRlIHN1ciBsYSBjb2xvbm5lICpIZXVyZSBkZSBsJ2luY2lkZW50KjogIjEyIiAgDQotIEV4cGxvcmVyIGxlcyByw6lzdWx0YXRzICANCi0gQ29tbWVudCBzJ2Fzc3VyZXIgZCdhdm9pciBzZXVsZW1lbnQgbGVzIGNhcyBzdXJ2ZW51cyBlbnRyZSAxMmggZXQgMTNoPyBDb21iaWVuIGRlIGxpZ25lcyBjb3JyZXNwb25kZW50IMOgIGNlcyBjb25kaXRpb25zP15bMTI6IG91IGV4cHJlc3Npb24gcmF0aW9ubmVsbGUgXjEyIC8gNDggY2FzXSAgDQotIFN1cHByaW1lciB0b3VzIGxlcyBmaWx0cmVzLg0KPC9kaXY+DQoNCjwvYnI+DQoNCioqKg0KDQoNCiMgNy4gTGVzIGZhY2V0dGVzDQoNCiMjIDcuMSBDYXJhY3TDqXJpc3RpcXVlcw0KDQo8ZGl2IGNsYXNzID0gInJpZ2h0Ij4NCjxpbWcgc3JjPSJpbWFnZXMvT1IzNC5qcGciICB3aWR0aD0iNjAlIiAvPg0KPC9kaXY+DQoNCi0gTGVzIGZhY2V0dGVzIGNvbnN0aXR1ZW50IGxhIG1hcnF1ZSBkZSBjb21tZXJjZSBkJ09wZW5SZWZpbmUsIGQnb8O5IGxlIGxvZ28hIA0KDQotIEZvbmN0aW9ubmFsaXTDqSBwdWlzc2FudGUgcXVpIHBlcm1ldCBkJ2V4cGxvcmVyIGV0IGRlIGZpbHRyZXIgc2VzIGRvbm7DqWVzIGVuIGZvbmN0aW9uIGRlIGRpZmbDqXJlbnRlcyBjb25kaXRpb25zLiAgDQoNCi0gTidhZmZlY3RlbnQgcGFzIGRpcmVjdGVtZW50IGxlcyBkb25uw6llcywgc2V1bGVtZW50IGxhIHByw6lzZW50YXRpb24uICANCg0KLSDDgCBsYSBiYXNlLCB1bmUgZmFjZXR0ZSBjb3JyZXNwb25kIMOgIGxhIGxpc3RlIGRlcyB2YWxldXJzIHBvc3NpYmxlcyBkJ3VuZSB2YXJpYWJsZSAgKGV0IGRlIGxldXIgb2NjdXJyZW5jZSkgcHLDqXNlbnTDqWUgc2Vsb24gbGUgZm9ybWF0IChjaGFpbmUsIG51bcOpcmlxdWUsIGRhdGUpLiAgDQoNCi0gUGVybWV0dGVudCB1bmUgZXhwbG9yYXRpb24gZXQgbWFuaXB1bGF0aW9uIGRlcyB2YWxldXJzIHBvc3NpYmxlcyBldCBkZSBsZXVycyBjYXMgY29ycmVzcG9uZGFudHMgcGx1cyDDqWxhYm9yw6llcyBxdWUgbGVzIGZpbHRyZXMuICANCg0KLSBPbiBwZXV0IGFpbnNpIGlkZW50aWZpZXIgbGVzIHRlbmRhbmNlcywgbGVzIHLDqWd1bGFyaXTDqXMsIGxlcyBlcnJldXJzLCBsZXMgw6ljYXJ0cywgbGVzIHLDqXDDqXRpdGlvbnMgZXQgIGNpYmxlciBsZXMgdmFsZXVycyBkZSBzb3VzLWdyb3VwZXMgcHLDqWNpcy4gIA0KDQotIENlcyBzb3VzLWdyb3VwZXMgcGV1dmVudCBlbnN1aXRlIMOqdHJlIMOpZGl0w6lzIGV0IGV4cG9ydMOpcyAoYm91dG9uIGBFeHBvcnRlcmAgZW4gaGF1dCDDoCBkcm9pdGUpLiANCg0KPC9icj4NCg0KIyMjIFR5cGVzIGRlIGZhY2V0dGVzOg0KDQogIC0gTGVzIGZhY2V0dGVzIGF1dG9tYXRpc8OpZXMgKipbMV0qKi4gICANCiAgPC9icj4NCiAgLSBMZXMgZmFjZXR0ZXMgcGVyc29ubmFsaXPDqWVzICoqWzJdKiouICANCiAgPC9icj4NCiAgLSBJbCBlc3QgYXVzc2kgcG9zc2libGUgZGUgY3LDqWVyIHNlcyBwcm9wcmVzIGZhY2V0dGVzIGdyw6JjZSBhdSBsYW5nYWdlIEdSRUwgcG91ciBkw6lmaW5pciBkZXMgY29uZGl0aW9ucyBkZSBzw6lsZWN0aW9uL2ZpbHRyZSB0csOocyBwcsOpY2lzZXMgKipbM10qKiAob24gcGFybGUgZW5jb3JlIGljaSBkZSAqZmFjZXR0ZXMgcGVyc29ubmFsaXPDqWVzKiwgbWFpcyBlbGxlcyBkb2l2ZW50IMOqdHJlIHLDqWRpZ8OpZXMgbWFudWVsbGVtZW50KS4NCg0KPC9icj4NCg0KPGNlbnRlcj4gIA0KDQohW10oaW1hZ2VzL09SMjMuanBnKQ0KPC9jZW50ZXI+ICANCg0KPGRpdiBjbGFzcyA9ICJub3RlIj4NCiAgLSAqKls4XSoqIExlIGxpZW4gYGNoYW5nZXJgIHBlcm1ldCBkJ291dnJpciB1bmUgKipmZW7DqnRyZSBkJ8OpZGl0aW9uIEdSRUwqKiBwb3VyIG1vZGlmaWVyIGxhIHN5bnRheGUgZGUgbGEgZmFjZXR0ZS4gIA0KICAtICoqWzldKiogUG91ciBzdXBwcmltZXIgbGVzIGZhY2V0dGVzLCBjbGlxdWVyIHN1ciBsZSB4IGRlIGNoYXF1ZSBmZW7DqnRyZSBvdSBgVG91dCBzdXBwcmltZXJgLiAgDQogIC0gUG91ciBjb25zZXJ2ZXIgbGVzIGZlbsOqdHJlcyBtYWlzIHN1cHByaW1lciBsZXMgc8OpbGVjdGlvbnMgcXVpIHkgb250IMOpdMOpIGZhaXRlcywgY2xpcXVlciBzdXIgYHLDqWludGlhbGlzZXJgIHN1ciBjaGFxdWUgZmVuw6p0cmUgb3UgYFRvdXQgcsOpaW5pdGlhbGlzZXJgICoqWzldKiouICANCiAgLSAqKlsxMF0qKiBPcHRpb24gYEdyb3VwZWA6IE91dGlscyBwcm9wb3NhbnQgZGlmZsOpcmVudHMgYWxnb3JpdGhtZXMgZGUgc2ltaWxhcml0w6kgcGVybWV0dGFudCBkZSByZWdyb3VwZXIgZGVzIGNhdMOpZ29yaWVzIHNlbWJsYWJsZXMuICANCjwvZGl2PiANCg0KIyMjIEZvcm1hdHMgZGUgZmFjZXR0ZXM6DQoNCk9uIHJldHJvdXZlIMOpZ2FsZW1lbnQgZGlmZsOpcmVudHMgKipmb3JtYXRzIGRlIGZhY2V0dGVzKiogLT4gdW5lIHBvdXIgY2hhcXVlIGZvcm1hdCBkZSBkb25uw6llcyAoTGVzIGZhY2V0dGVzIHBlcnNvbm5hbGlzw6llcyBwcm9wb3NlbnQgYXVzc2kgZGVzIGZhY2V0dGVzIGJvb2zDqWVubmVzKS4gICANCg0KDQojIyMjIDEuIEZhY2V0dGUgdGV4dHVlbGxlICoqWzQtNV0qKiANCg0KLSBUeXBlIGRlIGZhY2V0dGUgbGUgcGx1cyBzb3V2ZW50IHV0aWxpc8OpLiAgIA0KLSBSZWdyb3VwZW50IGRhbnMgbGEgZmVuw6p0cmUgZGUgZ2F1Y2hlIGxlcyB2YWxldXJzIGRpc3RpbmN0ZXMgKHRleHR1ZWxsZXMgb3UgbnVtw6lyaXF1ZXMpIGRlcyBjb2xvbm5lcyB2b3VsdWVzLiAgIA0KICAtIE9uIHBldXQgZmFpcmUgdW5lIGZhY2V0dGUgdGV4dHVlbGxlIHN1ciB1bmUgY29sb25uZSBudW3DqXJpcXVlIG1haXMgcGFzIGwnaW52ZXJzZS4gIA0KICAtIDIwMDAgdmFsZXVycyBtYXhpbXVtIHBhciBkw6lmYXV0IG1haXMgcGV1dCDDqnRyZSBtb2RpZmnDqSBkYW5zIGxlcyBwcsOpZsOpcmVuY2VzLiBTaSBsZXMgdmFsZXVycyBzb250IHRyb3Agbm9tYnJldXNlcywgZWxsZXMgbmUgc2Vyb250IHBhcyBsaXN0w6llcyAodW4gZmlsdHJlIHBvdXJyYWl0IMOqdHJlIHV0aWxpc8OpKS4gDQotIFBlcm1ldHRlbnQgZGUgY29tYmluZXIgZGlmZsOpcmVudHMgZmlsdHJlcyBlbiBzw6lsZWN0aW9ubmFudCBkaWZmw6lyZW50ZXMgdmFsZXVycyBkJ3VuZSBvdSBwbHVzaWV1cnMgdmFyaWFibGVzIChldCBsZXVycyBjYXMgY29ycmVzcG9uZGFudHMpLiAgIA0KICAtIENsaXF1ZXIgYGluY2x1cmVgIG91IGBleGNsdXJlYCBwb3VyIHPDqWxlY3Rpb25uZXIgb3Ugc3VwcHJpbWVyIGRlcyBjaG9peCBtdWx0aXBsZXMgKipbMTJdKiouICAgDQogIC0gVW5lIGZvaXMgbGEgc8OpbGVjdGlvbiBmYWl0ZSwgbCdvcHRpb24gYGludmVyc2VyYCBwZXJtZXQgZGUgc8OpbGVjdGlvbm5lciB0b3V0IFNBVUYgbGEgc8OpbGVjdGlvbiAqKlsxMV0qKi4gICANCiAgLSBQZXV2ZW50IMOqdHJlIHRyacOpZXMgc2Vsb24gbGUgbm9tIG91IGxlIGNvbXB0ZSAobm9tYnJlIGQnb2NjdXJyZW5jZXMpLiAgIA0KLSBQZXJtZXR0ZW50ICoqZOKAmcOpZGl0ZXIgbGVzIHZhbGV1cnMqKiAoY29udGVudSBkZSBjaGFxdWUgY2VsbHVsZSBjb3JyZXNwb25kYW50ZSkgKipbMTNdKiouICANCg0KDQojIyMjIDIuIEZhY2V0dGUgbnVtw6lyaXF1ZSAqKls3XSoqDQoNCi0gVmlzdWFsaXNlciBldCBzw6lsZWN0aW9ubmVyIGxlcyB2YWxldXJzIGTigJl1bmUgdmFyaWFibGUgbnVtw6lyaXF1ZSBhbGxhbnQgZGUgbGEgcGx1cyBwZXRpdGUgw6AgbGEgcGx1cyBncmFuZGUuICANCg0KDQojIyMjIDMuIEZhY2V0dGUgY2hyb25vbG9naXF1ZSAqKls2XSoqDQoNCi0gVmlzdWFsaXNlciBldCBzw6lsZWN0aW9ubmVyIGxlcyB2YWxldXJzIGTigJl1bmUgY29sb25uZSBkYXRlIGVuIGxpZ25lIGR1IHRlbXBzLiAgDQoNCg0KPC9icj4NCg0KIyMgRXhlcmNpY2UNCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KKipGaWx0cmVyKiogDQoNCi0gRXhwbG9yZXIgbGVzIHZhbGV1cnMgZGUgbGEgdmFyaWFibGUgKkNhdXNlIHByaW1haXJlKi4gUXVlbGxlIGVzdCBsYSBkZXV4acOobWUgcGx1cyBmcsOpcXVlbnRlPyANCi0gUXVlbGxlcyBzb250IGxlcyBjYXTDqWdvcmllcyBkZSAqQ2F1c2Ugc2Vjb25kYWlyZSogcmVsacOpZXMgw6AgbGEgKkNhdXNlIHByaW1haXJlICJDbGllbnTDqGxlIio/ICAgDQotIFF1ZWxsZSBlc3QgbGEgcGx1cyBmcsOpcXVlbnRlPyBTw6lsZWN0aW9ubmVyIGNldHRlIHZhbGV1ci4gQ29tYmllbiBkZSBjYXMgY29ycmVzcG9uZGVudCDDoCBjZXR0ZSBzw6lsZWN0aW9uPyAgDQotIMOAIHF1ZWwgKmpvdXIgZGUgbGEgc2VtYWluZSogY2V0dGUgY2F1c2UgZXN0LWVsbGUgc3VydmVudWUgbGUgcGx1cyBzb3V2ZW50P15bQ2xpZW50w6hsZSAvIEJsZXNzw6llIG91IG1hbGFkZSwgTcOpZmFpdCB2b2xvbnRhaXJlLCBOdWlzYW5jZSBpbnZvbG9udGFpcmUgLyBNw6lmYWl0IHZvbG9udGFpcmUgNzgxLyA1XSAgIA0KLSBSw6lpbml0aWFsaXNlciB0b3V0ZXMgbGVzIGZhY2V0dGVzLg0KDQoqKsOJZGl0ZXIqKiAgDQoNCi0gRGFucyBsYSBmYWNldHRlICpDYXVzZSBwcmltYWlyZSosIHJlbm9tbWVyIGxhIHZhbGV1ciAiYXV0cmUiIHBvdXIgcXUnZWxsZSBzb2l0IGZ1c2lvbm7DqWUgw6AgbGEgdmFsZXVyICJBdXRyZXMiLiAgDQotIFN1cHByaW1lciB0b3V0ZXMgbGVzIGZhY2V0dGVzLg0KPC9kaXY+DQoNCjwvYnI+DQoNCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCioqRmlsdHJlcioqIA0KDQotIFF1ZWwgZXN0IGxlICpzeW1wdG9tZSogbGUgcGx1cyBmcsOpcXVlbnQ/IFPDqWxlY3Rpb25uZXIgY2V0dGUgdmFsZXVyLiAgDQotIENlcyDDqXbDqW5lbWVudHMgb250LWlscyBuw6ljZXNzaXTDqSB1bmUgKsOpdmFjdWF0aW9uKj9eW0NsaWVudMOobGUgLyBMaWduZSBvcmFuZ2UgLyBPdWkgMTddICAgICANCg0KKirDiWRpdGVyKiogIA0KDQotIMOJZGl0ZXIgbGEgdmFyaWFibGUgKsOpdmFjdWF0aW9uKiBkZSBmYcOnb24gw6AgY2UgcXUnaWwgbid5IGFpdCBxdWUgKipkZXV4IHZhbGV1cnMqKiBwb3NzaWJsZXM6IE91aSBldCBOb24uICAgIA0KDQo8L2Rpdj4NCg0KKioqDQoNCg0KIyMgNy4yLiBMZXMgcmVncm91cGVtZW50cyAoY2x1c3RlcmluZykNCg0KLSBGb25jdGlvbiBxdWkgcGVybWV0IGQnaWRlbnRpZmllciBkYW5zIHVuZSBjb2xvbm5lIGxlcyB2YWxldXJzIGRpc3RpbmN0ZXMgcXVpIHBvdXJyYWllbnQgYXZvaXIgbGEgbcOqbWUgc2lnbmlmaWNhdGlvbiBvdSBxdWkgcG91cnJhaWVudCDDqnRyZSByZWdyb3Vww6llcyBkYW5zIHVuZSBtw6ptZSBjYXTDqWdvcmllID0gInZhcmlhdGlvbnMgc3VyIGxlIG3Dqm1lIHRow6htZSIgw6l2YWx1w6llcyBlbiBmb25jdGlvbiBkZSBbZGlmZsOpcmVudHMgYWxnb3JpdGhtZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuUmVmaW5lL09wZW5SZWZpbmUvd2lraS9DbHVzdGVyaW5nLUluLURlcHRoKS4gDQoNCi0gQ2hhcXVlIHN1Z2dlc3Rpb24gZG9pdCDDqnRyZSBhcHByb3V2w6llIGluZGl2aWR1ZWxsZW1lbnQgcG91ciBxdWUgbGVzIG1vZGlmaWNhdGlvbnMgcydhcHBsaXF1ZW50IChsZXMgcmVncm91cGVtZW50cyBwcm9wb3PDqXMgbmUgc29udCBwYXMgbsOpY2Vzc2FpcmVtZW50IHBlcnRpbmVudHMpLg0KDQotIE9wZW5SZWZpbmUgcHJvcG9zZSBkZXMgKmNsdXN0ZXJzKiBzZWxvbiBkaWZmw6lyZW50ZXMgbcOpdGhvZGVzIHBsdXMgb3UgbW9pbnMgw6lsYWJvcsOpZXMgKCpQcm9jaGUgdm9pc2luKiBwcmVuZCBwbHVzIGRlIG3DqW1vaXJlKSBxdWkgcGVybWV0dGVudCBkZSByZWdyb3VwZXIgbGVzIHZhbGV1cnMgc2ltaWxhaXJlcyBldCBwcm9wb3NlbnQgZGVzIG1hdGNocyBwb3NzaWJsZXMgKCpmdXp6eSBtYXRjaGluZyopOiBwYXIgZXhlbXBsZSAqZW1wcmVpbnRlKiBlc3QgcGx1cyBjb25zZXJ2YXRldXIgKGRpc3Rpbmd1ZSBjYXNzZSwgZXNwYWNlcywgb3JkcmUsIHLDqXDDqXRpdGlvbiwgcG9uY3R1YXRpb24uLi4pLCAqbmdyYW0qIGVzdCBwbHVzIGZsZXhpYmxlIChtw6ptZXMgY2FyYWN0w6hyZXMpLCAqTWV0YXBob25lMyogZXN0IGxlIHBsdXMgImxpYsOpcmFsIiAobcOqbWUgcHJvbm9uY2lhdGlvbikuDQoNCiMjIEV4ZXJjaWNlDQoNCjxkaXYgY2xhc3MgPSAiYm94MSI+DQotIENyw6llciB1bmUgZmFjZXR0ZSB0ZXh0dWVsbGUgc3VyIGxhIGNvbG9ubmUgKkNvZGUgZGUgbGlldSouICANCi0gQ2xpcXVlciBzdXIgYEdyb3VwZWAgZXQgZXhwbG9yZXIgbGVzIHJlZ3JvdXBlbWVudHMgZW4gZm9uY3Rpb24gZGVzIGRpZmbDqXJlbnRzIGFsZ29yaXRobWVzLiAgDQo8L2Rpdj4NCg0KKioqDQoNCg0KIyMgNy4zLiBMZXMgZmFjZXR0ZXMgcGVyc29ubmFsaXPDqWVzIA0KDQoNCi0gRm9uY3Rpb25uZW50IGNvbW1lIGRlcyBmYWNldHRlcyBhdXRvbWF0aXPDqWVzIHNhdWYgcXUnb24gbmUgcGV1dCDDqWRpdGVyIGVuIGZvbmN0aW9uIGRlIGNlcyByw6lzdWx0YXRzIGNhciBlbGxlcyBwcsOpc2VudGVudCBkZXMgZG9ubsOpZXMgbW9kaWZpw6llcyBlbiBtw6ltb2lyZS4NCg0KLSBPbnQgw6l0w6kgZMOpdmVsb3Bww6llcyBldCBhdXRvbWF0aXPDqWVzIGFmaW4gZCdleHBsb3JlciBkZXMgYXNwZWN0cyBwcsOpY2lzIGRlcyBkb25uw6llcyBzYW5zIGF2b2lyIMOgIGxlcyAgcsOpZGlnZXIgZW4gc3ludGF4ZSBHUkVMOiANCg0KICAtIGBGYWNldHRlIHBhciBtb3RgIDogRGl2aXNlIGNoYXF1ZSBtb3QgKHPDqXBhcsOpIGQndW4gZXNwYWNlKSBkJ3VuZSBjb2xvbm5lIGV0IGxlcyBwcsOpc2VudGUgZW4gbGlzdGUgZGUgdmFsZXVycyBkaXN0aW5jdGVzIFt2YWx1ZS5zcGxpdCgiICIpXS4NCiAgDQogIC0gYEZhY2V0dGUgZG91YmxvbnNgOiB2YWxldXJzIGJvb2zDqWVubmVzIGluZGlxdWFudCBzaSBsZXMgdmFsZXVycyBzb250IHVuaXF1ZXMgKGZhbHNlKSBvdSBub24gKHRydWUpIFtmYWNldENvdW50KHZhbHVlLCAndmFsdWUnLCAnU3ltcHRvbWUnKSA+IDFdLiAgDQogIA0KICAtIGBGYWNldHRlcyBsb2dhcml0aG1pcXVlc2A6IG1vZGlmaWNhdGlvbiBsb2dhcml0aG1pcXVlIGRlIHZhbGV1cnMgbnVtw6lyaXF1ZXMgW3ZhbHVlLmxvZygpXS4NCiAgDQogIC0gYEZhY2V0dGUgbG9uZ3VldXIgZGUgdGV4dGVgOiBsaXN0ZSBsZSBub21icmUgZGUgY2FyYWN0w6hyZXMgZHUgY29udGVudSBkZXMgY2VsbHVsZXMgZCd1bmUgY29sb25uZSBbdmFsdWUubGVuZ3RoKCldLg0KICANCiAgLSBGYWNldHRlcyBwZXJtZXR0YW50IGQnZXhwbG9yZXIgbGVzIHZhbGV1cnMgZCdgZXJyZXVyYCwgYG51bGxlc2AsIGB2aWRlc2AuLi4gW2lzRW1wdHlTdHJpbmcodmFsdWUpXQ0KDQoqKiogDQoNCiMgOC4gIFRyYW5zZm9ybWF0aW9ucw0KDQotIE9wZW5SZWZpbmUgcGVybWV0IGQnZXhwbG9yZXIgbWFpcyBhdXNzaSBkZSBtb2RpZmllciBzZXMgZG9ubsOpZXMgc2FucyBhdm9pciDDoCB0b3VjaGVyIGF1IGNvbnRlbnUgZGUgY2VsbHVsZXMgbWFudWVsbGVtZW50LiAgDQoNCi0gQ29tbWUgcG91ciBsZXMgZmFjZXR0ZXMsIGxlcyBmb25jdGlvbnMgZGUgdHJhbnNmb3JtYXRpb24gcGV1dmVudCBzZSBmYWlyZSBkZSBkZXV4IGZhw6dvbnM6ICAgIA0KDQogIDEuIFRyYW5zZm9ybWF0aW9ucyBhdXRvbWF0aXPDqWVzIChgVHJhbnNmb3JtYXRpb25zIGNvdXJhbnRlc2ApICoqWzJdKio6IGZvbmN0aW9ucyBwZXJtZXR0YW50IGQnYXBwbGlxdWVyIGRlcyBtb2RpZmljYXRpb25zIGNvdXJhbnRlcyBzdXIgbGUgZm9ybWF0IGV0IGxhIHN0cnVjdHVyZSBkZXMgY2VsbHVsZXMvY29sb25uZXMuICANCiAgDQogIDIuIFRyYW5zZm9ybWF0aW9ucyBtYW51ZWxsZXMgZGFucyBsYSBmZW7DqnRyZSBHUkVMICoqWzFdKiogYWZpbiBkJ2FsbGVyIGJlYXVjb3VwIHBsdXMgbG9pbi4gIA0KICANCg0KIVtdKGltYWdlcy9PUjI0LmpwZykNCg0KDQo8ZGl2IGNsYXNzID0gIm5vdGUiPg0KUG91ciB2b2lyIGxhIHN5bnRheGUgY29ycmVzcG9uZGFudCDDoCBjaGFxdWUgZm9uY3Rpb24gZGUgYHRyYW5zZm9ybWF0aW9ucyBjb3VyYW50ZXNgLCBhcHBsaXF1ZXIgbGEgZm9uY3Rpb24gc3VyIHVuZSBjb2xvbm5lIHB1aXMgYWxsZXIgdm9pciBsJ2hpc3RvcmlxdWUuIFBhciBleGVtcGxlOiBgdmFsdWUudG9OdW1iZXIoKWAsIGB2YWx1ZS50b1RpdGxlY2FzZSgpYCwgYHZhbHVlLnRvTnVtYmVyKClgLCBgdmFsdWUudG9VcHBlcmNhc2UoKWAsIGB2YWx1ZS50cmltKClgLi4uIDwvZGl2Pg0KDQoqKiogDQoNCg0KIyMgOC4xLiBEaXZpc2VyIGxlIGNvbnRlbnUgZGUgY2VsbHVsZXMgbXVsdGl2YXJpw6llcw0KDQotICoqRGV1eCBvcHRpb25zOiAqKiAgDQogIDEuIEVuIGRpdmlzYW50IGxlIGNvbnRlbnUgZGVzIGNlbGx1bGVzIGVuICoqcGx1c2lldXJzIGNvbG9ubmVzKio6IGDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gRGl2aXNlciBlbiBwbHVzaWV1cnMgY29sb25uZXNgICANCiAgMi4gRW4gZGl2aXNhbnQgbGUgY29udGVudSBzdXIgKipwbHVzaWV1cnMgbGlnbmVzKio6IGDDiWRpdGVyIGxlcyBjZWxsdWxlcyAtPiBEaXZpc2VyIGxlcyBjZWxsdWxlcyBtdWx0aXZhcmnDqWVzYCAgDQoNCjwvYnI+DQoNCiFbXShpbWFnZXMvT1IzNy5qcGcpICANCg0KLSBMYSBwcmVtacOocmUgb3B0aW9uIGVzdCBsYSBwbHVzIGZyw6lxdWVudGUuIA0KLSBMYSBkZXV4acOobWUgb3B0aW9uIGF1cmEgdW4gZWZmZXQgaW1wb3J0YW50IHN1ciBsYSBzdHJ1Y3R1cmUgZGVzIG9ic2VydmF0aW9ucyBwdWlzcXUnZWxsZSBtdWx0aXBsaWVyYSBsZSBub21icmUgZGUgbGlnbmVzIHBhciBjYXMgKGNlIHF1aSBuw6ljZXNzaXRlcmEgZGUgcGFzc2VyIMOgIGxhIHZ1ZSBwYXIgYGVudHLDqWVzYCkuDQoNCiMjIEV4ZXJjaWNlDQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQpVbmlmb3JtaXNlciBldCBkaXZpc2VyIGxlIGNvbnRlbnUgZGUgbGEgdmFyaWFibGUgKkxpZ25lKg0KPC9kaXY+DQo8ZGl2IGNsYXNzID0gImJveDEiPg0KKipVbmlmb3JtaXNlciBsZSBub20gZGVzIGxpZ25lczoqKiAgDQoNCi0gQ3LDqWVyIHVuZSBmYWNldHRlIHN1ciBsYSBjb2xvbm5lIExpZ25lLiANCg0KLSBEZXV4IHByb2Jsw6htZXMgc2UgcG9zZW50OiAxKSBsZXMgbm9tcyBkZSBsaWduZXMgbm9uIHVuaWZvcm1lcyBldCAyKSBsZXMgdmFsZXVycyBtdWx0aXBsZXMuICANCg0KLSBOb3VzIGNob2lzaXNzb25zIGQndW5pZm9ybWlzZXIgbGVzIHZhbGV1cnMgZW4gdXRpbGlzYW50IGxlcyBudW3DqXJvcyBkZSBsaWduZXMgZXQgZW4gc3VwcHJpbWFudCBsZSBtb3QgTGlnbmUuICANCg0KLSBFeHBsb3JlciBldCBhY2NlcHRlciBsZXMgcmVncm91cGVtZW50cyBwcm9wb3PDqXMgYXZlYyBsYSBmb25jdGlvbiBgR3JvdXBlYC4gIA0KDQotIFN1cHByaW1lciBsZSBtb3QgbGlnbmU6ICANCg0KICAtIGDDiWRpdGVyIGxlcyBjZWxsdWxlcyAtPiByZW1wbGFjZXJgIC0+ICJMaWduZSIgcGFyOiBuZSByaWVuIHNhaXNpciBkYW5zIGwnZW5jYWRyw6kuICAgIA0KDQoNCi0gQ2xpcXVlciBlbnN1aXRlIGRpcmVjdGVtZW50IHN1ciBgZWRpdGAgc3VyIHVuZSBjZWxsdWxlIGRlIGxhIGNvbG9ubmUgZGUgKkxpZ25lKiAtPiByZW1hcnF1ZXIgbGEgcHLDqXNlbmNlIGQndW4gZXNwYWNlLCBzdXBwcmltZXIgbCdlc3BhY2UgZXQgZmVybWVyLiANCg0KLSBSYWZyYWljaGlyIGxhIGZhY2V0dGUgZXQgb2JzZXJ2ZXIgbCdpbXBhY3QgLSBsZXMgZXNwYWNlcyBwZXV2ZW50IMOqdHJlIHN1cHByaW3DqXMgZ3LDomNlIMOgIGxhIGZvbmN0aW9uOiBgw4lkaXRlciBsZXMgY2VsbHVsZXMgLT4gVHJhbnNmb3JtYXRpb25zIGNvdXJhbnRlcyAtPiBTdXBwcmltZXIgbGVzIGVzcGFjZXMgZGUgZMOpYnV0IGV0IGRlIGZpbmAuIA0KLSBSZW1wbGFjZXIgbGVzIGNvdWxldXJzIGRlIGxpZ25lIHBhciBsZXVyIG51bcOpcm8gZGlyZWN0ZW1lbnQgZGFucyBsYSBmYWNldHRlLiAgIA0KPC9kaXY+DQoNCg0KDQo8ZGl2IGNsYXNzID0gImJveDEiPg0KKipEaXZpc2VyIGxlIGNvbnRlbnUgZGVzIGNlbGx1bGVzIGVuIGNyw6lhbnQgZGVzIGNvbG9ubmVzIGF2ZWMgdW5lIHNldWxlIHZhbGV1ciAgKioNCg0KLSBEYW5zIGxhIGZhY2V0dGUsIHJlbXBsYWNlciBsZXMgIi0iIHBhciBkZXMgIiwiLiAgICANCg0KLSBgw4lkaXRlciBsYSBjb2xvbm5lIC0+IERpdmlzZXIgZW4gcGx1c2lldXJzIGNvbG9ubmVzYDoNCiAgLSBEw6lmaW5pciBsZSBzw6lwYXJhdGV1ciAiLCIgKGNlbHVpLWNpIGRpc3BhcmFpdHJhKS4gIA0KICAtIETDqWNvY2hlciBsZXMgb3B0aW9ucyAiRGV2aW5lciIgZXQgIlN1cHByaW1lciIuICANCi0gTGVzIG5vdXZlbGxlcyBjb2xvbm5lcyByZXByZW5kcm9udCBsZSBub20gZGUgbCdvcmlnaW5hbCBudW3DqXJvdMOpLiBMZXMgcmVub21tZXI6IHByZW1pZXJlLCBkZXV4aWVtZSwgdHJvaXNpZW1lLCBxdWF0cmllbWUuICANCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KRGl2aXNlciBwYXIgbGVzIGxvbmd1ZXVycyBkZSBjaGFtcHMgbGEgY29sb25uZSAqTnVtw6lybyBkJ2luY2lkZW50KiBwb3VyIGVuIGNyw6llciBkZXV4IG5vdXZlbGxlczogIA0KICAxLiBVbmUgY29sb25uZSBjb250ZW5hbnQgbGUgcHJlbWllciBjYXJhY3TDqHJlIGluZGlxdWFudCBsZSB0eXBlIGQnaW5jaWRlbnQsIHNvaXQgVCAodHJhaW4pIG91IFMgKHNlcnZpY2UpLiAgDQogIDIuIFVuZSBjb2xvbm5lIGNvbnRlbmFudCBsJ2Vuc2VtYmxlIGRlcyBjYXJhY3TDqHJlcyBudW3DqXJpcXVlcyBpbmRpcXVhbnQgbGUgbnVtw6lybyBkJ2luY2lkZW50LiAgDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQoqKlbDqXJpZmljYXRpb25zIHByw6lhbGFibGVzOioqDQogIDEuIFbDqXJpZmllciBxdSdpbCBuJ3kgYSBwYXMgZGUgZG91YmxvbiBkYW5zIGNldHRlIGNvbG9ubmU6IGBGYWNldHRlcyBwZXJzb25uYWxpc8OpZXMgLT4gRmFjZXR0ZSBkb3VibG9uYCAtPiBRdWVsIGVzdCBsZSBwcm9ibMOobWU/ICBDbGlxdWVyIHN1ciBgQ2hhbmdlcmAgZXQgYW5hbHlzZXIgbCdleHByZXNzaW9uLiAgDQogIDIuIFbDqXJpZmllciBsYSBsb25ndWV1ciBkZSBjaGFxdWUgY2FzOiAgYEZhY2V0dGVzIHBlcnNvbm5hbGlzw6llcyAtPiBGYWNldHRlIGxvbmd1ZXVyIGR1IHRleHRlYC4gICAgDQoNCioqRGl2aXNlciBsYSBjb2xvbm5lOioqICANCi0gYMOJZGl0ZXIgbGEgY29sb25uZSAtPiBEaXZpc2VyIGVuIHBsdXNpZXVycyBjb2xvbm5lcyBzZWxvbiBsZXMgbG9uZ3VldXJzIGRlIGNoYW1wc2AgOiAxLCA4LiAgICANCi0gRMOpY29jaGVyIDogZGV2aW5lciBsZSB0eXBlIGRlIGNlbGx1bGUgZXQgU3VwcHJpbWVyIGNldHRlIGNvbG9ubmUuICAgIA0KLSBSZW5vbW1lciBsZXMgY29sb25uZXMgOiBUeXBlIGV0IElELiAgICANCjwvZGl2Pg0KDQo8L2JyPg0KDQoqKioNCg0KIyMgOC4yLiBGdXNpb25uZXIgbGUgY29udGVudSBkZSBwbHVzaWV1cnMgY29sb25uZXMNCg0KIyMgRXhlcmNpY2UgICANCg0KTm91cyBzb3VoYWl0b25zIGNhbGN1bGVyIGxhIGR1csOpZSBkZXMgaW5jaWRlbnRzIChuw6ljZXNzaXRlIGwndXRpbGlzYXRpb24gZGUgR1JFTCkuIFBvdXIgY2UgZmFpcmUgbm91cyBjcsOpZXJvbnMgZGV1eCBjb2xvbm5lcyBwb3VyIGVuc3VpdGUgY2FsY3VsZXIgbGEgZGlmZsOpcmVuY2UgZW50cmUgbGVzIGRldXg6ICAgIA0KLSAqKlRyYW5zZm9ybWF0aW9uIHNpbXBsZSBhdXRvbWF0aXPDqWUqKjogQ3LDqWVyIHVuZSBub3V2ZWxsZSBjb2xvbm5lIGZ1c2lvbm5hbnQgbGVzIGNvbG9ubmVzOiAqQW5uw6llIGNpdmlsZSosICpNb2lzIGNhbGVuZHJpZXIqLCAqam91cnMgZHUgbW9pcyogZXQgKkhldXJlIGRlIGwnaW5jaWRlbnQqLiAgDQotICoqVHJhbnNmb3JtYXRpb24gYXZhbmPDqWUgR1JFTCoqIChwZXV0IMOqdHJlIHLDqWFsaXPDqWUgZGUgZmHDp29uIGF1dG9tYXRpc8OpZSk6IENyw6llciB1bmUgbm91dmVsbGUgY29sb25uZSBmdXNpb25uYW50IGxlcyBjb2xvbm5lczogKkFubsOpZSBjaXZpbGUqLCAqTW9pcyBjYWxlbmRyaWVyKiwgKmpvdXJzIGR1IG1vaXMqIGV0ICpIZXVyZSBkZSBsJ2luY2lkZW50Ki4gIA0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gIm5vdGUiPg0KTG9yc3F1ZSBsJ29uIGZ1c2lvbm5lIGRlcyBjb2xvbm5lcywgaWwgZmF1dCBwb3J0ZXIgdW5lIGF0dGVudGlvbiBwYXJ0aWN1bGnDqHJlIGF1IHPDqXBhcmF0ZXVyIGNob2lzaS4gTmUgcGFzIHV0aWxpc2VyIHVuIGNhcmFjdMOocmUgcXVpIHBvdXJyYWl0IGZhaXJlIHBhcnRpZSBkdSBjb250ZW51IChleDogLCkgb3UgcXVpIHNlcnZpcmEgw6AgZGl2aXNlciBsZXMgY29sb25uZXMgKC5jc3YpDQo8L2Rpdj4NCg0KPC9icj4NCg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KMS4gKipGb25jdGlvbiBhdXRvbWF0aXPDqWUqKiAtPiBGdXNpb25uZXIgbGVzIGNvbG9ubmVzOiAqQW5uw6llIGNpdmlsZSosICpNb2lzIGNhbGVuZHJpZXIqLCAqam91cnMgZHUgbW9pcyogZXQgKkhldXJlIGRlIGwnaW5jaWRlbnQqDQo8L2Rpdj4NCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCi0gQW5uw6llIGNpdmlsZSAtPiBgw4lkaXRlciBsYSBjb2xvbm5lYCAtPiBgSm9pbmRyZSBsZXMgY29sb25uZXNgLiAgICANCi0gSm9pbmRyZSBkZXMgY29sb25uZXMgLT4gQ29jaGVyIGxlcyBjb2xvbm5lcyB2b3VsdWVzIGV0IGxlcyB0cmllciBzZWxvbiBsJ29yZHJlIHZvdWx1IGRhbnMgbGEgbm91dmVsbGUgdmFsZXVyLiAgDQotIFPDqXBhcmF0ZXVyIGVudHJlIGxlIGNvbnRlbnUgZGUgY2hhcXVlIGNvbG9ubmU6ICItIi4gICAgDQotIMOJY3JpcmUgbGUgcsOpc3VsdGF0IGRhbnMgdW5lIG5vdXZlbGxlIGNvbG9ubmUgbm9tbcOpZTogKkRhdGUqLiAgICANCg0KLSBUcmFuc2Zvcm1lciBlbiBmb3JtYXQgZGF0ZTogYMOJZGl0ZXIgbGVzIGNlbGx1bGVzIC0+IFRyYW5zZm9ybWF0aW9ucyBjb3VyYW50ZXMgLT4gRW4gZGF0ZWAuICAgIA0KPC9kaXY+DQoNCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQoyLiAqKkZlbsOqdHJlIEdSRUwqKiAtPiBGdXNpb25uZXIgbGVzIGNvbG9ubmVzOiAqQW5uw6llIGNpdmlsZSosICpNb2lzIGNhbGVuZHJpZXIqLCAqam91cnMgZHUgbW9pcyogZXQgKkhldXJlIGRlIHJlcHJpc2UqDQo8L2Rpdj4NCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCi0gQW5uw6llIGNpdmlsZSAtPiDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gQWpvdXRlciB1bmUgY29sb25uZSBlbiBmb25jdGlvbiBkZSBjZXR0ZSBjb2xvbm5lOiAgDQoNCmBjZWxsc1siQW5uw6llIGNpdmlsZSJdLnZhbHVlICsgIi0iICsgIjAiICsgY2VsbHNbIk1vaXMgY2FsZW5kcmllciJdLnZhbHVlICsgIi0iICsgIjAiICsgY2VsbHNbIkpvdXIgZHUgbW9pcyJdLnZhbHVlICsgIiAiICsgIGNlbGxzWyJIZXVyZSBkZSBsJ2luY2lkZW50Il0udmFsdWVgLiAgDQoNCi0gVsOpcmlmaWVyIGxhIHRyYW5zZm9ybWF0aW9uIGF2ZWMgdW5lIGZhY2V0dGUgYHZhbHVlLnR5cGUoKWAuICANCg0KLSBSZWNvbW1lbmNlciBsYSBqb2ludHVyZSBwb3VyIGNyw6llciB1bmUgY29sb25uZSBhdmVjIGxhIGRhdGUtaGV1cmUgZGUgZmluIGRlIGwnaW5jaWRlbnQNCmBjZWxsc1siQW5uw6llIGNpdmlsZSJdLnZhbHVlICsgIi0iICsgIjAiICsgY2VsbHNbIk1vaXMgY2FsZW5kcmllciJdLnZhbHVlICsgIi0iICsgIjAiICsgY2VsbHNbIkpvdXIgZHUgbW9pcyJdLnZhbHVlICsgIiAiICsgIGNlbGxzWyJIZXVyZSBkZSBsJ2luY2lkZW50Il0udmFsdWVgLiAgDQoNCi0gVHJhbnNmb3JtZXIgZW4gZm9ybWF0IGRhdGU6IGDDiWRpdGVyIGxlcyBjZWxsdWxlcyAtPiBUcmFuc2Zvcm1hdGlvbnMgY291cmFudGVzIC0+IEVuIGRhdGVgLiAgDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gyIj4NCkNhbGN1bGVyIGxhIGR1csOpZSBkZSBsJ2luY2lkZW50ICANCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KLSBDcsOpZXIgdW5lIG5vdXZlbGxlIGNvbG9ubmUgdmlkZTogIA0KYMOJZGl0ZXIgbGEgY29sb25uZSA+IEFqb3V0ZXIgdW5lIGNvbG9ubmUgZW4gZm9uY3Rpb24gZGUgY2V0dGUgY29sb25uZSBgIC0+IENob2lzaXIgdW4gbm91dmVhdSBub20gZXQgbGUgY29udGVudTogIiIuICANCg0KLSBQb3VyIGNhbGN1bGVyIHVuZSBkaWZmw6lyZW5jZSBlbnRyZSBkYXRlOiBgZGlmZihkYXRlMSwgZGF0ZTIsICJyZXN1bHRzIGZvcm1hdCIpYC4gICAgDQoNCmBkaWZmKGNlbGxzWydkYXRlMiddLnZhbHVlLGNlbGxzWydkYXRlMSddLnZhbHVlLCAnbWludXRlcycpYC4gICANCjwvZGl2Pg0KDQo8L2JyPg0KDQoqKioNCg0KIyA5LiBMZSBsYW5nYWdlIEdSRUwgDQoNCg0KLSAqR29vZ2xlIFJlZmluZSBFeHByZXNzaW9uIExhbmd1YWdlKiANCi0gTGFuZ2FnZSBzaW1pbGFpcmUgw6AgamF2YXNjcmlwdCBldCBmb3JtdWxlcyBleGNlbC4gICAgDQotIFBlcm1ldCBsYSByw6lkYWN0aW9uIGQnZXhwcmVzc2lvbnMgdmlzYW50IMOgIG1hbmlwdWxlci90cmFuc2Zvcm1lciBsZSBjb250ZW51IGRlcyBjZWxsdWxlcyBkJ3VuZSBjb2xvbm5lLiAgDQooVm9pciBsYSBbZG9jdW1lbnRhdGlvbiBvZmZpY2llbGxlXShodHRwczovL2RvY3Mub3BlbnJlZmluZS5vcmcvbWFudWFsL2dyZWwpIHBvdXIgcGx1cyBkZSBkw6l0YWlscykgIA0KLSBMYW5nYWdlIGNvbXBvc8OpIGRlIFtmb25jdGlvbnNdKGh0dHBzOi8vZG9jcy5vcGVucmVmaW5lLm9yZy9tYW51YWwvZ3JlbGZ1bmN0aW9ucykgZXQgZCdbb2JqZXRzXShodHRwczovL2RvY3Mub3BlbnJlZmluZS5vcmcvbWFudWFsL2V4cHJlc3Npb25zI3ZhcmlhYmxlcykuDQoNCjwvYnI+DQoNCiMjICA5LjEuIEdSRUwgLSBQcmluY2lwZXMgZGUgYmFzZSANCg0KIyMjIyBVdGlsaXNlIHVuZSBzeW50YXhlIHBhcnRpY3VsacOocmUgcG91ciBjaWJsZXIgbGVzIG9iamV0cyAodmFyaWFibGVzKTogIA0KLSBDb250ZW51IGRlIGNvbG9ubmUgYWN0dWVsbGU6IGB2YWx1ZWAuICAgICANCi0gQ29udGVudSBkJ3VuZSBhdXRyZSBjb2xvbm5lOiBgY2VsbHNbJ25vbS1jb2xvbm5lJ10udmFsdWVgLiAgICANCi0gQ29udGVudSB0ZXh0dWVsOiAiZ3VpbGxlbWV0IHNpbXBsZSBvdSBkb3VibGUiLiAgICANCg0KPC9icj4NCg0KIyMjIyBEZXV4IGZvcm1hdHMgZGUgbm90YXRpb246ICANCi0gSW1icmlxdcOpZTogKHRyaW0odG9Mb3dlcmNhc2UodmFsdWUpKS4gICAgDQotICoqU8OpcXVlbnRpZWxsZSoqOiB2YWx1ZS50b0xvd2VyY2FzZSgpLnRyaW0oKSAocGx1cyBmYWNpbGUgw6AgbGlyZSkuICAgIA0KDQo8L2JyPg0KDQojIyMjIERpZmbDqXJlbnRzIHR5cGVzIGRlIGZvbmN0aW9uczogIA0KLSBMZXMgZm9uY3Rpb25zIGV0IGxldXIgY29tcG9ydGVtZW50IGTDqXBlbmRyb250IGR1IHR5cGUgZGUgZG9ubsOpZXMgbWFuaXB1bMOpZXMuICANCi0gW0NlcnRhaW5lcyBmb25jdGlvbnNdKGh0dHBzOi8vZG9jcy5vcGVucmVmaW5lLm9yZy9tYW51YWwvZ3JlbGZ1bmN0aW9ucyNzbGljZWEtbi1mcm9tLW4tdG8tb3B0aW9uYWwpIHBlcm1ldHRlbnQgZGUgdHJhbnNmb3JtZXIgbGUgY29udGVudSBkZSBjZWxsdWxlcyBlbiBgYXJyYXlzYCAobGlzdGUgZCfDqWzDqW1lbnRzKSBldCBkZSBsZXMgbWFuaXB1bGVyLiAgDQotIFtDZXJ0YWluZXMgZm9uY3Rpb25zXShodHRwczovL2RvY3Mub3BlbnJlZmluZS5vcmcvbWFudWFsL2V4cHJlc3Npb25zI3JlZ3VsYXItZXhwcmVzc2lvbnMpIHBlcm1ldHRlbnQgZCd1dGlsaXNlciBsZXMgW2V4cHJlc3Npb25zIHLDqWd1bGnDqHJlc10oI2V4cHJlc3Npb24pLiAgDQoNCjwvYnI+DQoNCiMjIyMgRGlmZsOpcmVudHMgdHlwZXMgZCdvcMOpcmF0ZXVyczogIA0KU2Vsb24gbGUgZm9ybWF0LCBkaWZmw6lyZW50cyB0eXBlcyBkJyoqb3DDqXJhdGV1cnMqKiBwZXV2ZW50IMOqdHJlIHV0aWxpc8OpcyBlbnRyZSBsZXMgdmFsZXVyczogIA0KCS0gT3DDqXJhdGV1cnMgYXJpdGhtw6l0aXF1ZXM6ICssIC0sICosIC8gIA0KCS0gT3DDqXJhdGV1cnMgZGUgY29tcGFyYWlzb246ID09LCA+LCA8ICANCiAgDQoqKlBhciBleGVtcGxlOioqDQoNCi0gTGUgIisiIGVudHJlIGRldXggY29udGVudXMgbnVtw6lyaXF1ZXMgPSBzb21tZQ0KDQohW10oaW1hZ2VzL09SMzAuanBnKQ0KDQotIExlICIrIiBhdmVjIHVuIGNvbnRlbnUgdGV4dHVlbCA9IGNvbmNhdMOpbmF0aW9uDQoNCiFbXShpbWFnZXMvT1IzMS5qcGcpDQoNCjwvYnI+DQoNCioqKiAgDQoNCiMjICA5LjIuIEdSRUwgLSBMJ2luZGV4YXRpb24sIGxhIHPDqWxlY3Rpb24gZXQgbGEgbWFuaXB1bGF0aW9uIGQnw6lsw6ltZW50czogIA0KDQotIENoYXF1ZSBjYXJhY3TDqHJlIGNvbXBvc2FudCBsYSB2YWxldXIgZCd1bmUgY2VsbHVsZSBlc3Qgb3Jkb25uw6kgZGFucyB1biBpbmRleCAqKsOgIHBhcnRpciBkZSAwKiogKDFlciDDqWzDqW1lbnQpLg0KLSBDaGFxdWUgw6lsw6ltZW50IGQndW4gKmFycmF5KiBlc3Qgb3Jkb25uw6kgZGFucyB1biBpbmRleCAqKsOgIHBhcnRpciBkZSAwKiogKDFlciDDqWzDqW1lbnQpIGV0IHBldXQgw6p0cmUgY2libMOpIGdyw6JjZSBhdXggYFsgXWAuICANCi0gTCdvcMOpcmF0ZXVyIGBbIF1gIHBlcm1ldCBkZSBjaWJsZXIvc8OpbGVjdGlvbm5lciBkZXMgY2hhaW5lcyBkZSBjYXJhY3TDqHJlcyBvdSBkZXMgc291cy3DqWzDqW1lbnRzIHNww6ljaWZpcXVlcy4gDQoNCjwvYnI+DQoNCiMjIyBFeGVtcGxlIC0gRm9uY3Rpb24gc3BsaXQoKSAgIA0KDQo+IGB2YWx1ZVswLDhdYCAtPiBNb250csOpYWwgKFF1w6liZWMpID0gPyAgIA0KPiBgdmFsdWUuc3BsaXQoIigiKVsxXWAgLT4gTW9udHLDqWFsIChRdcOpYmVjKSA9ID8gICANCj4gYHZhbHVlLnNwbGl0KCIoIilbMV0uc3BsaXQoIikiKVswXWAgLT4gTW9udHLDqWFsIChRdcOpYmVjKSA9ID8gIA0KPiBgdmFsdWVbMF0gKyB2YWx1ZVszXSArIHZhbHVlWzddYCAtPiBNb250csOpYWwgKFF1w6liZWMpID0gP15bTW9udHLDqWFsIC8gUXXDqWJlYykgLyBRdcOpYmVjIC8gTXRsXSAgDQoNCjwvYnI+DQoNCiMjIEV4ZXJjaWNlIC0gRm9uY3Rpb24gcmVwbGFjZSgpICANCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KYElTQk46IDk3OC0yLTEzLTA4MjkzMC0wYA0KDQpDb25zZXJ2ZXIgc2V1bGVtZW50IGxlIGNoaWZmcmUgZGUgbCdJU0JOIHNhbnMgbGVzIHRyYWl0cyBkJ3VuaW9uP15bdmFsdWVbNSwyNF0ucmVwbGFjZSgiLSIsICIiKV0NCg0KSW5kaWNlcyA6ICANCg0KLSBEZXV4IGZhw6dvbnMgZGUgZmFpcmU6IGB2YWx1ZVtdYCBPVSBgdmFsdWUuc3BsaXQoKWANCi0gYHJlcGxhY2UoKWAgKGlsIGZhdXQgcmVtcGxhY2VyICJxdWVscXVlIGNob3NlIiwgInBhciBsZSB2aWRlIikNCg0KPC9kaXY+DQoNCjwvYnI+DQoNCiMjIyBFeGVtcGxlIC0gRm9uY3Rpb24gc2xpY2UoKSAgDQoNCmBNYXJ0aW5vbGxpLCBQYXNjYWw7IEdhYnJpZWxsaSwgTmlubzsgRm9ydGllciwgQ2F0aGVyaW5lOyBCZWxsZW1hcmUsIFBhc2NhbGVgDQoNCiFbXShpbWFnZXMvT1IyNS5qcGcpDQoNCsOJZGl0ZXIgbGVzIGNlbGx1bGVzIC0+IFRyYW5zZm9ybWVyIC0+IGB2YWx1ZS5zcGxpdCgiOyAiKS5zbGljZSgxKS5qb2luKCJcbiIpYCANCg0KIVtdKGltYWdlcy9PUjM5LmpwZykNCg0KLSBgc3BsaXQoKWA6IGRpdmlzZXIgbGEgY2VsbHVsZSBlbiDDqWzDqW1lbnRzIGRpc3RpbmN0cyBzdXIgbGEgYmFzZSBkdSBzw6lwYXJhdGV1ciA7DQotIGBzbGljZSgpYCA6IGNvbnNlcnZlciBsZXMgw6lsw6ltZW50cyDDoCBwYXJ0aXIgZGUgbCfDqWzDqW1lbnQgMSBkb25jIHN1cHByaW1lIGxlIDAuIA0KLSBgam9pbigpYDogam9pbmRyZSBhdmVjIGxlIHPDqXBhcmF0ZXVyIDsNCg0KPC9icj4NCg0KIyMgRXhlcmNpY2UgLSBGb25jdGlvbiBzb3J0KCkgIA0KDQo8ZGl2IGNsYXNzID0gImJveDEiPg0KDQpNZXR0cmUgbGVzIG5vbXMgZW4gb3JkcmUgYWxwaGFiw6l0aXF1ZSBldCBsZXMgam9pbmRyZSBhdmVjIHVuZSB2aXJndWxlLl5bdmFsdWUuc3BsaXQoIjsgIikuc29ydCgpLmpvaW4oIiwgIildDQoNCkluZGljZXM6ICANCg0KLSBgc3BsaXQoKWA6IGRpdmlzZXIgbGEgY2VsbHVsZSBlbiDDqWzDqW1lbnRzIGRpc3RpbmN0cyBzdXIgbGEgYmFzZSBkdSBzw6lwYXJhdGV1ciAgDQoNCi0gYHNvcnQoKWA6IHRyaWVyIGxlcyDDqWzDqW1lbnRzIChyZXN0ZSB2aWRlKQ0KDQotIGBqb2luKClgOiBqb2luZHJlIGF2ZWMgbGUgc8OpcGFyYXRldXIgIA0KDQoNCjwvZGl2Pg0KDQoNCjwvYnI+DQoNCiMjIyBFeGVtcGxlIC0gRm9uY3Rpb24gcmV2ZXJzZSgpICANCg0Kw4lkaXRlciBsZXMgY2VsbHVsZXMgLT4gVHJhbnNmb3JtZXIgLT4gYHZhbHVlLnNwbGl0KCI7ICIpWzFdLnNwbGl0KCIsICIpLnJldmVyc2UoKS5qb2luKCIgIikgKyAiIMOoIGZhbnRhc3RpY28hImAgDQoNCiFbXShpbWFnZXMvT1IzOC5qcGcpDQoNCi0gYHNwbGl0KClgOiBkaXZpc2UgbGEgY2VsbHVsZSBlbiDDqWzDqW1lbnRzIGRpc3RpbmN0cyBzdXIgbGEgYmFzZSBkdSBzw6lwYXJhdGV1ciA7IGV0IHJldGllbnQgbGUgZGV1eGnDqG1lIMOpbMOpbWVudA0KLSBgc3BsaXQoKWA6IGRpdmlzZSBjZXQgw6lsw6ltZW50IHN1ciBsZSBzw6lwYXJhdGV1ciAsDQotIGByZXZlcnNlKClgOiBpbnZlcnNlIGwnb3JkcmUgZGVzIGRldXggw6lsw6ltZW50cw0KLSBgam9pbigpYDogcmF0dGFjaGUgbGVzIGRldXggw6lsw6ltZW50cyBkaXZpc8OpIGF2ZWMgdW4gZXNwYWNlDQoNCjwvYnI+DQoNCioqKg0KDQojIyA5LjMuIENyw6llciBkZXMgZmFjZXR0ZXMgYXZlYyBHUkVMDQoNCiMjIEV4ZXJjaWNlcw0KDQo8ZGl2IGNsYXNzID0gImJveDEiPg0KDQpDcsOpZXIgdW5lIGZhY2V0dGUgcG91ciBsaXN0ZXIgbGVzIGNhcyBzZWxvbiBsJypoZXVyZSBkZSBsJ2luY2lkZW50KiBzZXVsZW1lbnQsIHNhbnMgbGVzIG1pbnV0ZXMgKDIgcHJlbWllcnMgY2FyYWN0w6hyZXMpLiBDb21tZW50IGZhaXJlIGFmZmljaGVyIGxlcyBtaW51dGVzIHNldWxlbWVudD9eW3ZhbHVlWzMsNV0gb3UgdmFsdWUuc3Vic3RyaW5nKDMpXSANCg0KYHZhbHVlWzAsMl1gICAgDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDEiPg0KDQpDcsOpZXIgdW5lIGZhY2V0dGUgc3VyIGxhIGNvbG9ubmUgKkNvZGUgZGUgbGlldSogcG91ciBpZGVudGlmaWVyIGxlcyBjYXMgZG9udCBsYSB2YWxldXIgY29tbWVuY2UgcGFyICJDw7R0ZSIgIA0KDQpgdmFsdWUuc3RhcnRzV2l0aCjigJxDw7R0ZeKAnSlgICAgIA0KDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KQ3LDqWVyIHVuZSBmYWNldHRlIHBvdXIgaWRlbnRpZmllciBsZXMgY2FzIGRvbnQgbGEgdmFsZXVyIGRhbnMgbGEgY29sb25uZSAqQ2F1c2UgcHJpbWFpcmUqIGVzdCBsYSBtw6ptZSBxdWUgZGFucyBsYSBjb2xvbm5lICpDYXVzZSBzZWNvbmRhaXJlKg0KDQpgdmFsdWUgPT0gY2VsbHNbIkNhdXNlIHNlY29uZGFpcmUiXS52YWx1ZWAgICANCg0KPC9kaXY+DQoNCjwvYnI+DQoNCioqKg0KDQoNCiMjIDkuNC4gUmVjaGVyY2hlci9yZW1wbGFjZXIgdW4gY2FyYWN0w6hyZSBkYW5zIHRvdXRlcyBsZXMgY29sb25uZXMgYXZlYyBHUkVMDQoNCiMjIEV4ZXJjaWNlDQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQpSZW1wbGFjZXIgbGVzIHZhbGV1cnMgIiMiIGRhbnMgdG91dGUgbGEgYmFzZSBkZSBkb25uw6llcyBwYXIgImF1Y3VuIioqICAgDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQotIFF1ZWwgcHJvYmzDqG1lIGNlIHJlbXBsYWNlbWVudCBwZXV0LWlsIHByb3ZvcXVlcj8gICAgDQotIEV4cGxvcmVyIGwnaW1wYWN0IGRlcyB0cm9pcyBleHByZXNzaW9ucyBkZSByZW1wbGFjZW1lbnQgc3VpdmFudGVzOiAgDQoNCjEuIGB2YWx1ZS5yZXBsYWNlKCIjIiwgImF1Y3VuIilgICAgDQoocmVtcGxhY2UgbGUgY2FyYWN0w6hyZSAjOiBhdWN1biBldCBhdWN1bk4vRCApICAgICANCiANCjIuIGBpZih2YWx1ZS5jb250YWlucygiIyIpLCJhdWN1biIsIHZhbHVlKWAgICANCihyZW1wbGFjZSBsZXMgY2VsbHVsZXMgZGVzICMgZXQgI05EIHBhciBhdWN1bikgIA0KDQozLiBgaWYodmFsdWU9PSgiIyIpLCJhdWN1biIsIHZhbHVlKWAgICAgIA0KKHJlbXBsYWNlIHNldWxlbWVudCBsZXMgY2VsbHVsZXMgIywgcGFzIGxlcyAjTkQgcGFyIGF1Y3VuKSANCjwvZGl2Pg0KDQo8L2JyPg0KDQoNCioqKg0KDQojIyA5LjUuIENyw6llciBldCBjb3BpZXIgZGVzIGNvbG9ubmVzDQoNCjwvYnI+DQoNCmDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gQWpvdXRlciB1bmUgY29sb25uZSBlbiBmb25jdGlvbiBkZSBjZXR0ZSBjb2xvbm5lYA0KDQohW10oaW1hZ2VzL09SMzIuanBnKQ0KDQoNCiMjIEV4ZXJjaWNlDQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQpDcsOpZXIgdW5lIG5vdXZlbGxlIGNvbG9ubmUgc3VyIGxhIGJhc2UgZGUgbGEgY29sb25uZSAqSm91ciBkZSBsYSBzZW1haW5lKiBpbmRpcXVhbnQgc2kgbGUgam91ciBlc3QgZW4gc2VtYWluZSBvdSBmaW4gZGUgc2VtYWluZS4NCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCmBpZih2YWx1ZSA+IDUsImZpbiBkZSBzZW1haW5lIiwic2VtYWluZSIpYA0KPC9kaXY+DQoNCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQpDcsOpZXIgdW5lIGNvbG9ubmUgw6AgcGFydGlyIGRlIGxhIGNvbG9ubmUgKmhldXJlIGRlIGwnaW5jaWRlbnQqIGVuIG5lIGNvbnNlcnZhbnQgcXVlIGwnaGV1cmUsIHNhbnMgbGVzIG1pbnV0ZXMsIGV0IHJham91dGVyIGxhIGxldHRyZSBoIHBvdXIgZG9ubmVyIHBhciBleGVtcGxlIGNlY2k6IDE1OjEyICAtPiAgMTVoLiAgDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQpgdmFsdWUuc3BsaXQoJzonKVswXSArICJoImAuICANCg0KT3UNCg0KYHZhbHVlLnNwbGl0QnlMZW5ndGhzKDIpWzBdICsgImgiYC4gIA0KPC9kaXY+DQoNCjwvYnI+DQoNCg0KKioqDQoNCg0KIyAxMC4gTGVzIGV4cHJlc3Npb25zIHLDqWd1bGnDqHJlcyB7I2V4cHJlc3Npb259DQoNCiMjIDEwLjEuIENhcmFjdMOpcmlzdGlxdWVzICANCg0KLSBMJ3VzYWdlIGRlIEdSRUwgcGVybWV0IGRlcyBtYW5pcHVsYXRpb25zIGRlIGRvbm7DqWVzIGJlYXVjb3VwIHBsdXMgYXZhbmPDqWVzIHF1ZSBsJ3V0aWxpc2F0aW9uIGRlcyBmb25jdGlvbnMgYXV0b21hdGlzw6llcywgbWFpcyBPcGVuUmVmaW5lIHBlcm1ldCBlbiBwbHVzIGRlIGNvbWJpbmVyIGwndXRpbGlzYXRpb24gZGVzIGV4cHJlc3Npb25zIHLDqWd1bGnDqHJlcyBhdmVjIEdSRUwgcG91ciBlbiBhdWdtZW50ZXIgbGEgcHVpc3NhbmNlLiANCi0gTGVzIGV4cHJlc3Npb25zIHLDqWd1bGnDqHJlcyBwZXJtZXR0ZW50LCDDoCBwYXJ0aXIgZCd1bmUgc3ludGF4ZSBzcMOpY2lmaXF1ZSwgZCdpZGVudGlmaWVyIGRlcyBwYXR0ZXJucyBkYW5zIHVuIGNvbnRlbnUuICANCi0gTG9yc3F1J3V0aWxpc8OpZXMgYXZlYyBHUkVMLCBjZXMgZXhwcmVzc2lvbnMgcGVybWV0dGVudCBkb25jIGQnaWRlbnRpZmllciBldCBkJ2V4dHJhaXJlIGRlcyBjb250ZW51cyB0csOocyBwcsOpY2lzIHBvdXIgZW5zdWl0ZSBsZXMgbWFuaXB1bGVyIHNlbG9uIGxlcyBiZXNvaW5zLiAgDQotIEVsbGVzIHBldXZlbnQgw6p0cmUgdXRpbGlzw6llcyDDoCBkaWZmw6lyZW50cyBlbmRyb2l0cyBkYW5zIE9wZW5SZWZpbmUgZXQgZG9pdmVudCB0b3Vqb3VycyDDqnRyZSBlbnRvdXLDqWVzIGRlIGAvIC9gOiBmaWx0cmVzLCBmYWNldHRlcywgZmVuw6p0cmUgR1JFTC4NCi0gQ2VydGFpbmVzIGV4cHJlc3Npb25zIHBldXZlbnQgcyfDqWNyaXJlIGVuIEdSRUwgYXZlYyBvdSBzYW5zIHJlZ2V4LiAgDQotIExlcyBmb25jdGlvbnMgR1JFTCBxdWkgYWNjZXB0ZW50IGxlcyBleHByZXNzaW9ucyByw6lndWxpw6hyZXM6IGByZXBsYWNlYCwgYG1hdGNoYCwgYHBhcnRpdGlvbmAsIGBycGFydGl0aW9uYCwgYHNwbGl0YC4NCg0KPC9icj4NCg0KIVtdKGltYWdlcy9PUjMzLmpwZykNCg0KDQotIE1haXMgY2VydGFpbmVzIGZvbmN0aW9ucyAoY29tbWUgYG1hdGNoYCkgbidhY2NlcHRlbnQgcXVlIGNlcyBleHByZXNzaW9ucy4gIA0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJub3RlIj4NCg0KTGVzIGV4cHJlc3Npb25zIHLDqWd1bGnDqHJlcyBwZXV2ZW50IMOqdHJlIHV0aWxpc8OpZXMgYXZlYyBwbHVzaWV1cnMgYXV0cmVzIGxhbmdhZ2VzIGRvbnQgW1JdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9hLWdlbnRsZS1pbnRyb2R1Y3Rpb24tdG8tcmVndWxhci1leHByZXNzaW9ucy13aXRoLXItZGY1ZTg5N2NhNDMyKSBldCBbUHl0aG9uXShodHRwczovL2RvY3MucHl0aG9uLm9yZy8zL2hvd3RvL3JlZ2V4Lmh0bWwpIGV0IGRhbnMgZGVzIGxvZ2ljaWVscyBxdWkgbidvbnQgcmllbiDDoCB2b2lyIGF2ZWMgbGVzIHN0YXRpc3RpcXVlcyBjb21tZSBbT3Blbk9mZmljZV0oaHR0cHM6Ly93aWtpLm9wZW5vZmZpY2Uub3JnL3dpa2kvRG9jdW1lbnRhdGlvbi9Ib3dfVG9zL1JlZ3VsYXJfRXhwcmVzc2lvbnNfaW5fV3JpdGVyKS4NCg0KUG91ciBlbiBzYXZvaXIgcGx1czogIA0KLSBodHRwczovL2dpdGh1Yi5jb20vT3BlblJlZmluZS9PcGVuUmVmaW5lL3dpa2kvVW5kZXJzdGFuZGluZy1SZWd1bGFyLUV4cHJlc3Npb25zICANCi0gaHR0cHM6Ly9yZWdleDEwMS5jb20vICANCg0KPC9kaXY+DQoNCjwvYnI+DQoNCioqKg0KDQojIyAxMC4yLiBMYSBzeW50YXhlIGRlIGJhc2U6ICAgDQoNCkxhIHN5bnRheGUgZXN0IGNvbXBvc8OpZSBkJ8OpbMOpbWVudHMgcGVybWV0dGFudCBkZSAgY2libGVyIGRlcyBjYXJhY3TDqHJlcyBwcsOpY2lzIGV0IGRlIGTDqWZpbmlyIGxldXIgZW1wbGFjZW1lbnQgZXQgbGV1ciBvY2N1cnJlbmNlLg0KDQorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IFRZUEVTIERFIENBUkFDVMOIUkVTICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IFFVQU5USUZJQ0FURVVSUyBFVCBFTVBMQUNFTUVOVCAgICAgICAgICAgICAgICAgfCANCis9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Kz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSsNCnwgYC5gIDogTuKAmWltcG9ydGUgcXVvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGArYCA6IDEgb3UgcGx1cyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgIA0KKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBgXHdgIDogbidpbXBvcnRlIHF1ZWwgbW90LCBjaGlmZnJlIG91IF8gIChgXFdgIDogc2F1ZikgICAgIHwgYCpgIDogMCBvdSBwbHVzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICANCistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgYFxkYCA6IENoaWZmcmVzICAgICAgKGBcRGAgOiBzYXVmKSAgICAgICAgICAgICAgICAgICAgfCBgP2AgOiAwIG91IHVuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgDQorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IGBcc2AgOiBFc3BhY2VzICAgICAgICAgKGBcU2AgOiBzYXVmKSAgICAgICAgICAgICAgICAgIHwgYHsyfWAgOiBOb21icmUgZXhhY3QgKGljaSAyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IA0KKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgYFtBLVpdYCA6IE1hanVzY3VsZXMgICAgIChgW15BLVpdYCA6IHNhdWYpICAgICAgICAgICAgfCBgeyw0fWAgOiBFbnRyZSAwIGV0IDQgaW5jbC4gICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICANCistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IGBbYS16XWAgOiBNaW51c2N1bGVzICAgICAgKGBbXmEtel1gIDogc2F1ZikgICAgICAgICAgIHwgYHs0LH1gIDogNCBvdSBwbHVzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCANCistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQp8IGBbYWJkO11gIDogbGVzIGxldHRyZXMgYSwgYiwgYywgZCBldCBsZSA7ICAgICAgICAgICAgIHwgYHsxOzN9YCA6IDEgT1UgMyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgDQorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgYGFiY2RgIDogdW5lIG91IHBsdXNpZXVycyBsZXR0cmVzIGV4YWN0ZXMgICAgICAgICAgICAgfCBgezEsM31gIDogRW50cmUgMSBldCAzIGluY2wuICAgICAgICAgICAgICAgICAgICAgfCANCistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBgfGAgOiBPdSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBgXmAgOiBEw6lidXQgZCd1bmUgbGlnbmUgICAgICAgICAgICAgICAgfCANCistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKw0KfCBgKClgIDogR3JvdXBlciB1biBjb250ZW51IGV0IGxlIGdhcmRlciBlbiBtw6ltb2lyZSAgICAgIHwgYCRgIDogRmluIGQndW5lIGxpZ25lIG91IHJhcHBlbGVyIHVuIGdyb3VwZSAgICB8DQorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsNCnwgIGBcYCA6IENoZXJjaGVyIHVuIGNhcmFjdMOocmUgc3DDqWNpYWwgbGl0dMOpcmFsZW1lbnQgICAgfCBTYW5zIHF1YW50aWZpY2F0ZXVyLCBsJ29jY3VycmVuY2UgZXN0IGRlIDEgICAgICAgfA0KKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rDQoNCiMjIyMjIFBhciBleGVtcGxlLCBqZSBjaGVyY2hlIHVuIGNvbnRlbnUgY29ycmVzcG9uZGFudCBhdSBtb3RpZjogIA0KDQpgXlxkezR9ICtbQS1aXVwuYCAgICANCiAgIA0KLSBkw6lidXRlIHBhciA0IGNoaWZmcmVzICAgDQotIHN1aXZpIGQndW4gZXNwYWNlIG91IHBsdXMgICANCi0gc3VpdmkgZCd1bmUgbGV0dHJlIG1hanVzY3VsZSBhdmVjIHVuIHBvaW50ICAgDQoNCjwvYnI+DQoNCiMjIyMjIEF1dHJlcyBleGVtcGxlcyBhdmVjIGxhIHN5bnRheGUgT3BlblJlZmluZToNCg0KLSBgdmFsdWUuZmluZCgvW0NjXWFyb2xpbmUvKWA6IENhcm9saW5lIGV0IGNhcm9saW5lDQoNCi0gYHZhbHVlLmZpbmQoL2NhK3JvbGluZS8pYDogY2Fyb2xpbmUgZXQgY2FhYWFyb2xpbmUNCg0KLSBgdmFsdWUuZmluZCgvY2Eqcm9saW5lLylgOiBjYXJvbGluZSwgY2FhYXJvbGluZSBldCBjcm9saW5lDQoNCi0gYHZhbHVlLmZpbmQoL2NhP3JvbGluZS8pYDogY2Fyb2xpbmUgZXQgY3JvbGluZSBtYWlzIHBhcyBjYWFhcm9saW5lDQoNCi0gYHZhbHVlLmZpbmQoL2NhezR9cm9saW5lLylgOiBjYWFhYXJvbGluZQ0KDQotIGB2YWx1ZS5maW5kKC9eQ2Fyb2xcYi8pYDogQ2Fyb2wgZW4gZMOpYnV0IGQnZXhwcmVzc2lvbiwgbWFpcyBwYXMgQ2Fyb2xpbmUgKFxiID0gImJvdW5kYXJ5IikNCg0KLSBgdmFsdWUuZmluZCgvY1thLXpdezZ9ZS8pYDogYyArIDYgbWludXNjdWxlcyArIGUNCg0KLSBgdmFsdWUuZmluZCgvQ1thLXpBLVowLTldezZ9ZS8pYDogQyArIDYgbWludXNjdWxlcywgbWFqdXNjdWxlcyBvdSBjaGlmZnJlcyArIGUNCg0KLSBgdmFsdWUuZmluZCgvQ1x3ezZ9ZS8pYDogQyArIFtBLVphLXowLTlfXSArIGUNCg0KLSBgdmFsdWUuZmluZCgvQy57Nn1lLylgOiBDICsgNiBuJ2ltcG9ydGUgcXVvaSArIGUNCg0KDQoqKioNCg0KIyMgRXhlcmNpY2UNCg0KIyMjIE1hbmlwdWxlciBsZXMgw6lsw6ltZW50cyBkZSByw6lmw6lyZW5jZXMgYmlibGlvZ3JhcGhpcXVlcw0KDQohW10oaW1hZ2VzL09SMzYuanBnKQ0KDQo8ZGl2IGNsYXNzID0gImJveDEiPg0KMS4gQWxsZXIgc3VyIGxlIFtndWlkZSBBUEFdKGh0dHBzOi8vYmliLnVtb250cmVhbC5jYS9jaXRlci9zdHlsZXMtYmlibGlvZ3JhcGhpcXVlcy9hcGE/dGFiPTMyODEpLiAgICAgDQoyLiBDb3BpZXIgbGVzIGRldXggcsOpZsOpcmVuY2VzIGRlIExlbWFpcmUgZXQgTGVib3ZpY2kgYXUgcG9pbnQgMi4xLiAgICAgIA0KMy4gRGFucyBPcGVuUmVmaW5lLCBjbGlxdWVyIHN1ciBsZSBwZXRpdCBsb2dvIGVuIGhhdXQgw6AgZ2F1Y2hlIC0+IGBDcsOpZXIgdW4gcHJvamV0YCAtPiBgUHJlc3NlLXBhcGllcmA6IENvbGxlciBsZXMgZGV1eCByw6lmw6lyZW5jZXMgZW4gIGFqb3V0YW50IHVuIHPDqXBhcmF0ZXVyICoqIjsiKiogw6AgbGEgZmluIGRlIGxhIHByZW1pw6hyZSAtPiBTdWl2YW50LiAgICAgICANCg0KNC4gTW9kaWZpZXIgbGVzIG9wdGlvbnM6IA0KICAtIExlcyBjb2xvbm5lcyBzb250IHPDqXBhcsOpZXMgcGFyIC0gcGVyc29ubmFsaXPDqSAiOyIuICANCiAgLSBEw6ljb2NoZXIgIkFuYWx5c2VyIGxhIG91IGxlcwkxIGxpZ25lKHMpIHN1aXZhbnRlKHMpIGNvbW1lIGRlcyBlbnTDqnRlcyBkZSBjb2xvbm5lcyIuICANCjUuIENyw6llciBwcm9qZXQuICAgDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCjYuIGDDiWRpdGVyIGxhIGNvbG9ubmUgLT4gQWpvdXRlciB1bmUgY29sb25uZSBlbiBmb25jdGlvbiBkZSBjZXR0ZSBjb2xvbm5lYCAgDQoNCjcuIEV4YW1pbmVyIGwnaW1wYWN0IGRlIGNlcyBkZXV4IGNvbW1hbmRlcyAqKkdSRUwgKyByZWdleCoqLiBRdSdlc3QtY2UgcXVpIHNlIHBhc3NlPw0KDQotIMOJZGl0ZXIgbGVzIGNlbGx1bGVzIC0+IFRyYW5zZm9ybWVyOiANCg0KPiBgdmFsdWUuZmluZCgvXCguKj9cKS8pYCAgDQoNCj4gYHZhbHVlLmZpbmQoL1woLio/XCkvKS5qb2luKCcsJykucmVwbGFjZSgiKCIsIiAiKS5yZXBsYWNlKCIpIiwgIiIpYCAgDQoNCi0+IEF0dGVudGlvbiBhdXggW3F1YW50aWZpY2F0ZXVycyAiZ291cm1hbmRzIl0oaHR0cHM6Ly9kb2NzLm1pY3Jvc29mdC5jb20vZW4tdXMvZG90bmV0L3N0YW5kYXJkL2Jhc2UtdHlwZXMvcXVhbnRpZmllcnMtaW4tcmVndWxhci1leHByZXNzaW9ucyNncmVlZHktYW5kLWxhenktcXVhbnRpZmllcnMpICh2cyBwYXJlc3NldXgpLg0KDQo8L2JyPg0KDQrDiWRpdGVyIGxhIGNvbG9ubmUgLT4gQWpvdXRlciB1bmUgY29sb25uZSBlbiBmb25jdGlvbiBkZSBjZXR0ZSBjb2xvbm5lOiAgDQoNCiAgLSBDcsOpZXIgbGEgY29sb25uZSBBdXRldXIgOiBgdmFsdWUucGFydGl0aW9uKCIoIilbMF1gIG91IGB2YWx1ZS5zcGxpdCgiKCIpWzBdYCAgIA0KICAtIENyw6llciBsYSBjb2xvbm5lIEFubsOpZTogYHZhbHVlLnBhcnRpdGlvbigiKCIpWzJdLnBhcnRpdGlvbigiKSIpWzBdYCAgIG91IGF2ZWMgcmVnZXg6IGB2YWx1ZS5tYXRjaCgvLio/KFxkezR9KS4qPy8pWzBdYC4gICAgDQogIC0gQ3LDqWVyIGxhIGNvbG9ubmUgdGl0cmU6IGB2YWx1ZS5wYXJ0aXRpb24oIikuIilbMl0ucGFydGl0aW9uKCIoIilbMF1gLiAgICAgIA0KICAtIENyw6llciBsYSBjb2xvbm5lIMOpZGl0ZXVyOiBgdmFsdWUucGFydGl0aW9uKCIpLiIpWzJdLnBhcnRpdGlvbigiKS4iKVsyXWAuICAgICANCiAgLSBDcsOpZXIgbGEgY29sb25uZSDDqWRpdGlvbjogYHZhbHVlLnBhcnRpdGlvbigiKS4iKVsyXS5wYXJ0aXRpb24oIigiKVsyXS5wYXJ0aXRpb24oIsOpZCIpWzBdYCBvdSBhdmVjIHJlZ2V4OiBgdmFsdWUubWF0Y2goLy4qKFxkKykuIMOpZC4qLylbMF1gLiAgDQogIC0gQ3LDqWVyIGxhIGNvbG9ubmUgdm9sdW1lOiBgdmFsdWUucGFydGl0aW9uKCJ2b2wuIilbMl0ucGFydGl0aW9uKCIpIilbMF1gIG91IGF2ZWMgcmVnZXg6IGB2YWx1ZS5tYXRjaCgvLip2b2wuIChcZCspLiovKVswXWAuICANCk1haXMgZW5jb3JlIGF2ZWMgcmVnZXg6ICANCi0gU3VwcHJpbWVyIGxlcyBsZXR0cmVzIGR1IHByw6lub206IGB2YWx1ZS5yZXBsYWNlKC8oXHNbQS1aXS5ccyl8KFxzW0EtWl0uLFxzKS8sICIgIilgLiAgDQotIFN1cHByaW1lciB0b3V0IGxlIGNvbnRlbnUgc2F1ZiBsZXMgbm9tcyBkZSBmYW1pbGxlOiBgdmFsdWUucmVwbGFjZSgvKFxzW0EtWl0uXHMpfChcc1tBLVpdLixccyl8KGV0KXwoLCkvLCAiICIpYC4gIA0KDQo8L2JyPg0KDQoqKioNCg0KIyAxMS4gVHJhbnNwb3NpdGlvbg0KDQojIyBFeGVyY2ljZTogdHJhbnNwb3NlciB1biB0YWJsZWF1IGQnaW5kaWNhdGV1cnMgZHUgV0RJDQo8L2JyPg0KDQoqKkZpY2hpZXIgb3JpZ2luYWwgdMOpbMOpY2hhcmfDqSBkZSBsYSBbQmFucXVlIG1vbmRpYWxlXShodHRwczovL2RhdGFiYW5rLmJhbnF1ZW1vbmRpYWxlLm9yZy9yZXBvcnRzLmFzcHg/c291cmNlPXdvcmxkLWRldmVsb3BtZW50LWluZGljYXRvcnMpIGVuIGZvcm1hdCAuY3N2IGNvbXBvc8OpIGRlIDUgcGF5cyBldCA0IGluZGljYXRldXJzIMOgIGwnaG9yaXpvbnRhbGUgZXQgMyBhbm7DqWVzIMOgIGxhIHZlcnRpY2FsZSoqICANCg0KLSBQb3VyIG91dnJpciBsZSBmaWNoaWVyIMOgIHBhcnRpciBkZSBzb24gZW1wbGFjZW1lbnQgc3VyIEdpdGh1YjogaHR0cHM6Ly9naXRodWIuY29tL0NSTE5QL29wZW5yZWZpbmUgDQogIC0gQ2xpcXVlciBzdXIgbGUgZmljaGllciAqV0RJX0RhdGFfRXh0cmFjdC5jc3YqIC0+IENsaXF1ZXIgc3VyIGxlIGJvdXRvbiBSQVcgLT4gY29waWVyIGwnYWRyZXNzZSBkdSBuYXZpZ2F0ZXVyLg0KICAtIERhbnMgT3BlblJlZmluZSwgQ3LDqWVyIHVuIHByb2pldCAtPiBBZHJlc3NlcyB3ZWIgKFVSTHMpIC0+IGNvbGxlciBsZSBsaWVuLg0KICANCiFbXShpbWFnZXMvT1ItdHJhbnNwb3NlMS5qcGcpDQoNCjwvYnI+DQoNCioqMS4gVHJhbnNwb3NlciBsZXMgZGF0ZXMgw6AgbCdob3Jpem9udGFsZSAoZm9ybWF0ICpsb25nKikqKiAgDQoNCjwvYnI+DQoNCirDiWRpdGVyIGxlcyBjZWxsdWxlcyAtPiBUcmFuc3Bvc2VyIC0+IFRyYW5zcG9zZXIgbGVzIGNlbGx1bGVzIGRlIHBsdXNpZXVycyBjb2xvbm5lcyBlbiBsaWduZXMuLi4qDQoNCg0KPC9icj4NCg0KDQohW10oaW1hZ2VzL09SLXRyYW5zcG9zZTIuanBnKQ0KDQo8L2JyPg0KDQoNCiFbXShpbWFnZXMvT1ItdHJhbnNwb3NlMy5qcGcpDQoNCjwvYnI+DQoNCioqMi4gUmVtcGxpciBhdXRvbWF0aXF1ZW1lbnQgbGVzIGNlbGx1bGVzIHZpZGVzIGRlcyBkZXV4IGNvbG9ubmVzIMOgIGxhIHZlcnRpY2FsZSoqDQoNCirDiWRpdGVyIGxlcyBjZWxsdWxlcyAtPiBSZWNvcGllciBsZXMgdmFsZXVycyBkYW5zIGxlcyBjZWxsdWxlcyB2aWRlcyBjb25zw6ljdXRpdmVzKg0KDQo8L2JyPg0KDQoqKjMuIFRyYW5zcG9zZXIgbGVzIGluZGljYXRldXJzIGVuIHZhcmlhYmxlcyDDoCBsYSB2ZXJ0aWNhbGUqKg0KDQoqVHJhbnNwb3NlciAtPiBDb252ZXJ0aXIgZW4gbGlzdGUgbGVzIGNvbG9ubmVzIGRlIGNsw6kvdmFsZXVyLi4uKg0KDQo8L2JyPg0KDQohW10oaW1hZ2VzL09SLXRyYW5zcG9zZTQuanBnKQ0KDQo8L2JyPg0KDQohW10oaW1hZ2VzL09SLXRyYW5zcG9zZTUuanBnKQ0KDQo8L2JyPg0KDQoNCioqKg0KDQojIDEyLiBFeHBvcnRlciB1biBmaWNoaWVyIGV0IGZlcm1lciBPcGVuUmVmaW5lDQoNCi0gRm9uY3Rpb24gw6AgdXRpbGlzZXIgbG9yc3F1ZSBsJ29uIGVzdCBwcsOqdCDDoCBleHBvcnRlciBzb24gZmljaGllciBlbiBkaWZmw6lyZW50cyBmb3JtYXRzIHBvdXIgdHJhdmFpbGxlciBkYW5zIHVuIGF1dHJlIGxvZ2ljaWVsICguY3N2LCAueGxzLi4uKQ0KLSBPUiBzYXV2ZWdhcmRlIGF1dG9tYXRpcXVlbWVudCBsZXMgZmljaGllcnMgc291cyBmb3JtZSBkJ2FyY2hpdmVzIGRlIHByb2pldCBkYW5zIHVuIGRvc3NpZXIgc3VyIGxlIHBvc3RlIGRlIHRyYXZhaWwgYXV4cXVlbGxlcyBvbiBwZXV0IGFjY8OpZGVyIGVuIGNsaXF1YW50IHN1ciBgT3V2cmlyIHVuIHByb2pldGAgc3VyIGxhIHBhZ2UgcHJpbmNpcGFsZS4NCi0gTCdvdXRpbCBgRXhwb3J0ZXVyIHRhYnVsYWlyZSBwZXJzb25uYWxpc8OpYCBlc3QgdHLDqHMgdXRpbGUgcG91ciBwYXJhbcOpdHJlciBsJ2V4cG9ydGF0aW9uIChzw6lsZWN0aW9uIGRlIGNvbG9ubmVzLCBmb3JtYXQgZGUgZGF0ZXMsIGZvcm1hdCBkZSBmaWNoaWVyLi4uKQ0KLSBGZXJtZXIgbCdvbmdsZXQgbmUgZmVybWUgcGFzIGxlIHNlcnZldXIgcXVpIGNvbnRpbnVlcmEgw6Agcm91bGVyIGVuIGFycmnDqHJlLXBsYW4uDQotIEFsbGVyIMOgIGxhIGZlbsOqdHJlIG5vaXJlIGR1IHRlcm1pbmFsIGV0IHV0aWxpc2VyIGxlcyB0b3VjaGVzIENUUkwgKyBDIGp1c3F1J8OgIGNlIHF1J2VsbGUgc2UgZmVybWUgZCdlbGxlLW3Dqm1lIChpbCBlc3QgcGFyZm9pcyBuw6ljZXNzYWlyZSBkZSByw6lww6l0ZXIgw6AgcGx1cyBkJ3VuZSByZXByaXNlKS4gTGUgZmljaGllciBzZXJhIGVucmVnaXN0csOpIHVuZSBkZXJuacOocmUgZm9pcyBldCBsZSBsb2dpY2llbCBzZXJhICBtYWludGVuYW50IGJlbCBldCBiaWVuIGZlcm3DqS4NCg0KPC9icj4NCg0KKioqDQoNCg0KIyAxMy4gUXVlbHF1ZXMgcmVjZXR0ZXMgcG91ciBmYWlyZSBkdXJlciBsZSBwbGFpc2lyDQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQojIyMjIEV4dHJhaXJlIHNldWxlbWVudCBjZXJ0YWlucyBjYXJhY3TDqHJlcyBzZWxvbiBsZXVyIHBvc2l0aW9uDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQoNCkV4dHJhaXJlIHNldWxlbWVudCBsZXMgY2FyYWN0w6hyZXMgZGUgNSDDoCA3ICANCg0KLSB2YWx1ZVs1LCA3XQ0KDQpFeHRyYWlyZSBsZXMgY2FyYWN0w6hyZXMgw6AgcGFydGlyIGRlIDUgIA0KDQotIHZhbHVlLnN1YnN0cmluZyg1KQ0KPC9kaXY+DQoNCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQojIyMjIFNhdm9pciBzaSB1bmUgY29uZGl0aW9uIGVzdCB2cmFpZSBvdSBmYXVzc2U/DQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQpFc3QtY2UgcXVlIGxlIGNvbnRlbnUgZGVzIHZhbGV1cnMgY29ycmVzcG9uZCDDoCAiMjAxOS0wMS0wMSIgIA0KDQotIHZhbHVlPT0iMjAxOS0wMS0wMSINCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBDb25uYcOudHJlIGxhIGxvbmd1ZXVyIGRlcyB2YWxldXJzIGQndW5lIGNvbG9ubmUNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCi0gdmFsdWUubGVuZ3RoKCkNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBDb21wdGVyIGxlIG5vbWJyZSBkZSBtb3RzIGRhbnMgZGVzIGNlbGx1bGVzIChzw6lwYXLDqXMgcGFyIGRlcyBlc3BhY2VzKQ0KPC9kaXY+DQo8ZGl2IGNsYXNzID0gImJveDEiPg0KLSB2YWx1ZS5zcGxpdCgiICIpLmxlbmd0aCgpIG91IHZhbHVlLnNwbGl0KC9ccy8pLmxlbmd0aCgpDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gyIj4NCiMjIyMgQ2FsY3VsIGQndW4gcG91cmNlbnRhZ2UgYXJyb25kaSAoZXggZCd1biByw6lzdWx0YXQgc3VyIDEwKQ0KPC9kaXY+DQo8ZGl2IGNsYXNzID0gImJveDEiPg0KLSByb3VuZCgodmFsdWUqMTAwKSAvIDEwKQ0KPC9kaXY+DQoNCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQojIyMjIFRyYW5zZm9ybWVyIHVuIGZvcm1hdCBkYXRlIGVuIGZvcm1hdCB0ZXh0ZSBwbHVzIGxpc2libGUNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCi0gdmFsdWUudG9TdHJpbmcoImRkIE1NTU0geXl5eSIpDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQojIyMjIExhIGNyw6lhdGlvbiBldCBtYW5pcHVsYXRpb24gZGUgbGlzdGVzICgqYXJyYXkqKSAtIERpdmlzZXIgbGUgY29udGVudSBkZSBjZWxsdWxlcyANCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCkRpdmlzZXIgbGUgY29udGVudSBkZSBjZWxsdWxlcyBlbiBmb25jdGlvbiBkJ3VuIHPDqXBhcmF0ZXVyIHBvdXIgbmUgY29uc2VydmVyIHF1ZSBsZSBwcmVtaWVyIMOpbMOpbWVudCAgICANCg0KLSB2YWx1ZS5zcGxpdCgiICIpWzBdDQoNCkRpdmlzZXIgbGUgY29udGVudSBkJ3VuZSBjZWxsdWxlIHBvdXIgbGUgcsOpb3Jkb25uZXIgDQoNCi0gdmFsdWUuc3BsaXQoIiwiKS5yZXZlcnNlKCkuam9pbigiLCIpDQoNCi0gdmFsdWUuc3BsaXQoIiwiKS5zb3J0KCkuam9pbigiLCIpDQoNCkRpdmlzZXIgYXByw6hzIGxlcyAzIHByZW1pZXJzIGNhcmFjdMOocmVzIGV0IGNvbnNlcnZlciBsZSBwcmVtaWVyIMOpbMOpbWVudCAgDQoNCi0gdmFsdWUuc3BsaXRCeUxlbmd0aHMoMylbMF0gDQoNCkRpdmlzZXIgc2Vsb24gbGUgdHlwZSBkZSBjYXJhY3TDqHJlcyBldCByZXRlbmlyIGxlIGRldXhpw6htZSDDqWzDqW1lbnQgIA0KDQotIHZhbHVlLnNwbGl0QnlDaGFyVHlwZSgpWzFdDQoNCkRpdmlzZXIgbGUgY29udGVudSBkJ3VuZSBjZWxsdWxlIHN1ciB1biB0ZXJtZSB4IGV0IGNvbnNlcnZlciBsZSBjb250ZW51IHByw6ljw6lkZW50IA0KDQotIHZhbHVlLnBhcnRpdGlvbigidGVybWUiKVswXQ0KDQotIHZhbHVlLnBhcnRpdGlvbigiIHRvICIpWzJdLnBhcnRpdGlvbigiIG9uICIpWzBdDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBJbnZlcnNlciBsZSBjb250ZW51IGQndW5lIGNlbGx1bGUNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCkRpdmlzZXIgbGUgY29udGVudSBkJ3VuZSBjZWxsdWxlIGV0IGludmVyc2VyIGwnb3JkcmUgZGUgcHLDqXNlbnRhdGlvbiBlbiBham91dGFudCB1bmUgdmlyZ3VsZSBlbnRyZSBsZXMgZGV1eCAgDQoNCi0gdmFsdWUuc3BsaXQoJyAnKVsxXSArICIsIiArICIgIiArIHZhbHVlLnNwbGl0KCcgJylbMF0NCg0KT1UNCg0KLSB2YWx1ZS5tYXRjaCgvKC4qKSwoLiopLykucmV2ZXJzZSgpLmpvaW4oIiAiKQ0KPC9kaXY+DQoNCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gyIj4NCiMjIyMgQWpvdXRlciB1biB6w6lybyBwb3VyIGF2b2lyIHVuIG5vbWJyZSBkZSBjYXJhY3TDqHJlcyBwcsOpY2lzDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQpBam91dGVyIHVuIHrDqXJvIGRldmFudCBsZSBjb250ZW51IHNpIGRvbm5lIHVuZSBjaGFpbmUgZGUgMCDDoCAyIGNhcmFjdMOocmVzICANCg0KLSAiMCJbMCwyLWxlbmd0aCh2YWx1ZSldICsgdmFsdWUNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBBcHBsaXF1ZXIgZGVzIGNvbmRpdGlvbnMNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCkZvbmN0aW9uIGlmIC0gbcOqbWUgY2hvc2UgcXVlIGRhbnMgZXhjZWwgIA0KDQotIGlmKHRlc3QsIHNpIHRlc3QgZXN0IHZyYWksIHNpIHRlc3QgZXN0IHZyYWkpDQoNClNpIGxhIGNlbGx1bGUgY29udGllbnQgeCwgw6ljcmlyZSB4LCBzaW5vbiB5DQoNCi0gaWYodmFsdWUuY29udGFpbnMoIngiKSwgIngiLCAieSIpDQogDQotIGlmKHZhbHVlLmNvbnRhaW5zKCIxIiksIHZhbHVlLCBudWxsKQ0KDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gyIj4NCiMjIyMgQ29tcGFyZXIgZGV1eCBjb2xvbm5lcw0KPC9kaXY+DQo8ZGl2IGNsYXNzID0gImJveDEiPg0KSWRlbnRpZmllciBzaSBsZSBjb250ZW51IGRlcyBjZWxsdWxlcyBkJ3VuZSBjb2xvbm5lIGVzdCBwYXJlaWwgw6AgdW5lIGF1dHJlICANCg0KLSB2YWx1ZSA9PSBjZWxsc1snYXV0cmUtY29sb25uZSddLnZhbHVlDQoNCkVzdC1jZSBxdWUgbGUgcHJlbWllciBjYXJhY3TDqHJlIGRlIGxhIGNvbG9ubmUgeCBlc3QgbGUgbcOqbWUgcXVlIGxhIGNvbG9ubmUgeSAgDQoNCi0gY2VsbHNbImNvbG9ubmUxIl0udmFsdWVbMF0gPT0gY2VsbHNbImNvbG9ubmUyIl0udmFsdWVbMF0NCg0KQ29tcGFyZXIgbGUgY29udGVudSBkZSBkZXV4IGNvbG9ubmVzIGV0IG1vZGlmaWVyIGxlcyB2YWxldXJzIHNlbG9uIGxlIHLDqXN1bHRhdCBkZSBsYSBjb25kaXRpb24gIA0KDQotIGlmKGNlbGxzWyJjb2xvbm5lMSJdLnZhbHVlID09IGNlbGxzWyJjb2xvbm5lMiJdLnZhbHVlLCAiUGFyZWlsIiwgIlBhcyBwYXJlaWwiKQ0KPC9kaXY+DQoNCjwvYnI+DQoNCjxkaXYgY2xhc3MgPSAiYm94MiI+DQojIyMjIFbDqXJpZmllciBsZSBmb3JtYXQgZCd1bmUgY29sb25uZQ0KPC9kaXY+DQo8ZGl2IGNsYXNzID0gImJveDEiPg0KDQotIHZhbHVlLnR5cGUoKSAgDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQoNCg0KPGRpdiBjbGFzcyA9ICJib3gyIj4NCiMjIyMgRmFpcmUgZGVzIGNhbGN1bHMgc2ltcGxlcyAodmFsZXVycyBudW3DqXJpcXVlcykNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KU29tbWUgZCd1bmUgY29sb25uZSBwbHVzIHVuZSBhdXRyZSAgDQoNCi0gdmFsdWUgKyBjZWxsc1snSm91ciBkdSBtb2lzJ10udmFsdWUNCg0KQXJyb25kaXIgbGUgY29udGVudSAgDQoNCi0gcm91bmQodmFsdWUpDQo8L2Rpdj4NCg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBSZXByZW5kcmUgZXQgY29uY2F0w6luZXIgbGUgY29udGVudSBkJ3VuZSBhdXRyZSBjb2xvbm5lDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQpDcsOpZXIgdW5lIG5vdXZlbGxlIGNvbG9ubmUgZW4gZnVzaW9ubmFudCBsZSBjb250ZW51IGRlIGRldXggYXV0cmVzIGV0IGFqb3V0ZXIgZHUgdGV4dGUgIA0KDQotIGNlbGxzWydub20nXS52YWx1ZSArIGNlbGxzWydub20nXS52YWx1ZSArICJCb25qb3VyISINCg0KQ3LDqWVyIHVuZSBub3V2ZWxsZSBjb2xvbm5lIGF2ZWMgbGVzIHRyb2lzIHByZW1pZXJzIGNhcmFjdMOocmVzIHNldWxlbWVudCAgDQoNCi0gY2VsbHNbJ1N5bXB0b21lJ10udmFsdWVbMCwzXQ0KDQpUcmFuc2Zvcm1lciBsZSBjb250ZW51IGQndW5lIGNvbG9ubmUgZW4gY29uY2F0w6luYW50IGxlIGNvbnRlbnUgZCd1bmUgYXV0cmUgIA0KDQotIHZhbHVlICsgJyAnICsgY2VsbHNbJ3N0cmVldC10eXBlJ10udmFsdWUNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBSZW1wbGFjZXIgZGVzIGNhcmFjdMOocmVzDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQoNClJlbXBsYWNlciB0b3V0IGxlIGNvbnRlbnUgZCd1bmUgY29sb25uZSAoaWNpLCB2aWRlciBsYSBjb2xvbm5lKSAgDQoNCi0gdmFsdWUucmVwbGFjZSh2YWx1ZSwgIiIpDQoNClJlbXBsYWNlciB1bmUgbGV0dHJlIHBhciB1bmUgYXV0cmUgIA0KDQotIHZhbHVlLnJlcGxhY2VDaGFycygibyIsICJhIikNCg0KRmFpcmUgcGx1c2lldXJzIHJlbXBsYWNlbWVudHMgZCd1biBjb3VwICANCg0KLSB2YWx1ZS5yZXBsYWNlKCIxIiwgInVuIikucmVwbGFjZSgiMiIsICJkZXV4IikucmVwbGFjZSgiMyIsICJ0cm9pcyIpDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gyIj4NCiMjIyMgSWRlbnRpZmllciBkZXMgY2VsbHVsZXMgcXVpIGNvbW1lbmNlbnQgcGFyLi4uIChyw6lzdWx0YXQgYm9vbMOpZW4pDQo8L2Rpdj4NCjxkaXYgY2xhc3MgPSAiYm94MSI+DQoNCi0gdmFsdWUuc3RhcnRzV2l0aCgiQmVycmkiKSAgDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBTdXBwcmltZXIgdW4gY2FyYWN0w6hyZSBkZSBkw6lidXQgb3UgZmluIGRlIHZhbGV1cjoNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KU3VwcHJpbWUg4oCcU+KAnSBkdSBkw6lidXQgZGUgbGEgY2VsbHVsZSAgDQoNCi0gdmFsdWUucmVwbGFjZSgvXlMvLCIiKSBbcmVnZXggXiBpbmRpcXVlIGxlIGTDqWJ1dCBkJ3VuZSBjZWxsdWxlXQ0KDQpTdXBwcmltZSAiLiIgw6AgbGEgZmluIGRlIGxhIGNlbGx1bGUgIA0KDQotIHZhbHVlLnJlcGxhY2UoL1wuJC8sIiIpIFtyZWdleCAkIGluZGlxdWUgbGEgZmluIGQndW5lIGNlbGx1bGVdDQo8L2Rpdj4NCg0KPC9icj4NCg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCg0KTW9kaWZpZXIvc3VwcHJpbWVyIGxhIHBvbmN0dWF0aW9uDQoNCi0gdmFsdWUucmVwbGFjZSgvXHB7UHVuY3R9LywnICcpDQoNCjwvZGl2Pg0KDQo8L2JyPg0KDQo8ZGl2IGNsYXNzID0gImJveDIiPg0KIyMjIyBUcmF2YWlsbGVyIGF2ZWMgdW4gZm9ybWF0IGRhdGUNCjwvZGl2Pg0KPGRpdiBjbGFzcyA9ICJib3gxIj4NCkV4dHJhaXJlIHNldWxlbWVudCB1bmUgcGFydGllIGQndW5lIGRhdGUgIA0KDQotIHZhbHVlLnRvRGF0ZSgpLmRhdGVQYXJ0KCJ5ZWFyIikgIA0KDQotICBkaWZmKG5vdygpLHZhbHVlLCd3ZWVrcycpICANCg0KPC9kaXY+DQoNCg0KKioqDQoNCg0KIyAxNC4gUmVzc291cmNlcw0KDQotIFtTaXRlIGV0IGRvY3VtZW50YXRpb24gb2ZmaWNpZWxzXShodHRwczovL29wZW5yZWZpbmUub3JnLykNCg0KLSBKb2huIExpdHRsZSwgMjAxOCwgW0NsZWFuaW5nIERhdGEgd2l0aCBPcGVuUmVmaW5lXShodHRwczovL2xpYmpvaG4uZ2l0aHViLmlvL29wZW5yZWZpbmUvaW5kZXguaHRtbCkgIA0KDQotIEV2YW4gV2lsbCwgMjAyMSwgW0dldCBTdGFydGVkIHdpdGggT3BlblJlZmluZTogRXhwbG9yZSwgQ2xlYW4sIGFuZCBUcmFuc2Zvcm0geW91ciBEYXRhIV0oaHR0cHM6Ly9ldmFud2lsbC5naXRodWIuaW8vb3BlbnJlZmluZS1iLykgIA0KDQotIFVDTEEsIDIwMTksIFtHZXR0aW5nIHN0YXJ0ZWQgd2l0aCBPcGVuUmVmaW5lIERpZ2l0YWwgSHVtYW5pdGllcyAyMDFdKGh0dHA6Ly9taXJpYW1wb3NuZXIuY29tL2NsYXNzZXMvZGgyMDF3MTkvdHV0b3JpYWxzLWd1aWRlcy9kYXRhLWNsZWFuaW5nLWFuZC1tYW5pcHVsYXRpb24vZ2V0dGluZy1zdGFydGVkLXdpdGgtb3BlbnJlZmluZS8pDQoNCi0gW1JlZmluZVBybyBLbm93bGVkZ2UgQmFzZSBmb3IgT3BlblJlZmluZV0oaHR0cHM6Ly9rYi5yZWZpbmVwcm8uY29tLykNCg0KLSBTZXRoIHZhbiBIb29sYW5kLCBSdWJlbiBWZXJib3JnaCwgYW5kIE1heCBEZSBXaWxkZSwgW0NsZWFuaW5nIERhdGEgd2l0aCBPcGVuUmVmaW5lXShodHRwczovL3Byb2dyYW1taW5naGlzdG9yaWFuLm9yZy9lbi9sZXNzb25zL2NsZWFuaW5nLWRhdGEtd2l0aC1vcGVucmVmaW5lKQ0KDQotIFtJbnRyb2R1Y3Rpb24gdG8gT3BlblJlZmluZV0oaHR0cHM6Ly9kb2FuYS5naXRib29rcy5pby90ZXN0L2NvbnRlbnQvKQ0KDQotIERhdGEgQ2FycGVudHJ5LCBbRGF0YSBDbGVhbmluZyB3aXRoIE9wZW5SZWZpbmUgZm9yIEVjb2xvZ2lzdHNdKGh0dHBzOi8vZGF0YWNhcnBlbnRyeS5vcmcvT3BlblJlZmluZS1lY29sb2d5LWxlc3Nvbi8wMC1nZXR0aW5nLXN0YXJ0ZWQvaW5kZXguaHRtbCkNCg0KLSBPd2VuIFN0ZXBoZW5zLCAyMDE0LCBbSW50cm9kdWN0aW9uIHRvIE9wZW5SZWZpbmVdKGh0dHA6Ly93d3cubWVhbmJveWZyaWVuZC5jb20vb3ZlcmR1ZV9pZGVhcy93cC1jb250ZW50L3VwbG9hZHMvMjAxNC8xMS9JbnRyb2R1Y3Rpb24tdG8tT3BlblJlZmluZS1oYW5kb3V0LUNDLUJZLnBkZikNCg0KLSBWZXJib3JnaCBldCBEZSBXaWxkZSwgMjAxMywgW1VzaW5nIE9wZW5SZWZpbmVdKGh0dHBzOi8vd3d3LmdiaWYuZXMvd3AtY29udGVudC91cGxvYWRzLzIwMTgvMDEvVXNpbmctT3BlblJlZmluZUJvb2sucGRmKQ0KDQotIFtMaWJyYXJ5IENhcnBlbnRyeTogT3BlblJlZmluZV0oaHR0cHM6Ly9saWJyYXJ5Y2FycGVudHJ5Lm9yZy9sYy1vcGVuLXJlZmluZS8wMS1pbnRyb2R1Y3Rpb24vaW5kZXguaHRtbCkNCg0KLSBbR3JhdGVmdWwgRGF0YV0oaHR0cHM6Ly9naXRodWIuY29tL3Njb3R0eXRoZXJlZC9ncmF0ZWZ1bGRhdGEvd2lraSkgIA0KDQotIFtEYXZpZCBIdXluaCwgR29vZ2xlIFJlZmluZV0oaHR0cDovL3d3dy5kYXZpZGh1eW5oLm5ldC9zcGFjZXMvbmljYXIyMDExL3R1dG9yaWFsLnBkZikNCg0KLSBbT3BlbiBSZWZpbmUgRk9yIExpYnJhcmlhbnNdKGh0dHA6Ly9saXdvbmcuYmxvZ3Nwb3QuY29tLykNCg0KLSBbQ2hlYXQgU2hlZXQ6IFJlZ3VsYXIgRXhwcmVzc2lvbnMgJiBHUkVMXShodHRwczovL2NvZGU0bGlidG9yb250by5naXRodWIuaW8vMjAxOC0xMC0xMi1hY2Nlc3MvR29vZ2xlUmVmaW5lQ2hlYXRTaGVldHMucGRmKQ0KDQotICpSZWNpcGVzKjogW09wZW4gUmVmaW5lIGZvciBMaWJyYXJpYW5zXShodHRwOi8vbGl3b25nLmJsb2dzcG90LmNvbS9zZWFyY2gvbGFiZWwvcmVjaXBlKQ0KDQotIFtHUkVMIFJlY2lwZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuUmVmaW5lL09wZW5SZWZpbmUvd2lraS9SZWNpcGVzKQ0KDQotIFtFdGMhXShodHRwczovL2dpdGh1Yi5jb20vT3BlblJlZmluZS9PcGVuUmVmaW5lL3dpa2kvRXh0ZXJuYWwtUmVzb3VyY2VzKQ0KDQoNCjxzdHlsZT4NCi5yaWdodCB7DQogZmxvYXQ6IHJpZ2h0Ow0KfQ0KDQouY2VudGVyIHsNCiBhbGlnbjogY2VudGVyOw0KfQ0KDQoubm90ZSB7DQogIHBhZGRpbmc6IDAuNWVtOw0KICBib3JkZXItc3R5bGU6IHNvbGlkOw0KICBib3JkZXItY29sb3I6IGdyZWVuOw0KICBib3JkZXItd2lkdGg6IHRoaW47DQogIGZvbnQtc2l6ZTogOTAlOw0KICBib3JkZXItcmFkaXVzOiAxMHB4Ow0KfQ0KDQouYm94MSB7DQogIHBhZGRpbmc6IDAuNWVtOw0KICBiYWNrZ3JvdW5kOiAjZTBlYmViOw0KICBjb2xvcjogYmxhY2s7DQogIGJvcmRlci1yYWRpdXM6IDEwcHg7DQp9DQoNCi5ib3gyIHsNCiAgcGFkZGluZzogMC41ZW07DQogIGJhY2tncm91bmQ6ICM5MmI5Yjk7DQogIGNvbG9yOiB3aGl0ZTsNCiAgYm9yZGVyLXJhZGl1czogMTBweDsNCn0NCi5jZW50ZXIgew0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCi50aXRsZSB7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgY29sb3I6ICMwMDMzNjY7DQp9DQoNCi5zdWJ0aXRsZSB7DQogIGNvbG9yOiAjMDAzMzY2Ow0KfQ0KDQpoMSwgaDIsIGgzLCBoNCwgaDUsIGg2LCBsZWdlbmQgew0KICBjb2xvcjogIzVBN0I5QzsNCn0NCg0KPC9zdHlsZT4=