Carregamento dos dados

dados <- read_excel("dados.xlsx", sheet = "dados")
dados$trat <- as.factor(dados$trat)
levels(dados$trat) <- c("50ml","100ml","200ml")

ANOVA e Tukey para Altura

with(dados,fat2.dic(cult,trat,alt, fac.names=c("Cultivar","Tratamento")))
------------------------------------------------------------------------
Legenda:
FATOR 1:  Cultivar 
FATOR 2:  Tratamento 
------------------------------------------------------------------------


Quadro da analise de variancia
------------------------------------------------------------------------
                    GL      SQ      QM     Fc    Pr>Fc
Cultivar             4 115.731 28.9328 38.958 0.000000
Tratamento           2  24.153 12.0763 16.261 0.000175
Cultivar*Tratamento  8  11.191  1.3988  1.884 0.138309
Residuo             15  11.140  0.7427                
Total               29 162.215                        
------------------------------------------------------------------------
CV = 9.35 %

------------------------------------------------------------------------
Teste de normalidade dos residuos (Shapiro-Wilk)
valor-p:  0.8347244 
De acordo com o teste de Shapiro-Wilk a 5% de significancia, os residuos podem ser considerados normais.
------------------------------------------------------------------------

Interacao nao significativa: analisando os efeitos simples
------------------------------------------------------------------------
Cultivar
Teste de Tukey
------------------------------------------------------------------------
Grupos Tratamentos Medias
a    CGH - 271   12.7 
 b   CGH - 298   9.166667 
 b   CGH - 227   8.916667 
 b   CGH - 328   8.666667 
  c      CGH - 323   6.616667 
------------------------------------------------------------------------

Tratamento
Teste de Tukey
------------------------------------------------------------------------
Grupos Tratamentos Medias
a    100ml   10.42 
 b   200ml   8.95 
 b   50ml    8.27 
------------------------------------------------------------------------

Gráfico

#
dados %>% ggplot() + geom_bar(aes(reorder(cult,-alt), alt, fill = trat),
                              stat = "identity",
                              position = "dodge") + theme_classic() +xlab("Cultivar") + ylab("Altura (cm)") + scale_fill_discrete(name="Tratamento")

sum_my_rise(dados, alt, cult, trat) %>% ggplot() +
  aes(x=trat, y=mean, fill=cult) +
  geom_bar(stat = "identity", position = "dodge") + 
  xlab('') + ylab('Média de Altura (cm)') +
  scale_fill_discrete(name="Cultivar")+
  geom_errorbar(aes(ymin  = mean - se,
                    ymax  = mean + se),
                width = 0.3,
                size  = 0.9,
                position = pd,
                color = "black")+
  theme(
    axis.text.x = element_text(
      angle = 45,
      hjust = 1,
      colour = "black")) +theme_classic()

ANOVA e Tukey N. de Folhas

with(dados,fat2.dic(cult,trat,nf, fac.names=c("Cultivar","Tratamento")))
------------------------------------------------------------------------
Legenda:
FATOR 1:  Cultivar 
FATOR 2:  Tratamento 
------------------------------------------------------------------------


Quadro da analise de variancia
------------------------------------------------------------------------
                    GL     SQ      QM     Fc   Pr>Fc
Cultivar             4 518.47 129.617 82.734 0.00000
Tratamento           2   4.07   2.033  1.298 0.30208
Cultivar*Tratamento  8  14.93   1.867  1.191 0.36598
Residuo             15  23.50   1.567               
Total               29 560.97                       
------------------------------------------------------------------------
CV = 11.34 %

------------------------------------------------------------------------
Teste de normalidade dos residuos (Shapiro-Wilk)
valor-p:  0.04977834 
ATENCAO: a 5% de significancia, os residuos nao podem ser considerados normais!
------------------------------------------------------------------------

Interacao nao significativa: analisando os efeitos simples
------------------------------------------------------------------------
Cultivar
Teste de Tukey
------------------------------------------------------------------------
Grupos Tratamentos Medias
a    CGH - 227   16.66667 
a    CGH - 271   15.5 
 b   CGH - 298   8.333333 
 b   CGH - 323   7.5 
 b   CGH - 328   7.166667 
------------------------------------------------------------------------

Tratamento
De acordo com o teste F, as medias desse fator sao estatisticamente iguais.
------------------------------------------------------------------------
  Niveis Medias
1  100ml   11.5
2  200ml   11.0
3   50ml   10.6
------------------------------------------------------------------------
# Gráficos
#
dados %>% ggplot() + geom_bar(aes(reorder(cult,-nf), nf, fill = trat),
                              stat = "identity",
                              position = "dodge") + theme_classic() +xlab("Cultivar") + ylab("Número de Folhas") + scale_fill_discrete(name="Tratamento")

sum_my_rise(dados, nf, cult, trat) %>% ggplot() +
  aes(x=trat, y=mean, fill=cult) +
  geom_bar(stat = "identity", position = "dodge") + 
  xlab('') + ylab('Média de N. de Folhas') +
  scale_fill_discrete(name="Cultivar")+
  geom_errorbar(aes(ymin  = mean - se,
                    ymax  = mean + se),
                width = 0.3,
                size  = 0.9,
                position = pd,
                color = "black")+
  theme(
    axis.text.x = element_text(
      angle = 45,
      hjust = 1,
      colour = "black")) +theme_classic()

Análise Multivariada

a<-aggregate(nf ~ cult + trat, dados, mean)
b<-aggregate(alt ~ cult + trat, dados, mean)
dados2 <- merge(a,b)
dados2$inter <- interaction(dados2$cult,dados2$trat)
rownames(dados2) <- dados2$inter
#levels(dados2$trat) <- c("50","100","200")

dados2 <- dados2[,c(3:4)] 

names(dados2) <- c("N. Folhas","Altura")

dados2 %>% kable
N. Folhas Altura
CGH - 227.100ml 15.5 9.75
CGH - 227.200ml 17.0 8.50
CGH - 227.50ml 17.5 8.50
CGH - 271.100ml 16.5 14.50
CGH - 271.200ml 15.5 12.75
CGH - 271.50ml 14.5 10.85
CGH - 298.100ml 9.0 9.25
CGH - 298.200ml 8.5 10.00
CGH - 298.50ml 7.5 8.25
CGH - 323.100ml 8.5 8.35
CGH - 323.200ml 6.5 5.50
CGH - 323.50ml 7.5 6.00
CGH - 328.100ml 8.0 10.25
CGH - 328.200ml 7.5 8.00
CGH - 328.50ml 6.0 7.75
#dados2$mL <- as.numeric(dados2$mL)

Dimensionamento e padronização

df <- scale(dados2) 

df %>% kable()
N. Folhas Altura
CGH - 227.100ml 1.0194990 0.2310403
CGH - 227.200ml 1.3618680 -0.3070971
CGH - 227.50ml 1.4759910 -0.3070971
CGH - 271.100ml 1.2477450 2.2759626
CGH - 271.200ml 1.0194990 1.5225702
CGH - 271.50ml 0.7912529 0.7046013
CGH - 298.100ml -0.4641003 0.0157854
CGH - 298.200ml -0.5782233 0.3386678
CGH - 298.50ml -0.8064693 -0.4147246
CGH - 323.100ml -0.5782233 -0.3716736
CGH - 323.200ml -1.0347154 -1.5986269
CGH - 323.50ml -0.8064693 -1.3833720
CGH - 328.100ml -0.6923463 0.4462953
CGH - 328.200ml -0.8064693 -0.5223521
CGH - 328.50ml -1.1488384 -0.6299796

Número ótimo de clusters

# Silhueta média para kmeans
fviz_nbclust(df, kmeans, method = "silhouette")

# Estatística de lacunas
fviz_nbclust(df, kmeans, method = "gap_stat")

# Método Elbow para kmeans
fviz_nbclust(df, kmeans, method = "wss") + geom_vline(xintercept = 6, linetype = 2)

nbclust_out <- NbClust(
  data = df,
  distance = "euclidean",
  min.nc = 2,
  max.nc = 8,
  method = "kmeans"
)

*** : The Hubert index is a graphical method of determining the number of clusters.
                In the plot of Hubert index, we seek a significant knee that corresponds to a 
                significant increase of the value of the measure i.e the significant peak in Hubert
                index second differences plot. 
 

*** : The D index is a graphical method of determining the number of clusters. 
                In the plot of D index, we seek a significant knee (the significant peak in Dindex
                second differences plot) that corresponds to a significant increase of the value of
                the measure. 
 
******************************************************************* 
* Among all indices:                                                
* 4 proposed 2 as the best number of clusters 
* 3 proposed 3 as the best number of clusters 
* 2 proposed 4 as the best number of clusters 
* 4 proposed 5 as the best number of clusters 
* 6 proposed 6 as the best number of clusters 
* 3 proposed 7 as the best number of clusters 
* 1 proposed 8 as the best number of clusters 

                   ***** Conclusion *****                            
 
