1 Libraries and setup

Uncomment if notebook location is different from project location to set working directory for the entire notebook

#wd<-"D:/your_path_to_folder"
#knitr::opts_knit$set(root.dir = normalizePath(wd))

Loading libraries required for analyses

#load required Seurat version, 
#if you have only the version needed here installed, 
#you can skip the lib.loc specification
library(Seurat, lib.loc = "../../R/R-4.0.0/library/different_versions/") 
library(ggplot2)
library(monocle)

2 Loading data

#load whole hippocampus data (hypoxia vs. normoxia) from Butt et al (2020): GSE162079
HYP<-readRDS("../Butt_et_al_hypoxia_hippocampus.RDS")
#load CA1 data (EPO vs. placebo) from Wakhloo et al (2020): GSE144444
EPO<-readRDS("../Wakhloo_et_al_EPO_CA1.RDS")
#update object to latest Seurat version
EPO<-UpdateSeuratObject(EPO)
#load CA1 glutamatergic clusters from Wakhloo et al (2020) 
#analyzed in pseudotime analysis (Monocle2) 
#(https://github.com/AgnesSteixner/EPO_Wakhloo_et_al_NATCOMM/tree/master/trajectory)
mon<-readRDS("../Wakhloo_et_al_monocle_pseudotime.RDS")

Create dataframe of hypoxia object for plotting

d_hyp<-data.frame(t(data.frame(GetAssayData(HYP, slot = "data", assay = "RNA"))))
d_hyp$group<-HYP$group
d_hyp$final_identity<-HYP$final_identity

3 Figure 2

3.1 Figure 2G

plot_cell_trajectory(mon, color_by = "Pseudotime", show_branch_points = F)+
  theme(legend.title = element_text(size = 14))+
  theme(legend.text = element_text(size = 14, vjust = -1))+
  theme(axis.text.y = element_text(size = 14, colour = "black"))+
  theme(axis.text.x = element_text(size = 14, colour = "black",vjust = 0.5))+
  theme(axis.title.x = element_text(size = 14, colour = "black",vjust = 0.5))+
  theme(axis.title.y = element_text(size = 14, colour = "black"))+
  theme(legend.position = c(0.57,0.9))+
  coord_cartesian(xlim = c(-19.99,20), ylim= c(-5,5.2), clip = "off", expand = F)+
  theme(plot.margin = unit(c(1,1,0.5,0.5), "cm"))+
  scale_color_gradient(low = "lightblue",
  high = "darkblue")+
  theme(legend.key.size = unit(0.7, "cm"), legend.key.height = unit(0.6, "cm"), 
        legend.direction = "horizontal")

3.2 Figure 2H


plot_cell_trajectory(mon, markers = "Tbr1", use_color_gradient = T, cell_size = 1.5, 
                     show_branch_points = F)+
  theme(axis.text = element_text(size = 16, colour = "black"))+
  theme(axis.title = element_text(size = 16, colour = "black"))+
  theme(legend.position = c(0.3, 0.75))+
  theme(legend.text = element_text(size = 16))+
  theme(legend.title = element_blank())+
  theme(legend.key.size = unit(0.5, "cm"), legend.key.height = unit(0.6, "cm"))+
  scale_color_gradientn(colors=alpha(c("seagreen", "magenta", "deeppink4"),0.45))+
  coord_cartesian(xlim = c(-19.99,20), ylim= c(-5,5.2), clip = "off", expand = F)+
  theme(plot.margin = unit(c(-0.48,1,0,0), "cm"))

3.3 Figure 2I (left panel)

#define intermediate neuronal stage
mon$Pseudotime_interm<-"other"
mon$Pseudotime_interm[mon$Pseudotime>3&mon$Pseudotime<25]<-"intermediate"

#plot trajectory
plot_cell_trajectory(mon, color_by = "Pseudotime_interm", show_branch_points = F)+
  theme(legend.title = element_blank())+
  theme(legend.text = element_text(size = 14))+
  theme(axis.text.y = element_text(size = 14, colour = "black"))+
  theme(axis.text.x = element_text(size = 14, colour = "black",vjust = 0.5))+
  theme(axis.title.x = element_text(size = 14, colour = "black",vjust = 0.5))+
  theme(axis.title.y = element_text(size = 14, colour = "black"))+
  theme(legend.position = c(0.6,0.9))+
  guides(color=guide_legend(nrow = 1))+
  coord_cartesian(xlim = c(-19.99,20), ylim= c(-5,5.2), clip = "off", expand = F)+
  theme(plot.margin = unit(c(0.5,0,0.5,0.5), "cm"))

3.4 Figure 2I (right panel)

# subset monocle object
mon_zbtb<-mon["Zbtb20",]

# create pseudotime expression graph for Zbtb20
plot_genes_in_pseudotime(mon_zbtb, color_by = "Pseudotime", cell_size = 2)+
  theme(axis.text = element_text(size = 20, colour = "black"))+
  theme(axis.title = element_text(size = 22, colour = "black"))+
  theme(axis.line = element_line(colour = "black"))+
  theme(legend.position = "none")+
  scale_color_gradient(low = "lightblue",
  high = "darkblue")+
  coord_cartesian(xlim = c(0,45), clip = "off", expand = F)+
  theme(plot.margin = unit(c(0.2,0,0,0), "cm"))+
  ylab("Zbtb20 relative expression")

4 Figure 4

4.1 Figure 4B

#shift ependymal cells upwards on dimension plot for easier visualization
#get UMAP embeddings
emb<-Embeddings(HYP, reduction = "umap")
#shift selected cells upwards on UMAP2
emb[,2][emb[,2]<(-15)]<-emb[,2][emb[,2]<(-15)]+12
#feed changed embeddings back into object
HYP@reductions$umap@cell.embeddings<-emb

# create dimension plot
DimPlot(HYP, reduction = "umap")+
theme(legend.position = "none")+
theme(axis.text = element_blank())+
theme(axis.title = element_blank())+
theme(axis.line = element_blank())+
theme(axis.ticks = element_blank())

4.2 Figure 4C - Csf1r

Note: Wilcox test was performed with limma as implemented in Seurat. This implementation corrects for correlation within groups (when correlation is positive, more conservative statistics) and continuity. Testing is done for both directions -> smaller p is multiplied by 2; Bonferroni adjusted p = p*number of genes in dataset.

# calculate p value
p<-formatC(min(limma::rankSumTestWithCorrelation(statistics = HYP@assays$RNA@data["Csf1r",], 
                                                 index = which(HYP$group=="Hypoxia")))*
                                                          2*nrow(HYP),2)
# calculate log-fold change
logfc<-round(log(mean(expm1(HYP@assays$RNA@data["Csf1r",HYP$group=="Hypoxia"]))+1)-
               log(mean(expm1(HYP@assays$RNA@data["Csf1r",HYP$group=="Normoxia"]))+1),2)

