—————————
1.1 Sources des données
Les données sont extraites du site de la FAO qui fournit de nombreuses informations au niveau mondial sur des thèmes tels que la population, l’agriculture, la sécurité etc.
Il y a des variables imposées :
- différence de population entre une année antérieure (au choix) et l’année courante, exprimée en pourcentage
- proportion de protéines d’origine animale par rapport à la quantité totale de protéines dans la disponibilité alimentaire du pays
- disponibilité alimentaire en protéines par habitant
- disponibilité alimentaire en calories par habitant
Et des variables au choix : - PIB par habitant ( pour avoir une idée de la possibilité des vendre quelquechose ) - Distance depuis la France ( pour évaluer le coût de transport et l’impact écologique ) - Nom des pays au format ISO trois caractères ( pour combiner le tableau des distances ) - Production de poulets ( pour voir la concurrence potentielle ) - Indice de sécurité ( pour évaluer le risque de s’implanter dans ce pays )
1.2 Installation des packages
-> L’installation des packages ne se fait qu’une seule fois, je les ai commentées pour éviter de réisntaller à chaque chargement du script
#install.packages("FactoMineR", dependendcies=T)
#install.packages("factoextra",dependencies=T)
#install.packages(c("Factoshiny"))
#install.packages("ggpubr")
1.3 Installation des libraries
-> L’activation des librairies se fait à chaque démarrage du script
-> corrplot doit être appelé après ggplot2 pour éviter un warning
library(FactoMineR)
library(factoextra)
library(ggpubr)
library(dplyr)
library(ggplot2)
library(corrplot)
options(ggrepel.max.overlaps = Inf)
1.4 Configuration des variables pour chaque fichier
-> définition d’une variable répertoire pour faciliter le changement d’OS
repertoire <- "/home/user/Documents/formations/oc/Formation Analyst/P5/sources/"
fic_pop <- paste (repertoire,"population.csv",sep = "")
fic_pop2017 <- paste (repertoire,"pop_2017.csv",sep = "")
fic_cal <- paste(repertoire,"kcal_personne.csv",sep="")
fic_prot_volaille <- paste(repertoire,"prot_volaille.csv",sep="")
fic_poulet_prod <- paste(repertoire,"poulets_production_2019.csv",sep="")
fic_prot_ani <- paste(repertoire,"prot_ani.csv",sep="")
fic_prot_veg <- paste(repertoire,"prot_veg.csv",sep="")
fic_pib <- paste (repertoire,"pib_gdp.csv",sep = "")
fic_dis <- paste (repertoire,"distances.csv",sep = "")
fic_iso <- paste (repertoire,"sql-pays.csv",sep = "")
fic_prod <- paste (repertoire,"production_poulet.csv",sep = "")
fic_secu <- paste (repertoire,"security.csv",sep = "")
fic_full <- paste (repertoire,"full.csv", sep = "")
fic_export_pays_cluster <- paste (repertoire,"../P5_pays_cluster.csv", sep = "")
fic_export_centroid <- paste (repertoire,"../P5_centroid.csv", sep = "")
1.5 Création des Data Frame par lecture des fichiers
-> les critères d’importation, séparateurs, virgules décimales, entête etc, ont étés définis après observation des fichiers sources à l’aide d’une éditeur de texte ou d’un tableur
df_pop <- read.csv2(fic_pop,header = TRUE, sep = ",", dec = ".")
df_pop2017 <- read.csv2(fic_pop2017,header = TRUE, sep = ",", dec = ".")
df_cal <- read.csv2(fic_cal,header = TRUE, sep = ",", dec = ".")
df_prot_volaille <- read.csv2(fic_prot_volaille,header = TRUE, sep = ",", dec = ".")
df_prot_ani <- read.csv2(fic_prot_ani,header = TRUE, sep = ",", dec = ".")
df_prot_veg <- read.csv2(fic_prot_veg,header = TRUE, sep = ",", dec = ".")
df_pib <- read.csv2(fic_pib,header = TRUE, sep = ",", dec = ".")
df_dis <- read.csv2(fic_dis,header = TRUE, sep = ",", dec = ".")
df_iso <- read.csv2(fic_iso,header = FALSE, sep = ",", dec = ".")
df_prod <- read.csv2(fic_prod,header = TRUE, sep = ",", dec = ".")
df_secu <- read.csv2(fic_secu,header = TRUE, sep = ",", dec = ".")
-> Vérification d’un DF créé par importation
head(df_prot_ani)
1.6 Nettoyage des DataFrames en supprimant et renommant des colonnes
-> Je supprime les colonnes superflues et normalise les noms des variables ou les rend plus explicites
df_pop <- subset(df_pop, select = c(Code.zone, Area, Value))
names(df_pop)[names(df_pop)=="Area"]<-"Zone"
names(df_pop)[names(df_pop)=="Value"]<-"Hab1000"
df_pop2017 <- subset(df_pop2017, select = c(Code.zone, Valeur))
names(df_pop2017)[names(df_pop2017)=="Valeur"]<-"Hab2017x1000"
df_cal <- subset(df_cal, select = c(Code.zone, Valeur))
names(df_cal)[names(df_cal)=="Valeur"]<-"kcal_pers_jour"
df_prot_veg <- subset(df_prot_veg, select = c(Code.zone, Valeur))
names(df_prot_veg)[names(df_prot_veg)=="Valeur"]<-"prot_veg"
df_prot_ani <- subset(df_prot_ani, select = c(Code.zone, Valeur))
names(df_prot_ani)[names(df_prot_ani)=="Valeur"]<-"prot_ani"
df_prot_volaille <- subset(df_prot_volaille, select = c(Code.zone, Valeur))
names(df_prot_volaille)[names(df_prot_volaille)=="Valeur"]<-"prot_volaille"
df_pib <- subset(df_pib, select = c(Code.zone, Valeur))
names(df_pib)[names(df_pib)=="Valeur"]<-"PIB_usd_hab"
df_dis <- subset(df_dis, select = c(X, FRA))
names(df_dis)[names(df_dis)=="X"]<-"ISO"
names(df_dis)[names(df_dis)=="FRA"]<-"distance"
df_iso <- subset(df_iso, select = c(V6, V4))
names(df_iso)[names(df_iso)=="V6"]<-"Zone"
names(df_iso)[names(df_iso)=="V4"]<-"ISO"
df_prod <- subset(df_prod, select = c(Code.zone, Valeur))
names(df_prod)[names(df_prod)=="Valeur"]<-"Poulets1000"
df_secu <- subset(df_secu, select = c(Area.Code, Value))
names(df_secu)[names(df_secu)=="Value"]<-"securite"
names(df_secu)[names(df_secu)=="Area.Code"]<-"Code.zone"
-> Vérification d’une modification de DF
head(df_prot_ani)
-> Suppression des provinces de la Chine pour éviter les doublons car on a déjà vu que la chine était représentée deux fois, une fois le pays et une fois les provinces mais aussi la France car ce n’est pas un pays d’exportation
subset(df_pop, Zone == "France")
df_pop <- df_pop[!df_pop$Code.zone %in% c("96","128","41","214","68"),]
-> Vérification de la compilation des DF
head(df_full)
1.8 Colonnes calculées ( évolution population et rapport protéines )
df_full$pop_evo <-100-(100*df_full$Hab2017x1000/df_full$Hab1000)
df_full$prot_rapport <-df_full$prot_ani/(df_full$prot_veg+df_full$prot_ani)
-> suppression des colonnes qui ont servi pour les calculs
df_full <- subset(df_full, select = -c(Code.zone, ISO, Hab2017x1000,prot_veg,prot_ani, prot_volaille))
Nous vérifions les variables qui auraient des manques.
print(paste0('Il y a ', dim(subset(df_full, is.na(Hab1000)))[1]," données manquantes pour le nombre d'habitants."))
[1] "Il y a 0 données manquantes pour le nombre d'habitants."
print(paste0('Il y a ', dim(subset(df_full, is.na(kcal_pers_jour)))[1]," données manquantes pour le kcal_pers_jour."))
[1] "Il y a 0 données manquantes pour le kcal_pers_jour."
print(paste0('Il y a ', dim(subset(df_full, is.na(PIB_usd_hab)))[1]," données manquantes pour le PIB_usd_hab."))
[1] "Il y a 0 données manquantes pour le PIB_usd_hab."
print(paste0('Il y a ', dim(subset(df_full, is.na(Poulets1000)))[1]," données manquantes pour le Poulets1000."))
[1] "Il y a 0 données manquantes pour le Poulets1000."
print(paste0('Il y a ', dim(subset(df_full, is.na(distance)))[1]," données manquantes pour la distance."))
[1] "Il y a 0 données manquantes pour la distance."
print(paste0('Il y a ', dim(subset(df_full, is.na(securite)))[1]," données manquantes pour la securite."))
[1] "Il y a 0 données manquantes pour la securite."
print(paste0('Il y a ', dim(subset(df_full, is.na(pop_evo)))[1]," données manquantes pour le pop_evo."))
[1] "Il y a 0 données manquantes pour le pop_evo."
print(paste0('Il y a ', dim(subset(df_full, is.na(prot_rapport)))[1]," données manquantes pour le prot_rapport."))
[1] "Il y a 0 données manquantes pour le prot_rapport."
# on aurait pu ne garder que les pays ayant toutes les variables définies avec la commande suivante
df_full <- df_full[complete.cases(df_full),]
Vérification
head(df_full)
Ecriture d’un fichier CSV avec cette DF complête pour un contrôle extérieur si nécessaire
write.csv2(df_full, file = fic_full)
DF trié par nom de pays et nom du pays comme index
df_full_order <- df_full[order(df_full[,"Zone"],decreasing=F),]
df_full_individus<- data.frame(df_full_order[,-1], row.names=df_full_order[,1])
# vérification
head(df_full_individus)
—————————
Objetcif : Identifier des groupes similaires dans un jeu de données
data frame centré réduit avec scale - réduit le poids des variables à forte variance
df_full_centre_reduit <- scale(df_full_individus)
HCPC par rapport à l’ACP sur 5 clusters
-> je fais dabord un premier calcul de l’ACP pour utiliser le résultat avec la fonction HCPC
-> j’exploite le res.pca issu de la fonction PCA sur la data frame centré réduit
ACP sur la table centré réduit
res.pca <- PCA(df_full_centre_reduit, scale.unit = FALSE, graph = FALSE)
HCPC
res.hcpc <- HCPC(res.pca,nb.clust = 5, graph = FALSE)
dendograme en 5 clusters à partir de l’HCPC
img_dendogramme <- fviz_dend(res.hcpc,
labelsize = 2,
cex = 0.7, # Taille du text
palette = "jco", # Palette de couleur ?ggpubr::ggpar
rect = TRUE, rect_fill = TRUE, # Rectangle autour des groupes
rect_border = "jco", # Couleur du rectangle
labels_track_height = 0.8 # Augment l'espace pour le texte
) + ggsave("P5_img_dendogramme.png", width = 11, height = 8)
plot(img_dendogramme)

Observation des clusters
fviz_cluster(res.hcpc,
labelsize = 3,
repel = TRUE, # Evite le chevauchement des textes
show.clust.cent = TRUE, # Montre le centre des clusters
palette = "jco", # Palette de couleurs, voir ?ggpubr::ggpar
ggtheme = theme_minimal(),
main = "Factor map"
)

rajout de la variable cluster au df
df_full_centre_reduit_cluster <-res.hcpc$data.clust
pays_cluster <- subset(df_full_centre_reduit_cluster, select=c(clust))
write.csv2(pays_cluster, file = fic_export_pays_cluster)
head(pays_cluster)
Centroides - grouby sur les cluster et moyennes de chaque varibles
df_full_cluster <- cbind(df_full_individus,pays_cluster$clust)
colnames(df_full_cluster)[colnames(df_full_cluster)=="pays_cluster$clust"] <- "clust"
df_full_centroides <- df_full_cluster %>%
group_by(clust) %>%
summarize(moy_hab = mean(Hab1000, na.rm = TRUE), moy_dis = mean(distance,na.rm=TRUE), moy_PIB=mean(PIB_usd_hab,na.rm=TRUE),moy_poulets=mean(Poulets1000,na.rm=TRUE),
moy_secu=mean(securite,na.rm=TRUE),moy_kcal=mean(kcal_pers_jour,na.rm=TRUE), moy_pop_evo=mean(pop_evo,na.rm=TRUE),moy_prot=mean(prot_rapport,na.rm=TRUE) )
write.csv2(df_full_centroides, file = fic_export_centroid)
head(df_full_centroides)
df_centroid <- df_full_centroides[,2:9]
df_centroid_scaled <- scale(df_centroid)
Matrice <- data.matrix(df_centroid_scaled)
print(Matrice)
moy_hab moy_dis moy_PIB moy_poulets moy_secu moy_kcal moy_pop_evo
[1,] -0.4009869 -0.09033865 -0.6414561 -0.4676152 -0.82938665 -1.2559588 1.57151929
[2,] 1.7880118 0.86341248 -0.5549279 1.7883461 -1.03896752 -0.3772466 0.06496343
[3,] -0.4537773 1.12973859 -0.3495361 -0.4324813 0.50847179 -0.3622087 -0.13029278
[4,] -0.4462014 -1.23398449 -0.2178675 -0.4156580 -0.04444845 0.7164432 -1.18600755
[5,] -0.4870461 -0.66882794 1.7637878 -0.4725916 1.40433082 1.2789709 -0.32018239
moy_prot
[1,] -1.4253574
[2,] -0.4060094
[3,] 0.2949569
[4,] 0.2504042
[5,] 1.2860057
attr(,"scaled:center")
moy_hab moy_dis moy_PIB moy_poulets moy_secu moy_kcal
1.178189e+05 5.947875e+03 1.958858e+04 4.148921e+05 -1.261467e-01 2.943993e+03
moy_pop_evo moy_prot
1.194850e+00 4.364698e-01
attr(,"scaled:scale")
moy_hab moy_dis moy_PIB moy_poulets moy_secu moy_kcal moy_pop_evo
2.196203e+05 2.991056e+03 2.798917e+04 7.913869e+05 8.699533e-01 3.790431e+02 7.637357e-01
moy_prot
1.405852e-01
Description de la répartition des clusters
res.hcpc$desc.var
Link between the cluster variable and the quantitative variables
================================================================
Eta2 P-value
PIB_usd_hab 0.7467896 3.244785e-37
Poulets1000 0.6596635 4.762308e-29
prot_rapport 0.6233566 2.959460e-26
kcal_pers_jour 0.5553040 1.093472e-21
pop_evo 0.5416622 7.381464e-21
distance 0.5352245 1.781485e-20
Hab1000 0.4606421 2.109411e-16
securite 0.4350143 3.894074e-15
Description of each cluster by quantitative variables
=====================================================
$`1`
v.test Mean in category Overall mean sd in category Overall sd
pop_evo 7.801112 0.9786282 -2.714581e-17 0.54097450 0.9962335
PIB_usd_hab -4.315366 -0.5413509 -3.201413e-17 0.08106279 0.9962335
securite -6.068048 -0.7612200 1.330389e-18 0.84216224 0.9962335
kcal_pers_jour -6.729919 -0.8442500 1.357519e-16 0.75417992 0.9962335
prot_rapport -8.588433 -1.0773955 7.492571e-17 0.48658880 0.9962335
p.value
pop_evo 6.136397e-15
PIB_usd_hab 1.593388e-05
securite 1.294742e-09
kcal_pers_jour 1.697575e-11
prot_rapport 8.816324e-18
$`2`
v.test Mean in category Overall mean sd in category Overall sd p.value
Poulets1000 9.317068 4.587946 -1.383214e-17 3.002534 0.9962335 1.196001e-20
Hab1000 7.778593 3.830364 1.943412e-18 3.933976 0.9962335 7.333563e-15
$`3`
v.test Mean in category Overall mean sd in category Overall sd
distance 7.196330 0.8039690 5.154607e-17 0.8196829 0.9962335
securite 4.480013 0.5005039 1.330389e-18 0.6781611 0.9962335
prot_rapport 4.169296 0.4657908 7.492571e-17 0.6649568 0.9962335
pop_evo -2.098623 -0.2344567 -2.714581e-17 0.6774155 0.9962335
p.value
distance 6.185483e-13
securite 7.463847e-06
prot_rapport 3.055425e-05
pop_evo 3.585011e-02
$`4`
v.test Mean in category Overall mean sd in category Overall sd
kcal_pers_jour 5.459027 0.9379086 1.357519e-16 0.6784478 0.9962335
prot_rapport 2.478485 0.4258254 7.492571e-17 0.6974020 0.9962335
pop_evo -5.744707 -0.9869909 -2.714581e-17 0.9007136 0.9962335
distance -6.337045 -1.0887597 5.154607e-17 0.2718960 0.9962335
p.value
kcal_pers_jour 4.787501e-08
prot_rapport 1.319416e-02
pop_evo 9.208006e-09
distance 2.342134e-10
$`5`
v.test Mean in category Overall mean sd in category Overall sd
PIB_usd_hab 9.521384 3.064530 -3.201413e-17 1.2229449 0.9962335
kcal_pers_jour 4.493226 1.446179 1.357519e-16 0.2544259 0.9962335
prot_rapport 4.209311 1.354799 7.492571e-17 0.4681281 0.9962335
securite 4.180053 1.345382 1.330389e-18 0.2388849 0.9962335
distance -1.976700 -0.636216 5.154607e-17 1.3324673 0.9962335
p.value
PIB_usd_hab 1.708871e-21
kcal_pers_jour 7.015228e-06
prot_rapport 2.561507e-05
securite 2.914417e-05
distance 4.807553e-02
Heatmap des variables dans chaque cluster pour voir leur importance
corrplot(Matrice, is.corr = FALSE, method = "circle")