* According to the majority rule, the best number of clusters is  6 
 
 
******************************************************************* 
nbclust_plot <- data.frame(clusters = nbclust_out$Best.nc[1, ])

nbclust_plot <- subset(nbclust_plot, clusters >= 2 & clusters <= 8)


ggplot(nbclust_plot) +
  aes(x = clusters) +
  geom_histogram(bins = 30L, fill = "#0c4c8a") +
  labs(x = "Number of clusters", y = "Frequency among all indices", title = "Optimal number of clusters") +
  theme_minimal()

Clusterização k-means

set.seed(123)
km.res=kmeans(df, 6, nstart=25)
print(km.res)
K-means clustering with 6 clusters of sizes 2, 2, 4, 3, 2, 2

Cluster means:
   N. Folhas     Altura
1 -0.9205924 -1.4909995
2  1.4189295 -0.3070971
3 -0.8350001 -0.4846825
4 -0.5782233  0.2669162
5  0.9053760  0.4678208
6  1.1336220  1.8992664

Clustering vector:
CGH - 227.100ml CGH - 227.200ml  CGH - 227.50ml CGH - 271.100ml CGH - 271.200ml 
              5               2               2               6               6 
 CGH - 271.50ml CGH - 298.100ml CGH - 298.200ml  CGH - 298.50ml CGH - 323.100ml 
              5               4               4               3               3 
CGH - 323.200ml  CGH - 323.50ml CGH - 328.100ml CGH - 328.200ml  CGH - 328.50ml 
              1               1               4               3               3 