# create violin plot
ggplot(d_hyp, aes(x=group, y=Csf1r, fill=group))+
  geom_violin()+ geom_jitter()+
  theme(panel.background = element_blank())+
  coord_cartesian(expand = F, ylim = c(0,4), clip = "off")+
  scale_fill_manual(values = c("#F7E7FC","#551A8B"))+ 
  theme(axis.title.x = element_blank())+ylab('Csf1r normalized expression')+
  theme(axis.text.x = element_text(size = 19, color = 'black'),
        axis.text.y = element_text(size = 19, color = 'black'), 
        axis.title = element_text(size = 20.5), 
        axis.line = element_line(colour = 'black'))+
  theme(legend.position = 'none')+
  annotate("text", x=1.5, y=4.1, label=paste0("italic('p')","==", p), size=6.7, parse=T)+
  annotate("text", x=1.5, y=3.8, label=paste0("logFC = ", logfc), size=6.7)+
  theme(plot.margin = unit(c(0.9,0,0.1,0),"cm"))+
  stat_summary(fun=median, geom="point", size=2, color="firebrick2")

4.3 Figure 4C - Csf1

# calculate p value
p<-formatC(min(limma::rankSumTestWithCorrelation(statistics = HYP@assays$RNA@data["Csf1",], 
                                                 index = which(HYP$group=="Hypoxia")))*2*nrow(HYP),2)
# calculate log-fold change
logfc<-round(log(mean(expm1(HYP@assays$RNA@data["Csf1",HYP$group=="Hypoxia"]))+1)-
               log(mean(expm1(HYP@assays$RNA@data["Csf1",HYP$group=="Normoxia"]))+1),2)

# create violin plot
ggplot(d_hyp, aes(x=group, y=Csf1, fill=group))+
  geom_violin()+ geom_jitter()+
  theme(panel.background = element_blank())+
  coord_cartesian(expand = F, ylim = c(0,4), clip = "off")+
  scale_fill_manual(values = c("#F7E7FC","#551A8B"))+ 
  theme(axis.title.x = element_blank())+ylab('Csf1 normalized expression')+
  theme(axis.text.x = element_text(size = 19, color = 'black'),
        axis.text.y = element_text(size = 19, color = 'black'), 
        axis.title = element_text(size = 20.5), 
        axis.line = element_line(colour = 'black'))+
  theme(legend.position = 'none')+
  annotate("text", x=1.5, y=4.1, label=paste0("italic('p')","==", p), size=6.7, parse=T)+
  annotate("text", x=1.5, y=3.8, label=paste0("logFC = ", logfc), size=6.7)+
  theme(plot.margin = unit(c(0.9,0,0.1,0),"cm"))+
  stat_summary(fun=median, geom="point", size=2, color="firebrick2")

4.4 Figure 4C - Il34

# calculate p-value
# p-value is "0" due to R limitation -> show it as approximation
#p<-formatC(min(limma::rankSumTestWithCorrelation(statistics = HYP@assays$RNA@data["Il34",], 
#index = which(HYP$group=="Hypoxia")))*2*nrow(HYP),3)
p<-1e-300
# calculate log-fold change
logfc<-round(log(mean(expm1(HYP@assays$RNA@data["Il34",HYP$group=="Hypoxia"]))+1)-
               log(mean(expm1(HYP@assays$RNA@data["Il34",HYP$group=="Normoxia"]))+1),2)

# create violin plot
ggplot(d_hyp, aes(x=group, y=Il34, fill=group))+
  geom_violin()+
  theme(panel.background = element_blank())+
  coord_cartesian(expand = F, ylim = c(0,4), clip = "off")+
  scale_fill_manual(values = c("#F7E7FC","#551A8B"))+ 
  theme(axis.title.x = element_blank())+ylab('Il34 normalized expression')+
  theme(axis.text.x = element_text(size = 19, color = 'black'),
        axis.text.y = element_text(size = 19, color = 'black'), 
        axis.title = element_text(size = 20.5), 
        axis.line = element_line(colour = 'black'))+
  theme(legend.position = 'none')+
  annotate("text", x=1.5, y=3.8, label=paste0("italic('p')","<", p), size=6.7, parse=T)+
  annotate("text", x=1.5, y=3.5, label=paste0("logFC = ", logfc), size=6.7)+
  theme(plot.margin = unit(c(0.5,0,0,0),"cm"))+
  stat_summary(fun=median, geom="point", size=2, color="firebrick2")

4.5 Figure 4D

#subset microglia
M<-subset(HYP, final_identity=="Microglia")
d_m<-data.frame(t(data.frame(GetAssayData(M, slot = "data", assay = "RNA"))))
d_m$group<-M$group
# calculate p-value
p<-formatC(min(limma::rankSumTestWithCorrelation(statistics = M@assays$RNA@data["Csf1r",], 
                                                 index = which(M$group=="Hypoxia")))*2*nrow(M),3)
# calculate log-fold change
logfc<-round(log(mean(expm1(M@assays$RNA@data["Csf1r",M$group=="Hypoxia"]))+1)-
               log(mean(expm1(M@assays$RNA@data["Csf1r",M$group=="Normoxia"]))+1),2)

# create violin plot
ggplot(d_m, aes(x=group, y=Csf1r, fill=group))+
  geom_violin()+
  theme(panel.background = element_blank())+
  coord_cartesian(expand = F, xlim=c(0.4, 2.5), ylim = c(0,4), clip = "off")+
  scale_fill_manual(values = c("#F7E7FC","#551A8B"))+ 
  theme(axis.title.x = element_blank())+ylab('Csf1r normalized expression')+
  theme(axis.text.x = element_text(size = 19.3, color = 'black'),
        axis.text.y = element_text(size = 19, color = 'black'), 
        axis.title = element_text(size = 20.5), 
        axis.line = element_line(colour = 'black'))+
  theme(legend.position = 'none')+
  annotate("text", x=1.5, y=4, label=paste0("italic('p')","==", p), size=6.7, parse=T)+
  annotate("text", x=1.5, y=3.6, label=paste0("logFC = ", logfc), size=6.7)+
  theme(plot.margin = unit(c(0.9,0,0.1,0),"cm"))+
  stat_summary(fun=median, geom="point", size=2, color="firebrick2")

4.6 Figure 4E

# define glial identity
d_hyp$glia<-"NO"
d_hyp$glia[d_hyp$final_identity=="OPC"|d_hyp$final_identity=="Oligodendrocytes"|
             d_hyp$final_identity=="Astrocytes"|d_hyp$final_identity=="Microglia"|
             d_hyp$final_identity=="Ependymal_cells"]<-"YES"
# show table of glial numbers
table(d_hyp$glia)

   NO   YES 
20622  5228 
# set identity to glia
Idents(HYP)<-d_hyp$glia
# calculate p-value and log-fold change
csf1_glia_stats<-FindMarkers(HYP, features = "Csf1", group.by = "group", 
                             ident.1 = "Hypoxia", logfc.threshold = 0.01, 
                             subset.ident = "YES")

  |                                                  | 0 % ~calculating  
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
#round values
p<-round(csf1_glia_stats$p_val_adj,4)
logfc<-round(csf1_glia_stats$avg_logFC, 2)