Interprétation : -> plus le point est bleu, plus la variable caractérise le cluster
-> plus le point est grand, plus la variable est forte
-> plus le point est rouge moins la variable caractérise le cluster
-> plus le point est petit plus la variable est faible
CLUSTER 1
- évolution de la population est forte
- kcal et protéines sont très faibles
CLUSTER 2 - nombre d’habitants et de poulets élevés
- distance un peu favorable
- la sécurité est en revanche défavorable
CLUSTER 3
- seul la distance est l’atout de cet ensemble
CLUSTER 4
- distance et évolution de la population sont deux variables particulièrement fortes et négatives pour cet ensemble
CLUSTER 5
- des pays riches et sûrs
- une alimentation riche en protéines et en kcal
-> Le groupe 5 présente les plus intéressants paramètres pour notre projet car on y trouve les meilleurs résultats en matière de richesse et de sécurité, ce qui permet d’envisager un commerce plus stable et moins risqué. De plus l’alimentation est plutôt riche.
4.1 Analyse des différents groupes
cluster 1 - évolution de la population sinificativement supérieur à la moyenne
cluster 2 - nombre de poulets sinificativement supérieur à la moyenne
cluster 3 - distances sinificativement supérieur à la moyenne
cluster 4 - évolution des protéines sinificativement supérieur à la moyenne
cluster 5 - PIB sinificativement supérieur à la moyenne
Représentation visuelle des Clusters
df_full_centre_reduit_cluster_trans <- transform(df_full_centre_reduit_cluster, clust = as.factor(clust))
fviz_pca_biplot(res.pca, pointsize = 1, labelsize = 2, axes = c(1,2), select.ind = list(cos2 = 0.50),addEllipses = TRUE, ellipse.level=0.60,col.ind = df_full_centre_reduit_cluster$clust, color_palette=c("#00AFBB", "#E7B800", "#FC4E07","#FC4E07","#FC4E07")) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5)) + ggsave("P5_img_biplot_pca.png", width = 11, height = 8)

-> Cette représentation confirme le choix du cluster 5 car c’est le cluster qui s’approche le plus des consommations souhaitées, mais aussi pour la richesse et la sécurité
—————————
5.1 Suppression de variables
clust car on garde tous les pays
PIB_usb_hab car tous ces pays sont riches
securite car tous ces pays sont sûrs
Poulets1000 car ils n’ont pas une grande quantité de volailles
pop_evo car l’évolution est semblable dans tous ces pays ( plutôt faible )
df_clust5 <- subset(df_clust5, select = -c(clust,PIB_usd_hab,Poulets1000, pop_evo, prot_rapport,securite))
5.2 Ajout d’une nouvelle variable pour essayer de distinguer les individus de ce groupe
# ajout de la production de poulets
fic_poulet_prod <- paste(repertoire,"poulets_production_2019.csv",sep="")
df_poulet_prod <- read.csv2(fic_poulet_prod,header = TRUE, sep = ",", dec = ".")
df_poulet_prod <- subset(df_poulet_prod,select = c(Area,Value))
names(df_pop)[names(df_pop)=="Zone"]<-"Area"
df_poulet_prod <- merge(df_poulet_prod,df_pop,by="Area")
df_poulet_prod$prod_poulet_hab <-df_poulet_prod$Value/df_poulet_prod$Hab1000
df_poulet_prod <- subset(df_poulet_prod,select = c(Area,prod_poulet_hab))
df_clust5$Area <- rownames(df_clust5)
#df_clust5_prod <- merge(df_clust5,df_poulet_prod,by="Area")
#names(df_clust5_prod)[names(df_clust5_prod)=="Value"]<-"Prod_PouletX1000"
#df_clust5_prod<- data.frame(df_clust5_prod[,-1], row.names=df_clust5_prod[,1])
#df_full_individus
df_full_individus$Area <- rownames(df_full_individus)
df_clust5_full <- df_clust5[,0]
df_clust5_full$Area <- rownames(df_clust5_full)
df_clust5_full <- merge(df_clust5_full,df_full_individus, by = 'Area')
df_clust5_full <- merge(df_clust5_full,df_poulet_prod, by = 'Area')
df_clust5_full <- subset(df_clust5_full, select = -c(PIB_usd_hab,Poulets1000, pop_evo, prot_rapport,securite))
df_clust5_full<- data.frame(df_clust5_full[,-1], row.names=df_clust5_full[,1])
df_clust5 <- subset(df_clust5, select = -c(Area))
#df_clust5 <- subset(df_full_centre_reduit_cluster, clust == 5)
#print(df_clust5[,0])
Affichage des tables pour contrôle
df_pop
df_clust5
df_poulet_prod
#df_clust5_prod
df_clust5_full
6.3 ACP sur la table centré réduit du cluster 5
res5.pca <- PCA(df_clust5, scale.unit = FALSE, graph = FALSE)
6.4 HCPC par rapport à l’ACP sans préciser le nombre de clusters
res5.hcpc <- HCPC(res5.pca, graph = FALSE)
6.5 dendograme à partir de l’HCPC
fviz_dend(res5.hcpc,
cex = 0.7, # Taille du text
palette = "jco", # Palette de couleur ?ggpubr::ggpar
rect = TRUE, rect_fill = TRUE, # Rectangle autour des groupes
rect_border = "jco", # Couleur du rectangle
labels_track_height = 0.8 # Augment l'espace pour le texte
)

-> Le dendagramme a constitué 3 clusters ce qui semble un nombre correct de groupes compte tenu du nombre de pays dans chacun d’eux.
Justifier le choix des variables pib et sécurité corrélés mais tous ces pays sont riches et sécurisés
Observation des clusters
fviz_cluster(res5.hcpc,
labelsize = 8 ,
show.clust.cent = TRUE, # Montre le centre des clusters
palette = "jco", # Palette de couleurs, voir ?ggpubr::ggpar
ggtheme = theme_minimal(),
main = "Factor map"
)

fviz_pca_var (res5.pca, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE # Évite le chevauchement de texte
)

df_clust5_scaled <- as.data.frame(df_clust5)
res5.pca <- PCA(df_clust5_scaled, graph = FALSE)
éboulis de valeurs propres
eig5.val <- get_eigenvalue(res5.pca)
perte d’inertie en fonction des dimensions
fviz_eig(res5.pca, addlabels = TRUE, ylim = c(0, 50))

var5 <- get_pca_var(res5.pca)
corrplot(var5$cos2, is.corr=FALSE, title="Qualité des variables", mar=c(0,0,1,0))

# Colorer en fonction du cos2: qualité de représentation
fviz_pca_var(res5.pca, col.var = "cos2",gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),repel = TRUE) + labs(title = "Figure 10 - Cercle des corrélations") + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

NA
NA
fviz_pca_biplot(res5.pca, col.var = "#2E9FDF", pointsize = 1, labelsize = 3, axes = c(1,2)) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

df_clust_scaled_cluster <-res5.hcpc$data.clust
df_clust_scaled_cluster
pays_cluster <- subset(df_clust_scaled_cluster, select=c(clust))
# vérification
# summary(df_full_cluster)
pays_cluster
df_clust_scaled_cluster_trans <- transform(df_clust_scaled_cluster, clust = as.factor(clust))
fviz_pca_biplot(res5.pca, pointsize = 1, labelsize = 2, axes = c(1,2), select.ind = list(cos2 = 0.30),addEllipses = TRUE, ellipse.level=0.60,col.ind = df_clust_scaled_cluster$clust, color_palette=c("#00AFBB", "#E7B800", "#FC4E07","#FC4E07","#FC4E07")) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

df_clust_scaled_cluster_trans <- transform(df_clust_scaled_cluster, clust = as.factor(clust))
fviz_pca_biplot(res5.pca, pointsize = 1, labelsize = 2, axes = c(1,3), select.ind = list(cos2 = 0.30),addEllipses = TRUE, ellipse.level=0.60,col.ind = df_clust_scaled_cluster$clust, color_palette=c("#00AFBB", "#E7B800", "#FC4E07","#FC4E07","#FC4E07")) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

NA
NA
En faisant un ACP sur l’axe 1.2 et 1.3, on observe un groupe se distinguer des autres, le cluster 3 Islande, Luxembourg, Suisse, Finlande et Norvège.
si l’on souhaite réduire encore l’échantillon, je propose de prendre en compte la distance, ce qui réduira la sélection au Luxembourg et la Suisse, lesquels sont frontaliers, riches et qui plus est francophones.
trouver les informations concernant la production, l’importation et éventuellement la consommation
test avec df_clust5_full # ################################################### ### ACP sur la table centré réduit du cluster 5
df_clust5_full
df_clust5_full_centre_reduit
Hab1000 kcal_pers_jour distance prod_poulet_hab
Australia 0.5396770 -0.5428360 2.87116921 0.21115057
Canada 1.1777444 1.1636845 0.51793967 0.24849363
Denmark -0.4636119 -0.4453206 -0.55487032 0.03870601
Finland -0.4756407 -1.0109102 -0.36466099 -0.59947471
France 2.6405942 0.5395855 -0.77616541 -0.03294302
Iceland -0.7473900 2.0218205 -0.29529018 -0.90547345
Israel -0.3258267 0.7931257 -0.05861119 0.60724951
Kuwait -0.5482312 0.2372876 0.17909646 2.75647840
Luxembourg -0.7333708 0.1787783 -0.71422707 -1.03864342
Norway -0.4853149 -0.7378670 -0.48708771 -0.23466830
Switzerland -0.3182759 -0.9036432 -0.67070839 -0.69702870
United Arab Emirates -0.2603535 -1.2937051 0.35341593 -0.35384653
attr(,"scaled:center")
Hab1000 kcal_pers_jour distance prod_poulet_hab
14599.353750 3446.666667 3608.653838 3.772712
attr(,"scaled:scale")
Hab1000 kcal_pers_jour distance prod_poulet_hab
19083.264400 102.547845 4649.336044 3.422019
df_clust5_full_centre_reduit <- scale(df_clust5_full)
res5.pca <- PCA(df_clust5_full_centre_reduit, scale.unit = FALSE, graph = FALSE)
HCPC par rapport à l’ACP et je laisse libre le nombre de clusters
res5.hcpc <- HCPC(res5.pca, graph = FALSE) # nb.clust = 4,
dendograme à partir de l’HCPC
fviz_dend(res5.hcpc,
cex = 0.7, # Taille du text
palette = "jco", # Palette de couleur ?ggpubr::ggpar
rect = TRUE, rect_fill = TRUE, # Rectangle autour des groupes
rect_border = "jco", # Couleur du rectangle
labels_track_height = 0.8 # Augment l'espace pour le texte
)

Observation des clusters
fviz_cluster(res5.hcpc,
labelsize = 8 ,
show.clust.cent = TRUE, # Montre le centre des clusters
palette = "jco", # Palette de couleurs, voir ?ggpubr::ggpar
ggtheme = theme_minimal(),
main = "Factor map"
)

fviz_pca_var (res5.pca, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE # Évite le chevauchement de texte
)

res5.pca <- PCA(df_clust5_full_centre_reduit, graph = FALSE)
éboulis de valeurs propres
eig5.val <- get_eigenvalue(res5.pca)
perte d’inertie en fonction des dimensions
fviz_eig(res5.pca, addlabels = TRUE, ylim = c(0, 50))

var5 <- get_pca_var(res5.pca)
corrplot(var5$cos2, is.corr=FALSE, title="Qualité des variables", mar=c(0,0,1,0))

# Colorer en fonction du cos2: qualité de représentation
fviz_pca_var(res5.pca, col.var = "cos2",gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),repel = TRUE) + labs(title = "Figure 10 - Cercle des corrélations") + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

NA
NA
fviz_pca_biplot(res5.pca, col.var = "#2E9FDF", pointsize = 1, labelsize = 3, axes = c(1,2)) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

fviz_pca_biplot(res5.pca, pointsize = 1, labelsize = 3, axes = c(1,2), select.ind = list(cos2 = 0.30),addEllipses = TRUE, ellipse.level=0.60,col.ind = df_clust_scaled_cluster$clust, color_palette=c("#00AFBB", "#E7B800", "#FC4E07","#FC4E07","#FC4E07")) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

df_clust_scaled_cluster_trans <- transform(df_clust_scaled_cluster, clust = as.factor(clust))
fviz_pca_biplot(res5.pca, pointsize = 1, labelsize = 2, axes = c(1,3), select.ind = list(cos2 = 0.30),addEllipses = TRUE, ellipse.level=0.60,col.ind = df_clust_scaled_cluster$clust, color_palette=c("#00AFBB", "#E7B800", "#FC4E07","#FC4E07","#FC4E07")) + theme(plot.title = element_text(color="#3876C2", size=20, face="bold",hjust = 0.5),axis.title.x = element_text(color="black", size=14, face="bold",hjust = 0.5),axis.title.y = element_text(color="black", size=14, face="bold",vjust = 0.5))

En faisant un ACP sur l’axe 1.2 et 1.3, on observe un groupe se distinguer des autres, le cluster 3 Islande, Luxembourg, Suisse, Finlande et Norvège.
si l’on souhaite réduire encore l’échantillon, je propose de prendre en compte la distance, ce qui réduira la sélection au Luxembourg et la Suisse, lesquels sont frontaliers, riches et qui plus est francophones.
trouver les informations concernant la production, l’importation et éventuellement la consommation
—————————
Affichage des histogrames de plusieurs variables pour voir si l’on peut y retrouver la loi normale
# multiplot : Pour afficher plusieurs graphiques
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
library(grid)
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
p1 <- ggplot(df_full_individus, aes(x=kcal_pers_jour)) + geom_histogram(aes(y=..density..), colour="black", fill="white",bins=30)+
geom_density(alpha=.2, fill="#FF6666") +ggsave("img/figure12_histo.png", width = 15, height = 8)
p2 <- ggplot(df_full_individus, aes(x=prot_rapport)) + geom_histogram(aes(y=..density..), colour="black", fill="white",bins=30)+
geom_density(alpha=.3, fill="#FF6666")
p3 <- ggplot(df_full_individus, aes(x=Poulets1000))+ geom_histogram(aes(y=..density..), colour="black", fill="white",bins=30)+
geom_density(alpha=.3, fill="#FF6666")
p4 <- ggplot(df_full_individus, aes(x=pop_evo))+ geom_histogram(aes(y=..density..), colour="black", fill="white",bins=20)+
geom_density(alpha=.3, fill="#FF6666")
p5 <- ggplot(df_full_individus, aes(x=PIB_usd_hab)) + geom_histogram(aes(y=..density..), colour="black", fill="white",bins=6)+
geom_density(alpha=.3, fill="#FF6666")
p6 <- ggplot(df_full_individus, aes(x=distance)) + geom_histogram(aes(y=..density..), colour="black", fill="white",bins=50)+
geom_density(alpha=.3, fill="#FF6666")
p7 <- ggplot(df_full_individus, aes(x=securite)) + geom_histogram(aes(y=..density..), colour="black", fill="white",bins=8)+
geom_density(alpha=.3, fill="#FF6666")
multiplot(p1, p2, p3, p4,p5,p6,p7, cols=2)