Within cluster sum of squares by cluster:
[1] 0.049215479 0.006512032 0.206252166 0.126439986 0.138178111 0.309848191
 (between_SS / total_SS =  97.0 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
[6] "betweenss"    "size"         "iter"         "ifault"      

Criando novo banco de dados com cluster

aggregate(dados2, by=list(cluster=km.res$cluster), mean)
dd <- cbind(dados2, cluster = km.res$cluster)

km.res$cluster
CGH - 227.100ml CGH - 227.200ml  CGH - 227.50ml CGH - 271.100ml CGH - 271.200ml 
              5               2               2               6               6 
 CGH - 271.50ml CGH - 298.100ml CGH - 298.200ml  CGH - 298.50ml CGH - 323.100ml 
              5               4               4               3               3 
CGH - 323.200ml  CGH - 323.50ml CGH - 328.100ml CGH - 328.200ml  CGH - 328.50ml 
              1               1               4               3               3 
km.res$size
[1] 2 2 4 3 2 2
km.res$centers
   N. Folhas     Altura
1 -0.9205924 -1.4909995
2  1.4189295 -0.3070971
3 -0.8350001 -0.4846825
4 -0.5782233  0.2669162
5  0.9053760  0.4678208
6  1.1336220  1.8992664

Vizualizando os clusters

fviz_cluster(km.res, data=df,
             geom.ind = c("text"),
             ellipse.type="euclid",
             star.plot=TRUE,
             palette = "Dark2",
             repel=TRUE,
             ggtheme=theme_minimal()
)

Dendrograma

dista=dist(df, method="euclidean")
dista.hc=hclust(d=dista, method="ward.D")
fviz_dend(dista.hc, cex=0.5, k = 6, color_labels_by_k = TRUE, horiz = T)

res <- hcut(df, k = 6, stand = TRUE)
fviz_dend(res, rect = TRUE, cex = 0.5,
          k_colors = "Dark2", horiz = T)

km.res1 <- hkmeans(df, 6,hc.metric = "euclid" ,hc.method = "ward.D")


fviz_dend(km.res1, cex = 0.6, palette = "Dark2",
          rect = TRUE, rect_border = "Dark2", rect_fill = TRUE, horiz = T)

fviz_dist(dista, gradient = list(low = "#00AFBB", mid = "white", high = "#FC4E07"))

PCA

km.pca <- PCA(
  df,
  graph = F,
  scale.unit = TRUE)

eig.val <- get_eigenvalue(km.pca)

eig.val
      eigenvalue variance.percent cumulative.variance.percent
Dim.1  1.5904037         79.52018                    79.52018
Dim.2  0.4095963         20.47982                   100.00000
fviz_eig(km.pca, addlabels=TRUE)

var <- get_pca_var(km.pca)

var
Principal Component Analysis Results for variables
 ===================================================
  Name       Description                                    
1 "$coord"   "Coordinates for the variables"                
2 "$cor"     "Correlations between variables and dimensions"
3 "$cos2"    "Cos2 for the variables"                       
4 "$contrib" "contributions of the variables"               
$coord

$cor

$cos2

$contrib

Coordinates for the variables

Correlations between variables and dimensions

Cos2 for the variables

contributions of the variables
#  Coordenadas
head(var$coord)
              Dim.1      Dim.2
N. Folhas 0.8917409 -0.4525463
Altura    0.8917409  0.4525463
# Cos2: qualidade no mapa do fator
head(var$cos2)
              Dim.1     Dim.2
N. Folhas 0.7952018 0.2047982
Altura    0.7952018 0.2047982
# Contribuições para os componentes principais
head(var$contrib)
          Dim.1 Dim.2
N. Folhas    50    50
Altura       50    50
fviz_cos2(km.pca, choice = "var", axes = 1:2)

df %>% cor(method = "spearman") %>% corrplot(.,
                                             method = "number",
                                             type = "upper",
                                             tl.pos = "td")

summary(km.pca)

Call:
PCA(X = df, scale.unit = TRUE, graph = F) 


Eigenvalues
                      Dim.1  Dim.2
Variance               1.59   0.41
% of var.             79.52  20.48
Cumulative % of var.  79.52 100.00

Individuals (the 10 first)
                    Dist    Dim.1    ctr   cos2    Dim.2    ctr   cos2  
CGH - 227.100ml |  1.082 |  0.915  3.512  0.716 | -0.577  5.421  0.284 |
CGH - 227.200ml |  1.445 |  0.772  2.498  0.285 | -1.222 24.287  0.715 |
CGH - 227.50ml  |  1.561 |  0.856  3.068  0.301 | -1.305 27.722  0.699 |
CGH - 271.100ml |  2.687 |  2.579 27.883  0.922 |  0.753  9.218  0.078 |
CGH - 271.200ml |  1.897 |  1.861 14.511  0.962 |  0.368  2.207  0.038 |
CGH - 271.50ml  |  1.097 |  1.095  5.025  0.997 | -0.063  0.065  0.003 |
CGH - 298.100ml |  0.481 | -0.328  0.451  0.466 |  0.351  2.008  0.534 |
CGH - 298.200ml |  0.694 | -0.175  0.129  0.064 |  0.671  7.330  0.936 |
CGH - 298.50ml  |  0.939 | -0.894  3.349  0.907 |  0.287  1.338  0.093 |
CGH - 323.100ml |  0.712 | -0.695  2.026  0.955 |  0.151  0.372  0.045 |

Variables
                   Dim.1    ctr   cos2    Dim.2    ctr   cos2  
N. Folhas       |  0.892 50.000  0.795 | -0.453 50.000  0.205 |
Altura          |  0.892 50.000  0.795 |  0.453 50.000  0.205 |
# Contribuições de variáveis para PC1
fviz_contrib(km.pca, choice = "var", axes = 1, top = 10)

# Contribuições de variáveis para PC2
fviz_contrib(km.pca, choice = "var", axes = 2, top = 10)

# contribuição total para PC1 e PC2 

fviz_contrib(km.pca, choice = "var", axes = 1:2)

fviz_pca_biplot(
  km.pca,
  geom.ind = "text",
  col.var = "contrib",
  gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
  legend.title = "Contribuição",
  palette = "Dark2",
  repel = F
)

fviz_pca_ind(
  km.pca,
  geom = "text",
  habillage = as.factor(dd$cluster),
  addEllipses = TRUE,
  palette = "Dark2"
)

fviz_pca_ind(km.pca,
             geom.ind = "text",
             col.ind = as.factor(dd$cluster),
             addEllipses = TRUE, 
             legend.title = "Grupos",
             repel = T,
             palette = "Dark2"
)

df %>% pairs.panels(., 
                    show.points=TRUE, 
                    method = "spearman",
                    gap=0, 
                    stars=TRUE,
                    ci=FALSE,
                    alpha=0.05,
                    cex.cor=1,
                    cex=1.0,
                    breaks="Sturges",
                    rug=FALSE,
                    density=F,
                    hist.col="darkgreen",
                    factor=5,
                    digits=2,
                    ellipses=FALSE,
                    scale=FALSE,
                    smooth=TRUE,
                    lm=T,
                    cor=T
) 

ind <- get_pca_ind(km.pca)
ind
Principal Component Analysis Results for individuals
 ===================================================
  Name       Description                       
1 "$coord"   "Coordinates for the individuals" 
2 "$cos2"    "Cos2 for the individuals"        
3 "$contrib" "contributions of the individuals"
$coord

$cos2

$contrib

Coordinates for the individuals

Cos2 for the individuals

contributions of the individuals
# Coordenadas de indivíduos
head(ind$coord)
                    Dim.1       Dim.2
CGH - 227.100ml 0.9153011 -0.57709263
CGH - 227.200ml 0.7720133 -1.22155739
CGH - 227.50ml  0.8555428 -1.30508689
CGH - 271.100ml 2.5790899  0.75257822
CGH - 271.200ml 1.8606041  0.36821043
CGH - 271.50ml  1.0948532 -0.06342251
# Qualidade dos indivíduos
head(ind$cos2)
                    Dim.1       Dim.2
CGH - 227.100ml 0.7155513 0.284448676
CGH - 227.200ml 0.2854145 0.714585525
CGH - 227.50ml  0.3005716 0.699428441
CGH - 271.100ml 0.9215340 0.078466030
CGH - 271.200ml 0.9623122 0.037687752
CGH - 271.50ml  0.9966556 0.003344415
# Contribuições de indivíduos
head(ind$contrib)
                    Dim.1       Dim.2
CGH - 227.100ml  3.511796  5.42055506
CGH - 227.200ml  2.498336 24.28736839
CGH - 227.50ml   3.068208 27.72244699
CGH - 271.100ml 27.882668  9.21840950
CGH - 271.200ml 14.511400  2.20670805
CGH - 271.50ml   5.024735  0.06546959
fviz_pca_ind(km.pca, col.ind = "cos2", 
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE
)

fviz_contrib(km.pca, choice = "ind", axes = 1:2)

set.seed(123)
my.cont.var <- rnorm(15)

fviz_pca_ind(km.pca, col.ind = my.cont.var,
             gradient.cols = c("blue", "yellow", "red"),
             legend.title = "Cont.Var")

fviz_pca_ind(km.pca,
             geom.ind = "point",
             col.ind = as.factor(dd$cluster),
             palette = "Dark2",
             addEllipses = TRUE, 
             legend.title = "Grupos"
)

fviz_pca_biplot(km.pca, 
                geom.ind = c("point","text"),
                fill.ind = as.factor(dd$cluster), col.ind = "black",
                pointshape = 21, 
                pointsize = 2,
                palette = "jco",
                repel = T,
                addEllipses = TRUE,
                alpha.var ="contrib", 
                col.var = "contrib",
                gradient.cols = "Dark2",
                legend.title = list(fill = "Cluster",
                                    color = "Contrib",
                                    alpha = "Contrib")
)

Outro teste

library(tidyverse)
library(ggpubr)
library(rstatix)

pd = position_dodge(1)


dados %>% sample_n_by(cult,trat, size = 1)
dados %>%
  group_by(cult,trat) %>%
  get_summary_stats(alt,nf, type = "mean_sd")
bxp <- ggboxplot(
  dados, x = "cult", y = "alt",
  color = "trat", palette = "jco", ylab = "Altura", xlab= "Cultura",
)

ggpar(bxp,
      legend = "right", legend.title = "Tratamento") 

dados %>%
  group_by(cult) %>%
  shapiro_test(alt)
dados %>% 
  group_by(cult) %>%
  identify_outliers(alt)
dados %>% 
  group_by(cult) %>%
  identify_outliers(nf)
# Build the linear model
model  <- lm(alt ~ cult, data = dados)
# Create a QQ plot of residuals
ggqqplot(residuals(model))

# Build the linear model
model  <- lm(nf ~ cult, data = dados)
# Create a QQ plot of residuals
ggqqplot(residuals(model))

dados %>%
  group_by(cult) %>%
  shapiro_test(alt)
dados %>%
  group_by(cult) %>%
  shapiro_test(nf)
ggqqplot(dados, "alt", facet.by = "cult")

ggqqplot(dados, "nf", facet.by = "cult")

plot(model, 1)

dados %>% levene_test(alt ~ cult)
dados %>% levene_test(nf ~ cult)
res.aov <- dados %>% anova_test(alt ~ cult * trat)
res.aov
model <- lm(alt ~ cult * trat, data = dados)

dados %>%
  group_by(cult) %>%
  anova_test(alt ~ trat, error = model)
library(emmeans)
pwc <- dados %>% 
  group_by(cult) %>%
  emmeans_test(alt ~ trat, p.adjust.method = "bonferroni") 
pwc
res.aov
dados %>%
  pairwise_t_test(
    alt ~ cult, 
    p.adjust.method = "bonferroni"
  )
model <- lm(alt ~ cult * trat, data = dados)

dados %>% 
  emmeans_test(
    alt ~ cult, p.adjust.method = "bonferroni",
    model = model
  )
pwc <- pwc %>% add_xy_position(x = "cult")

ggpar(bxp,
      legend = "right", legend.title = "Tratamento") +
  stat_pvalue_manual(pwc) +
  labs(
    subtitle = get_test_label(res.aov, detailed = TRUE),
    caption = get_pwc_label(pwc)
  ) + theme(legend.position = "right")

Referência

Os procedimentos estatísticos utilizados neste estudo foram realizados no programa R (R Core Team 2020). Pacotes stats (R Core Team 2020). Pacote dyplr, para manipulação de dados, (Wickham et al. 2020). Pacote ggpot2: elementos gráficos (Wickham 2016), Para análise multivariada foram utilizados os pacotes factoextra, (Kassambara and Mundt 2020), FactorMiner, (Lê, Josse, and Husson 2008), vegan (Oksanen et al. 2019), corrplot (Wei and Simko 2017), NbClust (Charrad et al. 2014), e para ANAVA e Teste de Tukey foi utilizado o ExpDes.pt (Ferreira, Cavalcanti, and Nogueira 2018)

Charrad, Malika, Nadia Ghazzali, Véronique Boiteau, and Azam Niknafs. 2014. “NbClust: An R Package for Determining the Relevant Number of Clusters in a Data Set.” Journal of Statistical Software 61 (6): 1–36. http://www.jstatsoft.org/v61/i06/.

Ferreira, Eric Batista, Portya Piscitelli Cavalcanti, and Denismar Alves Nogueira. 2018. ExpDes.pt: Pacote Experimental Designs (Portuguese). https://CRAN.R-project.org/package=ExpDes.pt.

Kassambara, Alboukadel, and Fabian Mundt. 2020. Factoextra: Extract and Visualize the Results of Multivariate Data Analyses. https://CRAN.R-project.org/package=factoextra.

Lê, Sébastien, Julie Josse, and François Husson. 2008. “FactoMineR: A Package for Multivariate Analysis.” Journal of Statistical Software 25 (1): 1–18. https://doi.org/10.18637/jss.v025.i01.

Oksanen, Jari, F. Guillaume Blanchet, Michael Friendly, Roeland Kindt, Pierre Legendre, Dan McGlinn, Peter R. Minchin, et al. 2019. Vegan: Community Ecology Package. https://CRAN.R-project.org/package=vegan.

R Core Team. 2020. “R: A Language and Environment for Statistical Computing.” https://www.R-project.org/.

Wei, Taiyun, and Viliam Simko. 2017. R Package "Corrplot": Visualization of a Correlation Matrix. https://github.com/taiyun/corrplot.

Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.

Wickham, Hadley, Romain François, Lionel Henry, and Kirill Müller. 2020. Dplyr: A Grammar of Data Manipulation. https://CRAN.R-project.org/package=dplyr.

IycgLS0tDQojJyB0aXRsZTogIkV4cGVyaW1lbnRvIGRlIFJvYmVydG8gQm9uaW5hIg0KIycgYXV0aG9yOiBDaWQgRWRzb24gUMOzdm9hcw0KIycgYmlibGlvZ3JhcGh5OiBScGFja2FnZXMuYmliDQojJyBvdXRwdXQ6DQojJyAgIGh0bWxfbm90ZWJvb2s6IA0KIycgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KIycgICAgIHRvYzogdHJ1ZQ0KIycgICAgIHRvY19mbG9hdDogdHJ1ZQ0KIycgICAgIGNvbGxhcHNlZDogZmFsc2UNCiMnIC0tLQ0KIysgd2FybmluZz1GQUxTRSwgZWNobz1ULCBtZXNzYWdlPUZBTFNFDQojKyBzZXR1cCwgaW5jbHVkZT1GLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeSh2ZWdhbikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShwc3ljaCkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShOYkNsdXN0KQ0KbGlicmFyeShFeHBEZXMucHQpDQoNCg0KZ2diaXBsb3QyPWZ1bmN0aW9uKHBjb2JqLCBjaG9pY2VzID0gMToyLCBzY2FsZSA9IDEsIHBjLmJpcGxvdCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgIG9icy5zY2FsZSA9IDEgLSBzY2FsZSwgdmFyLnNjYWxlID0gc2NhbGUsIA0KICAgICAgICAgICAgICAgICAgIGdydXBvcyA9IE5VTEwsIGVsbGlwc2UgPSBGQUxTRSwgZWxsaXBzZS5wcm9iID0gMC42OCwgDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gTlVMTCwgbGFiZWxzLnNpemUgPSAzLCBhbHBoYSA9IDEsIA0KICAgICAgICAgICAgICAgICAgIHZhci5heGVzID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgY2lyY2xlID0gRkFMU0UsIGNpcmNsZS5wcm9iID0gMC42OSwgDQogICAgICAgICAgICAgICAgICAgdmFybmFtZS5zaXplID0gMywgdmFybmFtZS5hZGp1c3QgPSAxLjUsIA0KICAgICAgICAgICAgICAgICAgIHZhcm5hbWUuYWJicmV2ID0gRkFMU0UsIC4uLikNCnsNCiAgbGlicmFyeShnZ3Bsb3QyKQ0KICBsaWJyYXJ5KHBseXIpDQogIGxpYnJhcnkoc2NhbGVzKQ0KICBsaWJyYXJ5KGdyaWQpDQogIA0KICBzdG9waWZub3QobGVuZ3RoKGNob2ljZXMpID09IDIpDQogIA0KICAjIFJlY292ZXIgdGhlIFNWRA0KICBpZihpbmhlcml0cyhwY29iaiwgJ3ByY29tcCcpKXsNCiAgICBub2JzLmZhY3RvciA8LSBzcXJ0KG5yb3cocGNvYmokeCkgLSAxKQ0KICAgIGQgPC0gcGNvYmokc2Rldg0KICAgIHUgPC0gc3dlZXAocGNvYmokeCwgMiwgMSAvIChkICogbm9icy5mYWN0b3IpLCBGVU4gPSAnKicpDQogICAgdiA8LSBwY29iaiRyb3RhdGlvbg0KICB9IGVsc2UgaWYoaW5oZXJpdHMocGNvYmosICdwcmluY29tcCcpKSB7DQogICAgbm9icy5mYWN0b3IgPC0gc3FydChwY29iaiRuLm9icykNCiAgICBkIDwtIHBjb2JqJHNkZXYNCiAgICB1IDwtIHN3ZWVwKHBjb2JqJHNjb3JlcywgMiwgMSAvIChkICogbm9icy5mYWN0b3IpLCBGVU4gPSAnKicpDQogICAgdiA8LSBwY29iaiRsb2FkaW5ncw0KICB9IGVsc2UgaWYoaW5oZXJpdHMocGNvYmosICdQQ0EnKSkgew0KICAgIG5vYnMuZmFjdG9yIDwtIHNxcnQobnJvdyhwY29iaiRjYWxsJFgpKQ0KICAgIGQgPC0gdW5saXN0KHNxcnQocGNvYmokZWlnKVsxXSkNCiAgICB1IDwtIHN3ZWVwKHBjb2JqJGluZCRjb29yZCwgMiwgMSAvIChkICogbm9icy5mYWN0b3IpLCBGVU4gPSAnKicpDQogICAgdiA8LSBzd2VlcChwY29iaiR2YXIkY29vcmQsMixzcXJ0KHBjb2JqJGVpZ1sxOm5jb2wocGNvYmokdmFyJGNvb3JkKSwxXSksRlVOPSIvIikNCiAgfSBlbHNlIHsNCiAgICBzdG9wKCdFeHBlY3RlZCBhIG9iamVjdCBvZiBjbGFzcyBwcmNvbXAsIHByaW5jb21wIG9yIFBDQScpDQogIH0NCiAgDQogICMgU2NvcmVzDQogIGRmLnUgPC0gYXMuZGF0YS5mcmFtZShzd2VlcCh1WyxjaG9pY2VzXSwgMiwgZFtjaG9pY2VzXV5vYnMuc2NhbGUsIEZVTj0nKicpKQ0KICANCiAgIyBEaXJlY3Rpb25zDQogIHYgPC0gc3dlZXAodiwgMiwgZF52YXIuc2NhbGUsIEZVTj0nKicpDQogIGRmLnYgPC0gYXMuZGF0YS5mcmFtZSh2WywgY2hvaWNlc10pDQogIA0KICBuYW1lcyhkZi51KSA8LSBjKCd4dmFyJywgJ3l2YXInKQ0KICBuYW1lcyhkZi52KSA8LSBuYW1lcyhkZi51KQ0KICANCiAgaWYocGMuYmlwbG90KSB7DQogICAgZGYudSA8LSBkZi51ICogbm9icy5mYWN0b3INCiAgfQ0KICANCiAgIyBTY2FsZSB0aGUgcmFkaXVzIG9mIHRoZSBjb3JyZWxhdGlvbiBjaXJjbGUgc28gdGhhdCBpdCBjb3JyZXNwb25kcyB0byANCiAgIyBhIGRhdGEgZWxsaXBzZSBmb3IgdGhlIHN0YW5kYXJkaXplZCBQQyBzY29yZXMNCiAgciA8LSAxDQogIA0KICAjIFNjYWxlIGRpcmVjdGlvbnMNCiAgdi5zY2FsZSA8LSByb3dTdW1zKHZeMikNCiAgZGYudiA8LSBkZi52IC8gc3FydChtYXgodi5zY2FsZSkpDQogIA0KICAjIyBTY2FsZSBTY29yZXMNCiAgci5zY2FsZT1zcXJ0KG1heChkZi51WywxXV4yK2RmLnVbLDJdXjIpKQ0KICBkZi51PS45OSpkZi51L3Iuc2NhbGUNCiAgDQogICMgQ2hhbmdlIHRoZSBsYWJlbHMgZm9yIHRoZSBheGVzDQogIGlmKG9icy5zY2FsZSA9PSAwKSB7DQogICAgdS5heGlzLmxhYnMgPC0gcGFzdGUoJ3N0YW5kYXJkaXplZCBQQycsIGNob2ljZXMsIHNlcD0nJykNCiAgfSBlbHNlIHsNCiAgICB1LmF4aXMubGFicyA8LSBwYXN0ZSgnQ29tcG9uZW50ZSBQcmluY2lwYWwgJywgY2hvaWNlcywgc2VwPScnKQ0KICB9DQogIA0KICAjIEFwcGVuZCB0aGUgcHJvcG9ydGlvbiBvZiBleHBsYWluZWQgdmFyaWFuY2UgdG8gdGhlIGF4aXMgbGFiZWxzDQogIHUuYXhpcy5sYWJzIDwtIHBhc3RlKHUuYXhpcy5sYWJzLCANCiAgICAgICAgICAgICAgICAgICAgICAgc3ByaW50ZignKCUwLjFmJSUpJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwICogcGNvYmokc2RldltjaG9pY2VzXV4yL3N1bShwY29iaiRzZGV2XjIpKSkNCiAgDQogICMgU2NvcmUgTGFiZWxzDQogIGlmKCFpcy5udWxsKGxhYmVscykpIHsNCiAgICBkZi51JGxhYmVscyA8LSBsYWJlbHMNCiAgfQ0KICANCiAgIyBHcm91cGluZyB2YXJpYWJsZQ0KICBpZighaXMubnVsbChncnVwb3MpKSB7DQogICAgZGYudSRncnVwb3MgPC0gZ3J1cG9zDQogIH0NCiAgDQogICMgVmFyaWFibGUgTmFtZXMNCiAgaWYodmFybmFtZS5hYmJyZXYpIHsNCiAgICBkZi52JHZhcm5hbWUgPC0gYWJicmV2aWF0ZShyb3duYW1lcyh2KSkNCiAgfSBlbHNlIHsNCiAgICBkZi52JHZhcm5hbWUgPC0gcm93bmFtZXModikNCiAgfQ0KICANCiAgIyBWYXJpYWJsZXMgZm9yIHRleHQgbGFiZWwgcGxhY2VtZW50DQogIGRmLnYkYW5nbGUgPC0gd2l0aChkZi52LCAoMTgwL3BpKSAqIGF0YW4oeXZhciAvIHh2YXIpKQ0KICBkZi52JGhqdXN0ID0gd2l0aChkZi52LCAoMSAtIHZhcm5hbWUuYWRqdXN0ICogc2lnbih4dmFyKSkgLyAyKQ0KICANCiAgIyBCYXNlIHBsb3QNCiAgZyA8LSBnZ3Bsb3QoZGF0YSA9IGRmLnUsIGFlcyh4ID0geHZhciwgeSA9IHl2YXIpKSArIA0KICAgIHhsYWIodS5heGlzLmxhYnNbMV0pICsgeWxhYih1LmF4aXMubGFic1syXSkgKyBjb29yZF9lcXVhbCgpDQogIA0KICBpZih2YXIuYXhlcykgew0KICAgICMgRHJhdyBjaXJjbGUNCiAgICBpZihjaXJjbGUpIA0KICAgIHsNCiAgICAgIHRoZXRhIDwtIGMoc2VxKC1waSwgcGksIGxlbmd0aCA9IDUwKSwgc2VxKHBpLCAtcGksIGxlbmd0aCA9IDUwKSkNCiAgICAgIGNpcmNsZSA8LSBkYXRhLmZyYW1lKHh2YXIgPSByICogY29zKHRoZXRhKSwgeXZhciA9IHIgKiBzaW4odGhldGEpKQ0KICAgICAgZyA8LSBnICsgZ2VvbV9wYXRoKGRhdGEgPSBjaXJjbGUsIGNvbG9yID0gbXV0ZWQoJ3doaXRlJyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLzIsIGFscGhhID0gMS8zKQ0KICAgIH0NCiAgICANCiAgICAjIERyYXcgZGlyZWN0aW9ucw0KICAgIGcgPC0gZyArDQogICAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IGRmLnYsDQogICAgICAgICAgICAgICAgICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IHh2YXIsIHllbmQgPSB5dmFyKSwNCiAgICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMS8yLCAncGljYXMnKSksIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gbXV0ZWQoJ3JlZCcpKQ0KICB9DQogIA0KICAjIERyYXcgZWl0aGVyIGxhYmVscyBvciBwb2ludHMNCiAgaWYoIWlzLm51bGwoZGYudSRsYWJlbHMpKSB7DQogICAgaWYoIWlzLm51bGwoZGYudSRncnVwb3MpKSB7DQogICAgICBnIDwtIGcgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gbGFiZWxzLCBjb2xvciA9IGdydXBvcyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBsYWJlbHMuc2l6ZSkNCiAgICB9IGVsc2Ugew0KICAgICAgZyA8LSBnICsgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVscyksIHNpemUgPSBsYWJlbHMuc2l6ZSkgICAgICANCiAgICB9DQogIH0gZWxzZSB7DQogICAgaWYoIWlzLm51bGwoZGYudSRncnVwb3MpKSB7DQogICAgICBnIDwtIGcgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGdydXBvcyksIGFscGhhID0gYWxwaGEpDQogICAgfSBlbHNlIHsNCiAgICAgIGcgPC0gZyArIGdlb21fcG9pbnQoYWxwaGEgPSBhbHBoYSkgICAgICANCiAgICB9DQogIH0NCiAgDQogICMgT3ZlcmxheSBhIGNvbmNlbnRyYXRpb24gZWxsaXBzZSBpZiB0aGVyZSBhcmUgZ3J1cG9zDQogIGlmKCFpcy5udWxsKGRmLnUkZ3J1cG9zKSAmJiBlbGxpcHNlKSB7DQogICAgdGhldGEgPC0gYyhzZXEoLXBpLCBwaSwgbGVuZ3RoID0gNTApLCBzZXEocGksIC1waSwgbGVuZ3RoID0gNTApKQ0KICAgIGNpcmNsZSA8LSBjYmluZChjb3ModGhldGEpLCBzaW4odGhldGEpKQ0KICAgIA0KICAgIGVsbCA8LSBkZHBseShkZi51LCAnZ3J1cG9zJywgZnVuY3Rpb24oeCkgew0KICAgICAgaWYobnJvdyh4KSA8IDIpIHsNCiAgICAgICAgcmV0dXJuKE5VTEwpDQogICAgICB9IGVsc2UgaWYobnJvdyh4KSA9PSAyKSB7DQogICAgICAgIHNpZ21hIDwtIHZhcihjYmluZCh4JHh2YXIsIHgkeXZhcikpDQogICAgICB9IGVsc2Ugew0KICAgICAgICBzaWdtYSA8LSBkaWFnKGModmFyKHgkeHZhciksIHZhcih4JHl2YXIpKSkNCiAgICAgIH0NCiAgICAgIG11IDwtIGMobWVhbih4JHh2YXIpLCBtZWFuKHgkeXZhcikpDQogICAgICBlZCA8LSBzcXJ0KHFjaGlzcShlbGxpcHNlLnByb2IsIGRmID0gMikpDQogICAgICBkYXRhLmZyYW1lKHN3ZWVwKGNpcmNsZSAlKiUgY2hvbChzaWdtYSkgKiBlZCwgMiwgbXUsIEZVTiA9ICcrJyksIA0KICAgICAgICAgICAgICAgICBncnVwb3MgPSB4JGdydXBvc1sxXSkNCiAgICB9KQ0KICAgIG5hbWVzKGVsbClbMToyXSA8LSBjKCd4dmFyJywgJ3l2YXInKQ0KICAgIGcgPC0gZyArIGdlb21fcGF0aChkYXRhID0gZWxsLCBhZXMoY29sb3IgPSBncnVwb3MsIGdyb3VwID0gZ3J1cG9zKSkNCiAgfQ0KICANCiAgIyBMYWJlbCB0aGUgdmFyaWFibGUgYXhlcw0KICBpZih2YXIuYXhlcykgew0KICAgIGcgPC0gZyArIA0KICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBkZi52LCANCiAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSB2YXJuYW1lLCB4ID0geHZhciwgeSA9IHl2YXIsIA0KICAgICAgICAgICAgICAgICAgICBhbmdsZSA9IGFuZ2xlLCBoanVzdCA9IGhqdXN0KSwgDQogICAgICAgICAgICAgICAgY29sb3IgPSAnZGFya3JlZCcsIHNpemUgPSB2YXJuYW1lLnNpemUpDQogIH0NCiAgIyBDaGFuZ2UgdGhlIG5hbWUgb2YgdGhlIGxlZ2VuZCBmb3IgZ3J1cG9zDQogICMgaWYoIWlzLm51bGwoZ3J1cG9zKSkgew0KICAjICAgZyA8LSBnICsgc2NhbGVfY29sb3JfYnJld2VyKG5hbWUgPSBkZXBhcnNlKHN1YnN0aXR1dGUoZ3J1cG9zKSksIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAnRGFyazInKQ0KICAjIH0NCiAgDQogICMgVE9ETzogQWRkIGEgc2Vjb25kIHNldCBvZiBheGVzDQogIA0KICByZXR1cm4oZykNCn0NCg0Kc3VtX215X3Jpc2UgPC0gZnVuY3Rpb24oeCwgbnVtX3ZhciwgLi4uKXsNCiAgZ3JvdXBfdmFyIDwtIHF1b3MoLi4uKQ0KICBudW1fdmFyIDwtIGVucXVvKG51bV92YXIpDQogIHggJT4lDQogICAgZ3JvdXBfYnkoISEhZ3JvdXBfdmFyKSAlPiUNCiAgICBzdW1tYXJpemUobWVhbiA9IG1lYW4oISFudW1fdmFyKSwgbiA9IG4oKSwgDQogICAgICAgICAgICAgIG1pbiA9IG1pbighIW51bV92YXIpLA0KICAgICAgICAgICAgICBtYXggPSBtYXgoISFudW1fdmFyKSwNCiAgICAgICAgICAgICAgc2QgPSBzZCghIW51bV92YXIpLCBzZSA9IHNkL3NxcnQobiksDQogICAgICAgICAgICAgIHN1bSA9IHN1bSghIW51bV92YXIpKQ0KfQ0KDQpwZCA9IHBvc2l0aW9uX2RvZGdlKDEpDQoNCiMnICMjIENhcnJlZ2FtZW50byBkb3MgZGFkb3MNCiMrIGVjaG89VCwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRQ0KDQpkYWRvcyA8LSByZWFkX2V4Y2VsKCJkYWRvcy54bHN4Iiwgc2hlZXQgPSAiZGFkb3MiKQ0KZGFkb3MkdHJhdCA8LSBhcy5mYWN0b3IoZGFkb3MkdHJhdCkNCmxldmVscyhkYWRvcyR0cmF0KSA8LSBjKCI1MG1sIiwiMTAwbWwiLCIyMDBtbCIpDQoNCg0KIycgIyMgQU5PVkEgZSBUdWtleSBwYXJhIEFsdHVyYQ0KIycgDQojKyBlY2hvPVQsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UNCg0Kd2l0aChkYWRvcyxmYXQyLmRpYyhjdWx0LHRyYXQsYWx0LCBmYWMubmFtZXM9YygiQ3VsdGl2YXIiLCJUcmF0YW1lbnRvIikpKQ0KDQojJyBHcsOhZmljbw0KIw0KIysgZWNobz1ULCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFDQoNCmRhZG9zICU+JSBnZ3Bsb3QoKSArIGdlb21fYmFyKGFlcyhyZW9yZGVyKGN1bHQsLWFsdCksIGFsdCwgZmlsbCA9IHRyYXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICJpZGVudGl0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIpICsgdGhlbWVfY2xhc3NpYygpICt4bGFiKCJDdWx0aXZhciIpICsgeWxhYigiQWx0dXJhIChjbSkiKSArIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iVHJhdGFtZW50byIpDQoNCg0KDQpzdW1fbXlfcmlzZShkYWRvcywgYWx0LCBjdWx0LCB0cmF0KSAlPiUgZ2dwbG90KCkgKw0KICBhZXMoeD10cmF0LCB5PW1lYW4sIGZpbGw9Y3VsdCkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArIA0KICB4bGFiKCcnKSArIHlsYWIoJ03DqWRpYSBkZSBBbHR1cmEgKGNtKScpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSJDdWx0aXZhciIpKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluICA9IG1lYW4gLSBzZSwNCiAgICAgICAgICAgICAgICAgICAgeW1heCAgPSBtZWFuICsgc2UpLA0KICAgICAgICAgICAgICAgIHdpZHRoID0gMC4zLA0KICAgICAgICAgICAgICAgIHNpemUgID0gMC45LA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcGQsDQogICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoDQogICAgICBhbmdsZSA9IDQ1LA0KICAgICAgaGp1c3QgPSAxLA0KICAgICAgY29sb3VyID0gImJsYWNrIikpICt0aGVtZV9jbGFzc2ljKCkNCiMnICMjIEFOT1ZBIGUgVHVrZXkgTi4gZGUgRm9saGFzDQojJyANCiMrIGVjaG89VCwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRQ0KDQp3aXRoKGRhZG9zLGZhdDIuZGljKGN1bHQsdHJhdCxuZiwgZmFjLm5hbWVzPWMoIkN1bHRpdmFyIiwiVHJhdGFtZW50byIpKSkNCg0KDQojIEdyw6FmaWNvcw0KIw0KZGFkb3MgJT4lIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKHJlb3JkZXIoY3VsdCwtbmYpLCBuZiwgZmlsbCA9IHRyYXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICJpZGVudGl0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIpICsgdGhlbWVfY2xhc3NpYygpICt4bGFiKCJDdWx0aXZhciIpICsgeWxhYigiTsO6bWVybyBkZSBGb2xoYXMiKSArIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iVHJhdGFtZW50byIpDQoNCg0Kc3VtX215X3Jpc2UoZGFkb3MsIG5mLCBjdWx0LCB0cmF0KSAlPiUgZ2dwbG90KCkgKw0KICBhZXMoeD10cmF0LCB5PW1lYW4sIGZpbGw9Y3VsdCkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArIA0KICB4bGFiKCcnKSArIHlsYWIoJ03DqWRpYSBkZSBOLiBkZSBGb2xoYXMnKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iQ3VsdGl2YXIiKSsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiAgPSBtZWFuIC0gc2UsDQogICAgICAgICAgICAgICAgICAgIHltYXggID0gbWVhbiArIHNlKSwNCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMywNCiAgICAgICAgICAgICAgICBzaXplICA9IDAuOSwNCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBkLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikrDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KA0KICAgICAgYW5nbGUgPSA0NSwNCiAgICAgIGhqdXN0ID0gMSwNCiAgICAgIGNvbG91ciA9ICJibGFjayIpKSArdGhlbWVfY2xhc3NpYygpDQoNCiMnICMjIEFuw6FsaXNlIE11bHRpdmFyaWFkYQ0KDQphPC1hZ2dyZWdhdGUobmYgfiBjdWx0ICsgdHJhdCwgZGFkb3MsIG1lYW4pDQpiPC1hZ2dyZWdhdGUoYWx0IH4gY3VsdCArIHRyYXQsIGRhZG9zLCBtZWFuKQ0KZGFkb3MyIDwtIG1lcmdlKGEsYikNCmRhZG9zMiRpbnRlciA8LSBpbnRlcmFjdGlvbihkYWRvczIkY3VsdCxkYWRvczIkdHJhdCkNCnJvd25hbWVzKGRhZG9zMikgPC0gZGFkb3MyJGludGVyDQojbGV2ZWxzKGRhZG9zMiR0cmF0KSA8LSBjKCI1MCIsIjEwMCIsIjIwMCIpDQoNCmRhZG9zMiA8LSBkYWRvczJbLGMoMzo0KV0gDQoNCm5hbWVzKGRhZG9zMikgPC0gYygiTi4gRm9saGFzIiwiQWx0dXJhIikNCg0KZGFkb3MyICU+JSBrYWJsZQ0KI2RhZG9zMiRtTCA8LSBhcy5udW1lcmljKGRhZG9zMiRtTCkNCiMnIERpbWVuc2lvbmFtZW50byBlIHBhZHJvbml6YcOnw6NvDQojKyBlY2hvPVQsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UNCg0KZGYgPC0gc2NhbGUoZGFkb3MyKSANCg0KZGYgJT4lIGthYmxlKCkNCg0KDQojJyBOw7ptZXJvIMOzdGltbyBkZSBjbHVzdGVycw0KIysgZWNobz1ULCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFDQoNCiMgU2lsaHVldGEgbcOpZGlhIHBhcmEga21lYW5zDQpmdml6X25iY2x1c3QoZGYsIGttZWFucywgbWV0aG9kID0gInNpbGhvdWV0dGUiKQ0KDQojIEVzdGF0w61zdGljYSBkZSBsYWN1bmFzDQpmdml6X25iY2x1c3QoZGYsIGttZWFucywgbWV0aG9kID0gImdhcF9zdGF0IikNCg0KIyBNw6l0b2RvIEVsYm93IHBhcmEga21lYW5zDQpmdml6X25iY2x1c3QoZGYsIGttZWFucywgbWV0aG9kID0gIndzcyIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNiwgbGluZXR5cGUgPSAyKQ0KDQpuYmNsdXN0X291dCA8LSBOYkNsdXN0KA0KICBkYXRhID0gZGYsDQogIGRpc3RhbmNlID0gImV1Y2xpZGVhbiIsDQogIG1pbi5uYyA9IDIsDQogIG1heC5uYyA9IDgsDQogIG1ldGhvZCA9ICJrbWVhbnMiDQopDQoNCm5iY2x1c3RfcGxvdCA8LSBkYXRhLmZyYW1lKGNsdXN0ZXJzID0gbmJjbHVzdF9vdXQkQmVzdC5uY1sxLCBdKQ0KDQpuYmNsdXN0X3Bsb3QgPC0gc3Vic2V0KG5iY2x1c3RfcGxvdCwgY2x1c3RlcnMgPj0gMiAmIGNsdXN0ZXJzIDw9IDgpDQoNCg0KZ2dwbG90KG5iY2x1c3RfcGxvdCkgKw0KICBhZXMoeCA9IGNsdXN0ZXJzKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMEwsIGZpbGwgPSAiIzBjNGM4YSIpICsNCiAgbGFicyh4ID0gIk51bWJlciBvZiBjbHVzdGVycyIsIHkgPSAiRnJlcXVlbmN5IGFtb25nIGFsbCBpbmRpY2VzIiwgdGl0bGUgPSAiT3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojJyBDbHVzdGVyaXphw6fDo28gay1tZWFucw0KIysgZWNobz1ULCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFDQoNCnNldC5zZWVkKDEyMykNCmttLnJlcz1rbWVhbnMoZGYsIDYsIG5zdGFydD0yNSkNCnByaW50KGttLnJlcykNCg0KDQoNCiMnIENyaWFuZG8gbm92byBiYW5jbyBkZSBkYWRvcyBjb20gY2x1c3Rlcg0KDQphZ2dyZWdhdGUoZGFkb3MyLCBieT1saXN0KGNsdXN0ZXI9a20ucmVzJGNsdXN0ZXIpLCBtZWFuKQ0KDQpkZCA8LSBjYmluZChkYWRvczIsIGNsdXN0ZXIgPSBrbS5yZXMkY2x1c3RlcikNCg0Ka20ucmVzJGNsdXN0ZXINCmttLnJlcyRzaXplDQprbS5yZXMkY2VudGVycw0KDQojJyBWaXp1YWxpemFuZG8gb3MgY2x1c3RlcnMNCiMrIGVjaG89VCwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRQ0KDQoNCmZ2aXpfY2x1c3RlcihrbS5yZXMsIGRhdGE9ZGYsDQogICAgICAgICAgICAgZ2VvbS5pbmQgPSBjKCJ0ZXh0IiksDQogICAgICAgICAgICAgZWxsaXBzZS50eXBlPSJldWNsaWQiLA0KICAgICAgICAgICAgIHN0YXIucGxvdD1UUlVFLA0KICAgICAgICAgICAgIHBhbGV0dGUgPSAiRGFyazIiLA0KICAgICAgICAgICAgIHJlcGVsPVRSVUUsDQogICAgICAgICAgICAgZ2d0aGVtZT10aGVtZV9taW5pbWFsKCkNCikNCg0KDQojJyBEZW5kcm9ncmFtYQ0KIysgZWNobz1ULCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFDQoNCmRpc3RhPWRpc3QoZGYsIG1ldGhvZD0iZXVjbGlkZWFuIikNCmRpc3RhLmhjPWhjbHVzdChkPWRpc3RhLCBtZXRob2Q9IndhcmQuRCIpDQpmdml6X2RlbmQoZGlzdGEuaGMsIGNleD0wLjUsIGsgPSA2LCBjb2xvcl9sYWJlbHNfYnlfayA9IFRSVUUsIGhvcml6ID0gVCkNCg0KDQpyZXMgPC0gaGN1dChkZiwgayA9IDYsIHN0YW5kID0gVFJVRSkNCmZ2aXpfZGVuZChyZXMsIHJlY3QgPSBUUlVFLCBjZXggPSAwLjUsDQogICAgICAgICAga19jb2xvcnMgPSAiRGFyazIiLCBob3JpeiA9IFQpDQoNCg0KDQprbS5yZXMxIDwtIGhrbWVhbnMoZGYsIDYsaGMubWV0cmljID0gImV1Y2xpZCIgLGhjLm1ldGhvZCA9ICJ3YXJkLkQiKQ0KDQoNCmZ2aXpfZGVuZChrbS5yZXMxLCBjZXggPSAwLjYsIHBhbGV0dGUgPSAiRGFyazIiLA0KICAgICAgICAgIHJlY3QgPSBUUlVFLCByZWN0X2JvcmRlciA9ICJEYXJrMiIsIHJlY3RfZmlsbCA9IFRSVUUsIGhvcml6ID0gVCkNCg0KDQpmdml6X2Rpc3QoZGlzdGEsIGdyYWRpZW50ID0gbGlzdChsb3cgPSAiIzAwQUZCQiIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAiI0ZDNEUwNyIpKQ0KDQojJyAjIyBQQ0ENCiMrIGVjaG89VCwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRQ0KDQprbS5wY2EgPC0gUENBKA0KICBkZiwNCiAgZ3JhcGggPSBGLA0KICBzY2FsZS51bml0ID0gVFJVRSkNCg0KZWlnLnZhbCA8LSBnZXRfZWlnZW52YWx1ZShrbS5wY2EpDQoNCmVpZy52YWwNCg0KZnZpel9laWcoa20ucGNhLCBhZGRsYWJlbHM9VFJVRSkNCg0KdmFyIDwtIGdldF9wY2FfdmFyKGttLnBjYSkNCg0KdmFyDQoNCg0KDQoNCg0KIyAgQ29vcmRlbmFkYXMNCmhlYWQodmFyJGNvb3JkKQ0KIyBDb3MyOiBxdWFsaWRhZGUgbm8gbWFwYSBkbyBmYXRvcg0KaGVhZCh2YXIkY29zMikNCiMgQ29udHJpYnVpw6fDtWVzIHBhcmEgb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFpcw0KaGVhZCh2YXIkY29udHJpYikNCg0KZnZpel9jb3MyKGttLnBjYSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAxOjIpDQoNCmRmICU+JSBjb3IobWV0aG9kID0gInNwZWFybWFuIikgJT4lIGNvcnJwbG90KC4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAibnVtYmVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAidXBwZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGwucG9zID0gInRkIikNCg0KDQoNCg0Kc3VtbWFyeShrbS5wY2EpDQoNCg0KIyBDb250cmlidWnDp8O1ZXMgZGUgdmFyacOhdmVpcyBwYXJhIFBDMQ0KZnZpel9jb250cmliKGttLnBjYSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAxLCB0b3AgPSAxMCkNCiMgQ29udHJpYnVpw6fDtWVzIGRlIHZhcmnDoXZlaXMgcGFyYSBQQzINCmZ2aXpfY29udHJpYihrbS5wY2EsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMiwgdG9wID0gMTApDQoNCiMgY29udHJpYnVpw6fDo28gdG90YWwgcGFyYSBQQzEgZSBQQzIgDQoNCmZ2aXpfY29udHJpYihrbS5wY2EsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMToyKQ0KDQoNCmZ2aXpfcGNhX2JpcGxvdCgNCiAga20ucGNhLA0KICBnZW9tLmluZCA9ICJ0ZXh0IiwNCiAgY29sLnZhciA9ICJjb250cmliIiwNCiAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksDQogIGxlZ2VuZC50aXRsZSA9ICJDb250cmlidWnDp8OjbyIsDQogIHBhbGV0dGUgPSAiRGFyazIiLA0KICByZXBlbCA9IEYNCikNCg0KDQpmdml6X3BjYV9pbmQoDQogIGttLnBjYSwNCiAgZ2VvbSA9ICJ0ZXh0IiwNCiAgaGFiaWxsYWdlID0gYXMuZmFjdG9yKGRkJGNsdXN0ZXIpLA0KICBhZGRFbGxpcHNlcyA9IFRSVUUsDQogIHBhbGV0dGUgPSAiRGFyazIiDQopDQoNCmZ2aXpfcGNhX2luZChrbS5wY2EsDQogICAgICAgICAgICAgZ2VvbS5pbmQgPSAidGV4dCIsDQogICAgICAgICAgICAgY29sLmluZCA9IGFzLmZhY3RvcihkZCRjbHVzdGVyKSwNCiAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsIA0KICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9ICJHcnVwb3MiLA0KICAgICAgICAgICAgIHJlcGVsID0gVCwNCiAgICAgICAgICAgICBwYWxldHRlID0gIkRhcmsyIg0KKQ0KDQoNCmRmICU+JSBwYWlycy5wYW5lbHMoLiwgDQogICAgICAgICAgICAgICAgICAgIHNob3cucG9pbnRzPVRSVUUsIA0KICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3BlYXJtYW4iLA0KICAgICAgICAgICAgICAgICAgICBnYXA9MCwgDQogICAgICAgICAgICAgICAgICAgIHN0YXJzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgIGNpPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBhbHBoYT0wLjA1LA0KICAgICAgICAgICAgICAgICAgICBjZXguY29yPTEsDQogICAgICAgICAgICAgICAgICAgIGNleD0xLjAsDQogICAgICAgICAgICAgICAgICAgIGJyZWFrcz0iU3R1cmdlcyIsDQogICAgICAgICAgICAgICAgICAgIHJ1Zz1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgZGVuc2l0eT1GLA0KICAgICAgICAgICAgICAgICAgICBoaXN0LmNvbD0iZGFya2dyZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgZmFjdG9yPTUsDQogICAgICAgICAgICAgICAgICAgIGRpZ2l0cz0yLA0KICAgICAgICAgICAgICAgICAgICBlbGxpcHNlcz1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgc2NhbGU9RkFMU0UsDQogICAgICAgICAgICAgICAgICAgIHNtb290aD1UUlVFLA0KICAgICAgICAgICAgICAgICAgICBsbT1ULA0KICAgICAgICAgICAgICAgICAgICBjb3I9VA0KKSANCg0KDQppbmQgPC0gZ2V0X3BjYV9pbmQoa20ucGNhKQ0KaW5kDQoNCg0KIyBDb29yZGVuYWRhcyBkZSBpbmRpdsOtZHVvcw0KaGVhZChpbmQkY29vcmQpDQojIFF1YWxpZGFkZSBkb3MgaW5kaXbDrWR1b3MNCmhlYWQoaW5kJGNvczIpDQojIENvbnRyaWJ1acOnw7VlcyBkZSBpbmRpdsOtZHVvcw0KaGVhZChpbmQkY29udHJpYikNCg0KDQoNCg0KDQpmdml6X3BjYV9pbmQoa20ucGNhLCBjb2wuaW5kID0gImNvczIiLCANCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwNCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUNCikNCg0KZnZpel9jb250cmliKGttLnBjYSwgY2hvaWNlID0gImluZCIsIGF4ZXMgPSAxOjIpDQoNCg0Kc2V0LnNlZWQoMTIzKQ0KbXkuY29udC52YXIgPC0gcm5vcm0oMTUpDQoNCmZ2aXpfcGNhX2luZChrbS5wY2EsIGNvbC5pbmQgPSBteS5jb250LnZhciwNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiYmx1ZSIsICJ5ZWxsb3ciLCAicmVkIiksDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIkNvbnQuVmFyIikNCg0KDQpmdml6X3BjYV9pbmQoa20ucGNhLA0KICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwNCiAgICAgICAgICAgICBjb2wuaW5kID0gYXMuZmFjdG9yKGRkJGNsdXN0ZXIpLA0KICAgICAgICAgICAgIHBhbGV0dGUgPSAiRGFyazIiLA0KICAgICAgICAgICAgIGFkZEVsbGlwc2VzID0gVFJVRSwgDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIkdydXBvcyINCikNCg0KDQpmdml6X3BjYV9iaXBsb3Qoa20ucGNhLCANCiAgICAgICAgICAgICAgICBnZW9tLmluZCA9IGMoInBvaW50IiwidGV4dCIpLA0KICAgICAgICAgICAgICAgIGZpbGwuaW5kID0gYXMuZmFjdG9yKGRkJGNsdXN0ZXIpLCBjb2wuaW5kID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICBwb2ludHNoYXBlID0gMjEsIA0KICAgICAgICAgICAgICAgIHBvaW50c2l6ZSA9IDIsDQogICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLA0KICAgICAgICAgICAgICAgIHJlcGVsID0gVCwNCiAgICAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgYWxwaGEudmFyID0iY29udHJpYiIsIA0KICAgICAgICAgICAgICAgIGNvbC52YXIgPSAiY29udHJpYiIsDQogICAgICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9ICJEYXJrMiIsDQogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gbGlzdChmaWxsID0gIkNsdXN0ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiQ29udHJpYiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9ICJDb250cmliIikNCikNCg0KDQojJyAjIyBPdXRybyB0ZXN0ZQ0KIycgDQojKyBlY2hvPVQsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UNCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkocnN0YXRpeCkNCg0KcGQgPSBwb3NpdGlvbl9kb2RnZSgxKQ0KDQoNCmRhZG9zICU+JSBzYW1wbGVfbl9ieShjdWx0LHRyYXQsIHNpemUgPSAxKQ0KDQpkYWRvcyAlPiUNCiAgZ3JvdXBfYnkoY3VsdCx0cmF0KSAlPiUNCiAgZ2V0X3N1bW1hcnlfc3RhdHMoYWx0LG5mLCB0eXBlID0gIm1lYW5fc2QiKQ0KDQpieHAgPC0gZ2dib3hwbG90KA0KICBkYWRvcywgeCA9ICJjdWx0IiwgeSA9ICJhbHQiLA0KICBjb2xvciA9ICJ0cmF0IiwgcGFsZXR0ZSA9ICJqY28iLCB5bGFiID0gIkFsdHVyYSIsIHhsYWI9ICJDdWx0dXJhIiwNCikNCg0KZ2dwYXIoYnhwLA0KICAgICAgbGVnZW5kID0gInJpZ2h0IiwgbGVnZW5kLnRpdGxlID0gIlRyYXRhbWVudG8iKSANCg0KZGFkb3MgJT4lDQogIGdyb3VwX2J5KGN1bHQpICU+JQ0KICBzaGFwaXJvX3Rlc3QoYWx0KQ0KDQpkYWRvcyAlPiUgDQogIGdyb3VwX2J5KGN1bHQpICU+JQ0KICBpZGVudGlmeV9vdXRsaWVycyhhbHQpDQoNCmRhZG9zICU+JSANCiAgZ3JvdXBfYnkoY3VsdCkgJT4lDQogIGlkZW50aWZ5X291dGxpZXJzKG5mKQ0KDQojIEJ1aWxkIHRoZSBsaW5lYXIgbW9kZWwNCm1vZGVsICA8LSBsbShhbHQgfiBjdWx0LCBkYXRhID0gZGFkb3MpDQojIENyZWF0ZSBhIFFRIHBsb3Qgb2YgcmVzaWR1YWxzDQpnZ3FxcGxvdChyZXNpZHVhbHMobW9kZWwpKQ0KDQojIEJ1aWxkIHRoZSBsaW5lYXIgbW9kZWwNCm1vZGVsICA8LSBsbShuZiB+IGN1bHQsIGRhdGEgPSBkYWRvcykNCiMgQ3JlYXRlIGEgUVEgcGxvdCBvZiByZXNpZHVhbHMNCmdncXFwbG90KHJlc2lkdWFscyhtb2RlbCkpDQoNCmRhZG9zICU+JQ0KICBncm91cF9ieShjdWx0KSAlPiUNCiAgc2hhcGlyb190ZXN0KGFsdCkNCg0KZGFkb3MgJT4lDQogIGdyb3VwX2J5KGN1bHQpICU+JQ0KICBzaGFwaXJvX3Rlc3QobmYpDQoNCmdncXFwbG90KGRhZG9zLCAiYWx0IiwgZmFjZXQuYnkgPSAiY3VsdCIpDQpnZ3FxcGxvdChkYWRvcywgIm5mIiwgZmFjZXQuYnkgPSAiY3VsdCIpDQoNCnBsb3QobW9kZWwsIDEpDQoNCmRhZG9zICU+JSBsZXZlbmVfdGVzdChhbHQgfiBjdWx0KQ0KZGFkb3MgJT4lIGxldmVuZV90ZXN0KG5mIH4gY3VsdCkNCg0KcmVzLmFvdiA8LSBkYWRvcyAlPiUgYW5vdmFfdGVzdChhbHQgfiBjdWx0ICogdHJhdCkNCnJlcy5hb3YNCg0KbW9kZWwgPC0gbG0oYWx0IH4gY3VsdCAqIHRyYXQsIGRhdGEgPSBkYWRvcykNCg0KZGFkb3MgJT4lDQogIGdyb3VwX2J5KGN1bHQpICU+JQ0KICBhbm92YV90ZXN0KGFsdCB+IHRyYXQsIGVycm9yID0gbW9kZWwpDQoNCmxpYnJhcnkoZW1tZWFucykNCnB3YyA8LSBkYWRvcyAlPiUgDQogIGdyb3VwX2J5KGN1bHQpICU+JQ0KICBlbW1lYW5zX3Rlc3QoYWx0IH4gdHJhdCwgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiKSANCnB3Yw0KDQpyZXMuYW92DQoNCmRhZG9zICU+JQ0KICBwYWlyd2lzZV90X3Rlc3QoDQogICAgYWx0IH4gY3VsdCwgDQogICAgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiDQogICkNCg0KbW9kZWwgPC0gbG0oYWx0IH4gY3VsdCAqIHRyYXQsIGRhdGEgPSBkYWRvcykNCg0KZGFkb3MgJT4lIA0KICBlbW1lYW5zX3Rlc3QoDQogICAgYWx0IH4gY3VsdCwgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiLA0KICAgIG1vZGVsID0gbW9kZWwNCiAgKQ0KDQpwd2MgPC0gcHdjICU+JSBhZGRfeHlfcG9zaXRpb24oeCA9ICJjdWx0IikNCg0KZ2dwYXIoYnhwLA0KICAgICAgbGVnZW5kID0gInJpZ2h0IiwgbGVnZW5kLnRpdGxlID0gIlRyYXRhbWVudG8iKSArDQogIHN0YXRfcHZhbHVlX21hbnVhbChwd2MpICsNCiAgbGFicygNCiAgICBzdWJ0aXRsZSA9IGdldF90ZXN0X2xhYmVsKHJlcy5hb3YsIGRldGFpbGVkID0gVFJVRSksDQogICAgY2FwdGlvbiA9IGdldF9wd2NfbGFiZWwocHdjKQ0KICApICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikNCg0KDQoNCiMnIA0KIycgIyMgKipSZWZlcsOqbmNpYSoqDQojJyBPcyBwcm9jZWRpbWVudG9zIGVzdGF0w61zdGljb3MgdXRpbGl6YWRvcyBuZXN0ZSBlc3R1ZG8gZm9yYW0gcmVhbGl6YWRvcyBubyBwcm9ncmFtYSBSIFtAUkNvcmVUZWFtXS4gUGFjb3RlcyAqc3RhdHMqIFtAUkNvcmVUZWFtXS4gUGFjb3RlICpkeXBsciosIHBhcmEgbWFuaXB1bGHDp8OjbyBkZSBkYWRvcywgW0BkcGx5cl0uIFBhY290ZSAqZ2dwb3QyKjogZWxlbWVudG9zIGdyw6FmaWNvcyBbQEdHUGxvdDJdLCBQYXJhIGFuw6FsaXNlIG11bHRpdmFyaWFkYSBmb3JhbSB1dGlsaXphZG9zIG9zIHBhY290ZXMgKmZhY3RvZXh0cmEqLCBbQEZhY3RvZXh0cmFdLCAqRmFjdG9yTWluZXIqLCBbQEZhY3RvTWluZVJdLCAqdmVnYW4qIFtAdmVnYW5dLCAqY29ycnBsb3QqIFtAY29ycnBsb3QyMDE3XSwgKk5iQ2x1c3QqIFtATmJDbHVzdF0sIGUgcGFyYSBBTkFWQSBlIFRlc3RlIGRlIFR1a2V5IGZvaSB1dGlsaXphZG8gbyAqRXhwRGVzLnB0KiBbQEV4cERlcy5wdF0NCg0K