# create violin plot
ggplot(d_hyp[d_hyp$glia=="YES",], aes(x=group, y=Csf1, fill=group))+
  geom_violin()+
  theme(panel.background = element_blank())+
  coord_cartesian(expand = F, ylim = c(0,4), clip = "off")+
  scale_fill_manual(values = c("#F7E7FC","#551A8B"))+ 
  theme(axis.title.x = element_blank())+ylab('Csf1 normalized expression')+
  theme(axis.text.x = element_text(size = 19, color = 'black'),
        axis.text.y = element_text(size = 19, color = 'black'), 
        axis.title = element_text(size = 20.5), 
        axis.line = element_line(colour = 'black'))+
  theme(legend.position = 'none')+
  annotate("text", x=1.5, y=3.8, label=paste0("italic('p')","==", p), size=6.7, parse=T)+
  annotate("text", x=1.5, y=3.5, label=paste0("logFC = ", logfc), size=6.7)+
  theme(plot.margin = unit(c(0.5,0,0,0),"cm"))+
  stat_summary(fun=median, geom="point", size=2, color="firebrick2")

4.7 Figure 4F

# create identity of excitatory neurons
HYP$excitatory<-"NO"
HYP$excitatory[HYP$final_identity %in% c("Glutamatergic0_DG/CA2/CA3","Glutamatergic1_CA1",
                                         "Glutamatergic2","Glutamatergic3","Glutamatergic4", 
                                         "Mossy_cells")]<-"YES"
# show table of excitatory neuron number
table(HYP$excitatory)  

   NO   YES 
 8039 17811 
# fill info into dataframe
d_hyp$excitatory<-HYP$excitatory

# create violin plot for Il34 expression in glutamatergic neurons
# set identity to excitatory neuron
Idents(HYP)<-HYP$excitatory
# calculate stats for differential expression between hypoxia and normoxia
il34_glut_stats<-FindMarkers(HYP, features = "Il34", group.by = "group", 
                             ident.1 = "Hypoxia", logfc.threshold = 0.01, 
                             subset.ident = "YES")

  |                                                  | 0 % ~calculating  
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
p<-formatC(il34_glut_stats$p_val_adj,3)
logfc<-round(il34_glut_stats$avg_logFC, 2)

#create violin plot
ggplot(d_hyp[d_hyp$excitatory=="YES",], aes(x=group, y=Il34, fill=group))+
  geom_violin()+
  theme(panel.background = element_blank())+
  coord_cartesian(expand = F, ylim = c(0,4), clip = "off")+
  scale_fill_manual(values = c("#F7E7FC","#551A8B"))+
  theme(axis.title.x = element_blank())+
  ylab('Il34 normalized expression')+
  theme(axis.text.x = element_text(size = 19, color = 'black'),
        axis.text.y = element_text(size = 19, color = 'black'), 
        axis.title =element_text(size = 20.5), 
        axis.line = element_line(colour = 'black'))+
  theme(legend.position = 'none')+
  annotate("text", x=1.5, y=3.8, label=paste0("italic('p')","==", p), size=6.7, parse=T)+
  annotate("text", x=1.5, y=3.5, label=paste0("logFC = ", logfc), size=6.7)+
  theme(plot.margin = unit(c(0.5,0,0,0),"cm"))+
  stat_summary(fun=median, geom="point", size=2, color="firebrick2")

5 Session info

sessionInfo()
R version 4.0.0 (2020-04-24)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

Matrix products: default

locale:
[1] LC_COLLATE=German_Germany.1252  LC_CTYPE=German_Germany.1252    LC_MONETARY=German_Germany.1252 LC_NUMERIC=C                    LC_TIME=German_Germany.1252    

attached base packages:
 [1] splines   stats4    parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] monocle_2.16.0      DDRTree_0.1.5       irlba_2.3.3         VGAM_1.1-3          Biobase_2.48.0      BiocGenerics_0.34.0 Matrix_1.2-18       ggplot2_3.3.0      
[9] Seurat_3.1.5       

loaded via a namespace (and not attached):
  [1] Rtsne_0.15           colorspace_1.4-1     ellipsis_0.3.1       ggridges_0.5.2       rprojroot_1.3-2      fs_1.4.1             rstudioapi_0.11     
  [8] farver_2.0.3         leiden_0.3.3         listenv_0.8.0        rstan_2.19.3         remotes_2.2.0        ggrepel_0.8.2        fansi_0.4.1         
 [15] codetools_0.2-16     docopt_0.6.1         knitr_1.30           pkgload_1.0.2        jsonlite_1.6.1       packrat_0.5.0        ica_1.0-2           
 [22] cluster_2.1.0        png_0.1-7            pheatmap_1.0.12      uwot_0.1.8           sctransform_0.2.1    BiocManager_1.30.10  compiler_4.0.0      
 [29] httr_1.4.2           backports_1.1.6      assertthat_0.2.1     lazyeval_0.2.2       limma_3.44.1         cli_2.1.0            formatR_1.7         
 [36] htmltools_0.5.0      prettyunits_1.1.1    tools_4.0.0          rsvd_1.0.3           igraph_1.2.5         gtable_0.3.0         glue_1.4.1          
 [43] RANN_2.6.1           reshape2_1.4.4       dplyr_0.8.5          rappdirs_0.3.1       Rcpp_1.0.4.6         slam_0.1-47          vctrs_0.3.0         
 [50] ape_5.4              nlme_3.1-147         lmtest_0.9-37        xfun_0.19            stringr_1.4.0        globals_0.12.5       ps_1.3.3            
 [57] testthat_2.3.2       lifecycle_0.2.0      devtools_2.3.0       future_1.17.0        MASS_7.3-51.5        zoo_1.8-8            scales_1.1.1        
 [64] inline_0.3.15        RColorBrewer_1.1-2   yaml_2.2.1           curl_4.3             memoise_1.1.0        reticulate_1.16      pbapply_1.4-3       
 [71] gridExtra_2.3        loo_2.2.0            StanHeaders_2.19.2   fastICA_1.2-2        stringi_1.4.6        desc_1.2.0           densityClust_0.3    
 [78] pkgbuild_1.1.0       rlang_0.4.6          pkgconfig_2.0.3      matrixStats_0.56.0   qlcMatrix_0.9.7      evaluate_0.14        lattice_0.20-41     
 [85] ROCR_1.0-11          purrr_0.3.4          labeling_0.3         patchwork_1.0.0      htmlwidgets_1.5.2    cowplot_1.1.0        processx_3.4.4      
 [92] tidyselect_1.1.0     RcppAnnoy_0.0.16     plyr_1.8.6           magrittr_1.5         R6_2.4.1             combinat_0.0-8       pillar_1.4.6        
 [99] withr_2.3.0          fitdistrplus_1.1-1   survival_3.1-12      tibble_3.0.1         future.apply_1.5.0   tsne_0.1-3           crayon_1.3.4        