La loi normale se représente par une courbe semblable à une cloche d’église avec un point culminant au milieu
Deux histogrammes s’apparentent à une loi normale, la sécurité et l’évolution de la population
Nous allons donc réaliser des test statistiques sur ces deux variables pour voir si elles respectent la loi normale
—————————
D’après le graphe on peut voir que les cluster 4 et 5 sont proches, nous allons faire une comparaison des variances sur la variable de sécurité pour ces deux clusters
var.test(clust4_secu,clust5_secu)
F test to compare two variances
data: clust4_secu and clust5_secu
F = 10.747, num df = 26, denom df = 8, p-value = 0.00167
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
2.736687 29.330586
sample estimates:
ratio of variances
10.74663
La p-valeur valant 0.2833, on ne rejette donc pas l’égalité des variances au niveau de test 5%.
TEST D’ÉGALITÉ DES MOYENNES
t.test(clust5_secu,clust4_secu,var.equal=TRUE,alternative="greater")
Two Sample t-test
data: clust5_secu and clust4_secu
t = 4.8187, df = 34, p-value = 1.474e-05
alternative hypothesis: true difference in means is greater than 0
95 percent confidence interval:
0.8868746 Inf
sample estimates:
mean of x mean of y
1.34538169 -0.02095088
La p-valeur étant proche de 0 on rejette l’hypothèse d’égalité des moyennes. Les moyennes μ4 et μ5 ne sont donc pas égales.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayAtIFBST0pFVCA1IC0gUEVZUk9OTkUiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICBsYXRleF9lbmdpbmU6IGx1YWxhdGV4CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMjIyBSYXBwZWwgZHUgcHJvamV0Ckwnb2JqZWN0aWYgZGUgY2UgcHJvamV0IGVzdCBkZSByw6lhbGlzZXIgdW5lIMOpdHVkZSBkZSBtYXJjaMOpIMOgIGwnYWlkZSBkJ2luZm9ybWF0aW9ucyBxdWUgbCdvbiBwZXV0IGNob2lzaXIgbGlicmVtZW50IHBvdXIgdHJvdXZlciBkZXMgcGF5cyBkYW5zIGxlc3F1ZWxzIGlsIHNlcmFpdCBwb3NzaWJsZSBkJ2V4cG9ydGVyIGRlcyBwb3VsZXRzIGRlcHVpcyBsYSBGcmFuY2UuCkFpbnNpLCBpZMOpYWxlbWVudCwgbm91cyByZWNoZXJjaG9ucyBkZXMgcGF5cyByaWNoZXMgZXQgc8O7cnMsIHZvaXNpbnMgZGUgbGEgRnJhbmNlIGRhbnMgbGVzcXVlc2wgbGEgY29uc29tbWF0aW9uIGRlIHByb3TDqWluZXMgYW5pbWFsZSBlc3Qgw6lsZXbDqWUgbWFpcyBsYSBwcm9kdWN0aW9uIHkgZXN0IGZhaWJsZS4KCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIDEgSW1wb3J0YXRpb24gZGVzIGRvbm7DqWVzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgMS4xIFNvdXJjZXMgZGVzIGRvbm7DqWVzCkxlcyBkb25uw6llcyBzb250IGV4dHJhaXRlcyBkdSBzaXRlIGRlIGxhIEZBTyBxdWkgZm91cm5pdCBkZSBub21icmV1c2VzIGluZm9ybWF0aW9ucyBhdSBuaXZlYXUgbW9uZGlhbCBzdXIgZGVzIHRow6htZXMgdGVscyBxdWUgbGEgcG9wdWxhdGlvbiwgbCdhZ3JpY3VsdHVyZSwgbGEgc8OpY3VyaXTDqSBldGMuCgpJbCB5IGEgZGVzIHZhcmlhYmxlcyBpbXBvc8OpZXMgOgoKLSBkaWZmw6lyZW5jZSBkZSBwb3B1bGF0aW9uIGVudHJlIHVuZSBhbm7DqWUgYW50w6lyaWV1cmUgKGF1IGNob2l4KSBldCBsJ2FubsOpZSBjb3VyYW50ZSwgZXhwcmltw6llIGVuIHBvdXJjZW50YWdlCi0gcHJvcG9ydGlvbiBkZSBwcm90w6lpbmVzIGQnb3JpZ2luZSBhbmltYWxlIHBhciByYXBwb3J0IMOgIGxhIHF1YW50aXTDqSB0b3RhbGUgZGUgcHJvdMOpaW5lcyBkYW5zIGxhIGRpc3BvbmliaWxpdMOpIGFsaW1lbnRhaXJlIGR1IHBheXMKLSBkaXNwb25pYmlsaXTDqSBhbGltZW50YWlyZSBlbiBwcm90w6lpbmVzIHBhciBoYWJpdGFudAotIGRpc3BvbmliaWxpdMOpIGFsaW1lbnRhaXJlIGVuIGNhbG9yaWVzIHBhciBoYWJpdGFudAoKRXQgZGVzIHZhcmlhYmxlcyBhdSBjaG9peCA6Ci0gUElCIHBhciBoYWJpdGFudCAoIHBvdXIgYXZvaXIgdW5lIGlkw6llIGRlIGxhIHBvc3NpYmlsaXTDqSBkZXMgdmVuZHJlIHF1ZWxxdWVjaG9zZSApCi0gRGlzdGFuY2UgZGVwdWlzIGxhIEZyYW5jZSAoIHBvdXIgw6l2YWx1ZXIgbGUgY2/Du3QgZGUgdHJhbnNwb3J0IGV0IGwnaW1wYWN0IMOpY29sb2dpcXVlICkKLSBOb20gZGVzIHBheXMgYXUgZm9ybWF0IElTTyB0cm9pcyBjYXJhY3TDqHJlcyAoIHBvdXIgY29tYmluZXIgbGUgdGFibGVhdSBkZXMgZGlzdGFuY2VzICkKLSBQcm9kdWN0aW9uIGRlIHBvdWxldHMgKCBwb3VyIHZvaXIgbGEgY29uY3VycmVuY2UgcG90ZW50aWVsbGUgKQotIEluZGljZSBkZSBzw6ljdXJpdMOpICggcG91ciDDqXZhbHVlciBsZSByaXNxdWUgZGUgcydpbXBsYW50ZXIgZGFucyBjZSBwYXlzICkKCiMjIyAxLjIgSW5zdGFsbGF0aW9uIGRlcyBwYWNrYWdlcyAKKi0+IEwnaW5zdGFsbGF0aW9uIGRlcyBwYWNrYWdlcyBuZSBzZSBmYWl0IHF1J3VuZSBzZXVsZSBmb2lzLCBqZSBsZXMgYWkgY29tbWVudMOpZXMgcG91ciDDqXZpdGVyIGRlIHLDqWlzbnRhbGxlciDDoCBjaGFxdWUgY2hhcmdlbWVudCBkdSBzY3JpcHQgKgpgYGB7ciBJbnN0YWxsYXRpb24gZGVzIHBhY2thZ2VzLCBlY2hvPVRSVUV9CiNpbnN0YWxsLnBhY2thZ2VzKCJGYWN0b01pbmVSIiwgZGVwZW5kZW5kY2llcz1UKQojaW5zdGFsbC5wYWNrYWdlcygiZmFjdG9leHRyYSIsZGVwZW5kZW5jaWVzPVQpCiNpbnN0YWxsLnBhY2thZ2VzKGMoIkZhY3Rvc2hpbnkiKSkKI2luc3RhbGwucGFja2FnZXMoImdncHViciIpCmBgYAojIyMgMS4zIEluc3RhbGxhdGlvbiBkZXMgbGlicmFyaWVzCiotPiBMJ2FjdGl2YXRpb24gZGVzIGxpYnJhaXJpZXMgc2UgZmFpdCDDoCBjaGFxdWUgZMOpbWFycmFnZSBkdSBzY3JpcHQqICAKKi0+IGNvcnJwbG90IGRvaXQgw6p0cmUgYXBwZWzDqSBhcHLDqHMgZ2dwbG90MiBwb3VyIMOpdml0ZXIgdW4gd2FybmluZyoKYGBge3IgSW5zdGFsbGF0aW9uIGRlcyBsaWJyYXJpZXMsIHJlc3VsdHM9RkFMU0V9CmxpYnJhcnkoRmFjdG9NaW5lUikKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvcnJwbG90KSAKb3B0aW9ucyhnZ3JlcGVsLm1heC5vdmVybGFwcyA9IEluZikKYGBgCiMjIyAxLjQgQ29uZmlndXJhdGlvbiBkZXMgdmFyaWFibGVzIHBvdXIgY2hhcXVlIGZpY2hpZXIKKi0+IGTDqWZpbml0aW9uIGQndW5lIHZhcmlhYmxlIHLDqXBlcnRvaXJlIHBvdXIgZmFjaWxpdGVyIGxlIGNoYW5nZW1lbnQgZCdPUyAqCmBgYHtyIEltcG9ydGF0aW9uIGRlcyBkb25uw6llc30KcmVwZXJ0b2lyZSA8LSAiL2hvbWUvdXNlci9Eb2N1bWVudHMvZm9ybWF0aW9ucy9vYy9Gb3JtYXRpb24gQW5hbHlzdC9QNS9zb3VyY2VzLyIKZmljX3BvcCA8LSBwYXN0ZSAocmVwZXJ0b2lyZSwicG9wdWxhdGlvbi5jc3YiLHNlcCA9ICIiKQpmaWNfcG9wMjAxNyA8LSBwYXN0ZSAocmVwZXJ0b2lyZSwicG9wXzIwMTcuY3N2IixzZXAgPSAiIikKZmljX2NhbCA8LSBwYXN0ZShyZXBlcnRvaXJlLCJrY2FsX3BlcnNvbm5lLmNzdiIsc2VwPSIiKQpmaWNfcHJvdF92b2xhaWxsZSA8LSBwYXN0ZShyZXBlcnRvaXJlLCJwcm90X3ZvbGFpbGxlLmNzdiIsc2VwPSIiKQpmaWNfcG91bGV0X3Byb2QgPC0gcGFzdGUocmVwZXJ0b2lyZSwicG91bGV0c19wcm9kdWN0aW9uXzIwMTkuY3N2IixzZXA9IiIpCmZpY19wcm90X2FuaSA8LSBwYXN0ZShyZXBlcnRvaXJlLCJwcm90X2FuaS5jc3YiLHNlcD0iIikKZmljX3Byb3RfdmVnIDwtIHBhc3RlKHJlcGVydG9pcmUsInByb3RfdmVnLmNzdiIsc2VwPSIiKQpmaWNfcGliIDwtIHBhc3RlIChyZXBlcnRvaXJlLCJwaWJfZ2RwLmNzdiIsc2VwID0gIiIpCmZpY19kaXMgPC0gcGFzdGUgKHJlcGVydG9pcmUsImRpc3RhbmNlcy5jc3YiLHNlcCA9ICIiKQpmaWNfaXNvIDwtIHBhc3RlIChyZXBlcnRvaXJlLCJzcWwtcGF5cy5jc3YiLHNlcCA9ICIiKQpmaWNfcHJvZCA8LSBwYXN0ZSAocmVwZXJ0b2lyZSwicHJvZHVjdGlvbl9wb3VsZXQuY3N2IixzZXAgPSAiIikKZmljX3NlY3UgPC0gcGFzdGUgKHJlcGVydG9pcmUsInNlY3VyaXR5LmNzdiIsc2VwID0gIiIpCmZpY19mdWxsIDwtIHBhc3RlIChyZXBlcnRvaXJlLCJmdWxsLmNzdiIsIHNlcCA9ICIiKQpmaWNfZXhwb3J0X3BheXNfY2x1c3RlciA8LSBwYXN0ZSAocmVwZXJ0b2lyZSwiLi4vUDVfcGF5c19jbHVzdGVyLmNzdiIsIHNlcCA9ICIiKQpmaWNfZXhwb3J0X2NlbnRyb2lkIDwtIHBhc3RlIChyZXBlcnRvaXJlLCIuLi9QNV9jZW50cm9pZC5jc3YiLCBzZXAgPSAiIikKYGBgCiMjIyAxLjUgQ3LDqWF0aW9uIGRlcyBEYXRhIEZyYW1lIHBhciBsZWN0dXJlIGRlcyBmaWNoaWVycwoqLT4gbGVzIGNyaXTDqHJlcyBkJ2ltcG9ydGF0aW9uLCBzw6lwYXJhdGV1cnMsIHZpcmd1bGVzIGTDqWNpbWFsZXMsIGVudMOqdGUgZXRjLCBvbnQgw6l0w6lzIGTDqWZpbmlzIGFwcsOocyBvYnNlcnZhdGlvbiBkZXMgZmljaGllcnMgc291cmNlcyDDoCBsJ2FpZGUgZCd1bmUgw6lkaXRldXIgZGUgdGV4dGUgb3UgZCd1biB0YWJsZXVyKgpgYGB7ciBDcsOpYXRpb24gZGVzIERGIHBhciBsZWN0dXJlIGRlcyBmaWNoaWVyc30KZGZfcG9wIDwtIHJlYWQuY3N2MihmaWNfcG9wLGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgZGVjID0gIi4iKQpkZl9wb3AyMDE3IDwtIHJlYWQuY3N2MihmaWNfcG9wMjAxNyxoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIGRlYyA9ICIuIikKZGZfY2FsIDwtIHJlYWQuY3N2MihmaWNfY2FsLGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgZGVjID0gIi4iKQpkZl9wcm90X3ZvbGFpbGxlIDwtIHJlYWQuY3N2MihmaWNfcHJvdF92b2xhaWxsZSxoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIGRlYyA9ICIuIikKZGZfcHJvdF9hbmkgPC0gcmVhZC5jc3YyKGZpY19wcm90X2FuaSxoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIGRlYyA9ICIuIikKZGZfcHJvdF92ZWcgPC0gcmVhZC5jc3YyKGZpY19wcm90X3ZlZyxoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIGRlYyA9ICIuIikKZGZfcGliIDwtIHJlYWQuY3N2MihmaWNfcGliLGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgZGVjID0gIi4iKQpkZl9kaXMgPC0gcmVhZC5jc3YyKGZpY19kaXMsaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCBkZWMgPSAiLiIpCmRmX2lzbyA8LSByZWFkLmNzdjIoZmljX2lzbyxoZWFkZXIgPSBGQUxTRSwgc2VwID0gIiwiLCBkZWMgPSAiLiIpCmRmX3Byb2QgPC0gcmVhZC5jc3YyKGZpY19wcm9kLGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgZGVjID0gIi4iKQpkZl9zZWN1IDwtIHJlYWQuY3N2MihmaWNfc2VjdSxoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIGRlYyA9ICIuIikKYGBgCiMjIyAtPiBWw6lyaWZpY2F0aW9uIGQndW4gREYgY3LDqcOpIHBhciBpbXBvcnRhdGlvbgpgYGB7ciBDb250cm9sZX0KaGVhZChkZl9wcm90X2FuaSkKYGBgCgojIyMgMS42IE5ldHRveWFnZSBkZXMgRGF0YUZyYW1lcyBlbiBzdXBwcmltYW50IGV0IHJlbm9tbWFudCBkZXMgY29sb25uZXMKKi0+IEplIHN1cHByaW1lIGxlcyBjb2xvbm5lcyBzdXBlcmZsdWVzIGV0IG5vcm1hbGlzZSBsZXMgbm9tcyBkZXMgdmFyaWFibGVzIG91IGxlcyByZW5kIHBsdXMgZXhwbGljaXRlcyoKCmBgYHtyIE5ldHRveWFnZSBkZXMgRGF0YUZyYW1lcyBlbiBzdXBwcmltYW50IGV0IHJlbm9tbWFudCBkZXMgY29sb25uZXN9CmRmX3BvcCA8LSBzdWJzZXQoZGZfcG9wLCBzZWxlY3QgPSBjKENvZGUuem9uZSwgQXJlYSwgVmFsdWUpKQpuYW1lcyhkZl9wb3ApW25hbWVzKGRmX3BvcCk9PSJBcmVhIl08LSJab25lIgpuYW1lcyhkZl9wb3ApW25hbWVzKGRmX3BvcCk9PSJWYWx1ZSJdPC0iSGFiMTAwMCIKZGZfcG9wMjAxNyA8LSBzdWJzZXQoZGZfcG9wMjAxNywgc2VsZWN0ID0gYyhDb2RlLnpvbmUsIFZhbGV1cikpCm5hbWVzKGRmX3BvcDIwMTcpW25hbWVzKGRmX3BvcDIwMTcpPT0iVmFsZXVyIl08LSJIYWIyMDE3eDEwMDAiCmRmX2NhbCA8LSBzdWJzZXQoZGZfY2FsLCBzZWxlY3QgPSBjKENvZGUuem9uZSwgVmFsZXVyKSkKbmFtZXMoZGZfY2FsKVtuYW1lcyhkZl9jYWwpPT0iVmFsZXVyIl08LSJrY2FsX3BlcnNfam91ciIKZGZfcHJvdF92ZWcgPC0gc3Vic2V0KGRmX3Byb3RfdmVnLCBzZWxlY3QgPSBjKENvZGUuem9uZSwgVmFsZXVyKSkKbmFtZXMoZGZfcHJvdF92ZWcpW25hbWVzKGRmX3Byb3RfdmVnKT09IlZhbGV1ciJdPC0icHJvdF92ZWciCmRmX3Byb3RfYW5pIDwtIHN1YnNldChkZl9wcm90X2FuaSwgc2VsZWN0ID0gYyhDb2RlLnpvbmUsIFZhbGV1cikpCm5hbWVzKGRmX3Byb3RfYW5pKVtuYW1lcyhkZl9wcm90X2FuaSk9PSJWYWxldXIiXTwtInByb3RfYW5pIgpkZl9wcm90X3ZvbGFpbGxlIDwtIHN1YnNldChkZl9wcm90X3ZvbGFpbGxlLCBzZWxlY3QgPSBjKENvZGUuem9uZSwgVmFsZXVyKSkKbmFtZXMoZGZfcHJvdF92b2xhaWxsZSlbbmFtZXMoZGZfcHJvdF92b2xhaWxsZSk9PSJWYWxldXIiXTwtInByb3Rfdm9sYWlsbGUiCmRmX3BpYiA8LSBzdWJzZXQoZGZfcGliLCBzZWxlY3QgPSBjKENvZGUuem9uZSwgVmFsZXVyKSkKbmFtZXMoZGZfcGliKVtuYW1lcyhkZl9waWIpPT0iVmFsZXVyIl08LSJQSUJfdXNkX2hhYiIKZGZfZGlzIDwtIHN1YnNldChkZl9kaXMsIHNlbGVjdCA9IGMoWCwgRlJBKSkKbmFtZXMoZGZfZGlzKVtuYW1lcyhkZl9kaXMpPT0iWCJdPC0iSVNPIgpuYW1lcyhkZl9kaXMpW25hbWVzKGRmX2Rpcyk9PSJGUkEiXTwtImRpc3RhbmNlIgpkZl9pc28gPC0gc3Vic2V0KGRmX2lzbywgc2VsZWN0ID0gYyhWNiwgVjQpKQpuYW1lcyhkZl9pc28pW25hbWVzKGRmX2lzbyk9PSJWNiJdPC0iWm9uZSIKbmFtZXMoZGZfaXNvKVtuYW1lcyhkZl9pc28pPT0iVjQiXTwtIklTTyIKZGZfcHJvZCA8LSBzdWJzZXQoZGZfcHJvZCwgc2VsZWN0ID0gYyhDb2RlLnpvbmUsIFZhbGV1cikpCm5hbWVzKGRmX3Byb2QpW25hbWVzKGRmX3Byb2QpPT0iVmFsZXVyIl08LSJQb3VsZXRzMTAwMCIKZGZfc2VjdSA8LSBzdWJzZXQoZGZfc2VjdSwgc2VsZWN0ID0gYyhBcmVhLkNvZGUsIFZhbHVlKSkKbmFtZXMoZGZfc2VjdSlbbmFtZXMoZGZfc2VjdSk9PSJWYWx1ZSJdPC0ic2VjdXJpdGUiCm5hbWVzKGRmX3NlY3UpW25hbWVzKGRmX3NlY3UpPT0iQXJlYS5Db2RlIl08LSJDb2RlLnpvbmUiCmBgYAoKIyMjIC0+IFbDqXJpZmljYXRpb24gZCd1bmUgbW9kaWZpY2F0aW9uIGRlIERGCmBgYHtyIFbDqXJpZmljYXRpb24gZCB1bmUgbW9kaWZpY2F0aW9uIGRlIERGfQpoZWFkKGRmX3Byb3RfYW5pKQpgYGAKCiMjIyAtPiBTdXBwcmVzc2lvbiBkZXMgcHJvdmluY2VzIGRlIGxhIENoaW5lIHBvdXIgw6l2aXRlciBsZXMgZG91YmxvbnMgY2FyIG9uIGEgZMOpasOgIHZ1IHF1ZSBsYSBjaGluZSDDqXRhaXQgcmVwcsOpc2VudMOpZSBkZXV4IGZvaXMsIHVuZSBmb2lzIGxlIHBheXMgZXQgdW5lIGZvaXMgbGVzIHByb3ZpbmNlcyBtYWlzIGF1c3NpIGxhIEZyYW5jZSBjYXIgY2Ugbidlc3QgcGFzIHVuIHBheXMgZCdleHBvcnRhdGlvbgpgYGB7ciBzdXBwcmVzc2lvbiBwcm92aW5jZXMgY2hpbm9pc2VzIH0Kc3Vic2V0KGRmX3BvcCwgIFpvbmUgPT0gIkZyYW5jZSIpCmRmX3BvcCA8LSBkZl9wb3BbIWRmX3BvcCRDb2RlLnpvbmUgJWluJSBjKCI5NiIsIjEyOCIsIjQxIiwiMjE0IiwiNjgiKSxdCmBgYAoKIyMjIDEuNyBDb21waWxhdGlvbiBkZXMgZGYgcG91ciBmb3JtZXIgbGEgREYgZ2xvYmFsZSBub21tw6llIGRmX2Z1bGwKLT4gSidhdXJhaXMgw6l0w6kgdGVudMOpIGRlIGwnYXBwZWxlciBkYXRhLCBtYWlzIG4nYXlhbnQgcGFzIGVuY29yZSBub3ZpY2UsIGplIHByw6lmw6hyZSBsdWkgZG9ubmVyIHVuIG5vbSBwbHVzIHBlcnNvbm5lbCBlbiBjb21tZW7Dp2FudCBwYXIgZGYgKCBkYXRhIGZyYW1lICkgcHVpcyBmdWxsIHBvdXIgcGxlaW4gZXQgYXByw6hzIGoneSByYWpvdXRlcmFpcyBsZXMgZGlmZsOpcmVudGVzIGZvcm1lcyBvdSBjb21wbMOpbWVudHMgIAotPiBKZSBzdWlzIHBhcnRpIGRlcyBwYXlzIGRlIGxhIHBvcHVsYXRpb24gZXQgaidhaSBjb21wbMOpdMOpIGF2ZWMgbGVzIGF1dHJlcyBkb25uw6llcwpgYGB7ciBtZXJnZSBkZXMgREYgfQpkZl9mdWxsIDwtIG1lcmdlKGRmX3BvcCxkZl9wb3AyMDE3LGJ5PSJDb2RlLnpvbmUiKQpkZl9mdWxsIDwtIG1lcmdlKGRmX2Z1bGwsZGZfaXNvLGJ5PSJab25lIikKZGZfZnVsbCA8LSBtZXJnZShkZl9mdWxsLGRmX2NhbCxieT0iQ29kZS56b25lIikKZGZfZnVsbCA8LSBtZXJnZShkZl9mdWxsLGRmX3Byb3RfdmVnLGJ5PSJDb2RlLnpvbmUiKQpkZl9mdWxsIDwtIG1lcmdlKGRmX2Z1bGwsZGZfcHJvdF9hbmksYnk9IkNvZGUuem9uZSIpCmRmX2Z1bGwgPC0gbWVyZ2UoZGZfZnVsbCxkZl9wcm90X3ZvbGFpbGxlLGJ5PSJDb2RlLnpvbmUiKQpkZl9mdWxsIDwtIG1lcmdlKGRmX2Z1bGwsZGZfcGliLGJ5PSJDb2RlLnpvbmUiKQpkZl9mdWxsIDwtIG1lcmdlKGRmX2Z1bGwsZGZfcHJvZCxieT0iQ29kZS56b25lIikKZGZfZnVsbCA8LSBtZXJnZShkZl9mdWxsLGRmX2RpcyxieT0iSVNPIikKZGZfZnVsbCA8LSBtZXJnZShkZl9mdWxsLGRmX3NlY3UsYnk9IkNvZGUuem9uZSIpCmBgYAojIyMgLT4gVsOpcmlmaWNhdGlvbiBkZSBsYSBjb21waWxhdGlvbiBkZXMgREYKYGBge3IgUsOpc3VsdGF0IGRlIGxhIGNvbXBpbGF0aW9uIGRlcyBERn0KaGVhZChkZl9mdWxsKQpgYGAKCiMjIyAxLjggQ29sb25uZXMgY2FsY3Vsw6llcyAoIMOpdm9sdXRpb24gcG9wdWxhdGlvbiBldCByYXBwb3J0IHByb3TDqWluZXMgKQpgYGB7ciBDYWxjdWwgZGUgw6l2b2x1dGlvbiBwb3B1bGF0aW9uIGV0IHJlcHBvcnQgcHJvdMOpaW5lc30KZGZfZnVsbCRwb3BfZXZvIDwtMTAwLSgxMDAqZGZfZnVsbCRIYWIyMDE3eDEwMDAvZGZfZnVsbCRIYWIxMDAwKQpkZl9mdWxsJHByb3RfcmFwcG9ydCA8LWRmX2Z1bGwkcHJvdF9hbmkvKGRmX2Z1bGwkcHJvdF92ZWcrZGZfZnVsbCRwcm90X2FuaSkKYGBgCgojIyMgLT4gc3VwcHJlc3Npb24gZGVzIGNvbG9ubmVzIHF1aSBvbnQgc2VydmkgcG91ciBsZXMgY2FsY3VscwpgYGB7ciBTdXBwcmVzc2lvbiBkZXMgY29sb25uZXMgc3VwZXJmbHVlcyBheWFudCBzZXJ2aWVzIGF1eCBjYWxjdWxzfQpkZl9mdWxsIDwtIHN1YnNldChkZl9mdWxsLCBzZWxlY3QgPSAtYyhDb2RlLnpvbmUsIElTTywgSGFiMjAxN3gxMDAwLHByb3RfdmVnLHByb3RfYW5pLCBwcm90X3ZvbGFpbGxlKSkKYGBgCgojIyMgTm91cyB2w6lyaWZpb25zIGxlcyB2YXJpYWJsZXMgcXVpIGF1cmFpZW50IGRlcyBtYW5xdWVzLgpgYGB7cn0KcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShIYWIxMDAwKSkpWzFdLCIgZG9ubsOpZXMgbWFucXVhbnRlcyBwb3VyIGxlIG5vbWJyZSBkJ2hhYml0YW50cy4iKSkKcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShrY2FsX3BlcnNfam91cikpKVsxXSwiIGRvbm7DqWVzIG1hbnF1YW50ZXMgcG91ciBsZSBrY2FsX3BlcnNfam91ci4iKSkKcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShQSUJfdXNkX2hhYikpKVsxXSwiIGRvbm7DqWVzIG1hbnF1YW50ZXMgcG91ciBsZSBQSUJfdXNkX2hhYi4iKSkKcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShQb3VsZXRzMTAwMCkpKVsxXSwiIGRvbm7DqWVzIG1hbnF1YW50ZXMgcG91ciBsZSBQb3VsZXRzMTAwMC4iKSkKcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShkaXN0YW5jZSkpKVsxXSwiIGRvbm7DqWVzIG1hbnF1YW50ZXMgcG91ciBsYSBkaXN0YW5jZS4iKSkKcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShzZWN1cml0ZSkpKVsxXSwiIGRvbm7DqWVzIG1hbnF1YW50ZXMgcG91ciBsYSBzZWN1cml0ZS4iKSkKcHJpbnQocGFzdGUwKCdJbCB5IGEgJywgZGltKHN1YnNldChkZl9mdWxsLCBpcy5uYShwb3BfZXZvKSkpWzFdLCIgZG9ubsOpZXMgbWFucXVhbnRlcyBwb3VyIGxlIHBvcF9ldm8uIikpCnByaW50KHBhc3RlMCgnSWwgeSBhICcsIGRpbShzdWJzZXQoZGZfZnVsbCwgaXMubmEocHJvdF9yYXBwb3J0KSkpWzFdLCIgZG9ubsOpZXMgbWFucXVhbnRlcyBwb3VyIGxlIHByb3RfcmFwcG9ydC4iKSkKIyBvbiBhdXJhaXQgcHUgbmUgZ2FyZGVyIHF1ZSBsZXMgcGF5cyBheWFudCB0b3V0ZXMgbGVzIHZhcmlhYmxlcyBkw6lmaW5pZXMgYXZlYyBsYSBjb21tYW5kZSBzdWl2YW50ZQpkZl9mdWxsIDwtIGRmX2Z1bGxbY29tcGxldGUuY2FzZXMoZGZfZnVsbCksXQpgYGAKIyMjIFbDqXJpZmljYXRpb24KYGBge3J9CmhlYWQoZGZfZnVsbCkKYGBgCgojIyMgRWNyaXR1cmUgZCd1biBmaWNoaWVyIENTViBhdmVjIGNldHRlIERGIGNvbXBsw6p0ZSBwb3VyIHVuIGNvbnRyw7RsZSBleHTDqXJpZXVyIHNpIG7DqWNlc3NhaXJlCmBgYHtyIEV4cG9ydCBkZl9mdWxsIGVuIGZpY2hpZXIgQ1NWfQp3cml0ZS5jc3YyKGRmX2Z1bGwsIGZpbGUgPSBmaWNfZnVsbCkKYGBgCiMjIyBERiB0cmnDqSBwYXIgbm9tIGRlIHBheXMgZXQgbm9tIGR1IHBheXMgY29tbWUgaW5kZXggCmBgYHtyIE5vbSBkdSBwYXlzIGNvbW1lIGluZGV4fQpkZl9mdWxsX29yZGVyIDwtIGRmX2Z1bGxbb3JkZXIoZGZfZnVsbFssIlpvbmUiXSxkZWNyZWFzaW5nPUYpLF0KZGZfZnVsbF9pbmRpdmlkdXM8LSBkYXRhLmZyYW1lKGRmX2Z1bGxfb3JkZXJbLC0xXSwgcm93Lm5hbWVzPWRmX2Z1bGxfb3JkZXJbLDFdKQojIHbDqXJpZmljYXRpb24KaGVhZChkZl9mdWxsX2luZGl2aWR1cykgCmBgYAoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyAyIC0gQ0FIIENsYXNzaWZpY2F0aW9uIEFzc2VuZGFudGUgSGnDqXJhcmNoaXF1ZSAKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KKipPYmpldGNpZiA6IElkZW50aWZpZXIgZGVzIGdyb3VwZXMgc2ltaWxhaXJlcyBkYW5zIHVuIGpldSBkZSBkb25uw6llcyoqCgojIyMgZGF0YSBmcmFtZSBjZW50csOpIHLDqWR1aXQgYXZlYyBzY2FsZSAtIHLDqWR1aXQgbGUgcG9pZHMgZGVzIHZhcmlhYmxlcyDDoCBmb3J0ZSB2YXJpYW5jZQpgYGB7cn0KZGZfZnVsbF9jZW50cmVfcmVkdWl0IDwtIHNjYWxlKGRmX2Z1bGxfaW5kaXZpZHVzKSAKYGBgCgojIyMgSENQQyBwYXIgcmFwcG9ydCDDoCBsJ0FDUCBzdXIgNSBjbHVzdGVycwotPiBqZSBmYWlzIGRhYm9yZCB1biBwcmVtaWVyIGNhbGN1bCBkZSBsJ0FDUCBwb3VyIHV0aWxpc2VyIGxlIHLDqXN1bHRhdCBhdmVjIGxhIGZvbmN0aW9uIEhDUEMgIAotPiBqJ2V4cGxvaXRlIGxlIHJlcy5wY2EgaXNzdSBkZSBsYSBmb25jdGlvbiBQQ0Egc3VyIGxhIGRhdGEgZnJhbWUgY2VudHLDqSByw6lkdWl0CgojIyMgQUNQIHN1ciBsYSB0YWJsZSBjZW50csOpIHLDqWR1aXQKYGBge3J9CnJlcy5wY2EgPC0gUENBKGRmX2Z1bGxfY2VudHJlX3JlZHVpdCwgc2NhbGUudW5pdCA9IEZBTFNFLCBncmFwaCA9IEZBTFNFKQpgYGAKCiMjIyBIQ1BDCmBgYHtyfQpyZXMuaGNwYyA8LSBIQ1BDKHJlcy5wY2EsbmIuY2x1c3QgPSA1LCBncmFwaCA9IEZBTFNFKQpgYGAKCiMjIyBkZW5kb2dyYW1lIGVuIDUgY2x1c3RlcnMgw6AgcGFydGlyIGRlIGwnSENQQwpgYGB7cn0KaW1nX2RlbmRvZ3JhbW1lIDwtIGZ2aXpfZGVuZChyZXMuaGNwYywKICAgICAgICAgIGxhYmVsc2l6ZSA9IDIsCiAgICAgICAgICBjZXggPSAwLjcsICAgICAgICAgICAgICAgICAgICAgIyBUYWlsbGUgZHUgdGV4dAogICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLCAgICAgICAgICAgICAgICMgUGFsZXR0ZSBkZSBjb3VsZXVyID9nZ3B1YnI6OmdncGFyCiAgICAgICAgICByZWN0ID0gVFJVRSwgcmVjdF9maWxsID0gVFJVRSwgIyBSZWN0YW5nbGUgYXV0b3VyIGRlcyBncm91cGVzCiAgICAgICAgICByZWN0X2JvcmRlciA9ICJqY28iLCAgICAgICAgICAgIyBDb3VsZXVyIGR1IHJlY3RhbmdsZQogICAgICAgICAgbGFiZWxzX3RyYWNrX2hlaWdodCA9IDAuOCAgICAgICMgQXVnbWVudCBsJ2VzcGFjZSBwb3VyIGxlIHRleHRlCiAgICAgICAgICApICsgZ2dzYXZlKCJQNV9pbWdfZGVuZG9ncmFtbWUucG5nIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKcGxvdChpbWdfZGVuZG9ncmFtbWUpCmBgYAoKIyMjIE9ic2VydmF0aW9uIGRlcyBjbHVzdGVycwpgYGB7cn0KZnZpel9jbHVzdGVyKHJlcy5oY3BjLAogICAgICAgICAgICAgbGFiZWxzaXplID0gMywKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwgICAgICAgICAgICAjIEV2aXRlIGxlIGNoZXZhdWNoZW1lbnQgZGVzIHRleHRlcwogICAgICAgICAgICAgc2hvdy5jbHVzdC5jZW50ID0gVFJVRSwgIyBNb250cmUgbGUgY2VudHJlIGRlcyBjbHVzdGVycwogICAgICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLCAgICAgICAgICMgUGFsZXR0ZSBkZSBjb3VsZXVycywgdm9pciA/Z2dwdWJyOjpnZ3BhcgogICAgICAgICAgICAgZ2d0aGVtZSA9IHRoZW1lX21pbmltYWwoKSwKICAgICAgICAgICAgIG1haW4gPSAiRmFjdG9yIG1hcCIKKQpgYGAKCiMjIyByYWpvdXQgZGUgbGEgdmFyaWFibGUgY2x1c3RlciBhdSBkZiAKYGBge3J9CmRmX2Z1bGxfY2VudHJlX3JlZHVpdF9jbHVzdGVyIDwtcmVzLmhjcGMkZGF0YS5jbHVzdApwYXlzX2NsdXN0ZXIgPC0gc3Vic2V0KGRmX2Z1bGxfY2VudHJlX3JlZHVpdF9jbHVzdGVyLCBzZWxlY3Q9YyhjbHVzdCkpCndyaXRlLmNzdjIocGF5c19jbHVzdGVyLCBmaWxlID0gZmljX2V4cG9ydF9wYXlzX2NsdXN0ZXIpCmhlYWQocGF5c19jbHVzdGVyKQpgYGAKCiMjIyBDZW50cm9pZGVzIC0gZ3JvdWJ5IHN1ciBsZXMgY2x1c3RlciBldCBtb3llbm5lcyBkZSBjaGFxdWUgdmFyaWJsZXMKYGBge3J9CmRmX2Z1bGxfY2x1c3RlciA8LSBjYmluZChkZl9mdWxsX2luZGl2aWR1cyxwYXlzX2NsdXN0ZXIkY2x1c3QpCmNvbG5hbWVzKGRmX2Z1bGxfY2x1c3RlcilbY29sbmFtZXMoZGZfZnVsbF9jbHVzdGVyKT09InBheXNfY2x1c3RlciRjbHVzdCJdIDwtICJjbHVzdCIKZGZfZnVsbF9jZW50cm9pZGVzIDwtIGRmX2Z1bGxfY2x1c3RlciAlPiUKICBncm91cF9ieShjbHVzdCkgJT4lCiAgc3VtbWFyaXplKG1veV9oYWIgPSBtZWFuKEhhYjEwMDAsIG5hLnJtID0gVFJVRSksIG1veV9kaXMgPSBtZWFuKGRpc3RhbmNlLG5hLnJtPVRSVUUpLCBtb3lfUElCPW1lYW4oUElCX3VzZF9oYWIsbmEucm09VFJVRSksbW95X3BvdWxldHM9bWVhbihQb3VsZXRzMTAwMCxuYS5ybT1UUlVFKSwKICAgICAgICAgICAgbW95X3NlY3U9bWVhbihzZWN1cml0ZSxuYS5ybT1UUlVFKSxtb3lfa2NhbD1tZWFuKGtjYWxfcGVyc19qb3VyLG5hLnJtPVRSVUUpLCBtb3lfcG9wX2V2bz1tZWFuKHBvcF9ldm8sbmEucm09VFJVRSksbW95X3Byb3Q9bWVhbihwcm90X3JhcHBvcnQsbmEucm09VFJVRSkgKQp3cml0ZS5jc3YyKGRmX2Z1bGxfY2VudHJvaWRlcywgZmlsZSA9IGZpY19leHBvcnRfY2VudHJvaWQpCmhlYWQoZGZfZnVsbF9jZW50cm9pZGVzKQpgYGAKCmBgYHtyfQpkZl9jZW50cm9pZCA8LSBkZl9mdWxsX2NlbnRyb2lkZXNbLDI6OV0KZGZfY2VudHJvaWRfc2NhbGVkIDwtIHNjYWxlKGRmX2NlbnRyb2lkKQpNYXRyaWNlIDwtIGRhdGEubWF0cml4KGRmX2NlbnRyb2lkX3NjYWxlZCkKcHJpbnQoTWF0cmljZSkKYGBgCiMjIyBEZXNjcmlwdGlvbiBkZSBsYSByw6lwYXJ0aXRpb24gZGVzIGNsdXN0ZXJzIApgYGB7cn0KcmVzLmhjcGMkZGVzYy52YXIKYGBgCgojIyMgSGVhdG1hcCBkZXMgdmFyaWFibGVzIGRhbnMgY2hhcXVlIGNsdXN0ZXIgcG91ciB2b2lyIGxldXIgaW1wb3J0YW5jZQpgYGB7cn0KY29ycnBsb3QoTWF0cmljZSwgaXMuY29yciA9IEZBTFNFLCBtZXRob2QgPSAiY2lyY2xlIikKYGBgCkludGVycHLDqXRhdGlvbiA6Ci0+IHBsdXMgbGUgcG9pbnQgZXN0IGJsZXUsIHBsdXMgbGEgdmFyaWFibGUgY2FyYWN0w6lyaXNlIGxlIGNsdXN0ZXIgIAotPiBwbHVzIGxlIHBvaW50IGVzdCBncmFuZCwgcGx1cyBsYSB2YXJpYWJsZSBlc3QgZm9ydGUgIAotPiBwbHVzIGxlIHBvaW50IGVzdCByb3VnZSBtb2lucyBsYSB2YXJpYWJsZSBjYXJhY3TDqXJpc2UgbGUgY2x1c3RlciAgCi0+IHBsdXMgbGUgcG9pbnQgZXN0IHBldGl0IHBsdXMgbGEgdmFyaWFibGUgZXN0IGZhaWJsZSAgCgpDTFVTVEVSIDEgIAotIMOpdm9sdXRpb24gZGUgbGEgcG9wdWxhdGlvbiBlc3QgZm9ydGUgIAotIGtjYWwgZXQgcHJvdMOpaW5lcyBzb250IHRyw6hzIGZhaWJsZXMgIApDTFVTVEVSIDIKLSBub21icmUgZCdoYWJpdGFudHMgZXQgZGUgcG91bGV0cyDDqWxldsOpcyAgCi0gZGlzdGFuY2UgdW4gcGV1IGZhdm9yYWJsZSAgCi0gbGEgc8OpY3VyaXTDqSBlc3QgZW4gcmV2YW5jaGUgZMOpZmF2b3JhYmxlICAKQ0xVU1RFUiAzICAKLSBzZXVsIGxhIGRpc3RhbmNlIGVzdCBsJ2F0b3V0IGRlIGNldCBlbnNlbWJsZSAgCkNMVVNURVIgNCAgCi0gZGlzdGFuY2UgZXQgw6l2b2x1dGlvbiBkZSBsYSBwb3B1bGF0aW9uIHNvbnQgZGV1eCB2YXJpYWJsZXMgcGFydGljdWxpw6hyZW1lbnQgZm9ydGVzIGV0IG7DqWdhdGl2ZXMgcG91ciBjZXQgZW5zZW1ibGUgIApDTFVTVEVSIDUgIAotIGRlcyBwYXlzIHJpY2hlcyBldCBzw7tycyAgCi0gdW5lIGFsaW1lbnRhdGlvbiByaWNoZSBlbiBwcm90w6lpbmVzIGV0IGVuIGtjYWwgIAoKLT4gTGUgZ3JvdXBlIDUgcHLDqXNlbnRlIGxlcyBwbHVzIGludMOpcmVzc2FudHMgcGFyYW3DqHRyZXMgcG91ciBub3RyZSBwcm9qZXQgY2FyIG9uIHkgdHJvdXZlIGxlcyBtZWlsbGV1cnMgcsOpc3VsdGF0cyBlbiBtYXRpw6hyZSBkZSByaWNoZXNzZSBldCBkZSBzw6ljdXJpdMOpLCBjZSBxdWkgcGVybWV0IGQnZW52aXNhZ2VyIHVuIGNvbW1lcmNlIHBsdXMgc3RhYmxlIGV0IG1vaW5zIHJpc3F1w6kuIERlIHBsdXMgbCdhbGltZW50YXRpb24gZXN0IHBsdXTDtHQgcmljaGUuIAoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgMyBBQ1AgLSBBbmFseXNlIGRlIENvbXBvc2FudGVzIFByaW5jaXBhbGVzIAojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpgYGB7cn0KcmVzLmRlc2MgPC0gZGltZGVzYyhyZXMucGNhLCBheGVzID0gYygxLDIpLCBwcm9iYSA9IDAuMDUpCnJlcy5kZXNjJERpbS4xCmBgYAojIyBFYm91bGlzIGRlcyB2YWxldXJzIHByb3ByZXMgOiBwb3VyY2VudGFnZSBkZSB2YXJpYW5jZSBleHBsaXF1w6llIHBhciBjaGFxdWUgZGltZW5zaW9uCmBgYHtyfQplaWcudmFsIDwtIGdldF9laWdlbnZhbHVlKHJlcy5wY2EpIAplaWcudmFsCmZ2aXpfZWlnKHJlcy5wY2EsIGFkZGxhYmVscyA9IFRSVUUsIHlsaW0gPSBjKDAsIDUwKSkKYGBgCi0+IE9uIG9ic2VydmUgdW4gY291ZGUgYXUgbml2ZWF1IGRlIGxhIHNlY29uZGUgZGltZW5zaW9uLiBBcHLDqHMgcXVvaSBsYSBkaW1pbnV0aW9uIGVzdCBwbHVzIHLDqWd1bGnDqHJlLiAgIApNYWlzIGlsIHNlcmEgcGV1dC3DqnRyZSBuw6ljZXNzYWlyZSBkJ29ic2VydmVyIGxlcyAzIHByZW1pw6hyZXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXMgcG91ciB0b3RhbGlzZXIgNzAlIGRlcyBpbmZvcm1hdGlvbnMuCgojIyMgQ29tcGFyYWlzb24gZGUgbGEgcXVhbGl0w6kgZGUgbGEgcmVwcsOpc2VudGF0aW9uIGRlcyB2YXJpYWJsZXMgZW4gZm9uY3Rpb24gZGVzIGRpbWVuc2lvbnMKYGBge3J9CnZhciA8LSBnZXRfcGNhX3ZhcihyZXMucGNhKQpjb3JycGxvdCh2YXIkY29zMiwgaXMuY29ycj1GQUxTRSxhZGRDb2VmLmNvbCA9ICJibGFjayIsIHRpdGxlPSJRdWFsaXTDqSBkZSByZXByw6lzZW50YXRpb24gZGVzIHZhcmlhYmxlcyIsIG1hcj1jKDAsMCwxLDApKQpgYGAKLT4gZGFucyBsYSBwcmVtacOocmUgY29tcG9zYW50ZSwgY2Ugc29udCBrY2FsLCBwaWIsIHPDqWN1cml0w6kgZXQgcmFwcG9ydCBlbiBwcm90w6lpbmVzIHF1aSBzb250IGxlIG1pZXV4IHJlcHLDqXNlbnTDqWVzICAKLT4gZGFucyBsYSBzZWNvbmRlLCBjJ2VzdCBsZSBub21icmUgZGUgcG91bGV0cyBldCBkJ2hhYml0YW50cy4gIAotPiBkYW5zIGxhIHRyb2lzacOobWUsIGMnZXN0IGxhIGRpc3RhbmNlIHF1aSBlc3QgbGUgbWlldXggcmVwcsOpc2VudMOpZSAgCgoKIyMjIEdyYXBoaXF1ZSBkZXMgY29ycsOpbGF0aW9ucyBwb3VyIGxlcyBkaW1lbnNpb25zIDEgZXQgMgpgYGB7cn0KZnZpel9wY2FfdmFyIChyZXMucGNhLCBjb2wudmFyID0gImNvczIiLAogICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLAogICAgICAgICAgICAgIHJlcGVsID0gVFJVRSAjIMOJdml0ZSBsZSBjaGV2YXVjaGVtZW50IGRlIHRleHRlCikKCmBgYApgYGB7cn0KZnZpel9wY2FfdmFyKHJlcy5wY2EsIGNvbC52YXIgPSAiY29zMiIsZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikscmVwZWwgPSBUUlVFKSsgbGFicyh0aXRsZSA9ICJDZXJjbGUgZGVzIGNvcnLDqWxhdGlvbnMiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKQpgYGAKCgpMZSBncmFwaGlxdWUgZGUgY29ycsOpbGF0aW9uIGRlcyB2YXJpYWJsZXMgbW9udHJlIGxlcyByZWxhdGlvbnMgZW50cmUgdG91dGVzIGxlcyB2YXJpYWJsZXMgZXQgbGVzIGF4ZXMgZmFjdG9yaWVscy4gSWwgcGV1dCDDqnRyZSBpbnRlcnByw6l0w6kgY29tbWUgc3VpdDoKCiAgICBMZXMgdmFyaWFibGVzIHBvc2l0aXZlbWVudCBjb3Jyw6lsw6llcyBzb250IHJlZ3JvdXDDqWVzIDoKICAgICAgICBkaXNwX2FsaV9wcm90X2dfcGVyc19qb3VyLCBkaXNwX2FsaV9rY2FsX3BlcnNfam91cgogICAgICAgIHByb3BfYW5pX2Rpc3BfYWxpLCBwaWJfaGFiCiAgICBMZXMgdmFyaWFibGVzIG7DqWdhdGl2ZW1lbnQgY29ycsOpbMOpZXMgc29udCBwb3NpdGlvbm7DqWVzIHN1ciBsZXMgY8O0dMOpcyBvcHBvc8OpcyBkZSBsJ29yaWdpbmUgZHUgZ3JhcGhpcXVlIChxdWFkcmFudHMgb3Bwb3PDqXMpIDoKICAgICAgICBpbmRpY2VfcmlzcXVlX3BheXMgZXQgZXZvbHV0aW9uX3BvcF8yMDE1XzIwMTYgcGFyIHJhcHBvcnQgYXV4IGF1dHJlcwogICAgTGEgZGlzdGFuY2UgZW50cmUgbGVzIHZhcmlhYmxlcyBldCBsJ29yaWdpbmUgbWVzdXJlIGxhIHF1YWxpdMOpIGRlIHJlcHLDqXNlbnRhdGlvbiBkZXMgdmFyaWFibGVzLiBMZXMgdmFyaWFibGVzIHF1aSBzb250IGxvaW4gZGUgbCdvcmlnaW5lIHNvbnQgYmllbiByZXByw6lzZW50w6llcyBwYXIgbCdBQ1AgKGNvdWxldXIgcm91Z2UgLyBvcmFuZ2UpLiBUb3V0ZXMgbGVzIHZhcmlhYmxlcyAodW4gcGV1IG1vaW5zIHBvdXIgZXZvbHV0aW9uX3BvcF8yMDE1XzIwMTYgOiBjb3VsZXVyIGJsZXVlKSBzb250IGJpZW4gZXhwbGlxdcOpZXMgcGFyIGxlcyBkZXV4IHByZW1pw6hyZXMgY29tcG9zYW50ZXMgcHJpbmNpcGFsZXMgKERpbS4xICYgRGltLjIpIGNhciBlbGxlcyBzb250IHBvc2l0aW9ubsOpZXMgcHLDqHMgZHUgbGUgY2VyY2xlIGRlIGNvcnLDqWxhdGlvbi4KClNvaXQgbGUgcmVww6hyZSBvcnRob2dvbmFsIHBvcnTDqSBwYXIgbGVzIGF4ZXMgKGRpc3RhbmNlX2ZyX2ZtIGV0IHVuIGF4ZSBub3JtYWwgw6AgY2UgZGVybmllcikuCgogICAgTGEgZGltZW5zaW9uIDEgc3ltYm9saXNlIGxhIHF1YWxpdMOpIGRlIHZpZSBkYW5zIGxlIHBheXMgOiBsZXMgcGF5cyBsZXMgcGx1cyDDoCBkcm9pdGUgc29udCBsZXMgcGF5cyBvw7kgbGEgcXVhbGl0w6kgZGUgdmllIGVzdCBsYSBtZWlsbGV1ciAoZm9ydCBQSUIgcGFyIGhhYml0YW50LCBmb3J0ZSBkaXNwb25pYmlsaXTDqSBhbGltZW50YWlyZSBlbiBrY2FsIC8gcHJvdMOpaW5lcywgZm9ydGUgY29uc29tbWF0aW9uIGRlIHByb2R1aXRzIGQnb3JpZ2luZSBhbmltYWxlLCBib25uZSBzdGFiaWxpdMOpIHBvbGl0aXF1ZSkuCiAgICBMYSBkaW1lbnNpb24gMiBzeW1ib2xpc2UgbGEgZGlzdGFuY2UgZHUgcGF5cyDDoCBsYSBGcmFuY2UuIDogcGx1cyB1biBwYXlzIGVzdCBlbiBiYXMsIHBsdXMgaWwgZXN0IHByb2NoZSBkZSBsYSBGcmFuY2UuCiAgICBMZXMgcGF5cyBxdWkgbm91cyBpbnTDqXJlc3NlbnQgc29udCBkb25jIGxlcyBwYXlzIGxlcyBwbHVzIMOgIGRyb2l0ZSAocHJpb3JpdGFpcmVtZW50IGNhciBsYSBkaXN0YW5jZSByZXN0ZSBzZWNvbmRhaXJlIGF1IHZ1ZSBkZSBsYSBxdWFsaXTDqSBkZSB2aWUgZGFucyBsZSBwYXlzKSBldCBsZXMgcGx1cyBlbiBiYXMuCgpEZSBtYW5pw6hyZSBnw6luw6lyYWxlLCBsZSBjZXJjbGUgZGVzIGNvcnLDqWxhdGlvbnMgbidlc3QgcGFzIGZhaXQgcG91ciBpbnRlcnByw6l0ZXIgbGVzIGNvcnLDqWxhdGlvbnMgZW50cmUgbGVzIHZhcmlhYmxlcyBpbml0aWFsZXMuIElsIGVzdCBmYWl0IHBvdXIgaW50ZXJwcsOpdGVyIGxlcyBheGVzIGQnaW5lcnRpZSBGMSwgRjIsIGV0Yy4gUG91ciB2w6lyaWZpZXIgbGEgY29ycsOpbGF0aW9uIGVudHJlIGxlcyB2YXJpYWJsZXMsIGxlcyBjb2VmZmljaWVudHMgZGUgY29ycsOpbGF0aW9ucyBlbnRyZSBsZXMgdmFyaWFibGVzIHNvbnQgY2FsY3Vsw6lzIGV0IGFmZmljaMOpcyBkYW5zIGxhIG1hdHJpY2UgZGVzIGNvcnLDqWxhdGlvbnMuCgoKIyMgcXVhbGl0w6kgZGUgcmVwcsOpc2VudGF0aW9uICggY29zMiApIGJhcnBsb3QKIyMjIFZhcmlhYmxlcwpgYGB7cn0KZnZpel9jb3MyKHJlcy5wY2EsIGNob2ljZSA9ICJ2YXIiKQpgYGAKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgNCBDbHVzdGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyA0LjEgQW5hbHlzZSBkZXMgZGlmZsOpcmVudHMgZ3JvdXBlcwoKIyMjIGNsdXN0ZXIgMSAtIMOpdm9sdXRpb24gZGUgbGEgcG9wdWxhdGlvbiBzaW5pZmljYXRpdmVtZW50IHN1cMOpcmlldXIgw6AgbGEgbW95ZW5uZQojIyMgY2x1c3RlciAyIC0gbm9tYnJlIGRlIHBvdWxldHMgIHNpbmlmaWNhdGl2ZW1lbnQgc3Vww6lyaWV1ciDDoCBsYSBtb3llbm5lCiMjIyBjbHVzdGVyIDMgLSBkaXN0YW5jZXMgIHNpbmlmaWNhdGl2ZW1lbnQgc3Vww6lyaWV1ciDDoCBsYSBtb3llbm5lCiMjIyBjbHVzdGVyIDQgLSDDqXZvbHV0aW9uIGRlcyBwcm90w6lpbmVzICBzaW5pZmljYXRpdmVtZW50IHN1cMOpcmlldXIgw6AgbGEgbW95ZW5uZQojIyMgY2x1c3RlciA1IC0gUElCIHNpbmlmaWNhdGl2ZW1lbnQgc3Vww6lyaWV1ciDDoCBsYSBtb3llbm5lCgojIyBSZXByw6lzZW50YXRpb24gdmlzdWVsbGUgZGVzIENsdXN0ZXJzCgpgYGB7cn0KZGZfZnVsbF9jZW50cmVfcmVkdWl0X2NsdXN0ZXJfdHJhbnMgPC0gdHJhbnNmb3JtKGRmX2Z1bGxfY2VudHJlX3JlZHVpdF9jbHVzdGVyLCBjbHVzdCA9IGFzLmZhY3RvcihjbHVzdCkpIApmdml6X3BjYV9iaXBsb3QocmVzLnBjYSwgcG9pbnRzaXplID0gMSwgbGFiZWxzaXplID0gMiwgYXhlcyA9IGMoMSwyKSwgc2VsZWN0LmluZCA9IGxpc3QoY29zMiA9IDAuNTApLGFkZEVsbGlwc2VzID0gVFJVRSwgZWxsaXBzZS5sZXZlbD0wLjYwLGNvbC5pbmQgPSBkZl9mdWxsX2NlbnRyZV9yZWR1aXRfY2x1c3RlciRjbHVzdCwgY29sb3JfcGFsZXR0ZT1jKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIsIiNGQzRFMDciLCIjRkM0RTA3IikpICsgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKSArIGdnc2F2ZSgiUDVfaW1nX2JpcGxvdF9wY2EucG5nIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gOCkKCmBgYAotPiBDZXR0ZSByZXByw6lzZW50YXRpb24gY29uZmlybWUgbGUgY2hvaXggZHUgY2x1c3RlciA1IGNhciBjJ2VzdCBsZSBjbHVzdGVyIHF1aSBzJ2FwcHJvY2hlIGxlIHBsdXMgZGVzIGNvbnNvbW1hdGlvbnMgc291aGFpdMOpZXMsIG1haXMgYXVzc2kgcG91ciBsYSByaWNoZXNzZSBldCBsYSBzw6ljdXJpdMOpIAoKIyA0LjIgQ2hvaXggZHUgY2x1c3RlciA1CmBgYHtyfQpkZl9mdWxsX2luZGl2aWR1cwpkZl9mdWxsX2luZGl2aWR1cyRBcmVhIDwtIHJvd25hbWVzKGRmX2Z1bGxfaW5kaXZpZHVzKQpkZl9jbHVzdDUgPC0gc3Vic2V0KGRmX2Z1bGxfY2VudHJlX3JlZHVpdF9jbHVzdGVyLCBjbHVzdCA9PSA1KQojZGZfY2x1c3Q1X2Z1bGwgPC0gZGZfY2x1c3Q1WywwXQojZGZfY2x1c3Q1X2Z1bGwkQXJlYSA8LSByb3duYW1lcyhkZl9jbHVzdDVfZnVsbCkKI2RmX2NsdXN0NV9mdWxsIDwtIG1lcmdlKGRmX2NsdXN0NV9mdWxsLGRmX2Z1bGxfaW5kaXZpZHVzLCBieSA9ICdBcmVhJykKI2RmX2NsdXN0NSA8LSBzdWJzZXQoZGZfZnVsbF9jZW50cmVfcmVkdWl0X2NsdXN0ZXIsIGNsdXN0ID09IDUpCnByaW50KGRmX2NsdXN0NVssMF0pCmBgYAoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyA1IENsdXN0ZXIgbnVtw6lybyA1IC0gQXBwbGljYXRpb24gZGUgbm91dmVsbGVzIGFuYWx5c2VzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgNS4xIFN1cHByZXNzaW9uIGRlIHZhcmlhYmxlcwpjbHVzdCBjYXIgb24gZ2FyZGUgdG91cyBsZXMgcGF5cyAgClBJQl91c2JfaGFiIGNhciB0b3VzIGNlcyBwYXlzIHNvbnQgcmljaGVzICAKc2VjdXJpdGUgY2FyIHRvdXMgY2VzIHBheXMgc29udCBzw7tycyAgClBvdWxldHMxMDAwIGNhciBpbHMgbidvbnQgcGFzIHVuZSBncmFuZGUgcXVhbnRpdMOpIGRlIHZvbGFpbGxlcyAgCnBvcF9ldm8gY2FyIGwnw6l2b2x1dGlvbiBlc3Qgc2VtYmxhYmxlIGRhbnMgdG91cyBjZXMgcGF5cyAoIHBsdXTDtHQgZmFpYmxlICkgIAoKYGBge3J9CmRmX2NsdXN0NSA8LSBzdWJzZXQoZGZfY2x1c3Q1LCBzZWxlY3QgPSAtYyhjbHVzdCxQSUJfdXNkX2hhYixQb3VsZXRzMTAwMCwgcG9wX2V2bywgcHJvdF9yYXBwb3J0LHNlY3VyaXRlKSkKYGBgCgojIyMgNS4yIEFqb3V0IGQndW5lIG5vdXZlbGxlIHZhcmlhYmxlIHBvdXIgZXNzYXllciBkZSBkaXN0aW5ndWVyIGxlcyBpbmRpdmlkdXMgZGUgY2UgZ3JvdXBlCgpgYGB7cn0KIyBham91dCBkZSBsYSBwcm9kdWN0aW9uIGRlIHBvdWxldHMKZmljX3BvdWxldF9wcm9kIDwtIHBhc3RlKHJlcGVydG9pcmUsInBvdWxldHNfcHJvZHVjdGlvbl8yMDE5LmNzdiIsc2VwPSIiKQpkZl9wb3VsZXRfcHJvZCA8LSByZWFkLmNzdjIoZmljX3BvdWxldF9wcm9kLGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgZGVjID0gIi4iKQpkZl9wb3VsZXRfcHJvZCA8LSBzdWJzZXQoZGZfcG91bGV0X3Byb2Qsc2VsZWN0ID0gYyhBcmVhLFZhbHVlKSkKbmFtZXMoZGZfcG9wKVtuYW1lcyhkZl9wb3ApPT0iWm9uZSJdPC0iQXJlYSIKZGZfcG91bGV0X3Byb2QgPC0gbWVyZ2UoZGZfcG91bGV0X3Byb2QsZGZfcG9wLGJ5PSJBcmVhIikKZGZfcG91bGV0X3Byb2QkcHJvZF9wb3VsZXRfaGFiIDwtZGZfcG91bGV0X3Byb2QkVmFsdWUvZGZfcG91bGV0X3Byb2QkSGFiMTAwMApkZl9wb3VsZXRfcHJvZCA8LSBzdWJzZXQoZGZfcG91bGV0X3Byb2Qsc2VsZWN0ID0gYyhBcmVhLHByb2RfcG91bGV0X2hhYikpCgpkZl9jbHVzdDUkQXJlYSA8LSByb3duYW1lcyhkZl9jbHVzdDUpCiNkZl9jbHVzdDVfcHJvZCA8LSBtZXJnZShkZl9jbHVzdDUsZGZfcG91bGV0X3Byb2QsYnk9IkFyZWEiKQojbmFtZXMoZGZfY2x1c3Q1X3Byb2QpW25hbWVzKGRmX2NsdXN0NV9wcm9kKT09IlZhbHVlIl08LSJQcm9kX1BvdWxldFgxMDAwIgoKI2RmX2NsdXN0NV9wcm9kPC0gZGF0YS5mcmFtZShkZl9jbHVzdDVfcHJvZFssLTFdLCByb3cubmFtZXM9ZGZfY2x1c3Q1X3Byb2RbLDFdKQojZGZfZnVsbF9pbmRpdmlkdXMKZGZfZnVsbF9pbmRpdmlkdXMkQXJlYSA8LSByb3duYW1lcyhkZl9mdWxsX2luZGl2aWR1cykKCmRmX2NsdXN0NV9mdWxsIDwtIGRmX2NsdXN0NVssMF0KZGZfY2x1c3Q1X2Z1bGwkQXJlYSA8LSByb3duYW1lcyhkZl9jbHVzdDVfZnVsbCkKZGZfY2x1c3Q1X2Z1bGwgPC0gbWVyZ2UoZGZfY2x1c3Q1X2Z1bGwsZGZfZnVsbF9pbmRpdmlkdXMsIGJ5ID0gJ0FyZWEnKQpkZl9jbHVzdDVfZnVsbCA8LSBtZXJnZShkZl9jbHVzdDVfZnVsbCxkZl9wb3VsZXRfcHJvZCwgYnkgPSAnQXJlYScpCmRmX2NsdXN0NV9mdWxsIDwtIHN1YnNldChkZl9jbHVzdDVfZnVsbCwgc2VsZWN0ID0gLWMoUElCX3VzZF9oYWIsUG91bGV0czEwMDAsIHBvcF9ldm8sIHByb3RfcmFwcG9ydCxzZWN1cml0ZSkpCmRmX2NsdXN0NV9mdWxsPC0gZGF0YS5mcmFtZShkZl9jbHVzdDVfZnVsbFssLTFdLCByb3cubmFtZXM9ZGZfY2x1c3Q1X2Z1bGxbLDFdKQoKZGZfY2x1c3Q1IDwtIHN1YnNldChkZl9jbHVzdDUsIHNlbGVjdCA9IC1jKEFyZWEpKQoKI2RmX2NsdXN0NSA8LSBzdWJzZXQoZGZfZnVsbF9jZW50cmVfcmVkdWl0X2NsdXN0ZXIsIGNsdXN0ID09IDUpCiNwcmludChkZl9jbHVzdDVbLDBdKQpgYGAKIyMjIEFmZmljaGFnZSBkZXMgdGFibGVzIHBvdXIgY29udHLDtGxlCmBgYHtyfQpkZl9wb3AKZGZfY2x1c3Q1CmRmX3BvdWxldF9wcm9kCiNkZl9jbHVzdDVfcHJvZApkZl9jbHVzdDVfZnVsbApgYGAKCiMjIyA2LjMgQUNQIHN1ciBsYSB0YWJsZSBjZW50csOpIHLDqWR1aXQgZHUgY2x1c3RlciA1CmBgYHtyfQpyZXM1LnBjYSA8LSBQQ0EoZGZfY2x1c3Q1LCBzY2FsZS51bml0ID0gRkFMU0UsIGdyYXBoID0gRkFMU0UpCmBgYAojIyMgNi40IEhDUEMgcGFyIHJhcHBvcnQgw6AgbCdBQ1Agc2FucyBwcsOpY2lzZXIgbGUgbm9tYnJlIGRlIGNsdXN0ZXJzCmBgYHtyfQpyZXM1LmhjcGMgPC0gSENQQyhyZXM1LnBjYSwgZ3JhcGggPSBGQUxTRSkgCmBgYAojIyA2LjUgZGVuZG9ncmFtZSDDoCBwYXJ0aXIgZGUgbCdIQ1BDCmBgYHtyfQpmdml6X2RlbmQocmVzNS5oY3BjLCAKICAgICAgICAgIGNleCA9IDAuNywgICAgICAgICAgICAgICAgICAgICAjIFRhaWxsZSBkdSB0ZXh0CiAgICAgICAgICBwYWxldHRlID0gImpjbyIsICAgICAgICAgICAgICAgIyBQYWxldHRlIGRlIGNvdWxldXIgP2dncHVicjo6Z2dwYXIKICAgICAgICAgIHJlY3QgPSBUUlVFLCByZWN0X2ZpbGwgPSBUUlVFLCAjIFJlY3RhbmdsZSBhdXRvdXIgZGVzIGdyb3VwZXMKICAgICAgICAgIHJlY3RfYm9yZGVyID0gImpjbyIsICAgICAgICAgICAjIENvdWxldXIgZHUgcmVjdGFuZ2xlCiAgICAgICAgICBsYWJlbHNfdHJhY2tfaGVpZ2h0ID0gMC44ICAgICAgIyBBdWdtZW50IGwnZXNwYWNlIHBvdXIgbGUgdGV4dGUKKQoKYGBgCi0+IExlIGRlbmRhZ3JhbW1lIGEgY29uc3RpdHXDqSAzIGNsdXN0ZXJzIGNlIHF1aSBzZW1ibGUgdW4gbm9tYnJlIGNvcnJlY3QgZGUgZ3JvdXBlcyBjb21wdGUgdGVudSBkdSBub21icmUgZGUgcGF5cyBkYW5zIGNoYWN1biBkJ2V1eC4gIAoKSnVzdGlmaWVyIGxlIGNob2l4IGRlcyB2YXJpYWJsZXMgcGliIGV0IHPDqWN1cml0w6kgY29ycsOpbMOpcyBtYWlzIHRvdXMgY2VzIHBheXMgc29udCByaWNoZXMgZXQgc8OpY3VyaXPDqXMgCgojIyBPYnNlcnZhdGlvbiBkZXMgY2x1c3RlcnMKYGBge3J9CmZ2aXpfY2x1c3RlcihyZXM1LmhjcGMsCiAgICAgICAgICAgICBsYWJlbHNpemUgPSA4ICwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudCA9IFRSVUUsICMgTW9udHJlIGxlIGNlbnRyZSBkZXMgY2x1c3RlcnMKICAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwgICAgICAgICAjIFBhbGV0dGUgZGUgY291bGV1cnMsIHZvaXIgP2dncHVicjo6Z2dwYXIKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCksCiAgICAgICAgICAgICBtYWluID0gIkZhY3RvciBtYXAiCikKCmBgYApgYGB7cn0KZnZpel9wY2FfdmFyIChyZXM1LnBjYSwgY29sLnZhciA9ICJjb3MyIiwKICAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgICByZXBlbCA9IFRSVUUgIyDDiXZpdGUgbGUgY2hldmF1Y2hlbWVudCBkZSB0ZXh0ZQopCgpgYGAKCmBgYHtyfQpkZl9jbHVzdDVfc2NhbGVkIDwtIGFzLmRhdGEuZnJhbWUoZGZfY2x1c3Q1KQpyZXM1LnBjYSA8LSBQQ0EoZGZfY2x1c3Q1X3NjYWxlZCwgZ3JhcGggPSBGQUxTRSkKYGBgCiMjIMOpYm91bGlzIGRlIHZhbGV1cnMgcHJvcHJlcwpgYGB7cn0KZWlnNS52YWwgPC0gZ2V0X2VpZ2VudmFsdWUocmVzNS5wY2EpCmBgYAoKIyMgcGVydGUgZCdpbmVydGllIGVuIGZvbmN0aW9uIGRlcyBkaW1lbnNpb25zCmBgYHtyfQpmdml6X2VpZyhyZXM1LnBjYSwgYWRkbGFiZWxzID0gVFJVRSwgeWxpbSA9IGMoMCwgNTApKQoKYGBgCgpgYGB7cn0KdmFyNSA8LSBnZXRfcGNhX3ZhcihyZXM1LnBjYSkKY29ycnBsb3QodmFyNSRjb3MyLCBpcy5jb3JyPUZBTFNFLCB0aXRsZT0iUXVhbGl0w6kgZGVzIHZhcmlhYmxlcyIsIG1hcj1jKDAsMCwxLDApKQpgYGAKCmBgYHtyfQojIENvbG9yZXIgZW4gZm9uY3Rpb24gZHUgY29zMjogcXVhbGl0w6kgZGUgcmVwcsOpc2VudGF0aW9uCmZ2aXpfcGNhX3ZhcihyZXM1LnBjYSwgY29sLnZhciA9ICJjb3MyIixncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSxyZXBlbCA9IFRSVUUpICsgbGFicyh0aXRsZSA9ICJGaWd1cmUgMTAgLSBDZXJjbGUgZGVzIGNvcnLDqWxhdGlvbnMiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKSAKCgpgYGAKCmBgYHtyfQpmdml6X3BjYV9iaXBsb3QocmVzNS5wY2EsIGNvbC52YXIgPSAiIzJFOUZERiIsIHBvaW50c2l6ZSA9IDEsIGxhYmVsc2l6ZSA9IDMsIGF4ZXMgPSBjKDEsMikpICsgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKQpgYGAKYGBge3J9CmRmX2NsdXN0X3NjYWxlZF9jbHVzdGVyIDwtcmVzNS5oY3BjJGRhdGEuY2x1c3QKZGZfY2x1c3Rfc2NhbGVkX2NsdXN0ZXIKcGF5c19jbHVzdGVyIDwtIHN1YnNldChkZl9jbHVzdF9zY2FsZWRfY2x1c3Rlciwgc2VsZWN0PWMoY2x1c3QpKQojIHbDqXJpZmljYXRpb24KIyBzdW1tYXJ5KGRmX2Z1bGxfY2x1c3RlcikKcGF5c19jbHVzdGVyCmBgYAoKCmBgYHtyfQpkZl9jbHVzdF9zY2FsZWRfY2x1c3Rlcl90cmFucyA8LSB0cmFuc2Zvcm0oZGZfY2x1c3Rfc2NhbGVkX2NsdXN0ZXIsIGNsdXN0ID0gYXMuZmFjdG9yKGNsdXN0KSkgCmZ2aXpfcGNhX2JpcGxvdChyZXM1LnBjYSwgcG9pbnRzaXplID0gMSwgbGFiZWxzaXplID0gMiwgYXhlcyA9IGMoMSwyKSwgc2VsZWN0LmluZCA9IGxpc3QoY29zMiA9IDAuMzApLGFkZEVsbGlwc2VzID0gVFJVRSwgZWxsaXBzZS5sZXZlbD0wLjYwLGNvbC5pbmQgPSBkZl9jbHVzdF9zY2FsZWRfY2x1c3RlciRjbHVzdCwgY29sb3JfcGFsZXR0ZT1jKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIsIiNGQzRFMDciLCIjRkM0RTA3IikpICsgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKQoKYGBgCgpgYGB7cn0KZGZfY2x1c3Rfc2NhbGVkX2NsdXN0ZXJfdHJhbnMgPC0gdHJhbnNmb3JtKGRmX2NsdXN0X3NjYWxlZF9jbHVzdGVyLCBjbHVzdCA9IGFzLmZhY3RvcihjbHVzdCkpIApmdml6X3BjYV9iaXBsb3QocmVzNS5wY2EsIHBvaW50c2l6ZSA9IDEsIGxhYmVsc2l6ZSA9IDIsIGF4ZXMgPSBjKDEsMyksIHNlbGVjdC5pbmQgPSBsaXN0KGNvczIgPSAwLjMwKSxhZGRFbGxpcHNlcyA9IFRSVUUsIGVsbGlwc2UubGV2ZWw9MC42MCxjb2wuaW5kID0gZGZfY2x1c3Rfc2NhbGVkX2NsdXN0ZXIkY2x1c3QsIGNvbG9yX3BhbGV0dGU9YygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciLCIjRkM0RTA3IiwiI0ZDNEUwNyIpKSArICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yPSIjMzg3NkMyIiwgc2l6ZT0yMCwgZmFjZT0iYm9sZCIsaGp1c3QgPSAwLjUpLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siLCBzaXplPTE0LCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLHZqdXN0ID0gMC41KSkKCgpgYGAKIyMgRW4gZmFpc2FudCB1biBBQ1Agc3VyIGwnYXhlIDEuMiBldCAxLjMsIG9uIG9ic2VydmUgdW4gZ3JvdXBlIHNlIGRpc3Rpbmd1ZXIgZGVzIGF1dHJlcywgbGUgY2x1c3RlciAzIElzbGFuZGUsIEx1eGVtYm91cmcsIFN1aXNzZSwgRmlubGFuZGUgZXQgTm9ydsOoZ2UuICAKIyMgc2kgbCdvbiBzb3VoYWl0ZSByw6lkdWlyZSBlbmNvcmUgbCfDqWNoYW50aWxsb24sIGplIHByb3Bvc2UgZGUgcHJlbmRyZSBlbiBjb21wdGUgbGEgZGlzdGFuY2UsIGNlIHF1aSByw6lkdWlyYSBsYSBzw6lsZWN0aW9uIGF1IEx1eGVtYm91cmcgZXQgbGEgU3Vpc3NlLCBsZXNxdWVscyBzb250IGZyb250YWxpZXJzLCByaWNoZXMgZXQgcXVpIHBsdXMgZXN0IGZyYW5jb3Bob25lcy4gIAojIyB0cm91dmVyIGxlcyBpbmZvcm1hdGlvbnMgY29uY2VybmFudCBsYSBwcm9kdWN0aW9uLCBsJ2ltcG9ydGF0aW9uIGV0IMOpdmVudHVlbGxlbWVudCBsYSBjb25zb21tYXRpb24gIAoKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKdGVzdCBhdmVjIGRmX2NsdXN0NV9mdWxsCiMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyBBQ1Agc3VyIGxhIHRhYmxlIGNlbnRyw6kgcsOpZHVpdCBkdSBjbHVzdGVyIDUKYGBge3J9CmRmX2NsdXN0NV9mdWxsCmRmX2NsdXN0NV9mdWxsX2NlbnRyZV9yZWR1aXQKZGZfY2x1c3Q1X2Z1bGxfY2VudHJlX3JlZHVpdCA8LSBzY2FsZShkZl9jbHVzdDVfZnVsbCkKcmVzNS5wY2EgPC0gUENBKGRmX2NsdXN0NV9mdWxsX2NlbnRyZV9yZWR1aXQsIHNjYWxlLnVuaXQgPSBGQUxTRSwgZ3JhcGggPSBGQUxTRSkKYGBgCgojIyMgSENQQyBwYXIgcmFwcG9ydCDDoCBsJ0FDUCBldCBqZSBsYWlzc2UgbGlicmUgbGUgbm9tYnJlIGRlIGNsdXN0ZXJzCmBgYHtyfQpyZXM1LmhjcGMgPC0gSENQQyhyZXM1LnBjYSwgZ3JhcGggPSBGQUxTRSkgIyBuYi5jbHVzdCA9IDQsCmBgYAoKIyMgZGVuZG9ncmFtZSDDoCBwYXJ0aXIgZGUgbCdIQ1BDCmBgYHtyfQpmdml6X2RlbmQocmVzNS5oY3BjLCAKICAgICAgICAgIGNleCA9IDAuNywgICAgICAgICAgICAgICAgICAgICAjIFRhaWxsZSBkdSB0ZXh0CiAgICAgICAgICBwYWxldHRlID0gImpjbyIsICAgICAgICAgICAgICAgIyBQYWxldHRlIGRlIGNvdWxldXIgP2dncHVicjo6Z2dwYXIKICAgICAgICAgIHJlY3QgPSBUUlVFLCByZWN0X2ZpbGwgPSBUUlVFLCAjIFJlY3RhbmdsZSBhdXRvdXIgZGVzIGdyb3VwZXMKICAgICAgICAgIHJlY3RfYm9yZGVyID0gImpjbyIsICAgICAgICAgICAjIENvdWxldXIgZHUgcmVjdGFuZ2xlCiAgICAgICAgICBsYWJlbHNfdHJhY2tfaGVpZ2h0ID0gMC44ICAgICAgIyBBdWdtZW50IGwnZXNwYWNlIHBvdXIgbGUgdGV4dGUKKQoKYGBgCgojIyBPYnNlcnZhdGlvbiBkZXMgY2x1c3RlcnMKYGBge3J9CmZ2aXpfY2x1c3RlcihyZXM1LmhjcGMsCiAgICAgICAgICAgICBsYWJlbHNpemUgPSA4ICwKICAgICAgICAgICAgIHNob3cuY2x1c3QuY2VudCA9IFRSVUUsICMgTW9udHJlIGxlIGNlbnRyZSBkZXMgY2x1c3RlcnMKICAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwgICAgICAgICAjIFBhbGV0dGUgZGUgY291bGV1cnMsIHZvaXIgP2dncHVicjo6Z2dwYXIKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCksCiAgICAgICAgICAgICBtYWluID0gIkZhY3RvciBtYXAiCikKCmBgYAoKYGBge3J9CmZ2aXpfcGNhX3ZhciAocmVzNS5wY2EsIGNvbC52YXIgPSAiY29zMiIsCiAgICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksCiAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFICMgw4l2aXRlIGxlIGNoZXZhdWNoZW1lbnQgZGUgdGV4dGUKKQoKYGBgCgoKYGBge3J9CgpyZXM1LnBjYSA8LSBQQ0EoZGZfY2x1c3Q1X2Z1bGxfY2VudHJlX3JlZHVpdCwgZ3JhcGggPSBGQUxTRSkKYGBgCiMjIMOpYm91bGlzIGRlIHZhbGV1cnMgcHJvcHJlcwpgYGB7cn0KZWlnNS52YWwgPC0gZ2V0X2VpZ2VudmFsdWUocmVzNS5wY2EpCmBgYAoKIyMgcGVydGUgZCdpbmVydGllIGVuIGZvbmN0aW9uIGRlcyBkaW1lbnNpb25zCmBgYHtyfQpmdml6X2VpZyhyZXM1LnBjYSwgYWRkbGFiZWxzID0gVFJVRSwgeWxpbSA9IGMoMCwgNTApKQoKYGBgCgpgYGB7cn0KdmFyNSA8LSBnZXRfcGNhX3ZhcihyZXM1LnBjYSkKY29ycnBsb3QodmFyNSRjb3MyLCBpcy5jb3JyPUZBTFNFLCB0aXRsZT0iUXVhbGl0w6kgZGVzIHZhcmlhYmxlcyIsIG1hcj1jKDAsMCwxLDApKQpgYGAKCmBgYHtyfQojIENvbG9yZXIgZW4gZm9uY3Rpb24gZHUgY29zMjogcXVhbGl0w6kgZGUgcmVwcsOpc2VudGF0aW9uCmZ2aXpfcGNhX3ZhcihyZXM1LnBjYSwgY29sLnZhciA9ICJjb3MyIixncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSxyZXBlbCA9IFRSVUUpICsgbGFicyh0aXRsZSA9ICJGaWd1cmUgMTAgLSBDZXJjbGUgZGVzIGNvcnLDqWxhdGlvbnMiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKSAKCgpgYGAKCmBgYHtyfQpmdml6X3BjYV9iaXBsb3QocmVzNS5wY2EsIGNvbC52YXIgPSAiIzJFOUZERiIsIHBvaW50c2l6ZSA9IDEsIGxhYmVsc2l6ZSA9IDMsIGF4ZXMgPSBjKDEsMikpICsgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3I9IiMzODc2QzIiLCBzaXplPTIwLCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsdmp1c3QgPSAwLjUpKQpgYGAKCmBgYHtyfQpmdml6X3BjYV9iaXBsb3QocmVzNS5wY2EsIHBvaW50c2l6ZSA9IDEsIGxhYmVsc2l6ZSA9IDMsIGF4ZXMgPSBjKDEsMiksIHNlbGVjdC5pbmQgPSBsaXN0KGNvczIgPSAwLjMwKSxhZGRFbGxpcHNlcyA9IFRSVUUsIGVsbGlwc2UubGV2ZWw9MC42MCxjb2wuaW5kID0gZGZfY2x1c3Rfc2NhbGVkX2NsdXN0ZXIkY2x1c3QsIGNvbG9yX3BhbGV0dGU9YygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciLCIjRkM0RTA3IiwiI0ZDNEUwNyIpKSArICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yPSIjMzg3NkMyIiwgc2l6ZT0yMCwgZmFjZT0iYm9sZCIsaGp1c3QgPSAwLjUpLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siLCBzaXplPTE0LCBmYWNlPSJib2xkIixoanVzdCA9IDAuNSksYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIsIHNpemU9MTQsIGZhY2U9ImJvbGQiLHZqdXN0ID0gMC41KSkKCmBgYAoKYGBge3J9CmRmX2NsdXN0X3NjYWxlZF9jbHVzdGVyX3RyYW5zIDwtIHRyYW5zZm9ybShkZl9jbHVzdF9zY2FsZWRfY2x1c3RlciwgY2x1c3QgPSBhcy5mYWN0b3IoY2x1c3QpKSAKZnZpel9wY2FfYmlwbG90KHJlczUucGNhLCBwb2ludHNpemUgPSAxLCBsYWJlbHNpemUgPSAyLCBheGVzID0gYygxLDMpLCBzZWxlY3QuaW5kID0gbGlzdChjb3MyID0gMC4zMCksYWRkRWxsaXBzZXMgPSBUUlVFLCBlbGxpcHNlLmxldmVsPTAuNjAsY29sLmluZCA9IGRmX2NsdXN0X3NjYWxlZF9jbHVzdGVyJGNsdXN0LCBjb2xvcl9wYWxldHRlPWMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiwiI0ZDNEUwNyIsIiNGQzRFMDciKSkgKyAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iIzM4NzZDMiIsIHNpemU9MjAsIGZhY2U9ImJvbGQiLGhqdXN0ID0gMC41KSxheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiwgc2l6ZT0xNCwgZmFjZT0iYm9sZCIsaGp1c3QgPSAwLjUpLGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siLCBzaXplPTE0LCBmYWNlPSJib2xkIix2anVzdCA9IDAuNSkpCgpgYGAKIyMgRW4gZmFpc2FudCB1biBBQ1Agc3VyIGwnYXhlIDEuMiBldCAxLjMsIG9uIG9ic2VydmUgdW4gZ3JvdXBlIHNlIGRpc3Rpbmd1ZXIgZGVzIGF1dHJlcywgbGUgY2x1c3RlciAzIElzbGFuZGUsIEx1eGVtYm91cmcsIFN1aXNzZSwgRmlubGFuZGUgZXQgTm9ydsOoZ2UuCiMjIHNpIGwnb24gc291aGFpdGUgcsOpZHVpcmUgZW5jb3JlIGwnw6ljaGFudGlsbG9uLCBqZSBwcm9wb3NlIGRlIHByZW5kcmUgZW4gY29tcHRlIGxhIGRpc3RhbmNlLCBjZSBxdWkgcsOpZHVpcmEgbGEgc8OpbGVjdGlvbiBhdSBMdXhlbWJvdXJnIGV0IGxhIFN1aXNzZSwgbGVzcXVlbHMgc29udCBmcm9udGFsaWVycywgcmljaGVzIGV0IHF1aSBwbHVzIGVzdCBmcmFuY29waG9uZXMuIAojIyB0cm91dmVyIGxlcyBpbmZvcm1hdGlvbnMgY29uY2VybmFudCBsYSBwcm9kdWN0aW9uLCBsJ2ltcG9ydGF0aW9uIGV0IMOpdmVudHVlbGxlbWVudCBsYSBjb25zb21tYXRpb24KCgoKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyA3IC0gVEVTVFMgU1RBVElTVElRVUVTCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMjIyBBZmZpY2hhZ2UgZGVzIGhpc3RvZ3JhbWVzIGRlIHBsdXNpZXVycyB2YXJpYWJsZXMgcG91ciB2b2lyIHNpIGwnb24gcGV1dCB5IHJldHJvdXZlciBsYSBsb2kgbm9ybWFsZQoKYGBge3J9CiMgbXVsdGlwbG90IDogUG91ciBhZmZpY2hlciBwbHVzaWV1cnMgZ3JhcGhpcXVlcyAKCm11bHRpcGxvdCA8LSBmdW5jdGlvbiguLi4sIHBsb3RsaXN0PU5VTEwsIGZpbGUsIGNvbHM9MSwgbGF5b3V0PU5VTEwpIHsKICBsaWJyYXJ5KGdyaWQpCgogICMgTWFrZSBhIGxpc3QgZnJvbSB0aGUgLi4uIGFyZ3VtZW50cyBhbmQgcGxvdGxpc3QKICBwbG90cyA8LSBjKGxpc3QoLi4uKSwgcGxvdGxpc3QpCgogIG51bVBsb3RzID0gbGVuZ3RoKHBsb3RzKQoKICAjIElmIGxheW91dCBpcyBOVUxMLCB0aGVuIHVzZSAnY29scycgdG8gZGV0ZXJtaW5lIGxheW91dAogIGlmIChpcy5udWxsKGxheW91dCkpIHsKICAgICMgTWFrZSB0aGUgcGFuZWwKICAgICMgbmNvbDogTnVtYmVyIG9mIGNvbHVtbnMgb2YgcGxvdHMKICAgICMgbnJvdzogTnVtYmVyIG9mIHJvd3MgbmVlZGVkLCBjYWxjdWxhdGVkIGZyb20gIyBvZiBjb2xzCiAgICBsYXlvdXQgPC0gbWF0cml4KHNlcSgxLCBjb2xzICogY2VpbGluZyhudW1QbG90cy9jb2xzKSksCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IGNvbHMsIG5yb3cgPSBjZWlsaW5nKG51bVBsb3RzL2NvbHMpKQogIH0KCiBpZiAobnVtUGxvdHM9PTEpIHsKICAgIHByaW50KHBsb3RzW1sxXV0pCgogIH0gZWxzZSB7CiAgICAjIFNldCB1cCB0aGUgcGFnZQogICAgZ3JpZC5uZXdwYWdlKCkKICAgIHB1c2hWaWV3cG9ydCh2aWV3cG9ydChsYXlvdXQgPSBncmlkLmxheW91dChucm93KGxheW91dCksIG5jb2wobGF5b3V0KSkpKQoKICAgICMgTWFrZSBlYWNoIHBsb3QsIGluIHRoZSBjb3JyZWN0IGxvY2F0aW9uCiAgICBmb3IgKGkgaW4gMTpudW1QbG90cykgewogICAgICAjIEdldCB0aGUgaSxqIG1hdHJpeCBwb3NpdGlvbnMgb2YgdGhlIHJlZ2lvbnMgdGhhdCBjb250YWluIHRoaXMgc3VicGxvdAogICAgICBtYXRjaGlkeCA8LSBhcy5kYXRhLmZyYW1lKHdoaWNoKGxheW91dCA9PSBpLCBhcnIuaW5kID0gVFJVRSkpCgogICAgICBwcmludChwbG90c1tbaV1dLCB2cCA9IHZpZXdwb3J0KGxheW91dC5wb3Mucm93ID0gbWF0Y2hpZHgkcm93LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dC5wb3MuY29sID0gbWF0Y2hpZHgkY29sKSkKICAgIH0KICB9Cn0KYGBgCgpgYGB7cn0KcDEgPC0gZ2dwbG90KGRmX2Z1bGxfaW5kaXZpZHVzLCBhZXMoeD1rY2FsX3BlcnNfam91cikpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2xvdXI9ImJsYWNrIiwgZmlsbD0id2hpdGUiLGJpbnM9MzApKwogZ2VvbV9kZW5zaXR5KGFscGhhPS4yLCBmaWxsPSIjRkY2NjY2IikgK2dnc2F2ZSgiaW1nL2ZpZ3VyZTEyX2hpc3RvLnBuZyIsIHdpZHRoID0gMTUsIGhlaWdodCA9IDgpCnAyIDwtIGdncGxvdChkZl9mdWxsX2luZGl2aWR1cywgYWVzKHg9cHJvdF9yYXBwb3J0KSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIsYmlucz0zMCkrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjMsIGZpbGw9IiNGRjY2NjYiKSAKcDMgPC0gZ2dwbG90KGRmX2Z1bGxfaW5kaXZpZHVzLCBhZXMoeD1Qb3VsZXRzMTAwMCkpKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIsYmlucz0zMCkrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjMsIGZpbGw9IiNGRjY2NjYiKSAKcDQgPC0gZ2dwbG90KGRmX2Z1bGxfaW5kaXZpZHVzLCBhZXMoeD1wb3BfZXZvKSkrIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIixiaW5zPTIwKSsKIGdlb21fZGVuc2l0eShhbHBoYT0uMywgZmlsbD0iI0ZGNjY2NiIpIApwNSA8LSBnZ3Bsb3QoZGZfZnVsbF9pbmRpdmlkdXMsIGFlcyh4PVBJQl91c2RfaGFiKSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIsYmlucz02KSsKIGdlb21fZGVuc2l0eShhbHBoYT0uMywgZmlsbD0iI0ZGNjY2NiIpIApwNiA8LSBnZ3Bsb3QoZGZfZnVsbF9pbmRpdmlkdXMsIGFlcyh4PWRpc3RhbmNlKSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIsYmlucz01MCkrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjMsIGZpbGw9IiNGRjY2NjYiKSAKcDcgPC0gZ2dwbG90KGRmX2Z1bGxfaW5kaXZpZHVzLCBhZXMoeD1zZWN1cml0ZSkpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2xvdXI9ImJsYWNrIiwgZmlsbD0id2hpdGUiLGJpbnM9OCkrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjMsIGZpbGw9IiNGRjY2NjYiKSAKbXVsdGlwbG90KHAxLCBwMiwgcDMsIHA0LHA1LHA2LHA3LCBjb2xzPTIpCmBgYAoKIyMjIExhIGxvaSBub3JtYWxlIHNlIHJlcHLDqXNlbnRlIHBhciB1bmUgY291cmJlIHNlbWJsYWJsZSDDoCB1bmUgY2xvY2hlIGQnw6lnbGlzZSBhdmVjIHVuIHBvaW50IGN1bG1pbmFudCBhdSBtaWxpZXUKIyMjIERldXggaGlzdG9ncmFtbWVzIHMnYXBwYXJlbnRlbnQgw6AgdW5lIGxvaSBub3JtYWxlLCBsYSBzw6ljdXJpdMOpIGV0IGwnw6l2b2x1dGlvbiBkZSBsYSBwb3B1bGF0aW9uCiMjIyBOb3VzIGFsbG9ucyBkb25jIHLDqWFsaXNlciBkZXMgdGVzdCBzdGF0aXN0aXF1ZXMgc3VyIGNlcyBkZXV4IHZhcmlhYmxlcyBwb3VyIHZvaXIgc2kgZWxsZXMgcmVzcGVjdGVudCBsYSBsb2kgbm9ybWFsZQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIyA3LjEgLSBURVNUIEQnQURFUVVBVElPTgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIFBvdXIgbGEgc8OpY3VyaXTDqQpgYGB7cn0KZGZfc2VjdV90ZXN0IDwtIHRyYW5zZm9ybShkZl9zZWN1LCBzZWN1cml0ZSA9IGFzLm51bWVyaWMoc2VjdXJpdGUpKQprcy50ZXN0KGRmX3NlY3Ukc2VjdXJpdGUsInBub3JtIixtZWFuPW1lYW4oZGZfc2VjdSRzZWN1cml0ZSkpCmBgYApMYSBwLXZhbGV1ciBlc3Qgc3Vww6lyaWV1cmUgw6AgNSUuCk9uIG5lIHBldXQgZG9uYyBwYXMgcmVqZXRlciBs4oCZaHlwb3Row6hzZSBkZSBub3JtYWxpdMOpIGF1IG5pdmVhdSBkdSB0ZXN0IMOgIDUlLgpMJ2luZGljZSBkZSBsYSBzw6ljdXJpdMOpIHN1aXQgdW5lIGxvaSBub3JtYWxlLgoKIyMjIFBvdXIgbCfDqXZvbHV0aW9uIGRlIGxhIHBvcHVsYXRpb24KYGBge3J9CmRmX3BvcF90ZXN0IDwtIHRyYW5zZm9ybShkZl9wb3AsIEhhYjEwMDAgPSBhcy5udW1lcmljKEhhYjEwMDApKQprcy50ZXN0KGRmX3BvcCRIYWIxMDAwLCJwbm9ybSIsbWVhbj1tZWFuKGRmX3BvcCRIYWIxMDAwKSkKYGBgCgpRdWFuZCDDoCBsYSBwb3B1bGF0aW9uLCBhdmVjIHVuZSBwLXZhbGV1ciBkZSAyLjJlLTE2IG9uIHBldXQgZGlyZSBxdWUgbCdpbmRpY2UgZGUgbGEgcG9wdWxhdGlvbiBuZSBzdWl0IHBhcyB1bmUgbG9pIG5vcm1hbGUuCgoKIyMgbG9pIG5vcm1hbGUgc3VyIGNsdXN0ZXIgNCBldCA1IHBvdXIgc8OpY3VyaXTDqQpgYGB7cn0KY2x1c3Q0X3NlY3UgPC0gZmlsdGVyKGRmX2Z1bGxfY2VudHJlX3JlZHVpdF9jbHVzdGVyLCBjbHVzdCA9PSAnNCcpJHNlY3VyaXRlCmNsdXN0NV9zZWN1IDwtIGZpbHRlcihkZl9mdWxsX2NlbnRyZV9yZWR1aXRfY2x1c3RlciwgY2x1c3QgPT0gJzUnKSRzZWN1cml0ZQpgYGAKCiMjIyBsb2kgbm9ybWFsZSBzdXIgbGEgc8OpY3VyaXTDqSBkdSBjbHVzdGVyIDQKYGBge3J9CmtzLnRlc3QoY2x1c3Q0X3NlY3UsInBub3JtIixtZWFuPW1lYW4oY2x1c3Q0X3NlY3UpKQpgYGAKTGEgcC12YWxldXIgZXN0IHN1cMOpcmlldXJlIMOgIDUlLgpPbiBuZSBwZXV0IGRvbmMgcGFzIHJlamV0ZXIgbOKAmWh5cG90aMOoc2UgZGUgbm9ybWFsaXTDqSBhdSBuaXZlYXUgZHUgdGVzdCDDoCA1JS4KTCdpbmRpY2UgZGUgbGEgc8OpY3VyaXTDqSBzdWl0IHVuZSBsb2kgbm9ybWFsZS4KCiMjIyBsb2kgbm9ybWFsZSBzdXIgbGEgc8OpY3VyaXTDqSBkdSBjbHVzdGVyIDUKYGBge3J9CmtzLnRlc3QoY2x1c3Q1X3NlY3UsInBub3JtIixtZWFuPW1lYW4oY2x1c3Q1X3NlY3UpKQpgYGAKUG91ciBsZSBjbHVzdGVyIDUuCkxhIHAtdmFsZXVyIGVzdCBpbmbDqXJpZXVyZSDDoCA1JS4KT24gcGV1dCBkb25jIHJlamV0ZXIgbOKAmWh5cG90aMOoc2UgZGUgbm9ybWFsaXTDqSBhdSBuaXZlYXUgZHUgdGVzdCDDoCA1JS4KTCdpbmRpY2UgZGUgbGEgc8OpY3VyaXTDqSBuZSBzdWl0IHBhcyB1bmUgbG9pIG5vcm1hbGUuCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIyA3LjIgLSBURVNUIERFIENPTVBBUkFJU09OCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpEJ2FwcsOocyBsZSBncmFwaGUgb24gcGV1dCB2b2lyIHF1ZSBsZXMgY2x1c3RlciA0IGV0IDUgc29udCBwcm9jaGVzLCBub3VzIGFsbG9ucyBmYWlyZSB1bmUgY29tcGFyYWlzb24gZGVzIHZhcmlhbmNlcyBzdXIgbGEgdmFyaWFibGUgZGUgc8OpY3VyaXTDqSBwb3VyIGNlcyBkZXV4IGNsdXN0ZXJzCgoKYGBge3J9CnZhci50ZXN0KGNsdXN0NF9zZWN1LGNsdXN0NV9zZWN1KQpgYGAKTGEgcC12YWxldXIgdmFsYW50IDAuMjgzMywgb24gbmUgcmVqZXR0ZSBkb25jIHBhcyBs4oCZw6lnYWxpdMOpIGRlcyB2YXJpYW5jZXMgYXUgbml2ZWF1IGRlIHRlc3QgNSUuCgpURVNUIEQnw4lHQUxJVMOJIERFUyBNT1lFTk5FUwoKYGBge3J9CnQudGVzdChjbHVzdDVfc2VjdSxjbHVzdDRfc2VjdSx2YXIuZXF1YWw9VFJVRSxhbHRlcm5hdGl2ZT0iZ3JlYXRlciIpCmBgYAoKTGEgcC12YWxldXIgw6l0YW50IHByb2NoZSBkZSAwIG9uIHJlamV0dGUgbCdoeXBvdGjDqHNlIGQnw6lnYWxpdMOpIGRlcyBtb3llbm5lcy4KTGVzIG1veWVubmVzIM68NCBldCDOvDUgbmUgc29udCBkb25jIHBhcyDDqWdhbGVzLgoKIyBFbiBjb25jbHVzaW9uIDoKIyAtLS0tLS0tLS0tLS0tLS0tLQojIyMgTGEgdmFyaWFibGUgc8OpY3VyaXTDqSBhIMOpdMOpIHNvdW1pc2Ugw6AgZGVzIHRlc3RzIHN0YXRpc3RpcXVlcyBkYW5zIGxlIGJ1dCBkZSBzYXZvaXIgc2kgZWxsZSBzdWl2YWl0IGxlcyBtw6ptZXMgaW5mbHVlbmNlcyBzdXIgZGV1eCBjbHVzdGVycyBkaWZmw6lyZW50cyBtYWlzIHByb2NoZXMuCiMjIyBMJ2FzcGVjdCBnYXVzc2llbiBkZXMgdmFyaWFibGVzIHPDqWN1cml0w6kgYSDDqXTDqSB2w6lyaWZpw6kgcGFyIHVuIHRlc3QgZCdhZMOpcXVhdGlvbiB2aWEgdW5lIGxvaSBub3JtYWxlIHBhciBsZSB0ZXN0IGRlIEtvbG1vZ29yb3YtU21pcm5vdi4gUG91ciBsZXMgY2x1c3RlcnMgNCBldCA1LCBsJ2h5cG90aMOoc2UgZCfDqWdhbGl0w6kgZGVzIHZhcmlhbmNlcyBhIMOpdMOpIHbDqXJpZmnDqWUuCiMjIyBjb250cmFpcmVtZW50IMOgIGwnaHlwb3Row6hzZSBkJ8OpZ2FsaXTDqSBkZXMgbW95ZW5uZXMgZGUgbGEgdmFyaWFibGUgc8OpY3VyaXTDqSBwb3VyIGxlcyBjbHVzdGVycyA0IGV0IDUgcXVpIG5lIHN1aXZlbnQgcGFzIGxhIG3Dqm1lIGRpc3RyaWJ1dGlvbiBzdXIgbGVzIGRldXggY2x1c3RlcnMgZXQgc29udCBkb25jIGRpc3RpbmN0cy4gCg==