[106] KernSmooth_2.23-16   plotly_4.9.2.1       rmarkdown_2.5.3      viridis_0.5.1        usethis_1.6.1        grid_4.0.0           data.table_1.12.8   
[113] FNN_1.1.3            callr_3.5.1          sparsesvd_0.2        HSMMSingleCell_1.8.0 digest_0.6.26        tidyr_1.0.3          munsell_0.5.0       
[120] viridisLite_0.3.0    sessioninfo_1.1.1   
LS0tDQp0aXRsZTogIkZlcm5hbmRleiBHYXJjaWEtQWd1ZG8gZXQgYWw6IHNjUk5Bc2VxIGFuYWx5c2lzIg0KYXV0aG9yOiAiQWduZXMgQS4gU3RlaXhuZXItS3VtYXIiDQpkYXRlOiAiMjYgMTEgMjAyMCINCm91dHB1dDogDQogIHBkZl9kb2N1bWVudDoNCiAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXggDQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGZpZ19oZWlnaHQ6IDgNCiAgICBmaWdfd2lkdGg6IDEzDQogICAga2VlcF90ZXg6IG5vDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICBodG1sX25vdGVib29rOiANCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgZmlnX2hlaWdodDogOA0KICAgIGZpZ193aWR0aDogMTMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvYzogeWVzDQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBmaWdfaGVpZ2h0OiA4DQogICAgZmlnX3dpZHRoOiAxMw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHRydWUNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCiMgTGlicmFyaWVzIGFuZCBzZXR1cA0KVW5jb21tZW50IGlmIG5vdGVib29rIGxvY2F0aW9uIGlzIGRpZmZlcmVudCBmcm9tIHByb2plY3QgbG9jYXRpb24gdG8gc2V0IHdvcmtpbmcgZGlyZWN0b3J5IGZvciB0aGUgZW50aXJlIG5vdGVib29rDQpgYGB7ciBzZXR1cH0NCiN3ZDwtIkQ6L3lvdXJfcGF0aF90b19mb2xkZXIiDQoja25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBub3JtYWxpemVQYXRoKHdkKSkNCmBgYA0KDQpMb2FkaW5nIGxpYnJhcmllcyByZXF1aXJlZCBmb3IgYW5hbHlzZXMNCmBgYHtyIGxpYnJhcmllcywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQ0KI2xvYWQgcmVxdWlyZWQgU2V1cmF0IHZlcnNpb24sIA0KI2lmIHlvdSBoYXZlIG9ubHkgdGhlIHZlcnNpb24gbmVlZGVkIGhlcmUgaW5zdGFsbGVkLCANCiN5b3UgY2FuIHNraXAgdGhlIGxpYi5sb2Mgc3BlY2lmaWNhdGlvbg0KbGlicmFyeShTZXVyYXQsIGxpYi5sb2MgPSAiLi4vLi4vUi9SLTQuMC4wL2xpYnJhcnkvZGlmZmVyZW50X3ZlcnNpb25zLyIpIA0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShtb25vY2xlKQ0KYGBgDQoNCiMgTG9hZGluZyBkYXRhDQpgYGB7ciBlY2hvPVRSVUUsIGV2YWwgPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQ0KI2xvYWQgd2hvbGUgaGlwcG9jYW1wdXMgZGF0YSAoaHlwb3hpYSB2cy4gbm9ybW94aWEpIGZyb20gQnV0dCBldCBhbCAoMjAyMCk6IEdTRTE2MjA3OQ0KSFlQPC1yZWFkUkRTKCIuLi9CdXR0X2V0X2FsX2h5cG94aWFfaGlwcG9jYW1wdXMuUkRTIikNCiNsb2FkIENBMSBkYXRhIChFUE8gdnMuIHBsYWNlYm8pIGZyb20gV2FraGxvbyBldCBhbCAoMjAyMCk6IEdTRTE0NDQ0NA0KRVBPPC1yZWFkUkRTKCIuLi9XYWtobG9vX2V0X2FsX0VQT19DQTEuUkRTIikNCiN1cGRhdGUgb2JqZWN0IHRvIGxhdGVzdCBTZXVyYXQgdmVyc2lvbg0KRVBPPC1VcGRhdGVTZXVyYXRPYmplY3QoRVBPKQ0KI2xvYWQgQ0ExIGdsdXRhbWF0ZXJnaWMgY2x1c3RlcnMgZnJvbSBXYWtobG9vIGV0IGFsICgyMDIwKSANCiNhbmFseXplZCBpbiBwc2V1ZG90aW1lIGFuYWx5c2lzIChNb25vY2xlMikgDQojKGh0dHBzOi8vZ2l0aHViLmNvbS9BZ25lc1N0ZWl4bmVyL0VQT19XYWtobG9vX2V0X2FsX05BVENPTU0vdHJlZS9tYXN0ZXIvdHJhamVjdG9yeSkNCm1vbjwtcmVhZFJEUygiLi4vV2FraGxvb19ldF9hbF9tb25vY2xlX3BzZXVkb3RpbWUuUkRTIikNCmBgYA0KDQpDcmVhdGUgZGF0YWZyYW1lIG9mIGh5cG94aWEgb2JqZWN0IGZvciBwbG90dGluZw0KYGBge3IgY3JlYXRlX2RmLCBldmFsID0gVFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCmRfaHlwPC1kYXRhLmZyYW1lKHQoZGF0YS5mcmFtZShHZXRBc3NheURhdGEoSFlQLCBzbG90ID0gImRhdGEiLCBhc3NheSA9ICJSTkEiKSkpKQ0KZF9oeXAkZ3JvdXA8LUhZUCRncm91cA0KZF9oeXAkZmluYWxfaWRlbnRpdHk8LUhZUCRmaW5hbF9pZGVudGl0eQ0KYGBgDQoNCiMgRmlndXJlIDINCiMjIEZpZ3VyZSAyRw0KYGBge3IgcHNldWRvdGltZV90cmFqZWN0b3J5LCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCnBsb3RfY2VsbF90cmFqZWN0b3J5KG1vbiwgY29sb3JfYnkgPSAiUHNldWRvdGltZSIsIHNob3dfYnJhbmNoX3BvaW50cyA9IEYpKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkrDQogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgdmp1c3QgPSAtMSkpKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG91ciA9ICJibGFjayIpKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvdXIgPSAiYmxhY2siLHZqdXN0ID0gMC41KSkrDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG91ciA9ICJibGFjayIsdmp1c3QgPSAwLjUpKSsNCiAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3VyID0gImJsYWNrIikpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuNTcsMC45KSkrDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMTkuOTksMjApLCB5bGltPSBjKC01LDUuMiksIGNsaXAgPSAib2ZmIiwgZXhwYW5kID0gRikrDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDEsMSwwLjUsMC41KSwgImNtIikpKw0KICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAibGlnaHRibHVlIiwNCiAgaGlnaCA9ICJkYXJrYmx1ZSIpKw0KICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNywgImNtIiksIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjYsICJjbSIpLCANCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikNCmBgYA0KDQojIyBGaWd1cmUgMkgNCmBgYHtyIHBzZXVkb3RpbWVfdGJyMSwgZmlnLmFsaWduPSJjZW50ZXIiLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUV9DQoNCnBsb3RfY2VsbF90cmFqZWN0b3J5KG1vbiwgbWFya2VycyA9ICJUYnIxIiwgdXNlX2NvbG9yX2dyYWRpZW50ID0gVCwgY2VsbF9zaXplID0gMS41LCANCiAgICAgICAgICAgICAgICAgICAgIHNob3dfYnJhbmNoX3BvaW50cyA9IEYpKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4zLCAwLjc1KSkrDQogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKw0KICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgImNtIiksIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjYsICJjbSIpKSsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycz1hbHBoYShjKCJzZWFncmVlbiIsICJtYWdlbnRhIiwgImRlZXBwaW5rNCIpLDAuNDUpKSsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC0xOS45OSwyMCksIHlsaW09IGMoLTUsNS4yKSwgY2xpcCA9ICJvZmYiLCBleHBhbmQgPSBGKSsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoLTAuNDgsMSwwLDApLCAiY20iKSkNCmBgYA0KDQojIyBGaWd1cmUgMkkgKGxlZnQgcGFuZWwpDQpgYGB7ciBpbnRlcm1lZGlhdGVfdHJhamVjdG9yeSwgZmlnLmFsaWduPSJjZW50ZXIiLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUV9DQojZGVmaW5lIGludGVybWVkaWF0ZSBuZXVyb25hbCBzdGFnZQ0KbW9uJFBzZXVkb3RpbWVfaW50ZXJtPC0ib3RoZXIiDQptb24kUHNldWRvdGltZV9pbnRlcm1bbW9uJFBzZXVkb3RpbWU+MyZtb24kUHNldWRvdGltZTwyNV08LSJpbnRlcm1lZGlhdGUiDQoNCiNwbG90IHRyYWplY3RvcnkNCnBsb3RfY2VsbF90cmFqZWN0b3J5KG1vbiwgY29sb3JfYnkgPSAiUHNldWRvdGltZV9pbnRlcm0iLCBzaG93X2JyYW5jaF9wb2ludHMgPSBGKSsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkrDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3VyID0gImJsYWNrIikpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG91ciA9ICJibGFjayIsdmp1c3QgPSAwLjUpKSsNCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3VyID0gImJsYWNrIix2anVzdCA9IDAuNSkpKw0KICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC42LDAuOSkpKw0KICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG5yb3cgPSAxKSkrDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMTkuOTksMjApLCB5bGltPSBjKC01LDUuMiksIGNsaXAgPSAib2ZmIiwgZXhwYW5kID0gRikrDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAuNSwwLDAuNSwwLjUpLCAiY20iKSkNCmBgYA0KDQojIyBGaWd1cmUgMkkgKHJpZ2h0IHBhbmVsKQ0KYGBge3IgcHNldWRvdGltZV9leHByZXNzaW9uLCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCiMgc3Vic2V0IG1vbm9jbGUgb2JqZWN0DQptb25femJ0YjwtbW9uWyJaYnRiMjAiLF0NCg0KIyBjcmVhdGUgcHNldWRvdGltZSBleHByZXNzaW9uIGdyYXBoIGZvciBaYnRiMjANCnBsb3RfZ2VuZXNfaW5fcHNldWRvdGltZShtb25femJ0YiwgY29sb3JfYnkgPSAiUHNldWRvdGltZSIsIGNlbGxfc2l6ZSA9IDIpKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyLCBjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrDQogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJsaWdodGJsdWUiLA0KICBoaWdoID0gImRhcmtibHVlIikrDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDQ1KSwgY2xpcCA9ICJvZmYiLCBleHBhbmQgPSBGKSsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMC4yLDAsMCwwKSwgImNtIikpKw0KICB5bGFiKCJaYnRiMjAgcmVsYXRpdmUgZXhwcmVzc2lvbiIpDQpgYGANCg0KIyBGaWd1cmUgNA0KIyMgRmlndXJlIDRCDQpgYGB7ciBkaW1wbG90X2hpcHBvY2FtcHVzLCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCiNzaGlmdCBlcGVuZHltYWwgY2VsbHMgdXB3YXJkcyBvbiBkaW1lbnNpb24gcGxvdCBmb3IgZWFzaWVyIHZpc3VhbGl6YXRpb24NCiNnZXQgVU1BUCBlbWJlZGRpbmdzDQplbWI8LUVtYmVkZGluZ3MoSFlQLCByZWR1Y3Rpb24gPSAidW1hcCIpDQojc2hpZnQgc2VsZWN0ZWQgY2VsbHMgdXB3YXJkcyBvbiBVTUFQMg0KZW1iWywyXVtlbWJbLDJdPCgtMTUpXTwtZW1iWywyXVtlbWJbLDJdPCgtMTUpXSsxMg0KI2ZlZWQgY2hhbmdlZCBlbWJlZGRpbmdzIGJhY2sgaW50byBvYmplY3QNCkhZUEByZWR1Y3Rpb25zJHVtYXBAY2VsbC5lbWJlZGRpbmdzPC1lbWINCg0KIyBjcmVhdGUgZGltZW5zaW9uIHBsb3QNCkRpbVBsb3QoSFlQLCByZWR1Y3Rpb24gPSAidW1hcCIpKw0KdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsNCnRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQp0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsNCnRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSkrDQp0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNCiMjIEZpZ3VyZSA0QyAtIENzZjFyDQpOb3RlOiBXaWxjb3ggdGVzdCB3YXMgcGVyZm9ybWVkIHdpdGggbGltbWEgYXMgaW1wbGVtZW50ZWQgaW4gU2V1cmF0LiBUaGlzIGltcGxlbWVudGF0aW9uIGNvcnJlY3RzIGZvciBjb3JyZWxhdGlvbiB3aXRoaW4gZ3JvdXBzICh3aGVuIGNvcnJlbGF0aW9uIGlzIHBvc2l0aXZlLCBtb3JlIGNvbnNlcnZhdGl2ZSBzdGF0aXN0aWNzKSBhbmQgY29udGludWl0eS4gVGVzdGluZyBpcyBkb25lIGZvciBib3RoIGRpcmVjdGlvbnMgLT4gc21hbGxlciBwIGlzIG11bHRpcGxpZWQgYnkgMjsgQm9uZmVycm9uaSBhZGp1c3RlZCBwID0gcCpudW1iZXIgb2YgZ2VuZXMgaW4gZGF0YXNldC4NCmBgYHtyIHZsbnBsb3RfY3NmMXJfaGlwcG9jYW1wdXMsIGZpZy5hbGlnbj0iY2VudGVyIiwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQ0KIyBjYWxjdWxhdGUgcCB2YWx1ZQ0KcDwtZm9ybWF0QyhtaW4obGltbWE6OnJhbmtTdW1UZXN0V2l0aENvcnJlbGF0aW9uKHN0YXRpc3RpY3MgPSBIWVBAYXNzYXlzJFJOQUBkYXRhWyJDc2YxciIsXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSB3aGljaChIWVAkZ3JvdXA9PSJIeXBveGlhIikpKSoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyKm5yb3coSFlQKSwyKQ0KIyBjYWxjdWxhdGUgbG9nLWZvbGQgY2hhbmdlDQpsb2dmYzwtcm91bmQobG9nKG1lYW4oZXhwbTEoSFlQQGFzc2F5cyRSTkFAZGF0YVsiQ3NmMXIiLEhZUCRncm91cD09Ikh5cG94aWEiXSkpKzEpLQ0KICAgICAgICAgICAgICAgbG9nKG1lYW4oZXhwbTEoSFlQQGFzc2F5cyRSTkFAZGF0YVsiQ3NmMXIiLEhZUCRncm91cD09Ik5vcm1veGlhIl0pKSsxKSwyKQ0KDQojIGNyZWF0ZSB2aW9saW4gcGxvdA0KZ2dwbG90KGRfaHlwLCBhZXMoeD1ncm91cCwgeT1Dc2YxciwgZmlsbD1ncm91cCkpKw0KICBnZW9tX3Zpb2xpbigpKyBnZW9tX2ppdHRlcigpKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKSsNCiAgY29vcmRfY2FydGVzaWFuKGV4cGFuZCA9IEYsIHlsaW0gPSBjKDAsNCksIGNsaXAgPSAib2ZmIikrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGN0U3RkMiLCIjNTUxQThCIikpKyANCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSt5bGFiKCdDc2YxciBub3JtYWxpemVkIGV4cHJlc3Npb24nKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE5LCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTksIGNvbG9yID0gJ2JsYWNrJyksIA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMC41KSwgDQogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAnYmxhY2snKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrDQogIGFubm90YXRlKCJ0ZXh0IiwgeD0xLjUsIHk9NC4xLCBsYWJlbD1wYXN0ZTAoIml0YWxpYygncCcpIiwiPT0iLCBwKSwgc2l6ZT02LjcsIHBhcnNlPVQpKw0KICBhbm5vdGF0ZSgidGV4dCIsIHg9MS41LCB5PTMuOCwgbGFiZWw9cGFzdGUwKCJsb2dGQyA9ICIsIGxvZ2ZjKSwgc2l6ZT02LjcpKw0KICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjksMCwwLjEsMCksImNtIikpKw0KICBzdGF0X3N1bW1hcnkoZnVuPW1lZGlhbiwgZ2VvbT0icG9pbnQiLCBzaXplPTIsIGNvbG9yPSJmaXJlYnJpY2syIikNCg0KYGBgDQojIyBGaWd1cmUgNEMgLSBDc2YxDQpgYGB7ciB2bG5wbG90X2NzZjFfaGlwcG9jYW1wdXMsIGZpZy5hbGlnbj0iY2VudGVyIiwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQ0KIyBjYWxjdWxhdGUgcCB2YWx1ZQ0KcDwtZm9ybWF0QyhtaW4obGltbWE6OnJhbmtTdW1UZXN0V2l0aENvcnJlbGF0aW9uKHN0YXRpc3RpY3MgPSBIWVBAYXNzYXlzJFJOQUBkYXRhWyJDc2YxIixdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRleCA9IHdoaWNoKEhZUCRncm91cD09Ikh5cG94aWEiKSkpKjIqbnJvdyhIWVApLDIpDQojIGNhbGN1bGF0ZSBsb2ctZm9sZCBjaGFuZ2UNCmxvZ2ZjPC1yb3VuZChsb2cobWVhbihleHBtMShIWVBAYXNzYXlzJFJOQUBkYXRhWyJDc2YxIixIWVAkZ3JvdXA9PSJIeXBveGlhIl0pKSsxKS0NCiAgICAgICAgICAgICAgIGxvZyhtZWFuKGV4cG0xKEhZUEBhc3NheXMkUk5BQGRhdGFbIkNzZjEiLEhZUCRncm91cD09Ik5vcm1veGlhIl0pKSsxKSwyKQ0KDQojIGNyZWF0ZSB2aW9saW4gcGxvdA0KZ2dwbG90KGRfaHlwLCBhZXMoeD1ncm91cCwgeT1Dc2YxLCBmaWxsPWdyb3VwKSkrDQogIGdlb21fdmlvbGluKCkrIGdlb21faml0dGVyKCkrDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kID0gRiwgeWxpbSA9IGMoMCw0KSwgY2xpcCA9ICJvZmYiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y3RTdGQyIsIiM1NTFBOEIiKSkrIA0KICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpK3lsYWIoJ0NzZjEgbm9ybWFsaXplZCBleHByZXNzaW9uJykrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOSwgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE5LCBjb2xvciA9ICdibGFjaycpLCANCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAuNSksIA0KICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gJ2JsYWNrJykpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpKw0KICBhbm5vdGF0ZSgidGV4dCIsIHg9MS41LCB5PTQuMSwgbGFiZWw9cGFzdGUwKCJpdGFsaWMoJ3AnKSIsIj09IiwgcCksIHNpemU9Ni43LCBwYXJzZT1UKSsNCiAgYW5ub3RhdGUoInRleHQiLCB4PTEuNSwgeT0zLjgsIGxhYmVsPXBhc3RlMCgibG9nRkMgPSAiLCBsb2dmYyksIHNpemU9Ni43KSsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMC45LDAsMC4xLDApLCJjbSIpKSsNCiAgc3RhdF9zdW1tYXJ5KGZ1bj1tZWRpYW4sIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0iZmlyZWJyaWNrMiIpDQpgYGANCiMjIEZpZ3VyZSA0QyAtIElsMzQNCmBgYHtyIHZsbnBsb3RfaWwzNF9oaXBwb2NhbXB1cywgZmlnLmFsaWduPSJjZW50ZXIiLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUV9DQojIGNhbGN1bGF0ZSBwLXZhbHVlDQojIHAtdmFsdWUgaXMgIjAiIGR1ZSB0byBSIGxpbWl0YXRpb24gLT4gc2hvdyBpdCBhcyBhcHByb3hpbWF0aW9uDQojcDwtZm9ybWF0QyhtaW4obGltbWE6OnJhbmtTdW1UZXN0V2l0aENvcnJlbGF0aW9uKHN0YXRpc3RpY3MgPSBIWVBAYXNzYXlzJFJOQUBkYXRhWyJJbDM0IixdLCANCiNpbmRleCA9IHdoaWNoKEhZUCRncm91cD09Ikh5cG94aWEiKSkpKjIqbnJvdyhIWVApLDMpDQpwPC0xZS0zMDANCiMgY2FsY3VsYXRlIGxvZy1mb2xkIGNoYW5nZQ0KbG9nZmM8LXJvdW5kKGxvZyhtZWFuKGV4cG0xKEhZUEBhc3NheXMkUk5BQGRhdGFbIklsMzQiLEhZUCRncm91cD09Ikh5cG94aWEiXSkpKzEpLQ0KICAgICAgICAgICAgICAgbG9nKG1lYW4oZXhwbTEoSFlQQGFzc2F5cyRSTkFAZGF0YVsiSWwzNCIsSFlQJGdyb3VwPT0iTm9ybW94aWEiXSkpKzEpLDIpDQoNCiMgY3JlYXRlIHZpb2xpbiBwbG90DQpnZ3Bsb3QoZF9oeXAsIGFlcyh4PWdyb3VwLCB5PUlsMzQsIGZpbGw9Z3JvdXApKSsNCiAgZ2VvbV92aW9saW4oKSsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIGNvb3JkX2NhcnRlc2lhbihleHBhbmQgPSBGLCB5bGltID0gYygwLDQpLCBjbGlwID0gIm9mZiIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjdFN0ZDIiwiIzU1MUE4QiIpKSsgDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkreWxhYignSWwzNCBub3JtYWxpemVkIGV4cHJlc3Npb24nKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE5LCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTksIGNvbG9yID0gJ2JsYWNrJyksIA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMC41KSwgDQogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAnYmxhY2snKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrDQogIGFubm90YXRlKCJ0ZXh0IiwgeD0xLjUsIHk9My44LCBsYWJlbD1wYXN0ZTAoIml0YWxpYygncCcpIiwiPCIsIHApLCBzaXplPTYuNywgcGFyc2U9VCkrDQogIGFubm90YXRlKCJ0ZXh0IiwgeD0xLjUsIHk9My41LCBsYWJlbD1wYXN0ZTAoImxvZ0ZDID0gIiwgbG9nZmMpLCBzaXplPTYuNykrDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAuNSwwLDAsMCksImNtIikpKw0KICBzdGF0X3N1bW1hcnkoZnVuPW1lZGlhbiwgZ2VvbT0icG9pbnQiLCBzaXplPTIsIGNvbG9yPSJmaXJlYnJpY2syIikNCmBgYA0KIyMgRmlndXJlIDREDQpgYGB7ciB2bG5wbG90X2NzZjFyX21pY3JvLCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCiNzdWJzZXQgbWljcm9nbGlhDQpNPC1zdWJzZXQoSFlQLCBmaW5hbF9pZGVudGl0eT09Ik1pY3JvZ2xpYSIpDQpkX208LWRhdGEuZnJhbWUodChkYXRhLmZyYW1lKEdldEFzc2F5RGF0YShNLCBzbG90ID0gImRhdGEiLCBhc3NheSA9ICJSTkEiKSkpKQ0KZF9tJGdyb3VwPC1NJGdyb3VwDQojIGNhbGN1bGF0ZSBwLXZhbHVlDQpwPC1mb3JtYXRDKG1pbihsaW1tYTo6cmFua1N1bVRlc3RXaXRoQ29ycmVsYXRpb24oc3RhdGlzdGljcyA9IE1AYXNzYXlzJFJOQUBkYXRhWyJDc2YxciIsXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSB3aGljaChNJGdyb3VwPT0iSHlwb3hpYSIpKSkqMipucm93KE0pLDMpDQojIGNhbGN1bGF0ZSBsb2ctZm9sZCBjaGFuZ2UNCmxvZ2ZjPC1yb3VuZChsb2cobWVhbihleHBtMShNQGFzc2F5cyRSTkFAZGF0YVsiQ3NmMXIiLE0kZ3JvdXA9PSJIeXBveGlhIl0pKSsxKS0NCiAgICAgICAgICAgICAgIGxvZyhtZWFuKGV4cG0xKE1AYXNzYXlzJFJOQUBkYXRhWyJDc2YxciIsTSRncm91cD09Ik5vcm1veGlhIl0pKSsxKSwyKQ0KDQojIGNyZWF0ZSB2aW9saW4gcGxvdA0KZ2dwbG90KGRfbSwgYWVzKHg9Z3JvdXAsIHk9Q3NmMXIsIGZpbGw9Z3JvdXApKSsNCiAgZ2VvbV92aW9saW4oKSsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIGNvb3JkX2NhcnRlc2lhbihleHBhbmQgPSBGLCB4bGltPWMoMC40LCAyLjUpLCB5bGltID0gYygwLDQpLCBjbGlwID0gIm9mZiIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjdFN0ZDIiwiIzU1MUE4QiIpKSsgDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkreWxhYignQ3NmMXIgbm9ybWFsaXplZCBleHByZXNzaW9uJykrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOS4zLCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTksIGNvbG9yID0gJ2JsYWNrJyksIA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMC41KSwgDQogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAnYmxhY2snKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrDQogIGFubm90YXRlKCJ0ZXh0IiwgeD0xLjUsIHk9NCwgbGFiZWw9cGFzdGUwKCJpdGFsaWMoJ3AnKSIsIj09IiwgcCksIHNpemU9Ni43LCBwYXJzZT1UKSsNCiAgYW5ub3RhdGUoInRleHQiLCB4PTEuNSwgeT0zLjYsIGxhYmVsPXBhc3RlMCgibG9nRkMgPSAiLCBsb2dmYyksIHNpemU9Ni43KSsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMC45LDAsMC4xLDApLCJjbSIpKSsNCiAgc3RhdF9zdW1tYXJ5KGZ1bj1tZWRpYW4sIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0iZmlyZWJyaWNrMiIpDQpgYGANCiMjIEZpZ3VyZSA0RQ0KYGBge3IgdmxucGxvdF9jc2YxX2dsaWEsIGZpZy5hbGlnbj0iY2VudGVyIiwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQ0KIyBkZWZpbmUgZ2xpYWwgaWRlbnRpdHkNCmRfaHlwJGdsaWE8LSJOTyINCmRfaHlwJGdsaWFbZF9oeXAkZmluYWxfaWRlbnRpdHk9PSJPUEMifGRfaHlwJGZpbmFsX2lkZW50aXR5PT0iT2xpZ29kZW5kcm9jeXRlcyJ8DQogICAgICAgICAgICAgZF9oeXAkZmluYWxfaWRlbnRpdHk9PSJBc3Ryb2N5dGVzInxkX2h5cCRmaW5hbF9pZGVudGl0eT09Ik1pY3JvZ2xpYSJ8DQogICAgICAgICAgICAgZF9oeXAkZmluYWxfaWRlbnRpdHk9PSJFcGVuZHltYWxfY2VsbHMiXTwtIllFUyINCiMgc2hvdyB0YWJsZSBvZiBnbGlhbCBudW1iZXJzDQp0YWJsZShkX2h5cCRnbGlhKQ0KIyBzZXQgaWRlbnRpdHkgdG8gZ2xpYQ0KSWRlbnRzKEhZUCk8LWRfaHlwJGdsaWENCiMgY2FsY3VsYXRlIHAtdmFsdWUgYW5kIGxvZy1mb2xkIGNoYW5nZQ0KY3NmMV9nbGlhX3N0YXRzPC1GaW5kTWFya2VycyhIWVAsIGZlYXR1cmVzID0gIkNzZjEiLCBncm91cC5ieSA9ICJncm91cCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4xID0gIkh5cG94aWEiLCBsb2dmYy50aHJlc2hvbGQgPSAwLjAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0LmlkZW50ID0gIllFUyIpDQojcm91bmQgdmFsdWVzDQpwPC1yb3VuZChjc2YxX2dsaWFfc3RhdHMkcF92YWxfYWRqLDQpDQpsb2dmYzwtcm91bmQoY3NmMV9nbGlhX3N0YXRzJGF2Z19sb2dGQywgMikNCg0KIyBjcmVhdGUgdmlvbGluIHBsb3QNCmdncGxvdChkX2h5cFtkX2h5cCRnbGlhPT0iWUVTIixdLCBhZXMoeD1ncm91cCwgeT1Dc2YxLCBmaWxsPWdyb3VwKSkrDQogIGdlb21fdmlvbGluKCkrDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kID0gRiwgeWxpbSA9IGMoMCw0KSwgY2xpcCA9ICJvZmYiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y3RTdGQyIsIiM1NTFBOEIiKSkrIA0KICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpK3lsYWIoJ0NzZjEgbm9ybWFsaXplZCBleHByZXNzaW9uJykrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOSwgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE5LCBjb2xvciA9ICdibGFjaycpLCANCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAuNSksIA0KICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gJ2JsYWNrJykpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpKw0KICBhbm5vdGF0ZSgidGV4dCIsIHg9MS41LCB5PTMuOCwgbGFiZWw9cGFzdGUwKCJpdGFsaWMoJ3AnKSIsIj09IiwgcCksIHNpemU9Ni43LCBwYXJzZT1UKSsNCiAgYW5ub3RhdGUoInRleHQiLCB4PTEuNSwgeT0zLjUsIGxhYmVsPXBhc3RlMCgibG9nRkMgPSAiLCBsb2dmYyksIHNpemU9Ni43KSsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMC41LDAsMCwwKSwiY20iKSkrDQogIHN0YXRfc3VtbWFyeShmdW49bWVkaWFuLCBnZW9tPSJwb2ludCIsIHNpemU9MiwgY29sb3I9ImZpcmVicmljazIiKQ0KYGBgDQojIyBGaWd1cmUgNEYNCmBgYHtyIHZsbnBsb3RfaWwzNF9pbDM0LCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCiMgY3JlYXRlIGlkZW50aXR5IG9mIGV4Y2l0YXRvcnkgbmV1cm9ucw0KSFlQJGV4Y2l0YXRvcnk8LSJOTyINCkhZUCRleGNpdGF0b3J5W0hZUCRmaW5hbF9pZGVudGl0eSAlaW4lIGMoIkdsdXRhbWF0ZXJnaWMwX0RHL0NBMi9DQTMiLCJHbHV0YW1hdGVyZ2ljMV9DQTEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2x1dGFtYXRlcmdpYzIiLCJHbHV0YW1hdGVyZ2ljMyIsIkdsdXRhbWF0ZXJnaWM0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNb3NzeV9jZWxscyIpXTwtIllFUyINCiMgc2hvdyB0YWJsZSBvZiBleGNpdGF0b3J5IG5ldXJvbiBudW1iZXINCnRhYmxlKEhZUCRleGNpdGF0b3J5KSAgDQojIGZpbGwgaW5mbyBpbnRvIGRhdGFmcmFtZQ0KZF9oeXAkZXhjaXRhdG9yeTwtSFlQJGV4Y2l0YXRvcnkNCg0KIyBjcmVhdGUgdmlvbGluIHBsb3QgZm9yIElsMzQgZXhwcmVzc2lvbiBpbiBnbHV0YW1hdGVyZ2ljIG5ldXJvbnMNCiMgc2V0IGlkZW50aXR5IHRvIGV4Y2l0YXRvcnkgbmV1cm9uDQpJZGVudHMoSFlQKTwtSFlQJGV4Y2l0YXRvcnkNCiMgY2FsY3VsYXRlIHN0YXRzIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIGh5cG94aWEgYW5kIG5vcm1veGlhDQppbDM0X2dsdXRfc3RhdHM8LUZpbmRNYXJrZXJzKEhZUCwgZmVhdHVyZXMgPSAiSWwzNCIsIGdyb3VwLmJ5ID0gImdyb3VwIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50LjEgPSAiSHlwb3hpYSIsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQuaWRlbnQgPSAiWUVTIikNCnA8LWZvcm1hdEMoaWwzNF9nbHV0X3N0YXRzJHBfdmFsX2FkaiwzKQ0KbG9nZmM8LXJvdW5kKGlsMzRfZ2x1dF9zdGF0cyRhdmdfbG9nRkMsIDIpDQoNCiNjcmVhdGUgdmlvbGluIHBsb3QNCmdncGxvdChkX2h5cFtkX2h5cCRleGNpdGF0b3J5PT0iWUVTIixdLCBhZXMoeD1ncm91cCwgeT1JbDM0LCBmaWxsPWdyb3VwKSkrDQogIGdlb21fdmlvbGluKCkrDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kID0gRiwgeWxpbSA9IGMoMCw0KSwgY2xpcCA9ICJvZmYiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y3RTdGQyIsIiM1NTFBOEIiKSkrDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHlsYWIoJ0lsMzQgbm9ybWFsaXplZCBleHByZXNzaW9uJykrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOSwgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE5LCBjb2xvciA9ICdibGFjaycpLCANCiAgICAgICAgYXhpcy50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemUgPSAyMC41KSwgDQogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAnYmxhY2snKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrDQogIGFubm90YXRlKCJ0ZXh0IiwgeD0xLjUsIHk9My44LCBsYWJlbD1wYXN0ZTAoIml0YWxpYygncCcpIiwiPT0iLCBwKSwgc2l6ZT02LjcsIHBhcnNlPVQpKw0KICBhbm5vdGF0ZSgidGV4dCIsIHg9MS41LCB5PTMuNSwgbGFiZWw9cGFzdGUwKCJsb2dGQyA9ICIsIGxvZ2ZjKSwgc2l6ZT02LjcpKw0KICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjUsMCwwLDApLCJjbSIpKSsNCiAgc3RhdF9zdW1tYXJ5KGZ1bj1tZWRpYW4sIGdlb209InBvaW50Iiwgc2l6ZT0yLCBjb2xvcj0iZmlyZWJyaWNrMiIpDQpgYGANCiMgU2Vzc2lvbiBpbmZvDQpgYGB7ciwgdGlkeT1UUlVFLCB0aWR5Lm9wdHM9bGlzdCh3aWR0aC5jdXRvZmY9ODApfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQo=