library(reshape2)

Attaching package: ‘reshape2’

The following objects are masked from ‘package:data.table’:

    dcast, melt
library(ggplot2)
library(gplots)
package ‘gplots’ was built under R version 3.5.2
Attaching package: ‘gplots’

The following object is masked from ‘package:IRanges’:

    space

The following object is masked from ‘package:S4Vectors’:

    space

The following object is masked from ‘package:stats’:

    lowess
library(pheatmap)
package ‘pheatmap’ was built under R version 3.5.2
library(plyr)
package ‘plyr’ was built under R version 3.5.2
Attaching package: ‘plyr’

The following object is masked from ‘package:IRanges’:

    desc

The following object is masked from ‘package:S4Vectors’:

    rename
set.seed(123)
library(data.table)
library(magrittr)
library(dplyr)
package ‘dplyr’ was built under R version 3.5.2
Attaching package: ‘dplyr’

The following objects are masked from ‘package:plyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following objects are masked from ‘package:data.table’:

    between, first, last

The following object is masked from ‘package:AnnotationDbi’:

    select

The following objects are masked from ‘package:GenomicRanges’:

    intersect, setdiff, union

The following object is masked from ‘package:GenomeInfoDb’:

    intersect

The following objects are masked from ‘package:IRanges’:

    collapse, desc, intersect, setdiff, slice, union

The following objects are masked from ‘package:S4Vectors’:

    first, intersect, rename, setdiff, setequal, union

The following object is masked from ‘package:Biobase’:

    combine

The following objects are masked from ‘package:BiocGenerics’:

    combine, intersect, setdiff, union

The following object is masked from ‘package:biomaRt’:

    select

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(readr)
library(cowplot)
package ‘cowplot’ was built under R version 3.5.2
********************************************************
Note: As of version 1.0.0, cowplot does not change the
  default ggplot2 theme anymore. To recover the previous
  behavior, execute:
  theme_set(theme_cowplot())
********************************************************
library(igraph)
package ‘igraph’ was built under R version 3.5.2
Attaching package: ‘igraph’

The following objects are masked from ‘package:dplyr’:

    as_data_frame, groups, union

The following object is masked from ‘package:GenomicRanges’:

    union

The following object is masked from ‘package:IRanges’:

    union

The following object is masked from ‘package:S4Vectors’:

    union

The following objects are masked from ‘package:BiocGenerics’:

    normalize, path, union

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
theme_set(theme_classic() )


get_colors <- function(groups, group.col = palette()){
  groups <- as.factor(groups)
  ngrps <- length(levels(groups))
  if(ngrps > length(group.col)) 
    group.col <- rep(group.col, ngrps)
  color <- group.col[as.numeric(groups)]
  names(color) <- as.vector(groups)
  return(color)
}


gg_color_hue <- function(n) {
  hues = seq(15, 375, length = n + 1)
  hcl(h = hues, l = 65, c = 100)[1:n]
}

Importing metadata

metadata
     File.accession Biosample.Age Experiment.date.released Biosample.term.name Paired.end Paired.with Audit.WARNING
  1:    ENCFF405VKS      13.5 day               2015-10-13         neural tube         NA                          
  2:    ENCFF241GLU      13.5 day               2015-10-13         neural tube         NA                          
  3:    ENCFF957SPL         0 day               2015-06-23         neural tube         NA                          
  4:    ENCFF046EJC         0 day               2015-06-23         neural tube         NA                          
  5:    ENCFF085MBO         0 day               2015-06-23         neural tube         NA                          
 ---                                                                                                               
293:     SRR1805824          P30a                    16484        whole cortex         NA                          
294:     SRR1805823         P110a                    16484        whole cortex         NA                          
295:     SRR1805822         P110b                    16484        whole cortex         NA                          
296:     SRR1805821          21Ma                    16484        whole cortex         NA                          
297:     SRR1805820          21Mb                    16484        whole cortex         NA                          

ME_final.rep1 <- fread("~/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/out.high_quality.txt")
ME_final.rep2 <- fread("~/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep2/out.high_quality.txt")

ME_final <- ME_final.rep1[ ME %in% ME_final.rep2$ME, ]


ME_cov <- fread("~/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/out_filtered_ME.PSI.txt")
ME_cov[, `:=`(FILE_NAME=File, ME=ME_coords)]

number_of_microexons <- length(ME_final[ , unique(ME)])



ME_cov_filtered <- ME_cov[ME %in% ME_final[, ME]  , ]
library(stringi)




#mat <- stri_split_fixed(ME_cov_filtered$ME_coverages, ',', simplify=T)
#mat <- `dim<-`(as.numeric(mat), dim(mat))  # convert to numeric and save dims
#rowsum(mat, na.rm=T)

#sum(mat, na.rm=T)


#sapply(strsplit(as.character(ME_cov_filtered$ME_coverages), ",", fixed=T), function(x) sum(as.numeric(x)))
#ME_cov_filtered[, strsplit( ME_coverages, ",") ]


#library(dplyr)
#library(tidyr)
#df %>%
#   separate_rows(y, z, convert = TRUE) %>%
#   group_by(x) %>% 
#   summarise_all(sum)

Obtainin PSI matrix




Tissues <- as.character(metadata$Biosample.term.name)
names(Tissues) <- as.character(metadata$File.accession)

Ages <- as.character(metadata$Biosample.Age)
names(Ages) <- as.character(metadata$File.accession)



ME_cov_filtered  <- unique(ME_cov_filtered[FILE_NAME %in% metadata[ , File.accession],])
#ME_cov_filtered_ENCODE <- unique(ME_cov_filtered[FILE_NAME %in% metadata[ , File.accession],])



#colnames(Tissue_PSI_matrix_dcast) <- as.character( paste(sep = " ", Tissues[colnames(Tissue_PSI_matrix_dcast)], Ages[colnames(Tissue_PSI_matrix_dcast)])) #To replase the file name by the biological sample name

#Tissue_PSI_matrix_dcast <- Tissue_PSI_matrix_dcast[, order(paste(sep = " ", Tissues[colnames(Tissue_PSI_matrix_dcast)], Ages[colnames(Tissue_PSI_matrix_dcast)]))]

Probabilistic PCA


library(pcaMethods)

Tissue_PSI_matrix_melt <- ME_cov_filtered[, c("ME", "FILE_NAME", "PSI") ]
Tissue_PSI_matrix_dcast <- reshape2::dcast(Tissue_PSI_matrix_melt, ME ~ FILE_NAME)
row.names(Tissue_PSI_matrix_dcast) <- Tissue_PSI_matrix_dcast$ME
Tissue_PSI_matrix_dcast <- data.matrix(Tissue_PSI_matrix_dcast)[,-1]


Tissue_PSI_matrix_dcast[Tissue_PSI_matrix_dcast=="NaN"] <- NA

dim(Tissue_PSI_matrix_dcast)

dim(Tissue_PSI_matrix_dcast[apply(Tissue_PSI_matrix_dcast, 1, function(x) length(which(is.na(x)))) < 271*0.9, ])

dim(Tissue_PSI_matrix_dcast[apply(Tissue_PSI_matrix_dcast, 1, function(x) length(which(is.na(x)))) < 289*0.9, ])

result <- pca(t(Tissue_PSI_matrix_dcast[apply(Tissue_PSI_matrix_dcast, 1, function(x) length(which(is.na(x)))) < 289*0.9, ]), method="ppca", nPcs=3, seed=123)
## Get the estimated complete observations
cObs <- completeObs(result)
## Plot the scores
plotPcs(result, type = "scores")




summary(result)

Tissue_PSI_matrix_dcast_ppca <- t(cObs)

Tissue_PSI_matrix_dcast_ppca[Tissue_PSI_matrix_dcast_ppca>1] <- 1
Tissue_PSI_matrix_dcast_ppca[Tissue_PSI_matrix_dcast_ppca<0] <- 0


##colnames(Tissue_PSI_matrix_dcast_ppca) <- as.character( paste(sep = " ", Tissues[colnames(Tissue_PSI_matrix_dcast_ppca)], Ages[colnames(Tissue_PSI_matrix_dcast_ppca)])) #To replase the file name by the biological sample name



#tissue_heatmap <- pheatmap::pheatmap(Tissue_PSI_matrix_dcast_ppca,  , fontsize = 4,  cutree_rows = 24, cutree_cols = 16, clustering_method = "ward.D2")

#Tissue_PSI_matrix_dcast_ppca <- t(cObs)

#Tissue_PSI_matrix_dcast_ppca[Tissue_PSI_matrix_dcast_ppca>1] <- 1
#Tissue_PSI_matrix_dcast_ppca[Tissue_PSI_matrix_dcast_ppca<0] <- 0


##colnames(Tissue_PSI_matrix_dcast_ppca) <- as.character( paste(sep = " ", Tissues[colnames(Tissue_PSI_matrix_dcast_ppca)], Ages[colnames(Tissue_PSI_matrix_dcast_ppca)])) #To replase the file name by the biological sample name



#tissue_heatmap <- pheatmap::pheatmap(Tissue_PSI_matrix_dcast_ppca,  , fontsize = 4,  cutree_rows = 24, cutree_cols = 17, clustering_method = "ward.D2")

hc_cols <- hclust(dist(t(Tissue_PSI_matrix_dcast_ppca)), method = "ward.D2")
hc_rows <- hclust(dist(Tissue_PSI_matrix_dcast_ppca), method = "ward.D2")
Tissues_name <- as.character(metadata$Biosample.term.name)
names(Tissues_name) <- as.character(metadata$File.accession)

Tissues_age <- as.character(metadata$Biosample.Age)
names(Tissues_age) <- as.character(metadata$File.accession)

Tissue_date <- as.character(metadata$Experiment.date.released)
names(Tissue_date) <- as.character(metadata$File.accession)
#Tissue_clusters <- cutree(hc_cols, k = 16)
#Tissue_clusters <- cbind(Tissue_clusters, Tissues_name[names(Tissue_clusters)], Tissues_age[names(Tissue_clusters)], Tissue_date[names(Tissue_clusters)]) 

#colnames(Tissue_clusters) <- c("cluster", "name", "age", "date")

#Tissue_clusters <- data.frame(Tissue_clusters)

##Tissue_clusters_sum[which(grepl("hindbrain|midbrain|forebrain|neural\ tube", Tissue_clusters_sum$name)), ]

#Tissue_clusters$name <- factor(Tissue_clusters$name, level=c( "skeletal muscle tissue", "heart", "thymus", "spleen", "liver",  "adrenal gland", "intestine", "stomach", "lung",  "kidney", "bladder", "limb", "embryonic facial prominence", "forebrain", "hindbrain", "midbrain", "neural tube", "whole cortex"))


#Tissue_clusters$age <- mapvalues(Tissue_clusters$age, 
#          from = c("10.5 day", "11.5 day", "12.5 day", "13.5 day", "14.5 day", "15.5 day", "16.5 day", "0 day", "8 week", "P0a", "P0b", "P110a", "P110b", "P15a", "P15b", "P30a", "P30b", "P4a", #"P4a", "P7a", "P7b", "21Ma", "21Mb", "E14.5", "E16.5", "P4b"),
#         to = c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21, 59, 21, 21, 131, 131, 36, 36, 41,41, 25, 25, 27,27, 651, 651, 14.5, 16.5, 25 ) )




#Tissue_clusters$age <- factor(Tissue_clusters$age, levels = as.character(sort(as.numeric(levels(Tissue_clusters$age)))))
Tissue_clusters <- cutree(hc_cols, k = 16)
Tissue_clusters <- cbind(Tissue_clusters, Tissues_name[names(Tissue_clusters)], Tissues_age[names(Tissue_clusters)], Tissue_date[names(Tissue_clusters)]) 

colnames(Tissue_clusters) <- c("cluster", "name", "age", "date")

Tissue_clusters <- data.frame(Tissue_clusters)

#Tissue_clusters_sum[which(grepl("hindbrain|midbrain|forebrain|neural\ tube", Tissue_clusters_sum$name)), ]

Tissue_clusters$name <- factor(Tissue_clusters$name, level=c( "skeletal muscle tissue", "heart", "thymus", "spleen", "liver",  "adrenal gland", "intestine", "stomach", "lung",  "kidney", "bladder", "limb", "embryonic facial prominence", "forebrain", "hindbrain", "midbrain", "neural tube", "whole cortex"))

#Tissue_clusters$age <- factor(Tissue_clusters$age, levels=c("10.5 day", "11.5 day", "12.5 day", "13.5 day", "14.5 day", "15.5 day", "16.5 day", "0 day", "8 week"))

Tissue_clusters$File.accession <- row.names(Tissue_clusters)


Tissue_clusters <- data.table(Tissue_clusters)


Tissue_clusters$age <- mapvalues(Tissue_clusters$age, 
          from = c("10.5 day", "11.5 day", "12.5 day", "13.5 day", "14.5 day", "15.5 day", "16.5 day", "0 day", "8 week", "P0a", "P0b", "P110a", "P110b", "P15a", "P15b", "P30a", "P30b", "P4a", "P4a", "P7a", "P7b", "21Ma", "21Mb", "E14.5", "E16.5", "P4b"),
          to = c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21, 59, 21, 21, 131, 131, 36, 36, 41,41, 25, 25, 27,27, 651, 651, 14.5, 16.5, 25 ) )

ME_clusters <- cutree(hc_rows, k = 24)

PCA_loadings <- data.frame(loadings(result))
PCA_loadings$ME <- row.names(PCA_loadings)


PCA_loadings <- data.table(PCA_loadings)
PCA_loadings[, `:=`(PC1=-PC1, PC2=-PC2)]


PCA_loadings$ME_cluster <- ME_clusters[PCA_loadings$ME]


PCA_loadings_stats <- PCA_loadings[ , .(PC1_mean=mean(PC1)) , by="ME_cluster"]
ME_cluster_loading_order <- PCA_loadings_stats[order(PC1_mean)]$ME_cluster

PCA_loadings$ME_cluster <- factor(PCA_loadings$ME_cluster , levels=ME_cluster_loading_order)


ggplot(PCA_loadings) +
  geom_boxplot(aes(as.factor(ME_cluster) , PC1))
ggplot(PCA_loadings) +
  geom_boxplot(aes(as.factor(ME_cluster) , PC2))
ggplot(PCA_loadings) +
  geom_boxplot(aes(as.factor(ME_cluster) , PC3))

PCA_loadings_stats <- PCA_loadings[ , .(PC1_mean=mean(PC1)) , by="ME_cluster"]

PCA_loadings_stats_PC2 <- PCA_loadings[ , .(PC2_mean=mean(PC2)) , by="ME_cluster"]



ME_cluster_loading_order <- PCA_loadings_stats[order(PC1_mean)]$ME_cluster

Neuronal Microexons

PCA_loadings_stats[abs(PC1_mean)>0.03, ][order(PC1_mean)]
PCA_loadings_stats_PC2[abs(PC2_mean)>0.03, ][order(-PC2_mean)]
Tissue_PSI_matrix_melt_ppca <- melt(Tissue_PSI_matrix_dcast_ppca)

colnames(Tissue_PSI_matrix_melt_ppca) <- c("ME", "FILE_NAME", "PSI")

ME_clusters_table <- data.frame(ME_clusters)

ME_clusters_table$ME <- row.names(ME_clusters_table)
ME_clusters_table <- data.table(ME_clusters_table)


ME_clusters_PSI <-  data.table(merge(Tissue_PSI_matrix_melt_ppca, ME_clusters_table , by=c("ME")))



fwrite( ME_clusters_PSI, "../../Paper/Jacob/ME_clusters_PSI.tvs", quote = FALSE, col.names = TRUE, sep="\t")

fwrite( ME_cluster_names, "../../Paper/Jacob/ME_cluster_names.tvs", quote = FALSE, col.names = TRUE, sep="\t")
ME_clusters_PSI$ME_clusters <- mapvalues(ME_clusters_PSI$ME_clusters, 
          from =1:18,
          to = c("I1", "E1", "E3", "I2", "N1", "M1", "N2", "NM3", "NM2", "N5", "NM1", "N3", "N4", "NN2", "E2", "I4", "I3", "NN1"))
Tissue_PSI_matrix_melt_ppca <- data.table(Tissue_PSI_matrix_melt_ppca)

Tissue_PSI_matrix_melt_ppca

PCA_loadings_stats <- PCA_loadings[ , .(PC1_mean=mean(PC1), PC2_mean=mean(PC2) ) , by="ME_cluster"]

#PCA_loadings_stats[, PC1_mean:=-PC1_mean]

PCA_loadings_stats[order(-PC1_mean)]
PCA_loadings_stats[order(PC2_mean)]

#PCA_loadings_stats_PC2[, PC2_mean:=-PC2_mean]
PCA_loadings_stats[order(PC2_mean)]



loading_threshold <- 0.010
loading_threshold_PC2 <- 0.010


Neuronal <- PCA_loadings_stats[ round(PC1_mean, 3) >  loading_threshold, ][order(-PC1_mean)]$ME_cluster
Muscular <- PCA_loadings_stats_PC2[round(PC2_mean, 3) < -loading_threshold_PC2, ][order(PC2_mean)]$ME_cluster

NonNeuronal<- PCA_loadings_stats[ round(PC1_mean, 3) <= -loading_threshold, ][order(PC1_mean)]$ME_cluster

#WeakNeuronal <- PCA_loadings_stats[  round(PC1_mean, 3) < loading_threshold & round(PC1_mean, 3) >=  0.01, ][order(PC1_mean)]$ME_cluster

N = 1 
NM = 1
NN = 1
M = 1
WN = 1

ME_cluster_names <- data.table()


for (ME_cluster in Neuronal){
  
  if (ME_cluster %in% Muscular){
    
    ME_cluster.name = paste0("NM", NM)
    ME_cluster.type = "Neuro-Muscular"
    
    ME_cluster_names = rbind(ME_cluster_names, cbind(ME_cluster, ME_cluster.name, ME_cluster.type  ))
    
    NM = NM + 1
    
  }

  
  else {
    
    ME_cluster.name = paste0("N", N)
    ME_cluster.type = "Neuronal"
    
    ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
    
    N = N + 1
    
  }
  
}


for (ME_cluster in NonNeuronal) {
  

  ME_cluster.name = paste0("NN", NN)
  ME_cluster.type = "Non-Neuronal"
  
  ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
  
  NN = NN + 1
  
  
}


#for (ME_cluster in WeakNeuronal) {
  

#  ME_cluster.name = paste0("WN", WN)
#  ME_cluster.type = "Weak-Neuronal"
  
#  ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
  
#  WN = WN + 1
  
  
#}



for (ME_cluster in Muscular){
  
  
  if ( (ME_cluster %in% ME_cluster_names$ME_cluster)==F) {
  
  
  ME_cluster.name = paste0("M", M)
  ME_cluster.type = "Muscular"
  
  ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
  
  M = M + 1
  
  }
  
  
  }


ME_cluster_names


ME_clusters_mean_PSIs <-  ME_clusters_PSI[, .(mean_PSI=mean(PSI), sd_PSI=sd(PSI)), by="ME_clusters" ]

ME_clusters_flat <- ME_clusters_mean_PSIs[ ! ME_clusters %in% ME_cluster_names$ME_cluster,  ]


E = 1
I = 1
O = 1 



for (ME_cluster in ME_clusters_flat[ mean_PSI <= 1/3,  ][order(mean_PSI)]$ME_clusters) {
  
  
  ME_cluster.name = paste0("E", E)
  ME_cluster.type = "Excluded"
  
  ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
  
  E = E + 1
  
  
} 



for (ME_cluster in ME_clusters_flat[ mean_PSI>=2/3,  ][order(-mean_PSI)]$ME_clusters) {
  
  
  ME_cluster.name = paste0("I", I)
  ME_cluster.type = "Included"
  
  ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
  
  I = I + 1
  
  
}




for (ME_cluster in ME_clusters_flat[ mean_PSI > 1/3  &  mean_PSI < 2/3  ,  ][order(mean_PSI)]$ME_clusters) {
  
  
  ME_cluster.name = paste0("O", O)
  ME_cluster.type = "Other"
  
  ME_cluster_names = rbind(ME_cluster_names,  cbind(ME_cluster, ME_cluster.name, ME_cluster.type ))
  
  O = O + 1
  
  
} 
ME_cluster_names

ME_cluster_names$ME_cluster <- as.numeric(ME_cluster_names$ME_cluster)

ME_cluster_names <- merge( x=ME_cluster_names, y=ME_clusters_mean_PSIs, by.x="ME_cluster", by.y="ME_clusters")

PCA_loadings_stats$ME_cluster <- as.numeric(as.character(PCA_loadings_stats$ME_cluster))

PCA_loadings_stats_PC2$ME_cluster <- as.numeric(as.character(PCA_loadings_stats_PC2$ME_cluster))


ME_cluster_names <- merge(ME_cluster_names, PCA_loadings_stats, by="ME_cluster")
#ME_cluster_names <- merge(ME_cluster_names, PCA_loadings_stats_PC2, by="ME_cluster")

ME_cluster_names$ME_cluster.type <- factor(ME_cluster_names$ME_cluster.type, levels = c("Excluded", "Included", "Neuronal",  "Non-Neuronal", "Muscular",  "Neuro-Muscular", "Other"))
Fig5.X.2 <- ggplot(ME_cluster_names) +
  geom_text(aes(x=PC1_mean, y=-PC2_mean, label = ME_cluster.name, colour = ME_cluster.type ), ) +
  xlab("Mean PC1 loading") +
  ylab("Mean PC2 loading") +
    theme(legend.position="top")


Fig5.X.2
Fig5.X.3 <- ggplot(ME_cluster_names) +
  geom_text(aes(x=mean_PSI, y=sd_PSI, label = ME_cluster.name, colour = ME_cluster.type ), ) +
  xlab("Mean PSI") +
  ylab("PSI standar deviation") +
    theme(legend.position="top") 
  


Fig5.X.3


ME_clusters.table <- cbind(ME_clusters, names(ME_clusters))
colnames(ME_clusters.table) <- c("ME_clusters", "ME")

ME_clusters.table <- data.table(ME_clusters.table)
ME_clusters.table$ME_clusters <- as.numeric(ME_clusters.table$ME_clusters)


ME_cluster_info <- merge(ME_clusters.table, ME_final[, c("ME", "len_micro_exon_seq_found", "U2_scores")], by="ME")
ME_cluster_info <- data.table(ME_cluster_info)


ME_cluster_info_by <- ME_cluster_info[ , .(asym = sum(len_micro_exon_seq_found %% 3),
                    mean_U2_score = mean(U2_scores),
                    total=.N
                    ), by="ME_clusters"  ]

ME_cluster_info_by[, symetrical_fraction:=(total-asym)/total]


ME_cluster_names <- merge(ME_cluster_names, ME_cluster_info_by, by.x="ME_cluster", by.y="ME_clusters")




#ME_cluster_info <- merge(ME_cluster_info_by[, .(ME_clusters=unique(ME_clusters)), by=ME], ME_final[, c("ME", "len_micro_exon_seq_found", "U2_scores")], by="ME")


 






Fig5.X.4 <- ggplot(ME_cluster_names) +
  geom_text(aes(x=symetrical_fraction, y=mean_U2_score, label = ME_cluster.name, colour = ME_cluster.type ), ) +
  xlab("In-frame microexon fraction") +
  ylab("Mean splicing strength") +
    theme(legend.position="top")


Fig5.X.4
  
ME_cluster_names[ ME_cluster.type=="Excluded", ]
ME_cluster_names[ ME_cluster.type=="Included", ]
ME_cluster_names[ ME_cluster.type=="Neuronal", ]
ME_cluster_names[ ME_cluster.type=="Neuro-Muscular", ]
ME_cluster_names[ ME_cluster.type=="Neuronal", ]
ME_cluster_names[ ME_cluster.type=="Included", ]
ME_cluster_names[ ME_cluster.type=="Excluded", ]
ME_cluster_names[ ME_cluster.type=="Included", ]
ME_cluster_names[ ME_cluster.type=="Other", ]

levels(factor(ME_cluster_names$ME_cluster.type))
ME_cluster_names.levels <- c()

for (i in levels(factor(ME_cluster_names$ME_cluster.type))){
  
  
  
  
  ME_cluster_names.levels<- c(ME_cluster_names.levels, ME_cluster_names[ME_cluster.type==i, ME_cluster.name])
  
  
}
Fig5.X.1.legend
TableGrob (5 x 5) "guide-box": 2 grobs
                                    z     cells                  name           grob
99_4000b8f4423e777ea3de92bc832bc4ce 1 (3-3,3-3)                guides gtable[layout]
                                    0 (2-4,2-4) legend.box.background zeroGrob[NULL]

Fig5.X.plots <- plot_grid(Fig5.X.1 + theme(legend.position="none"), 
                    Fig5.X.2 + theme(legend.position="none"), 
                    Fig5.X.3 + theme(legend.position="none"), 
                    Fig5.X.4 + theme(legend.position="none"), 
                    nrow =1,
                    rel_widths = c(1.7,1,1,1),
                    labels = "AUTO" )


Fig5.X <- plot_grid(Fig5.X.1.legend, Fig5.X.plots, ncol = 1, rel_heights = c(0.2, 1))

Fig5.X
ME_clusters.names <- data.table(ME_clusters)
ME_clusters.names$ME <- names(ME_clusters)
ME_clusters.names <- merge(ME_clusters.names,  ME_cluster_names[, c("ME_cluster", "ME_cluster.name")],  by.x="ME_clusters", by.y="ME_cluster")
ME_final.ME_clusters <- merge(ME_final, ME_clusters.names, by="ME")

ME_cluster.conservation <- ME_final.ME_clusters[ mean_conservations_vertebrates!="None" ,  .(mean_conservation=mean(as.numeric(mean_conservations_vertebrates)))  , by=c("ME_clusters", "ME_cluster.name")]


ME_cluster_names <-  merge(ME_cluster_names, ME_cluster.conservation,  by.x=c("ME_cluster", "ME_cluster.name"), by.y=c("ME_clusters", "ME_cluster.name"))

round(cor(ME_cluster_names$symetrical_fraction, ME_cluster_names$mean_conservation, method="pearson"), 2)


ggplot(ME_cluster_names, aes(x=symetrical_fraction, y=mean_conservation)) +
  geom_smooth(method=lm, linetype="dashed") +
  geom_text(aes( label = ME_cluster.name, colour = ME_cluster.type ) ) +
  xlab("In-frame microexon fraction") +
  ylab("Mean Phylop conservation score") +
  theme(legend.position="top") +
 labs(color = "Microexon cluster class")

some_ME_clusters <-c(
ME_clusters[ME_clusters==1][1],
ME_clusters[ME_clusters==2][1],
ME_clusters[ME_clusters==3][1],
ME_clusters[ME_clusters==4][1],
ME_clusters[ME_clusters==5][1],
ME_clusters[ME_clusters==6][1],
ME_clusters[ME_clusters==7][1],
ME_clusters[ME_clusters==8][1],
ME_clusters[ME_clusters==9][1],
ME_clusters[ME_clusters==10][1],
ME_clusters[ME_clusters==11][1],
ME_clusters[ME_clusters==12][1],
ME_clusters[ME_clusters==13][1],
ME_clusters[ME_clusters==14][1],
ME_clusters[ME_clusters==15][1],
ME_clusters[ME_clusters==16][1],
ME_clusters[ME_clusters==17][1],
ME_clusters[ME_clusters==18][1],
ME_clusters[ME_clusters==19][1],
ME_clusters[ME_clusters==20][1],
ME_clusters[ME_clusters==21][1],
ME_clusters[ME_clusters==22][1],
ME_clusters[ME_clusters==23][1],
ME_clusters[ME_clusters==24][1]

)


col_ann <- data.frame(  Tissue_clusters$cluster, row.names=Tissue_clusters$File.accession)
colnames(col_ann) <- "Tissue clusters"

rownames(col_ann) <- Tissue_clusters$File.accession



tissue_cluster_type = data.frame(cluster=c(1, 6, 8, 14, 12, 7, 15, 5, 11, 4, 9, 3, 13, 10, 16, 2), 
                                 `Tissue cluster type`=c("Non-neuronal",
                                                "Non-neuronal",
                                                "Non-neuronal",
                                                "Non-neuronal",
                                                "Embryonic neuronal",
                                                "Adrenal gland",
                                                "Skeletal muscle",
                                                "Heart",
                                                "Embryonic neuronal",
                                                "Embryonic neuronal",
                                                "Embryonic neuronal",
                                                "Postnatal neuronal",
                                                "Embryonic neuronal",
                                                "Postnatal neuronal",
                                                "Postnatal neuronal",
                                                "Postnatal neuronal"))

col_ann$File <- rownames(col_ann)
col_ann <- merge(col_ann, tissue_cluster_type, by.x="Tissue clusters",by.y="cluster")
rownames(col_ann) <- col_ann$File

colnames(col_ann) <- c("Tissue clusters", "File", "Tissue cluster type")



ann_colors = list(
    cluster = c(black="black"),
    `Tissue.cluster.type` =  c(`Adrenal gland` = "#B79F00",
                      `Skeletal muscle` = "#00BFC4",
                      `Heart` = "#F564E3",
                      `Non-neuronal` = "#A58AFF",
                      `Embryonic neuronal` = "#00BA38",
                      `Postnatal neuronal` = "#F8766D"
                      ),
    GeneClass = c(Path1 = "#7570B3", Path2 = "#E7298A", Path3 = "#66A61E")
)

col_ann$`Tissue cluster type` <- factor(col_ann$`Tissue cluster type` , levels = c("Adrenal gland", "Skeletal muscle", "Heart", "Non-neuronal", "Intermediate", "Embryonic neuronal", "Postnatal neuronal"))

fake_plot <- ggplot(col_ann, aes(as.numeric(`Tissue clusters`), `Tissue clusters`, fill=`Tissue cluster type` )) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values=c("#B79F00", "#00BFC4", "#F564E3", "#A58AFF", "#00BA38", "#F8766D" ), name= "Tissue cluster type") +
   theme(legend.position="top", legend.justification="center") +
  guides(fill=guide_legend(nrow=1,byrow=TRUE)) 


fake_plot.legend <- get_legend(fake_plot)

library(rlang)



#rownames(col_ann) <- rownames(Tissue_clusters)

Tissue_PSI_matrix_dcast_ppca <- t(cObs)

Tissue_PSI_matrix_dcast_ppca[Tissue_PSI_matrix_dcast_ppca>1] <- 1
Tissue_PSI_matrix_dcast_ppca[Tissue_PSI_matrix_dcast_ppca<0] <- 0


Tissue_PSI_matrix_dcast_ppca_heatmap <- duplicate(Tissue_PSI_matrix_dcast_ppca)


some_ME_clusters_space <- paste("      ", some_ME_clusters, sep = "") 
names(some_ME_clusters_space) <- names(some_ME_clusters)

row.names(Tissue_PSI_matrix_dcast_ppca_heatmap) <- some_ME_clusters_space[row.names(Tissue_PSI_matrix_dcast_ppca_heatmap)]



#tissue_heatmap <- pheatmap::pheatmap(Tissue_PSI_matrix_dcast_ppca_heatmap,  , fontsize = 10 ,  cutree_rows = 24, cutree_cols = 16, clustering_method = "ward.D2" , show_colnames=FALSE, annotation_col= col_ann, annotation_names_col=FALSE, treeheight_col=200, treeheight_row=100)

plot_grid(fake_plot.legend)



PCA <- data.frame(scores(result))





PCA$File.accession <- row.names(PCA)
PCA <- data.table(PCA)
PCA <- PCA[, `:=`(PC1=-PC1) ]


PCA <- merge(Tissue_clusters, PCA, by="File.accession")

PCA$age <- as.numeric(as.character(PCA$age))
PCA_stats <- PCA[ , .(mean_PC1=mean(PC1)) , by=c("name", "age")]


Sup_PCA_age.B <- ggplot() +
  geom_jitter(data = PCA[name %in% c("forebrain", "midbrain", "hindbrain", "neural tube"), ],  aes(age, PC1, colour=name), width=0.1, height = 0 ) +
  geom_line(data = PCA_stats[name %in% c("forebrain", "midbrain", "hindbrain", "neural tube"), ], aes(age, mean_PC1, group=name, colour=name)) +
  labs(colour="Neural tissue")
PCA_stats<- PCA[ , .(mean_PC1=mean(PC1)) , by=c("name", "age")]

Fig4.C <- ggplot() +
  geom_line(data = PCA_stats[name %in% c("forebrain", "midbrain", "hindbrain", "neural tube", "whole cortex"), ], aes(log(age), mean_PC1, group=name, colour=name)) +
  geom_point(data = PCA_stats[name %in% c("forebrain", "midbrain", "hindbrain", "neural tube", "whole cortex"), ], aes(log(age), mean_PC1, group=name, colour=name)) +
  xlab("log(DPC)") +
  ylab("Mean PC1") +
  xlim(c(log(10), log(50))) +
  theme(legend.position="top") +
  scale_color_discrete(name="Neuronal tissue", labels=c("Forebrain", "Hindbrain", "Midbrain", "Neural tube", "Whole cortex"))
  

Fig4.C

PCA_stats_PC2<- PCA[ name=="heart" , .(mean_PC2=mean(PC2)) , by=c("name", "age")]
PC1_cluster <- PCA[ , .(PC1=mean(PC1))  , by=cluster]

tissue_cluster_PCA <- factor(PC1_cluster[order(PC1)]$cluster, levels = PC1_cluster[order(PC1)]$cluster)


my_col <- get_colors(tissue_cluster_PCA, group.col=colorRampPalette(colors = c("black",  "purple", "blue", "seagreen", "gold", "red"))(14))

PCA$cluster <- factor(PCA$cluster, levels = PC1_cluster[order(PC1)]$cluster)


Sup_PCA.A <- ggplot(PCA) +
  geom_text(aes(PC1, PC2, label=cluster, colour=cluster) ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none")

Sup_PCA.B <-  ggplot(PCA) +
  geom_text(aes(PC1, PC3, label=cluster, colour=cluster) ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none")

Sup_PCA.C <-  ggplot(PCA) +
  geom_text(aes(PC2, PC3, label=cluster, colour=cluster) ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none")

library(rlang)

PCA_plot <- duplicate(PCA)


PCA_plot[name=="heart", group:="Heart"]
PCA_plot[name=="skeletal muscle tissue", group:="SKM"]
PCA_plot[name=="adrenal gland", group:="Adrenal Gland"]
PCA_plot[name=="whole cortex", group:="Cortex"]
PCA_plot[name %in% c("forebrain", "midbrain", "hindbrain", "neural tube") , group:="Neural"]

PCA_plot$age <- as.numeric(as.character(PCA_plot$age ))


PCA_plot[!name %in% c("forebrain", "midbrain", "hindbrain", "neural tube", "whole cortex", "heart","skeletal muscle tissue", "adrenal gland"), `:=`(group="Other", age=NA )]

ggplot(PCA_plot[name!="whole cortex",]) +
  geom_point(aes(PC1, PC2, colour=age, shape=group ) ) +
  geom_point(aes(PC1, PC2, colour=age, shape=group ) ) +
  scale_color_gradient(low="blue",  high="red")

library(stringr)

Sup_PCA_age.A <- ggplot() +
  geom_point(data=PCA_plot[group=="Other"], aes(PC1, PC2, colour=age ), alpha=0.5) +
  geom_text(data=PCA_plot[group!="Other" & name!="whole cortex"], aes(PC1, PC2, colour=age, label=str_sub(group, 1,1) ), size=3.5, alpha=0.5 ) +
  scale_color_gradient(low="blue",  high="red") +
  labs(colour="Embryonic stage (DPC)")
ggplot() +
  geom_point(data=PCA_plot[group=="Other"], aes(PC1, PC2, colour=log(age) ), alpha=0.8) +
  geom_text(data=PCA_plot[group!="Other"], aes(PC1, PC2, colour=log(age), label=str_sub(group, 1,1) ), size=3.5, alpha=0.8 ) +
  scale_color_gradient2(low="blue", mid="gold",  high="red", midpoint = 3.7)
plot_grid(Sup_PCA_age.A, Sup_PCA_age.B, labels = "AUTO")


PCA_batch <- merge(PCA, PCA[, .N, by=c("date")][, .(date, batch=frank(date) )], by="date")

my_col_date <- get_colors(tissue_cluster_PCA, group.col=colorRampPalette(colors = c("black",  "purple", "blue", "seagreen", "gold", "red"))(10))





Sup_PCA.D <-  ggplot(PCA_plot) +
  geom_text(aes(PC1, PC2, label=str_sub(group, 1,1) , colour=factor(cluster) ) ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none")


Sup_PCA.E <-  ggplot(PCA_plot) +
  geom_text(aes(PC1, PC3, label=str_sub(group, 1,1) , colour=factor(cluster) ) ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none")

Sup_PCA.F <-  ggplot(PCA_plot) +
  geom_text(aes(PC2, PC3, label=str_sub(group, 1,1) , colour=factor(cluster) ) ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none")




Sup_PCA.G <-  ggplot(PCA_batch) +
  geom_text(aes(PC1, PC2, label=cluster, colour=factor(batch) ) ) +
  scale_color_manual(values=my_col_date) + 
  theme(legend.position = "none")


Sup_PCA.H <-  ggplot(PCA_batch) +
  geom_text(aes(PC1, PC3, label=cluster, colour=factor(batch) ) ) +
  scale_color_manual(values=my_col_date) + 
  theme(legend.position = "none")


Sup_PCA.I <-  ggplot(PCA_batch) +
  geom_text(aes(PC2, PC3, label=cluster, colour=factor(batch) ) ) +
  scale_color_manual(values=my_col_date) + 
  theme(legend.position = "none")
plot_grid(Sup_PCA.A, Sup_PCA.B, Sup_PCA.C, Sup_PCA.D, Sup_PCA.E, Sup_PCA.F, Sup_PCA.G, Sup_PCA.H, Sup_PCA.I, labels="AUTO" )
#Tissue_clusters <- cutree(hc_cols, k = 18)
#Tissue_clusters <- cbind(Tissue_clusters, Tissues_name[names(Tissue_clusters)], Tissues_age[names(Tissue_clusters)], Tissue_date[names(Tissue_clusters)]) 

#colnames(Tissue_clusters) <- c("cluster", "name", "age", "date")

#Tissue_clusters <- data.frame(Tissue_clusters)

#Tissue_clusters_sum[which(grepl("hindbrain|midbrain|forebrain|neural\ tube", Tissue_clusters_sum$name)), ]

#Tissue_clusters$name <- factor(Tissue_clusters$name, level=c( "skeletal muscle tissue", "heart", "thymus", "spleen", "liver",  "adrenal gland", "intestine", "stomach", "lung",  "kidney", "bladder", "limb", "embryonic facial prominence", "forebrain", "hindbrain", "midbrain", "neural tube", "whole cortex"))


#Tissue_clusters$age <- factor(Tissue_clusters$age, levels = as.character(sort(as.numeric(levels(Tissue_clusters$age)))))


#Tissue_clusters_sum <- Tissue_clusters %>% group_by(cluster, name, age ) %>% summarise(count = n())

Tissue_clusters_DT <- data.table(Tissue_clusters)
Tissue_clusters_sum <- Tissue_clusters_DT[, .(count=.N) , by=c("cluster", "name", "age" )]

Tissue_clusters_sum$age <- factor(Tissue_clusters_sum$age, levels= sort(as.numeric(as.character(levels(Tissue_clusters_sum$age)))) )


## NA ###

Tissue_clusters_sum$cluster <- factor(Tissue_clusters_sum$cluster , levels =PCA[, mean(PC1), by="cluster" ][order(V1)]$cluster)


Tissue_clusters_sum <- merge(Tissue_clusters_sum, PCA[, .(mPC1=mean(PC1), mPC2=mean(PC2), mPC3=mean(PC3) ), by="cluster" ][order(mPC1)], by="cluster")
Tissue_clusters_sum[, `:=`(mean_PC1=round(mPC1, 2),mean_PC2=round(mPC2, 2), mean_PC3=round(mPC3, 2))  ]

Sup.Tissue_clusters.b.pre <- ggplot( Tissue_clusters_sum, aes(age, name) ) +
  geom_tile(aes(fill = count)) +
  scale_fill_gradient(low="grey", high="red")+
  facet_grid(. ~ cluster + mean_PC1 + mean_PC2 + mean_PC3, labeller = label_parsed ) +
  theme_bw()+
  labs(fill = "Sample count") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))


Sup.Tissue_clusters.c <- plot_grid(fake_plot.legend, Sup.Tissue_clusters.b.pre, ncol=1, rel_heights = c(0.1, 1) )
Sup.Tissue_clusters.c

library(ggrepel)

PCA_plot[, `:=`(mPC1=mean(PC1), mPC2=mean(PC2)), by="cluster" ]




Sup.Tissue_clusters.a <- ggplot(PCA_plot) +
  geom_point(aes(PC1, PC2 , colour=factor(cluster) ),  alpha=0.3 ) +
  stat_ellipse(aes(PC1, PC2 , colour=factor(cluster) )) +
  geom_text_repel(data=PCA_plot[, .(mPC1=mean(PC1), mPC2=mean(PC2)), by="cluster" ],
                  aes(mPC1, mPC2, label=cluster), size=7, point.padding = NA, fontface = "bold" ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none") 

Sup.Tissue_clusters.b <- ggplot(PCA_plot) +
  geom_point(aes(PC1, PC3 , colour=factor(cluster) ),  alpha=0.3 ) +
  stat_ellipse(aes(PC1, PC3 , colour=factor(cluster) )) +
  geom_text_repel(data=PCA_plot[, .(mPC1=mean(PC1), mPC2=mean(PC3)), by="cluster" ],
                  aes(mPC1, mPC2, label=cluster), size=7, point.padding = NA, fontface = "bold" ) +
  scale_color_manual(values=my_col) + 
  theme(legend.position = "none") 
  

Sup.Tissue_clusters.ab <- plot_grid(Sup.Tissue_clusters.a, Sup.Tissue_clusters.b, labels = c("E", "F"))
Sup.Tissue_clusters.ab
Fig4.EFG <- plot_grid( Sup.Tissue_clusters.ab, Sup.Tissue_clusters.c, ncol=1, labels=c("", "G"), rel_heights = c(0.8, 1) )
Fig4.EFG
Fig.4A <- ggplot(PCA_plot) +
  geom_point(aes(PC1, PC2, colour=log(age), shape=group ), size=3 , alpha=0.7) +
  scale_color_gradient2(low="blue", mid="yellow",  high="red", midpoint = 3.7, name="ln(Age)") +
  scale_shape(name="Tissue") +
  theme(legend.position="top") 

plot_grid(Fig4, Fig4.EFG, ncol=1, rel_heights = c(2, 1))

Here we sorted microexons by PC1 loadings, but we fliped PC1 we cocider the values as -1 PCA loading on our paper

Loading therhold is abs(0.035)


ME_Tissues_clusters_PSI <- merge(ME_clusters_PSI, Tissue_clusters, by.x="FILE_NAME", by.y = "File.accession")
ME_Tissues_clusters_PSI$cluster <- factor(ME_Tissues_clusters_PSI$cluster, levels = levels(Tissue_clusters_sum$cluster))
ME_Tissues_clusters_PSI <- merge( ME_Tissues_clusters_PSI,  ME_cluster_names[ , c("ME_cluster", "ME_cluster.name")], by.x="ME_clusters", by.y="ME_cluster")

ME_Tissues_clusters_PSI$ME_cluster.name <- factor(ME_Tissues_clusters_PSI$ME_cluster.name, levels = sort(as.character(unique(ME_Tissues_clusters_PSI$ME_cluster.name))))

ME_Tissues_clusters_PSI_sub <- ME_Tissues_clusters_PSI[ME_cluster.name %in%  ME_cluster_names[ME_cluster.type %in% c("Neuronal", "Neuro-Muscular", "Muscular",  "Non-Neuronal"), ME_cluster.name], ]
ME_Tissues_clusters_PSI_non_neuronal <- ME_Tissues_clusters_PSI_sub[cluster %in% c(1, 8, 6, 7, 15, 5) , ]

ME_Tissues_clusters_PSI_non_neuronal$cluster <- mapvalues(ME_Tissues_clusters_PSI_non_neuronal$cluster,
          from = c(1, 8, 6, 7, 15, 5),
          to = c( "C1", "C8", "C6", "C7", "C15", "C5") )


ME_Tissues_clusters_PSI_non_neuronal$cluster <- factor(ME_Tissues_clusters_PSI_non_neuronal$cluster, levels=c( "C1", "C8", "C6", "C7", "C15", "C5"))

ME_Tissues_clusters_PSI_non_neuronal_by_ME <- ME_Tissues_clusters_PSI_non_neuronal[ , .(PSI_mean=mean(PSI)), by=c("ME", "cluster", "ME_cluster.name") ]
ME_Tissues_clusters_PSI_non_neuronal_by_ME_cluster <- ME_Tissues_clusters_PSI_non_neuronal[ , .(PSI_mean=mean(PSI)), by=c( "cluster", "ME_cluster.name") ]



  
ggplot( ) +
        geom_line(data= ME_Tissues_clusters_PSI_non_neuronal_by_ME, aes(factor(cluster), PSI_mean, group=ME), colour="grey") +
        facet_grid( ME_cluster.name ~ .)
  

TOTAL.ME_level <- rbind(
ME_Tissues_clusters_PSI_non_neuronal_by_ME[ , .(ME, age.name=cluster, ME_cluster.name, PSI_mean) ], 
ME_Tissues_clusters_PSI_neuronal_by_ME )

TOTAL.cluster_level <-  rbind(
ME_Tissues_clusters_PSI_neuronal_by_ME_cluster,
ME_Tissues_clusters_PSI_non_neuronal_by_ME_cluster[ , .(age.name=cluster, ME_cluster.name,  name="Non neuronal", PSI_mean) ] )


TOTAL.cluster_level$name <- mapvalues(TOTAL.cluster_level$name,
          from = c("forebrain", "midbrain", "hindbrain", "neural tube", "whole cortex"),
          to = c("Forebrain", "Midbrain", "Hindbrain", "Neural tube", "Whole cortex") )


TOTAL.cluster_level$name <- factor(TOTAL.cluster_level$name, levels=c("Non neuronal", "Forebrain", "Midbrain", "Hindbrain", "Neural tube", "Whole cortex") )



Fig5.A <- ggplot( ) +
        geom_line(data= TOTAL.ME_level, aes(factor(age.name), PSI_mean, group=ME), colour="grey", alpha=0.5) +
        geom_line(data = TOTAL.cluster_level, aes(factor(age.name), PSI_mean, group=name, colour=name ), size=1.2 ) +
        facet_grid( ME_cluster.name ~ .) +
        labs(colour = "Mean PSI by") +
        ylab("PSI") +
        xlab("") +
        theme(panel.background = element_rect(fill = 'white', colour = 'black')) +
        theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")

Fig5.A



ggplot( ) +
        geom_line(data= TOTAL.ME_level, aes(factor(age.name), PSI_mean, group=ME), colour="grey", alpha=0.5) +
        geom_line(data = TOTAL.cluster_level, aes(factor(age.name), PSI_mean, group=name, colour=name ), size=1.2 ) +
        facet_grid( ME_cluster.name ~ .) +
        labs(colour = "Mean PSI by") +
        ylab("PSI") +
        xlab("") +
        theme(panel.background = element_rect(fill = 'white', colour = 'black')) +
        theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")

Whippet-delta




file.remove('./whippet_delta.yaml')



write.table( "whippet_delta:", file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)


wcontrol <- paste(Tissue_clusters[cluster %in% c(1, 8, 6),  ]$File.accession, collapse=",")


for (i in c("forebrain", "midbrain", "hindbrain", "neural tube")){
  
  for (a in c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21)) {
    
    if (length(Tissue_clusters[name==i & age==a , ]$File.accession)>=4){
    
      name = paste0("    ", gsub(" ", "_", paste("control_vs", i, paste0(a, ":"), sep=" " )))
      A =  paste0("        A : ", wcontrol )
      B =  paste0("        B : ",  paste(Tissue_clusters[name==i & age==a , ]$File.accession, collapse=","))
      
      write.table(name, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
      write.table( A, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
      write.table( B, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    
    }

  }
  
}


signal = c("hindbrain", "neural tube")

for (a in c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21)) {
    
  if (length(Tissue_clusters[name %in% signal & age==a , ]$File.accession)>=4){
    
    name = paste0("    ", gsub(" ", "_", paste("control_vs", paste(signal, collapse="-" ), paste0(a, ":"), sep=" " )))
    A =  paste0("        A : ", wcontrol )
    B =  paste0("        B : ",  paste(Tissue_clusters[name %in% signal & age==a , ]$File.accession, collapse=","))
      
    write.table(name, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( A, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( B, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)

  }
}
 

signal = c("hindbrain", "neural tube", "midbrain")

for (a in c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21)) {
    
  if (length(Tissue_clusters[name %in% signal & age==a , ]$File.accession)>=4){
    
    name = paste0("    ", gsub(" ", "_", paste("control_vs", paste(signal, collapse="-" ), paste0(a, ":"), sep=" " )))
    A =  paste0("        A : ", wcontrol )
    B =  paste0("        B : ",  paste(Tissue_clusters[name %in% signal & age==a , ]$File.accession, collapse=","))
      
    write.table(name, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( A, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( B, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)

  }
}


signal = c("hindbrain", "neural tube", "midbrain","forebrain")

for (a in c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21)) {
    
  if (length(Tissue_clusters[name %in% signal & age==a , ]$File.accession)>=4){
    
    name = paste0("    ", gsub(" ", "_", paste("control_vs", paste(signal, collapse="-" ), paste0(a, ":"), sep=" " )))
    A =  paste0("        A : ", wcontrol )
    B =  paste0("        B : ",  paste(Tissue_clusters[name %in% signal & age==a , ]$File.accession, collapse=","))
      
    write.table(name, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( A, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( B, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)

  }
}



signal = c("adrenal gland", "skeletal muscle tissue", "heart")

for (tissue in signal) {
    
  if (length(Tissue_clusters[name==tissue, ]$File.accession)>=4){
    
    name = paste0("    ", gsub(" ", "_", paste("control_vs", paste0(tissue, ":"), sep=" " )))
    A =  paste0("        A : ", wcontrol )
    B =  paste0("        B : ",  paste(Tissue_clusters[name==tissue, ]$File.accession, collapse=","))
      
    write.table(name, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( A, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
    write.table( B, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)

  }
}


name= "    hindbrain_neural_tube_21_vs_forebrain_midbrain_21:"
A = paste0("        A : ",  paste(Tissue_clusters[age==21 & name %in% c("hindbrain", "neural tube"), ]$File.accession, collapse=","))
B = paste0("        B : ",  paste(Tissue_clusters[age==21 & name %in% c("forebrain", "midbrain"), ]$File.accession, collapse=","))

write.table(name, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
write.table( A, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)
write.table( B, file="./whippet_delta.yaml", append=TRUE, quote = FALSE, row.names = FALSE, col.names = FALSE)

Whippet ENCODE


Get_delta_table <- function( signal, ages, path, extension ){

  Delta_group <- data.table()
  
  
  for (a in ages) {
      
    if (length(Tissue_clusters[name %in% signal & age==a , ]$File.accession)>=4){
      
      name = gsub(" ", "_", paste("control_vs", paste(signal, collapse="-" ), a, sep=" " ))
  
      delta <- fread ( paste0(path, name, extension))
      
      delta$age <- a
      
      Delta_group <- rbind(Delta_group, delta )
      
    }
  
  }
  return(Delta_group)    
}
length(unique(Delta_HNM_merge[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9, exon_ID]))
[1] 421

Delta_F_whippet <- Get_delta_table( c("forebrain"),
                                      c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21),
                                      "~/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/",
                                      ".diff.microexons")


Delta_F_ME <- Get_delta_table( c("forebrain"),
                                      c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21),
                                      "~/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/",
                                      ".diff.ME.microexons")


Delta_F_merge <- merge(Delta_F_whippet, Delta_F_ME, by=c("exon_ID", "age"))

length(unique(Delta_F_merge[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9, exon_ID]))

Sup_vulcano.B <- ggplot( ) +
  geom_point(data=Delta_HNM_ME, aes(-DeltaPsi, Probability)) +
  geom_point(data=Delta_HNM_ME[ DeltaPsi>=0.1 &  Probability >= 0.9 , ], aes(-DeltaPsi, Probability), color="brown") +
  geom_point(data=Delta_HNM_ME[ DeltaPsi<(-0.1) &  Probability >= 0.9 , ], aes(-DeltaPsi, Probability), color="darkgreen") +
  geom_text(data=Delta_HNM_ME[ DeltaPsi>=0.1 &  Probability >= 0.9 , .N, by="age"], aes(-0.85, 0.9, label=N), colour = "brown", fontface = "bold", size=5) +
  geom_text(data=Delta_HNM_ME[ DeltaPsi<(-0.1) &  Probability >= 0.9  , .N, by="age"], aes(0.85, 0.9, label=N), colour = "darkgreen", fontface = "bold", size=5) +
  facet_grid(. ~ age) +
  xlim(c(-1,1)) +
  xlab("Delta PSI") +
  theme_bw()


Sup_vulcano.A <- ggplot( ) +
  geom_point(data=Delta_HNM_whippet, aes(-DeltaPsi, Probability)) +
  geom_point(data=Delta_HNM_whippet[ DeltaPsi>=0.1 &  Probability >= 0.9 , ], aes(-DeltaPsi, Probability), color="brown") +
  geom_point(data=Delta_HNM_whippet[ DeltaPsi<(-0.1) &  Probability >= 0.9 , ], aes(-DeltaPsi, Probability), color="darkgreen") +
  geom_text(data=Delta_HNM_whippet[ DeltaPsi>=0.1 &  Probability >= 0.9 , .N, by="age"], aes(-0.85, 0.9, label=N), colour = "brown", fontface = "bold", size=5) +
  geom_text(data=Delta_HNM_whippet[ DeltaPsi<(-0.1) &  Probability >= 0.9  , .N, by="age"], aes(0.85, 0.9, label=N), colour = "darkgreen", fontface = "bold", size=5) +  
  facet_grid(. ~ age) +
  xlim(c(-1,1)) +
  xlab("Delta PSI") +
  theme_bw()

whipet vs ME

ME_AD_AA <- fread("../Final_Report/Reps/Rep1/Whippet/Quant/ME_AD_AA.txt")

Delta_HNM_total <-  merge(
Delta_HNM_whippet[ , c("exon_ID", "Gene", "Node", "Coord", "Strand", "Type", "DeltaPsi", "Probability", "age")],
Delta_HNM_ME[ , c("exon_ID", "Gene", "Node", "Coord", "Strand", "Type", "DeltaPsi", "Probability", "age")],

by=c("exon_ID", "Gene", "Node", "Coord", "Strand", "Type",  "age"))

Delta_HNM_total[ , cor(DeltaPsi.x, DeltaPsi.y, method="pearson") , by=age ]

Delta_HNM_total[paste( exon_ID, age, sep="|") %in% total_diff_HNM , cor(DeltaPsi.x, DeltaPsi.y, method="pearson") , by=age ]


Delta_HNM_total[, Node_type:=paste0("m", Type)]
Delta_HNM_total[ Type=="CE" & exon_ID %in% ME_AD_AA[ Type=="AA" & exon_type=="E" ,  exon_ID  ], Node_type:="mCE_AA" ]
Delta_HNM_total[ Type=="CE" & exon_ID %in% ME_AD_AA[ Type=="AA" & exon_type=="ME" ,  exon_ID  ], Node_type:="mCE_mAA" ]
Delta_HNM_total[ Type=="CE" & exon_ID %in% ME_AD_AA[ Type=="AD" & exon_type=="E" ,  exon_ID  ], Node_type:="mCE_AD" ]
Delta_HNM_total[ Type=="CE" & exon_ID %in% ME_AD_AA[ Type=="AD" & exon_type=="ME" ,  exon_ID  ], Node_type:="mCE_mAD" ]

whippet_ME_corr <- merge( Delta_HNM_total[ , cor(DeltaPsi.x, DeltaPsi.y, method="pearson") , by=age ], 
                          Delta_HNM_total[ (abs(DeltaPsi.x)>=0.1 & Probability.x>=0.9) |(abs(DeltaPsi.y)>=0.1 & Probability.y>=0.9)  ,
                                           cor(DeltaPsi.x, DeltaPsi.y, method="pearson") , by=age ], 
                          by="age")

#whippet_ME_corr.types <- merge( Delta_HNM_total[ , .(N=.N, cor.total=(cor(DeltaPsi.x, DeltaPsi.y, method="pearson"))) , by=c("age", "Node_type") ], 
#                          Delta_HNM_total[paste( exon_ID, age, sep="|") %in% total_diff_HNM , .(N=.N, cor.sig=(cor(DeltaPsi.x, DeltaPsi.y, method="pearson"))) , by=c("age", #"Node_type") ],
#                          by=c("age", "Node_type"))



whippet_ME_corr.types <- Delta_HNM_total[ , .(N=.N, cor.total=(cor(DeltaPsi.x, DeltaPsi.y, method="pearson"))) , by=c("age", "Node_type") ]


#whippet_ME_corr.types[N.y<5, cor.sig:=NA]

#whippet_ME_corr.types.melted <- rbind(whippet_ME_corr.types[, .(age, Node_type, N=N.x, cor=cor.total, Group="Total") ],
 #     whippet_ME_corr.types[, .(age, Node_type, N=N.y, cor=cor.sig, Group="Significant") ])

Delta_HNM_total$Node_type <- factor(Delta_HNM_total$Node_type , levels = c("mCE", "mAA", "mAD", "mCE_mAA", "mCE_mAD", "mCE_AA", "mCE_AD"))

whippet_ME_corr.types$Node_type <- factor(whippet_ME_corr.types$Node_type , levels = c("mCE", "mAA", "mAD", "mCE_mAA", "mCE_mAD", "mCE_AA", "mCE_AD"))


Sup_vulcano.D <- ggplot(whippet_ME_corr.types[N>5, ]) +
  geom_boxplot(aes(Node_type, cor.total, fill=Node_type)) +
  scale_fill_discrete(name = "Microexon node type") +
  xlab("") +
  ylab("Delta PSI correlation") +
  theme_bw() +
  theme(legend.position = "top") +
  theme(axis.text.x = element_text(angle = 45, vjust = 0.6)) +
     guides(fill = guide_legend(nrow = 1))

Sup_vulcano.C <- ggplot(Delta_HNM_total[!is.na(Node_type)] ) +
  geom_bar(aes(as.factor(age), fill=Node_type), stat="count" ) +
  geom_text( data=Delta_HNM_total[ , .(N=.N, cor=cor(DeltaPsi.x, DeltaPsi.y, method="pearson")) , by=age ],
             aes(x=as.factor(age), y=N+200, label= paste0("R=", round(cor, 2)))) +
  xlab("DPC") +
  ylab("Number of splicing nodes") +
    scale_fill_discrete(name = "Microexon node type") +
  theme_bw() +
  theme(legend.position = "top") +
  guides(fill = guide_legend(nrow = 1))

Sup_vulcano.legend <- get_legend(Sup_vulcano.C)

library(ggExtra)

ME_AD_AA

Delta_HNM_total.alt_ME <- merge(Delta_HNM_total[ , .(exon_ID, Node_type, age, 
                                                     DeltaPsi.wp=DeltaPsi.x, Probability.wp=Probability.x, 
                                                     DeltaPsi.me=DeltaPsi.y, Probability.me=Probability.y)],
                                ME_AD_AA[ ,c("exon_ID", "exon_ID.alt")], by=c("exon_ID"))

Delta_HNM_total.alt_ME.compare <- merge(Delta_HNM_total.alt_ME,
                                        Delta_HNM_total[ , .(exon_ID, Node_type, age, 
                                                             DeltaPsi.wp.alt=DeltaPsi.x, Probability.wp.alt=Probability.x, 
                                                             DeltaPsi.me.alt=DeltaPsi.y, Probability.me.alt=Probability.y)],
                                        by.x=c("exon_ID.alt", "age"), by.y=c("exon_ID", "age") )



Delta_HNM_total.alt_ME.compare.stats <- Delta_HNM_total.alt_ME.compare[, .( alt_cor.wp=cor(DeltaPsi.wp, DeltaPsi.wp.alt), alt_cor.me=cor(DeltaPsi.me, DeltaPsi.me.alt) ), by=c("exon_ID.alt", "Node_type.x") ]


p <- ggplot(Delta_HNM_total.alt_ME.compare.stats)+
  geom_point(aes(x=alt_cor.wp, y=alt_cor.me), alpha=0.4)+
  theme_bw() +
  geom_density_2d(aes(x=alt_cor.wp, y=alt_cor.me), alpha=0.4, n=500, adjust=1.3) +
  geom_rug() +
  xlab("Whippet short/long microexon correlation") +
  ylab("MicroExonator short/long microexon correlation")


Sup_vulcano.E <- ggMarginal(p, type = "histogram", fill="transparent")


Sup_vulcano.CD <- plot_grid(Sup_vulcano.C  + theme(legend.position = "NA"),
                                Sup_vulcano.D  + theme(legend.position = "NA"),
                                nrow=1, labels = c("C", "D") )


Sup_vulcano.CD <- plot_grid(Sup_vulcano.legend, Sup_vulcano.CD, ncol=1, rel_heights = c(1, 8) )


Sup_vulcano.bottom <-plot_grid(Sup_vulcano.CD, plot_grid(nullGrob(), Sup_vulcano.E, nullGrob(),  nrow=1, rel_widths = c(1,3,1), labels = c("", "E", "") ), ncol=1)

Sup_vulcano.bottom <-plot_grid(Sup_vulcano.CD, Sup_vulcano.E, labels = c( "", "E"), nrow=1, rel_widths = c(2, 1))




plot_grid(Sup_vulcano.A, Sup_vulcano.B, Sup_vulcano.bottom,  ncol=1, labels = c("A", "B", ""), rel_heights = c(1,1,3))

library(gridExtra)
library(grid)

plot_grid(Sup_vulcano.CD, plot_grid(nullGrob(), Sup_vulcano.E, nullGrob(),  nrow=1, rel_widths = c(1,3,1), labels = c("", "E", "") ), ncol=1)

Delta_HNM_whippet_ME <- merge(Delta_HNM_whippet, Delta_HNM_ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type", "age") )

Delta_HNM_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , .N , by=(age)]

Delta_HNM_whippet_ME_included <- Delta_HNM_whippet_ME[ (DeltaPsi.x<=-0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y<=-0.1 &  Probability.y >= 0.9)  , .N , by=(age)]
Delta_HNM_whippet_ME_excluded <- Delta_HNM_whippet_ME[ (DeltaPsi.x>=0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y>=0.1 &  Probability.y >= 0.9)  , .N , by=(age)]


Delta_HNM_included_stats <- cbind(Delta_HNM_whippet_included[order(age)], Delta_HNM_ME_included[order(age), 2], Delta_HNM_whippet_ME_included[order(age), 2])
colnames(Delta_HNM_included_stats) <- c("age", "Whippet", "MicroExonator", "Both")


whippet_ME_age_stats <- function(Delta_S_whippet, Delta_S_ME) { 


  Delta_S_whippet_ME <- merge(Delta_S_whippet, Delta_S_ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type", "age") )
  
  Delta_S_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , .N , by=(age)]
  
  Delta_S_whippet_ME_included <- Delta_S_whippet_ME[ (DeltaPsi.x<=-0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y<=-0.1 &  Probability.y >= 0.9)  , .N , by=(age)]
  Delta_S_whippet_ME_excluded <- Delta_S_whippet_ME[ (DeltaPsi.x>=0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y>=0.1 &  Probability.y >= 0.9)  , .N , by=(age)]
  
  
  #Delta_S_included_stats <- cbind(Delta_S_whippet_included[order(age)], Delta_S_ME_included[order(age), 2], Delta_S_whippet_ME_included[order(age), 2])
  #colnames(Delta_S_included_stats) <- c("age", "Whippet", "MicroExonator", "Both")
  
  
  
  Delta_S_whippet_ME[, diff_high:=FALSE]
  Delta_S_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , diff_high:=TRUE]
  
  Delta_S_whippet_ME[, diff_low:=FALSE]
  Delta_S_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.8) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.8) , diff_low:=TRUE]
  
  
  ages <- sort(unique(Delta_S_whippet_ME$age))
  age_int <- c(ages[length(ages)])
  
  
    
  for (a in rev(ages[1:length(ages)-1])){
    
    age_int = cbind(age_int, a)
    
    Delta_S_whippet_ME[ age==a & diff_high==TRUE &  exon_ID %in% Delta_S_whippet_ME[age %in% age_int & diff_high==TRUE, .N, by=c("exon_ID", "Gene") ][N==length(age_int)]$exon_ID   , diff_age:=a ]
  }
    
  Delta_S_whippet_ME_age_diff <- Delta_S_whippet_ME[ diff_high==TRUE, .(diff_age = min(diff_age, na.rm = TRUE)), by=c("exon_ID", "Gene")]
  
  
  Delta_S_whippet_ME$delta_sing <- sign(Delta_S_whippet_ME$DeltaPsi.x)
  
  Delta_S_whippet_ME_diff_count <- Delta_S_whippet_ME[diff_high==TRUE , .N , by=c("exon_ID", "delta_sing")]
  rescue_exons <- Delta_S_whippet_ME_diff_count[N>=2 & !exon_ID %in% Delta_S_whippet_ME_age_diff[diff_age!=Inf, ]$exon_ID , ]$exon_ID
  
  
  #ages <- Delta_S_included_stats$age
  #age_int <- c(ages[length(ages)])
  Delta_S_whippet_ME[exon_ID %in% rescue_exons]
  
    
  for (a in rev(ages[1:length(ages)-1])){
    
    age_int = cbind(age_int, a)
    
    Delta_S_whippet_ME[exon_ID %in% rescue_exons & age==a & diff_low==TRUE &  exon_ID %in% Delta_S_whippet_ME[age %in% age_int & diff_low==TRUE, .N, by=c("exon_ID", "Gene") ][N==length(age_int)]$exon_ID   , diff_age_low:=a ]
  }
    
  
  Delta_S_whippet_ME_age_diff_low <- Delta_S_whippet_ME[ diff_low==TRUE, .(diff_age = min(diff_age_low, na.rm = TRUE)), by=c("exon_ID", "Gene")]
  
  
  diff_ME_sing <- Delta_S_whippet_ME[diff_high==TRUE, -sign(DeltaPsi.y)]
  names(diff_ME_sing) <- Delta_S_whippet_ME[diff_high==TRUE, exon_ID]
  
  
  Delta_S_whippet_ME_age_diff_total <-  rbind(Delta_S_whippet_ME_age_diff[diff_age!=Inf], Delta_S_whippet_ME_age_diff_low[diff_age!=Inf])
  
  Delta_S_whippet_ME_age_diff_total[, change_dir:=diff_ME_sing[exon_ID] ]
  
  return(Delta_S_whippet_ME_age_diff_total)

}

Delta_HNM_whippet_ME_age_diff_total <-  whippet_ME_age_stats(Delta_HNM_whippet, Delta_HNM_ME)
Delta_F_whippet_ME_age_diff_total <-  whippet_ME_age_stats(Delta_F_whippet, Delta_F_ME)


Delta_F_whippet_ME_age_diff_total_stats <-  Delta_F_whippet_ME_age_diff_total[, .(Count=.N) , by=c("diff_age", "change_dir") ]
Delta_HNM_whippet_ME_age_diff_total_stats <-  Delta_HNM_whippet_ME_age_diff_total[, .(Count=.N) , by=c("diff_age", "change_dir") ]

ggplot() +
  geom_bar(data=Delta_F_whippet_ME_age_diff_total_stats[change_dir==1], aes(factor(diff_age), Count), stat = "identity", fill="skyblue") +

  geom_bar(data=Delta_F_whippet_ME_age_diff_total_stats[change_dir==-1], aes(factor(diff_age), -Count), stat = "identity", fill="firebrick") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA))






ggplot() +
  geom_bar(data=Delta_HNM_whippet_ME_age_diff_total_stats[change_dir==1], aes(factor(diff_age), Count), stat = "identity", fill="skyblue") +

  geom_bar(data=Delta_HNM_whippet_ME_age_diff_total_stats[change_dir==-1], aes(factor(diff_age), -Count), stat = "identity", fill="firebrick") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA))



ME_diff_age <- Delta_HNM_whippet_ME_age_diff_total$diff_age
names(ME_diff_age) <- Delta_HNM_whippet_ME_age_diff_total$exon_ID


diff_ME_sing <- Delta_HNM_whippet_ME_age_diff_total$change_dir
names(diff_ME_sing) <- Delta_HNM_whippet_ME_age_diff_total$exon_ID

ME_clusters_table[, diff_age:=NA]
ME_clusters_table[, change_dir:=NA]
ME_clusters_table[, diff_age:=ME_diff_age[ME] ]
ME_clusters_table[, change_dir:=diff_ME_sing[ME] ]

ME_clusters_table[!is.na(diff_age)]


ME_clusters_table[ , Total:=.N, by= ME_clusters]

ME_clusters_table_stats <-  ME_clusters_table[, .N , by=c("ME_clusters", "diff_age", "change_dir", "Total")]

ME_clusters_table_stats[, Percentage:=N*100/Total]


ME_clusters_table_stats[ , sum(N), by=c( "change_dir" ) ] #TOTAL
ME_clusters_table_stats[ , sum(N), by=c( "diff_age", "change_dir" ) ] #TOTAL

ME_clusters_table_stats <- merge(ME_clusters_table_stats, ME_cluster_names[, c("ME_cluster", "ME_cluster.name", "ME_cluster.type")], by.x="ME_clusters", by.y="ME_cluster")

ME_clusters_table_stats_HNM <- ME_clusters_table_stats[diff_age!="NA" & change_dir!="NA"]



ME_clusters_table_stats_HNM_sub <- ME_clusters_table_stats_HNM[ME_cluster.name %in%  ME_cluster_names[ME_cluster.type %in% c("Neuronal", "Neuro-Muscular", "Muscular", "Non-Neuronal"), ME_cluster.name], ]
ME_clusters_table_stats_HNM_sub$ME_cluster.name <- factor(ME_clusters_table_stats_HNM_sub$ME_cluster.name, levels = sort(unique(as.character(ME_clusters_table_stats_HNM_sub$ME_cluster.name))))



Fig5.B <- ggplot() +
  geom_bar(data=ME_clusters_table_stats_HNM_sub[change_dir==1], aes(factor(diff_age), Percentage), stat = "identity", fill="skyblue") +
  geom_bar(data=ME_clusters_table_stats_HNM_sub[change_dir==-1], aes(factor(diff_age), -Percentage), stat = "identity", fill="firebrick") +
  facet_grid( ME_cluster.name ~ .) +
  ylim(c(-30, 75)) +
  ylab("Percentage") +
  xlab("") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0))
Fig5.B



ME_diff_age <- Delta_F_whippet_ME_age_diff_total$diff_age
names(ME_diff_age) <- Delta_F_whippet_ME_age_diff_total$exon_ID


diff_ME_sing <- Delta_F_whippet_ME_age_diff_total$change_dir
names(diff_ME_sing) <- Delta_F_whippet_ME_age_diff_total$exon_ID

ME_clusters_table[, diff_age:=NA]
ME_clusters_table[, change_dir:=NA]
ME_clusters_table[, diff_age:=ME_diff_age[ME] ]
ME_clusters_table[, change_dir:=diff_ME_sing[ME] ]

ME_clusters_table[!is.na(diff_age)]




#ME_clusters_table[ , Total:=.N, by= ME_clusters]

ME_clusters_table_stats <-  ME_clusters_table[, .N , by=c("ME_clusters", "diff_age", "change_dir", "Total")]

ME_clusters_table_stats[, Percentage:=N*100/Total]


 ME_clusters_table_stats[ , sum(N), by=c( "change_dir" ) ] # Total

ME_clusters_table_stats <- merge(ME_clusters_table_stats, ME_cluster_names[, c("ME_cluster", "ME_cluster.name", "ME_cluster.type")], by.x="ME_clusters", by.y="ME_cluster") 
ME_clusters_table_stats_F <- ME_clusters_table_stats[diff_age!="NA" & change_dir!="NA"]


ME_clusters_table_stats_F_sub <- ME_clusters_table_stats_F[ME_cluster.name %in%  ME_cluster_names[ME_cluster.type %in% c("Neuronal", "Neuro-Muscular", "Muscular", "Non-Neuronal"), ME_cluster.name], ]
ME_clusters_table_stats_F_sub$ME_cluster.name <- factor(ME_clusters_table_stats_F_sub$ME_cluster.name, levels = sort(unique(as.character(ME_clusters_table_stats_F_sub$ME_cluster.name))))




Fig5.C <- ggplot() +
  geom_bar(data=ME_clusters_table_stats_F_sub[change_dir==1], aes(factor(diff_age), Percentage), stat = "identity", fill="skyblue") +
  geom_bar(data=ME_clusters_table_stats_F_sub[change_dir==-1], aes(factor(diff_age), -Percentage), stat = "identity", fill="firebrick") +
  facet_grid( ME_cluster.name ~ .) +
  ylim(c(-30, 75)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA))

Fig5.C

Delta_SKM_whippet <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/control_vs_skeletal_muscle_tissue.diff.microexons")
Delta_SKM_ME <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/control_vs_skeletal_muscle_tissue.diff.ME.microexons")
Delta_SKM_whippet_ME <- merge(Delta_SKM_whippet, Delta_SKM_ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type")  )
Delta_SKM_whippet_ME[, diff_high:=FALSE]
Delta_SKM_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , diff_high:=TRUE]
Delta_SKM_whippet_ME[diff_high==TRUE , change_dir:=sign(DeltaPsi.x) ]
Delta_SKM_whippet_ME[, Tissue:="SKM"]

Delta_Heart_whippet <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/control_vs_heart.diff.microexons")
Delta_Heart_ME <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/control_vs_heart.diff.ME.microexons")
Delta_Heart_whippet_ME <- merge(Delta_Heart_whippet, Delta_Heart_ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type")  )
Delta_Heart_whippet_ME[, diff_high:=FALSE]
Delta_Heart_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , diff_high:=TRUE]
Delta_Heart_whippet_ME[diff_high==TRUE , change_dir:=sign(DeltaPsi.x) ]
Delta_Heart_whippet_ME[, Tissue:="Heart"]



Delta_AG_whippet <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/control_vs_adrenal_gland.diff.microexons")
Delta_AG_ME <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Whippet/control_vs_adrenal_gland.diff.ME.microexons")
Delta_AG_whippet_ME <- merge(Delta_AG_whippet, Delta_AG_ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type")  )
Delta_AG_whippet_ME[, diff_high:=FALSE]
Delta_AG_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , diff_high:=TRUE]
Delta_AG_whippet_ME[diff_high==TRUE , change_dir:=sign(DeltaPsi.x)]
Delta_AG_whippet_ME[, Tissue:="Heart"]
neural_AG_PSI <- merge(merge(
Delta_AG_whippet_ME[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9, .(exon_ID, PSI_AG=Psi_B.x)  ],

Delta_HNM_merge[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9,  .(exon_ID, age, PSI_HNM=Psi_B.x)],
by="exon_ID"),

Delta_F_merge[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9,  .(exon_ID, age, PSI_F=Psi_B.x)],
by=c("exon_ID", "age") )

table(neural_AG_PSI$age) # Over 14.5 there is the highest number of intersections


neural_AG_PSI_melted <- melt(neural_AG_PSI[age==14.5, c("exon_ID", "PSI_AG", "PSI_HNM", "PSI_F")])



Sup.AG_MHNF.A <- ggplot(neural_AG_PSI_melted, aes(variable, value)) +
  geom_boxplot() +
  geom_jitter() +
  #geom_line(aes(group=exon_ID)) +
  xlab("Tissue") +
  ylab("PSI") +
  ggsignif::geom_signif(test = "wilcox.test", comparisons = list(c("PSI_AG", "PSI_HNM"), c("PSI_AG", "PSI_F"))
, step_increase=0.15 , test.args = list(alternative = "two.sided", paired = TRUE), map_signif_level = TRUE) +
  scale_x_discrete(labels = c('Adrenal Gland','Brain MHN','Forebrain'))



Sup.AG_MHNF.B <- ggplot(neural_AG_PSI_melted, aes(variable, value)) +
  #geom_boxplot() +
  #geom_jitter() +
  geom_line(aes(group=exon_ID)) +
  xlab("Tissue") +
  ylab("PSI") +
  ggsignif::geom_signif(test = "wilcox.test", comparisons = list(c("PSI_AG", "PSI_HNM"), c("PSI_AG", "PSI_F"))
, step_increase=0.15 , test.args = list(alternative = "two.sided", paired = TRUE), map_signif_level = TRUE) +
  scale_x_discrete(labels = c('Adrenal Gland','Brain MHN','Forebrain'))


plot_grid(Sup.AG_MHNF.A, Sup.AG_MHNF.B, ncol=1, labels="AUTO")



ME_clusters_table[ , Diff_SKM:="FALSE"]
ME_clusters_table[ME %in% Delta_SKM_whippet_ME[diff_high==TRUE & change_dir==1, exon_ID], Diff_SKM:="Excluded" ]
ME_clusters_table[ME %in% Delta_SKM_whippet_ME[diff_high==TRUE & change_dir==-1, exon_ID], Diff_SKM:="Included"]

ME_clusters_table[ , Diff_Heart:="FALSE"]
ME_clusters_table[ME %in% Delta_Heart_whippet_ME[diff_high==TRUE & change_dir==1, exon_ID], Diff_Heart:="Excluded" ]
ME_clusters_table[ME %in% Delta_Heart_whippet_ME[diff_high==TRUE & change_dir==-1, exon_ID], Diff_Heart:="Included"]

ME_clusters_table[ , Diff_AG:="FALSE"]
ME_clusters_table[ME %in% Delta_AG_whippet_ME[diff_high==TRUE & change_dir==1, exon_ID], Diff_AG:="Excluded" ]
ME_clusters_table[ME %in% Delta_AG_whippet_ME[diff_high==TRUE & change_dir==-1, exon_ID], Diff_AG:="Included"]





ME_clusters_table_stats_SKM <- ME_clusters_table[ Diff_SKM!="FALSE", .N, by=c("ME_clusters", "Total", "Diff_SKM") ]
ME_clusters_table_stats_SKM[, Percentage:=(N*100/Total)]
ME_clusters_table_stats_SKM[, Tissue:="SKM"]
colnames(ME_clusters_table_stats_SKM) <- c("ME_clusters", "Total", "Diff", "N", "Percentage", "Tissue" )

ME_clusters_table_stats_Heart <- ME_clusters_table[ Diff_Heart!="FALSE", .N, by=c("ME_clusters", "Total", "Diff_Heart") ]
ME_clusters_table_stats_Heart[, Percentage:=(N*100/Total)]
ME_clusters_table_stats_Heart[, Tissue:="HRT"]
colnames(ME_clusters_table_stats_Heart) <- c("ME_clusters", "Total", "Diff", "N", "Percentage", "Tissue" )

ME_clusters_table_stats_AG <- ME_clusters_table[ Diff_AG!="FALSE", .N, by=c("ME_clusters", "Total", "Diff_AG") ]
ME_clusters_table_stats_AG[, Percentage:=(N*100/Total)]
ME_clusters_table_stats_AG[, Tissue:="AD"]
colnames(ME_clusters_table_stats_AG) <- c("ME_clusters", "Total", "Diff", "N", "Percentage", "Tissue" )


ME_clusters_table_stats_SHA <- rbind(ME_clusters_table_stats_SKM, ME_clusters_table_stats_Heart, ME_clusters_table_stats_AG)



ME_clusters_table_stats_SHA <- merge(ME_clusters_table_stats_SHA, ME_cluster_names[, c("ME_cluster", "ME_cluster.name", "ME_cluster.type")], by.x="ME_clusters", by.y="ME_cluster")

ME_clusters_table_stats_SHA_sub <- ME_clusters_table_stats_SHA[ME_cluster.name %in%  ME_cluster_names[ME_cluster.type %in% c("Neuronal", "Neuro-Muscular", "Muscular", "Non-Neuronal"), ME_cluster.name], ]


ME_clusters_table_stats_SHA_sub$ME_cluster.name <- factor(ME_clusters_table_stats_SHA_sub$ME_cluster.name, levels = sort(unique(as.character(ME_clusters_table_stats_SHA_sub$ME_cluster.name))))




Fig5.D <- ggplot() +
  geom_bar(data=ME_clusters_table_stats_SHA_sub[Diff=="Included"], aes(factor(Tissue), Percentage), stat = "identity", fill="skyblue") +
  geom_bar(data=ME_clusters_table_stats_SHA_sub[Diff=="Excluded"], aes(factor(Tissue), -Percentage), stat = "identity", fill="firebrick") +
  facet_grid( ME_cluster.name ~ .) +
  ylim(c(-30, 75)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA))
Fig5.D
library(UpSetR)

require(UpSetR)

listInput <- list(one = c(1, 2, 3, 5, 7, 8, 11, 12, 13), two = c(1, 2, 4, 5, 
    10), three = c(1, 5, 6, 7, 8, 9, 10, 12, 13))



Delta_HNM_whippet_ME_age_diff_total[,  exon_ID]

Delta_F_whippet_ME_age_diff_total[, exon_ID ]


tissue_intersection <- list(Brain = ME_clusters_table[diff_age!="NA", ME],
                            SKM = ME_clusters_table[Diff_SKM!=FALSE, ME],
                            Heart = ME_clusters_table[Diff_Heart!=FALSE, ME],
                            AG = ME_clusters_table[Diff_AG!=FALSE, ME]
                            )


tissue_intersection <- list(Brain_HNM = Delta_HNM_whippet_ME_age_diff_total[,  exon_ID],
                            Brain_F = Delta_F_whippet_ME_age_diff_total[,  exon_ID],
                            SKM = ME_clusters_table[Diff_SKM!=FALSE, ME],
                            Heart = ME_clusters_table[Diff_Heart!=FALSE, ME],
                            AG = ME_clusters_table[Diff_AG!=FALSE, ME]
                            )



Fig5.y <- upset(fromList(tissue_intersection), order.by = "freq", nsets = 5, keep.order = T)
Fig5.y
gg_color_hue <- function(n) {
  hues = seq(15, 375, length = n + 1)
  hcl(h = hues, l = 65, c = 100)[1:n]
}


library(eulerr)



tissue_intersection <- list(Brain = ME_clusters_table[diff_age!="NA", ME],
                            SKM = ME_clusters_table[Diff_SKM!=FALSE, ME],
                            Heart = ME_clusters_table[Diff_Heart!=FALSE, ME],
                            AG = ME_clusters_table[Diff_AG!=FALSE, ME])


tissue_intersection.venn <- euler(c("Brain" = 212,  
                    "SKM" = 35,  
                    "Heart" = 11, 
                    "AG" = 11,
                    "Brain&AG" = 29,
                    "SKM&Heart" = 21,
                    "Brain&Heart" = 18,
                    "Brain&SKM&Heart" = 18,
                    "Brain&SKM" = 14,
                    "Brain&SKM&Heart&AG" = 3,
                    "Brain&Heart&AG" = 2,
                    "Heart&AG" = 1,
                    "SKM&AG" = 1,
                    "Brain&SKM&AG" = 1))




tissue_intersection.venn <- euler(c("Brain_HNM&Brain_F" = 156,
                                    "Brain_HNM" = 71,
                                    "SKM" = 34,
                                    "Brain_HNM&Brain_F&AG" = 29,
                                    "SKM&Heart" = 20,
                                    "Brain_HNM&Brain_F&Heart" = 19,
                                    "Brain_F" = 15,
                                    "Brain_HNM&Brain_F&SKM&Heart" = 14,
                                    "Brain_HNM&Brain_F&SKM" = 13,
                                    "Heart" = 11,
                                    "AG" = 11,
                                    "Brain_HNM&SKM" = 5,
                                    "Brain_HNM&Brain_F&SKM&Heart&AG" = 5,                                   
                                    "Brain_HNM&SKM&Heart" = 4,
                                    "Brain_HNM&Heart" = 3,
                                    "Brain_F&AG" = 2,
                                    "Brain_HNM&Heart&AG" = 2,
                                    "Heart&AG" = 1,
                                    "SKM&AG" = 1 ,
                                    "Brain_F&SKM" = 1,
                                    "Brain_F&SKM&Heart" = 1,
                                    "Brain_HNM&SKM&AG" = 1,
                                    "Brain_HNM&Brain_F&Heart&AG" = 1,
                                    "Brain_HNM&Brain_F&SKM&AG" = 1))

                    
    
ven <- plot(tissue_intersection.venn, counts = FALSE, font=4, cex=1, alpha=0.5,
     fill=gg_color_hue(5), quantities = list(fontsize = 0))

ven


library(ggplotify)



Fig5.col2.row1 <- plot_grid(Fig5.B, Fig5.C, Fig5.D, nrow=1,  labels = c("F", "G", "H"), rel_widths = c(2, 1.5, 1.5) )

Fig5.col2 <- plot_grid(Fig5.col2.row1, as.grob(Fig5.y), ncol = 1,   labels = c("", "I"), rel_heights = c(3, 1) )

Fig5.bottom <- plot_grid(Fig5.A, Fig5.col2, nrow=1,  rel_widths = c(1, 1), labels = c("E", ""))


#Fig5 <- plot_grid(Fig5.col1, Fig5.B, Fig5.C, Fig5.D, nrow=1, rel_widths = c(10, 2, 1.5, 1.5 ), labels = c("", "F", "G", "H") )
Fig5 <- plot_grid(Fig5.X, Fig5.bottom, ncol=1, rel_heights = c(1, 4) )
Fig5 

Error


Delta_HNM_whippet_ME_age_diff[diff_age!="Inf", ]$exon_ID

Delta_HNM_whippet_ME$delta_sing <- sign(Delta_HNM_whippet_ME$DeltaPsi.x)

Delta_HNM_whippet_ME_diff_count <- Delta_HNM_whippet_ME[diff_high==TRUE , .N , by=c("exon_ID", "delta_sing")]



Delta_HNM_whippet_ME_diff_count[ N==2 & !exon_ID %in% Delta_HNM_whippet_ME_age_diff[diff_age!="Inf", ]$exon_ID, ]

Delta_HNM_whippet_ME_age_diff_low[diff_age!=Inf]

library(biomaRt)





MicroExon_genes <- gsub("\\..*","", Delta_HNM_whippet_ME$Gene) 
names(MicroExon_genes) <- Delta_HNM_whippet_ME$exon_ID
 
Delta_HNM_whippet_ME_age_diff_total[, ensembl_gene_id:=MicroExon_genes[exon_ID]]

ensembl = useEnsembl(biomart="ensembl", dataset="mmusculus_gene_ensembl")





gene_table <- data.table(getBM(attributes=c('ensembl_gene_id', "mgi_symbol"),filters = 'ensembl_gene_id', values = Delta_HNM_whippet_ME_age_diff_total$ensembl_gene_id , mart = ensembl))


gene_table <- data.table(getBM(attributes=c('ensembl_gene_id', "mgi_symbol"),filters = 'ensembl_gene_id', values = Delta_HNM_whippet_ME_age_diff_total$ensembl_gene_id , mart = ensembl))


Delta_HNM_whippet_ME_age_diff_total <- merge( Delta_HNM_whippet_ME_age_diff_total, gene_table, by='ensembl_gene_id')



cat(as.character(unique(Delta_HNM_whippet_ME_age_diff_total$mgi_symbol)), sep='\n') 


Delta_HNM_whippet_ME_age_diff_total[mgi_symbol=="Dctn2"]

Input for PPI network

genes_background <- unique(c(Delta_HNM_merge$Gene.x, Delta_F_merge$Gene.x))

genes_background <-  gsub("\\..*","", genes_background)


neuronal_ME_genes <- unique(c(Delta_HNM_whippet_ME_age_diff_total$Gene, Delta_F_whippet_ME_age_diff_total$Gene))
neuronal_ME_genes <- gsub("\\..*","", neuronal_ME_genes)

neuronal_ME_gene_names <-  gene_table[ensembl_gene_id %in% neuronal_ME_genes, ]

cat(as.character(unique(neuronal_ME_gene_names$mgi_symbol)), sep='\n') 


fwrite(data.table(genes_background), "../PPI/genes_background.txt", quote = FALSE, col.names = FALSE)

Delta_HNM_whippet_ME_age_diff_total[ , ensembl_gene_id:=gsub("\\..*","", Gene) ]
Delta_HNM_whippet_ME_age_diff_total[ , ensembl_gene_id:=gsub("\\..*","", Gene) ]


Delta_HNMF_whippet_ME_age_diff_total <- merge(Delta_HNM_whippet_ME_age_diff_total, Delta_F_whippet_ME_age_diff_total, by=c("exon_ID", "Gene", "change_dir"), all=TRUE)
Delta_HNMF_whippet_ME_age_diff_total[, diff_age:=min(diff_age.y, diff_age.x, na.rm=TRUE), by=exon_ID]

Delta_HNMF_whippet_ME_age_diff_total[ , ensembl_gene_id:=gsub("\\..*","", Gene) ]





Delta_HNMF_whippet_ME_age_diff_total <- merge(Delta_HNMF_whippet_ME_age_diff_total, neuronal_ME_gene_names, by="ensembl_gene_id")




#merge( Delta_HNMF_whippet_ME_age_diff_total, PPI_centrality, by="mgi_symbol")



#Delta_HNMF_whippet_ME_age_diff_total[!mgi_symbol %in% PPI_centrality$mgi_symbol]


fwrite(data.table(data.table(unique(Delta_HNMF_whippet_ME_age_diff_total$ensembl_gene_id))), "../Final_Figures/Figure5/microexons_HMNF_genes.txt", quote = FALSE, col.names = FALSE)

Delta_Heart_whippet_ME[ , ensembl_gene_id:=gsub("\\..*","", Gene) ]
Delta_SKM_whippet_ME[ , ensembl_gene_id:=gsub("\\..*","", Gene) ]
Delta_AG_whippet_ME[ , ensembl_gene_id:=gsub("\\..*","", Gene) ]


Delta_Heart_whippet_ME <- merge(Delta_Heart_whippet_ME, neuronal_ME_gene_names, by="ensembl_gene_id")
Delta_SKM_whippet_ME <- merge(Delta_SKM_whippet_ME, neuronal_ME_gene_names, by="ensembl_gene_id")
Delta_AG_whippet_ME <- merge(Delta_AG_whippet_ME, neuronal_ME_gene_names, by="ensembl_gene_id")

fwrite(data.table(data.table(unique(Delta_Heart_whippet_ME[diff_high==TRUE, ensembl_gene_id]))), "../Final_Figures/Figure5/heart_genes.txt", quote = FALSE, col.names = FALSE)
fwrite(data.table(data.table(unique(Delta_SKM_whippet_ME[diff_high==TRUE, ensembl_gene_id]))), "../Final_Figures/Figure5/SKM_genes.txt", quote = FALSE, col.names = FALSE)
fwrite(data.table(data.table(unique(Delta_AG_whippet_ME[diff_high==TRUE, ensembl_gene_id]))), "../Final_Figures/Figure5/AG_genes.txt", quote = FALSE, col.names = FALSE)


Delta_Heart_whippet_ME[diff_high==TRUE, ensembl_gene_id]
Delta_SKM_whippet_ME[diff_high==TRUE, ensembl_gene_id]
Delta_AG_whippet_ME[diff_high==TRUE, ensembl_gene_id]

microexons_Vastdb <- read_delim("~/Google_Drive/Results/ME/mm10/VastDB/VastDb.microexons.txt", 
    " ", escape_double = FALSE, col_names = FALSE, 
    trim_ws = TRUE)


microexons_Vastdb <- microexons_Vastdb$X1



microexons_GENCODE <- read_delim("~/Google_Drive/Results/ME/mm10/gencode.vM16.annotation.microexons.txt", 
    " ", escape_double = FALSE, col_names = FALSE, 
    trim_ws = TRUE)


microexons_GENCODE <- microexons_GENCODE$X1
ME_final.out[, In.10_percent_of_bulk:=ME %in% me_after_10_samples_filter) ]  
Error: unexpected ')' in "ME_final.out[, In.10_percent_of_bulk:=ME %in% me_after_10_samples_filter)"
ME_final.out[In.10_percent_of_bulk==TRUE, .N, by="type"]
fwrite(neuronal_ME_HNMF.table, "../../../../Thesis/"neuronal_ME_HNMF.tsv", sep="\t" )
Error: unexpected symbol in "fwrite(neuronal_ME_HNMF.table, "../../../../Thesis/"neuronal_ME_HNMF.tsv"

#library("STRINGdb")

#string_db <- STRINGdb$new( version="10", species=9606, score_threshold=0, input_directory="" )


#neuronal_ME_gene_names_mapped <- string_db$map( neuronal_ME_gene_names, "mgi_symbol", removeUnmappedRows = TRUE )

# string_db$plot_network( neuronal_ME_gene_names_mapped )



#hits <- as.character(unique(neuronal_ME_gene_names$mgi_symbol))

#example1_mapped <- string_db$map( hits, "gene", removeUnmappedRows = TRUE )

#plot_network( hits )

#data(diff_exp_example1)


#example1_mapped <- string_db$map( diff_exp_example1, "gene", removeUnmappedRows = TRUE )

#map

#?STRINGdb


neuronal_clusters_genes <- merge(neuronal_clusters, gene_info, by.x="transcript", by.y="ensembl_transcript_id")

neuronal_clusters_genes$ME_clusters <- mapvalues(neuronal_clusters_genes$ME_clusters, 
          from =1:18,
          to = c("I1", "E1", "E3", "I2", "N1", "M1", "N2", "NM3", "NM2", "N5", "NM1", "N3", "N4", "NN2", "E2", "I4", "I3", "NN1"))

#Generaring values for pie vertics

colour_pallete <- list( c(heat.colors(8), "#1E90FFFF"))
values_clusters = list()

ME_per_gene = list()

vertex_shape = list()
circle_color = list()

label_color = list()

for (i in 1:144){
  

  gene_name = nodes[i, ]$id


  if (i==16){
    
    gene_name = "Sptan1"   # STRING DB changed the name from Spna2 to Spatan1
  }
  
  if (i==49){
    
    gene_name = "Diaph1"   ## STRING DB changed the name from Diap1 to Diaph1
  }
  
  
  ME_per_gene[[i]] <- nrow(neuronal_clusters_genes[mgi_symbol==gene_name, ])


  N1 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="N1", ])
  N2 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="N2", ])
  N3 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="N3", ])
  N4 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="N4", ])
  N5 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="N5", ])
  NM1 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="NM1", ])
  NM2 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="NM2", ])
  NM3 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="NM3", ])
  NN1 =  nrow(neuronal_clusters_genes[mgi_symbol==gene_name  & ME_clusters=="NN1", ])
  
  
  #values_clusters[[i]] <- c(N1, N2, N3, N4, N5, NM1, NM2, NM3, NN1)
  
  cluster_counts <- c(NM1, N1, NM2,  N2, NM3, N3, N4, N5,  NN1)
  
  values_clusters[[i]] <- cluster_counts
  
  if (length(which(cluster_counts!=0) ) == 1  ) {
    
    vertex_shape[[i]] <- "circle"   #Nodes with only one kind of cluster need to be circles instead of pie to avoid pie border
    circle_color[[i]] <-  colour_pallete[[1]][which(cluster_counts!=0)] 
    
    
  } else {
    
    
    vertex_shape[[i]] <- "pie"
    circle_color[[i]] <-  "#FFFF00FF"   #This colour is not taken in consideration for pies
    
    
  }
  
  
  #if (gene_name %in%  SFARI_Gene_animal_genes[model.species=="Mus musculus" , gene.symbol]) {
    
  if (gene_name %in%  SFARI_Gene_human_genes[ gene.score<=3 , gene.symbol]) {  
    
    
    
    label_color[[i]] <- "darkgreen"
    
    
  } else{
    
     label_color[[i]] <- "black"
    
  }
  
    
    
  if ( sum( c( N1, N2, N3, N4, N5, NM1, NM2, NM3, NN1)) == 0 ) {
    
    print( c(i, nodes[i, ]$id ) )
  }
  

}

library(igraph)

vertex.pie.color=list(heat.colors(9))





ME_PPI <- fread("../PPI/ME.PPI.tsv")




links <- ME_PPI[, c("#node1", "node2", "combined_score")]



colnames(links) <- c("from", "to", "score")

nodes.1 <- ME_PPI[, c("#node1")]
colnames(nodes.1) <- c("id")

nodes.2 <- ME_PPI[, c("node2")]
colnames(nodes.2) <- c("id")


nodes <- rbind(nodes.1, nodes.2)


nodes <- unique(  nodes[ , , by="id"] )



net <- graph_from_data_frame(d=links, vertices=nodes, directed=F)

E(net)$size <- log(2-  E(net)$score)

E(net)$width <- (1-  E(net)$score)  * 15




#V(net)$size <- log(unlist(ME_per_gene) + 2) * 4

#E(net)$score

#plot(net, vertex.shape= unlist(vertex_shape), vertex.color = unlist(circle_color)  , vertex.pie=values_clusters, rescale=T, pie.lty=2, vertex.pie.color=colour_pallete, vertex.label.font=2, vertex.label.dist=0.4, vertex.label.color=unlist(label_color), vertex.label.cex=1.2)

#colour_pallete


#plot(net,rescale=T, vertex.label.cex=1.2, vertex.size=1 )





#harmonic_centrality <- PPI_diff_age_HNMF$harmonic_centrality
#names(harmonic_centrality) <- PPI_diff_age_HNMF$mapped_gene

#V(net)$size <- log(harmonic_centrality[names(V(net))] +1 )


#V(net)$size <- harmonic_centrality[names(V(net))]/6

#plot(net)




#PPI_diff_age_HNM_central [  %in% names(V(net))

#harmonic_centrality[names(V(net))]


#harmonic_centrality[names(V(net))]




#harmonic_centrality[names(V(net))]


#names(V(net)) 

#PPI_diff_age_HNM_central[  (mgi_symbol %in%  names(V(net)))==FALSE ,  ]

#PPI_diff_age_HNM_central[mgi_symbol=="Itsn1"]

#PPI_diff_age_HNMF
library(CINNA)

PPI_betweenness <- estimate_betweenness(net, vids = V(net), directed = F, cutoff=-1,
  weights = NULL, nobigint = TRUE)

PPI_eigen_centrality <- eigen_centrality(net, directed = F, scale = T, weights = NULL)$vector


#cbind(as.numeric(PPI_betweenness[V(net)]), as.numeric( PPI_eigen_centrality[V(net)]  ) )

PPI_harmonic_centrality <- harmonic_centrality(net)


PPI_degree_centrality <- centr_degree(net)$res
names(PPI_degree_centrality) <- V(net)$name

PPI_centrality <- data.frame(cbind(  PPI_betweenness[V(net)] ,  PPI_eigen_centrality[V(net)], PPI_harmonic_centrality, PPI_degree_centrality   ))

colnames(PPI_centrality) <- c("betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality")

PPI_centrality$mapped_gene <-  row.names(PPI_centrality)

PPI_centrality <- data.table(PPI_centrality)


PPI_diff_age_HNM_stats_EC <- PPI_diff_age_HNMF[is.na(diff_age.x)!=TRUE][,  .(min_dif_age=min(diff_age.x), Number_of_ME=.N), by=c("ensembl_gene_id", "eigen_centrality") ]
PPI_diff_age_HNM_stats_EC[, rank:=frank(-eigen_centrality)]
PPI_diff_age_HNM_stats_EC[ , max_rank:=max(rank)]
PPI_diff_age_HNM_stats_EC[ , percentil:=rank/max_rank*100]
PPI_diff_age_HNM_stats_EC[, central:=FALSE]
PPI_diff_age_HNM_stats_EC[percentil<15, central:=TRUE]



ggplot(PPI_diff_age_HNM_stats_EC) +
  geom_bar(aes(min_dif_age, fill=central), stat = "count", position="fill" ) +
  xlab("Earliest microexon differential inclusion detection per gene (DPC)")+
  ylab("Protein type proportion") +
  scale_x_continuous(breaks=seq(10.5,16.5,1)) +
  scale_fill_discrete(name = "Protein type", labels = c("Non-central", "Central"))  +
            theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")




PPI_diff_age_HNM_stats_HC <- PPI_diff_age_HNMF[is.na(diff_age.x)!=TRUE][,  .(min_dif_age=min(diff_age.x), Number_of_ME=.N), by=c("ensembl_gene_id", "harmonic_centrality") ]
PPI_diff_age_HNM_stats_HC[, rank:=frank(-harmonic_centrality)]
PPI_diff_age_HNM_stats_HC[ , max_rank:=max(rank)]
PPI_diff_age_HNM_stats_HC[ , percentil:=rank/max_rank*100]
PPI_diff_age_HNM_stats_HC[, central:=FALSE]
PPI_diff_age_HNM_stats_HC[percentil<15, central:=TRUE]



ggplot(PPI_diff_age_HNM_stats_HC) +
  geom_bar(aes(min_dif_age, fill=central), stat = "count", position="fill" ) +
  xlab("Earliest microexon differential inclusion detection per gene (DPC)")+
  ylab("Protein type proportion") +
  scale_x_continuous(breaks=seq(10.5,16.5,1)) +
  scale_fill_discrete(name = "Protein type", labels = c("Non-central", "Central"))  +
            theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")




centrality_logistic_regression <- glm(formula = central ~ min_dif_age, family = "binomial", data = PPI_diff_age_HNM_stats_EC)
summary(centrality_logistic_regression)


centrality_logistic_regression <- glm(formula = central ~ min_dif_age, family = "binomial", data = PPI_diff_age_HNM_stats_HC)
summary(centrality_logistic_regression)
var2str <- function(v1) {
  deparse(substitute(v1))
}
#GO_Reactome <- fread("../Figures/New_Figure 5/STRING/GO/Whole_genome_background/Reactome Pathways.tsv")




Axon_guidance <- unlist(strsplit(GO_Reactome[`term description`=="Axon guidance"]$`matching proteins in your network (labels)`, ","))
L1CAM_interactions <- unlist(strsplit(GO_Reactome[`term description`=="L1CAM interactions"]$`matching proteins in your network (labels)`, ","))
Protein_protein_interactions_at_synapses <- unlist(strsplit(GO_Reactome[`term description`=="Protein-protein interactions at synapses"]$`matching proteins in your network (labels)`, ","))
ER_to_Golgi_Anterograde_Transport <- unlist(strsplit(GO_Reactome[`term description`=="ER to Golgi Anterograde Transport"]$`matching proteins in your network (labels)`, ","))
Clathrin_mediated_endocytosis <- unlist(strsplit(GO_Reactome[`term description`=="Clathrin-mediated endocytosis"]$`matching proteins in your network (labels)`, ","))
Golgi_Associated_Vesicle_Biogenesis <- unlist(strsplit(GO_Reactome[`term description`=="Golgi Associated Vesicle Biogenesis"]$`matching proteins in your network (labels)`, ","))
Membrane_Trafficking <- unlist(strsplit(GO_Reactome[`term description`=="Membrane Trafficking"]$`matching proteins in your network (labels)`, ","))
Intra_Golgi_and_retrograde_Golgi_to_ER_traffic <- unlist(strsplit(GO_Reactome[`term description`=="Intra-Golgi and retrograde Golgi-to-ER traffic"]$`matching proteins in your network (labels)`, ","))

GOs <- list(Axon_guidance, L1CAM_interactions)

PPI_centrality_GO <- PPI_diff_age_HNMF[, c("mapped_gene", "exon_ID", "diff_age",  "betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality", "type") ]

PPI_centrality_GO <-
  rbind(PPI_diff_age_HNMF[ mapped_gene %in% Axon_guidance, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(Axon_guidance)) ],
PPI_diff_age_HNMF[ mapped_gene %in% L1CAM_interactions, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(L1CAM_interactions)) ],
PPI_diff_age_HNMF[ mapped_gene %in% Protein_protein_interactions_at_synapses, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(Protein_protein_interactions_at_synapses)) ],
PPI_diff_age_HNMF[ mapped_gene %in% ER_to_Golgi_Anterograde_Transport, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(ER_to_Golgi_Anterograde_Transport)) ],
PPI_diff_age_HNMF[ mapped_gene %in% Clathrin_mediated_endocytosis, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(Clathrin_mediated_endocytosis)) ],
PPI_diff_age_HNMF[ mapped_gene %in% Golgi_Associated_Vesicle_Biogenesis, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(Golgi_Associated_Vesicle_Biogenesis)) ],
PPI_diff_age_HNMF[ mapped_gene %in% Membrane_Trafficking, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(Membrane_Trafficking)) ],
PPI_diff_age_HNMF[ mapped_gene %in% Intra_Golgi_and_retrograde_Golgi_to_ER_traffic, .(mapped_gene, exon_ID, diff_age,  betweenness, eigen_centrality, harmonic_centrality, degree_centrality, type, GO=var2str(Intra_Golgi_and_retrograde_Golgi_to_ER_traffic)) ])







ggplot(PPI_centrality_GO, aes(GO, log(betweenness))) +
  geom_jitter() +
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0))


PPI_centrality_GO_gene_centered <- PPI_centrality_GO[ , .(diff_age=min(diff_age)) , by=c("mapped_gene", "betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality", "GO")]


ggplot(PPI_centrality_GO_gene_centered ) +
  geom_jitter(aes(harmonic_centrality, diff_age, color=GO), width=0.5, height=0.1 ) +
   theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")
ggplot(PPI_centrality_GO_gene_centered, aes(GO, diff_age)) +
+     geom_jitter(height = 0.1, width = 0.1) +
+     theme(axis.text.x = element_text(angle = 90, vjust = 0))

PPI_centrality_GO_gene_centered_stats <-  PPI_centrality_GO_gene_centered[ , .(N=.N),  by=c("GO", "diff_age")]

PPI_centrality_GO_gene_centered_stats[ , Total:=sum(N), by ="GO"]

PPI_centrality_GO_gene_centered_stats[, fraction:=N/Total ]

diff_age_levels <- PPI_centrality_GO_gene_centered_stats[ , .(mean=mean(diff_age)), by="GO"][order(-mean)]$GO


PPI_centrality_GO_gene_centered_stats$GO <- factor(PPI_centrality_GO_gene_centered_stats$GO, levels= diff_age_levels)

ggplot(PPI_centrality_GO_gene_centered_stats) +
  geom_tile(aes( diff_age, GO, fill = fraction)) +
  scale_fill_gradient(low="grey", high="red")+
  theme_bw()+
  labs(fill = "Gene fraction") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))

GO_Reactome_all <- rbind(
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% Axon_guidance, .(mapped_gene, exon_ID, diff_age, GO=var2str(Axon_guidance)) ] ,
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% L1CAM_interactions, .(mapped_gene, exon_ID, diff_age, GO=var2str(L1CAM_interactions)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% Protein_protein_interactions_at_synapses, .(mapped_gene, exon_ID, diff_age, GO=var2str(Protein_protein_interactions_at_synapses)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% ER_to_Golgi_Anterograde_Transport, .(mapped_gene, exon_ID, diff_age, GO=var2str(ER_to_Golgi_Anterograde_Transport)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% Clathrin_mediated_endocytosis, .(mapped_gene, exon_ID, diff_age, GO=var2str(Clathrin_mediated_endocytosis)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% Golgi_Associated_Vesicle_Biogenesis, .(mapped_gene, exon_ID, diff_age, GO=var2str(Golgi_Associated_Vesicle_Biogenesis)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% Membrane_Trafficking, .(mapped_gene, exon_ID, diff_age, GO=var2str(Membrane_Trafficking)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% Intra_Golgi_and_retrograde_Golgi_to_ER_traffic, .(mapped_gene, exon_ID, diff_age, GO=var2str(Intra_Golgi_and_retrograde_Golgi_to_ER_traffic))] )


GO_Reactome_all_stats <-  GO_Reactome_all[ , .(N=.N),  by=c("GO", "diff_age")]
GO_Reactome_all_stats[ , Total:=sum(N), by ="GO"]
GO_Reactome_all_stats[, fraction:=N/Total ]
diff_age_levels <- GO_Reactome_all_stats[ , .(mean=mean(diff_age)), by="GO"][order(-mean)]$GO

diff_age_levels <- c("Membrane_Trafficking",
                     "Intra_Golgi_and_retrograde_Golgi_to_ER_traffic",
                     "Golgi_Associated_Vesicle_Biogenesis",
                     "Clathrin_mediated_endocytosis",
                     "ER_to_Golgi_Anterograde_Transport",
                      "Axon_guidance",
                      "L1CAM_interactions",
                      "Protein_protein_interactions_at_synapses")


GO_Reactome_all_stats$GO <- factor(GO_Reactome_all_stats$GO, levels= rev(diff_age_levels))


F6G <- ggplot(GO_Reactome_all_stats) +
  geom_tile(aes( diff_age, GO, fill = fraction)) +
  geom_text(aes(diff_age, GO, label = N), color="white") +
  scale_fill_gradient(low="grey", high="red", limits=c(0, 0.7) )+
    scale_x_continuous(breaks=seq(10.5,16.5,1)) +
  theme_bw()+
  xlab("DPC") +
  ylab("") +
  labs(fill = "Gene fraction") +
  theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")

F6G
F6FG <- plot_grid(F6F, F6G, ncol=1, labels = c("F", "G"), rel_heights = c(1.3, 1))


Biological_Process <- fread("../PPI/enrichment.Process.tsv")
Cellular_Component <- fread("../PPI/enrichment.Component.tsv")
GO_Reactome <- fread("../PPI/enrichment.RCTM.tsv")


nervous_system_development <- unlist(strsplit(Biological_Process[`term description`=="nervous system development"]$`matching proteins in your network (labels)`, ","))
vesicle_mediated_transport <- unlist(strsplit(Biological_Process[`term description`=="vesicle-mediated transport"]$`matching proteins in your network (labels)`, ","))
cytoskeleton_organization <- unlist(strsplit(Biological_Process[`term description`=="cytoskeleton organization"]$`matching proteins in your network (labels)`, ","))
synapse_assembly <- unlist(strsplit(Biological_Process[`term description`=="synapse assembly"]$`matching proteins in your network (labels)`, ","))
signal_transduction <- unlist(strsplit(Biological_Process[`term description`=="signal transduction"]$`matching proteins in your network (labels)`, ","))

synapse <- unlist(strsplit(Cellular_Component[`term description`=="synapse"]$`matching proteins in your network (labels)`, ","))
somatodendritic_compartment <- unlist(strsplit(Cellular_Component[`term description`=="somatodendritic compartment"]$`matching proteins in your network (labels)`, ","))
postsynapse <- unlist(strsplit(Cellular_Component[`term description`=="postsynapse"]$`matching proteins in your network (labels)`, ","))
presynapse <- unlist(strsplit(Cellular_Component[`term description`=="presynapse"]$`matching proteins in your network (labels)`, ","))
growth_cone <- unlist(strsplit(Cellular_Component[`term description`=="growth cone"]$`matching proteins in your network (labels)`, ","))

GO_Biological_Process <- rbind(
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% nervous_system_development, .(mapped_gene, exon_ID, diff_age, GO=var2str(nervous_system_development)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% vesicle_mediated_transport, .(mapped_gene, exon_ID, diff_age, GO=var2str(vesicle_mediated_transport)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% cytoskeleton_organization, .(mapped_gene, exon_ID, diff_age, GO=var2str(cytoskeleton_organization)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% synapse_assembly, .(mapped_gene, exon_ID, diff_age, GO=var2str(synapse_assembly)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% signal_transduction, .(mapped_gene, exon_ID, diff_age, GO=var2str(signal_transduction)) ] )

GO_Cellular_Component <- rbind(
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% synapse, .(mapped_gene, exon_ID, diff_age, GO=var2str(synapse)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% somatodendritic_compartment, .(mapped_gene, exon_ID, diff_age, GO=var2str(somatodendritic_compartment)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% postsynapse, .(mapped_gene, exon_ID, diff_age, GO=var2str(postsynapse)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% presynapse, .(mapped_gene, exon_ID, diff_age, GO=var2str(presynapse)) ],
Delta_HNMF_whippet_ME_age_diff_total_PPI[ mapped_gene %in% growth_cone, .(mapped_gene, exon_ID, diff_age, GO=var2str(growth_cone)) ] )




GO_Biological_Process_stats <-  GO_Biological_Process[ , .(N=.N),  by=c("GO", "diff_age")]
GO_Biological_Process_stats[ , Total:=sum(N), by ="GO"]
GO_Biological_Process_stats[, fraction:=N/Total ]
diff_age_levels <- GO_Biological_Process_stats[ , .(mean=median(diff_age)), by="GO"][order(-mean)]$GO
GO_Biological_Process_stats$GO <- factor(GO_Biological_Process_stats$GO, levels= diff_age_levels)



Sup_GO_time.A <- ggplot(GO_Biological_Process_stats) +
  geom_tile(aes( diff_age, GO, fill = fraction)) +
    geom_text(aes(diff_age, GO, label = N), color="white") +
  scale_fill_gradient(low="grey", high="red" )+
  theme_bw()+
  labs(fill = "Gene fraction") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))



GO_Cellular_Component_stats <-  GO_Cellular_Component[ , .(N=.N),  by=c("GO", "diff_age")]
GO_Cellular_Component_stats[ , Total:=sum(N), by ="GO"]
GO_Cellular_Component_stats[, fraction:=N/Total ]
diff_age_levels <- GO_Cellular_Component_stats[ , .(mean=median(diff_age)), by="GO"][order(-mean)]$GO
GO_Cellular_Component_stats$GO <- factor(GO_Cellular_Component_stats$GO, levels= diff_age_levels)



Sup_GO_time.B <- ggplot(GO_Cellular_Component_stats) +
  geom_tile(aes( diff_age, GO, fill = fraction)) +
  geom_text(aes(diff_age, GO, label = N), color="white") +
  scale_fill_gradient(low="grey", high="red" )+
  theme_bw()+
  labs(fill = "Gene fraction") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0),
    axis.title = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))

library(ggpubr)


GO_Biological_Process_centrality <-  merge(GO_Biological_Process,  PPI_diff_age_HNMF[, c("exon_ID", "mapped_gene", "betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality", "type") ], by=c("exon_ID", "mapped_gene"))


GO_Biological_Process_centrality <- unique(GO_Biological_Process_centrality[, c("mapped_gene", "GO", "betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality")])[harmonic_centrality>10]  #Filterning nodes that are not conected to the main network


GO_Biological_Process_centrality$GO <- factor(GO_Biological_Process_centrality$GO,  levels = GO_Biological_Process_centrality[ , .(median=median(harmonic_centrality)) , by="GO" ][order(-median)]$GO)


ggplot(unique(GO_Biological_Process_centrality[, c("mapped_gene", "GO", "betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality")])[harmonic_centrality>10] )  +
  geom_boxplot(aes(GO, harmonic_centrality  ) ) +
    ylab("eigencentrality") +
    theme(axis.text.x = element_text(angle = 45, vjust = 0.6),
    axis.title.y = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))



GO_Biological_Process_centrality$GO <- factor(GO_Biological_Process_centrality$GO,  levels = GO_Biological_Process_centrality[ , .(median=median(eigen_centrality)) , by="GO" ][order(-median)]$GO)


ggplot( GO_Biological_Process_centrality )  +
  geom_boxplot(aes(GO, eigen_centrality  ) ) +
    ylab("eigencentrality") +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.6),
    axis.title.x = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))

GO_Biological_Process_centrality$GO <- factor(GO_Biological_Process_centrality$GO,  levels = GO_Biological_Process_centrality[ , .(median=median(betweenness)) , by="GO" ][order(-median)]$GO)


ggplot(unique(GO_Biological_Process_centrality[, c("mapped_gene", "GO", "betweenness", "eigen_centrality", "harmonic_centrality", "degree_centrality")])[harmonic_centrality>10] )  +
  geom_boxplot(aes(GO, log10(betweenness))   ) +
    theme(axis.text.x = element_text(angle = 45, vjust = 0.6),
    axis.title = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5))
GO_Biological_Process_centrality$GO <- factor(GO_Biological_Process_centrality$GO,  levels = GO_Biological_Process_centrality[ , .(median=median(eigen_centrality)) , by="GO" ][order(-median)]$GO)





my_comparisons <- list(c("vesicle_mediated_transport", "cytoskeleton_organization" ),
                       c("vesicle_mediated_transport", "signal_transduction" ),
                       c("vesicle_mediated_transport", "nervous_system_development"),
                       c("vesicle_mediated_transport", "synapse_assembly" ),
                       c("cytoskeleton_organization", "signal_transduction" ),
                       c("cytoskeleton_organization", "nervous_system_development" ),
                       c("cytoskeleton_organization", "synapse_assembly"),
                       c("signal_transduction", "nervous_system_development" ),
                       c("signal_transduction", "nervous_system_development" ),
                       c("nervous_system_development", "synapse_assembly" )
                       )


ggplot( GO_Biological_Process_centrality, aes(GO, eigen_centrality  )  )  +
  geom_boxplot() +
    ylab("eigencentrality") +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.6),
    axis.title.x = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5)) +
  geom_signif(comparisons = my_comparisons, 
              map_signif_level=TRUE , y_position =  seq(0.9, 1.9, 0.1))


GO_Biological_Process_centrality_HNM_age <- merge(GO_Biological_Process_centrality, Delta_HNMF_whippet_ME_age_diff_total_PPI[is.na(diff_age.x)!=TRUE][ , .(min_age_HNM=min(diff_age.x))  , by="mapped_gene" ], by="mapped_gene")

kruskal.test(data = GO_Biological_Process_centrality_HNM_age,  min_age_HNM ~ GO)


my_comparisons <- list(#c("vesicle_mediated_transport", "cytoskeleton_organization" ),
                       #c("vesicle_mediated_transport", "signal_transduction" ),
                       #c("vesicle_mediated_transport", "nervous_system_development"),
                       #c("vesicle_mediated_transport", "synapse_assembly" ),
                       c("cytoskeleton_organization", "signal_transduction" ),
                       c("cytoskeleton_organization", "nervous_system_development" ),
                       c("cytoskeleton_organization", "synapse_assembly")
                       #c("signal_transduction", "nervous_system_development" ),
                       #c("signal_transduction", "nervous_system_development" ),
                       #c("nervous_system_development", "synapse_assembly" )
                       )


F6I <- ggplot( GO_Biological_Process_centrality_HNM_age, aes(GO, min_age_HNM  )  )  +
  geom_boxplot() +
    ylab("Earliest microexon alternative inclusion per gene") +
   theme_bw() +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.6),
    axis.title.x = element_text(colour = NA),
    strip.text = element_text(hjust = 0.5)) +
      scale_y_continuous(breaks=seq(10.5,16.5,1)) +
  ggsignif::geom_signif(test = "wilcox.test", comparisons = my_comparisons, step_increase=0.15 , test.args = list(alternative = "less", paired = FALSE), map_signif_level = TRUE) +
  scale_x_discrete(labels=c("Vesicle mediated transportt", "Cytoskeleton organization", "Signal transduction", "Nervous system development", "Synapse assembly"))



kruskal.test(GO_Biological_Process_centrality_HNM_age$min_age_HNM, GO_Biological_Process_centrality_HNM_age$GO)
pairwise.wilcox.test(GO_Biological_Process_centrality_HNM_age$min_age_HNM, GO_Biological_Process_centrality_HNM_age$GO)

library(ggstatsplot)
df_pair <- ggstatsplot::pairwise_p(GO_Biological_Process_centrality, eigen_centrality,  type = "nonparametric", GO)
kruskal.test(data = GO_Biological_Process_centrality,  eigen_centrality ~ GO)
kruskal.test(data = GO_Biological_Process_centrality,  harmonic_centrality ~ GO)



pairwise.wilcox.test(GO_Biological_Process_centrality$eigen_centrality, GO_Biological_Process_centrality$GO)
pairwise.wilcox.test(GO_Biological_Process_centrality$harmonic_centrality, GO_Biological_Process_centrality$GO)
pairwise.wilcox.test(GO_Biological_Process_centrality$eigen_centrality, GO_Biological_Process_centrality$GO)
pairwise.wilcox.test(GO_Biological_Process_centrality$harmonic_centrality, GO_Biological_Process_centrality$GO)
Biological_Process <- fread("../Figures/New_Figure 5/STRING/GO/ME_genes_background/Biological_Process.tsv")
Cellular_Component <- fread("../Figures/New_Figure 5/STRING/GO/ME_genes_background/Cellular_Component.tsv")
Protein_Domains <- fread("../Figures/New_Figure 5/STRING/GO/ME_genes_background/INTERPRO Protein Domains and Features.tsv")



Biological_Process[ , `:=`( minus_log10_FDR=-log10(`false discovery rate`),
                            GO_size=(`observed gene count` + `background gene count`) ,
                            GO_fraction=(`observed gene count`/`background gene count`) ,
                            GO_class="Biological Process") ]



Cellular_Component[ , `:=`( minus_log10_FDR=-log10(`false discovery rate`),
                            GO_size=(`observed gene count` + `background gene count`) ,
                            GO_fraction=(`observed gene count`/`background gene count`) ,
                            GO_class="Cellular Component") ]


Protein_Domains[ , `:=`( minus_log10_FDR=-log10(`false discovery rate`),
                            GO_size=(`observed gene count` + `background gene count`) ,
                            GO_fraction=(`observed gene count`/`background gene count`) ,
                            GO_class="INTERPRO Protein Domains") ]


Total_GO <- rbind(Biological_Process, Cellular_Component, Protein_Domains)



ggplot(Total_GO[GO_size>20]) + 
  geom_point( aes(GO_fraction, minus_log10_FDR, size=log2(GO_size), colour=GO_class),  alpha=0.2) +
  facet_grid( . ~  GO_class ) +
  theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")
ggplot(PPI_diff_age_HNM_stats_EC) +
  geom_bar(aes(min_dif_age, fill=central), stat = "count", position="fill" ) +
  xlab("Earliest microexon differential inclusion detection per gene (DPC)")+
  ylab("Protein type proportion") +
  scale_x_continuous(breaks=seq(10.5,16.5,1)) +
  scale_fill_discrete(name = "Protein type", labels = c("Non-central", "Central"))  +
            theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")


ggplot(PPI_diff_age_HNM_stats_B) +
  geom_bar(aes(min_dif_age, fill=central), stat = "count", position="fill" ) +
  xlab("Earliest microexon differential inclusion detection per gene (DPC)")+
  ylab("Protein type proportion") +
  scale_x_continuous(breaks=seq(10.5,16.5,1)) +
  scale_fill_discrete(name = "Protein type", labels = c("Non-central", "Central"))  +
            theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")

Zebrafish


total_zebra <-  fread("../../Zebrafish/Final_Report/out_filtered_ME.txt")
total_zebra_cov <- fread("../../Zebrafish/Final_Report/out_filtered_ME.cov.txt")


exons.zebra <- fread("../../Zebrafish/danRer11.ensembl.bed12.exons")


mouse_to_zebra <- fread("../../Zebrafish/Conserved/out.high_quality.txt.mm10.bed.liftOver_minMatch_0.01.danRer11.closest_d.out.high_quality.txt.danRer11.bed.formatted")
zebra_to_mouse <- fread("../../Zebrafish/Conserved/out.high_quality.txt.danRer11.bed.liftOver_minMatch_0.01.mm10.closest_d.out.high_quality.txt.mm10.formatted")



mouse_to_zebra <- fread("../../Zebrafish/Conserved/Old/out.high_quality.mm10.bed_liftover_mm10todanRer11.overlap_wo.out.high_quality.bed")
zebra_to_mouse <- fread("../../Zebrafish/Conserved/Old/out.high_quality.bed.liftover_0.001_mm10.overlap_wo.out.high_quality.bed.liftover_0.001_mm10")

Mouse_Zebra.IDs <- unique(rbind(mouse_to_zebra[  , .(ME.mouse=V4, ME.zebra=V10 ) ], zebra_to_mouse[ , .(ME.mouse=V10, ME.zebra=V4) ] ))  #In here we are already applying a filter of 0.8 lengh


#View(Mouse_Zebra.IDs[, .(mouse.len, zebra.len, abs(mouse.len-abs(mouse.len-zebra.len))/max(mouse.len,zebra.len) )] )


mouse_len <- c(mouse_to_zebra[, V3-V2], zebra_to_mouse[, V9-V8])
names(mouse_len) <- c(mouse_to_zebra$V4, zebra_to_mouse$V10)


zebra_len <-  c(zebra_to_mouse[, V3-V2], mouse_to_zebra[, V9-V8])
names(zebra_len) <- c(zebra_to_mouse$V4, mouse_to_zebra$V10)




Mouse_Zebra.IDs[, mouse.len:=mouse_len[ME.mouse]]
Mouse_Zebra.IDs[, zebra.len:=zebra_len[ME.zebra]]


ggplot(Mouse_Zebra.IDs) +
  geom_bin2d(aes(mouse.len, zebra.len), bins = 30, color ="white") +
  theme_bw() +
  scale_fill_gradient(low =  "#00AFBB", high = "#FC4E07")


Mouse_Zebra.IDs <- Mouse_Zebra.IDs[mouse.len==zebra.len, ]

Mouse_Zebra.IDs.table <- merge(Mouse_Zebra.IDs, ME_cluster_names[ , c("ME_cluster.name" , "ME_cluster.type")], by="ME_cluster.name", all = TRUE)


Mouse_Zebra.IDs.table <- Mouse_Zebra.IDs.table[ , .(mouse.coord=ME.mouse, mouse.len=mouse.len, mouse.cluster_name=ME_cluster.name, mouse.cluster_type=ME_cluster.type, 
                           mouse.anno=type, mouse.ensembl=ensemble_mouse, 
                           zebra.coord=ME.zebra, zebra.len=zebra.len, zebra.ensembl=ensemble_zebra)] 


is.data.table(Mouse_Zebra.IDs.table)

Mouse_Zebra.IDs.table <- unique(merge(Mouse_Zebra.IDs.table, gene_table.TOTAL[ , c("ME", "mgi_symbol")], by.x="mouse.coord" , by.y="ME" ))

div_3 <- function(x) x %% 3 == 0]

Mouse_Zebra.IDs.table[ , .(mouse.coord, mgi_symbol, mouse.cluster_name, mouse.cluster_type, mouse.len, mouse.sym=(mouse.len%%3 == 0), mouse.ensembl, zebra.coord, zebra.len, zebra.sym=(zebra.len%%3 == 0), zebra.ensembl)  ]


Mouse_Zebra.IDs.thesis.table <- unique(Mouse_Zebra.IDs.table[ , .(mouse.coord, mgi_symbol, mouse.cluster_name, mouse.cluster_type,
                                                                  mouse.len, mouse.sym=(mouse.len%%3 == 0), mouse.ensembl,
                                                                  zebra.num=.N,
                                                                  zebra.coords=as.character(list(zebra.coord)),
                                                                  zebra.lens=as.character(list(zebra.len)),
                                                                  zebra.syms=as.character(list((zebra.len%%3 == 0))),
                                                                  zebra.ensembls=as.character(list(zebra.ensembl) )),
                                                              by= mouse.coord  ][order(mgi_symbol, mouse.coord)])



Mouse_Zebra.IDs.thesis.table[ , `:=`( zebra.coords=gsub('^c\\(|\\)$|\ |\"' , "", zebra.coords),
                                      zebra.lens=gsub('^c\\(|\\)$|\ |\"' , "", zebra.lens),
                                      zebra.syms=gsub('^c\\(|\\)$|\ |\"' , "", zebra.syms),
                                      zebra.ensembls=gsub('^c\\(|\\)$|\ |\"' , "", zebra.ensembls)
                                                        )]




fwrite(Mouse_Zebra.IDs.table, "../Final_Figures/Supplementary/Mouse_Zebra_microexons.tsv", append = FALSE, quote = "auto", sep = ",",  row.names = FALSE, col.names = TRUE )
fwrite(Mouse_Zebra.IDs.thesis.table, "~/Google_Drive/Thesis/Mouse_zebrafish.tsv", append = FALSE, quote = "auto", sep = "\t",  row.names = FALSE, col.names = TRUE )
Mouse_Zebra.IDs.thesis.table
                    mouse.coord                mouse.coord    mgi_symbol mouse.cluster_name mouse.cluster_type mouse.len mouse.sym mouse.ensembl zebra.num
  1: chr2_+_120495235_120495247 chr2_+_120495235_120495247                               O2              Other        12      TRUE          TRUE         1
  2: chr9_+_107346145_107346171 chr9_+_107346145_107346171 6430571L13Rik                 I1           Included        26     FALSE          TRUE         1
  3:   chr1_+_60438941_60438959   chr1_+_60438941_60438959          Abi2                 N4           Neuronal        18      TRUE          TRUE         2
  4:   chr1_+_60438952_60438959   chr1_+_60438952_60438959          Abi2                 E1           Excluded         7     FALSE         FALSE         2
  5:  chr11_+_84290287_84290311  chr11_+_84290287_84290311         Acaca                 I1           Included        24      TRUE          TRUE         1
 ---                                                                                                                                                      
312:   chr3_+_16183921_16183946   chr3_+_16183921_16183946        Ythdf3                 I1           Included        25     FALSE          TRUE         1
313: chr4_+_129340727_129340752 chr4_+_129340727_129340752       Zbtb8os                 I2           Included        25     FALSE          TRUE         1
314:  chr15_-_93395586_93395615  chr15_-_93395586_93395615         Zcrb1                 I1           Included        29     FALSE          TRUE         1
315:  chr19_+_41938807_41938836  chr19_+_41938807_41938836       Zdhhc16                 O2              Other        29     FALSE          TRUE         2
316:   chr8_-_82771338_82771358   chr8_-_82771338_82771358        Zfp330               <NA>               <NA>        20     FALSE          TRUE         1
                                          zebra.coords zebra.lens  zebra.syms zebra.ensembls
  1:                         chr22_-_26308944_26308956         12        TRUE          FALSE
  2:                          chr6_+_53364857_53364883         26       FALSE           TRUE
  3:   chr9_+_13770822_13770840,chr6_+_9985080_9985098      18,18   TRUE,TRUE     FALSE,TRUE
  4:   chr9_+_13770822_13770840,chr6_+_9985080_9985098      18,18   TRUE,TRUE     FALSE,TRUE
  5:                          chr5_-_56372282_56372306         24        TRUE           TRUE
 ---                                                                                        
312:                         chr24_+_24286425_24286450         25       FALSE           TRUE
313:                         chr13_+_44860543_44860568         25       FALSE           TRUE
314:                          chr4_-_13929692_13929721         29       FALSE           TRUE
315: chr12_-_2857061_2857090,chr13_-_31384958_31384987      29,29 FALSE,FALSE      TRUE,TRUE
316:                          chr1_-_53276279_53276299         20       FALSE           TRUE
Mouse_Zebra.IDs.table.summer[!is.na(mouse.coord), ]
                     mouse.coord mouse.len mouse.cluster_name mouse.cluster_type         mouse.anno mouse.ensembl               zebra.coord zebra.len zebra.ensembl
  1: chr10_+_106859776_106859806        30                 I1           Included  Missing in VastDB          TRUE  chr4_-_21989573_21989603        30          TRUE
  2:   chr10_+_24883203_24883221        18                NM2     Neuro-Muscular          Annotated          TRUE   chr20_-_2566047_2566065        18         FALSE
  3:   chr10_+_28554769_28554799        30                 N4           Neuronal          Annotated          TRUE   chr20_-_1490720_1490750        30          TRUE
  4:   chr10_+_28570173_28570191        18               <NA>               <NA>          Annotated          TRUE   chr20_-_1472362_1472380        18          TRUE
  5:   chr10_+_69823077_69823101        24                 E2           Excluded          Annotated          TRUE chr17_-_20794173_20794197        24          TRUE
 ---                                                                                                                                                               
398:    chrX_-_13596685_13596694         9                 N6           Neuronal Missing in GENCODE         FALSE  chr9_-_33407086_33407104        18         FALSE
399:    chrX_-_13596685_13596703        18                 N2           Neuronal  Missing in VastDB          TRUE  chr9_-_33407086_33407104        18         FALSE
400:    chrX_-_57241805_57241826        21                 I3           Included          Annotated          TRUE chr14_-_31813517_31813538        21          TRUE
401:    chrX_-_73855651_73855663        12                NM5     Neuro-Muscular          Annotated          TRUE chr23_+_28680393_28680405        12          TRUE
402:    chrX_-_74232966_74232990        24                NM3     Neuro-Muscular          Annotated          TRUE chr23_+_19793592_19793616        24          TRUE
     MHN.diff_age MHN.change_dir F.diff_age F.change_dir
  1:           NA             NA         NA           NA
  2:         13.5              1         NA           NA
  3:         13.5              1       14.5            1
  4:           NA             NA         NA           NA
  5:           NA             NA         NA           NA
 ---                                                    
398:           NA             NA       12.5            1
399:         11.5              1       12.5            1
400:           NA             NA         NA           NA
401:         14.5              1       14.5            1
402:           NA             NA         NA           NA
Mouse_Zebra.IDs[ME.mouse %in%  names(ME_clusters), ME_cluster:=ME_clusters[ME.mouse] ]



Mouse_Zebra.IDs<- merge(Mouse_Zebra.IDs , 
ME_cluster_names[, c("ME_cluster", "ME_cluster.name")] , by="ME_cluster", all.x=TRUE )


ggplot(Mouse_Zebra.IDs) +
  geom_bar(aes(x=ME_cluster.name), stat="count")




Mouse_Zebra.IDs[ , type:="Annotated"  ]

Mouse_Zebra.IDs[!ME.mouse %in% microexons_Vastdb, type:="Missing in VastDB"   ]
Mouse_Zebra.IDs[!ME.mouse %in% microexons_GENCODE, type:="Missing in GENCODE"   ]
Mouse_Zebra.IDs[!ME.mouse %in% microexons_GENCODE & !ME.mouse %in% microexons_Vastdb , type:="Novel"   ]


Mouse_Zebra.IDs[ , ensemble_zebra:=FALSE  ]
Mouse_Zebra.IDs[ME.zebra %in%  exons.zebra$V4, ensemble_zebra:=TRUE ]

Mouse_Zebra.IDs[ , ensemble_mouse:=FALSE  ]
Mouse_Zebra.IDs[ME.mouse %in%  microexons_GENCODE, ensemble_mouse:=TRUE ]







Delta_HNMF_whippet_ME_age_diff_total[exon_ID %in% Mouse_Zebra.IDs$ME.mouse]


Delta_HNMF_whippet_ME_age_diff_total[]


Mouse_Zebra.IDs[ME.mouse %in% Delta_HNMF_whippet_ME_age_diff_total$exon_ID][ ME.zebra %in% exons.zebra$V4]

 

ggplot(Mouse_Zebra.IDs) +
  geom_bar(aes(x=ME_cluster.name, fill=type), stat="count", position="fill")


length(unique(Mouse_Zebra.IDs$ME.mouse))

length(unique(Mouse_Zebra.IDs$ME.zebra))

PPI_diff_age_HNMF_central[ , conserved:=FALSE ]
PPI_diff_age_HNMF_central[exon_ID %in% Mouse_Zebra.IDs$ME.mouse, conserved:=TRUE ]

ggplot(PPI_diff_age_HNMF_central) +
  geom_jitter(aes(harmonic_centrality, diff_age,  shape= type, colour=conserved  ), width=0, height=0.1) + 
  xlab("Harmonic Centrality") +
  ylab("Earliest microexon differential inclusion detection (DPC)") +
   scale_y_continuous(breaks=seq(10.5,16.5,1)) +
    geom_text_repel(data=PPI_diff_age_HNMF_central[  central==TRUE  ], 
                  aes(x=harmonic_centrality, y=diff_age,  colour=conserved  ), 
                  nudge_y      = 0.5,
                  direction    = "x",
                  angle        = 90,
                  segment.size = 0.2,
                  label=PPI_diff_age_HNMF_central[central==TRUE  , mapped_gene],
                  show.legend = FALSE) +
          theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")


ggplot(PPI_diff_age_HNMF_central) +
  geom_boxplot(aes(conserved, log2(betweenness) ))
Mouse_Zebra.IDs[ensemble_zebra==FALSE]


zebra.zebra <-  ggplot(Mouse_Zebra.IDs) + 
  geom_bar(aes(ME_cluster.name, fill=ensemble_zebra), stat="count" ) +
    theme(axis.text.x = element_text(angle = 45), legend.position = "top", legend.direction = "horizontal")


zebra.mouse <- ggplot(Mouse_Zebra.IDs) + 
  geom_bar(aes(ME_cluster.name, fill=ensemble_mouse), stat="count") +
    theme(axis.text.x = element_text(angle = 45), legend.position = "top", legend.direction = "horizontal")
  



Mouse_Zebra.IDs.cluster_names <- merge(Mouse_Zebra.IDs, ME_cluster_names[, c("ME_cluster.name", "ME_cluster.type")], by="ME_cluster.name")
Mouse_Zebra_stats  <- Mouse_Zebra.IDs.cluster_names[ , .N , by=c("ME_cluster.type", "ensemble_zebra", "ensemble_mouse")]

Mouse_Zebra_stats[ , Type:=paste(ensemble_zebra, ensemble_mouse, sep = "_") ]

Mouse_Zebra_stats$ME_cluster.type <- factor(Mouse_Zebra_stats$ME_cluster.type,  levels=Mouse_Zebra_stats[!ensemble_zebra  | !ensemble_mouse , sum(N), by=c("ME_cluster.type")][order(V1), ME_cluster.type])

  
  

Fig7.E <- ggplot(Mouse_Zebra_stats[!ensemble_zebra  | !ensemble_mouse]) +
  geom_bar(aes(x=ME_cluster.type, y=N, fill=Type), stat = "identity", position="stack"  ) + 
  ylab("Number of microexons") +
  xlab("Microexon clusters") + 
   scale_fill_discrete(name = "Type", labels = c("Missing in both", "Missing in zebrafish", "Missing in mouse")) +
            theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal") +
    theme_bw() + 
  theme(axis.text.x = element_text(angle = 90))


Fig7.E
length(unique(Mouse_Zebra.IDs$ME.mouse))
length(unique(Mouse_Zebra.IDs$ME.zebra))

round((Mouse_Zebra_stats[ensemble_mouse==FALSE, sum(N) ] * 100) / length(unique(Mouse_Zebra.IDs$ME.mouse)), 1)
round((Mouse_Zebra_stats[ensemble_zebra==FALSE, sum(N) ] * 100 ) / length(unique(Mouse_Zebra.IDs$ME.zebra)), 1)
library(ggsignif)

#Mouse_Zebra.IDs[, ME_cluster.name:=ME_cluster.name.x]

Mouse_Zebra.conserved_frac <- unique(Mouse_Zebra.IDs[, c("ME.mouse", "ME_cluster.name")])[ ,.N , by=ME_cluster.name ]

Mouse_Zebra.conserved_frac <-  merge( Mouse_Zebra.conserved_frac , ME_clusters.names[ , .(Total=.N) , by=ME_cluster.name], by="ME_cluster.name")

Mouse_Zebra.conserved_frac[, percetage:=(N*100/Total)]

Mouse_Zebra.conserved_frac[order(percetage)]

Mouse_Zebra.conserved_frac <- merge(Mouse_Zebra.conserved_frac, ME_cluster_names[, c("ME_cluster.name", "ME_cluster.type")], by="ME_cluster.name" )

Mouse_Zebra.conserved_frac[, broad_class:="Other"]
Mouse_Zebra.conserved_frac[ME_cluster.type %in% c("Neuronal", "Neuro-Muscular", "Non-Neuronal", "Weak-Neuronal"), broad_class:="Neuronal"]
Mouse_Zebra.conserved_frac[ME_cluster.type %in% c("Neuro-Muscular"), broad_class:="Neuro-Muscular"]

Fig7.D <- ggplot(Mouse_Zebra.conserved_frac, aes(x = broad_class,  y = percetage )) +
  geom_jitter( aes( colour = ME_cluster.type), width=0.1) +
  geom_signif(comparisons = list(c("Neuronal", "Other")), map_signif_level=TRUE, test="wilcox.test", margin_top=5,  y_position=35, test.args = list(alternative = "two.sided", paired = FALSE)) +
  xlab("Microexon cluster with neuronal pattern") +
  ylab("Percentage of conserved microexons") +
  theme_bw() + 
  theme(axis.text.x = element_text(angle = 90))

Fig7.D

Exploring lift zebra that do not overlap with mouse microexons

zebra.total_lift <- fread("../../Zebrafish/Conserved/out.high_quality.bed.liftover_0.001_mm10")

zebra.total_lift[!V4 %in%  zebra_to_mouse$V4, ]

plot_grid(Fig7.D, Fig7.E, ncol=1)

Zebra diff



diff.W.file <-  "../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-TOTAL.diff.microexons"
diff.ME.file <- "../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-TOTAL.diff.ME.microexons"
comp_name = "16Mo_vs_4Mo-TOTAL"


diff_zebra <- function(diff.W.file, diff.ME.file, comp_name) {


diff.W <- fread(diff.W.file)
diff.ME <- fread(diff.ME.file)

diff.WME <- merge(diff.W, diff.ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type"))

diff.WME[, Name:=comp_name]

diff.WME[ , diff:="NA"]
diff.WME[ (DeltaPsi.x>=0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y>=0.1 &  Probability.y >= 0.9), diff:="Included"]
diff.WME[ (DeltaPsi.x<=-0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y<=-0.1 &  Probability.y >= 0.9)  , diff:="Excluded" ]

return(diff.WME)
}
Zebra.16Mo_vs_4Mo.TOTAL <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-TOTAL.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-TOTAL.diff.ME.microexons", 
                                "16Mo_vs_4Mo-TOTAL")



Zebra.20Mo_vs_16Mo.ZT16 <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_16Mo-ZT16.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_16Mo-ZT16.diff.ME.microexons", 
                                "20Mo_vs_16Mo-ZT16")


Zebra.20Mo_vs_4M.ZT16 <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_4M-ZT16.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_4M-ZT16.diff.ME.microexons", 
                                "20Mo_vs_4M-ZT16")



Zebra.16Mo_vs_4Mo.ZT16 <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-ZT16.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-ZT16.diff.ME.microexons", 
                                "16Mo_vs_4Mo-ZT16")



Zebra.20Mo_vs_16Mo.ZT4 <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_16Mo-ZT4.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_16Mo-ZT4.diff.ME.microexons", 
                                "20Mo_vs_16Mo-ZT4")


Zebra.20Mo_vs_4M.ZT4 <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_4M-ZT4.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/20Mo_vs_4M-ZT4.diff.ME.microexons", 
                                "20Mo_vs_4M-ZT4")



Zebra.16Mo_vs_4Mo.ZT4 <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-ZT4.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/16Mo_vs_4Mo-ZT4.diff.ME.microexons", 
                                "16Mo_vs_4Mo-ZT4")




Zebra.ZT16_vs_ZT4.20M <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/ZT16_vs_ZT4-20Mo.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/ZT16_vs_ZT4-20Mo.diff.ME.microexons", 
                                "ZT16_vs_ZT4-20Mo")

Zebra.ZT16_vs_ZT4.16M <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/ZT16_vs_ZT4-16Mo.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/ZT16_vs_ZT4-16Mo.diff.ME.microexons", 
                                "ZT16_vs_ZT4-16Mo")

Zebra.ZT16_vs_ZT4.4M <- diff_zebra("../../Zebrafish/Final_Report/Whippet/Delta/ZT16_vs_ZT4-4Mo.diff.microexons",
                                "../../Zebrafish/Final_Report/Whippet/Delta/ZT16_vs_ZT4-4Mo.diff.ME.microexons", 
                                "ZT16_vs_ZT4-4Mo")




Zebra.TOTAL_diff <- rbind(
Zebra.20Mo_vs_16Mo.ZT16[diff!="NA"],
Zebra.20Mo_vs_4M.ZT16[diff!="NA"],
Zebra.16Mo_vs_4Mo.ZT16[diff!="NA"],
Zebra.20Mo_vs_16Mo.ZT4[diff!="NA"],
Zebra.20Mo_vs_4M.ZT4[diff!="NA"],
Zebra.16Mo_vs_4Mo.ZT4[diff!="NA"],
Zebra.ZT16_vs_ZT4.20M[diff!="NA"],
Zebra.ZT16_vs_ZT4.16M[diff!="NA"],
Zebra.ZT16_vs_ZT4.4M[diff!="NA"] )


Zebra.TOTAL_diff <- Zebra.TOTAL_diff[ , lapply(.SD, paste0, collapse=",") , by="exon_ID"]


Mouse_Zebra.IDs[ME.zebra %in% Zebra.TOTAL_diff$exon_ID]
Delta_HNM_whippet_ME <- merge(Delta_HNM_whippet, Delta_HNM_ME, by=c("exon_ID", "Gene", "Node",  "Coord", "Strand", "Type", "age") )

Delta_HNM_whippet_ME[ (abs(DeltaPsi.x)>=0.1 &  Probability.x >= 0.9) &  (abs(DeltaPsi.y)>=0.1 &  Probability.y >= 0.9) , .N , by=(age)]

Delta_HNM_whippet_ME_included <- Delta_HNM_whippet_ME[ (DeltaPsi.x<=-0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y<=-0.1 &  Probability.y >= 0.9)  , .N , by=(age)]
Delta_HNM_whippet_ME_excluded <- Delta_HNM_whippet_ME[ (DeltaPsi.x>=0.1 &  Probability.x >= 0.9) &  (DeltaPsi.y>=0.1 &  Probability.y >= 0.9)  , .N , by=(age)]


Delta_HNM_included_stats <- cbind(Delta_HNM_whippet_included[order(age)], Delta_HNM_ME_included[order(age), 2], Delta_HNM_whippet_ME_included[order(age), 2])
colnames(Delta_HNM_included_stats) <- c("age", "Whippet", "MicroExonator", "Both")

centrality_logistic_regression_HC <- glm(formula = central ~ min_dif_age, family = "binomial", data = PPI_diff_age_HNM_stats_HC)
summary(centrality_logistic_regression_HC)


centrality_logistic_regression_EC <- glm(formula = central ~ min_dif_age, family = "binomial", data = PPI_diff_age_HNM_stats_EC)
summary(centrality_logistic_regression_EC)


centrality_logistic_regression_B <- glm(formula = central ~ min_dif_age, family = "binomial", data = PPI_diff_age_HNM_stats_B)
summary(centrality_logistic_regression_B)

PPI_diff_age_HNM$L1cam_and_interactors <- factor(PPI_diff_age_HNM$L1cam_and_interactors, levels=c(TRUE, FALSE))


F6G <- ggplot(PPI_diff_age_HNM) +
  geom_point(aes(eigen_centrality, betweenness, colour=L1cam_and_interactors)) +
  facet_wrap( . ~ diff_age, ncol = 2)  +
      geom_text_repel(data=PPI_diff_age_HNM[ L1cam_and_interactors==TRUE,  ], 
                  aes(x=eigen_centrality, y=betweenness, colour=L1cam_and_interactors ), 
                  nudge_y      = 3000,
                  direction    = "x",
                  angle        = 90,
                  segment.size = 0.2,
                  label=PPI_diff_age_HNM[L1cam_and_interactors==TRUE  , mgi_symbol],
                  show.legend = FALSE) +
          theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal") +
    scale_fill_discrete(name = "L1CAM pathway", labels = c("Member", "Non-member"))  
F6G <- ggplot(PPI_diff_age_HNM) +
  geom_point(aes(eigen_centrality, betweenness, colour=L1cam_and_interactors)) +
  facet_wrap( . ~ diff_age, ncol = 2)  +
      geom_text_repel(data=PPI_diff_age_HNM[ L1cam_and_interactors==TRUE,  ], 
                  aes(x=eigen_centrality, y=betweenness, colour=L1cam_and_interactors ), 
                  nudge_y      = 3000,
                  direction    = "x",
                  angle        = 90,
                  segment.size = 0.2,
                  label=PPI_diff_age_HNM[L1cam_and_interactors==TRUE  , mgi_symbol],
                  show.legend = FALSE) +
          theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal") +
    scale_fill_discrete(name = "L1CAM pathway", labels = c("Member", "Non-member"))  
Error in ggplot(PPI_diff_age_HNM) : object 'PPI_diff_age_HNM' not found
 ggplot(PPI_diff_age_HNM) +
  geom_jitter(aes(log(betweenness), diff_age, color=type ), width=0, height=0.1) +
  xlab("Betweenness") +
  ylab("Earliest microexon differential inclusion detection (DPC)") +
   scale_y_continuous(breaks=seq(10.5,16.5,1)) +
    geom_text_repel(data=PPI_diff_age_HNM[  log(betweenness)>6,  ],
                  aes(x=log(betweenness), y=diff_age, colour=type), 
                  nudge_y      = 0.5,
                  direction    = "x",
                  angle        = 90,
                  segment.size = 0.2,
                  show.legend = FALSE,
                  label=PPI_diff_age_HNM[log(betweenness)>6  , mgi_symbol] ) 

Tasic

ensembl = useEnsembl(biomart="ensembl", dataset="mmusculus_gene_ensembl", host = "www.ensembl.org")


ME_final.transcript <- gsub("\\..*","", ME_final$transcript)

ME_final$ensembl_transcript_id <- gsub("\\..*","", ME_final$transcript) 

gene_table.TOTAL <- data.table(getBM(attributes=c('ensembl_transcript_id', 'ensembl_gene_id', "mgi_symbol"),filters = 'ensembl_transcript_id', values = ME_final.transcript[nchar(ME_final.transcript)!=0], mart = ensembl,  ))


gene_table.TOTAL <- merge(gene_table.TOTAL, ME_final[, c("ensembl_transcript_id", "ME")], by="ensembl_transcript_id")
ensembl = useEnsembl(biomart="ensembl", dataset="mmusculus_gene_ensembl", host = "www.ensembl.org")
ME_final.transcript <- gsub("\\..*","", ME_final$transcript)
ME_final$ensembl_transcript_id <- gsub("\\..*","", ME_final$transcript) 
gene_table.TOTAL <- data.table(getBM(attributes=c('ensembl_transcript_id', 'ensembl_gene_id', "mgi_symbol"),filters = 'ensembl_transcript_id', values = ME_final.transcript[nchar(ME_final.transcript)!=0], mart = ensembl,  ))

Batch submitting query [==================================>----------------------------------------------------------------------------------------]  29% eta: 26s
Batch submitting query [====================================================>----------------------------------------------------------------------]  43% eta: 22s
Batch submitting query [=====================================================================>-----------------------------------------------------]  57% eta: 16s
Batch submitting query [=======================================================================================>-----------------------------------]  71% eta: 11s
Batch submitting query [========================================================================================================>------------------]  86% eta:  5s
Batch submitting query [===========================================================================================================================] 100% eta:  0s
                                                                                                                                                                  
gene_table.TOTAL <- merge(gene_table.TOTAL, ME_final[, c("ensembl_transcript_id", "ME")], by="ensembl_transcript_id")
ME_clusters.info <- merge(PCA_loadings, ME_cluster_names, by="ME_cluster")
Error in bmerge(i, x, leftcols, rightcols, roll, rollends, nomatch, mult,  : 
  Incompatible join types: x.ME_cluster (integer) and i.ME_cluster (factor). Factor columns must join to factor or character columns.





#C7_interesting <- c("chr1_-_93026831_93026855", "chr1_+_118512704_118512728", "chr11_-_106180954_106180983", "chr11_-_3352899_3352917", "chr11_+_54671654_54671678", "chr3_-_148827211_148827238"," chr4_-_76138555_76138573", "chr5_+_143703372_143703375", "chr5_+_48263640_48263667", "chr8_-_54645337_54645358")


#ggplot(ME_cov_filtered_tasic_primary_type[ ME %in% C7_interesting, ]  ) +
#  geom_pointrange(aes(x=primary_type, y=PSI, colour= broad_type, group=broad_type, shape=broad_type, ymin=lower, ymax=upper))+
#  theme(axis.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5)) +
#  facet_grid( gene_names[ME] ~ . )


target_genes <- c("Kif1a", "Dctn1", "Kdm1a", "Kdm2a",  "Itsn1", "Dnm1", "Dnm3", "Trrap", "Dclk2")

target_genes <- c("Kif1a", "Dctn1", "Kdm1a", "Kdm2a",  "Itsn1", "Dnm1", "Dnm3", "Trrap", "Dclk2")



ggplot(ME_cov_filtered_tasic_primary_type[ mgi_symbol %in% target_genes &  ME %in% Delta_HNMF_whippet_ME_age_diff_total$exon_ID , ]  ) +
  geom_pointrange(aes(x=primary_type, y=PSI, colour= broad_type, group=broad_type, shape=broad_type, ymin=lower, ymax=upper))+
  facet_grid( paste0( mgi_symbol, ME) ~ . ) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5))



ggplot(ME_cov_filtered_tasic_primary_type[ mgi_symbol %in% target_genes, ]  ) +
  geom_pointrange(aes(x=primary_type, y=PSI, colour= broad_type, group=broad_type, shape=broad_type, ymin=lower, ymax=upper))+
  facet_grid( paste0( mgi_symbol, ME) ~ . ) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5))

New Tasic


Tasic_total_diff_nodes <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Single_cell/GABA-ergic_Neuron_vs_Glutamatergic_Neuron.all_nodes.microexons.txt")



Tasic_total_diff_nodes.microexons <- merge( Tasic_total_diff_nodes[is.diff=="TRUE" & !is.na(microexon_ID), ], 
                                            unique(gene_table.TOTAL[, c("ME", "mgi_symbol")]),
                                            by.x="microexon_ID", by.y="ME")

Tasic_total_diff_nodes.microexons[!microexon_ID %in% Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron$exon_ID, ]
Tasic_total_diff_nodes <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Single_cell/GABA-ergic_Neuron_vs_Glutamatergic_Neuron.all_nodes.microexons.txt")
Tasic_total_diff_nodes.microexons <- merge( Tasic_total_diff_nodes[is.diff=="TRUE" & !is.na(microexon_ID), ], 
                                            unique(gene_table.TOTAL[, c("ME", "mgi_symbol")]),
                                            by.x="microexon_ID", by.y="ME")
Tasic_total_diff_nodes.microexons[!microexon_ID %in% Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron$exon_ID, ]
                  microexon_ID                  Gene Node                     Coord Strand Type Psi_A.mean Psi_B.mean DeltaPsi.mean DeltaPsi.sd Probability.mean
1: chr10_+_127728446_127728476 ENSMUSG00000025400.11    9 chr10:127728447-127728476      +   CE  0.9988179  0.8949054     0.1039116 0.005232909        0.9864583
2:    chr2_+_76569019_76569043 ENSMUSG00000042359.18   25    chr2:76569020-76569043      +   CE  0.4229608  0.9362494    -0.5132894 0.029304946        0.9067200
   Probability.sd Probability.var N.detected.reps     cdf.beta is.diff mgi_symbol
1:    0.005295355    2.804078e-05              48 8.007671e-38    TRUE       Tac2
2:    0.026344685    6.940424e-04              50 5.305384e-04    TRUE     Osbpl6
#ref Slc4a10 https://www.frontiersin.org/articles/10.3389/fncel.2015.00223/full
#ref Ank3 https://www.sciencedirect.com/science/article/pii/S0896627314009088
#ref KCNMA1 https://www.sciencedirect.com/science/article/pii/S0896627313001852
#ref Kif3a https://www.sciencedirect.com/science/article/pii/S089662730300062X
# ref DLGAP https://molecularbrain.biomedcentral.com/articles/10.1186/s13041-017-0324-9
Pre_synaptic <- c( "Ptprd" , "Ppfia2", "Dlgap1", "Gabrg2", "Kcnma1", "Kif3a", "Cadps") 
Post_synaptic <- c( "Nrxn3" , "Nrxn1")
PrePost_synaptic <- c("Ank3","Slc4a10")
Tasic_total_diff_nodes.microexons
                   microexon_ID                  Gene Node                     Coord Strand Type Psi_A.mean Psi_B.mean DeltaPsi.mean DeltaPsi.sd Probability.mean
 1: chr10_+_106882735_106882744 ENSMUSG00000053825.15   26 chr10:106882736-106882744      +   CE 0.04254298 0.40015960    -0.3576170 0.013543752        0.9423000
 2: chr10_+_127728446_127728476 ENSMUSG00000025400.11    9 chr10:127728447-127728476      +   CE 0.99881792 0.89490542     0.1039116 0.005232909        0.9864583
 3:   chr10_+_59767083_59767089 ENSMUSG00000020111.15   21   chr10:59767084-59767089      +   CE 0.50434320 0.90624060    -0.4018980 0.014786698        0.9524600
 4:   chr10_+_69980823_69980850 ENSMUSG00000069601.14   87   chr10:69980824-69980850      +   CE 0.83555840 0.14347140     0.6920866 0.020767159        0.9713200
 5:   chr11_+_53590716_53590725 ENSMUSG00000018395.19   21   chr11:53590717-53590725      +   CE 0.66200620 0.22252240     0.4394834 0.007520063        0.9907000
 6: chr11_-_112680921_112680950 ENSMUSG00000041674.16   31 chr11:112680922-112680950      -   CE 0.91463532 0.13275472     0.7818815 0.028238359        0.9804894
 7:   chr11_-_41913969_41913993 ENSMUSG00000020436.17   13   chr11:41913970-41913993      -   CE 0.78832760 0.49438140     0.2939452 0.003662291        0.9883000
 8:   chr12_+_89354452_89354479 ENSMUSG00000066392.11   28   chr12:89354453-89354479      +   CE 0.61528060 0.99319860    -0.3779194 0.015058715        0.9912800
 9: chr12_-_100340496_100340499  ENSMUSG00000033530.8   33 chr12:100340497-100340499      -   CE 0.08897032 0.45795740    -0.3689868 0.015599731        0.9196800
10:   chr14_-_12472397_12472406 ENSMUSG00000054423.14   37   chr14:12472398-12472406      -   CE 0.67774640 0.25092260     0.4268242 0.011500528        0.9458400
11:   chr14_-_23449199_23449208 ENSMUSG00000063142.15   37   chr14:23449200-23449208      -   CE 0.12223500 0.79508280    -0.6728472 0.011630571        0.9913000
12:   chr14_-_23449199_23449211 ENSMUSG00000063142.15   36   chr14:23449209-23449211      -   AA 0.12223200 0.79455880    -0.6723272 0.011685279        0.9914800
13:   chr16_+_58729215_58729223 ENSMUSG00000022744.12    9   chr16:58729216-58729223      +   CE 0.84074200 0.48995680     0.3507854 0.005506084        0.9701000
14:   chr17_+_70718195_70718225 ENSMUSG00000003279.16   29   chr17:70718196-70718225      +   CE 0.55267380 0.94271520    -0.3900420 0.010741757        0.9834200
15:   chr17_-_90561801_90561828 ENSMUSG00000024109.18   40   chr17:90561802-90561828      -   CE 0.05202180 0.42399920    -0.3719784 0.011344171        0.9733200
16:   chr17_-_90620864_90620891 ENSMUSG00000024109.18   30   chr17:90620865-90620891      -   CE 0.47302620 0.99741340    -0.5243858 0.024613597        0.9946200
17:    chr1_-_51786572_51786578 ENSMUSG00000018417.14   30    chr1:51786573-51786578      -   CE 0.28201560 0.90874460    -0.6267280 0.027523168        0.9336200
18:    chr2_+_62317497_62317514 ENSMUSG00000026904.17   35    chr2:62317498-62317514      +   CE 0.79882300 0.97748240    -0.1786596 0.005950109        0.9637600
19:    chr2_+_76569019_76569043 ENSMUSG00000042359.18   25    chr2:76569020-76569043      +   CE 0.42296080 0.93624940    -0.5132894 0.029304946        0.9067200
20:    chr3_+_69724256_69724270 ENSMUSG00000027787.14    8    chr3:69724257-69724270      +   CE 0.97109880 0.76964180     0.2014566 0.006564793        0.9468600
21:    chr4_-_76054588_76054600 ENSMUSG00000028399.18   71    chr4:76054589-76054600      -   CE 0.80153800 0.41104260     0.3904962 0.011873125        0.9194800
22:    chr4_-_76138555_76138573 ENSMUSG00000028399.18   37    chr4:76138556-76138573      -   CE 0.17602620 0.98994200    -0.8139158 0.021469308        0.9953000
23:    chr4_-_76139293_76139302 ENSMUSG00000028399.18   36    chr4:76139294-76139302      -   CE 0.07221076 0.92935940    -0.8571476 0.008669427        0.9976400
24:    chr5_+_48263640_48263667 ENSMUSG00000031558.15   66    chr5:48263641-48263667      +   CE 0.78063060 0.04944636     0.7311840 0.023120612        0.9710400
25:    chr5_-_73050866_73050875 ENSMUSG00000070733.13   85    chr5:73050867-73050875      -   CE 0.85641940 0.08213788     0.7742824 0.016144319        0.9724600
26:    chr7_+_75696321_75696338 ENSMUSG00000066406.15   37    chr7:75696322-75696338      +   CE 0.50410580 0.93627240    -0.4321666 0.027574986        0.9034200
27:  chr9_-_105493542_105493554 ENSMUSG00000032570.17   18  chr9:105493543-105493554      -   CE 0.31801920 0.93770440    -0.6196862 0.025207937        0.9588800
28:    chrX_+_71376886_71376910 ENSMUSG00000015214.14    5    chrX:71376887-71376910      +   CE 0.07470168 0.94029960    -0.8655980 0.010244770        0.9999800
29:  chrX_-_155214830_155214858 ENSMUSG00000025283.15   13  chrX:155214831-155214858      -   CE 0.25803900 0.47274340    -0.2147052 0.005831721        0.9018000
                   microexon_ID                  Gene Node                     Coord Strand Type Psi_A.mean Psi_B.mean DeltaPsi.mean DeltaPsi.sd Probability.mean
    Probability.sd Probability.var N.detected.reps      cdf.beta is.diff mgi_symbol     Location
 1:   0.0131028117    1.716837e-04              50  1.724799e-13    TRUE     Ppfia2  Presynaptic
 2:   0.0052953546    2.804078e-05              48  8.007671e-38    TRUE       Tac2         <NA>
 3:   0.0149054298    2.221718e-04              50  9.056338e-11    TRUE      Micu1         <NA>
 4:   0.0118484305    1.403853e-04              50  1.093610e-13    TRUE       Ank3         Both
 5:   0.0058458078    3.417347e-05              50  4.859664e-24    TRUE      Kif3a  Presynaptic
 6:   0.0129478424    1.676466e-04              47  7.190604e-10    TRUE   BC006965         <NA>
 7:   0.0056757630    3.221429e-05              50  5.694298e-30    TRUE     Gabrg2  Presynaptic
 8:   0.0057783551    3.338939e-05              50  2.074737e-23    TRUE      Nrxn3 Postsynaptic
 9:   0.0145116983    2.105894e-04              50  2.114484e-10    TRUE      Ttc7b         <NA>
10:   0.0147832779    2.185453e-04              50  5.108218e-11    TRUE      Cadps  Presynaptic
11:   0.0060684867    3.682653e-05              50  2.067205e-21    TRUE     Kcnma1  Presynaptic
12:   0.0063317793    4.009143e-05              50  1.461345e-19    TRUE     Kcnma1  Presynaptic
13:   0.0096895694    9.388776e-05              50  8.572693e-20    TRUE     Cldnd1         <NA>
14:   0.0092517842    8.559551e-05              50  9.431345e-16    TRUE     Dlgap1  Presynaptic
15:   0.0140006414    1.960180e-04              50  4.500230e-10    TRUE      Nrxn1 Postsynaptic
16:   0.0060132167    3.615878e-05              50  2.836469e-15    TRUE      Nrxn1 Postsynaptic
17:   0.0155404541    2.415057e-04              50  5.886836e-10    TRUE      Myo1b         <NA>
18:   0.0108035519    1.167167e-04              50  1.513312e-17    TRUE    Slc4a10         Both
19:   0.0263446854    6.940424e-04              50  5.305384e-04    TRUE     Osbpl6         <NA>
20:   0.0105907353    1.121637e-04              50  1.320554e-19    TRUE       Nmd3         <NA>
21:   0.0168925053    2.853567e-04              50  3.888772e-08    TRUE      Ptprd  Presynaptic
22:   0.0048075196    2.311224e-05              50  2.975151e-20    TRUE      Ptprd  Presynaptic
23:   0.0022835704    5.214694e-06              50  3.830921e-44    TRUE      Ptprd  Presynaptic
24:   0.0167891607    2.818759e-04              50  7.775889e-08    TRUE      Slit2         <NA>
25:   0.0154195873    2.377637e-04              50  9.252242e-09    TRUE       Fryl         <NA>
26:   0.0190135183    3.615139e-04              50  5.180120e-06    TRUE     Akap13         <NA>
27:   0.0152992463    2.340669e-04              50  4.602062e-10    TRUE     Atp2c1         <NA>
28:   0.0001414214    2.000000e-08              50 1.737462e-101    TRUE      Mtmr1         <NA>
29:   0.0184777859    3.414286e-04              50  3.573953e-06    TRUE       Sat1         <NA>
    Probability.sd Probability.var N.detected.reps      cdf.beta is.diff mgi_symbol     Location

ME_clusters.info <- merge(PCA_loadings, ME_cluster_names, by="ME_cluster")
Error in bmerge(i, x, leftcols, rightcols, roll, rollends, nomatch, mult,  : 
  Incompatible join types: x.ME_cluster (integer) and i.ME_cluster (factor). Factor columns must join to factor or character columns.
primary_type_levels <- c(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Endothelial Cell", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Oligodendrocyte", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Microglia", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Oligodendrocyte Precursor Cell", primary_type]),
sort(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Astrocyte", primary_type])),
sort(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Glutamatergic Neuron", primary_type])),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="GABA-ergic Neuron", primary_type]) )
ME_cov_filtered_tasic_primary_type$primary_type <- factor(ME_cov_filtered_tasic_primary_type$primary_type , levels = primary_type_levels)
target_genes <- c("Gabrg2", "Nrxn1", "Nrxn3", "Ptprd")
ME_cov_filtered_tasic_primary_type[(mgi_symbol %in% target_genes) & (ME %in% Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron$exon_ID)]
                            ME primary_type           broad_type sum_ME_coverage sum_SJ_coverage total_cov_alternatives_3 total_cov_alternatives_5       PSI     lower
  1: chr11_-_41913969_41913993   Vip Mybpc1    GABA-ergic Neuron            5881             887                        0                        0 0.8689421 0.8606926
  2: chr11_-_41913969_41913993    Vip Parm1    GABA-ergic Neuron            5465            3692                        0                        0 0.5968112 0.5867254
  3: chr11_-_41913969_41913993     L4 Ctxn3 Glutamatergic Neuron           12660            7816                        0                        0 0.6182848 0.6116091
  4: chr11_-_41913969_41913993     Vip Chat    GABA-ergic Neuron            5390            3757                        0                        0 0.5892642 0.5791469
  5: chr11_-_41913969_41913993   L2/3 Ptgs2 Glutamatergic Neuron            8799            3910                        0                        0 0.6923440 0.6842630
 ---                                                                                                                                                                  
339:  chr4_-_76139293_76139302  Pvalb Obox3    GABA-ergic Neuron               0               5                        0                        0 0.0000000 0.0000000
340:  chr4_-_76139293_76139302     L5b Tph2 Glutamatergic Neuron               3               0                        0                        0       NaN        NA
341:  chr4_-_76139293_76139302      L5 Ucma Glutamatergic Neuron              10               0                        0                        0 1.0000000 0.7224672
342:  chr4_-_76139293_76139302    L5 Chrna6 Glutamatergic Neuron               3               0                        0                        0       NaN        NA
343:  chr4_-_76139293_76139302    L5b Cdh13 Glutamatergic Neuron              19               0                        0                        0 1.0000000 0.8318208
         upper ensembl_transcript_id    ensembl_gene_id mgi_symbol
  1: 0.8767730    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  2: 0.6068157    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  3: 0.6249162    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  4: 0.5993067    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  5: 0.7003088    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
 ---                                                              
339: 0.4344825    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
340:        NA    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
341: 1.0000000    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
342:        NA    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
343: 1.0000000    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
ME_cov_filtered_tasic_primary_type[is.na(PSI), `:=`(lower=NA, upper=NA) ]
Fig8.c.top <- ggplot(ME_cov_filtered_tasic_primary_type[ mgi_symbol %in% target_genes & ME %in% Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron$exon_ID, ]  ) +
  geom_pointrange(aes(x=primary_type, y=PSI, colour= broad_type, group=broad_type, ymin=lower, ymax=upper))+
  facet_grid( paste0( mgi_symbol, ME) ~ . ) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5)) +
  theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal") +
  theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank())
Fig8.c.top


Tasic_clustering$primary_type <- factor(Tasic_clustering$primary_type , levels = primary_type_levels)

Fig8.c.bottom <- ggplot(Tasic_clustering[ broad_type!="Unclassified", .N , by=c("primary_type", "broad_type") ]) +
  geom_bar( aes(x=primary_type, y=N,  fill=broad_type) , stat="identity") +
    theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5)) +
  theme(axis.text.x = element_text(angle = 90), legend.position = "none", legend.direction = "horizontal", panel.grid.major = element_blank(), panel.grid.minor = element_blank())

Fig8.c.bottom

Single cell stast

plot_grid(Fig8.c.top, Fig8.c.bottom, ncol=1, rel_heights = c(7,2) )
Removed 65 rows containing missing values (geom_pointrange).

nrow(Tasic_total_diff_nodes)
[1] 195441
table(Tasic_total_diff_nodes$is.microexon)

 FALSE   TRUE 
193176   2265 
Tasic_total_diff_nodes[  , is.microexon:=!is.na(microexon_ID) ]
Tasic_total_diff_nodes[ is.na(is.diff) , is.diff:="FALSE"  ]
Coercing 'character' RHS to 'logical' to match the type of the target column (column 15 named 'is.diff').
Tasic_total_diff_nodes.stats <- Tasic_total_diff_nodes[ , .N , by=c("Type", "is.diff", "is.microexon")]
Tasic_total_diff_nodes.stats[ , Total:=sum(N), by=c("Type", "is.microexon")]
Tasic_total_diff_nodes.stats[is.diff=="TRUE", ]
   Type is.diff is.microexon  N  Total
1:   AF    TRUE        FALSE 36   4121
2:   CE    TRUE        FALSE 97 100168
3:   CE    TRUE         TRUE 28   2204
4:   AD    TRUE        FALSE 13   4749
5:   RI    TRUE        FALSE 18   7342
6:   AL    TRUE        FALSE  3   1708
7:   AA    TRUE        FALSE 12   5772
8:   AA    TRUE         TRUE  1     50
Tasic_total_diff_nodes.stats[, ratio:=N/Total]
Tasic_total_diff_nodes.stats <- Tasic_total_diff_nodes.stats[is.diff=="TRUE", ]
Tasic_total_diff_nodes.stats[is.diff=="TRUE", ]
   Type is.diff is.microexon  N  Total        ratio
1:   AF    TRUE        FALSE 36   4121 0.0087357438
2:   CE    TRUE        FALSE 97 100168 0.0009683731
3:   CE    TRUE         TRUE 28   2204 0.0127041742
4:   AD    TRUE        FALSE 13   4749 0.0027374184
5:   RI    TRUE        FALSE 18   7342 0.0024516481
6:   AL    TRUE        FALSE  3   1708 0.0017564403
7:   AA    TRUE        FALSE 12   5772 0.0020790021
8:   AA    TRUE         TRUE  1     50 0.0200000000
CE.cont <- matrix(nrow=2, c(Tasic_total_diff_nodes.stats[Type=="CE" & is.microexon=="TRUE", N ],
Tasic_total_diff_nodes.stats[Type=="CE" & is.microexon=="TRUE", Total-N ],
Tasic_total_diff_nodes.stats[Type=="CE" & is.microexon=="FALSE", N ],
Tasic_total_diff_nodes.stats[Type=="CE" & is.microexon=="FALSE", Total-N ]))
chisq.test(CE.cont)
Chi-squared approximation may be incorrect

    Pearson's Chi-squared test with Yates' continuity correction

data:  CE.cont
X-squared = 234.02, df = 1, p-value < 2.2e-16
CE.cont.total <- matrix(nrow=2, c(sum(Tasic_total_diff_nodes.stats[ is.microexon=="TRUE", N ]),
sum(Tasic_total_diff_nodes.stats[ is.microexon=="TRUE", Total-N ]),
sum(Tasic_total_diff_nodes.stats[is.microexon=="FALSE", N ]),
sum(Tasic_total_diff_nodes.stats[ is.microexon=="FALSE", Total-N ])))
chisq.test(CE.cont.total)
Chi-squared approximation may be incorrect

    Pearson's Chi-squared test with Yates' continuity correction

data:  CE.cont.total
X-squared = 168.49, df = 1, p-value < 2.2e-16
n=nrow(Tasic_total_diff_nodes)
a=nrow(Tasic_total_diff_nodes[ is.diff=="TRUE", ])
b=nrow(Tasic_total_diff_nodes[ is.microexon=="TRUE", ])
t=nrow(Tasic_total_diff_nodes[ is.microexon=="TRUE" &  is.diff=="TRUE", ])
dhyper(t, a, n - a, b)
[1] 1.875713e-22
sum(dhyper(t:b, a, n - a, b))
[1] 2.014586e-22
n=nrow(Tasic_total_diff_nodes[Type=="CE", ])
a=nrow(Tasic_total_diff_nodes[Type=="CE" & is.diff=="TRUE", ])
b=nrow(Tasic_total_diff_nodes[Type=="CE" & is.microexon=="TRUE", ])
t=nrow(Tasic_total_diff_nodes[Type=="CE" & is.microexon=="TRUE" &  is.diff=="TRUE", ])
dhyper(t, a, n - a, b)
[1] 1.423587e-20
sum(dhyper(t:b, a, n - a, b))
[1] 1.534839e-20
nrow(Tasic_total_diff_nodes[ is.microexon=="TRUE" &  is.diff=="TRUE", ])
[1] 29


Tasic_total_diff_nodes[is.diff==TRUE & is.microexon==TRUE, ]


Tasic_unpooled_diff_exons <- fread("/Users/gp7/Google_Drive/Results/ME/Paper/Final_Report/Reps/Rep1/Single_Cell/Unpooled/GABA-ergic_Neuron_vs_Glutamatergic_Neuron.diff.microexons")

Tasic_unpooled_pooled <- merge(Tasic_unpooled_diff_exons[ , c("exon_ID", "Probability", "DeltaPsi")], 
Tasic_total_diff_nodes[ is.microexon==TRUE , .(exon_ID=microexon_ID, mean_Probability=Probability.mean, mean_DeltaPsi=DeltaPsi.mean, sig_pool=is.diff)  ],
by="exon_ID")

Tasic_unpooled_pooled[ , sig_unpool:=FALSE ]
Tasic_unpooled_pooled[ abs(DeltaPsi) >= 0.1 &  Probability>=0.9, sig_unpool:=TRUE ]



 Tasic_unpooled_pooled[  ,.N, by=c( "sig_unpool", "sig_pool") ]
 Tasic_unpooled_pooled[  ,.N, by=c( "sig_unpool", "sig_pool") ]
   sig_unpool sig_pool    N
1:      FALSE    FALSE 2291
2:      FALSE     TRUE   19
3:       TRUE     TRUE   10
4:       TRUE    FALSE    4

Tasic

 Tasic_unpooled_pooled[  ,.N, by=c( "sig_unpool", "sig_pool") ]
   sig_unpool sig_pool    N
1:      FALSE    FALSE 2291
2:      FALSE     TRUE   19
3:       TRUE     TRUE   10
4:       TRUE    FALSE    4
library(ggplot2)
library(data.table)

ggplot(Tasic_unpooled_diff_exons) +
  geom_histogram(aes(Entropy), binwidth=0.1)

Tasic_unpooled_pooled <- merge(Tasic_unpooled_diff_exons[ , c("exon_ID", "Probability", "DeltaPsi")], 
Tasic_pooled_diff_exons[ , .( mean_Probability=mean(Probability), mean_DeltaPsi=mean(DeltaPsi)) , by="exon_ID"  ],
by="exon_ID")

Tasic_unpooled_pooled[ , sig_unpool:=FALSE ]
Tasic_unpooled_pooled[ abs(DeltaPsi) >= 0.1 &  Probability>=0.9, sig_unpool:=TRUE ]

Tasic_unpooled_pooled[ , sig_pool:=FALSE ]
Tasic_unpooled_pooled[ abs(mean_DeltaPsi) >= 0.1 &  mean_Probability>=0.9, sig_pool:=TRUE ]

Tasic_pooled_diff_exons[, sd_probability:=sd(Probability) , by="Coord"]

ggplot(Tasic_pooled_diff_exons) +
  geom_histogram(aes(x=sd_probability))
nrow(Tasic_unpooled_pooled[sig_unpool=="TRUE"])
nrow(Tasic_unpooled_pooled[sig_pool=="TRUE"])
ggplot() +
  
  geom_point( data=Tasic_unpooled_pooled, aes(mean_DeltaPsi - DeltaPsi , mean_Probability -Probability )) +
  geom_point( data=Tasic_unpooled_pooled[sig_unpool==FALSE & sig_pool==TRUE]  , aes(mean_DeltaPsi - DeltaPsi , mean_Probability -Probability ), color="red" ) +
  geom_point( data=Tasic_unpooled_pooled[sig_unpool==TRUE & sig_pool==TRUE]  , aes(mean_DeltaPsi - DeltaPsi , mean_Probability -Probability ), color="green" ) +
  geom_point( data=Tasic_unpooled_pooled[sig_unpool==TRUE & sig_pool==FALSE]  , aes(mean_DeltaPsi - DeltaPsi , mean_Probability -Probability ), color="blue" ) +
  theme_bw()
Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron_old <- Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron

Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron_old[ order(-abs(mean_DeltaPsi)), c("exon_ID", "mgi_symbol", "wikigene_description", "mean_DeltaPsi", "mean_Probability")]

Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron <- Tasic_unpooled_pooled[abs(mean_DeltaPsi - DeltaPsi) <=0.25 &  sig_pool==TRUE, ]

Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron <- merge( Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, unique(gene_table.TOTAL[, c("ME", "mgi_symbol")]), by.x="exon_ID", by.y="ME")

#Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron <- merge( Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron , unique(gene_info_total[ , c("mgi_symbol", "wikigene_description")]), by= "mgi_symbol")



Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[ order(-abs(mean_DeltaPsi))]

length(unique(Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[, mgi_symbol]))

#ref Slc4a10 https://www.frontiersin.org/articles/10.3389/fncel.2015.00223/full
#ref Ank3 https://www.sciencedirect.com/science/article/pii/S0896627314009088
#ref KCNMA1 https://www.sciencedirect.com/science/article/pii/S0896627313001852
#ref Kif3a https://www.sciencedirect.com/science/article/pii/S089662730300062X
# ref DLGAP https://molecularbrain.biomedcentral.com/articles/10.1186/s13041-017-0324-9


Pre_synaptic <- c( "Ptprd" , "Ppfia2", "Dlgap1", "Gabrg2", "Kcnma1", "Kif3a", "Cadps") 
Post_synaptic <- c( "Nrxn3" , "Nrxn1")
PrePost_synaptic <- c("Ank3","Slc4a10")

Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[  !exon_ID %in% microexons_GENCODE &  !exon_ID %in% microexons_Vastdb , c("exon_ID", "mgi_symbol", "wikigene_description", "mean_DeltaPsi", "mean_Probability")][order(-abs(mean_DeltaPsi))]

microexons_GENCODE
microexons_Vastdb
Brain_string_interactions_out[mgi_symbol=="Akap13",]
write.table(Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, file = "~/Desktop/Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron.txt", append = FALSE, quote = F, sep = "\t",
            eol = "\n", na = "NA", dec = ".", row.names = F,
            col.names = TRUE, qmethod = c("escape", "double"),
            fileEncoding = "")


ggplot()+
  geom_point(data=Tasic_unpooled_pooled, aes(mean_DeltaPsi, mean_Probability)) +
  geom_point(data=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, aes(mean_DeltaPsi, mean_Probability), color="red")
library("ggrepel")



Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Pre_synaptic, Location:="Presynaptic"]
Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Post_synaptic, Location:="Postsynaptic"]
Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% PrePost_synaptic, Location:="Both"]



#Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron <- Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[!exon_ID %in% ME_blacklist$ME]

ggplot()+
  geom_point(data=Tasic_unpooled_pooled, aes(mean_DeltaPsi, mean_Probability), color="grey") +
  geom_point(data=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, aes(mean_DeltaPsi, mean_Probability), color="black") +
  geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Pre_synaptic],
                  colour="forestgreen", aes(x=mean_DeltaPsi, y=mean_Probability), 
                  nudge_y      = 3,
                  direction    = "x",
                  angle        = 90,
                  vjust        = 1,
                  segment.size = 0.2,
                  label=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Pre_synaptic , mgi_symbol] ) +
  
  geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Post_synaptic],
                  colour="firebrick4", aes(x=mean_DeltaPsi, y=mean_Probability), 
                  nudge_y      = 3,
                  direction    = "x",
                  angle        = 90,
                  vjust        = 1,
                  segment.size = 0.2,
                  label=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Post_synaptic , mgi_symbol] ) +
  
  
  geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% PrePost_synaptic],
                  colour="darkgoldenrod", aes(x=mean_DeltaPsi, y=mean_Probability), 
                  nudge_y      = 3,
                  direction    = "x",
                  angle        = 90,
                  vjust        = 1,
                  segment.size = 0.2,
                  label=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% PrePost_synaptic , mgi_symbol] ) +
    
  
  ylim(0.5, 1.15) +
  theme_bw() +
  xlab("") +
  xlab("Mean delta PSI") +
  ylab("Mean probability")
ggplot()+
  geom_point(data=Tasic_unpooled_pooled, aes(mean_DeltaPsi, mean_Probability), color="grey") +
  geom_point(data=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, aes(mean_DeltaPsi, mean_Probability), color="black") +
  geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Pre_synaptic],
                  colour="forestgreen", aes(x=mean_DeltaPsi, y=mean_Probability), 
                  nudge_y      = 3,
                  direction    = "x",
                  angle        = 90,
                  vjust        = 1,
                  segment.size = 0.2,
                  label=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Pre_synaptic , mgi_symbol] ) +
  
  geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Post_synaptic],
                  colour="firebrick4", aes(x=mean_DeltaPsi, y=mean_Probability), 
                  nudge_y      = 3,
                  direction    = "x",
                  angle        = 90,
                  vjust        = 1,
                  segment.size = 0.2,
                  label=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Post_synaptic , mgi_symbol] ) +
  
  
  geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% PrePost_synaptic],
                  colour="darkgoldenrod", aes(x=mean_DeltaPsi, y=mean_Probability), 
                  nudge_y      = 3,
                  direction    = "x",
                  angle        = 90,
                  vjust        = 1,
                  segment.size = 0.2,
                  label=Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% PrePost_synaptic , mgi_symbol] ) +
    
  
  ylim(0.5, 1.15) +
  theme_bw() +
  xlab("") +
  xlab("Mean delta PSI") +
  ylab("Mean probability")
Error in geom_text_repel(data = Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in%  : 
  could not find function "geom_text_repel"
Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[mgi_symbol %in% Pre_synaptic, Location:="Presynaptic"]
Error in .checkTypos(e, names_x) : 
  Object 'mgi_symbol' not found amongst exon_ID, Probability, DeltaPsi, mean_Probability, mean_DeltaPsi and 2 more
primary_type_levels <- c(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Endothelial Cell", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Oligodendrocyte", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Microglia", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Oligodendrocyte Precursor Cell", primary_type]),
sort(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Astrocyte", primary_type])),
sort(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Glutamatergic Neuron", primary_type])),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="GABA-ergic Neuron", primary_type]) )

ME_cov_filtered_tasic_primary_type$primary_type <- factor(ME_cov_filtered_tasic_primary_type$primary_type , levels = primary_type_levels)
primary_type_levels <- c(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Endothelial Cell", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Oligodendrocyte", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Microglia", primary_type]),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="Oligodendrocyte Precursor Cell", primary_type]),
sort(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Astrocyte", primary_type])),
sort(unique(ME_cov_filtered_tasic_primary_type[broad_type=="Glutamatergic Neuron", primary_type])),
unique(ME_cov_filtered_tasic_primary_type[broad_type=="GABA-ergic Neuron", primary_type]) )
Error in unique(ME_cov_filtered_tasic_primary_type[broad_type == "Endothelial Cell",  : 
  object 'ME_cov_filtered_tasic_primary_type' not found
target_genes <- c("Gabrg2", "Nrxn1", "Nrxn3", "Ptprd")
ME_cov_filtered_tasic_primary_type[(mgi_symbol %in% target_genes) & (ME %in% Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron$exon_ID)]
                            ME primary_type           broad_type sum_ME_coverage sum_SJ_coverage total_cov_alternatives_3 total_cov_alternatives_5       PSI     lower
  1: chr11_-_41913969_41913993   Vip Mybpc1    GABA-ergic Neuron            5881             887                        0                        0 0.8689421 0.8606926
  2: chr11_-_41913969_41913993    Vip Parm1    GABA-ergic Neuron            5465            3692                        0                        0 0.5968112 0.5867254
  3: chr11_-_41913969_41913993     L4 Ctxn3 Glutamatergic Neuron           12660            7816                        0                        0 0.6182848 0.6116091
  4: chr11_-_41913969_41913993     Vip Chat    GABA-ergic Neuron            5390            3757                        0                        0 0.5892642 0.5791469
  5: chr11_-_41913969_41913993   L2/3 Ptgs2 Glutamatergic Neuron            8799            3910                        0                        0 0.6923440 0.6842630
 ---                                                                                                                                                                  
339:  chr4_-_76139293_76139302  Pvalb Obox3    GABA-ergic Neuron               0               5                        0                        0 0.0000000 0.0000000
340:  chr4_-_76139293_76139302     L5b Tph2 Glutamatergic Neuron               3               0                        0                        0       NaN 0.4385030
341:  chr4_-_76139293_76139302      L5 Ucma Glutamatergic Neuron              10               0                        0                        0 1.0000000 0.7224672
342:  chr4_-_76139293_76139302    L5 Chrna6 Glutamatergic Neuron               3               0                        0                        0       NaN 0.4385030
343:  chr4_-_76139293_76139302    L5b Cdh13 Glutamatergic Neuron              19               0                        0                        0 1.0000000 0.8318208
         upper ensembl_transcript_id    ensembl_gene_id mgi_symbol
  1: 0.8767730    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  2: 0.6068157    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  3: 0.6249162    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  4: 0.5993067    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
  5: 0.7003088    ENSMUST00000070725 ENSMUSG00000020436     Gabrg2
 ---                                                              
339: 0.4344825    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
340: 1.0000000    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
341: 1.0000000    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
342: 1.0000000    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
343: 1.0000000    ENSMUST00000174180 ENSMUSG00000028399      Ptprd
ME_cov_filtered_tasic_primary_type[is.na(PSI), `:=`(lower=NA, upper=NA) ]
ggplot(ME_cov_filtered_tasic_primary_type[ mgi_symbol %in% target_genes & ME %in% Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron$exon_ID, ]  ) +
  geom_pointrange(aes(x=primary_type, y=PSI, colour= broad_type, group=broad_type, ymin=lower, ymax=upper))+
  facet_grid( paste0( mgi_symbol, ME) ~ . ) +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust = 0, vjust = 0.5)) +
  theme(axis.text.x = element_text(angle = 90), legend.position = "top", legend.direction = "horizontal")

Numbers


###Abstract


Bulk_RNA_SEQ.Table <-  table(grepl("ENC",  unique(ME_cov_filtered[, FILE_NAME])))

Total_Bulk_RNA_seq <- sum(Bulk_RNA_SEQ.Table)
Total_scRNA_seq <-nrow(tasic_metadata)

Total_microexon.number <- length(ME_final[ , unique(ME)])
#HNMF_microexons.number <- length(Delta_HNMF_whippet_ME_age_diff_total_PPI[ , unique(exon_ID)])



diff_spliced.brain_dev <- length(unique(Delta_HNM_whippet_ME_age_diff_total$exon_ID , Delta_F_whippet_ME_age_diff_total$exon_ID))


diff_spliced.brain_dev.novel <-  length(unique(Delta_HNM_whippet_ME_age_diff_total[ ! exon_ID %in% c(microexons_Vastdb, microexons_GENCODE) ,  exon_ID  ], Delta_F_whippet_ME_age_diff_total[ ! exon_ID %in% c(microexons_Vastdb, microexons_GENCODE) ,  exon_ID  ]))


### Introduction

Total_microexon.number.not_gencode <- length(ME_final[ !ME %in% microexons_GENCODE , unique(ME)])
Total_microexon.number.not_gencode.percentage <- (Total_microexon.number.not_gencode / Total_microexon.number)*100


diff_spliced.brain_dev.not_vastdb <-  length(unique(Delta_HNM_whippet_ME_age_diff_total[ ! exon_ID %in% c(microexons_Vastdb) ,  exon_ID  ], Delta_F_whippet_ME_age_diff_total[ ! exon_ID %in% c(microexons_Vastdb) ,  exon_ID  ]))


diff_spliced.brain_dev.not_vastdb.percentage <- (diff_spliced.brain_dev.not_vastdb/diff_spliced.brain_dev)*100



conserved_zebra <-  length(unique(Mouse_Zebra.IDs[ , ME.zebra]))


conserved_zebra.not_ensembl <- length(unique(Mouse_Zebra.IDs[ensemble_zebra==FALSE, ME.zebra]))




#Results 

me_after_10_samples_filter <- rownames(Tissue_PSI_matrix_dcast[apply(Tissue_PSI_matrix_dcast, 1, function(x) length(which(is.na(x)))) < 289*0.9, ])

ME_final.out[ME %in% me_after_10_samples_filter, .N,  by="type"]



sym_percentage.neuronal_neuromuscular_muscular <- ME_cluster_names[ ME_cluster.type %in% c("Neuronal", "Neuro-Muscular", "Muscular") , 100- (sum(asym)/sum(total))*100]


Delta_HNM_whippet_ME_age_diff_total
Delta_HNMF_whippet_ME_age_diff_total

HNMF_microexons.not_vastdb.number <- nrow(Delta_HNMF_whippet_ME_age_diff_total_PPI[!exon_ID %in% microexons_Vastdb, ])
HNMF_microexons.not_vastdb.percentage <- round((HNMF_microexons.not_vastdb.number/HNMF_microexons.number)*100, 2)


Novel_gencode.number <- nrow(ME_final[ , .N, by=ME ][ !ME %in% microexons_GENCODE, ])
Novel_gencode.percentage <- (Novel_gencode.number / Total_microexon.number) *100


Novel_vastdb.number <- nrow(ME_final[ , .N, by=ME ][ !ME %in% microexons_Vastdb, ])
Novel_vastdb.percentage <- (Novel_vastdb.number / Total_microexon.number) *100


MHN_diff.whippet_ME <- length( unique(Delta_HNM_whippet[ abs(DeltaPsi)>=0.1 &  Probability >= 0.9 & exon_ID %in%  Delta_HNM_ME[ abs(DeltaPsi)>=0.1 &  Probability >= 0.9 ,  exon_ID ]   ,  exon_ID ]))
F_diff.whippet_ME <- length( unique(Delta_F_whippet[ abs(DeltaPsi)>=0.1 &  Probability >= 0.9 & exon_ID %in%  Delta_F_ME[ abs(DeltaPsi)>=0.1 &  Probability >= 0.9 ,  exon_ID ]   ,  exon_ID ]))


diff_heart <- nrow(Delta_Heart_whippet_ME[diff_high==TRUE, ])
diff_SKM <- nrow(Delta_SKM_whippet_ME[diff_high==TRUE, ])
diff_AG <- nrow(Delta_AG_whippet_ME[diff_high==TRUE, ])




Delta_HNMF_whippet_ME_age_diff_total[ , type:="Annotated"  ]
Delta_HNMF_whippet_ME_age_diff_total[!exon_ID %in% microexons_Vastdb, type:="Missing in VastDB"   ]
Delta_HNMF_whippet_ME_age_diff_total[!exon_ID %in% microexons_GENCODE, type:="Missing in GENCODE"   ]
Delta_HNMF_whippet_ME_age_diff_total[!exon_ID %in% microexons_GENCODE & !exon_ID %in% microexons_Vastdb , type:="Novel"   ]

table(Delta_HNMF_whippet_ME_age_diff_total$type)
ME_sizes <- ME_final.rep1$len_micro_exon_seq_found
names(ME_sizes) <- ME_final.rep1$ME


Delta_HNMF_whippet_ME_age_diff_total[ type=="Novel", .N , by=c("type", "ME_len") ]




Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron[ sig_unpool==TRUE ,  ]
ggplot(Delta_HNMF_whippet_ME_age_diff_total) +
  geom_histogram(aes(x=ME_len, fill=type), binwidth=1) +
  facet_grid(  type ~ .) +
  scale_fill_discrete(name="Microexon type") +
  xlab("Microexon length") +
  theme(legend.position="top") +
  theme(strip.background = element_blank(), strip.text = element_blank())
  
me_after_10_samples_filter <- rownames(Tissue_PSI_matrix_dcast[apply(Tissue_PSI_matrix_dcast, 1, function(x) length(which(is.na(x)))) < 289*0.9, ])
me_after_10_samples_filter <- rownames(Tissue_PSI_matrix_dcast[apply(Tissue_PSI_matrix_dcast, 1, function(x) length(which(is.na(x)))) < 289*0.9, ])
ME_final.out[ME %in% me_after_10_samples_filter, .N,  by="type"]
                 type    N
1:              Novel  866
2:          Annotated 1556
3: Missing in GENCODE  177

#rationale: https://www.gungorbudak.com/blog/2016/05/25/computing-significance-of-overlap/

AG_brain.intersect.number <- length(intersect(Delta_AG_whippet_ME[diff_high==TRUE]$exon_ID, Delta_HNMF_whippet_ME_age_diff_total$exon_ID))


AG.number <- length(unique(Delta_AG_whippet_ME[diff_high==TRUE, exon_ID]))
brain.number <- length(unique(Delta_HNMF_whippet_ME_age_diff_total$exon_ID))

Microexons.PPCA.number

phyper( AG_brain.intersect.number , AG.number,  Microexons.PPCA.number-AG.number, brain.number, lower.tail = FALSE  )
Supplemental




ME_clusters_table <- data.frame(ME_clusters)

ME_clusters_table$ME <- row.names(ME_clusters_table)
ME_clusters_table <- data.table(ME_clusters_table)


ME_clusters_PSI <-  data.table(merge(Tissue_PSI_matrix_melt_ppca, ME_clusters_table , by=c("ME")))


#ME_clusters_PSI <- ME_clusters_PSI[, c("ME", "FILE_NAME", "ME_clusters", "PSI")]


ME_Tissues_clusters_PSI<- merge(ME_clusters_PSI, PCA, by.x="FILE_NAME", by.y="File.accession")

ME_Tissues_clusters_PSI[, Tissue_clusters:=cluster]

PCA_loadings_stats$ME_cluster <- factor(PCA_loadings_stats$ME_cluster)
ME_Tissues_clusters_PSI$ME_clusters <- factor(ME_Tissues_clusters_PSI$ME_clusters)

ME_Tissues_clusters_PSI <- merge(ME_Tissues_clusters_PSI, PCA_loadings_stats, by.x="ME_clusters", by.y="ME_cluster" )

ME_Tissues_clusters_PSI$Tissue_clusters <- factor(ME_Tissues_clusters_PSI$Tissue_clusters, levels=PCA[, mean(PC1), by="cluster" ][order(V1)]$cluster) 



sub_ME_Tissues_clusters_PSI <- ME_Tissues_clusters_PSI[abs(PC1_mean)>0, ]
sub_ME_Tissues_clusters_PSI <- data.table(sub_ME_Tissues_clusters_PSI)
sub_ME_Tissues_clusters_PSI$ME_clusters <- factor(sub_ME_Tissues_clusters_PSI$ME_clusters , levels=ME_cluster_loading_order )


sub_ME_Tissues_clusters_PSI_aggregated <-  sub_ME_Tissues_clusters_PSI[, list(PSI=mean(PSI, na.rm = TRUE)), by=list(ME, ME_clusters,  Tissue_clusters) ]
sub_ME_Tissues_clusters_PSI_aggregated_mean <-  sub_ME_Tissues_clusters_PSI_aggregated[, list(PSI= mean(PSI, na.rm=TRUE) ), by=list(ME_clusters,  Tissue_clusters) ]


ggplot( ) +
        geom_line(data= sub_ME_Tissues_clusters_PSI_aggregated, aes(factor(Tissue_clusters), PSI, group=ME), colour="grey") +
        geom_line(data = sub_ME_Tissues_clusters_PSI_aggregated_mean, aes(factor(Tissue_clusters), PSI, group=ME_clusters),  colour="red" ) +
        facet_grid( ME_clusters ~ .) +
        xlab("Sample clusters (sorted by PC1)") +
        theme(panel.background = element_rect(fill = 'white', colour = 'black'))


col1 <- c("E1", "E2", "E3", "E4", "E5", "E6", "I1", "I2", "I3", "M1", "M2", "M3")
col2 <- c("N1", "N2", "N3", "N4", "NM1", "NM2", "NM3", "NN1", "O1", "O2", "WN1", "WN2")


sub_ME_Tissues_clusters_PSI_aggregated$ME_cluster <- as.numeric(as.character(sub_ME_Tissues_clusters_PSI_aggregated$ME_clusters)) 
sub_ME_Tissues_clusters_PSI_aggregated_mean$ME_cluster <- as.numeric(as.character(sub_ME_Tissues_clusters_PSI_aggregated_mean$ME_clusters)) 

plot_grid(
ggplot( ) +
        geom_line(data= merge(sub_ME_Tissues_clusters_PSI_aggregated, ME_cluster_names, by.x="ME_cluster",  by.y="ME_cluster")[ME_cluster.name %in% col1] , aes(factor(Tissue_clusters), PSI, group=ME), colour="grey") +
        geom_line(data = merge(sub_ME_Tissues_clusters_PSI_aggregated_mean, ME_cluster_names, by.x="ME_cluster",  by.y="ME_cluster")[ME_cluster.name %in% col1], aes(factor(Tissue_clusters), PSI, group=ME_clusters),  colour="red" ) +
        facet_grid( ME_cluster.name ~ .) +
        xlab("Sample clusters (sorted by PC1)") +
        theme(panel.background = element_rect(fill = 'white', colour = 'black')),

ggplot( ) +
        geom_line(data= merge(sub_ME_Tissues_clusters_PSI_aggregated, ME_cluster_names, by.x="ME_cluster",  by.y="ME_cluster")[ME_cluster.name %in% col2] , aes(factor(Tissue_clusters), PSI, group=ME), colour="grey") +
        geom_line(data = merge(sub_ME_Tissues_clusters_PSI_aggregated_mean, ME_cluster_names, by.x="ME_cluster",  by.y="ME_cluster")[ME_cluster.name %in% col2], aes(factor(Tissue_clusters), PSI, group=ME_clusters),  colour="red" ) +
        facet_grid( ME_cluster.name ~ .) +
        xlab("Sample clusters (sorted by PC1)") +
        theme(panel.background = element_rect(fill = 'white', colour = 'black'))

)


PCA_loadings$ME_clusters <- as.numeric(as.character(PCA_loadings$ME_cluster)) 


Sup_loading.A <- ggplot(merge(PCA_loadings, ME_cluster_names, by.x="ME_clusters",  by.y="ME_cluster")) +
  geom_boxplot(aes(ME_cluster.name , -PC1)) +
  ylab("Loading factors in PC1") +
  xlab("Microexon cluster") +
  theme(axis.text.x = element_text(angle = 90))



Sup_loading.B <-  ggplot(merge(PCA_loadings, ME_cluster_names, by.x="ME_clusters",  by.y="ME_cluster")) +
  geom_boxplot(aes(ME_cluster.name , PC2)) +
  ylab("Loading factors in PC2") +
  xlab("Microexon cluster") +
  theme(axis.text.x = element_text(angle = 90))



Sup_loading.C <-  ggplot(merge(PCA_loadings, ME_cluster_names, by.x="ME_clusters",  by.y="ME_cluster")) +
  geom_boxplot(aes(ME_cluster.name , PC3)) +
  ylab("Loading factors in PC3") +
  xlab("Microexon cluster") +
  theme(axis.text.x = element_text(angle = 90))


plot_grid(Sup_loading.A, Sup_loading.B, Sup_loading.C, labels = "AUTO", ncol=1)


PPI_centrality_GO[GO=="Axon_guidance", .N, by="mapped_gene" ]

Tables


TS2 <- unique(merge(Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, gene_table.TOTAL, by.x="exon_ID", by.y="ME"  ))


colnames(TS2) <- c("Coordinates", "Probability", "DeltaPsi", "Mean Probability", "Mean DeltaPsi", "Significance unpool", "Significance Pool", "Ensembl transcript ID",    "Ensembl gene ID", "Gene name")

fwrite(TS2, file = "../Final_Figures/Supplementary/Table_S2.csv", append = FALSE, quote = "auto", sep = ",",  row.names = FALSE, col.names = TRUE)
#R -e  'rmarkdown::render("src/final_filters2.Rmd",params = list(ME_table="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Round2/TOTAL.ME_centric.txt", ME_coverage="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Round2/TOTAL.filter1.ME_SJ_coverage", ME_matches_file="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Round2/TOTAL.ME_centric.ME_matches.txt", out_filtered_ME="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Report/test/out_filtered_ME.txt", out_low_scored_ME="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Report/test/out_low_scored_ME.txt", out_shorter_than_3_ME="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Report/test/out_shorter_than_3_ME.txt", min_number_files_detected=3, out_filtered_ME_cov="/lustre/scratch117/cellgen/team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Report/test/out_filtered_ME.cov.txt" ), output_format="pdf_document", output_file="/lustre/scratch117/cellgen /team218/gp7/Micro-exons/Runs/Paper/MicroExonator/Report/report.pdf")'

BetaDist

tasic.betadist <- fread("../../Single_cell/BetaDist/Sig_nodes/GABA-ergic_Neuron_vs_Glutamatergic_Neuron.txt")
ME_final[, .( stri_split_fixed(ME, "_")) ]
Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron

library(splitstackshape)
ME_final.chords <- cSplit(ME_final, 'ME', '_')[ is.na(ME_5) , .( paste0(ME_1, ":", as.numeric(as.character(ME_3))+1,  "-", ME_4) ) ]$V1


ME_final.chords <- cSplit(Sig_GABAergic_Neuron_vs_Glutamatergic_Neuron, 'exon_ID', '_')[  , .( paste0(exon_ID_1, ":", as.numeric(as.character(exon_ID_3))+1,  "-", exon_ID_4) ) ]$V1

tasic.betadist[ Coord %in%  ME_final.chords,]

cSplit(ME_final, 'ME', '_')[ is.na(ME_5) , .( paste0(ME_1, ":", ME_3,  "-", ME_4) ) ]


ME_final.chords[, .(as.numeric(as.character(ME_3)), ) ]

ME_final[ .(ME)]

Supplementary tables.


MHN.diff <- unique(Delta_HNM_merge[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9, exon_ID])
F.diff <- unique(Delta_F_merge[abs(DeltaPsi.x)>=0.1 & Probability.x>0.9 & abs(DeltaPsi.y)>=0.1 & Probability.y>0.9, exon_ID])
Delta_HNM_whippet_ME_age_diff_total[ , .(ME=exon_ID, HNM.diff_age=diff_age, HNM.change_dir=change_dir)] 
Delta_F_whippet_ME_age_diff_total[ , .(ME=exon_ID, F.diff_age=diff_age, F.change_dir=change_dir)] 
Delta_SKM_whippet_ME[ , .(ME=exon_ID, SKM.diff_age=diff_high)] 
Delta_Heart_whippet_ME[ , .(ME=exon_ID, Heart.diff_age=diff_high)] 
Delta_AG_whippet_ME[ , .(ME=exon_ID, AG.diff_age=diff_high)] 

TS1 <- ME_final.out[, .(ME,
             transcript,
             sum_total_coverage,
             total_SJs,
             total_coverages,
             len_micro_exon_seq_found,
             micro_exon_seq_found,
             total_number_of_micro_exons_matches,
             U2_scores,
             mean_conservations_vertebrates,
             P_MEs,
             total_ME,
             ME_P_value,
             ME_type,
             ensembl_transcript_id,
             type,
             Alt5_3,
             ME_cluster.type,
             ME_cluster.name,
             ME_cluster.number,
             PC1,
             PC2,
             PC3, 
             In.10_percent_of_bulk)]


TS1[ , MHN.diff:=(ME %in% MHN.diff) ]
TS1[ , F.diff:=(ME %in% F.diff) ]

TS1 <- merge(TS1, Delta_HNM_whippet_ME_age_diff_total[ , .(ME=exon_ID, HNM.diff_age=diff_age, HNM.change_dir=change_dir)], by="ME", all.x=TRUE) 
TS1 <- merge(TS1, Delta_F_whippet_ME_age_diff_total[ , .(ME=exon_ID, F.diff_age=diff_age, F.change_dir=change_dir)] , by="ME", all.x=TRUE) 
TS1 <- merge(TS1, Delta_SKM_whippet_ME[ , .(ME=exon_ID, SKM.diff=diff_high)] , by="ME", all.x=TRUE)
TS1 <- merge(TS1, Delta_Heart_whippet_ME[ , .(ME=exon_ID, Heart.diff=diff_high)] , by="ME", all.x=TRUE )
TS1 <- merge(TS1, Delta_AG_whippet_ME[ , .(ME=exon_ID, AG.diff=diff_high)] , by="ME", all.x=TRUE)

TS1[is.na(SKM.diff), SKM.diff:=FALSE ]
TS1[is.na(Heart.diff), Heart.diff:=FALSE ]
TS1[is.na(AG.diff), AG.diff:=FALSE ]

TS4 <- total_zebra

TS5 <- Mouse_Zebra.IDs.table.summer[!is.na(mouse.coord), .(mouse.coord,
                                                    mouse.len,
                                                    mouse.cluster_name,
                                                    mouse.cluster_type,
                                                    mouse.anno,
                                                    mouse.ensembl,
                                                    zebra.coord,
                                                    zebra.len,
                                                    zebra.ensembl)]


non_published <- Delta_HNMF_whippet_ME_age_diff_total[, .( ENSEMBL_gene_id=ensembl_gene_id,
                                          mgi_symbol=mgi_symbol.x,
                                          exon_ID,
                                          microexon.length=ME_len,
                                          change.direction=change_dir, 
                                          MHN.diff_start=diff_age.x,
                                          F.MHN.diff_start=diff_age.y,
                                          annotation.status=type
                                          )
                                     ]


TS6 <- Tasic_total_diff_nodes


ENCODE_metadata


Tissue_pool.table <- Tissue_clusters[ , .(File.accession, 
                                         Tissue=name,
                                         Age.DPC=age,
                                         Tissue.cluster=cluster)]


Tissue_pool.table[ Tissue %in% c("hindbrain", "neural tube", "midbrain") & Age.DPC %in% c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5),
                   Bulk.sample.group:=paste("MHN", Age.DPC, sep="_") ]
Tissue_pool.table[ Tissue %in% c("forebrain") & Age.DPC %in% c(10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 21) , 
                   Bulk.sample.group:=paste("F", Age.DPC, sep="_") ]

Tissue_pool.table[Tissue.cluster %in% c(1, 8, 6), Bulk.sample.group:="Control"]

Tissue_pool.table[Tissue=="heart" , Bulk.sample.group:="Heart" ]
Tissue_pool.table[Tissue=="skeletal muscle tissue" , Bulk.sample.group:="SKM" ]
Tissue_pool.table[Tissue=="adrenal gland" , Bulk.sample.group:="AD" ]

TS2 <- Tissue_pool.table
View(Tissue_pool.table)
TS1 
TS2
TS3
TS4
TS5
TS6[!is.na(microexon_ID) & is.diff==TRUE, ]



fwrite(TS1, file = "../Final_Figures/Supplementary/TS1.tsv", append = FALSE, quote = "auto", sep = "\t",  row.names = FALSE, col.names = TRUE)
fwrite(TS2, file = "../Final_Figures/Supplementary/TS2.tsv", append = FALSE, quote = "auto", sep = "\t",  row.names = FALSE, col.names = TRUE)
fwrite(TS4, file = "../Final_Figures/Supplementary/TS4.tsv", append = FALSE, quote = "auto", sep = "\t",  row.names = FALSE, col.names = TRUE)
fwrite(TS5, file = "../Final_Figures/Supplementary/TS5.tsv", append = FALSE, quote = "auto", sep = "\t",  row.names = FALSE, col.names = TRUE)
fwrite(TS6, file = "../Final_Figures/Supplementary/TS6.tsv", append = FALSE, quote = "auto", sep = "\t",  row.names = FALSE, col.names = TRUE)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCgpgYGB7cn0KbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdwbG90cykKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShwbHlyKQpzZXQuc2VlZCgxMjMpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGlncmFwaCkKdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoKSApCmBgYAoKCgoKYGBge3J9CgoKZ2V0X2NvbG9ycyA8LSBmdW5jdGlvbihncm91cHMsIGdyb3VwLmNvbCA9IHBhbGV0dGUoKSl7CiAgZ3JvdXBzIDwtIGFzLmZhY3Rvcihncm91cHMpCiAgbmdycHMgPC0gbGVuZ3RoKGxldmVscyhncm91cHMpKQogIGlmKG5ncnBzID4gbGVuZ3RoKGdyb3VwLmNvbCkpIAogICAgZ3JvdXAuY29sIDwtIHJlcChncm91cC5jb2wsIG5ncnBzKQogIGNvbG9yIDwtIGdyb3VwLmNvbFthcy5udW1lcmljKGdyb3VwcyldCiAgbmFtZXMoY29sb3IpIDwtIGFzLnZlY3Rvcihncm91cHMpCiAgcmV0dXJuKGNvbG9yKQp9CgoKZ2dfY29sb3JfaHVlIDwtIGZ1bmN0aW9uKG4pIHsKICBodWVzID0gc2VxKDE1LCAzNzUsIGxlbmd0aCA9IG4gKyAxKQogIGhjbChoID0gaHVlcywgbCA9IDY1LCBjID0gMTAwKVsxOm5dCn0KYGBgCgoKCgpJbXBvcnRpbmcgbWV0YWRhdGEKCgpgYGB7cn0KCkVOQ09ERV9tZXRhZGF0YSA8LSByZWFkLmRlbGltKCJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL21tMTAvbWV0YWRhdGEudHN2IiwgIGhlYWRlcj1UUlVFLCBzZXA9Ilx0IikKCkVOQ09ERV9tZXRhZGF0YSA8LSBkYXRhLnRhYmxlKEVOQ09ERV9tZXRhZGF0YSkKCgoKV2V5bl9lbF9hbF9tZXRhZGF0YSA8LSBkYXRhLnRhYmxlKHJlYWRfZGVsaW0oIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvV2V5bl9lbF9hbC5tZXRhZGF0YS50eHQiLCAgIlx0IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkpCgpXZXluX2VsX2FsX21ldGFkYXRhWywgYDo9YChGaWxlLmFjY2Vzc2lvbj1SdW4sCiAgICAgICAgICAgICAgICAgICAgQmlvc2FtcGxlLkFnZT1hZ2UsCiAgICAgICAgICAgICAgICAgICAgRXhwZXJpbWVudC5kYXRlLnJlbGVhc2VkPUxvYWREYXRlLAogICAgICAgICAgICAgICAgICAgIEJpb3NhbXBsZS50ZXJtLm5hbWU9dGlzc3VlLAogICAgICAgICAgICAgICAgICAgIFBhaXJlZC5lbmQ9TkEsCiAgICAgICAgICAgICAgICAgICAgUGFpcmVkLndpdGg9IiIsCiAgICAgICAgICAgICAgICAgICAgQXVkaXQuV0FSTklORz0iIikgXQoKbWV0YWRhdGEgPC0gcmJpbmQoIEVOQ09ERV9tZXRhZGF0YVssIGMoIkZpbGUuYWNjZXNzaW9uIiwgIkJpb3NhbXBsZS5BZ2UiLCAiRXhwZXJpbWVudC5kYXRlLnJlbGVhc2VkIiwgIkJpb3NhbXBsZS50ZXJtLm5hbWUiLCAiUGFpcmVkLmVuZCIsICJQYWlyZWQud2l0aCIsICJBdWRpdC5XQVJOSU5HIildLAogICAgICAgICAgICAgICAgICBXZXluX2VsX2FsX21ldGFkYXRhWywgYygiRmlsZS5hY2Nlc3Npb24iLCAiQmlvc2FtcGxlLkFnZSIsICJFeHBlcmltZW50LmRhdGUucmVsZWFzZWQiLCAiQmlvc2FtcGxlLnRlcm0ubmFtZSIsICJQYWlyZWQuZW5kIiwgIlBhaXJlZC53aXRoIiwgIkF1ZGl0LldBUk5JTkciKV0gKQoKCm1ldGFkYXRhIDwtIG1ldGFkYXRhW0F1ZGl0LldBUk5JTkchPSJsb3cgcmVwbGljYXRlIGNvbmNvcmRhbmNlLCBtaXNzaW5nIGZsb3djZWxsX2RldGFpbHMiLF0KCgoKYGBgCgoKCgoKCgpgYGB7cn0KCk1FX2ZpbmFsLnJlcDEgPC0gZnJlYWQoIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9vdXQuaGlnaF9xdWFsaXR5LnR4dCIpCk1FX2ZpbmFsLnJlcDIgPC0gZnJlYWQoIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMi9vdXQuaGlnaF9xdWFsaXR5LnR4dCIpCgpNRV9maW5hbCA8LSBNRV9maW5hbC5yZXAxWyBNRSAlaW4lIE1FX2ZpbmFsLnJlcDIkTUUsIF0KCgpNRV9jb3YgPC0gZnJlYWQoIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9vdXRfZmlsdGVyZWRfTUUuUFNJLnR4dCIpCk1FX2NvdlssIGA6PWAoRklMRV9OQU1FPUZpbGUsIE1FPU1FX2Nvb3JkcyldCgpudW1iZXJfb2ZfbWljcm9leG9ucyA8LSBsZW5ndGgoTUVfZmluYWxbICwgdW5pcXVlKE1FKV0pCgoKCk1FX2Nvdl9maWx0ZXJlZCA8LSBNRV9jb3ZbTUUgJWluJSBNRV9maW5hbFssIE1FXSAgLCBdCgoKYGBgCgoKYGBge3J9CmxpYnJhcnkoc3RyaW5naSkKCgoKCiNtYXQgPC0gc3RyaV9zcGxpdF9maXhlZChNRV9jb3ZfZmlsdGVyZWQkTUVfY292ZXJhZ2VzLCAnLCcsIHNpbXBsaWZ5PVQpCiNtYXQgPC0gYGRpbTwtYChhcy5udW1lcmljKG1hdCksIGRpbShtYXQpKSAgIyBjb252ZXJ0IHRvIG51bWVyaWMgYW5kIHNhdmUgZGltcwojcm93c3VtKG1hdCwgbmEucm09VCkKCiNzdW0obWF0LCBuYS5ybT1UKQoKCiNzYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKE1FX2Nvdl9maWx0ZXJlZCRNRV9jb3ZlcmFnZXMpLCAiLCIsIGZpeGVkPVQpLCBmdW5jdGlvbih4KSBzdW0oYXMubnVtZXJpYyh4KSkpCmBgYAoKCmBgYHtyfQojTUVfY292X2ZpbHRlcmVkWywgc3Ryc3BsaXQoIE1FX2NvdmVyYWdlcywgIiwiKSBdCgoKI2xpYnJhcnkoZHBseXIpCiNsaWJyYXJ5KHRpZHlyKQojZGYgJT4lCiMgICBzZXBhcmF0ZV9yb3dzKHksIHosIGNvbnZlcnQgPSBUUlVFKSAlPiUKIyAgIGdyb3VwX2J5KHgpICU+JSAKIyAgIHN1bW1hcmlzZV9hbGwoc3VtKQpgYGAKCgoKT2J0YWluaW4gUFNJIG1hdHJpeAoKYGBge3J9CgoKClRpc3N1ZXMgPC0gYXMuY2hhcmFjdGVyKG1ldGFkYXRhJEJpb3NhbXBsZS50ZXJtLm5hbWUpCm5hbWVzKFRpc3N1ZXMpIDwtIGFzLmNoYXJhY3RlcihtZXRhZGF0YSRGaWxlLmFjY2Vzc2lvbikKCkFnZXMgPC0gYXMuY2hhcmFjdGVyKG1ldGFkYXRhJEJpb3NhbXBsZS5BZ2UpCm5hbWVzKEFnZXMpIDwtIGFzLmNoYXJhY3RlcihtZXRhZGF0YSRGaWxlLmFjY2Vzc2lvbikKCgoKTUVfY292X2ZpbHRlcmVkICA8LSB1bmlxdWUoTUVfY292X2ZpbHRlcmVkW0ZJTEVfTkFNRSAlaW4lIG1ldGFkYXRhWyAsIEZpbGUuYWNjZXNzaW9uXSxdKQojTUVfY292X2ZpbHRlcmVkX0VOQ09ERSA8LSB1bmlxdWUoTUVfY292X2ZpbHRlcmVkW0ZJTEVfTkFNRSAlaW4lIG1ldGFkYXRhWyAsIEZpbGUuYWNjZXNzaW9uXSxdKQoKCgojY29sbmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3QpIDwtIGFzLmNoYXJhY3RlciggcGFzdGUoc2VwID0gIiAiLCBUaXNzdWVzW2NvbG5hbWVzKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0KV0sIEFnZXNbY29sbmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3QpXSkpICNUbyByZXBsYXNlIHRoZSBmaWxlIG5hbWUgYnkgdGhlIGJpb2xvZ2ljYWwgc2FtcGxlIG5hbWUKCiNUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCA8LSBUaXNzdWVfUFNJX21hdHJpeF9kY2FzdFssIG9yZGVyKHBhc3RlKHNlcCA9ICIgIiwgVGlzc3Vlc1tjb2xuYW1lcyhUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCldLCBBZ2VzW2NvbG5hbWVzKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0KV0pKV0KCgpgYGAKCgoKCgpQcm9iYWJpbGlzdGljIFBDQQoKCgoKYGBge3J9CgpsaWJyYXJ5KHBjYU1ldGhvZHMpCgpUaXNzdWVfUFNJX21hdHJpeF9tZWx0IDwtIE1FX2Nvdl9maWx0ZXJlZFssIGMoIk1FIiwgIkZJTEVfTkFNRSIsICJQU0kiKSBdClRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0IDwtIHJlc2hhcGUyOjpkY2FzdChUaXNzdWVfUFNJX21hdHJpeF9tZWx0LCBNRSB+IEZJTEVfTkFNRSkKcm93Lm5hbWVzKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0KSA8LSBUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCRNRQpUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCA8LSBkYXRhLm1hdHJpeChUaXNzdWVfUFNJX21hdHJpeF9kY2FzdClbLC0xXQoKClRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0W1Rpc3N1ZV9QU0lfbWF0cml4X2RjYXN0PT0iTmFOIl0gPC0gTkEKCmRpbShUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCkKCmRpbShUaXNzdWVfUFNJX21hdHJpeF9kY2FzdFthcHBseShUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCwgMSwgZnVuY3Rpb24oeCkgbGVuZ3RoKHdoaWNoKGlzLm5hKHgpKSkpIDwgMjcxKjAuOSwgXSkKCmRpbShUaXNzdWVfUFNJX21hdHJpeF9kY2FzdFthcHBseShUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCwgMSwgZnVuY3Rpb24oeCkgbGVuZ3RoKHdoaWNoKGlzLm5hKHgpKSkpIDwgMjg5KjAuOSwgXSkKCnJlc3VsdCA8LSBwY2EodChUaXNzdWVfUFNJX21hdHJpeF9kY2FzdFthcHBseShUaXNzdWVfUFNJX21hdHJpeF9kY2FzdCwgMSwgZnVuY3Rpb24oeCkgbGVuZ3RoKHdoaWNoKGlzLm5hKHgpKSkpIDwgMjg5KjAuOSwgXSksIG1ldGhvZD0icHBjYSIsIG5QY3M9Mywgc2VlZD0xMjMpCiMjIEdldCB0aGUgZXN0aW1hdGVkIGNvbXBsZXRlIG9ic2VydmF0aW9ucwpjT2JzIDwtIGNvbXBsZXRlT2JzKHJlc3VsdCkKIyMgUGxvdCB0aGUgc2NvcmVzCnBsb3RQY3MocmVzdWx0LCB0eXBlID0gInNjb3JlcyIpCgoKCgpzdW1tYXJ5KHJlc3VsdCkKCgoKCmBgYAoKCgoKYGBge3J9CgpUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhIDwtIHQoY09icykKClRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2FbVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYT4xXSA8LSAxClRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2FbVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYTwwXSA8LSAwCgoKIyNjb2xuYW1lcyhUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhKSA8LSBhcy5jaGFyYWN0ZXIoIHBhc3RlKHNlcCA9ICIgIiwgVGlzc3Vlc1tjb2xuYW1lcyhUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhKV0sIEFnZXNbY29sbmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYSldKSkgI1RvIHJlcGxhc2UgdGhlIGZpbGUgbmFtZSBieSB0aGUgYmlvbG9naWNhbCBzYW1wbGUgbmFtZQoKCgojdGlzc3VlX2hlYXRtYXAgPC0gcGhlYXRtYXA6OnBoZWF0bWFwKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EsICAsIGZvbnRzaXplID0gNCwgIGN1dHJlZV9yb3dzID0gMjQsIGN1dHJlZV9jb2xzID0gMTYsIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiKQoKCgpgYGAKCgoKCmBgYHtyfQoKI1Rpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EgPC0gdChjT2JzKQoKI1Rpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2FbVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYT4xXSA8LSAxCiNUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhW1Rpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2E8MF0gPC0gMAoKCiMjY29sbmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYSkgPC0gYXMuY2hhcmFjdGVyKCBwYXN0ZShzZXAgPSAiICIsIFRpc3N1ZXNbY29sbmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYSldLCBBZ2VzW2NvbG5hbWVzKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EpXSkpICNUbyByZXBsYXNlIHRoZSBmaWxlIG5hbWUgYnkgdGhlIGJpb2xvZ2ljYWwgc2FtcGxlIG5hbWUKCgoKI3Rpc3N1ZV9oZWF0bWFwIDwtIHBoZWF0bWFwOjpwaGVhdG1hcChUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhLCAgLCBmb250c2l6ZSA9IDQsICBjdXRyZWVfcm93cyA9IDI0LCBjdXRyZWVfY29scyA9IDE3LCBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIikKCgoKYGBgCgoKCmBgYHtyfQoKaGNfY29scyA8LSBoY2x1c3QoZGlzdCh0KFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EpKSwgbWV0aG9kID0gIndhcmQuRDIiKQpoY19yb3dzIDwtIGhjbHVzdChkaXN0KFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EpLCBtZXRob2QgPSAid2FyZC5EMiIpCgpgYGAKCgoKCgpgYGB7cn0KVGlzc3Vlc19uYW1lIDwtIGFzLmNoYXJhY3RlcihtZXRhZGF0YSRCaW9zYW1wbGUudGVybS5uYW1lKQpuYW1lcyhUaXNzdWVzX25hbWUpIDwtIGFzLmNoYXJhY3RlcihtZXRhZGF0YSRGaWxlLmFjY2Vzc2lvbikKClRpc3N1ZXNfYWdlIDwtIGFzLmNoYXJhY3RlcihtZXRhZGF0YSRCaW9zYW1wbGUuQWdlKQpuYW1lcyhUaXNzdWVzX2FnZSkgPC0gYXMuY2hhcmFjdGVyKG1ldGFkYXRhJEZpbGUuYWNjZXNzaW9uKQoKVGlzc3VlX2RhdGUgPC0gYXMuY2hhcmFjdGVyKG1ldGFkYXRhJEV4cGVyaW1lbnQuZGF0ZS5yZWxlYXNlZCkKbmFtZXMoVGlzc3VlX2RhdGUpIDwtIGFzLmNoYXJhY3RlcihtZXRhZGF0YSRGaWxlLmFjY2Vzc2lvbikKCmBgYAoKCgoKYGBge3J9CiNUaXNzdWVfY2x1c3RlcnMgPC0gY3V0cmVlKGhjX2NvbHMsIGsgPSAxNikKI1Rpc3N1ZV9jbHVzdGVycyA8LSBjYmluZChUaXNzdWVfY2x1c3RlcnMsIFRpc3N1ZXNfbmFtZVtuYW1lcyhUaXNzdWVfY2x1c3RlcnMpXSwgVGlzc3Vlc19hZ2VbbmFtZXMoVGlzc3VlX2NsdXN0ZXJzKV0sIFRpc3N1ZV9kYXRlW25hbWVzKFRpc3N1ZV9jbHVzdGVycyldKSAKCiNjb2xuYW1lcyhUaXNzdWVfY2x1c3RlcnMpIDwtIGMoImNsdXN0ZXIiLCAibmFtZSIsICJhZ2UiLCAiZGF0ZSIpCgojVGlzc3VlX2NsdXN0ZXJzIDwtIGRhdGEuZnJhbWUoVGlzc3VlX2NsdXN0ZXJzKQoKIyNUaXNzdWVfY2x1c3RlcnNfc3VtW3doaWNoKGdyZXBsKCJoaW5kYnJhaW58bWlkYnJhaW58Zm9yZWJyYWlufG5ldXJhbFwgdHViZSIsIFRpc3N1ZV9jbHVzdGVyc19zdW0kbmFtZSkpLCBdCgojVGlzc3VlX2NsdXN0ZXJzJG5hbWUgPC0gZmFjdG9yKFRpc3N1ZV9jbHVzdGVycyRuYW1lLCBsZXZlbD1jKCAic2tlbGV0YWwgbXVzY2xlIHRpc3N1ZSIsICJoZWFydCIsICJ0aHltdXMiLCAic3BsZWVuIiwgImxpdmVyIiwgICJhZHJlbmFsIGdsYW5kIiwgImludGVzdGluZSIsICJzdG9tYWNoIiwgImx1bmciLCAgImtpZG5leSIsICJibGFkZGVyIiwgImxpbWIiLCAiZW1icnlvbmljIGZhY2lhbCBwcm9taW5lbmNlIiwgImZvcmVicmFpbiIsICJoaW5kYnJhaW4iLCAibWlkYnJhaW4iLCAibmV1cmFsIHR1YmUiLCAid2hvbGUgY29ydGV4IikpCgoKI1Rpc3N1ZV9jbHVzdGVycyRhZ2UgPC0gbWFwdmFsdWVzKFRpc3N1ZV9jbHVzdGVycyRhZ2UsIAojICAgICAgICAgIGZyb20gPSBjKCIxMC41IGRheSIsICIxMS41IGRheSIsICIxMi41IGRheSIsICIxMy41IGRheSIsICIxNC41IGRheSIsICIxNS41IGRheSIsICIxNi41IGRheSIsICIwIGRheSIsICI4IHdlZWsiLCAiUDBhIiwgIlAwYiIsICJQMTEwYSIsICJQMTEwYiIsICJQMTVhIiwgIlAxNWIiLCAiUDMwYSIsICJQMzBiIiwgIlA0YSIsICMiUDRhIiwgIlA3YSIsICJQN2IiLCAiMjFNYSIsICIyMU1iIiwgIkUxNC41IiwgIkUxNi41IiwgIlA0YiIpLAojICAgICAgICAgdG8gPSBjKDEwLjUsIDExLjUsIDEyLjUsIDEzLjUsIDE0LjUsIDE1LjUsIDE2LjUsIDIxLCA1OSwgMjEsIDIxLCAxMzEsIDEzMSwgMzYsIDM2LCA0MSw0MSwgMjUsIDI1LCAyNywyNywgNjUxLCA2NTEsIDE0LjUsIDE2LjUsIDI1ICkgKQoKCgoKI1Rpc3N1ZV9jbHVzdGVycyRhZ2UgPC0gZmFjdG9yKFRpc3N1ZV9jbHVzdGVycyRhZ2UsIGxldmVscyA9IGFzLmNoYXJhY3Rlcihzb3J0KGFzLm51bWVyaWMobGV2ZWxzKFRpc3N1ZV9jbHVzdGVycyRhZ2UpKSkpKQoKCgoKYGBgCgoKCmBgYHtyfQpUaXNzdWVfY2x1c3RlcnMgPC0gY3V0cmVlKGhjX2NvbHMsIGsgPSAxNikKVGlzc3VlX2NsdXN0ZXJzIDwtIGNiaW5kKFRpc3N1ZV9jbHVzdGVycywgVGlzc3Vlc19uYW1lW25hbWVzKFRpc3N1ZV9jbHVzdGVycyldLCBUaXNzdWVzX2FnZVtuYW1lcyhUaXNzdWVfY2x1c3RlcnMpXSwgVGlzc3VlX2RhdGVbbmFtZXMoVGlzc3VlX2NsdXN0ZXJzKV0pIAoKY29sbmFtZXMoVGlzc3VlX2NsdXN0ZXJzKSA8LSBjKCJjbHVzdGVyIiwgIm5hbWUiLCAiYWdlIiwgImRhdGUiKQoKVGlzc3VlX2NsdXN0ZXJzIDwtIGRhdGEuZnJhbWUoVGlzc3VlX2NsdXN0ZXJzKQoKI1Rpc3N1ZV9jbHVzdGVyc19zdW1bd2hpY2goZ3JlcGwoImhpbmRicmFpbnxtaWRicmFpbnxmb3JlYnJhaW58bmV1cmFsXCB0dWJlIiwgVGlzc3VlX2NsdXN0ZXJzX3N1bSRuYW1lKSksIF0KClRpc3N1ZV9jbHVzdGVycyRuYW1lIDwtIGZhY3RvcihUaXNzdWVfY2x1c3RlcnMkbmFtZSwgbGV2ZWw9YyggInNrZWxldGFsIG11c2NsZSB0aXNzdWUiLCAiaGVhcnQiLCAidGh5bXVzIiwgInNwbGVlbiIsICJsaXZlciIsICAiYWRyZW5hbCBnbGFuZCIsICJpbnRlc3RpbmUiLCAic3RvbWFjaCIsICJsdW5nIiwgICJraWRuZXkiLCAiYmxhZGRlciIsICJsaW1iIiwgImVtYnJ5b25pYyBmYWNpYWwgcHJvbWluZW5jZSIsICJmb3JlYnJhaW4iLCAiaGluZGJyYWluIiwgIm1pZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgIndob2xlIGNvcnRleCIpKQoKI1Rpc3N1ZV9jbHVzdGVycyRhZ2UgPC0gZmFjdG9yKFRpc3N1ZV9jbHVzdGVycyRhZ2UsIGxldmVscz1jKCIxMC41IGRheSIsICIxMS41IGRheSIsICIxMi41IGRheSIsICIxMy41IGRheSIsICIxNC41IGRheSIsICIxNS41IGRheSIsICIxNi41IGRheSIsICIwIGRheSIsICI4IHdlZWsiKSkKClRpc3N1ZV9jbHVzdGVycyRGaWxlLmFjY2Vzc2lvbiA8LSByb3cubmFtZXMoVGlzc3VlX2NsdXN0ZXJzKQoKClRpc3N1ZV9jbHVzdGVycyA8LSBkYXRhLnRhYmxlKFRpc3N1ZV9jbHVzdGVycykKCgpUaXNzdWVfY2x1c3RlcnMkYWdlIDwtIG1hcHZhbHVlcyhUaXNzdWVfY2x1c3RlcnMkYWdlLCAKICAgICAgICAgIGZyb20gPSBjKCIxMC41IGRheSIsICIxMS41IGRheSIsICIxMi41IGRheSIsICIxMy41IGRheSIsICIxNC41IGRheSIsICIxNS41IGRheSIsICIxNi41IGRheSIsICIwIGRheSIsICI4IHdlZWsiLCAiUDBhIiwgIlAwYiIsICJQMTEwYSIsICJQMTEwYiIsICJQMTVhIiwgIlAxNWIiLCAiUDMwYSIsICJQMzBiIiwgIlA0YSIsICJQNGEiLCAiUDdhIiwgIlA3YiIsICIyMU1hIiwgIjIxTWIiLCAiRTE0LjUiLCAiRTE2LjUiLCAiUDRiIiksCiAgICAgICAgICB0byA9IGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSwgMjEsIDU5LCAyMSwgMjEsIDEzMSwgMTMxLCAzNiwgMzYsIDQxLDQxLCAyNSwgMjUsIDI3LDI3LCA2NTEsIDY1MSwgMTQuNSwgMTYuNSwgMjUgKSApCgoKCmBgYAoKCgoKCgoKCmBgYHtyfQoKTUVfY2x1c3RlcnMgPC0gY3V0cmVlKGhjX3Jvd3MsIGsgPSAyNCkKClBDQV9sb2FkaW5ncyA8LSBkYXRhLmZyYW1lKGxvYWRpbmdzKHJlc3VsdCkpClBDQV9sb2FkaW5ncyRNRSA8LSByb3cubmFtZXMoUENBX2xvYWRpbmdzKQoKClBDQV9sb2FkaW5ncyA8LSBkYXRhLnRhYmxlKFBDQV9sb2FkaW5ncykKUENBX2xvYWRpbmdzWywgYDo9YChQQzE9LVBDMSwgUEMyPS1QQzIpXQoKClBDQV9sb2FkaW5ncyRNRV9jbHVzdGVyIDwtIE1FX2NsdXN0ZXJzW1BDQV9sb2FkaW5ncyRNRV0KCgpQQ0FfbG9hZGluZ3Nfc3RhdHMgPC0gUENBX2xvYWRpbmdzWyAsIC4oUEMxX21lYW49bWVhbihQQzEpKSAsIGJ5PSJNRV9jbHVzdGVyIl0KTUVfY2x1c3Rlcl9sb2FkaW5nX29yZGVyIDwtIFBDQV9sb2FkaW5nc19zdGF0c1tvcmRlcihQQzFfbWVhbildJE1FX2NsdXN0ZXIKClBDQV9sb2FkaW5ncyRNRV9jbHVzdGVyIDwtIGZhY3RvcihQQ0FfbG9hZGluZ3MkTUVfY2x1c3RlciAsIGxldmVscz1NRV9jbHVzdGVyX2xvYWRpbmdfb3JkZXIpCgoKZ2dwbG90KFBDQV9sb2FkaW5ncykgKwogIGdlb21fYm94cGxvdChhZXMoYXMuZmFjdG9yKE1FX2NsdXN0ZXIpICwgUEMxKSkKCgpgYGAKCgoKYGBge3J9CmdncGxvdChQQ0FfbG9hZGluZ3MpICsKICBnZW9tX2JveHBsb3QoYWVzKGFzLmZhY3RvcihNRV9jbHVzdGVyKSAsIFBDMikpCmBgYAoKCgoKYGBge3J9CmdncGxvdChQQ0FfbG9hZGluZ3MpICsKICBnZW9tX2JveHBsb3QoYWVzKGFzLmZhY3RvcihNRV9jbHVzdGVyKSAsIFBDMykpCmBgYAoKCgoKCmBgYHtyfQoKUENBX2xvYWRpbmdzX3N0YXRzIDwtIFBDQV9sb2FkaW5nc1sgLCAuKFBDMV9tZWFuPW1lYW4oUEMxKSkgLCBieT0iTUVfY2x1c3RlciJdCgpQQ0FfbG9hZGluZ3Nfc3RhdHNfUEMyIDwtIFBDQV9sb2FkaW5nc1sgLCAuKFBDMl9tZWFuPW1lYW4oUEMyKSkgLCBieT0iTUVfY2x1c3RlciJdCgoKCk1FX2NsdXN0ZXJfbG9hZGluZ19vcmRlciA8LSBQQ0FfbG9hZGluZ3Nfc3RhdHNbb3JkZXIoUEMxX21lYW4pXSRNRV9jbHVzdGVyCmBgYAoKTmV1cm9uYWwgTWljcm9leG9ucwoKYGBge3J9ClBDQV9sb2FkaW5nc19zdGF0c1thYnMoUEMxX21lYW4pPjAuMDMsIF1bb3JkZXIoUEMxX21lYW4pXQpgYGAKCgoKYGBge3J9ClBDQV9sb2FkaW5nc19zdGF0c19QQzJbYWJzKFBDMl9tZWFuKT4wLjAzLCBdW29yZGVyKC1QQzJfbWVhbildCmBgYAoKCgoKYGBge3J9ClRpc3N1ZV9QU0lfbWF0cml4X21lbHRfcHBjYSA8LSBtZWx0KFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EpCgpjb2xuYW1lcyhUaXNzdWVfUFNJX21hdHJpeF9tZWx0X3BwY2EpIDwtIGMoIk1FIiwgIkZJTEVfTkFNRSIsICJQU0kiKQoKTUVfY2x1c3RlcnNfdGFibGUgPC0gZGF0YS5mcmFtZShNRV9jbHVzdGVycykKCk1FX2NsdXN0ZXJzX3RhYmxlJE1FIDwtIHJvdy5uYW1lcyhNRV9jbHVzdGVyc190YWJsZSkKTUVfY2x1c3RlcnNfdGFibGUgPC0gZGF0YS50YWJsZShNRV9jbHVzdGVyc190YWJsZSkKCgpNRV9jbHVzdGVyc19QU0kgPC0gIGRhdGEudGFibGUobWVyZ2UoVGlzc3VlX1BTSV9tYXRyaXhfbWVsdF9wcGNhLCBNRV9jbHVzdGVyc190YWJsZSAsIGJ5PWMoIk1FIikpKQoKCgpmd3JpdGUoIE1FX2NsdXN0ZXJzX1BTSSwgIi4uLy4uL1BhcGVyL0phY29iL01FX2NsdXN0ZXJzX1BTSS50dnMiLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBUUlVFLCBzZXA9Ilx0IikKCmZ3cml0ZSggTUVfY2x1c3Rlcl9uYW1lcywgIi4uLy4uL1BhcGVyL0phY29iL01FX2NsdXN0ZXJfbmFtZXMudHZzIiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSwgc2VwPSJcdCIpCgpgYGAKCgpgYGB7cn0KTUVfY2x1c3RlcnNfUFNJJE1FX2NsdXN0ZXJzIDwtIG1hcHZhbHVlcyhNRV9jbHVzdGVyc19QU0kkTUVfY2x1c3RlcnMsIAogICAgICAgICAgZnJvbSA9MToxOCwKICAgICAgICAgIHRvID0gYygiSTEiLCAiRTEiLCAiRTMiLCAiSTIiLCAiTjEiLCAiTTEiLCAiTjIiLCAiTk0zIiwgIk5NMiIsICJONSIsICJOTTEiLCAiTjMiLCAiTjQiLCAiTk4yIiwgIkUyIiwgIkk0IiwgIkkzIiwgIk5OMSIpKQpgYGAKCgoKYGBge3J9ClRpc3N1ZV9QU0lfbWF0cml4X21lbHRfcHBjYSA8LSBkYXRhLnRhYmxlKFRpc3N1ZV9QU0lfbWF0cml4X21lbHRfcHBjYSkKClRpc3N1ZV9QU0lfbWF0cml4X21lbHRfcHBjYQoKYGBgCgoKCgpgYGB7cn0KClBDQV9sb2FkaW5nc19zdGF0cyA8LSBQQ0FfbG9hZGluZ3NbICwgLihQQzFfbWVhbj1tZWFuKFBDMSksIFBDMl9tZWFuPW1lYW4oUEMyKSApICwgYnk9Ik1FX2NsdXN0ZXIiXQoKI1BDQV9sb2FkaW5nc19zdGF0c1ssIFBDMV9tZWFuOj0tUEMxX21lYW5dCgpQQ0FfbG9hZGluZ3Nfc3RhdHNbb3JkZXIoLVBDMV9tZWFuKV0KUENBX2xvYWRpbmdzX3N0YXRzW29yZGVyKFBDMl9tZWFuKV0KCiNQQ0FfbG9hZGluZ3Nfc3RhdHNfUEMyWywgUEMyX21lYW46PS1QQzJfbWVhbl0KYGBgCmBgYHtyfQpQQ0FfbG9hZGluZ3Nfc3RhdHNbb3JkZXIoUEMyX21lYW4pXQoKYGBgCgoKYGBge3J9CgoKCmxvYWRpbmdfdGhyZXNob2xkIDwtIDAuMDEwCmxvYWRpbmdfdGhyZXNob2xkX1BDMiA8LSAwLjAxMAoKCk5ldXJvbmFsIDwtIFBDQV9sb2FkaW5nc19zdGF0c1sgcm91bmQoUEMxX21lYW4sIDMpID4gIGxvYWRpbmdfdGhyZXNob2xkLCBdW29yZGVyKC1QQzFfbWVhbildJE1FX2NsdXN0ZXIKTXVzY3VsYXIgPC0gUENBX2xvYWRpbmdzX3N0YXRzX1BDMltyb3VuZChQQzJfbWVhbiwgMykgPCAtbG9hZGluZ190aHJlc2hvbGRfUEMyLCBdW29yZGVyKFBDMl9tZWFuKV0kTUVfY2x1c3RlcgoKTm9uTmV1cm9uYWw8LSBQQ0FfbG9hZGluZ3Nfc3RhdHNbIHJvdW5kKFBDMV9tZWFuLCAzKSA8PSAtbG9hZGluZ190aHJlc2hvbGQsIF1bb3JkZXIoUEMxX21lYW4pXSRNRV9jbHVzdGVyCgojV2Vha05ldXJvbmFsIDwtIFBDQV9sb2FkaW5nc19zdGF0c1sgIHJvdW5kKFBDMV9tZWFuLCAzKSA8IGxvYWRpbmdfdGhyZXNob2xkICYgcm91bmQoUEMxX21lYW4sIDMpID49ICAwLjAxLCBdW29yZGVyKFBDMV9tZWFuKV0kTUVfY2x1c3RlcgoKTiA9IDEgCk5NID0gMQpOTiA9IDEKTSA9IDEKV04gPSAxCgpNRV9jbHVzdGVyX25hbWVzIDwtIGRhdGEudGFibGUoKQoKCmZvciAoTUVfY2x1c3RlciBpbiBOZXVyb25hbCl7CiAgCiAgaWYgKE1FX2NsdXN0ZXIgJWluJSBNdXNjdWxhcil7CiAgICAKICAgIE1FX2NsdXN0ZXIubmFtZSA9IHBhc3RlMCgiTk0iLCBOTSkKICAgIE1FX2NsdXN0ZXIudHlwZSA9ICJOZXVyby1NdXNjdWxhciIKICAgIAogICAgTUVfY2x1c3Rlcl9uYW1lcyA9IHJiaW5kKE1FX2NsdXN0ZXJfbmFtZXMsIGNiaW5kKE1FX2NsdXN0ZXIsIE1FX2NsdXN0ZXIubmFtZSwgTUVfY2x1c3Rlci50eXBlICApKQogICAgCiAgICBOTSA9IE5NICsgMQogICAgCiAgfQoKICAKICBlbHNlIHsKICAgIAogICAgTUVfY2x1c3Rlci5uYW1lID0gcGFzdGUwKCJOIiwgTikKICAgIE1FX2NsdXN0ZXIudHlwZSA9ICJOZXVyb25hbCIKICAgIAogICAgTUVfY2x1c3Rlcl9uYW1lcyA9IHJiaW5kKE1FX2NsdXN0ZXJfbmFtZXMsICBjYmluZChNRV9jbHVzdGVyLCBNRV9jbHVzdGVyLm5hbWUsIE1FX2NsdXN0ZXIudHlwZSApKQogICAgCiAgICBOID0gTiArIDEKICAgIAogIH0KICAKfQoKCmZvciAoTUVfY2x1c3RlciBpbiBOb25OZXVyb25hbCkgewogIAoKICBNRV9jbHVzdGVyLm5hbWUgPSBwYXN0ZTAoIk5OIiwgTk4pCiAgTUVfY2x1c3Rlci50eXBlID0gIk5vbi1OZXVyb25hbCIKICAKICBNRV9jbHVzdGVyX25hbWVzID0gcmJpbmQoTUVfY2x1c3Rlcl9uYW1lcywgIGNiaW5kKE1FX2NsdXN0ZXIsIE1FX2NsdXN0ZXIubmFtZSwgTUVfY2x1c3Rlci50eXBlICkpCiAgCiAgTk4gPSBOTiArIDEKICAKICAKfQoKCiNmb3IgKE1FX2NsdXN0ZXIgaW4gV2Vha05ldXJvbmFsKSB7CiAgCgojICBNRV9jbHVzdGVyLm5hbWUgPSBwYXN0ZTAoIldOIiwgV04pCiMgIE1FX2NsdXN0ZXIudHlwZSA9ICJXZWFrLU5ldXJvbmFsIgogIAojICBNRV9jbHVzdGVyX25hbWVzID0gcmJpbmQoTUVfY2x1c3Rlcl9uYW1lcywgIGNiaW5kKE1FX2NsdXN0ZXIsIE1FX2NsdXN0ZXIubmFtZSwgTUVfY2x1c3Rlci50eXBlICkpCiAgCiMgIFdOID0gV04gKyAxCiAgCiAgCiN9CgoKCmZvciAoTUVfY2x1c3RlciBpbiBNdXNjdWxhcil7CiAgCiAgCiAgaWYgKCAoTUVfY2x1c3RlciAlaW4lIE1FX2NsdXN0ZXJfbmFtZXMkTUVfY2x1c3Rlcik9PUYpIHsKICAKICAKICBNRV9jbHVzdGVyLm5hbWUgPSBwYXN0ZTAoIk0iLCBNKQogIE1FX2NsdXN0ZXIudHlwZSA9ICJNdXNjdWxhciIKICAKICBNRV9jbHVzdGVyX25hbWVzID0gcmJpbmQoTUVfY2x1c3Rlcl9uYW1lcywgIGNiaW5kKE1FX2NsdXN0ZXIsIE1FX2NsdXN0ZXIubmFtZSwgTUVfY2x1c3Rlci50eXBlICkpCiAgCiAgTSA9IE0gKyAxCiAgCiAgfQogIAogIAogIH0KCgpNRV9jbHVzdGVyX25hbWVzCgoKTUVfY2x1c3RlcnNfbWVhbl9QU0lzIDwtICBNRV9jbHVzdGVyc19QU0lbLCAuKG1lYW5fUFNJPW1lYW4oUFNJKSwgc2RfUFNJPXNkKFBTSSkpLCBieT0iTUVfY2x1c3RlcnMiIF0KCk1FX2NsdXN0ZXJzX2ZsYXQgPC0gTUVfY2x1c3RlcnNfbWVhbl9QU0lzWyAhIE1FX2NsdXN0ZXJzICVpbiUgTUVfY2x1c3Rlcl9uYW1lcyRNRV9jbHVzdGVyLCAgXQoKCkUgPSAxCkkgPSAxCk8gPSAxIAoKCgpmb3IgKE1FX2NsdXN0ZXIgaW4gTUVfY2x1c3RlcnNfZmxhdFsgbWVhbl9QU0kgPD0gMS8zLCAgXVtvcmRlcihtZWFuX1BTSSldJE1FX2NsdXN0ZXJzKSB7CiAgCiAgCiAgTUVfY2x1c3Rlci5uYW1lID0gcGFzdGUwKCJFIiwgRSkKICBNRV9jbHVzdGVyLnR5cGUgPSAiRXhjbHVkZWQiCiAgCiAgTUVfY2x1c3Rlcl9uYW1lcyA9IHJiaW5kKE1FX2NsdXN0ZXJfbmFtZXMsICBjYmluZChNRV9jbHVzdGVyLCBNRV9jbHVzdGVyLm5hbWUsIE1FX2NsdXN0ZXIudHlwZSApKQogIAogIEUgPSBFICsgMQogIAogIAp9IAoKCgpmb3IgKE1FX2NsdXN0ZXIgaW4gTUVfY2x1c3RlcnNfZmxhdFsgbWVhbl9QU0k+PTIvMywgIF1bb3JkZXIoLW1lYW5fUFNJKV0kTUVfY2x1c3RlcnMpIHsKICAKICAKICBNRV9jbHVzdGVyLm5hbWUgPSBwYXN0ZTAoIkkiLCBJKQogIE1FX2NsdXN0ZXIudHlwZSA9ICJJbmNsdWRlZCIKICAKICBNRV9jbHVzdGVyX25hbWVzID0gcmJpbmQoTUVfY2x1c3Rlcl9uYW1lcywgIGNiaW5kKE1FX2NsdXN0ZXIsIE1FX2NsdXN0ZXIubmFtZSwgTUVfY2x1c3Rlci50eXBlICkpCiAgCiAgSSA9IEkgKyAxCiAgCiAgCn0KCgoKCmZvciAoTUVfY2x1c3RlciBpbiBNRV9jbHVzdGVyc19mbGF0WyBtZWFuX1BTSSA+IDEvMyAgJiAgbWVhbl9QU0kgPCAyLzMgICwgIF1bb3JkZXIobWVhbl9QU0kpXSRNRV9jbHVzdGVycykgewogIAogIAogIE1FX2NsdXN0ZXIubmFtZSA9IHBhc3RlMCgiTyIsIE8pCiAgTUVfY2x1c3Rlci50eXBlID0gIk90aGVyIgogIAogIE1FX2NsdXN0ZXJfbmFtZXMgPSByYmluZChNRV9jbHVzdGVyX25hbWVzLCAgY2JpbmQoTUVfY2x1c3RlciwgTUVfY2x1c3Rlci5uYW1lLCBNRV9jbHVzdGVyLnR5cGUgKSkKICAKICBPID0gTyArIDEKICAKICAKfSAKTUVfY2x1c3Rlcl9uYW1lcwpgYGAKCgoKYGBge3J9CgpNRV9jbHVzdGVyX25hbWVzJE1FX2NsdXN0ZXIgPC0gYXMubnVtZXJpYyhNRV9jbHVzdGVyX25hbWVzJE1FX2NsdXN0ZXIpCgpNRV9jbHVzdGVyX25hbWVzIDwtIG1lcmdlKCB4PU1FX2NsdXN0ZXJfbmFtZXMsIHk9TUVfY2x1c3RlcnNfbWVhbl9QU0lzLCBieS54PSJNRV9jbHVzdGVyIiwgYnkueT0iTUVfY2x1c3RlcnMiKQoKUENBX2xvYWRpbmdzX3N0YXRzJE1FX2NsdXN0ZXIgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoUENBX2xvYWRpbmdzX3N0YXRzJE1FX2NsdXN0ZXIpKQoKUENBX2xvYWRpbmdzX3N0YXRzX1BDMiRNRV9jbHVzdGVyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFBDQV9sb2FkaW5nc19zdGF0c19QQzIkTUVfY2x1c3RlcikpCgoKTUVfY2x1c3Rlcl9uYW1lcyA8LSBtZXJnZShNRV9jbHVzdGVyX25hbWVzLCBQQ0FfbG9hZGluZ3Nfc3RhdHMsIGJ5PSJNRV9jbHVzdGVyIikKI01FX2NsdXN0ZXJfbmFtZXMgPC0gbWVyZ2UoTUVfY2x1c3Rlcl9uYW1lcywgUENBX2xvYWRpbmdzX3N0YXRzX1BDMiwgYnk9Ik1FX2NsdXN0ZXIiKQoKTUVfY2x1c3Rlcl9uYW1lcyRNRV9jbHVzdGVyLnR5cGUgPC0gZmFjdG9yKE1FX2NsdXN0ZXJfbmFtZXMkTUVfY2x1c3Rlci50eXBlLCBsZXZlbHMgPSBjKCJFeGNsdWRlZCIsICJJbmNsdWRlZCIsICJOZXVyb25hbCIsICAiTm9uLU5ldXJvbmFsIiwgIk11c2N1bGFyIiwgICJOZXVyby1NdXNjdWxhciIsICJPdGhlciIpKQoKCgpgYGAKCgoKCmBgYHtyfQpGaWc1LlguMiA8LSBnZ3Bsb3QoTUVfY2x1c3Rlcl9uYW1lcykgKwogIGdlb21fdGV4dChhZXMoeD1QQzFfbWVhbiwgeT0tUEMyX21lYW4sIGxhYmVsID0gTUVfY2x1c3Rlci5uYW1lLCBjb2xvdXIgPSBNRV9jbHVzdGVyLnR5cGUgKSwgKSArCiAgeGxhYigiTWVhbiBQQzEgbG9hZGluZyIpICsKICB5bGFiKCJNZWFuIFBDMiBsb2FkaW5nIikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKQoKCkZpZzUuWC4yCgpgYGAKCgpgYGB7cn0KRmlnNS5YLjMgPC0gZ2dwbG90KE1FX2NsdXN0ZXJfbmFtZXMpICsKICBnZW9tX3RleHQoYWVzKHg9bWVhbl9QU0ksIHk9c2RfUFNJLCBsYWJlbCA9IE1FX2NsdXN0ZXIubmFtZSwgY29sb3VyID0gTUVfY2x1c3Rlci50eXBlICksICkgKwogIHhsYWIoIk1lYW4gUFNJIikgKwogIHlsYWIoIlBTSSBzdGFuZGFyIGRldmlhdGlvbiIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikgCiAgCgoKRmlnNS5YLjMKYGBgCgoKCgoKCmBgYHtyfQoKCk1FX2NsdXN0ZXJzLnRhYmxlIDwtIGNiaW5kKE1FX2NsdXN0ZXJzLCBuYW1lcyhNRV9jbHVzdGVycykpCmNvbG5hbWVzKE1FX2NsdXN0ZXJzLnRhYmxlKSA8LSBjKCJNRV9jbHVzdGVycyIsICJNRSIpCgpNRV9jbHVzdGVycy50YWJsZSA8LSBkYXRhLnRhYmxlKE1FX2NsdXN0ZXJzLnRhYmxlKQpNRV9jbHVzdGVycy50YWJsZSRNRV9jbHVzdGVycyA8LSBhcy5udW1lcmljKE1FX2NsdXN0ZXJzLnRhYmxlJE1FX2NsdXN0ZXJzKQoKCk1FX2NsdXN0ZXJfaW5mbyA8LSBtZXJnZShNRV9jbHVzdGVycy50YWJsZSwgTUVfZmluYWxbLCBjKCJNRSIsICJsZW5fbWljcm9fZXhvbl9zZXFfZm91bmQiLCAiVTJfc2NvcmVzIildLCBieT0iTUUiKQpNRV9jbHVzdGVyX2luZm8gPC0gZGF0YS50YWJsZShNRV9jbHVzdGVyX2luZm8pCgoKTUVfY2x1c3Rlcl9pbmZvX2J5IDwtIE1FX2NsdXN0ZXJfaW5mb1sgLCAuKGFzeW0gPSBzdW0obGVuX21pY3JvX2V4b25fc2VxX2ZvdW5kICUlIDMpLAogICAgICAgICAgICAgICAgICAgIG1lYW5fVTJfc2NvcmUgPSBtZWFuKFUyX3Njb3JlcyksCiAgICAgICAgICAgICAgICAgICAgdG90YWw9Lk4KICAgICAgICAgICAgICAgICAgICApLCBieT0iTUVfY2x1c3RlcnMiICBdCgpNRV9jbHVzdGVyX2luZm9fYnlbLCBzeW1ldHJpY2FsX2ZyYWN0aW9uOj0odG90YWwtYXN5bSkvdG90YWxdCgoKTUVfY2x1c3Rlcl9uYW1lcyA8LSBtZXJnZShNRV9jbHVzdGVyX25hbWVzLCBNRV9jbHVzdGVyX2luZm9fYnksIGJ5Lng9Ik1FX2NsdXN0ZXIiLCBieS55PSJNRV9jbHVzdGVycyIpCgoKCgojTUVfY2x1c3Rlcl9pbmZvIDwtIG1lcmdlKE1FX2NsdXN0ZXJfaW5mb19ieVssIC4oTUVfY2x1c3RlcnM9dW5pcXVlKE1FX2NsdXN0ZXJzKSksIGJ5PU1FXSwgTUVfZmluYWxbLCBjKCJNRSIsICJsZW5fbWljcm9fZXhvbl9zZXFfZm91bmQiLCAiVTJfc2NvcmVzIildLCBieT0iTUUiKQoKCiAKCgoKCgoKRmlnNS5YLjQgPC0gZ2dwbG90KE1FX2NsdXN0ZXJfbmFtZXMpICsKICBnZW9tX3RleHQoYWVzKHg9c3ltZXRyaWNhbF9mcmFjdGlvbiwgeT1tZWFuX1UyX3Njb3JlLCBsYWJlbCA9IE1FX2NsdXN0ZXIubmFtZSwgY29sb3VyID0gTUVfY2x1c3Rlci50eXBlICksICkgKwogIHhsYWIoIkluLWZyYW1lIG1pY3JvZXhvbiBmcmFjdGlvbiIpICsKICB5bGFiKCJNZWFuIHNwbGljaW5nIHN0cmVuZ3RoIikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKQoKCkZpZzUuWC40CiAgCmBgYAoKCmBgYHtyfQpNRV9jbHVzdGVyX25hbWVzWyBNRV9jbHVzdGVyLnR5cGU9PSJFeGNsdWRlZCIsIF0KTUVfY2x1c3Rlcl9uYW1lc1sgTUVfY2x1c3Rlci50eXBlPT0iSW5jbHVkZWQiLCBdCk1FX2NsdXN0ZXJfbmFtZXNbIE1FX2NsdXN0ZXIudHlwZT09Ik5ldXJvbmFsIiwgXQpNRV9jbHVzdGVyX25hbWVzWyBNRV9jbHVzdGVyLnR5cGU9PSJOZXVyby1NdXNjdWxhciIsIF0KTUVfY2x1c3Rlcl9uYW1lc1sgTUVfY2x1c3Rlci50eXBlPT0iTmV1cm9uYWwiLCBdCk1FX2NsdXN0ZXJfbmFtZXNbIE1FX2NsdXN0ZXIudHlwZT09IkluY2x1ZGVkIiwgXQpNRV9jbHVzdGVyX25hbWVzWyBNRV9jbHVzdGVyLnR5cGU9PSJFeGNsdWRlZCIsIF0KTUVfY2x1c3Rlcl9uYW1lc1sgTUVfY2x1c3Rlci50eXBlPT0iSW5jbHVkZWQiLCBdCk1FX2NsdXN0ZXJfbmFtZXNbIE1FX2NsdXN0ZXIudHlwZT09Ik90aGVyIiwgXQoKbGV2ZWxzKGZhY3RvcihNRV9jbHVzdGVyX25hbWVzJE1FX2NsdXN0ZXIudHlwZSkpCmBgYAoKYGBge3J9Ck1FX2NsdXN0ZXJfbmFtZXMubGV2ZWxzIDwtIGMoKQoKZm9yIChpIGluIGxldmVscyhmYWN0b3IoTUVfY2x1c3Rlcl9uYW1lcyRNRV9jbHVzdGVyLnR5cGUpKSl7CiAgCiAgCiAgCiAgCiAgTUVfY2x1c3Rlcl9uYW1lcy5sZXZlbHM8LSBjKE1FX2NsdXN0ZXJfbmFtZXMubGV2ZWxzLCBNRV9jbHVzdGVyX25hbWVzW01FX2NsdXN0ZXIudHlwZT09aSwgTUVfY2x1c3Rlci5uYW1lXSkKICAKICAKfQpgYGAKCgpgYGB7cn0KCk1FX2NsdXN0ZXJfbmFtZXMkTUVfY2x1c3Rlci5uYW1lIDwtIGZhY3RvcihNRV9jbHVzdGVyX25hbWVzJE1FX2NsdXN0ZXIubmFtZSwgCiAgICAgICBsZXZlbHMgPSBNRV9jbHVzdGVyX25hbWVzLmxldmVscykKCkZpZzUuWC4xIDwtIGdncGxvdChNRV9jbHVzdGVyX25hbWVzKSArCiAgZ2VvbV9iYXIoYWVzKE1FX2NsdXN0ZXIubmFtZSwgdG90YWwsICBmaWxsID0gTUVfY2x1c3Rlci50eXBlICksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArIAogIHhsYWIoIk51bWJlciBvZiBtaWNyb2V4b25zIikgKwogIHlsYWIoIk1pY3JvZXhvbiBjbHVzdGVyIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSArCiAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9Ik1pY3JvZXhvbiBjbHVzdGVyIGNsYXNzIikgCgpGaWc1LlguMQoKCkZpZzUuWC4xLmxlZ2VuZCA8LSBnZXRfbGVnZW5kKEZpZzUuWC4xICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsbGVnZW5kLmp1c3RpZmljYXRpb249ImNlbnRlciIgLGxlZ2VuZC5ib3guanVzdCA9ICJib3R0b20iKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChucm93PTEsYnlyb3c9VFJVRSkpKQpgYGAKCgoKCgpgYGB7ciwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MjB9CgpGaWc1LlgucGxvdHMgPC0gcGxvdF9ncmlkKEZpZzUuWC4xICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIAogICAgICAgICAgICAgICAgICAgIEZpZzUuWC4yICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIAogICAgICAgICAgICAgICAgICAgIEZpZzUuWC4zICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIAogICAgICAgICAgICAgICAgICAgIEZpZzUuWC40ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIAogICAgICAgICAgICAgICAgICAgIG5yb3cgPTEsCiAgICAgICAgICAgICAgICAgICAgcmVsX3dpZHRocyA9IGMoMS43LDEsMSwxKSwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSAiQVVUTyIgKQoKCkZpZzUuWCA8LSBwbG90X2dyaWQoRmlnNS5YLjEubGVnZW5kLCBGaWc1LlgucGxvdHMsIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoMC4yLCAxKSkKCkZpZzUuWApgYGAKCgoKCgpgYGB7cn0KTUVfY2x1c3RlcnMubmFtZXMgPC0gZGF0YS50YWJsZShNRV9jbHVzdGVycykKTUVfY2x1c3RlcnMubmFtZXMkTUUgPC0gbmFtZXMoTUVfY2x1c3RlcnMpCk1FX2NsdXN0ZXJzLm5hbWVzIDwtIG1lcmdlKE1FX2NsdXN0ZXJzLm5hbWVzLCAgTUVfY2x1c3Rlcl9uYW1lc1ssIGMoIk1FX2NsdXN0ZXIiLCAiTUVfY2x1c3Rlci5uYW1lIildLCAgYnkueD0iTUVfY2x1c3RlcnMiLCBieS55PSJNRV9jbHVzdGVyIikKCgpgYGAKCgpgYGB7cn0KTUVfZmluYWwuTUVfY2x1c3RlcnMgPC0gbWVyZ2UoTUVfZmluYWwsIE1FX2NsdXN0ZXJzLm5hbWVzLCBieT0iTUUiKQoKTUVfY2x1c3Rlci5jb25zZXJ2YXRpb24gPC0gTUVfZmluYWwuTUVfY2x1c3RlcnNbIG1lYW5fY29uc2VydmF0aW9uc192ZXJ0ZWJyYXRlcyE9Ik5vbmUiICwgIC4obWVhbl9jb25zZXJ2YXRpb249bWVhbihhcy5udW1lcmljKG1lYW5fY29uc2VydmF0aW9uc192ZXJ0ZWJyYXRlcykpKSAgLCBieT1jKCJNRV9jbHVzdGVycyIsICJNRV9jbHVzdGVyLm5hbWUiKV0KCgpNRV9jbHVzdGVyX25hbWVzIDwtICBtZXJnZShNRV9jbHVzdGVyX25hbWVzLCBNRV9jbHVzdGVyLmNvbnNlcnZhdGlvbiwgIGJ5Lng9YygiTUVfY2x1c3RlciIsICJNRV9jbHVzdGVyLm5hbWUiKSwgYnkueT1jKCJNRV9jbHVzdGVycyIsICJNRV9jbHVzdGVyLm5hbWUiKSkKCnJvdW5kKGNvcihNRV9jbHVzdGVyX25hbWVzJHN5bWV0cmljYWxfZnJhY3Rpb24sIE1FX2NsdXN0ZXJfbmFtZXMkbWVhbl9jb25zZXJ2YXRpb24sIG1ldGhvZD0icGVhcnNvbiIpLCAyKQoKCmdncGxvdChNRV9jbHVzdGVyX25hbWVzLCBhZXMoeD1zeW1ldHJpY2FsX2ZyYWN0aW9uLCB5PW1lYW5fY29uc2VydmF0aW9uKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD1sbSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBnZW9tX3RleHQoYWVzKCBsYWJlbCA9IE1FX2NsdXN0ZXIubmFtZSwgY29sb3VyID0gTUVfY2x1c3Rlci50eXBlICkgKSArCiAgeGxhYigiSW4tZnJhbWUgbWljcm9leG9uIGZyYWN0aW9uIikgKwogIHlsYWIoIk1lYW4gUGh5bG9wIGNvbnNlcnZhdGlvbiBzY29yZSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpICsKIGxhYnMoY29sb3IgPSAiTWljcm9leG9uIGNsdXN0ZXIgY2xhc3MiKQoKCgpgYGAKCgoKYGBge3J9Cgpzb21lX01FX2NsdXN0ZXJzIDwtYygKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTFdWzFdLApNRV9jbHVzdGVyc1tNRV9jbHVzdGVycz09Ml1bMV0sCk1FX2NsdXN0ZXJzW01FX2NsdXN0ZXJzPT0zXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTRdWzFdLApNRV9jbHVzdGVyc1tNRV9jbHVzdGVycz09NV1bMV0sCk1FX2NsdXN0ZXJzW01FX2NsdXN0ZXJzPT02XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTddWzFdLApNRV9jbHVzdGVyc1tNRV9jbHVzdGVycz09OF1bMV0sCk1FX2NsdXN0ZXJzW01FX2NsdXN0ZXJzPT05XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTEwXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTExXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTEyXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTEzXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTE0XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTE1XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTE2XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTE3XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTE4XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTE5XVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTIwXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTIxXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTIyXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTIzXVsxXSwKTUVfY2x1c3RlcnNbTUVfY2x1c3RlcnM9PTI0XVsxXQoKKQpgYGAKCgoKCmBgYHtyfQoKCmNvbF9hbm4gPC0gZGF0YS5mcmFtZSggIFRpc3N1ZV9jbHVzdGVycyRjbHVzdGVyLCByb3cubmFtZXM9VGlzc3VlX2NsdXN0ZXJzJEZpbGUuYWNjZXNzaW9uKQpjb2xuYW1lcyhjb2xfYW5uKSA8LSAiVGlzc3VlIGNsdXN0ZXJzIgoKcm93bmFtZXMoY29sX2FubikgPC0gVGlzc3VlX2NsdXN0ZXJzJEZpbGUuYWNjZXNzaW9uCgoKCnRpc3N1ZV9jbHVzdGVyX3R5cGUgPSBkYXRhLmZyYW1lKGNsdXN0ZXI9YygxLCA2LCA4LCAxNCwgMTIsIDcsIDE1LCA1LCAxMSwgNCwgOSwgMywgMTMsIDEwLCAxNiwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgVGlzc3VlIGNsdXN0ZXIgdHlwZWA9YygiTm9uLW5ldXJvbmFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vbi1uZXVyb25hbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb24tbmV1cm9uYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9uLW5ldXJvbmFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVtYnJ5b25pYyBuZXVyb25hbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZHJlbmFsIGdsYW5kIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNrZWxldGFsIG11c2NsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZWFydCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbWJyeW9uaWMgbmV1cm9uYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW1icnlvbmljIG5ldXJvbmFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVtYnJ5b25pYyBuZXVyb25hbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3N0bmF0YWwgbmV1cm9uYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW1icnlvbmljIG5ldXJvbmFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvc3RuYXRhbCBuZXVyb25hbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3N0bmF0YWwgbmV1cm9uYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zdG5hdGFsIG5ldXJvbmFsIikpCgpjb2xfYW5uJEZpbGUgPC0gcm93bmFtZXMoY29sX2FubikKY29sX2FubiA8LSBtZXJnZShjb2xfYW5uLCB0aXNzdWVfY2x1c3Rlcl90eXBlLCBieS54PSJUaXNzdWUgY2x1c3RlcnMiLGJ5Lnk9ImNsdXN0ZXIiKQpyb3duYW1lcyhjb2xfYW5uKSA8LSBjb2xfYW5uJEZpbGUKCmNvbG5hbWVzKGNvbF9hbm4pIDwtIGMoIlRpc3N1ZSBjbHVzdGVycyIsICJGaWxlIiwgIlRpc3N1ZSBjbHVzdGVyIHR5cGUiKQoKCgphbm5fY29sb3JzID0gbGlzdCgKICAgIGNsdXN0ZXIgPSBjKGJsYWNrPSJibGFjayIpLAogICAgYFRpc3N1ZS5jbHVzdGVyLnR5cGVgID0gIGMoYEFkcmVuYWwgZ2xhbmRgID0gIiNCNzlGMDAiLAogICAgICAgICAgICAgICAgICAgICAgYFNrZWxldGFsIG11c2NsZWAgPSAiIzAwQkZDNCIsCiAgICAgICAgICAgICAgICAgICAgICBgSGVhcnRgID0gIiNGNTY0RTMiLAogICAgICAgICAgICAgICAgICAgICAgYE5vbi1uZXVyb25hbGAgPSAiI0E1OEFGRiIsCiAgICAgICAgICAgICAgICAgICAgICBgRW1icnlvbmljIG5ldXJvbmFsYCA9ICIjMDBCQTM4IiwKICAgICAgICAgICAgICAgICAgICAgIGBQb3N0bmF0YWwgbmV1cm9uYWxgID0gIiNGODc2NkQiCiAgICAgICAgICAgICAgICAgICAgICApLAogICAgR2VuZUNsYXNzID0gYyhQYXRoMSA9ICIjNzU3MEIzIiwgUGF0aDIgPSAiI0U3Mjk4QSIsIFBhdGgzID0gIiM2NkE2MUUiKQopCgpjb2xfYW5uJGBUaXNzdWUgY2x1c3RlciB0eXBlYCA8LSBmYWN0b3IoY29sX2FubiRgVGlzc3VlIGNsdXN0ZXIgdHlwZWAgLCBsZXZlbHMgPSBjKCJBZHJlbmFsIGdsYW5kIiwgIlNrZWxldGFsIG11c2NsZSIsICJIZWFydCIsICJOb24tbmV1cm9uYWwiLCAiSW50ZXJtZWRpYXRlIiwgIkVtYnJ5b25pYyBuZXVyb25hbCIsICJQb3N0bmF0YWwgbmV1cm9uYWwiKSkKCmZha2VfcGxvdCA8LSBnZ3Bsb3QoY29sX2FubiwgYWVzKGFzLm51bWVyaWMoYFRpc3N1ZSBjbHVzdGVyc2ApLCBgVGlzc3VlIGNsdXN0ZXJzYCwgZmlsbD1gVGlzc3VlIGNsdXN0ZXIgdHlwZWAgKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNCNzlGMDAiLCAiIzAwQkZDNCIsICIjRjU2NEUzIiwgIiNBNThBRkYiLCAiIzAwQkEzOCIsICIjRjg3NjZEIiApLCBuYW1lPSAiVGlzc3VlIGNsdXN0ZXIgdHlwZSIpICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLCBsZWdlbmQuanVzdGlmaWNhdGlvbj0iY2VudGVyIikgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChucm93PTEsYnlyb3c9VFJVRSkpIAoKCmZha2VfcGxvdC5sZWdlbmQgPC0gZ2V0X2xlZ2VuZChmYWtlX3Bsb3QpCgoKCmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTE1fQoKbGlicmFyeShybGFuZykKCgoKI3Jvd25hbWVzKGNvbF9hbm4pIDwtIHJvd25hbWVzKFRpc3N1ZV9jbHVzdGVycykKClRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EgPC0gdChjT2JzKQoKVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYVtUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhPjFdIDwtIDEKVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYVtUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhPDBdIDwtIDAKCgpUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhX2hlYXRtYXAgPC0gZHVwbGljYXRlKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2EpCgoKc29tZV9NRV9jbHVzdGVyc19zcGFjZSA8LSBwYXN0ZSgiICAgICAgIiwgc29tZV9NRV9jbHVzdGVycywgc2VwID0gIiIpIApuYW1lcyhzb21lX01FX2NsdXN0ZXJzX3NwYWNlKSA8LSBuYW1lcyhzb21lX01FX2NsdXN0ZXJzKQoKcm93Lm5hbWVzKFRpc3N1ZV9QU0lfbWF0cml4X2RjYXN0X3BwY2FfaGVhdG1hcCkgPC0gc29tZV9NRV9jbHVzdGVyc19zcGFjZVtyb3cubmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYV9oZWF0bWFwKV0KCgoKI3Rpc3N1ZV9oZWF0bWFwIDwtIHBoZWF0bWFwOjpwaGVhdG1hcChUaXNzdWVfUFNJX21hdHJpeF9kY2FzdF9wcGNhX2hlYXRtYXAsICAsIGZvbnRzaXplID0gMTAgLCAgY3V0cmVlX3Jvd3MgPSAyNCwgY3V0cmVlX2NvbHMgPSAxNiwgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIgLCBzaG93X2NvbG5hbWVzPUZBTFNFLCBhbm5vdGF0aW9uX2NvbD0gY29sX2FubiwgYW5ub3RhdGlvbl9uYW1lc19jb2w9RkFMU0UsIHRyZWVoZWlnaHRfY29sPTIwMCwgdHJlZWhlaWdodF9yb3c9MTAwKQoKYGBgCgoKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9CgoKCgoKY29sX2Fubl8xYyA8LSBkYXRhLmZyYW1lKGNsdXN0ZXI9cmVwKCJibGFjayIgLG5yb3coY29sX2FubikpKSAKcm93bmFtZXMoY29sX2FubikgPC0gcm93bmFtZXMoY29sX2FubikKCgpjb2xfYW5uIDwtbWVyZ2UoY29sX2FubiwgVGlzc3VlX2NsdXN0ZXJzLCBieS54PSJGaWxlIiwgYnkueT0iRmlsZS5hY2Nlc3Npb24iKQoKY29sX2FubiA8LSBkYXRhLnRhYmxlKGNvbF9hbm4pCgpjb2xfYW5uWyFuYW1lICVpbiUgYygiZm9yZWJyYWluIiwgImhpbmRicmFpbiIsICJtaWRicmFpbiIsICJuZXVyYWwgdHViZSIsICJ3aG9sZSBjb3J0ZXgiKSwgYFRpc3N1ZSBjbHVzdGVyIHR5cGVgOj0iTm9uLW5ldXJvbmFsIl0KY29sX2FubltuYW1lPT0iaGVhcnQiLCBgVGlzc3VlIGNsdXN0ZXIgdHlwZWA6PSJIZWFydCJdCmNvbF9hbm5bbmFtZT09InNrZWxldGFsIG11c2NsZSB0aXNzdWUiLCBgVGlzc3VlIGNsdXN0ZXIgdHlwZWA6PSJTa2VsZXRhbCBtdXNjbGUiXQpjb2xfYW5uW25hbWU9PSJhZHJlbmFsIGdsYW5kIiwgYFRpc3N1ZSBjbHVzdGVyIHR5cGVgOj0iQWRyZW5hbCBnbGFuZCJdCmNvbF9hbm5bKG5hbWUgJWluJSBjKCJmb3JlYnJhaW4iLCAiaGluZGJyYWluIiwgIm1pZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgIndob2xlIGNvcnRleCIpKSAmIGFnZSAlaW4lIGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSkgLCAgYFRpc3N1ZSBjbHVzdGVyIHR5cGVgOj0iRW1icnlvbmljIG5ldXJvbmFsIl0KY29sX2FublsobmFtZSAlaW4lIGMoImZvcmVicmFpbiIsICJoaW5kYnJhaW4iLCAibWlkYnJhaW4iLCAibmV1cmFsIHR1YmUiLCAid2hvbGUgY29ydGV4IikpICYgIWFnZSAlaW4lIGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSkgLCAgYFRpc3N1ZSBjbHVzdGVyIHR5cGVgOj0iUG9zdG5hdGFsIG5ldXJvbmFsIl0KCgpjb2xfYW5uIDwtIGRhdGEuZnJhbWUoY29sX2FubikKcm93bmFtZXMoY29sX2FubikgPC0gY29sX2FubiRGaWxlCgoKCgp0aXNzdWVfaGVhdG1hcCA8LSBwaGVhdG1hcDo6cGhlYXRtYXAoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYV9oZWF0bWFwLCBjdXRyZWVfcm93cyA9IDI0LCBjdXRyZWVfY29scyA9IDE2LCBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiAsIHNob3dfY29sbmFtZXM9RkFMU0UsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fbGVnZW5kPUZBTFNFLCBhbm5vdGF0aW9uX2NvbD0gY29sX2Fubl8xYywgYW5ub3RhdGlvbl9uYW1lc19jb2w9RkFMU0UsIGFubm90YXRpb25fY29sb3JzPWFubl9jb2xvcnMpCgp0aXNzdWVfaGVhdG1hcCA8LSBwaGVhdG1hcDo6cGhlYXRtYXAoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYV9oZWF0bWFwLCBjdXRyZWVfcm93cyA9IDI0LCBjdXRyZWVfY29scyA9IDE2LCBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiAsIHNob3dfY29sbmFtZXM9RkFMU0UsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fbGVnZW5kPUYsIGFubm90YXRpb25fY29sPSBjb2xfYW5uWyJUaXNzdWUuY2x1c3Rlci50eXBlIl0sIGFubm90YXRpb25fbmFtZXNfY29sPUYsIGFubm90YXRpb25fY29sb3JzPWFubl9jb2xvcnMpCgojODc3LjI0MQojNTcxLjQ5CgpwaGVhdG1hcDo6cGhlYXRtYXAoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RfcHBjYV9oZWF0bWFwLCBjdXRyZWVfcm93cyA9IDI0LCBjdXRyZWVfY29scyA9IDE2LCBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiAsIHNob3dfY29sbmFtZXM9RkFMU0UsIHNob3dfcm93bmFtZXM9RkFMU0UsIGFubm90YXRpb25fbGVnZW5kPVQsIGFubm90YXRpb25fY29sPSBjb2xfYW5uWyJUaXNzdWUuY2x1c3RlcnMiXSwgYW5ub3RhdGlvbl9uYW1lc19jb2w9VCwgYW5ub3RhdGlvbl9jb2xvcnM9YW5uX2NvbG9ycykKCgpgYGAKCgoKCmBgYHtyLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9Mn0KcGxvdF9ncmlkKGZha2VfcGxvdC5sZWdlbmQpCmBgYAoKCgpgYGB7cn0KCgoKUENBIDwtIGRhdGEuZnJhbWUoc2NvcmVzKHJlc3VsdCkpCgoKCgoKUENBJEZpbGUuYWNjZXNzaW9uIDwtIHJvdy5uYW1lcyhQQ0EpClBDQSA8LSBkYXRhLnRhYmxlKFBDQSkKUENBIDwtIFBDQVssIGA6PWAoUEMxPS1QQzEpIF0KCgpQQ0EgPC0gbWVyZ2UoVGlzc3VlX2NsdXN0ZXJzLCBQQ0EsIGJ5PSJGaWxlLmFjY2Vzc2lvbiIpCgpQQ0EkYWdlIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFBDQSRhZ2UpKQoKCgpgYGAKCgoKCmBgYHtyfQpQQ0Ffc3RhdHMgPC0gUENBWyAsIC4obWVhbl9QQzE9bWVhbihQQzEpKSAsIGJ5PWMoIm5hbWUiLCAiYWdlIildCgoKU3VwX1BDQV9hZ2UuQiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IFBDQVtuYW1lICVpbiUgYygiZm9yZWJyYWluIiwgIm1pZGJyYWluIiwgImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIpLCBdLCAgYWVzKGFnZSwgUEMxLCBjb2xvdXI9bmFtZSksIHdpZHRoPTAuMSwgaGVpZ2h0ID0gMCApICsKICBnZW9tX2xpbmUoZGF0YSA9IFBDQV9zdGF0c1tuYW1lICVpbiUgYygiZm9yZWJyYWluIiwgIm1pZGJyYWluIiwgImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIpLCBdLCBhZXMoYWdlLCBtZWFuX1BDMSwgZ3JvdXA9bmFtZSwgY29sb3VyPW5hbWUpKSArCiAgbGFicyhjb2xvdXI9Ik5ldXJhbCB0aXNzdWUiKQoKCgpgYGAKCmBgYHtyfQpQQ0Ffc3RhdHM8LSBQQ0FbICwgLihtZWFuX1BDMT1tZWFuKFBDMSkpICwgYnk9YygibmFtZSIsICJhZ2UiKV0KCkZpZzQuQyA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBQQ0Ffc3RhdHNbbmFtZSAlaW4lIGMoImZvcmVicmFpbiIsICJtaWRicmFpbiIsICJoaW5kYnJhaW4iLCAibmV1cmFsIHR1YmUiLCAid2hvbGUgY29ydGV4IiksIF0sIGFlcyhsb2coYWdlKSwgbWVhbl9QQzEsIGdyb3VwPW5hbWUsIGNvbG91cj1uYW1lKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IFBDQV9zdGF0c1tuYW1lICVpbiUgYygiZm9yZWJyYWluIiwgIm1pZGJyYWluIiwgImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIsICJ3aG9sZSBjb3J0ZXgiKSwgXSwgYWVzKGxvZyhhZ2UpLCBtZWFuX1BDMSwgZ3JvdXA9bmFtZSwgY29sb3VyPW5hbWUpKSArCiAgeGxhYigibG9nKERQQykiKSArCiAgeWxhYigiTWVhbiBQQzEiKSArCiAgeGxpbShjKGxvZygxMCksIGxvZyg1MCkpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZT0iTmV1cm9uYWwgdGlzc3VlIiwgbGFiZWxzPWMoIkZvcmVicmFpbiIsICJIaW5kYnJhaW4iLCAiTWlkYnJhaW4iLCAiTmV1cmFsIHR1YmUiLCAiV2hvbGUgY29ydGV4IikpCiAgCgpGaWc0LkMKYGBgCgoKCmBgYHtyfQoKUENBX3N0YXRzX1BDMjwtIFBDQVsgbmFtZT09ImhlYXJ0IiAsIC4obWVhbl9QQzI9bWVhbihQQzIpKSAsIGJ5PWMoIm5hbWUiLCAiYWdlIildCgoKYGBgCgoKCgoKYGBge3J9ClBDMV9jbHVzdGVyIDwtIFBDQVsgLCAuKFBDMT1tZWFuKFBDMSkpICAsIGJ5PWNsdXN0ZXJdCgp0aXNzdWVfY2x1c3Rlcl9QQ0EgPC0gZmFjdG9yKFBDMV9jbHVzdGVyW29yZGVyKFBDMSldJGNsdXN0ZXIsIGxldmVscyA9IFBDMV9jbHVzdGVyW29yZGVyKFBDMSldJGNsdXN0ZXIpCgoKbXlfY29sIDwtIGdldF9jb2xvcnModGlzc3VlX2NsdXN0ZXJfUENBLCBncm91cC5jb2w9Y29sb3JSYW1wUGFsZXR0ZShjb2xvcnMgPSBjKCJibGFjayIsICAicHVycGxlIiwgImJsdWUiLCAic2VhZ3JlZW4iLCAiZ29sZCIsICJyZWQiKSkoMTQpKQoKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KClBDQSRjbHVzdGVyIDwtIGZhY3RvcihQQ0EkY2x1c3RlciwgbGV2ZWxzID0gUEMxX2NsdXN0ZXJbb3JkZXIoUEMxKV0kY2x1c3RlcikKCgpTdXBfUENBLkEgPC0gZ2dwbG90KFBDQSkgKwogIGdlb21fdGV4dChhZXMoUEMxLCBQQzIsIGxhYmVsPWNsdXN0ZXIsIGNvbG91cj1jbHVzdGVyKSApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPW15X2NvbCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpTdXBfUENBLkIgPC0gIGdncGxvdChQQ0EpICsKICBnZW9tX3RleHQoYWVzKFBDMSwgUEMzLCBsYWJlbD1jbHVzdGVyLCBjb2xvdXI9Y2x1c3RlcikgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1teV9jb2wpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKU3VwX1BDQS5DIDwtICBnZ3Bsb3QoUENBKSArCiAgZ2VvbV90ZXh0KGFlcyhQQzIsIFBDMywgbGFiZWw9Y2x1c3RlciwgY29sb3VyPWNsdXN0ZXIpICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9bXlfY29sKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoKCgpgYGB7cn0KCmxpYnJhcnkocmxhbmcpCgpQQ0FfcGxvdCA8LSBkdXBsaWNhdGUoUENBKQoKClBDQV9wbG90W25hbWU9PSJoZWFydCIsIGdyb3VwOj0iSGVhcnQiXQpQQ0FfcGxvdFtuYW1lPT0ic2tlbGV0YWwgbXVzY2xlIHRpc3N1ZSIsIGdyb3VwOj0iU0tNIl0KUENBX3Bsb3RbbmFtZT09ImFkcmVuYWwgZ2xhbmQiLCBncm91cDo9IkFkcmVuYWwgR2xhbmQiXQpQQ0FfcGxvdFtuYW1lPT0id2hvbGUgY29ydGV4IiwgZ3JvdXA6PSJDb3J0ZXgiXQpQQ0FfcGxvdFtuYW1lICVpbiUgYygiZm9yZWJyYWluIiwgIm1pZGJyYWluIiwgImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIpICwgZ3JvdXA6PSJOZXVyYWwiXQoKUENBX3Bsb3QkYWdlIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFBDQV9wbG90JGFnZSApKQoKClBDQV9wbG90WyFuYW1lICVpbiUgYygiZm9yZWJyYWluIiwgIm1pZGJyYWluIiwgImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIsICJ3aG9sZSBjb3J0ZXgiLCAiaGVhcnQiLCJza2VsZXRhbCBtdXNjbGUgdGlzc3VlIiwgImFkcmVuYWwgZ2xhbmQiKSwgYDo9YChncm91cD0iT3RoZXIiLCBhZ2U9TkEgKV0KCmdncGxvdChQQ0FfcGxvdFtuYW1lIT0id2hvbGUgY29ydGV4IixdKSArCiAgZ2VvbV9wb2ludChhZXMoUEMxLCBQQzIsIGNvbG91cj1hZ2UsIHNoYXBlPWdyb3VwICkgKSArCiAgZ2VvbV9wb2ludChhZXMoUEMxLCBQQzIsIGNvbG91cj1hZ2UsIHNoYXBlPWdyb3VwICkgKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJibHVlIiwgIGhpZ2g9InJlZCIpCgoKCmBgYAoKYGBge3J9CgpsaWJyYXJ5KHN0cmluZ3IpCgpTdXBfUENBX2FnZS5BIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGE9UENBX3Bsb3RbZ3JvdXA9PSJPdGhlciJdLCBhZXMoUEMxLCBQQzIsIGNvbG91cj1hZ2UgKSwgYWxwaGE9MC41KSArCiAgZ2VvbV90ZXh0KGRhdGE9UENBX3Bsb3RbZ3JvdXAhPSJPdGhlciIgJiBuYW1lIT0id2hvbGUgY29ydGV4Il0sIGFlcyhQQzEsIFBDMiwgY29sb3VyPWFnZSwgbGFiZWw9c3RyX3N1Yihncm91cCwgMSwxKSApLCBzaXplPTMuNSwgYWxwaGE9MC41ICkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iYmx1ZSIsICBoaWdoPSJyZWQiKSArCiAgbGFicyhjb2xvdXI9IkVtYnJ5b25pYyBzdGFnZSAoRFBDKSIpCmBgYAoKCgoKYGBge3J9CmdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGE9UENBX3Bsb3RbZ3JvdXA9PSJPdGhlciJdLCBhZXMoUEMxLCBQQzIsIGNvbG91cj1sb2coYWdlKSApLCBhbHBoYT0wLjgpICsKICBnZW9tX3RleHQoZGF0YT1QQ0FfcGxvdFtncm91cCE9Ik90aGVyIl0sIGFlcyhQQzEsIFBDMiwgY29sb3VyPWxvZyhhZ2UpLCBsYWJlbD1zdHJfc3ViKGdyb3VwLCAxLDEpICksIHNpemU9My41LCBhbHBoYT0wLjggKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdz0iYmx1ZSIsIG1pZD0iZ29sZCIsICBoaWdoPSJyZWQiLCBtaWRwb2ludCA9IDMuNykKYGBgCgoKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9NX0KcGxvdF9ncmlkKFN1cF9QQ0FfYWdlLkEsIFN1cF9QQ0FfYWdlLkIsIGxhYmVscyA9ICJBVVRPIikKYGBgCgoKCmBgYHtyfQoKClBDQV9iYXRjaCA8LSBtZXJnZShQQ0EsIFBDQVssIC5OLCBieT1jKCJkYXRlIildWywgLihkYXRlLCBiYXRjaD1mcmFuayhkYXRlKSApXSwgYnk9ImRhdGUiKQoKbXlfY29sX2RhdGUgPC0gZ2V0X2NvbG9ycyh0aXNzdWVfY2x1c3Rlcl9QQ0EsIGdyb3VwLmNvbD1jb2xvclJhbXBQYWxldHRlKGNvbG9ycyA9IGMoImJsYWNrIiwgICJwdXJwbGUiLCAiYmx1ZSIsICJzZWFncmVlbiIsICJnb2xkIiwgInJlZCIpKSgxMCkpCgoKCgoKU3VwX1BDQS5EIDwtICBnZ3Bsb3QoUENBX3Bsb3QpICsKICBnZW9tX3RleHQoYWVzKFBDMSwgUEMyLCBsYWJlbD1zdHJfc3ViKGdyb3VwLCAxLDEpICwgY29sb3VyPWZhY3RvcihjbHVzdGVyKSApICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9bXlfY29sKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpTdXBfUENBLkUgPC0gIGdncGxvdChQQ0FfcGxvdCkgKwogIGdlb21fdGV4dChhZXMoUEMxLCBQQzMsIGxhYmVsPXN0cl9zdWIoZ3JvdXAsIDEsMSkgLCBjb2xvdXI9ZmFjdG9yKGNsdXN0ZXIpICkgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1teV9jb2wpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKU3VwX1BDQS5GIDwtICBnZ3Bsb3QoUENBX3Bsb3QpICsKICBnZW9tX3RleHQoYWVzKFBDMiwgUEMzLCBsYWJlbD1zdHJfc3ViKGdyb3VwLCAxLDEpICwgY29sb3VyPWZhY3RvcihjbHVzdGVyKSApICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9bXlfY29sKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgoKClN1cF9QQ0EuRyA8LSAgZ2dwbG90KFBDQV9iYXRjaCkgKwogIGdlb21fdGV4dChhZXMoUEMxLCBQQzIsIGxhYmVsPWNsdXN0ZXIsIGNvbG91cj1mYWN0b3IoYmF0Y2gpICkgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1teV9jb2xfZGF0ZSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKU3VwX1BDQS5IIDwtICBnZ3Bsb3QoUENBX2JhdGNoKSArCiAgZ2VvbV90ZXh0KGFlcyhQQzEsIFBDMywgbGFiZWw9Y2x1c3RlciwgY29sb3VyPWZhY3RvcihiYXRjaCkgKSApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPW15X2NvbF9kYXRlKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpTdXBfUENBLkkgPC0gIGdncGxvdChQQ0FfYmF0Y2gpICsKICBnZW9tX3RleHQoYWVzKFBDMiwgUEMzLCBsYWJlbD1jbHVzdGVyLCBjb2xvdXI9ZmFjdG9yKGJhdGNoKSApICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9bXlfY29sX2RhdGUpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmBgYAoKCgpgYGB7ciwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9MTV9CnBsb3RfZ3JpZChTdXBfUENBLkEsIFN1cF9QQ0EuQiwgU3VwX1BDQS5DLCBTdXBfUENBLkQsIFN1cF9QQ0EuRSwgU3VwX1BDQS5GLCBTdXBfUENBLkcsIFN1cF9QQ0EuSCwgU3VwX1BDQS5JLCBsYWJlbHM9IkFVVE8iICkKYGBgCgoKCgoKCgpgYGB7cn0KI1Rpc3N1ZV9jbHVzdGVycyA8LSBjdXRyZWUoaGNfY29scywgayA9IDE4KQojVGlzc3VlX2NsdXN0ZXJzIDwtIGNiaW5kKFRpc3N1ZV9jbHVzdGVycywgVGlzc3Vlc19uYW1lW25hbWVzKFRpc3N1ZV9jbHVzdGVycyldLCBUaXNzdWVzX2FnZVtuYW1lcyhUaXNzdWVfY2x1c3RlcnMpXSwgVGlzc3VlX2RhdGVbbmFtZXMoVGlzc3VlX2NsdXN0ZXJzKV0pIAoKI2NvbG5hbWVzKFRpc3N1ZV9jbHVzdGVycykgPC0gYygiY2x1c3RlciIsICJuYW1lIiwgImFnZSIsICJkYXRlIikKCiNUaXNzdWVfY2x1c3RlcnMgPC0gZGF0YS5mcmFtZShUaXNzdWVfY2x1c3RlcnMpCgojVGlzc3VlX2NsdXN0ZXJzX3N1bVt3aGljaChncmVwbCgiaGluZGJyYWlufG1pZGJyYWlufGZvcmVicmFpbnxuZXVyYWxcIHR1YmUiLCBUaXNzdWVfY2x1c3RlcnNfc3VtJG5hbWUpKSwgXQoKI1Rpc3N1ZV9jbHVzdGVycyRuYW1lIDwtIGZhY3RvcihUaXNzdWVfY2x1c3RlcnMkbmFtZSwgbGV2ZWw9YyggInNrZWxldGFsIG11c2NsZSB0aXNzdWUiLCAiaGVhcnQiLCAidGh5bXVzIiwgInNwbGVlbiIsICJsaXZlciIsICAiYWRyZW5hbCBnbGFuZCIsICJpbnRlc3RpbmUiLCAic3RvbWFjaCIsICJsdW5nIiwgICJraWRuZXkiLCAiYmxhZGRlciIsICJsaW1iIiwgImVtYnJ5b25pYyBmYWNpYWwgcHJvbWluZW5jZSIsICJmb3JlYnJhaW4iLCAiaGluZGJyYWluIiwgIm1pZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgIndob2xlIGNvcnRleCIpKQoKCiNUaXNzdWVfY2x1c3RlcnMkYWdlIDwtIGZhY3RvcihUaXNzdWVfY2x1c3RlcnMkYWdlLCBsZXZlbHMgPSBhcy5jaGFyYWN0ZXIoc29ydChhcy5udW1lcmljKGxldmVscyhUaXNzdWVfY2x1c3RlcnMkYWdlKSkpKSkKCgoKCmBgYAoKCgoKYGBge3IsICBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0yMH0KCgojVGlzc3VlX2NsdXN0ZXJzX3N1bSA8LSBUaXNzdWVfY2x1c3RlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIsIG5hbWUsIGFnZSApICU+JSBzdW1tYXJpc2UoY291bnQgPSBuKCkpCgpUaXNzdWVfY2x1c3RlcnNfRFQgPC0gZGF0YS50YWJsZShUaXNzdWVfY2x1c3RlcnMpClRpc3N1ZV9jbHVzdGVyc19zdW0gPC0gVGlzc3VlX2NsdXN0ZXJzX0RUWywgLihjb3VudD0uTikgLCBieT1jKCJjbHVzdGVyIiwgIm5hbWUiLCAiYWdlIiApXQoKVGlzc3VlX2NsdXN0ZXJzX3N1bSRhZ2UgPC0gZmFjdG9yKFRpc3N1ZV9jbHVzdGVyc19zdW0kYWdlLCBsZXZlbHM9IHNvcnQoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIobGV2ZWxzKFRpc3N1ZV9jbHVzdGVyc19zdW0kYWdlKSkpKSApCgoKIyMgTkEgIyMjCgpUaXNzdWVfY2x1c3RlcnNfc3VtJGNsdXN0ZXIgPC0gZmFjdG9yKFRpc3N1ZV9jbHVzdGVyc19zdW0kY2x1c3RlciAsIGxldmVscyA9UENBWywgbWVhbihQQzEpLCBieT0iY2x1c3RlciIgXVtvcmRlcihWMSldJGNsdXN0ZXIpCgoKVGlzc3VlX2NsdXN0ZXJzX3N1bSA8LSBtZXJnZShUaXNzdWVfY2x1c3RlcnNfc3VtLCBQQ0FbLCAuKG1QQzE9bWVhbihQQzEpLCBtUEMyPW1lYW4oUEMyKSwgbVBDMz1tZWFuKFBDMykgKSwgYnk9ImNsdXN0ZXIiIF1bb3JkZXIobVBDMSldLCBieT0iY2x1c3RlciIpClRpc3N1ZV9jbHVzdGVyc19zdW1bLCBgOj1gKG1lYW5fUEMxPXJvdW5kKG1QQzEsIDIpLG1lYW5fUEMyPXJvdW5kKG1QQzIsIDIpLCBtZWFuX1BDMz1yb3VuZChtUEMzLCAyKSkgIF0KClN1cC5UaXNzdWVfY2x1c3RlcnMuYi5wcmUgPC0gZ2dwbG90KCBUaXNzdWVfY2x1c3RlcnNfc3VtLCBhZXMoYWdlLCBuYW1lKSApICsKICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBjb3VudCkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0iZ3JleSIsIGhpZ2g9InJlZCIpKwogIGZhY2V0X2dyaWQoLiB+IGNsdXN0ZXIgKyBtZWFuX1BDMSArIG1lYW5fUEMyICsgbWVhbl9QQzMsIGxhYmVsbGVyID0gbGFiZWxfcGFyc2VkICkgKwogIHRoZW1lX2J3KCkrCiAgbGFicyhmaWxsID0gIlNhbXBsZSBjb3VudCIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDApLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSBOQSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCgpTdXAuVGlzc3VlX2NsdXN0ZXJzLmMgPC0gcGxvdF9ncmlkKGZha2VfcGxvdC5sZWdlbmQsIFN1cC5UaXNzdWVfY2x1c3RlcnMuYi5wcmUsIG5jb2w9MSwgcmVsX2hlaWdodHMgPSBjKDAuMSwgMSkgKQpTdXAuVGlzc3VlX2NsdXN0ZXJzLmMKYGBgCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0yMH0KCmxpYnJhcnkoZ2dyZXBlbCkKClBDQV9wbG90WywgYDo9YChtUEMxPW1lYW4oUEMxKSwgbVBDMj1tZWFuKFBDMikpLCBieT0iY2x1c3RlciIgXQoKCgoKU3VwLlRpc3N1ZV9jbHVzdGVycy5hIDwtIGdncGxvdChQQ0FfcGxvdCkgKwogIGdlb21fcG9pbnQoYWVzKFBDMSwgUEMyICwgY29sb3VyPWZhY3RvcihjbHVzdGVyKSApLCAgYWxwaGE9MC4zICkgKwogIHN0YXRfZWxsaXBzZShhZXMoUEMxLCBQQzIgLCBjb2xvdXI9ZmFjdG9yKGNsdXN0ZXIpICkpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YT1QQ0FfcGxvdFssIC4obVBDMT1tZWFuKFBDMSksIG1QQzI9bWVhbihQQzIpKSwgYnk9ImNsdXN0ZXIiIF0sCiAgICAgICAgICAgICAgICAgIGFlcyhtUEMxLCBtUEMyLCBsYWJlbD1jbHVzdGVyKSwgc2l6ZT03LCBwb2ludC5wYWRkaW5nID0gTkEsIGZvbnRmYWNlID0gImJvbGQiICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9bXlfY29sKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgCgpTdXAuVGlzc3VlX2NsdXN0ZXJzLmIgPC0gZ2dwbG90KFBDQV9wbG90KSArCiAgZ2VvbV9wb2ludChhZXMoUEMxLCBQQzMgLCBjb2xvdXI9ZmFjdG9yKGNsdXN0ZXIpICksICBhbHBoYT0wLjMgKSArCiAgc3RhdF9lbGxpcHNlKGFlcyhQQzEsIFBDMyAsIGNvbG91cj1mYWN0b3IoY2x1c3RlcikgKSkgKwogIGdlb21fdGV4dF9yZXBlbChkYXRhPVBDQV9wbG90WywgLihtUEMxPW1lYW4oUEMxKSwgbVBDMj1tZWFuKFBDMykpLCBieT0iY2x1c3RlciIgXSwKICAgICAgICAgICAgICAgICAgYWVzKG1QQzEsIG1QQzIsIGxhYmVsPWNsdXN0ZXIpLCBzaXplPTcsIHBvaW50LnBhZGRpbmcgPSBOQSwgZm9udGZhY2UgPSAiYm9sZCIgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1teV9jb2wpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAKICAKClN1cC5UaXNzdWVfY2x1c3RlcnMuYWIgPC0gcGxvdF9ncmlkKFN1cC5UaXNzdWVfY2x1c3RlcnMuYSwgU3VwLlRpc3N1ZV9jbHVzdGVycy5iLCBsYWJlbHMgPSBjKCJFIiwgIkYiKSkKU3VwLlRpc3N1ZV9jbHVzdGVycy5hYgpgYGAKCgpgYGB7ciwgIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTE5fQpGaWc0LkVGRyA8LSBwbG90X2dyaWQoIFN1cC5UaXNzdWVfY2x1c3RlcnMuYWIsIFN1cC5UaXNzdWVfY2x1c3RlcnMuYywgbmNvbD0xLCBsYWJlbHM9YygiIiwgIkciKSwgcmVsX2hlaWdodHMgPSBjKDAuOCwgMSkgKQpGaWc0LkVGRwpgYGAKCgoKCgoKCmBgYHtyfQpGaWcuNEEgPC0gZ2dwbG90KFBDQV9wbG90KSArCiAgZ2VvbV9wb2ludChhZXMoUEMxLCBQQzIsIGNvbG91cj1sb2coYWdlKSwgc2hhcGU9Z3JvdXAgKSwgc2l6ZT0zICwgYWxwaGE9MC43KSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdz0iYmx1ZSIsIG1pZD0ieWVsbG93IiwgIGhpZ2g9InJlZCIsIG1pZHBvaW50ID0gMy43LCBuYW1lPSJsbihBZ2UpIikgKwogIHNjYWxlX3NoYXBlKG5hbWU9IlRpc3N1ZSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpIApgYGAKCgoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD0yMH0KCmxpYnJhcnkoZ2dwbG90aWZ5KQoKRmlnLjRBIDwtIGdncGxvdChQQ0FfcGxvdCkgKwogIGdlb21fcG9pbnQoYWVzKFBDMSwgUEMyLCBjb2xvdXI9bG9nKGFnZSksIHNoYXBlPWdyb3VwICksIHNpemU9MyAsIGFscGhhPTAuNykgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3c9ImJsdWUiLCBtaWQ9InllbGxvdyIsICBoaWdoPSJyZWQiLCBtaWRwb2ludCA9IDMuNywgbmFtZT0ibG4oQWdlKSIpICsKICBzY2FsZV9zaGFwZShuYW1lPSJUaXNzdWUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSAKCgojZ2dwbG90KCkgKwojICBnZW9tX3BvaW50KGRhdGE9UENBX3Bsb3RbZ3JvdXA9PSJPdGhlciJdLCBhZXMoUEMxLCBQQzIsIGNvbG91cj1hZ2UgKSwgYWxwaGE9MC41KSArCiMgIGdlb21fdGV4dChkYXRhPVBDQV9wbG90W2dyb3VwIT0iT3RoZXIiXSwgYWVzKFBDMSwgUEMyLCBjb2xvdXI9YWdlLCBsYWJlbD1zdHJfc3ViKGdyb3VwLCAxLDEpICksIHNpemU9My41LCBhbHBoYT0wLjUgKSArCiMgIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iYmx1ZSIsICBoaWdoPSJyZWQiKQoKRmlnLjRCIDwtIGdncGxvdChQQ0FfcGxvdCkgKwogIGdlb21fcG9pbnQoYWVzKFBDMSwgUEMzLCBjb2xvdXI9bG9nKGFnZSksIHNoYXBlPWdyb3VwICksIHNpemU9MyAsIGFscGhhPTAuNykgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3c9ImJsdWUiLCBtaWQ9InllbGxvdyIsICBoaWdoPSJyZWQiLCBtaWRwb2ludCA9IDMuNywgbmFtZT0ibG4oQWdlKSIpICsKICBzY2FsZV9zaGFwZShuYW1lPSJUaXNzdWUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSAKCgpGaWcuNEFCLmxlZ2VuZCA8LSBnZXRfbGVnZW5kKEZpZy40QSArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uPSJjZW50ZXIiKSApCgoKRmlnLjRBQi5wcmUgPC0gcGxvdF9ncmlkKEZpZy40QSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLCBGaWcuNEIgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwgbnJvdz0xLCBsYWJlbHMgPSAiQVVUTyIpCkZpZy40QUIgPC0gcGxvdF9ncmlkKEZpZy40QUIubGVnZW5kLCBGaWcuNEFCLnByZSwgcmVsX2hlaWdodHMgPSBjKDAuMiwgMSksIG5jb2w9MSApCgoKCgpGaWc0LkMubGVnZW5kIDwtIGdldF9sZWdlbmQoIEZpZzQuQyArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uPSJjZW50ZXIiKSkKRmlnNC5DLmNvbXAgPC0gcGxvdF9ncmlkKCBGaWc0LkMubGVnZW5kICwgRmlnNC5DICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIHJlbF9oZWlnaHRzID0gYygwLjIsIDEpLCBuY29sPTEgLCBsYWJlbHMgPSBjKCIiLCAiQyIpICkKCkZpZzQudG9wcm93IDwtcGxvdF9ncmlkKEZpZy40QUIsIEZpZzQuQy5jb21wLCByZWxfd2lkdGhzID0gYygxLjcsIDEpKQoKI0ZpZzQudG9wcm93IDwtIHBsb3RfZ3JpZChGaWcuNEEsIEZpZy40QiwgRmlnNC5DLCBsYWJlbHMgPSAiQVVUTyIsICBucm93ID0gMSkKRmlnNCA8LSBwbG90X2dyaWQoRmlnNC50b3Byb3csIGZha2VfcGxvdC5sZWdlbmQsIGFzLmdyb2IodGlzc3VlX2hlYXRtYXApLCBuY29sPTEsIHJlbF9oZWlnaHRzID0gYygxLCAwLjIsIDIuMikgLCBsYWJlbHMgPSBjKCIiLCAiIiwgIkQiKSkKRmlnNAoKIzE5MDAgeCAxMzAwCmBgYAoKCgpgYGB7ciwgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTE1fQpwbG90X2dyaWQoRmlnNCwgRmlnNC5FRkcsIG5jb2w9MSwgcmVsX2hlaWdodHMgPSBjKDIsIDEpKQpgYGAKCgpIZXJlIHdlIHNvcnRlZCBtaWNyb2V4b25zIGJ5IFBDMSBsb2FkaW5ncywgYnV0IHdlIGZsaXBlZCBQQzEgd2UgY29jaWRlciB0aGUgdmFsdWVzIGFzIC0xIFBDQSBsb2FkaW5nIG9uIG91ciBwYXBlcgpgYGB7cn0KCmBgYAoKCgpMb2FkaW5nIHRoZXJob2xkIGlzIGFicygwLjAzNSkKCgpgYGB7ciwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9N30KCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJIDwtIG1lcmdlKE1FX2NsdXN0ZXJzX1BTSSwgVGlzc3VlX2NsdXN0ZXJzLCBieS54PSJGSUxFX05BTUUiLCBieS55ID0gIkZpbGUuYWNjZXNzaW9uIikKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0kkY2x1c3RlciA8LSBmYWN0b3IoTUVfVGlzc3Vlc19jbHVzdGVyc19QU0kkY2x1c3RlciwgbGV2ZWxzID0gbGV2ZWxzKFRpc3N1ZV9jbHVzdGVyc19zdW0kY2x1c3RlcikpCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJIDwtIG1lcmdlKCBNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSSwgIE1FX2NsdXN0ZXJfbmFtZXNbICwgYygiTUVfY2x1c3RlciIsICJNRV9jbHVzdGVyLm5hbWUiKV0sIGJ5Lng9Ik1FX2NsdXN0ZXJzIiwgYnkueT0iTUVfY2x1c3RlciIpCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSSRNRV9jbHVzdGVyLm5hbWUgPC0gZmFjdG9yKE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJJE1FX2NsdXN0ZXIubmFtZSwgbGV2ZWxzID0gc29ydChhcy5jaGFyYWN0ZXIodW5pcXVlKE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJJE1FX2NsdXN0ZXIubmFtZSkpKSkKCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX3N1YiA8LSBNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSVtNRV9jbHVzdGVyLm5hbWUgJWluJSAgTUVfY2x1c3Rlcl9uYW1lc1tNRV9jbHVzdGVyLnR5cGUgJWluJSBjKCJOZXVyb25hbCIsICJOZXVyby1NdXNjdWxhciIsICJNdXNjdWxhciIsICAiTm9uLU5ldXJvbmFsIiksIE1FX2NsdXN0ZXIubmFtZV0sIF0KTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbm9uX25ldXJvbmFsIDwtIE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX3N1YltjbHVzdGVyICVpbiUgYygxLCA4LCA2LCA3LCAxNSwgNSkgLCBdCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9ub25fbmV1cm9uYWwkY2x1c3RlciA8LSBtYXB2YWx1ZXMoTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbm9uX25ldXJvbmFsJGNsdXN0ZXIsCiAgICAgICAgICBmcm9tID0gYygxLCA4LCA2LCA3LCAxNSwgNSksCiAgICAgICAgICB0byA9IGMoICJDMSIsICJDOCIsICJDNiIsICJDNyIsICJDMTUiLCAiQzUiKSApCgoKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbm9uX25ldXJvbmFsJGNsdXN0ZXIgPC0gZmFjdG9yKE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25vbl9uZXVyb25hbCRjbHVzdGVyLCBsZXZlbHM9YyggIkMxIiwgIkM4IiwgIkM2IiwgIkM3IiwgIkMxNSIsICJDNSIpKQoKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbm9uX25ldXJvbmFsX2J5X01FIDwtIE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25vbl9uZXVyb25hbFsgLCAuKFBTSV9tZWFuPW1lYW4oUFNJKSksIGJ5PWMoIk1FIiwgImNsdXN0ZXIiLCAiTUVfY2x1c3Rlci5uYW1lIikgXQpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9ub25fbmV1cm9uYWxfYnlfTUVfY2x1c3RlciA8LSBNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9ub25fbmV1cm9uYWxbICwgLihQU0lfbWVhbj1tZWFuKFBTSSkpLCBieT1jKCAiY2x1c3RlciIsICJNRV9jbHVzdGVyLm5hbWUiKSBdCgoKCiAgCmdncGxvdCggKSArCiAgICAgICAgZ2VvbV9saW5lKGRhdGE9IE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25vbl9uZXVyb25hbF9ieV9NRSwgYWVzKGZhY3RvcihjbHVzdGVyKSwgUFNJX21lYW4sIGdyb3VwPU1FKSwgY29sb3VyPSJncmV5IikgKwogICAgICAgIGZhY2V0X2dyaWQoIE1FX2NsdXN0ZXIubmFtZSB+IC4pCiAgCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD03fQoKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbmV1cm9uYWwgPC0gTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lbbmFtZSAlaW4lIGMoImZvcmVicmFpbiIsICJtaWRicmFpbiIsICJoaW5kYnJhaW4iLCAibmV1cmFsIHR1YmUiLCAid2hvbGUgY29ydGV4IiksIF0KCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25ldXJvbmFsJGFnZS5uYW1lIDwtIG1hcHZhbHVlcyhNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9uZXVyb25hbCRhZ2UsCiAgICAgICAgICBmcm9tID0gYygxMC41LCAxMS41LCAxMi41LCAxMy41LCAxNC41LCAxNS41LCAxNi41LCAyMSwgMjUsIDI3LCAzNiwgNDEsIDEzMSwgNjUxKSwKICAgICAgICAgIHRvID0gYyggIkUxMC41IiwgIkUxMS41IiwgIkUxMi41IiwgIkUxMy41IiwgIkUxNC41IiwgIkUxNS41IiwgIkUxNi41IiwgIlAwIiwgIlA0IiwgIlA3IiwgIlAxNSIsICJQMzAiLCAiUDExMCIsICIyMU1iIikgKQoKCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25ldXJvbmFsIDwtIE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25ldXJvbmFsW01FX2NsdXN0ZXIubmFtZSAlaW4lICBNRV9jbHVzdGVyX25hbWVzW01FX2NsdXN0ZXIudHlwZSAlaW4lIGMoIk5ldXJvbmFsIiwgIk5ldXJvLU11c2N1bGFyIiwgIk11c2N1bGFyIiwgIk5vbi1OZXVyb25hbCIpLCBNRV9jbHVzdGVyLm5hbWVdLCBdCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25ldXJvbmFsJGFnZS5uYW1lIDwtIGZhY3RvcihNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9uZXVyb25hbCRhZ2UubmFtZSwgbGV2ZWxzPSBjKCAiRTEwLjUiLCAiRTExLjUiLCAiRTEyLjUiLCAiRTEzLjUiLCAiRTE0LjUiLCAiRTE1LjUiLCAiRTE2LjUiLCAiUDAiLCAiUDQiLCAiUDciLCAiUDE1IiwgIlAzMCIsICJQMTEwIiwgIjIxTWIiKSApCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9uZXVyb25hbF9ieV9NRSA8LSBNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9uZXVyb25hbFsgLCAuKFBTSV9tZWFuPW1lYW4oUFNJKSksIGJ5PWMoIk1FIiwgImFnZS5uYW1lIiwgIk1FX2NsdXN0ZXIubmFtZSIpIF0KCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9uZXVyb25hbF9ieV9NRV9jbHVzdGVyIDwtIE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25ldXJvbmFsWyAsIC4oUFNJX21lYW49bWVhbihQU0kpKSwgYnk9YygiYWdlLm5hbWUiLCAiTUVfY2x1c3Rlci5uYW1lIiwgIm5hbWUiKSBdCgoKICAKZ2dwbG90KCApICsKICAgICAgICBnZW9tX2xpbmUoZGF0YT0gTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbmV1cm9uYWxfYnlfTUUsIGFlcyhmYWN0b3IoYWdlLm5hbWUpLCBQU0lfbWVhbiwgZ3JvdXA9TUUpLCBjb2xvdXI9ImdyZXkiKSArCiAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9uZXVyb25hbF9ieV9NRV9jbHVzdGVyLCBhZXMoZmFjdG9yKGFnZS5uYW1lKSwgUFNJX21lYW4sIGdyb3VwPW5hbWUsIGNvbG91cj1uYW1lICksIHNpemU9MS4yICkgKwogICAgICAgIGZhY2V0X2dyaWQoIE1FX2NsdXN0ZXIubmFtZSB+IC4pCgoKCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD03fQoKVE9UQUwuTUVfbGV2ZWwgPC0gcmJpbmQoCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25vbl9uZXVyb25hbF9ieV9NRVsgLCAuKE1FLCBhZ2UubmFtZT1jbHVzdGVyLCBNRV9jbHVzdGVyLm5hbWUsIFBTSV9tZWFuKSBdLCAKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfbmV1cm9uYWxfYnlfTUUgKQoKVE9UQUwuY2x1c3Rlcl9sZXZlbCA8LSAgcmJpbmQoCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25ldXJvbmFsX2J5X01FX2NsdXN0ZXIsCk1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX25vbl9uZXVyb25hbF9ieV9NRV9jbHVzdGVyWyAsIC4oYWdlLm5hbWU9Y2x1c3RlciwgTUVfY2x1c3Rlci5uYW1lLCAgbmFtZT0iTm9uIG5ldXJvbmFsIiwgUFNJX21lYW4pIF0gKQoKClRPVEFMLmNsdXN0ZXJfbGV2ZWwkbmFtZSA8LSBtYXB2YWx1ZXMoVE9UQUwuY2x1c3Rlcl9sZXZlbCRuYW1lLAogICAgICAgICAgZnJvbSA9IGMoImZvcmVicmFpbiIsICJtaWRicmFpbiIsICJoaW5kYnJhaW4iLCAibmV1cmFsIHR1YmUiLCAid2hvbGUgY29ydGV4IiksCiAgICAgICAgICB0byA9IGMoIkZvcmVicmFpbiIsICJNaWRicmFpbiIsICJIaW5kYnJhaW4iLCAiTmV1cmFsIHR1YmUiLCAiV2hvbGUgY29ydGV4IikgKQoKClRPVEFMLmNsdXN0ZXJfbGV2ZWwkbmFtZSA8LSBmYWN0b3IoVE9UQUwuY2x1c3Rlcl9sZXZlbCRuYW1lLCBsZXZlbHM9YygiTm9uIG5ldXJvbmFsIiwgIkZvcmVicmFpbiIsICJNaWRicmFpbiIsICJIaW5kYnJhaW4iLCAiTmV1cmFsIHR1YmUiLCAiV2hvbGUgY29ydGV4IikgKQoKCgpGaWc1LkEgPC0gZ2dwbG90KCApICsKICAgICAgICBnZW9tX2xpbmUoZGF0YT0gVE9UQUwuTUVfbGV2ZWwsIGFlcyhmYWN0b3IoYWdlLm5hbWUpLCBQU0lfbWVhbiwgZ3JvdXA9TUUpLCBjb2xvdXI9ImdyZXkiLCBhbHBoYT0wLjUpICsKICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IFRPVEFMLmNsdXN0ZXJfbGV2ZWwsIGFlcyhmYWN0b3IoYWdlLm5hbWUpLCBQU0lfbWVhbiwgZ3JvdXA9bmFtZSwgY29sb3VyPW5hbWUgKSwgc2l6ZT0xLjIgKSArCiAgICAgICAgZmFjZXRfZ3JpZCggTUVfY2x1c3Rlci5uYW1lIH4gLikgKwogICAgICAgIGxhYnMoY29sb3VyID0gIk1lYW4gUFNJIGJ5IikgKwogICAgICAgIHlsYWIoIlBTSSIpICsKICAgICAgICB4bGFiKCIiKSArCiAgICAgICAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJywgY29sb3VyID0gJ2JsYWNrJykpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgpGaWc1LkEKYGBgCgoKYGBge3J9CgoKCmdncGxvdCggKSArCiAgICAgICAgZ2VvbV9saW5lKGRhdGE9IFRPVEFMLk1FX2xldmVsLCBhZXMoZmFjdG9yKGFnZS5uYW1lKSwgUFNJX21lYW4sIGdyb3VwPU1FKSwgY29sb3VyPSJncmV5IiwgYWxwaGE9MC41KSArCiAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBUT1RBTC5jbHVzdGVyX2xldmVsLCBhZXMoZmFjdG9yKGFnZS5uYW1lKSwgUFNJX21lYW4sIGdyb3VwPW5hbWUsIGNvbG91cj1uYW1lICksIHNpemU9MS4yICkgKwogICAgICAgIGZhY2V0X2dyaWQoIE1FX2NsdXN0ZXIubmFtZSB+IC4pICsKICAgICAgICBsYWJzKGNvbG91ciA9ICJNZWFuIFBTSSBieSIpICsKICAgICAgICB5bGFiKCJQU0kiKSArCiAgICAgICAgeGxhYigiIikgKwogICAgICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScsIGNvbG91ciA9ICdibGFjaycpKSArCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKQpgYGAKCgojIyMjIFdoaXBwZXQtZGVsdGEKCgoKCgpgYGB7cn0KCgoKZmlsZS5yZW1vdmUoJy4vd2hpcHBldF9kZWx0YS55YW1sJykKCgoKd3JpdGUudGFibGUoICJ3aGlwcGV0X2RlbHRhOiIsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKCgp3Y29udHJvbCA8LSBwYXN0ZShUaXNzdWVfY2x1c3RlcnNbY2x1c3RlciAlaW4lIGMoMSwgOCwgNiksICBdJEZpbGUuYWNjZXNzaW9uLCBjb2xsYXBzZT0iLCIpCgoKZm9yIChpIGluIGMoImZvcmVicmFpbiIsICJtaWRicmFpbiIsICJoaW5kYnJhaW4iLCAibmV1cmFsIHR1YmUiKSl7CiAgCiAgZm9yIChhIGluIGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSwgMjEpKSB7CiAgICAKICAgIGlmIChsZW5ndGgoVGlzc3VlX2NsdXN0ZXJzW25hbWU9PWkgJiBhZ2U9PWEgLCBdJEZpbGUuYWNjZXNzaW9uKT49NCl7CiAgICAKICAgICAgbmFtZSA9IHBhc3RlMCgiICAgICIsIGdzdWIoIiAiLCAiXyIsIHBhc3RlKCJjb250cm9sX3ZzIiwgaSwgcGFzdGUwKGEsICI6IiksIHNlcD0iICIgKSkpCiAgICAgIEEgPSAgcGFzdGUwKCIgICAgICAgIEEgOiAiLCB3Y29udHJvbCApCiAgICAgIEIgPSAgcGFzdGUwKCIgICAgICAgIEIgOiAiLCAgcGFzdGUoVGlzc3VlX2NsdXN0ZXJzW25hbWU9PWkgJiBhZ2U9PWEgLCBdJEZpbGUuYWNjZXNzaW9uLCBjb2xsYXBzZT0iLCIpKQogICAgICAKICAgICAgd3JpdGUudGFibGUobmFtZSwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQogICAgICB3cml0ZS50YWJsZSggQSwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQogICAgICB3cml0ZS50YWJsZSggQiwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQogICAgCiAgICB9CgogIH0KICAKfQoKCnNpZ25hbCA9IGMoImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIpCgpmb3IgKGEgaW4gYygxMC41LCAxMS41LCAxMi41LCAxMy41LCAxNC41LCAxNS41LCAxNi41LCAyMSkpIHsKICAgIAogIGlmIChsZW5ndGgoVGlzc3VlX2NsdXN0ZXJzW25hbWUgJWluJSBzaWduYWwgJiBhZ2U9PWEgLCBdJEZpbGUuYWNjZXNzaW9uKT49NCl7CiAgICAKICAgIG5hbWUgPSBwYXN0ZTAoIiAgICAiLCBnc3ViKCIgIiwgIl8iLCBwYXN0ZSgiY29udHJvbF92cyIsIHBhc3RlKHNpZ25hbCwgY29sbGFwc2U9Ii0iICksIHBhc3RlMChhLCAiOiIpLCBzZXA9IiAiICkpKQogICAgQSA9ICBwYXN0ZTAoIiAgICAgICAgQSA6ICIsIHdjb250cm9sICkKICAgIEIgPSAgcGFzdGUwKCIgICAgICAgIEIgOiAiLCAgcGFzdGUoVGlzc3VlX2NsdXN0ZXJzW25hbWUgJWluJSBzaWduYWwgJiBhZ2U9PWEgLCBdJEZpbGUuYWNjZXNzaW9uLCBjb2xsYXBzZT0iLCIpKQogICAgICAKICAgIHdyaXRlLnRhYmxlKG5hbWUsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKICAgIHdyaXRlLnRhYmxlKCBBLCBmaWxlPSIuL3doaXBwZXRfZGVsdGEueWFtbCIsIGFwcGVuZD1UUlVFLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UpCiAgICB3cml0ZS50YWJsZSggQiwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQoKICB9Cn0KIAoKc2lnbmFsID0gYygiaGluZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgIm1pZGJyYWluIikKCmZvciAoYSBpbiBjKDEwLjUsIDExLjUsIDEyLjUsIDEzLjUsIDE0LjUsIDE1LjUsIDE2LjUsIDIxKSkgewogICAgCiAgaWYgKGxlbmd0aChUaXNzdWVfY2x1c3RlcnNbbmFtZSAlaW4lIHNpZ25hbCAmIGFnZT09YSAsIF0kRmlsZS5hY2Nlc3Npb24pPj00KXsKICAgIAogICAgbmFtZSA9IHBhc3RlMCgiICAgICIsIGdzdWIoIiAiLCAiXyIsIHBhc3RlKCJjb250cm9sX3ZzIiwgcGFzdGUoc2lnbmFsLCBjb2xsYXBzZT0iLSIgKSwgcGFzdGUwKGEsICI6IiksIHNlcD0iICIgKSkpCiAgICBBID0gIHBhc3RlMCgiICAgICAgICBBIDogIiwgd2NvbnRyb2wgKQogICAgQiA9ICBwYXN0ZTAoIiAgICAgICAgQiA6ICIsICBwYXN0ZShUaXNzdWVfY2x1c3RlcnNbbmFtZSAlaW4lIHNpZ25hbCAmIGFnZT09YSAsIF0kRmlsZS5hY2Nlc3Npb24sIGNvbGxhcHNlPSIsIikpCiAgICAgIAogICAgd3JpdGUudGFibGUobmFtZSwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQogICAgd3JpdGUudGFibGUoIEEsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKICAgIHdyaXRlLnRhYmxlKCBCLCBmaWxlPSIuL3doaXBwZXRfZGVsdGEueWFtbCIsIGFwcGVuZD1UUlVFLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UpCgogIH0KfQoKCnNpZ25hbCA9IGMoImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIsICJtaWRicmFpbiIsImZvcmVicmFpbiIpCgpmb3IgKGEgaW4gYygxMC41LCAxMS41LCAxMi41LCAxMy41LCAxNC41LCAxNS41LCAxNi41LCAyMSkpIHsKICAgIAogIGlmIChsZW5ndGgoVGlzc3VlX2NsdXN0ZXJzW25hbWUgJWluJSBzaWduYWwgJiBhZ2U9PWEgLCBdJEZpbGUuYWNjZXNzaW9uKT49NCl7CiAgICAKICAgIG5hbWUgPSBwYXN0ZTAoIiAgICAiLCBnc3ViKCIgIiwgIl8iLCBwYXN0ZSgiY29udHJvbF92cyIsIHBhc3RlKHNpZ25hbCwgY29sbGFwc2U9Ii0iICksIHBhc3RlMChhLCAiOiIpLCBzZXA9IiAiICkpKQogICAgQSA9ICBwYXN0ZTAoIiAgICAgICAgQSA6ICIsIHdjb250cm9sICkKICAgIEIgPSAgcGFzdGUwKCIgICAgICAgIEIgOiAiLCAgcGFzdGUoVGlzc3VlX2NsdXN0ZXJzW25hbWUgJWluJSBzaWduYWwgJiBhZ2U9PWEgLCBdJEZpbGUuYWNjZXNzaW9uLCBjb2xsYXBzZT0iLCIpKQogICAgICAKICAgIHdyaXRlLnRhYmxlKG5hbWUsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKICAgIHdyaXRlLnRhYmxlKCBBLCBmaWxlPSIuL3doaXBwZXRfZGVsdGEueWFtbCIsIGFwcGVuZD1UUlVFLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UpCiAgICB3cml0ZS50YWJsZSggQiwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQoKICB9Cn0KCgoKc2lnbmFsID0gYygiYWRyZW5hbCBnbGFuZCIsICJza2VsZXRhbCBtdXNjbGUgdGlzc3VlIiwgImhlYXJ0IikKCmZvciAodGlzc3VlIGluIHNpZ25hbCkgewogICAgCiAgaWYgKGxlbmd0aChUaXNzdWVfY2x1c3RlcnNbbmFtZT09dGlzc3VlLCBdJEZpbGUuYWNjZXNzaW9uKT49NCl7CiAgICAKICAgIG5hbWUgPSBwYXN0ZTAoIiAgICAiLCBnc3ViKCIgIiwgIl8iLCBwYXN0ZSgiY29udHJvbF92cyIsIHBhc3RlMCh0aXNzdWUsICI6IiksIHNlcD0iICIgKSkpCiAgICBBID0gIHBhc3RlMCgiICAgICAgICBBIDogIiwgd2NvbnRyb2wgKQogICAgQiA9ICBwYXN0ZTAoIiAgICAgICAgQiA6ICIsICBwYXN0ZShUaXNzdWVfY2x1c3RlcnNbbmFtZT09dGlzc3VlLCBdJEZpbGUuYWNjZXNzaW9uLCBjb2xsYXBzZT0iLCIpKQogICAgICAKICAgIHdyaXRlLnRhYmxlKG5hbWUsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKICAgIHdyaXRlLnRhYmxlKCBBLCBmaWxlPSIuL3doaXBwZXRfZGVsdGEueWFtbCIsIGFwcGVuZD1UUlVFLCBxdW90ZSA9IEZBTFNFLCByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UpCiAgICB3cml0ZS50YWJsZSggQiwgZmlsZT0iLi93aGlwcGV0X2RlbHRhLnlhbWwiLCBhcHBlbmQ9VFJVRSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQoKICB9Cn0KCgpuYW1lPSAiICAgIGhpbmRicmFpbl9uZXVyYWxfdHViZV8yMV92c19mb3JlYnJhaW5fbWlkYnJhaW5fMjE6IgpBID0gcGFzdGUwKCIgICAgICAgIEEgOiAiLCAgcGFzdGUoVGlzc3VlX2NsdXN0ZXJzW2FnZT09MjEgJiBuYW1lICVpbiUgYygiaGluZGJyYWluIiwgIm5ldXJhbCB0dWJlIiksIF0kRmlsZS5hY2Nlc3Npb24sIGNvbGxhcHNlPSIsIikpCkIgPSBwYXN0ZTAoIiAgICAgICAgQiA6ICIsICBwYXN0ZShUaXNzdWVfY2x1c3RlcnNbYWdlPT0yMSAmIG5hbWUgJWluJSBjKCJmb3JlYnJhaW4iLCAibWlkYnJhaW4iKSwgXSRGaWxlLmFjY2Vzc2lvbiwgY29sbGFwc2U9IiwiKSkKCndyaXRlLnRhYmxlKG5hbWUsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKd3JpdGUudGFibGUoIEEsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKd3JpdGUudGFibGUoIEIsIGZpbGU9Ii4vd2hpcHBldF9kZWx0YS55YW1sIiwgYXBwZW5kPVRSVUUsIHF1b3RlID0gRkFMU0UsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKCgoKYGBgCgoKCiMjIyMgV2hpcHBldCBFTkNPREUgIyMjIwoKCgpgYGB7cn0KCkdldF9kZWx0YV90YWJsZSA8LSBmdW5jdGlvbiggc2lnbmFsLCBhZ2VzLCBwYXRoLCBleHRlbnNpb24gKXsKCiAgRGVsdGFfZ3JvdXAgPC0gZGF0YS50YWJsZSgpCiAgCiAgCiAgZm9yIChhIGluIGFnZXMpIHsKICAgICAgCiAgICBpZiAobGVuZ3RoKFRpc3N1ZV9jbHVzdGVyc1tuYW1lICVpbiUgc2lnbmFsICYgYWdlPT1hICwgXSRGaWxlLmFjY2Vzc2lvbik+PTQpewogICAgICAKICAgICAgbmFtZSA9IGdzdWIoIiAiLCAiXyIsIHBhc3RlKCJjb250cm9sX3ZzIiwgcGFzdGUoc2lnbmFsLCBjb2xsYXBzZT0iLSIgKSwgYSwgc2VwPSIgIiApKQogIAogICAgICBkZWx0YSA8LSBmcmVhZCAoIHBhc3RlMChwYXRoLCBuYW1lLCBleHRlbnNpb24pKQogICAgICAKICAgICAgZGVsdGEkYWdlIDwtIGEKICAgICAgCiAgICAgIERlbHRhX2dyb3VwIDwtIHJiaW5kKERlbHRhX2dyb3VwLCBkZWx0YSApCiAgICAgIAogICAgfQogIAogIH0KICByZXR1cm4oRGVsdGFfZ3JvdXApICAgIAp9CgpgYGAKCgpgYGB7cn0KCkRlbHRhX0hOTV93aGlwcGV0IDwtIEdldF9kZWx0YV90YWJsZSggYygiaGluZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgIm1pZGJyYWluIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygxMC41LCAxMS41LCAxMi41LCAxMy41LCAxNC41LCAxNS41LCAxNi41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAifi9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9QYXBlci9GaW5hbF9SZXBvcnQvUmVwcy9SZXAxL1doaXBwZXQvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLmRpZmYubWljcm9leG9ucyIpCgoKRGVsdGFfSE5NX01FIDwtIEdldF9kZWx0YV90YWJsZSggYygiaGluZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgIm1pZGJyYWluIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygxMC41LCAxMS41LCAxMi41LCAxMy41LCAxNC41LCAxNS41LCAxNi41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAifi9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9QYXBlci9GaW5hbF9SZXBvcnQvUmVwcy9SZXAxL1doaXBwZXQvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLmRpZmYuTUUubWljcm9leG9ucyIpCgoKRGVsdGFfSE5NX21lcmdlIDwtIG1lcmdlKERlbHRhX0hOTV93aGlwcGV0LCBEZWx0YV9ITk1fTUUsIGJ5PWMoImV4b25fSUQiLCAiYWdlIikpCgoKbGVuZ3RoKHVuaXF1ZShEZWx0YV9ITk1fbWVyZ2VbYWJzKERlbHRhUHNpLngpPj0wLjEgJiBQcm9iYWJpbGl0eS54PjAuOSAmIGFicyhEZWx0YVBzaS55KT49MC4xICYgUHJvYmFiaWxpdHkueT4wLjksIGV4b25fSURdKSkKCmBgYAoKCgoKYGBge3J9CgpEZWx0YV9GX3doaXBwZXQgPC0gR2V0X2RlbHRhX3RhYmxlKCBjKCJmb3JlYnJhaW4iKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDEwLjUsIDExLjUsIDEyLjUsIDEzLjUsIDE0LjUsIDE1LjUsIDE2LjUsIDIxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAifi9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9QYXBlci9GaW5hbF9SZXBvcnQvUmVwcy9SZXAxL1doaXBwZXQvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLmRpZmYubWljcm9leG9ucyIpCgoKRGVsdGFfRl9NRSA8LSBHZXRfZGVsdGFfdGFibGUoIGMoImZvcmVicmFpbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSwgMjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL1BhcGVyL0ZpbmFsX1JlcG9ydC9SZXBzL1JlcDEvV2hpcHBldC8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIuZGlmZi5NRS5taWNyb2V4b25zIikKCgpEZWx0YV9GX21lcmdlIDwtIG1lcmdlKERlbHRhX0Zfd2hpcHBldCwgRGVsdGFfRl9NRSwgYnk9YygiZXhvbl9JRCIsICJhZ2UiKSkKCmxlbmd0aCh1bmlxdWUoRGVsdGFfRl9tZXJnZVthYnMoRGVsdGFQc2kueCk+PTAuMSAmIFByb2JhYmlsaXR5Lng+MC45ICYgYWJzKERlbHRhUHNpLnkpPj0wLjEgJiBQcm9iYWJpbGl0eS55PjAuOSwgZXhvbl9JRF0pKQpgYGAKCgoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNX0KClN1cF92dWxjYW5vLkIgPC0gZ2dwbG90KCApICsKICBnZW9tX3BvaW50KGRhdGE9RGVsdGFfSE5NX01FLCBhZXMoLURlbHRhUHNpLCBQcm9iYWJpbGl0eSkpICsKICBnZW9tX3BvaW50KGRhdGE9RGVsdGFfSE5NX01FWyBEZWx0YVBzaT49MC4xICYgIFByb2JhYmlsaXR5ID49IDAuOSAsIF0sIGFlcygtRGVsdGFQc2ksIFByb2JhYmlsaXR5KSwgY29sb3I9ImJyb3duIikgKwogIGdlb21fcG9pbnQoZGF0YT1EZWx0YV9ITk1fTUVbIERlbHRhUHNpPCgtMC4xKSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgLCBdLCBhZXMoLURlbHRhUHNpLCBQcm9iYWJpbGl0eSksIGNvbG9yPSJkYXJrZ3JlZW4iKSArCiAgZ2VvbV90ZXh0KGRhdGE9RGVsdGFfSE5NX01FWyBEZWx0YVBzaT49MC4xICYgIFByb2JhYmlsaXR5ID49IDAuOSAsIC5OLCBieT0iYWdlIl0sIGFlcygtMC44NSwgMC45LCBsYWJlbD1OKSwgY29sb3VyID0gImJyb3duIiwgZm9udGZhY2UgPSAiYm9sZCIsIHNpemU9NSkgKwogIGdlb21fdGV4dChkYXRhPURlbHRhX0hOTV9NRVsgRGVsdGFQc2k8KC0wLjEpICYgIFByb2JhYmlsaXR5ID49IDAuOSAgLCAuTiwgYnk9ImFnZSJdLCBhZXMoMC44NSwgMC45LCBsYWJlbD1OKSwgY29sb3VyID0gImRhcmtncmVlbiIsIGZvbnRmYWNlID0gImJvbGQiLCBzaXplPTUpICsKICBmYWNldF9ncmlkKC4gfiBhZ2UpICsKICB4bGltKGMoLTEsMSkpICsKICB4bGFiKCJEZWx0YSBQU0kiKSArCiAgdGhlbWVfYncoKQoKClN1cF92dWxjYW5vLkEgPC0gZ2dwbG90KCApICsKICBnZW9tX3BvaW50KGRhdGE9RGVsdGFfSE5NX3doaXBwZXQsIGFlcygtRGVsdGFQc2ksIFByb2JhYmlsaXR5KSkgKwogIGdlb21fcG9pbnQoZGF0YT1EZWx0YV9ITk1fd2hpcHBldFsgRGVsdGFQc2k+PTAuMSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgLCBdLCBhZXMoLURlbHRhUHNpLCBQcm9iYWJpbGl0eSksIGNvbG9yPSJicm93biIpICsKICBnZW9tX3BvaW50KGRhdGE9RGVsdGFfSE5NX3doaXBwZXRbIERlbHRhUHNpPCgtMC4xKSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgLCBdLCBhZXMoLURlbHRhUHNpLCBQcm9iYWJpbGl0eSksIGNvbG9yPSJkYXJrZ3JlZW4iKSArCiAgZ2VvbV90ZXh0KGRhdGE9RGVsdGFfSE5NX3doaXBwZXRbIERlbHRhUHNpPj0wLjEgJiAgUHJvYmFiaWxpdHkgPj0gMC45ICwgLk4sIGJ5PSJhZ2UiXSwgYWVzKC0wLjg1LCAwLjksIGxhYmVsPU4pLCBjb2xvdXIgPSAiYnJvd24iLCBmb250ZmFjZSA9ICJib2xkIiwgc2l6ZT01KSArCiAgZ2VvbV90ZXh0KGRhdGE9RGVsdGFfSE5NX3doaXBwZXRbIERlbHRhUHNpPCgtMC4xKSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgICwgLk4sIGJ5PSJhZ2UiXSwgYWVzKDAuODUsIDAuOSwgbGFiZWw9TiksIGNvbG91ciA9ICJkYXJrZ3JlZW4iLCBmb250ZmFjZSA9ICJib2xkIiwgc2l6ZT01KSArICAKICBmYWNldF9ncmlkKC4gfiBhZ2UpICsKICB4bGltKGMoLTEsMSkpICsKICB4bGFiKCJEZWx0YSBQU0kiKSArCiAgdGhlbWVfYncoKQoKCgoKCmBgYAoKCiMjIyB3aGlwZXQgdnMgTUUKCmBgYHtyfQpNRV9BRF9BQSA8LSBmcmVhZCgiLi4vRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9XaGlwcGV0L1F1YW50L01FX0FEX0FBLnR4dCIpCgpEZWx0YV9ITk1fdG90YWwgPC0gIG1lcmdlKApEZWx0YV9ITk1fd2hpcHBldFsgLCBjKCJleG9uX0lEIiwgIkdlbmUiLCAiTm9kZSIsICJDb29yZCIsICJTdHJhbmQiLCAiVHlwZSIsICJEZWx0YVBzaSIsICJQcm9iYWJpbGl0eSIsICJhZ2UiKV0sCkRlbHRhX0hOTV9NRVsgLCBjKCJleG9uX0lEIiwgIkdlbmUiLCAiTm9kZSIsICJDb29yZCIsICJTdHJhbmQiLCAiVHlwZSIsICJEZWx0YVBzaSIsICJQcm9iYWJpbGl0eSIsICJhZ2UiKV0sCgpieT1jKCJleG9uX0lEIiwgIkdlbmUiLCAiTm9kZSIsICJDb29yZCIsICJTdHJhbmQiLCAiVHlwZSIsICAiYWdlIikpCgpEZWx0YV9ITk1fdG90YWxbICwgY29yKERlbHRhUHNpLngsIERlbHRhUHNpLnksIG1ldGhvZD0icGVhcnNvbiIpICwgYnk9YWdlIF0KCkRlbHRhX0hOTV90b3RhbFtwYXN0ZSggZXhvbl9JRCwgYWdlLCBzZXA9InwiKSAlaW4lIHRvdGFsX2RpZmZfSE5NICwgY29yKERlbHRhUHNpLngsIERlbHRhUHNpLnksIG1ldGhvZD0icGVhcnNvbiIpICwgYnk9YWdlIF0KCgpEZWx0YV9ITk1fdG90YWxbLCBOb2RlX3R5cGU6PXBhc3RlMCgibSIsIFR5cGUpXQpEZWx0YV9ITk1fdG90YWxbIFR5cGU9PSJDRSIgJiBleG9uX0lEICVpbiUgTUVfQURfQUFbIFR5cGU9PSJBQSIgJiBleG9uX3R5cGU9PSJFIiAsICBleG9uX0lEICBdLCBOb2RlX3R5cGU6PSJtQ0VfQUEiIF0KRGVsdGFfSE5NX3RvdGFsWyBUeXBlPT0iQ0UiICYgZXhvbl9JRCAlaW4lIE1FX0FEX0FBWyBUeXBlPT0iQUEiICYgZXhvbl90eXBlPT0iTUUiICwgIGV4b25fSUQgIF0sIE5vZGVfdHlwZTo9Im1DRV9tQUEiIF0KRGVsdGFfSE5NX3RvdGFsWyBUeXBlPT0iQ0UiICYgZXhvbl9JRCAlaW4lIE1FX0FEX0FBWyBUeXBlPT0iQUQiICYgZXhvbl90eXBlPT0iRSIgLCAgZXhvbl9JRCAgXSwgTm9kZV90eXBlOj0ibUNFX0FEIiBdCkRlbHRhX0hOTV90b3RhbFsgVHlwZT09IkNFIiAmIGV4b25fSUQgJWluJSBNRV9BRF9BQVsgVHlwZT09IkFEIiAmIGV4b25fdHlwZT09Ik1FIiAsICBleG9uX0lEICBdLCBOb2RlX3R5cGU6PSJtQ0VfbUFEIiBdCgp3aGlwcGV0X01FX2NvcnIgPC0gbWVyZ2UoIERlbHRhX0hOTV90b3RhbFsgLCBjb3IoRGVsdGFQc2kueCwgRGVsdGFQc2kueSwgbWV0aG9kPSJwZWFyc29uIikgLCBieT1hZ2UgXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgRGVsdGFfSE5NX3RvdGFsWyAoYWJzKERlbHRhUHNpLngpPj0wLjEgJiBQcm9iYWJpbGl0eS54Pj0wLjkpIHwoYWJzKERlbHRhUHNpLnkpPj0wLjEgJiBQcm9iYWJpbGl0eS55Pj0wLjkpICAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3IoRGVsdGFQc2kueCwgRGVsdGFQc2kueSwgbWV0aG9kPSJwZWFyc29uIikgLCBieT1hZ2UgXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9ImFnZSIpCgojd2hpcHBldF9NRV9jb3JyLnR5cGVzIDwtIG1lcmdlKCBEZWx0YV9ITk1fdG90YWxbICwgLihOPS5OLCBjb3IudG90YWw9KGNvcihEZWx0YVBzaS54LCBEZWx0YVBzaS55LCBtZXRob2Q9InBlYXJzb24iKSkpICwgYnk9YygiYWdlIiwgIk5vZGVfdHlwZSIpIF0sIAojICAgICAgICAgICAgICAgICAgICAgICAgICBEZWx0YV9ITk1fdG90YWxbcGFzdGUoIGV4b25fSUQsIGFnZSwgc2VwPSJ8IikgJWluJSB0b3RhbF9kaWZmX0hOTSAsIC4oTj0uTiwgY29yLnNpZz0oY29yKERlbHRhUHNpLngsIERlbHRhUHNpLnksIG1ldGhvZD0icGVhcnNvbiIpKSkgLCBieT1jKCJhZ2UiLCAjIk5vZGVfdHlwZSIpIF0sCiMgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PWMoImFnZSIsICJOb2RlX3R5cGUiKSkKCgoKd2hpcHBldF9NRV9jb3JyLnR5cGVzIDwtIERlbHRhX0hOTV90b3RhbFsgLCAuKE49Lk4sIGNvci50b3RhbD0oY29yKERlbHRhUHNpLngsIERlbHRhUHNpLnksIG1ldGhvZD0icGVhcnNvbiIpKSkgLCBieT1jKCJhZ2UiLCAiTm9kZV90eXBlIikgXQoKCiN3aGlwcGV0X01FX2NvcnIudHlwZXNbTi55PDUsIGNvci5zaWc6PU5BXQoKI3doaXBwZXRfTUVfY29yci50eXBlcy5tZWx0ZWQgPC0gcmJpbmQod2hpcHBldF9NRV9jb3JyLnR5cGVzWywgLihhZ2UsIE5vZGVfdHlwZSwgTj1OLngsIGNvcj1jb3IudG90YWwsIEdyb3VwPSJUb3RhbCIpIF0sCiAjICAgICB3aGlwcGV0X01FX2NvcnIudHlwZXNbLCAuKGFnZSwgTm9kZV90eXBlLCBOPU4ueSwgY29yPWNvci5zaWcsIEdyb3VwPSJTaWduaWZpY2FudCIpIF0pCgpEZWx0YV9ITk1fdG90YWwkTm9kZV90eXBlIDwtIGZhY3RvcihEZWx0YV9ITk1fdG90YWwkTm9kZV90eXBlICwgbGV2ZWxzID0gYygibUNFIiwgIm1BQSIsICJtQUQiLCAibUNFX21BQSIsICJtQ0VfbUFEIiwgIm1DRV9BQSIsICJtQ0VfQUQiKSkKCndoaXBwZXRfTUVfY29yci50eXBlcyROb2RlX3R5cGUgPC0gZmFjdG9yKHdoaXBwZXRfTUVfY29yci50eXBlcyROb2RlX3R5cGUgLCBsZXZlbHMgPSBjKCJtQ0UiLCAibUFBIiwgIm1BRCIsICJtQ0VfbUFBIiwgIm1DRV9tQUQiLCAibUNFX0FBIiwgIm1DRV9BRCIpKQoKClN1cF92dWxjYW5vLkQgPC0gZ2dwbG90KHdoaXBwZXRfTUVfY29yci50eXBlc1tOPjUsIF0pICsKICBnZW9tX2JveHBsb3QoYWVzKE5vZGVfdHlwZSwgY29yLnRvdGFsLCBmaWxsPU5vZGVfdHlwZSkpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWljcm9leG9uIG5vZGUgdHlwZSIpICsKICB4bGFiKCIiKSArCiAgeWxhYigiRGVsdGEgUFNJIGNvcnJlbGF0aW9uIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjYpKSArCiAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEpKQoKCmBgYAoKCmBgYHtyfQoKU3VwX3Z1bGNhbm8uQyA8LSBnZ3Bsb3QoRGVsdGFfSE5NX3RvdGFsWyFpcy5uYShOb2RlX3R5cGUpXSApICsKICBnZW9tX2JhcihhZXMoYXMuZmFjdG9yKGFnZSksIGZpbGw9Tm9kZV90eXBlKSwgc3RhdD0iY291bnQiICkgKwogIGdlb21fdGV4dCggZGF0YT1EZWx0YV9ITk1fdG90YWxbICwgLihOPS5OLCBjb3I9Y29yKERlbHRhUHNpLngsIERlbHRhUHNpLnksIG1ldGhvZD0icGVhcnNvbiIpKSAsIGJ5PWFnZSBdLAogICAgICAgICAgICAgYWVzKHg9YXMuZmFjdG9yKGFnZSksIHk9TisyMDAsIGxhYmVsPSBwYXN0ZTAoIlI9Iiwgcm91bmQoY29yLCAyKSkpKSArCiAgeGxhYigiRFBDIikgKwogIHlsYWIoIk51bWJlciBvZiBzcGxpY2luZyBub2RlcyIpICsKICAgIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJNaWNyb2V4b24gbm9kZSB0eXBlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEpKQoKU3VwX3Z1bGNhbm8ubGVnZW5kIDwtIGdldF9sZWdlbmQoU3VwX3Z1bGNhbm8uQykKYGBgCgoKCgoKCmBgYHtyfQoKbGlicmFyeShnZ0V4dHJhKQoKTUVfQURfQUEKCkRlbHRhX0hOTV90b3RhbC5hbHRfTUUgPC0gbWVyZ2UoRGVsdGFfSE5NX3RvdGFsWyAsIC4oZXhvbl9JRCwgTm9kZV90eXBlLCBhZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbHRhUHNpLndwPURlbHRhUHNpLngsIFByb2JhYmlsaXR5LndwPVByb2JhYmlsaXR5LngsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbHRhUHNpLm1lPURlbHRhUHNpLnksIFByb2JhYmlsaXR5Lm1lPVByb2JhYmlsaXR5LnkpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNRV9BRF9BQVsgLGMoImV4b25fSUQiLCAiZXhvbl9JRC5hbHQiKV0sIGJ5PWMoImV4b25fSUQiKSkKCkRlbHRhX0hOTV90b3RhbC5hbHRfTUUuY29tcGFyZSA8LSBtZXJnZShEZWx0YV9ITk1fdG90YWwuYWx0X01FLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVsdGFfSE5NX3RvdGFsWyAsIC4oZXhvbl9JRCwgTm9kZV90eXBlLCBhZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVsdGFQc2kud3AuYWx0PURlbHRhUHNpLngsIFByb2JhYmlsaXR5LndwLmFsdD1Qcm9iYWJpbGl0eS54LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbHRhUHNpLm1lLmFsdD1EZWx0YVBzaS55LCBQcm9iYWJpbGl0eS5tZS5hbHQ9UHJvYmFiaWxpdHkueSldLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkueD1jKCJleG9uX0lELmFsdCIsICJhZ2UiKSwgYnkueT1jKCJleG9uX0lEIiwgImFnZSIpICkKCgoKRGVsdGFfSE5NX3RvdGFsLmFsdF9NRS5jb21wYXJlLnN0YXRzIDwtIERlbHRhX0hOTV90b3RhbC5hbHRfTUUuY29tcGFyZVssIC4oIGFsdF9jb3Iud3A9Y29yKERlbHRhUHNpLndwLCBEZWx0YVBzaS53cC5hbHQpLCBhbHRfY29yLm1lPWNvcihEZWx0YVBzaS5tZSwgRGVsdGFQc2kubWUuYWx0KSApLCBieT1jKCJleG9uX0lELmFsdCIsICJOb2RlX3R5cGUueCIpIF0KCgpwIDwtIGdncGxvdChEZWx0YV9ITk1fdG90YWwuYWx0X01FLmNvbXBhcmUuc3RhdHMpKwogIGdlb21fcG9pbnQoYWVzKHg9YWx0X2Nvci53cCwgeT1hbHRfY29yLm1lKSwgYWxwaGE9MC40KSsKICB0aGVtZV9idygpICsKICBnZW9tX2RlbnNpdHlfMmQoYWVzKHg9YWx0X2Nvci53cCwgeT1hbHRfY29yLm1lKSwgYWxwaGE9MC40LCBuPTUwMCwgYWRqdXN0PTEuMykgKwogIGdlb21fcnVnKCkgKwogIHhsYWIoIldoaXBwZXQgc2hvcnQvbG9uZyBtaWNyb2V4b24gY29ycmVsYXRpb24iKSArCiAgeWxhYigiTWljcm9FeG9uYXRvciBzaG9ydC9sb25nIG1pY3JvZXhvbiBjb3JyZWxhdGlvbiIpCgoKU3VwX3Z1bGNhbm8uRSA8LSBnZ01hcmdpbmFsKHAsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0idHJhbnNwYXJlbnQiKQoKCmBgYAoKCgoKYGBge3IsICBmaWcuaGVpZ2h0PTE1LCBmaWcud2lkdGg9MTJ9CgoKU3VwX3Z1bGNhbm8uQ0QgPC0gcGxvdF9ncmlkKFN1cF92dWxjYW5vLkMgICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5BIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3VwX3Z1bGNhbm8uRCAgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTkEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBucm93PTEsIGxhYmVscyA9IGMoIkMiLCAiRCIpICkKCgpTdXBfdnVsY2Fuby5DRCA8LSBwbG90X2dyaWQoU3VwX3Z1bGNhbm8ubGVnZW5kLCBTdXBfdnVsY2Fuby5DRCwgbmNvbD0xLCByZWxfaGVpZ2h0cyA9IGMoMSwgOCkgKQoKClN1cF92dWxjYW5vLmJvdHRvbSA8LXBsb3RfZ3JpZChTdXBfdnVsY2Fuby5DRCwgcGxvdF9ncmlkKG51bGxHcm9iKCksIFN1cF92dWxjYW5vLkUsIG51bGxHcm9iKCksICBucm93PTEsIHJlbF93aWR0aHMgPSBjKDEsMywxKSwgbGFiZWxzID0gYygiIiwgIkUiLCAiIikgKSwgbmNvbD0xKQoKU3VwX3Z1bGNhbm8uYm90dG9tIDwtcGxvdF9ncmlkKFN1cF92dWxjYW5vLkNELCBTdXBfdnVsY2Fuby5FLCBsYWJlbHMgPSBjKCAiIiwgIkUiKSwgbnJvdz0xLCByZWxfd2lkdGhzID0gYygyLCAxKSkKCgoKCnBsb3RfZ3JpZChTdXBfdnVsY2Fuby5BLCBTdXBfdnVsY2Fuby5CLCBTdXBfdnVsY2Fuby5ib3R0b20sICBuY29sPTEsIGxhYmVscyA9IGMoIkEiLCAiQiIsICIiKSwgcmVsX2hlaWdodHMgPSBjKDEsMSwzKSkKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQoKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZ3JpZCkKCnBsb3RfZ3JpZChTdXBfdnVsY2Fuby5DRCwgcGxvdF9ncmlkKG51bGxHcm9iKCksIFN1cF92dWxjYW5vLkUsIG51bGxHcm9iKCksICBucm93PTEsIHJlbF93aWR0aHMgPSBjKDEsMywxKSwgbGFiZWxzID0gYygiIiwgIkUiLCAiIikgKSwgbmNvbD0xKQpgYGAKCgojIyMKCgoKCmBgYHtyfQpEZWx0YV9ITk1fd2hpcHBldF9NRSA8LSBtZXJnZShEZWx0YV9ITk1fd2hpcHBldCwgRGVsdGFfSE5NX01FLCBieT1jKCJleG9uX0lEIiwgIkdlbmUiLCAiTm9kZSIsICAiQ29vcmQiLCAiU3RyYW5kIiwgIlR5cGUiLCAiYWdlIikgKQoKRGVsdGFfSE5NX3doaXBwZXRfTUVbIChhYnMoRGVsdGFQc2kueCk+PTAuMSAmICBQcm9iYWJpbGl0eS54ID49IDAuOSkgJiAgKGFicyhEZWx0YVBzaS55KT49MC4xICYgIFByb2JhYmlsaXR5LnkgPj0gMC45KSAsIC5OICwgYnk9KGFnZSldCgpEZWx0YV9ITk1fd2hpcHBldF9NRV9pbmNsdWRlZCA8LSBEZWx0YV9ITk1fd2hpcHBldF9NRVsgKERlbHRhUHNpLng8PS0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChEZWx0YVBzaS55PD0tMC4xICYgIFByb2JhYmlsaXR5LnkgPj0gMC45KSAgLCAuTiAsIGJ5PShhZ2UpXQpEZWx0YV9ITk1fd2hpcHBldF9NRV9leGNsdWRlZCA8LSBEZWx0YV9ITk1fd2hpcHBldF9NRVsgKERlbHRhUHNpLng+PTAuMSAmICBQcm9iYWJpbGl0eS54ID49IDAuOSkgJiAgKERlbHRhUHNpLnk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSkgICwgLk4gLCBieT0oYWdlKV0KCgpEZWx0YV9ITk1faW5jbHVkZWRfc3RhdHMgPC0gY2JpbmQoRGVsdGFfSE5NX3doaXBwZXRfaW5jbHVkZWRbb3JkZXIoYWdlKV0sIERlbHRhX0hOTV9NRV9pbmNsdWRlZFtvcmRlcihhZ2UpLCAyXSwgRGVsdGFfSE5NX3doaXBwZXRfTUVfaW5jbHVkZWRbb3JkZXIoYWdlKSwgMl0pCmNvbG5hbWVzKERlbHRhX0hOTV9pbmNsdWRlZF9zdGF0cykgPC0gYygiYWdlIiwgIldoaXBwZXQiLCAiTWljcm9FeG9uYXRvciIsICJCb3RoIikKCmBgYAoKCgoKYGBge3J9CgoKd2hpcHBldF9NRV9hZ2Vfc3RhdHMgPC0gZnVuY3Rpb24oRGVsdGFfU193aGlwcGV0LCBEZWx0YV9TX01FKSB7IAoKCiAgRGVsdGFfU193aGlwcGV0X01FIDwtIG1lcmdlKERlbHRhX1Nfd2hpcHBldCwgRGVsdGFfU19NRSwgYnk9YygiZXhvbl9JRCIsICJHZW5lIiwgIk5vZGUiLCAgIkNvb3JkIiwgIlN0cmFuZCIsICJUeXBlIiwgImFnZSIpICkKICAKICBEZWx0YV9TX3doaXBwZXRfTUVbIChhYnMoRGVsdGFQc2kueCk+PTAuMSAmICBQcm9iYWJpbGl0eS54ID49IDAuOSkgJiAgKGFicyhEZWx0YVBzaS55KT49MC4xICYgIFByb2JhYmlsaXR5LnkgPj0gMC45KSAsIC5OICwgYnk9KGFnZSldCiAgCiAgRGVsdGFfU193aGlwcGV0X01FX2luY2x1ZGVkIDwtIERlbHRhX1Nfd2hpcHBldF9NRVsgKERlbHRhUHNpLng8PS0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChEZWx0YVBzaS55PD0tMC4xICYgIFByb2JhYmlsaXR5LnkgPj0gMC45KSAgLCAuTiAsIGJ5PShhZ2UpXQogIERlbHRhX1Nfd2hpcHBldF9NRV9leGNsdWRlZCA8LSBEZWx0YV9TX3doaXBwZXRfTUVbIChEZWx0YVBzaS54Pj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChEZWx0YVBzaS55Pj0wLjEgJiAgUHJvYmFiaWxpdHkueSA+PSAwLjkpICAsIC5OICwgYnk9KGFnZSldCiAgCiAgCiAgI0RlbHRhX1NfaW5jbHVkZWRfc3RhdHMgPC0gY2JpbmQoRGVsdGFfU193aGlwcGV0X2luY2x1ZGVkW29yZGVyKGFnZSldLCBEZWx0YV9TX01FX2luY2x1ZGVkW29yZGVyKGFnZSksIDJdLCBEZWx0YV9TX3doaXBwZXRfTUVfaW5jbHVkZWRbb3JkZXIoYWdlKSwgMl0pCiAgI2NvbG5hbWVzKERlbHRhX1NfaW5jbHVkZWRfc3RhdHMpIDwtIGMoImFnZSIsICJXaGlwcGV0IiwgIk1pY3JvRXhvbmF0b3IiLCAiQm90aCIpCiAgCiAgCiAgCiAgRGVsdGFfU193aGlwcGV0X01FWywgZGlmZl9oaWdoOj1GQUxTRV0KICBEZWx0YV9TX3doaXBwZXRfTUVbIChhYnMoRGVsdGFQc2kueCk+PTAuMSAmICBQcm9iYWJpbGl0eS54ID49IDAuOSkgJiAgKGFicyhEZWx0YVBzaS55KT49MC4xICYgIFByb2JhYmlsaXR5LnkgPj0gMC45KSAsIGRpZmZfaGlnaDo9VFJVRV0KICAKICBEZWx0YV9TX3doaXBwZXRfTUVbLCBkaWZmX2xvdzo9RkFMU0VdCiAgRGVsdGFfU193aGlwcGV0X01FWyAoYWJzKERlbHRhUHNpLngpPj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjgpICYgIChhYnMoRGVsdGFQc2kueSk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOCkgLCBkaWZmX2xvdzo9VFJVRV0KICAKICAKICBhZ2VzIDwtIHNvcnQodW5pcXVlKERlbHRhX1Nfd2hpcHBldF9NRSRhZ2UpKQogIGFnZV9pbnQgPC0gYyhhZ2VzW2xlbmd0aChhZ2VzKV0pCiAgCiAgCiAgICAKICBmb3IgKGEgaW4gcmV2KGFnZXNbMTpsZW5ndGgoYWdlcyktMV0pKXsKICAgIAogICAgYWdlX2ludCA9IGNiaW5kKGFnZV9pbnQsIGEpCiAgICAKICAgIERlbHRhX1Nfd2hpcHBldF9NRVsgYWdlPT1hICYgZGlmZl9oaWdoPT1UUlVFICYgIGV4b25fSUQgJWluJSBEZWx0YV9TX3doaXBwZXRfTUVbYWdlICVpbiUgYWdlX2ludCAmIGRpZmZfaGlnaD09VFJVRSwgLk4sIGJ5PWMoImV4b25fSUQiLCAiR2VuZSIpIF1bTj09bGVuZ3RoKGFnZV9pbnQpXSRleG9uX0lEICAgLCBkaWZmX2FnZTo9YSBdCiAgfQogICAgCiAgRGVsdGFfU193aGlwcGV0X01FX2FnZV9kaWZmIDwtIERlbHRhX1Nfd2hpcHBldF9NRVsgZGlmZl9oaWdoPT1UUlVFLCAuKGRpZmZfYWdlID0gbWluKGRpZmZfYWdlLCBuYS5ybSA9IFRSVUUpKSwgYnk9YygiZXhvbl9JRCIsICJHZW5lIildCiAgCiAgCiAgRGVsdGFfU193aGlwcGV0X01FJGRlbHRhX3NpbmcgPC0gc2lnbihEZWx0YV9TX3doaXBwZXRfTUUkRGVsdGFQc2kueCkKICAKICBEZWx0YV9TX3doaXBwZXRfTUVfZGlmZl9jb3VudCA8LSBEZWx0YV9TX3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFICwgLk4gLCBieT1jKCJleG9uX0lEIiwgImRlbHRhX3NpbmciKV0KICByZXNjdWVfZXhvbnMgPC0gRGVsdGFfU193aGlwcGV0X01FX2RpZmZfY291bnRbTj49MiAmICFleG9uX0lEICVpbiUgRGVsdGFfU193aGlwcGV0X01FX2FnZV9kaWZmW2RpZmZfYWdlIT1JbmYsIF0kZXhvbl9JRCAsIF0kZXhvbl9JRAogIAogIAogICNhZ2VzIDwtIERlbHRhX1NfaW5jbHVkZWRfc3RhdHMkYWdlCiAgI2FnZV9pbnQgPC0gYyhhZ2VzW2xlbmd0aChhZ2VzKV0pCiAgRGVsdGFfU193aGlwcGV0X01FW2V4b25fSUQgJWluJSByZXNjdWVfZXhvbnNdCiAgCiAgICAKICBmb3IgKGEgaW4gcmV2KGFnZXNbMTpsZW5ndGgoYWdlcyktMV0pKXsKICAgIAogICAgYWdlX2ludCA9IGNiaW5kKGFnZV9pbnQsIGEpCiAgICAKICAgIERlbHRhX1Nfd2hpcHBldF9NRVtleG9uX0lEICVpbiUgcmVzY3VlX2V4b25zICYgYWdlPT1hICYgZGlmZl9sb3c9PVRSVUUgJiAgZXhvbl9JRCAlaW4lIERlbHRhX1Nfd2hpcHBldF9NRVthZ2UgJWluJSBhZ2VfaW50ICYgZGlmZl9sb3c9PVRSVUUsIC5OLCBieT1jKCJleG9uX0lEIiwgIkdlbmUiKSBdW049PWxlbmd0aChhZ2VfaW50KV0kZXhvbl9JRCAgICwgZGlmZl9hZ2VfbG93Oj1hIF0KICB9CiAgICAKICAKICBEZWx0YV9TX3doaXBwZXRfTUVfYWdlX2RpZmZfbG93IDwtIERlbHRhX1Nfd2hpcHBldF9NRVsgZGlmZl9sb3c9PVRSVUUsIC4oZGlmZl9hZ2UgPSBtaW4oZGlmZl9hZ2VfbG93LCBuYS5ybSA9IFRSVUUpKSwgYnk9YygiZXhvbl9JRCIsICJHZW5lIildCiAgCiAgCiAgZGlmZl9NRV9zaW5nIDwtIERlbHRhX1Nfd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUsIC1zaWduKERlbHRhUHNpLnkpXQogIG5hbWVzKGRpZmZfTUVfc2luZykgPC0gRGVsdGFfU193aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSwgZXhvbl9JRF0KICAKICAKICBEZWx0YV9TX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwgPC0gIHJiaW5kKERlbHRhX1Nfd2hpcHBldF9NRV9hZ2VfZGlmZltkaWZmX2FnZSE9SW5mXSwgRGVsdGFfU193aGlwcGV0X01FX2FnZV9kaWZmX2xvd1tkaWZmX2FnZSE9SW5mXSkKICAKICBEZWx0YV9TX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbLCBjaGFuZ2VfZGlyOj1kaWZmX01FX3NpbmdbZXhvbl9JRF0gXQogIAogIHJldHVybihEZWx0YV9TX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwpCgp9CgpgYGAKCgoKCmBgYHtyfQoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwgPC0gIHdoaXBwZXRfTUVfYWdlX3N0YXRzKERlbHRhX0hOTV93aGlwcGV0LCBEZWx0YV9ITk1fTUUpCkRlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCA8LSAgd2hpcHBldF9NRV9hZ2Vfc3RhdHMoRGVsdGFfRl93aGlwcGV0LCBEZWx0YV9GX01FKQoKCkRlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9zdGF0cyA8LSAgRGVsdGFfRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWywgLihDb3VudD0uTikgLCBieT1jKCJkaWZmX2FnZSIsICJjaGFuZ2VfZGlyIikgXQpEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9zdGF0cyA8LSAgRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbLCAuKENvdW50PS5OKSAsIGJ5PWMoImRpZmZfYWdlIiwgImNoYW5nZV9kaXIiKSBdCgpgYGAKCgoKCgoKCgoKCgpgYGB7cn0KCmdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhPURlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9zdGF0c1tjaGFuZ2VfZGlyPT0xXSwgYWVzKGZhY3RvcihkaWZmX2FnZSksIENvdW50KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGw9InNreWJsdWUiKSArCgogIGdlb21fYmFyKGRhdGE9RGVsdGFfRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX3N0YXRzW2NoYW5nZV9kaXI9PS0xXSwgYWVzKGZhY3RvcihkaWZmX2FnZSksIC1Db3VudCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJmaXJlYnJpY2siKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gTkEpKQoKYGBgCgoKCgoKCgoKCgoKCgpgYGB7cn0KCgoKCgoKZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGE9RGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfc3RhdHNbY2hhbmdlX2Rpcj09MV0sIGFlcyhmYWN0b3IoZGlmZl9hZ2UpLCBDb3VudCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJza3libHVlIikgKwoKICBnZW9tX2JhcihkYXRhPURlbHRhX0hOTV93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX3N0YXRzW2NoYW5nZV9kaXI9PS0xXSwgYWVzKGZhY3RvcihkaWZmX2FnZSksIC1Db3VudCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJmaXJlYnJpY2siKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gTkEpKQoKYGBgCgoKCgpgYGB7ciwgIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0zfQoKCgpNRV9kaWZmX2FnZSA8LSBEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRkaWZmX2FnZQpuYW1lcyhNRV9kaWZmX2FnZSkgPC0gRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRAoKCmRpZmZfTUVfc2luZyA8LSBEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRjaGFuZ2VfZGlyCm5hbWVzKGRpZmZfTUVfc2luZykgPC0gRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRAoKTUVfY2x1c3RlcnNfdGFibGVbLCBkaWZmX2FnZTo9TkFdCk1FX2NsdXN0ZXJzX3RhYmxlWywgY2hhbmdlX2Rpcjo9TkFdCk1FX2NsdXN0ZXJzX3RhYmxlWywgZGlmZl9hZ2U6PU1FX2RpZmZfYWdlW01FXSBdCk1FX2NsdXN0ZXJzX3RhYmxlWywgY2hhbmdlX2Rpcjo9ZGlmZl9NRV9zaW5nW01FXSBdCgpNRV9jbHVzdGVyc190YWJsZVshaXMubmEoZGlmZl9hZ2UpXQoKCk1FX2NsdXN0ZXJzX3RhYmxlWyAsIFRvdGFsOj0uTiwgYnk9IE1FX2NsdXN0ZXJzXQoKTUVfY2x1c3RlcnNfdGFibGVfc3RhdHMgPC0gIE1FX2NsdXN0ZXJzX3RhYmxlWywgLk4gLCBieT1jKCJNRV9jbHVzdGVycyIsICJkaWZmX2FnZSIsICJjaGFuZ2VfZGlyIiwgIlRvdGFsIildCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c1ssIFBlcmNlbnRhZ2U6PU4qMTAwL1RvdGFsXQoKCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzWyAsIHN1bShOKSwgYnk9YyggImNoYW5nZV9kaXIiICkgXSAjVE9UQUwKTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNbICwgc3VtKE4pLCBieT1jKCAiZGlmZl9hZ2UiLCAiY2hhbmdlX2RpciIgKSBdICNUT1RBTAoKTUVfY2x1c3RlcnNfdGFibGVfc3RhdHMgPC0gbWVyZ2UoTUVfY2x1c3RlcnNfdGFibGVfc3RhdHMsIE1FX2NsdXN0ZXJfbmFtZXNbLCBjKCJNRV9jbHVzdGVyIiwgIk1FX2NsdXN0ZXIubmFtZSIsICJNRV9jbHVzdGVyLnR5cGUiKV0sIGJ5Lng9Ik1FX2NsdXN0ZXJzIiwgYnkueT0iTUVfY2x1c3RlciIpCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19ITk0gPC0gTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNbZGlmZl9hZ2UhPSJOQSIgJiBjaGFuZ2VfZGlyIT0iTkEiXQoKCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19ITk1fc3ViIDwtIE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0hOTVtNRV9jbHVzdGVyLm5hbWUgJWluJSAgTUVfY2x1c3Rlcl9uYW1lc1tNRV9jbHVzdGVyLnR5cGUgJWluJSBjKCJOZXVyb25hbCIsICJOZXVyby1NdXNjdWxhciIsICJNdXNjdWxhciIsICJOb24tTmV1cm9uYWwiKSwgTUVfY2x1c3Rlci5uYW1lXSwgXQpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19ITk1fc3ViJE1FX2NsdXN0ZXIubmFtZSA8LSBmYWN0b3IoTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfSE5NX3N1YiRNRV9jbHVzdGVyLm5hbWUsIGxldmVscyA9IHNvcnQodW5pcXVlKGFzLmNoYXJhY3RlcihNRV9jbHVzdGVyc190YWJsZV9zdGF0c19ITk1fc3ViJE1FX2NsdXN0ZXIubmFtZSkpKSkKCgoKRmlnNS5CIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhPU1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0hOTV9zdWJbY2hhbmdlX2Rpcj09MV0sIGFlcyhmYWN0b3IoZGlmZl9hZ2UpLCBQZXJjZW50YWdlKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGw9InNreWJsdWUiKSArCiAgZ2VvbV9iYXIoZGF0YT1NRV9jbHVzdGVyc190YWJsZV9zdGF0c19ITk1fc3ViW2NoYW5nZV9kaXI9PS0xXSwgYWVzKGZhY3RvcihkaWZmX2FnZSksIC1QZXJjZW50YWdlKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGw9ImZpcmVicmljayIpICsKICBmYWNldF9ncmlkKCBNRV9jbHVzdGVyLm5hbWUgfiAuKSArCiAgeWxpbShjKC0zMCwgNzUpKSArCiAgeWxhYigiUGVyY2VudGFnZSIpICsKICB4bGFiKCIiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwKSkKRmlnNS5CCgpgYGAKCgoKYGBge3IsICBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9M30KCgoKTUVfZGlmZl9hZ2UgPC0gRGVsdGFfRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsJGRpZmZfYWdlCm5hbWVzKE1FX2RpZmZfYWdlKSA8LSBEZWx0YV9GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRAoKCmRpZmZfTUVfc2luZyA8LSBEZWx0YV9GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkY2hhbmdlX2RpcgpuYW1lcyhkaWZmX01FX3NpbmcpIDwtIERlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRleG9uX0lECgpNRV9jbHVzdGVyc190YWJsZVssIGRpZmZfYWdlOj1OQV0KTUVfY2x1c3RlcnNfdGFibGVbLCBjaGFuZ2VfZGlyOj1OQV0KTUVfY2x1c3RlcnNfdGFibGVbLCBkaWZmX2FnZTo9TUVfZGlmZl9hZ2VbTUVdIF0KTUVfY2x1c3RlcnNfdGFibGVbLCBjaGFuZ2VfZGlyOj1kaWZmX01FX3NpbmdbTUVdIF0KCk1FX2NsdXN0ZXJzX3RhYmxlWyFpcy5uYShkaWZmX2FnZSldCgoKCgojTUVfY2x1c3RlcnNfdGFibGVbICwgVG90YWw6PS5OLCBieT0gTUVfY2x1c3RlcnNdCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0cyA8LSAgTUVfY2x1c3RlcnNfdGFibGVbLCAuTiAsIGJ5PWMoIk1FX2NsdXN0ZXJzIiwgImRpZmZfYWdlIiwgImNoYW5nZV9kaXIiLCAiVG90YWwiKV0KCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzWywgUGVyY2VudGFnZTo9TioxMDAvVG90YWxdCgoKIE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzWyAsIHN1bShOKSwgYnk9YyggImNoYW5nZV9kaXIiICkgXSAjIFRvdGFsCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0cyA8LSBtZXJnZShNRV9jbHVzdGVyc190YWJsZV9zdGF0cywgTUVfY2x1c3Rlcl9uYW1lc1ssIGMoIk1FX2NsdXN0ZXIiLCAiTUVfY2x1c3Rlci5uYW1lIiwgIk1FX2NsdXN0ZXIudHlwZSIpXSwgYnkueD0iTUVfY2x1c3RlcnMiLCBieS55PSJNRV9jbHVzdGVyIikgCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0YgPC0gTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNbZGlmZl9hZ2UhPSJOQSIgJiBjaGFuZ2VfZGlyIT0iTkEiXQoKCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0Zfc3ViIDwtIE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0ZbTUVfY2x1c3Rlci5uYW1lICVpbiUgIE1FX2NsdXN0ZXJfbmFtZXNbTUVfY2x1c3Rlci50eXBlICVpbiUgYygiTmV1cm9uYWwiLCAiTmV1cm8tTXVzY3VsYXIiLCAiTXVzY3VsYXIiLCAiTm9uLU5ldXJvbmFsIiksIE1FX2NsdXN0ZXIubmFtZV0sIF0KTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfRl9zdWIkTUVfY2x1c3Rlci5uYW1lIDwtIGZhY3RvcihNRV9jbHVzdGVyc190YWJsZV9zdGF0c19GX3N1YiRNRV9jbHVzdGVyLm5hbWUsIGxldmVscyA9IHNvcnQodW5pcXVlKGFzLmNoYXJhY3RlcihNRV9jbHVzdGVyc190YWJsZV9zdGF0c19GX3N1YiRNRV9jbHVzdGVyLm5hbWUpKSkpCgoKCgpGaWc1LkMgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGE9TUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfRl9zdWJbY2hhbmdlX2Rpcj09MV0sIGFlcyhmYWN0b3IoZGlmZl9hZ2UpLCBQZXJjZW50YWdlKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGw9InNreWJsdWUiKSArCiAgZ2VvbV9iYXIoZGF0YT1NRV9jbHVzdGVyc190YWJsZV9zdGF0c19GX3N1YltjaGFuZ2VfZGlyPT0tMV0sIGFlcyhmYWN0b3IoZGlmZl9hZ2UpLCAtUGVyY2VudGFnZSksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJmaXJlYnJpY2siKSArCiAgZmFjZXRfZ3JpZCggTUVfY2x1c3Rlci5uYW1lIH4gLikgKwogIHlsaW0oYygtMzAsIDc1KSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSkKCkZpZzUuQwoKYGBgCgoKCgoKCmBgYHtyfQoKRGVsdGFfU0tNX3doaXBwZXQgPC0gZnJlYWQoIi9Vc2Vycy9ncDcvR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9XaGlwcGV0L2NvbnRyb2xfdnNfc2tlbGV0YWxfbXVzY2xlX3Rpc3N1ZS5kaWZmLm1pY3JvZXhvbnMiKQpEZWx0YV9TS01fTUUgPC0gZnJlYWQoIi9Vc2Vycy9ncDcvR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9XaGlwcGV0L2NvbnRyb2xfdnNfc2tlbGV0YWxfbXVzY2xlX3Rpc3N1ZS5kaWZmLk1FLm1pY3JvZXhvbnMiKQpEZWx0YV9TS01fd2hpcHBldF9NRSA8LSBtZXJnZShEZWx0YV9TS01fd2hpcHBldCwgRGVsdGFfU0tNX01FLCBieT1jKCJleG9uX0lEIiwgIkdlbmUiLCAiTm9kZSIsICAiQ29vcmQiLCAiU3RyYW5kIiwgIlR5cGUiKSAgKQpEZWx0YV9TS01fd2hpcHBldF9NRVssIGRpZmZfaGlnaDo9RkFMU0VdCkRlbHRhX1NLTV93aGlwcGV0X01FWyAoYWJzKERlbHRhUHNpLngpPj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChhYnMoRGVsdGFQc2kueSk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSkgLCBkaWZmX2hpZ2g6PVRSVUVdCkRlbHRhX1NLTV93aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSAsIGNoYW5nZV9kaXI6PXNpZ24oRGVsdGFQc2kueCkgXQpEZWx0YV9TS01fd2hpcHBldF9NRVssIFRpc3N1ZTo9IlNLTSJdCgpEZWx0YV9IZWFydF93aGlwcGV0IDwtIGZyZWFkKCIvVXNlcnMvZ3A3L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL1BhcGVyL0ZpbmFsX1JlcG9ydC9SZXBzL1JlcDEvV2hpcHBldC9jb250cm9sX3ZzX2hlYXJ0LmRpZmYubWljcm9leG9ucyIpCkRlbHRhX0hlYXJ0X01FIDwtIGZyZWFkKCIvVXNlcnMvZ3A3L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL1BhcGVyL0ZpbmFsX1JlcG9ydC9SZXBzL1JlcDEvV2hpcHBldC9jb250cm9sX3ZzX2hlYXJ0LmRpZmYuTUUubWljcm9leG9ucyIpCkRlbHRhX0hlYXJ0X3doaXBwZXRfTUUgPC0gbWVyZ2UoRGVsdGFfSGVhcnRfd2hpcHBldCwgRGVsdGFfSGVhcnRfTUUsIGJ5PWMoImV4b25fSUQiLCAiR2VuZSIsICJOb2RlIiwgICJDb29yZCIsICJTdHJhbmQiLCAiVHlwZSIpICApCkRlbHRhX0hlYXJ0X3doaXBwZXRfTUVbLCBkaWZmX2hpZ2g6PUZBTFNFXQpEZWx0YV9IZWFydF93aGlwcGV0X01FWyAoYWJzKERlbHRhUHNpLngpPj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChhYnMoRGVsdGFQc2kueSk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSkgLCBkaWZmX2hpZ2g6PVRSVUVdCkRlbHRhX0hlYXJ0X3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFICwgY2hhbmdlX2Rpcjo9c2lnbihEZWx0YVBzaS54KSBdCkRlbHRhX0hlYXJ0X3doaXBwZXRfTUVbLCBUaXNzdWU6PSJIZWFydCJdCgoKCkRlbHRhX0FHX3doaXBwZXQgPC0gZnJlYWQoIi9Vc2Vycy9ncDcvR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9XaGlwcGV0L2NvbnRyb2xfdnNfYWRyZW5hbF9nbGFuZC5kaWZmLm1pY3JvZXhvbnMiKQpEZWx0YV9BR19NRSA8LSBmcmVhZCgiL1VzZXJzL2dwNy9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9QYXBlci9GaW5hbF9SZXBvcnQvUmVwcy9SZXAxL1doaXBwZXQvY29udHJvbF92c19hZHJlbmFsX2dsYW5kLmRpZmYuTUUubWljcm9leG9ucyIpCkRlbHRhX0FHX3doaXBwZXRfTUUgPC0gbWVyZ2UoRGVsdGFfQUdfd2hpcHBldCwgRGVsdGFfQUdfTUUsIGJ5PWMoImV4b25fSUQiLCAiR2VuZSIsICJOb2RlIiwgICJDb29yZCIsICJTdHJhbmQiLCAiVHlwZSIpICApCkRlbHRhX0FHX3doaXBwZXRfTUVbLCBkaWZmX2hpZ2g6PUZBTFNFXQpEZWx0YV9BR193aGlwcGV0X01FWyAoYWJzKERlbHRhUHNpLngpPj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChhYnMoRGVsdGFQc2kueSk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSkgLCBkaWZmX2hpZ2g6PVRSVUVdCkRlbHRhX0FHX3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFICwgY2hhbmdlX2Rpcjo9c2lnbihEZWx0YVBzaS54KV0KRGVsdGFfQUdfd2hpcHBldF9NRVssIFRpc3N1ZTo9IkhlYXJ0Il0KCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD01fQpuZXVyYWxfQUdfUFNJIDwtIG1lcmdlKG1lcmdlKApEZWx0YV9BR193aGlwcGV0X01FW2FicyhEZWx0YVBzaS54KT49MC4xICYgUHJvYmFiaWxpdHkueD4wLjkgJiBhYnMoRGVsdGFQc2kueSk+PTAuMSAmIFByb2JhYmlsaXR5Lnk+MC45LCAuKGV4b25fSUQsIFBTSV9BRz1Qc2lfQi54KSAgXSwKCkRlbHRhX0hOTV9tZXJnZVthYnMoRGVsdGFQc2kueCk+PTAuMSAmIFByb2JhYmlsaXR5Lng+MC45ICYgYWJzKERlbHRhUHNpLnkpPj0wLjEgJiBQcm9iYWJpbGl0eS55PjAuOSwgIC4oZXhvbl9JRCwgYWdlLCBQU0lfSE5NPVBzaV9CLngpXSwKYnk9ImV4b25fSUQiKSwKCkRlbHRhX0ZfbWVyZ2VbYWJzKERlbHRhUHNpLngpPj0wLjEgJiBQcm9iYWJpbGl0eS54PjAuOSAmIGFicyhEZWx0YVBzaS55KT49MC4xICYgUHJvYmFiaWxpdHkueT4wLjksICAuKGV4b25fSUQsIGFnZSwgUFNJX0Y9UHNpX0IueCldLApieT1jKCJleG9uX0lEIiwgImFnZSIpICkKCnRhYmxlKG5ldXJhbF9BR19QU0kkYWdlKSAjIE92ZXIgMTQuNSB0aGVyZSBpcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgaW50ZXJzZWN0aW9ucwoKCm5ldXJhbF9BR19QU0lfbWVsdGVkIDwtIG1lbHQobmV1cmFsX0FHX1BTSVthZ2U9PTE0LjUsIGMoImV4b25fSUQiLCAiUFNJX0FHIiwgIlBTSV9ITk0iLCAiUFNJX0YiKV0pCgoKClN1cC5BR19NSE5GLkEgPC0gZ2dwbG90KG5ldXJhbF9BR19QU0lfbWVsdGVkLCBhZXModmFyaWFibGUsIHZhbHVlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcigpICsKICAjZ2VvbV9saW5lKGFlcyhncm91cD1leG9uX0lEKSkgKwogIHhsYWIoIlRpc3N1ZSIpICsKICB5bGFiKCJQU0kiKSArCiAgZ2dzaWduaWY6Omdlb21fc2lnbmlmKHRlc3QgPSAid2lsY294LnRlc3QiLCBjb21wYXJpc29ucyA9IGxpc3QoYygiUFNJX0FHIiwgIlBTSV9ITk0iKSwgYygiUFNJX0FHIiwgIlBTSV9GIikpCiwgc3RlcF9pbmNyZWFzZT0wLjE1ICwgdGVzdC5hcmdzID0gbGlzdChhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBwYWlyZWQgPSBUUlVFKSwgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoJ0FkcmVuYWwgR2xhbmQnLCdCcmFpbiBNSE4nLCdGb3JlYnJhaW4nKSkKCgoKU3VwLkFHX01ITkYuQiA8LSBnZ3Bsb3QobmV1cmFsX0FHX1BTSV9tZWx0ZWQsIGFlcyh2YXJpYWJsZSwgdmFsdWUpKSArCiAgI2dlb21fYm94cGxvdCgpICsKICAjZ2VvbV9qaXR0ZXIoKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cD1leG9uX0lEKSkgKwogIHhsYWIoIlRpc3N1ZSIpICsKICB5bGFiKCJQU0kiKSArCiAgZ2dzaWduaWY6Omdlb21fc2lnbmlmKHRlc3QgPSAid2lsY294LnRlc3QiLCBjb21wYXJpc29ucyA9IGxpc3QoYygiUFNJX0FHIiwgIlBTSV9ITk0iKSwgYygiUFNJX0FHIiwgIlBTSV9GIikpCiwgc3RlcF9pbmNyZWFzZT0wLjE1ICwgdGVzdC5hcmdzID0gbGlzdChhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBwYWlyZWQgPSBUUlVFKSwgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoJ0FkcmVuYWwgR2xhbmQnLCdCcmFpbiBNSE4nLCdGb3JlYnJhaW4nKSkKCgpwbG90X2dyaWQoU3VwLkFHX01ITkYuQSwgU3VwLkFHX01ITkYuQiwgbmNvbD0xLCBsYWJlbHM9IkFVVE8iKQoKYGBgCgoKCgpgYGB7ciwgIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0zfQoKCgpNRV9jbHVzdGVyc190YWJsZVsgLCBEaWZmX1NLTTo9IkZBTFNFIl0KTUVfY2x1c3RlcnNfdGFibGVbTUUgJWluJSBEZWx0YV9TS01fd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUgJiBjaGFuZ2VfZGlyPT0xLCBleG9uX0lEXSwgRGlmZl9TS006PSJFeGNsdWRlZCIgXQpNRV9jbHVzdGVyc190YWJsZVtNRSAlaW4lIERlbHRhX1NLTV93aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSAmIGNoYW5nZV9kaXI9PS0xLCBleG9uX0lEXSwgRGlmZl9TS006PSJJbmNsdWRlZCJdCgpNRV9jbHVzdGVyc190YWJsZVsgLCBEaWZmX0hlYXJ0Oj0iRkFMU0UiXQpNRV9jbHVzdGVyc190YWJsZVtNRSAlaW4lIERlbHRhX0hlYXJ0X3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFICYgY2hhbmdlX2Rpcj09MSwgZXhvbl9JRF0sIERpZmZfSGVhcnQ6PSJFeGNsdWRlZCIgXQpNRV9jbHVzdGVyc190YWJsZVtNRSAlaW4lIERlbHRhX0hlYXJ0X3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFICYgY2hhbmdlX2Rpcj09LTEsIGV4b25fSURdLCBEaWZmX0hlYXJ0Oj0iSW5jbHVkZWQiXQoKTUVfY2x1c3RlcnNfdGFibGVbICwgRGlmZl9BRzo9IkZBTFNFIl0KTUVfY2x1c3RlcnNfdGFibGVbTUUgJWluJSBEZWx0YV9BR193aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSAmIGNoYW5nZV9kaXI9PTEsIGV4b25fSURdLCBEaWZmX0FHOj0iRXhjbHVkZWQiIF0KTUVfY2x1c3RlcnNfdGFibGVbTUUgJWluJSBEZWx0YV9BR193aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSAmIGNoYW5nZV9kaXI9PS0xLCBleG9uX0lEXSwgRGlmZl9BRzo9IkluY2x1ZGVkIl0KCgoKCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19TS00gPC0gTUVfY2x1c3RlcnNfdGFibGVbIERpZmZfU0tNIT0iRkFMU0UiLCAuTiwgYnk9YygiTUVfY2x1c3RlcnMiLCAiVG90YWwiLCAiRGlmZl9TS00iKSBdCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NLTVssIFBlcmNlbnRhZ2U6PShOKjEwMC9Ub3RhbCldCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NLTVssIFRpc3N1ZTo9IlNLTSJdCmNvbG5hbWVzKE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NLTSkgPC0gYygiTUVfY2x1c3RlcnMiLCAiVG90YWwiLCAiRGlmZiIsICJOIiwgIlBlcmNlbnRhZ2UiLCAiVGlzc3VlIiApCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19IZWFydCA8LSBNRV9jbHVzdGVyc190YWJsZVsgRGlmZl9IZWFydCE9IkZBTFNFIiwgLk4sIGJ5PWMoIk1FX2NsdXN0ZXJzIiwgIlRvdGFsIiwgIkRpZmZfSGVhcnQiKSBdCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0hlYXJ0WywgUGVyY2VudGFnZTo9KE4qMTAwL1RvdGFsKV0KTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfSGVhcnRbLCBUaXNzdWU6PSJIUlQiXQpjb2xuYW1lcyhNRV9jbHVzdGVyc190YWJsZV9zdGF0c19IZWFydCkgPC0gYygiTUVfY2x1c3RlcnMiLCAiVG90YWwiLCAiRGlmZiIsICJOIiwgIlBlcmNlbnRhZ2UiLCAiVGlzc3VlIiApCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19BRyA8LSBNRV9jbHVzdGVyc190YWJsZVsgRGlmZl9BRyE9IkZBTFNFIiwgLk4sIGJ5PWMoIk1FX2NsdXN0ZXJzIiwgIlRvdGFsIiwgIkRpZmZfQUciKSBdCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0FHWywgUGVyY2VudGFnZTo9KE4qMTAwL1RvdGFsKV0KTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfQUdbLCBUaXNzdWU6PSJBRCJdCmNvbG5hbWVzKE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX0FHKSA8LSBjKCJNRV9jbHVzdGVycyIsICJUb3RhbCIsICJEaWZmIiwgIk4iLCAiUGVyY2VudGFnZSIsICJUaXNzdWUiICkKCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19TSEEgPC0gcmJpbmQoTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfU0tNLCBNRV9jbHVzdGVyc190YWJsZV9zdGF0c19IZWFydCwgTUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfQUcpCgoKCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NIQSA8LSBtZXJnZShNRV9jbHVzdGVyc190YWJsZV9zdGF0c19TSEEsIE1FX2NsdXN0ZXJfbmFtZXNbLCBjKCJNRV9jbHVzdGVyIiwgIk1FX2NsdXN0ZXIubmFtZSIsICJNRV9jbHVzdGVyLnR5cGUiKV0sIGJ5Lng9Ik1FX2NsdXN0ZXJzIiwgYnkueT0iTUVfY2x1c3RlciIpCgpNRV9jbHVzdGVyc190YWJsZV9zdGF0c19TSEFfc3ViIDwtIE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NIQVtNRV9jbHVzdGVyLm5hbWUgJWluJSAgTUVfY2x1c3Rlcl9uYW1lc1tNRV9jbHVzdGVyLnR5cGUgJWluJSBjKCJOZXVyb25hbCIsICJOZXVyby1NdXNjdWxhciIsICJNdXNjdWxhciIsICJOb24tTmV1cm9uYWwiKSwgTUVfY2x1c3Rlci5uYW1lXSwgXQoKCk1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NIQV9zdWIkTUVfY2x1c3Rlci5uYW1lIDwtIGZhY3RvcihNRV9jbHVzdGVyc190YWJsZV9zdGF0c19TSEFfc3ViJE1FX2NsdXN0ZXIubmFtZSwgbGV2ZWxzID0gc29ydCh1bmlxdWUoYXMuY2hhcmFjdGVyKE1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NIQV9zdWIkTUVfY2x1c3Rlci5uYW1lKSkpKQoKCgoKRmlnNS5EIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhPU1FX2NsdXN0ZXJzX3RhYmxlX3N0YXRzX1NIQV9zdWJbRGlmZj09IkluY2x1ZGVkIl0sIGFlcyhmYWN0b3IoVGlzc3VlKSwgUGVyY2VudGFnZSksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJza3libHVlIikgKwogIGdlb21fYmFyKGRhdGE9TUVfY2x1c3RlcnNfdGFibGVfc3RhdHNfU0hBX3N1YltEaWZmPT0iRXhjbHVkZWQiXSwgYWVzKGZhY3RvcihUaXNzdWUpLCAtUGVyY2VudGFnZSksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJmaXJlYnJpY2siKSArCiAgZmFjZXRfZ3JpZCggTUVfY2x1c3Rlci5uYW1lIH4gLikgKwogIHlsaW0oYygtMzAsIDc1KSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSkKRmlnNS5ECgpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0gMTAsIGZpZy53aWR0aD0xNX0KbGlicmFyeShVcFNldFIpCgpyZXF1aXJlKFVwU2V0UikKCmxpc3RJbnB1dCA8LSBsaXN0KG9uZSA9IGMoMSwgMiwgMywgNSwgNywgOCwgMTEsIDEyLCAxMyksIHR3byA9IGMoMSwgMiwgNCwgNSwgCiAgICAxMCksIHRocmVlID0gYygxLCA1LCA2LCA3LCA4LCA5LCAxMCwgMTIsIDEzKSkKCgoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbLCAgZXhvbl9JRF0KCkRlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFssIGV4b25fSUQgXQoKCnRpc3N1ZV9pbnRlcnNlY3Rpb24gPC0gbGlzdChCcmFpbiA9IE1FX2NsdXN0ZXJzX3RhYmxlW2RpZmZfYWdlIT0iTkEiLCBNRV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTS00gPSBNRV9jbHVzdGVyc190YWJsZVtEaWZmX1NLTSE9RkFMU0UsIE1FXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhlYXJ0ID0gTUVfY2x1c3RlcnNfdGFibGVbRGlmZl9IZWFydCE9RkFMU0UsIE1FXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFHID0gTUVfY2x1c3RlcnNfdGFibGVbRGlmZl9BRyE9RkFMU0UsIE1FXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKCnRpc3N1ZV9pbnRlcnNlY3Rpb24gPC0gbGlzdChCcmFpbl9ITk0gPSBEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFssICBleG9uX0lEXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJyYWluX0YgPSBEZWx0YV9GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbLCAgZXhvbl9JRF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTS00gPSBNRV9jbHVzdGVyc190YWJsZVtEaWZmX1NLTSE9RkFMU0UsIE1FXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhlYXJ0ID0gTUVfY2x1c3RlcnNfdGFibGVbRGlmZl9IZWFydCE9RkFMU0UsIE1FXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFHID0gTUVfY2x1c3RlcnNfdGFibGVbRGlmZl9BRyE9RkFMU0UsIE1FXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKCgpGaWc1LnkgPC0gdXBzZXQoZnJvbUxpc3QodGlzc3VlX2ludGVyc2VjdGlvbiksIG9yZGVyLmJ5ID0gImZyZXEiLCBuc2V0cyA9IDUsIGtlZXAub3JkZXIgPSBUKQpGaWc1LnkKYGBgCgoKCgoKYGBge3J9CmdnX2NvbG9yX2h1ZSA8LSBmdW5jdGlvbihuKSB7CiAgaHVlcyA9IHNlcSgxNSwgMzc1LCBsZW5ndGggPSBuICsgMSkKICBoY2woaCA9IGh1ZXMsIGwgPSA2NSwgYyA9IDEwMClbMTpuXQp9CgoKYGBgCgoKYGBge3J9CgoKbGlicmFyeShldWxlcnIpCgoKCnRpc3N1ZV9pbnRlcnNlY3Rpb24gPC0gbGlzdChCcmFpbiA9IE1FX2NsdXN0ZXJzX3RhYmxlW2RpZmZfYWdlIT0iTkEiLCBNRV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTS00gPSBNRV9jbHVzdGVyc190YWJsZVtEaWZmX1NLTSE9RkFMU0UsIE1FXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhlYXJ0ID0gTUVfY2x1c3RlcnNfdGFibGVbRGlmZl9IZWFydCE9RkFMU0UsIE1FXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFHID0gTUVfY2x1c3RlcnNfdGFibGVbRGlmZl9BRyE9RkFMU0UsIE1FXSkKCgp0aXNzdWVfaW50ZXJzZWN0aW9uLnZlbm4gPC0gZXVsZXIoYygiQnJhaW4iID0gMjEyLCAgCiAgICAgICAgICAgICAgICAgICAgIlNLTSIgPSAzNSwgIAogICAgICAgICAgICAgICAgICAgICJIZWFydCIgPSAxMSwgCiAgICAgICAgICAgICAgICAgICAgIkFHIiA9IDExLAogICAgICAgICAgICAgICAgICAgICJCcmFpbiZBRyIgPSAyOSwKICAgICAgICAgICAgICAgICAgICAiU0tNJkhlYXJ0IiA9IDIxLAogICAgICAgICAgICAgICAgICAgICJCcmFpbiZIZWFydCIgPSAxOCwKICAgICAgICAgICAgICAgICAgICAiQnJhaW4mU0tNJkhlYXJ0IiA9IDE4LAogICAgICAgICAgICAgICAgICAgICJCcmFpbiZTS00iID0gMTQsCiAgICAgICAgICAgICAgICAgICAgIkJyYWluJlNLTSZIZWFydCZBRyIgPSAzLAogICAgICAgICAgICAgICAgICAgICJCcmFpbiZIZWFydCZBRyIgPSAyLAogICAgICAgICAgICAgICAgICAgICJIZWFydCZBRyIgPSAxLAogICAgICAgICAgICAgICAgICAgICJTS00mQUciID0gMSwKICAgICAgICAgICAgICAgICAgICAiQnJhaW4mU0tNJkFHIiA9IDEpKQoKCgoKdGlzc3VlX2ludGVyc2VjdGlvbi52ZW5uIDwtIGV1bGVyKGMoIkJyYWluX0hOTSZCcmFpbl9GIiA9IDE1NiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0hOTSIgPSA3MSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNLTSIgPSAzNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0hOTSZCcmFpbl9GJkFHIiA9IDI5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0tNJkhlYXJ0IiA9IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJhaW5fSE5NJkJyYWluX0YmSGVhcnQiID0gMTksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCcmFpbl9GIiA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJhaW5fSE5NJkJyYWluX0YmU0tNJkhlYXJ0IiA9IDE0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJhaW5fSE5NJkJyYWluX0YmU0tNIiA9IDEzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGVhcnQiID0gMTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBRyIgPSAxMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0hOTSZTS00iID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0hOTSZCcmFpbl9GJlNLTSZIZWFydCZBRyIgPSA1LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCcmFpbl9ITk0mU0tNJkhlYXJ0IiA9IDQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCcmFpbl9ITk0mSGVhcnQiID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0YmQUciID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0hOTSZIZWFydCZBRyIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGVhcnQmQUciID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNLTSZBRyIgPSAxICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0YmU0tNIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCcmFpbl9GJlNLTSZIZWFydCIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJhaW5fSE5NJlNLTSZBRyIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnJhaW5fSE5NJkJyYWluX0YmSGVhcnQmQUciID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJyYWluX0hOTSZCcmFpbl9GJlNLTSZBRyIgPSAxKSkKCiAgICAgICAgICAgICAgICAgICAgCiAgICAKdmVuIDwtIHBsb3QodGlzc3VlX2ludGVyc2VjdGlvbi52ZW5uLCBjb3VudHMgPSBGQUxTRSwgZm9udD00LCBjZXg9MSwgYWxwaGE9MC41LAogICAgIGZpbGw9Z2dfY29sb3JfaHVlKDUpLCBxdWFudGl0aWVzID0gbGlzdChmb250c2l6ZSA9IDApKQoKdmVuCgpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTE2fQoKCmxpYnJhcnkoZ2dwbG90aWZ5KQoKCgpGaWc1LmNvbDIucm93MSA8LSBwbG90X2dyaWQoRmlnNS5CLCBGaWc1LkMsIEZpZzUuRCwgbnJvdz0xLCAgbGFiZWxzID0gYygiRiIsICJHIiwgIkgiKSwgcmVsX3dpZHRocyA9IGMoMiwgMS41LCAxLjUpICkKCkZpZzUuY29sMiA8LSBwbG90X2dyaWQoRmlnNS5jb2wyLnJvdzEsIGFzLmdyb2IoRmlnNS55KSwgbmNvbCA9IDEsICAgbGFiZWxzID0gYygiIiwgIkkiKSwgcmVsX2hlaWdodHMgPSBjKDMsIDEpICkKCkZpZzUuYm90dG9tIDwtIHBsb3RfZ3JpZChGaWc1LkEsIEZpZzUuY29sMiwgbnJvdz0xLCAgcmVsX3dpZHRocyA9IGMoMSwgMSksIGxhYmVscyA9IGMoIkUiLCAiIikpCgoKI0ZpZzUgPC0gcGxvdF9ncmlkKEZpZzUuY29sMSwgRmlnNS5CLCBGaWc1LkMsIEZpZzUuRCwgbnJvdz0xLCByZWxfd2lkdGhzID0gYygxMCwgMiwgMS41LCAxLjUgKSwgbGFiZWxzID0gYygiIiwgIkYiLCAiRyIsICJIIikgKQpGaWc1IDwtIHBsb3RfZ3JpZChGaWc1LlgsIEZpZzUuYm90dG9tLCBuY29sPTEsIHJlbF9oZWlnaHRzID0gYygxLCA0KSApCkZpZzUgCmBgYAoKCgoKI0Vycm9yCgoKCmBgYHtyfQoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZbZGlmZl9hZ2UhPSJJbmYiLCBdJGV4b25fSUQKCkRlbHRhX0hOTV93aGlwcGV0X01FJGRlbHRhX3NpbmcgPC0gc2lnbihEZWx0YV9ITk1fd2hpcHBldF9NRSREZWx0YVBzaS54KQoKRGVsdGFfSE5NX3doaXBwZXRfTUVfZGlmZl9jb3VudCA8LSBEZWx0YV9ITk1fd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUgLCAuTiAsIGJ5PWMoImV4b25fSUQiLCAiZGVsdGFfc2luZyIpXQoKCgpEZWx0YV9ITk1fd2hpcHBldF9NRV9kaWZmX2NvdW50WyBOPT0yICYgIWV4b25fSUQgJWluJSBEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZltkaWZmX2FnZSE9IkluZiIsIF0kZXhvbl9JRCwgXQoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfbG93W2RpZmZfYWdlIT1JbmZdCmBgYAoKCgpgYGB7cn0KCmxpYnJhcnkoYmlvbWFSdCkKCgoKCgpNaWNyb0V4b25fZ2VuZXMgPC0gZ3N1YigiXFwuLioiLCIiLCBEZWx0YV9ITk1fd2hpcHBldF9NRSRHZW5lKSAKbmFtZXMoTWljcm9FeG9uX2dlbmVzKSA8LSBEZWx0YV9ITk1fd2hpcHBldF9NRSRleG9uX0lECiAKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbLCBlbnNlbWJsX2dlbmVfaWQ6PU1pY3JvRXhvbl9nZW5lc1tleG9uX0lEXV0KCmVuc2VtYmwgPSB1c2VFbnNlbWJsKGJpb21hcnQ9ImVuc2VtYmwiLCBkYXRhc2V0PSJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIikKCgoKCgpnZW5lX3RhYmxlIDwtIGRhdGEudGFibGUoZ2V0Qk0oYXR0cmlidXRlcz1jKCdlbnNlbWJsX2dlbmVfaWQnLCAibWdpX3N5bWJvbCIpLGZpbHRlcnMgPSAnZW5zZW1ibF9nZW5lX2lkJywgdmFsdWVzID0gRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZW5zZW1ibF9nZW5lX2lkICwgbWFydCA9IGVuc2VtYmwpKQoKCmdlbmVfdGFibGUgPC0gZGF0YS50YWJsZShnZXRCTShhdHRyaWJ1dGVzPWMoJ2Vuc2VtYmxfZ2VuZV9pZCcsICJtZ2lfc3ltYm9sIiksZmlsdGVycyA9ICdlbnNlbWJsX2dlbmVfaWQnLCB2YWx1ZXMgPSBEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRlbnNlbWJsX2dlbmVfaWQgLCBtYXJ0ID0gZW5zZW1ibCkpCgoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwgPC0gbWVyZ2UoIERlbHRhX0hOTV93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsLCBnZW5lX3RhYmxlLCBieT0nZW5zZW1ibF9nZW5lX2lkJykKCgoKY2F0KGFzLmNoYXJhY3Rlcih1bmlxdWUoRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkbWdpX3N5bWJvbCkpLCBzZXA9J1xuJykgCgoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbbWdpX3N5bWJvbD09IkRjdG4yIl0KYGBgCgoKIyBJbnB1dCBmb3IgUFBJIG5ldHdvcmsKCgoKYGBge3J9CmdlbmVzX2JhY2tncm91bmQgPC0gdW5pcXVlKGMoRGVsdGFfSE5NX21lcmdlJEdlbmUueCwgRGVsdGFfRl9tZXJnZSRHZW5lLngpKQoKZ2VuZXNfYmFja2dyb3VuZCA8LSAgZ3N1YigiXFwuLioiLCIiLCBnZW5lc19iYWNrZ3JvdW5kKQoKCm5ldXJvbmFsX01FX2dlbmVzIDwtIHVuaXF1ZShjKERlbHRhX0hOTV93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsJEdlbmUsIERlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRHZW5lKSkKbmV1cm9uYWxfTUVfZ2VuZXMgPC0gZ3N1YigiXFwuLioiLCIiLCBuZXVyb25hbF9NRV9nZW5lcykKCm5ldXJvbmFsX01FX2dlbmVfbmFtZXMgPC0gIGdlbmVfdGFibGVbZW5zZW1ibF9nZW5lX2lkICVpbiUgbmV1cm9uYWxfTUVfZ2VuZXMsIF0KCmNhdChhcy5jaGFyYWN0ZXIodW5pcXVlKG5ldXJvbmFsX01FX2dlbmVfbmFtZXMkbWdpX3N5bWJvbCkpLCBzZXA9J1xuJykgCgoKZndyaXRlKGRhdGEudGFibGUoZ2VuZXNfYmFja2dyb3VuZCksICIuLi9QUEkvZ2VuZXNfYmFja2dyb3VuZC50eHQiLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKYGBgCgoKCgoKCmBgYHtyfQoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgZW5zZW1ibF9nZW5lX2lkOj1nc3ViKCJcXC4uKiIsIiIsIEdlbmUpIF0KRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgZW5zZW1ibF9nZW5lX2lkOj1nc3ViKCJcXC4uKiIsIiIsIEdlbmUpIF0KCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwgPC0gbWVyZ2UoRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwsIERlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCwgYnk9YygiZXhvbl9JRCIsICJHZW5lIiwgImNoYW5nZV9kaXIiKSwgYWxsPVRSVUUpCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFssIGRpZmZfYWdlOj1taW4oZGlmZl9hZ2UueSwgZGlmZl9hZ2UueCwgbmEucm09VFJVRSksIGJ5PWV4b25fSURdCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgZW5zZW1ibF9nZW5lX2lkOj1nc3ViKCJcXC4uKiIsIiIsIEdlbmUpIF0KCgoKCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwgPC0gbWVyZ2UoRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsLCBuZXVyb25hbF9NRV9nZW5lX25hbWVzLCBieT0iZW5zZW1ibF9nZW5lX2lkIikKCgoKCiNtZXJnZSggRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsLCBQUElfY2VudHJhbGl0eSwgYnk9Im1naV9zeW1ib2wiKQoKCgojRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWyFtZ2lfc3ltYm9sICVpbiUgUFBJX2NlbnRyYWxpdHkkbWdpX3N5bWJvbF0KCgpmd3JpdGUoZGF0YS50YWJsZShkYXRhLnRhYmxlKHVuaXF1ZShEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZW5zZW1ibF9nZW5lX2lkKSkpLCAiLi4vRmluYWxfRmlndXJlcy9GaWd1cmU1L21pY3JvZXhvbnNfSE1ORl9nZW5lcy50eHQiLCBxdW90ZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSkKCmBgYAoKCmBgYHtyfQoKRGVsdGFfSGVhcnRfd2hpcHBldF9NRVsgLCBlbnNlbWJsX2dlbmVfaWQ6PWdzdWIoIlxcLi4qIiwiIiwgR2VuZSkgXQpEZWx0YV9TS01fd2hpcHBldF9NRVsgLCBlbnNlbWJsX2dlbmVfaWQ6PWdzdWIoIlxcLi4qIiwiIiwgR2VuZSkgXQpEZWx0YV9BR193aGlwcGV0X01FWyAsIGVuc2VtYmxfZ2VuZV9pZDo9Z3N1YigiXFwuLioiLCIiLCBHZW5lKSBdCgoKRGVsdGFfSGVhcnRfd2hpcHBldF9NRSA8LSBtZXJnZShEZWx0YV9IZWFydF93aGlwcGV0X01FLCBuZXVyb25hbF9NRV9nZW5lX25hbWVzLCBieT0iZW5zZW1ibF9nZW5lX2lkIikKRGVsdGFfU0tNX3doaXBwZXRfTUUgPC0gbWVyZ2UoRGVsdGFfU0tNX3doaXBwZXRfTUUsIG5ldXJvbmFsX01FX2dlbmVfbmFtZXMsIGJ5PSJlbnNlbWJsX2dlbmVfaWQiKQpEZWx0YV9BR193aGlwcGV0X01FIDwtIG1lcmdlKERlbHRhX0FHX3doaXBwZXRfTUUsIG5ldXJvbmFsX01FX2dlbmVfbmFtZXMsIGJ5PSJlbnNlbWJsX2dlbmVfaWQiKQoKZndyaXRlKGRhdGEudGFibGUoZGF0YS50YWJsZSh1bmlxdWUoRGVsdGFfSGVhcnRfd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUsIGVuc2VtYmxfZ2VuZV9pZF0pKSksICIuLi9GaW5hbF9GaWd1cmVzL0ZpZ3VyZTUvaGVhcnRfZ2VuZXMudHh0IiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UpCmZ3cml0ZShkYXRhLnRhYmxlKGRhdGEudGFibGUodW5pcXVlKERlbHRhX1NLTV93aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSwgZW5zZW1ibF9nZW5lX2lkXSkpKSwgIi4uL0ZpbmFsX0ZpZ3VyZXMvRmlndXJlNS9TS01fZ2VuZXMudHh0IiwgcXVvdGUgPSBGQUxTRSwgY29sLm5hbWVzID0gRkFMU0UpCmZ3cml0ZShkYXRhLnRhYmxlKGRhdGEudGFibGUodW5pcXVlKERlbHRhX0FHX3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFLCBlbnNlbWJsX2dlbmVfaWRdKSkpLCAiLi4vRmluYWxfRmlndXJlcy9GaWd1cmU1L0FHX2dlbmVzLnR4dCIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFKQoKCkRlbHRhX0hlYXJ0X3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFLCBlbnNlbWJsX2dlbmVfaWRdCkRlbHRhX1NLTV93aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSwgZW5zZW1ibF9nZW5lX2lkXQpEZWx0YV9BR193aGlwcGV0X01FW2RpZmZfaGlnaD09VFJVRSwgZW5zZW1ibF9nZW5lX2lkXQpgYGAKCgoKYGBge3J9CgptaWNyb2V4b25zX1Zhc3RkYiA8LSByZWFkX2RlbGltKCJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL21tMTAvVmFzdERCL1Zhc3REYi5taWNyb2V4b25zLnR4dCIsIAogICAgIiAiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIGNvbF9uYW1lcyA9IEZBTFNFLCAKICAgIHRyaW1fd3MgPSBUUlVFKQoKCm1pY3JvZXhvbnNfVmFzdGRiIDwtIG1pY3JvZXhvbnNfVmFzdGRiJFgxCgoKCm1pY3JvZXhvbnNfR0VOQ09ERSA8LSByZWFkX2RlbGltKCJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL21tMTAvZ2VuY29kZS52TTE2LmFubm90YXRpb24ubWljcm9leG9ucy50eHQiLCAKICAgICIgIiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCBjb2xfbmFtZXMgPSBGQUxTRSwgCiAgICB0cmltX3dzID0gVFJVRSkKCgptaWNyb2V4b25zX0dFTkNPREUgPC0gbWljcm9leG9uc19HRU5DT0RFJFgxCmBgYAoKCgpgYGB7cn0KCgoKTUVfZmluYWxbICwgdHlwZTo9IkFubm90YXRlZCIgIF0KTUVfZmluYWxbIU1FICVpbiUgbWljcm9leG9uc19WYXN0ZGIsIHR5cGU6PSJNaXNzaW5nIGluIFZhc3REQiIgICBdCk1FX2ZpbmFsWyFNRSAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSwgdHlwZTo9Ik1pc3NpbmcgaW4gR0VOQ09ERSIgICBdCk1FX2ZpbmFsWyFNRSAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSAmICFNRSAlaW4lIG1pY3JvZXhvbnNfVmFzdGRiICwgdHlwZTo9Ik5vdmVsIiAgIF0KCgpNRV9maW5hbFssIEFsdDVfMzo9Ik5BIl0KCk1FX2ZpbmFsW01FICVpbiUgTUVfY292W0FsdDUhPSJOb25lIiwgTUVfY29vcmRzXSwgQWx0NV8zOj0iQWx0NSIgXQpNRV9maW5hbFtNRSAlaW4lIE1FX2NvdltBbHQzIT0iTm9uZSIsIE1FX2Nvb3Jkc10sIEFsdDVfMzo9IkFsdDMiIF0KCk1FX2ZpbmFsW01FICVpbiUgTUVfY292W0FsdDUhPSJOb25lIiwgTUVfY29vcmRzXSAmIE1FICVpbiUgTUVfY292W0FsdDMhPSJOb25lIiwgTUVfY29vcmRzXSwgQWx0NV8zOj0iQWx0NV8zIiBdCgpsZW5ndGgodW5pcXVlKE1FX2ZpbmFsJE1FKSkKCk1FX2ZpbmFsWyAsIC5OICwgYnk9YygiQWx0NV8zIiwgInR5cGUiKSBdCgpucm93KHVuaXF1ZShNRV9maW5hbC5vdXQpKQoKTUVfZmluYWwub3V0IDwtICBtZXJnZSgKdW5pcXVlKE1FX2ZpbmFsKSwKIE1FX2NsdXN0ZXJzLmluZm9bLCAuKE1FLCBNRV9jbHVzdGVyLnR5cGUsIE1FX2NsdXN0ZXIubmFtZSwgTUVfY2x1c3Rlci5udW1iZXI9TUVfY2x1c3RlciwgUEMxLCBQQzIsIFBDMyApXSwgYWxsLng9VFJVRSkKCgogIE1FX2NsdXN0ZXJzLmluZm9bLCAuKCJNRSIsICJNRV9jbHVzdGVyLnR5cGUiLCAiTUVfY2x1c3Rlci5uYW1lIildCgpNRV9maW5hbC5vdXRbICwgSW4uMTBfcGVyY2VudF9vZl9idWxrOj1NRSAlaW4lIG1lX2FmdGVyXzEwX3NhbXBsZXNfZmlsdGVyIF0gIAogICAKZndyaXRlKCBNRV9maW5hbC5vdXQsICJ+L0Rlc2t0b3AvTUVfZmluYWwudGFibGVfbWFydGluLnR4dCIsIHF1b3RlID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUsIHNlcD0iXHQiLCApCgoKYGBgCgoKYGBge3J9Ck1FX2ZpbmFsLm91dFtJbi4xMF9wZXJjZW50X29mX2J1bGs9PVRSVUUsIC5OLCBieT0idHlwZSJdCmBgYAoKCgpgYGB7cn0KCk1FX2NsdXN0ZXJzLnRhYmxlCgpgYGAKCgoKCmBgYHtyfQoKI25ldXJvbmFsX01FX0hOTUYgIDwtIHVuaXF1ZShyYmluZChEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFssIGMoImV4b25fSUQiLCAiR2VuZSIpXSwgRGVsdGFfRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWywgYygiZXhvbl9JRCIsICJHZW5lIildICkpCm5ldXJvbmFsX01FX0hOTUYgIDwtIHVuaXF1ZShtZXJnZShEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCwgRGVsdGFfRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsLCBieT1jKCJleG9uX0lEIiwgIkdlbmUiKSwgYWxsPVQgKSkKCgoKbmV1cm9uYWxfTUVfSE5NRlsgLCB0eXBlOj0iQW5ub3RhdGVkIiAgXQoKbmV1cm9uYWxfTUVfSE5NRlshZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfVmFzdGRiLCB0eXBlOj0iTWlzc2luZyBpbiBWYXN0REIiICAgXQoKbmV1cm9uYWxfTUVfSE5NRlshZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSwgdHlwZTo9Ik1pc3NpbmcgaW4gR0VOQ09ERSIgICBdCgpuZXVyb25hbF9NRV9ITk1GWyFleG9uX0lEICVpbiUgbWljcm9leG9uc19HRU5DT0RFICYgIWV4b25fSUQgJWluJSBtaWNyb2V4b25zX1Zhc3RkYiAsIHR5cGU6PSJOb3ZlbCIgICBdCgpuZXVyb25hbF9NRV9ITk1GLnRhYmxlIDwtIHVuaXF1ZShtZXJnZSggZ2VuZV90YWJsZS5UT1RBTFssIGMoIk1FIiwgIm1naV9zeW1ib2wiKV0sIG5ldXJvbmFsX01FX0hOTUYgLCBieS54PSJNRSIsIGJ5Lnk9ImV4b25fSUQiKSkKCgpuZXVyb25hbF9NRV9ITk1GLnRhYmxlIDwtIG5ldXJvbmFsX01FX0hOTUYudGFibGVbb3JkZXIobWdpX3N5bWJvbCwgTUUpXQoKZndyaXRlKG5ldXJvbmFsX01FX0hOTUYudGFibGUsICIuLi8uLi8uLi8uLi9UaGVzaXMvbmV1cm9uYWxfTUVfSE5NRi50c3YiLCBzZXA9Ilx0IiApCgoKbmV1cm9uYWxfTUVfSE5NRl9zdGF0cyA8LSBuZXVyb25hbF9NRV9ITk1GWyAsIC5OICwgYnk9InR5cGUiXQoKbmV1cm9uYWxfTUVfSE5NRl9zdGF0c1ssIFRvdGFsOj1zdW0oTildCgpuZXVyb25hbF9NRV9ITk1GX3N0YXRzWywgUGVyY2VudGFnZTo9TioxMDAvVG90YWxdCgpgYGAKCgoKYGBge3J9CgojbGlicmFyeSgiU1RSSU5HZGIiKQoKI3N0cmluZ19kYiA8LSBTVFJJTkdkYiRuZXcoIHZlcnNpb249IjEwIiwgc3BlY2llcz05NjA2LCBzY29yZV90aHJlc2hvbGQ9MCwgaW5wdXRfZGlyZWN0b3J5PSIiICkKCgojbmV1cm9uYWxfTUVfZ2VuZV9uYW1lc19tYXBwZWQgPC0gc3RyaW5nX2RiJG1hcCggbmV1cm9uYWxfTUVfZ2VuZV9uYW1lcywgIm1naV9zeW1ib2wiLCByZW1vdmVVbm1hcHBlZFJvd3MgPSBUUlVFICkKCiMgc3RyaW5nX2RiJHBsb3RfbmV0d29yayggbmV1cm9uYWxfTUVfZ2VuZV9uYW1lc19tYXBwZWQgKQoKCgojaGl0cyA8LSBhcy5jaGFyYWN0ZXIodW5pcXVlKG5ldXJvbmFsX01FX2dlbmVfbmFtZXMkbWdpX3N5bWJvbCkpCgojZXhhbXBsZTFfbWFwcGVkIDwtIHN0cmluZ19kYiRtYXAoIGhpdHMsICJnZW5lIiwgcmVtb3ZlVW5tYXBwZWRSb3dzID0gVFJVRSApCgojcGxvdF9uZXR3b3JrKCBoaXRzICkKCiNkYXRhKGRpZmZfZXhwX2V4YW1wbGUxKQoKCiNleGFtcGxlMV9tYXBwZWQgPC0gc3RyaW5nX2RiJG1hcCggZGlmZl9leHBfZXhhbXBsZTEsICJnZW5lIiwgcmVtb3ZlVW5tYXBwZWRSb3dzID0gVFJVRSApCgojbWFwCgojP1NUUklOR2RiCmBgYAoKCgoKCgoKYGBge3J9CgoKbmV1cm9uYWxfY2x1c3RlcnNfZ2VuZXMgPC0gbWVyZ2UobmV1cm9uYWxfY2x1c3RlcnMsIGdlbmVfaW5mbywgYnkueD0idHJhbnNjcmlwdCIsIGJ5Lnk9ImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIpCgpuZXVyb25hbF9jbHVzdGVyc19nZW5lcyRNRV9jbHVzdGVycyA8LSBtYXB2YWx1ZXMobmV1cm9uYWxfY2x1c3RlcnNfZ2VuZXMkTUVfY2x1c3RlcnMsIAogICAgICAgICAgZnJvbSA9MToxOCwKICAgICAgICAgIHRvID0gYygiSTEiLCAiRTEiLCAiRTMiLCAiSTIiLCAiTjEiLCAiTTEiLCAiTjIiLCAiTk0zIiwgIk5NMiIsICJONSIsICJOTTEiLCAiTjMiLCAiTjQiLCAiTk4yIiwgIkUyIiwgIkk0IiwgIkkzIiwgIk5OMSIpKQoKI0dlbmVyYXJpbmcgdmFsdWVzIGZvciBwaWUgdmVydGljcwoKY29sb3VyX3BhbGxldGUgPC0gbGlzdCggYyhoZWF0LmNvbG9ycyg4KSwgIiMxRTkwRkZGRiIpKQp2YWx1ZXNfY2x1c3RlcnMgPSBsaXN0KCkKCk1FX3Blcl9nZW5lID0gbGlzdCgpCgp2ZXJ0ZXhfc2hhcGUgPSBsaXN0KCkKY2lyY2xlX2NvbG9yID0gbGlzdCgpCgpsYWJlbF9jb2xvciA9IGxpc3QoKQoKZm9yIChpIGluIDE6MTQ0KXsKICAKCiAgZ2VuZV9uYW1lID0gbm9kZXNbaSwgXSRpZAoKCiAgaWYgKGk9PTE2KXsKICAgIAogICAgZ2VuZV9uYW1lID0gIlNwdGFuMSIgICAjIFNUUklORyBEQiBjaGFuZ2VkIHRoZSBuYW1lIGZyb20gU3BuYTIgdG8gU3BhdGFuMQogIH0KICAKICBpZiAoaT09NDkpewogICAgCiAgICBnZW5lX25hbWUgPSAiRGlhcGgxIiAgICMjIFNUUklORyBEQiBjaGFuZ2VkIHRoZSBuYW1lIGZyb20gRGlhcDEgdG8gRGlhcGgxCiAgfQogIAogIAogIE1FX3Blcl9nZW5lW1tpXV0gPC0gbnJvdyhuZXVyb25hbF9jbHVzdGVyc19nZW5lc1ttZ2lfc3ltYm9sPT1nZW5lX25hbWUsIF0pCgoKICBOMSA9ICBucm93KG5ldXJvbmFsX2NsdXN0ZXJzX2dlbmVzW21naV9zeW1ib2w9PWdlbmVfbmFtZSAgJiBNRV9jbHVzdGVycz09Ik4xIiwgXSkKICBOMiA9ICBucm93KG5ldXJvbmFsX2NsdXN0ZXJzX2dlbmVzW21naV9zeW1ib2w9PWdlbmVfbmFtZSAgJiBNRV9jbHVzdGVycz09Ik4yIiwgXSkKICBOMyA9ICBucm93KG5ldXJvbmFsX2NsdXN0ZXJzX2dlbmVzW21naV9zeW1ib2w9PWdlbmVfbmFtZSAgJiBNRV9jbHVzdGVycz09Ik4zIiwgXSkKICBONCA9ICBucm93KG5ldXJvbmFsX2NsdXN0ZXJzX2dlbmVzW21naV9zeW1ib2w9PWdlbmVfbmFtZSAgJiBNRV9jbHVzdGVycz09Ik40IiwgXSkKICBONSA9ICBucm93KG5ldXJvbmFsX2NsdXN0ZXJzX2dlbmVzW21naV9zeW1ib2w9PWdlbmVfbmFtZSAgJiBNRV9jbHVzdGVycz09Ik41IiwgXSkKICBOTTEgPSAgbnJvdyhuZXVyb25hbF9jbHVzdGVyc19nZW5lc1ttZ2lfc3ltYm9sPT1nZW5lX25hbWUgICYgTUVfY2x1c3RlcnM9PSJOTTEiLCBdKQogIE5NMiA9ICBucm93KG5ldXJvbmFsX2NsdXN0ZXJzX2dlbmVzW21naV9zeW1ib2w9PWdlbmVfbmFtZSAgJiBNRV9jbHVzdGVycz09Ik5NMiIsIF0pCiAgTk0zID0gIG5yb3cobmV1cm9uYWxfY2x1c3RlcnNfZ2VuZXNbbWdpX3N5bWJvbD09Z2VuZV9uYW1lICAmIE1FX2NsdXN0ZXJzPT0iTk0zIiwgXSkKICBOTjEgPSAgbnJvdyhuZXVyb25hbF9jbHVzdGVyc19nZW5lc1ttZ2lfc3ltYm9sPT1nZW5lX25hbWUgICYgTUVfY2x1c3RlcnM9PSJOTjEiLCBdKQogIAogIAogICN2YWx1ZXNfY2x1c3RlcnNbW2ldXSA8LSBjKE4xLCBOMiwgTjMsIE40LCBONSwgTk0xLCBOTTIsIE5NMywgTk4xKQogIAogIGNsdXN0ZXJfY291bnRzIDwtIGMoTk0xLCBOMSwgTk0yLCAgTjIsIE5NMywgTjMsIE40LCBONSwgIE5OMSkKICAKICB2YWx1ZXNfY2x1c3RlcnNbW2ldXSA8LSBjbHVzdGVyX2NvdW50cwogIAogIGlmIChsZW5ndGgod2hpY2goY2x1c3Rlcl9jb3VudHMhPTApICkgPT0gMSAgKSB7CiAgICAKICAgIHZlcnRleF9zaGFwZVtbaV1dIDwtICJjaXJjbGUiICAgI05vZGVzIHdpdGggb25seSBvbmUga2luZCBvZiBjbHVzdGVyIG5lZWQgdG8gYmUgY2lyY2xlcyBpbnN0ZWFkIG9mIHBpZSB0byBhdm9pZCBwaWUgYm9yZGVyCiAgICBjaXJjbGVfY29sb3JbW2ldXSA8LSAgY29sb3VyX3BhbGxldGVbWzFdXVt3aGljaChjbHVzdGVyX2NvdW50cyE9MCldIAogICAgCiAgICAKICB9IGVsc2UgewogICAgCiAgICAKICAgIHZlcnRleF9zaGFwZVtbaV1dIDwtICJwaWUiCiAgICBjaXJjbGVfY29sb3JbW2ldXSA8LSAgIiNGRkZGMDBGRiIgICAjVGhpcyBjb2xvdXIgaXMgbm90IHRha2VuIGluIGNvbnNpZGVyYXRpb24gZm9yIHBpZXMKICAgIAogICAgCiAgfQogIAogIAogICNpZiAoZ2VuZV9uYW1lICVpbiUgIFNGQVJJX0dlbmVfYW5pbWFsX2dlbmVzW21vZGVsLnNwZWNpZXM9PSJNdXMgbXVzY3VsdXMiICwgZ2VuZS5zeW1ib2xdKSB7CiAgICAKICBpZiAoZ2VuZV9uYW1lICVpbiUgIFNGQVJJX0dlbmVfaHVtYW5fZ2VuZXNbIGdlbmUuc2NvcmU8PTMgLCBnZW5lLnN5bWJvbF0pIHsgIAogICAgCiAgICAKICAgIAogICAgbGFiZWxfY29sb3JbW2ldXSA8LSAiZGFya2dyZWVuIgogICAgCiAgICAKICB9IGVsc2V7CiAgICAKICAgICBsYWJlbF9jb2xvcltbaV1dIDwtICJibGFjayIKICAgIAogIH0KICAKICAgIAogICAgCiAgaWYgKCBzdW0oIGMoIE4xLCBOMiwgTjMsIE40LCBONSwgTk0xLCBOTTIsIE5NMywgTk4xKSkgPT0gMCApIHsKICAgIAogICAgcHJpbnQoIGMoaSwgbm9kZXNbaSwgXSRpZCApICkKICB9CiAgCgp9CgoKCmBgYAoKCgoKCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTIwLCBmaWcud2lkdGg9MjB9CgpsaWJyYXJ5KGlncmFwaCkKCnZlcnRleC5waWUuY29sb3I9bGlzdChoZWF0LmNvbG9ycyg5KSkKCgoKCgpNRV9QUEkgPC0gZnJlYWQoIi4uL1BQSS9NRS5QUEkudHN2IikKCgoKCmxpbmtzIDwtIE1FX1BQSVssIGMoIiNub2RlMSIsICJub2RlMiIsICJjb21iaW5lZF9zY29yZSIpXQoKCgpjb2xuYW1lcyhsaW5rcykgPC0gYygiZnJvbSIsICJ0byIsICJzY29yZSIpCgpub2Rlcy4xIDwtIE1FX1BQSVssIGMoIiNub2RlMSIpXQpjb2xuYW1lcyhub2Rlcy4xKSA8LSBjKCJpZCIpCgpub2Rlcy4yIDwtIE1FX1BQSVssIGMoIm5vZGUyIildCmNvbG5hbWVzKG5vZGVzLjIpIDwtIGMoImlkIikKCgpub2RlcyA8LSByYmluZChub2Rlcy4xLCBub2Rlcy4yKQoKCm5vZGVzIDwtIHVuaXF1ZSggIG5vZGVzWyAsICwgYnk9ImlkIl0gKQoKCgpuZXQgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGQ9bGlua3MsIHZlcnRpY2VzPW5vZGVzLCBkaXJlY3RlZD1GKQoKRShuZXQpJHNpemUgPC0gbG9nKDItICBFKG5ldCkkc2NvcmUpCgpFKG5ldCkkd2lkdGggPC0gKDEtICBFKG5ldCkkc2NvcmUpICAqIDE1CgoKCgojVihuZXQpJHNpemUgPC0gbG9nKHVubGlzdChNRV9wZXJfZ2VuZSkgKyAyKSAqIDQKCiNFKG5ldCkkc2NvcmUKCiNwbG90KG5ldCwgdmVydGV4LnNoYXBlPSB1bmxpc3QodmVydGV4X3NoYXBlKSwgdmVydGV4LmNvbG9yID0gdW5saXN0KGNpcmNsZV9jb2xvcikgICwgdmVydGV4LnBpZT12YWx1ZXNfY2x1c3RlcnMsIHJlc2NhbGU9VCwgcGllLmx0eT0yLCB2ZXJ0ZXgucGllLmNvbG9yPWNvbG91cl9wYWxsZXRlLCB2ZXJ0ZXgubGFiZWwuZm9udD0yLCB2ZXJ0ZXgubGFiZWwuZGlzdD0wLjQsIHZlcnRleC5sYWJlbC5jb2xvcj11bmxpc3QobGFiZWxfY29sb3IpLCB2ZXJ0ZXgubGFiZWwuY2V4PTEuMikKCiNjb2xvdXJfcGFsbGV0ZQoKCiNwbG90KG5ldCxyZXNjYWxlPVQsIHZlcnRleC5sYWJlbC5jZXg9MS4yLCB2ZXJ0ZXguc2l6ZT0xICkKCgoKCgojaGFybW9uaWNfY2VudHJhbGl0eSA8LSBQUElfZGlmZl9hZ2VfSE5NRiRoYXJtb25pY19jZW50cmFsaXR5CiNuYW1lcyhoYXJtb25pY19jZW50cmFsaXR5KSA8LSBQUElfZGlmZl9hZ2VfSE5NRiRtYXBwZWRfZ2VuZQoKI1YobmV0KSRzaXplIDwtIGxvZyhoYXJtb25pY19jZW50cmFsaXR5W25hbWVzKFYobmV0KSldICsxICkKCgojVihuZXQpJHNpemUgPC0gaGFybW9uaWNfY2VudHJhbGl0eVtuYW1lcyhWKG5ldCkpXS82CgojcGxvdChuZXQpCgoKCgojUFBJX2RpZmZfYWdlX0hOTV9jZW50cmFsIFsgICVpbiUgbmFtZXMoVihuZXQpKQoKI2hhcm1vbmljX2NlbnRyYWxpdHlbbmFtZXMoVihuZXQpKV0KCgojaGFybW9uaWNfY2VudHJhbGl0eVtuYW1lcyhWKG5ldCkpXQoKCgoKI2hhcm1vbmljX2NlbnRyYWxpdHlbbmFtZXMoVihuZXQpKV0KCgojbmFtZXMoVihuZXQpKSAKCiNQUElfZGlmZl9hZ2VfSE5NX2NlbnRyYWxbICAobWdpX3N5bWJvbCAlaW4lICBuYW1lcyhWKG5ldCkpKT09RkFMU0UgLCAgXQoKI1BQSV9kaWZmX2FnZV9ITk1fY2VudHJhbFttZ2lfc3ltYm9sPT0iSXRzbjEiXQoKI1BQSV9kaWZmX2FnZV9ITk1GCmBgYAoKCgoKYGBge3J9CmxpYnJhcnkoQ0lOTkEpCgpQUElfYmV0d2Vlbm5lc3MgPC0gZXN0aW1hdGVfYmV0d2Vlbm5lc3MobmV0LCB2aWRzID0gVihuZXQpLCBkaXJlY3RlZCA9IEYsIGN1dG9mZj0tMSwKICB3ZWlnaHRzID0gTlVMTCwgbm9iaWdpbnQgPSBUUlVFKQoKUFBJX2VpZ2VuX2NlbnRyYWxpdHkgPC0gZWlnZW5fY2VudHJhbGl0eShuZXQsIGRpcmVjdGVkID0gRiwgc2NhbGUgPSBULCB3ZWlnaHRzID0gTlVMTCkkdmVjdG9yCgoKI2NiaW5kKGFzLm51bWVyaWMoUFBJX2JldHdlZW5uZXNzW1YobmV0KV0pLCBhcy5udW1lcmljKCBQUElfZWlnZW5fY2VudHJhbGl0eVtWKG5ldCldICApICkKClBQSV9oYXJtb25pY19jZW50cmFsaXR5IDwtIGhhcm1vbmljX2NlbnRyYWxpdHkobmV0KQoKClBQSV9kZWdyZWVfY2VudHJhbGl0eSA8LSBjZW50cl9kZWdyZWUobmV0KSRyZXMKbmFtZXMoUFBJX2RlZ3JlZV9jZW50cmFsaXR5KSA8LSBWKG5ldCkkbmFtZQoKUFBJX2NlbnRyYWxpdHkgPC0gZGF0YS5mcmFtZShjYmluZCggIFBQSV9iZXR3ZWVubmVzc1tWKG5ldCldICwgIFBQSV9laWdlbl9jZW50cmFsaXR5W1YobmV0KV0sIFBQSV9oYXJtb25pY19jZW50cmFsaXR5LCBQUElfZGVncmVlX2NlbnRyYWxpdHkgICApKQoKY29sbmFtZXMoUFBJX2NlbnRyYWxpdHkpIDwtIGMoImJldHdlZW5uZXNzIiwgImVpZ2VuX2NlbnRyYWxpdHkiLCAiaGFybW9uaWNfY2VudHJhbGl0eSIsICJkZWdyZWVfY2VudHJhbGl0eSIpCgpQUElfY2VudHJhbGl0eSRtYXBwZWRfZ2VuZSA8LSAgcm93Lm5hbWVzKFBQSV9jZW50cmFsaXR5KQoKUFBJX2NlbnRyYWxpdHkgPC0gZGF0YS50YWJsZShQUElfY2VudHJhbGl0eSkKCgpgYGAKCgoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CgpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShyZWFkcikKClBQSV9nZW5lcyA8LSByZWFkX2RlbGltKCJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL1BhcGVyL1BQSS9NRS5QUEkuYW5ub3RhdGlvbnMudHN2IiwgCiAgICAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKQoKUFBJX2dlbmVzIDwtIGZyZWFkKCIuLi9GaWd1cmVzL05ld19GaWd1cmUgNS9TVFJJTkcvSE1ORl9NRV9nZW5lLlNUUklOR19tYXAudHh0Iiwgc2VwPSJcdCIpCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwKCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJIDwtIG1lcmdlKERlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCwgUFBJX2dlbmVzLCAgYnkueD0iZW5zZW1ibF9nZW5lX2lkIiwgYnkueT0iaW5wdXRfdGVybSIpCgpQUElfZGlmZl9hZ2VfSE5NRiA8LSBtZXJnZShEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJLCBQUElfY2VudHJhbGl0eSwgYnk9Im1hcHBlZF9nZW5lIikKICAKICAKICAKCiNuZXVyb25hbF9NRV9nZW5lX25hbWVzX2RpZmZfYWdlIDwtIG1lcmdlKG5ldXJvbmFsX01FX2dlbmVfbmFtZXMsIFBQSV9jZW50cmFsaXR5LCBieT0ibWdpX3N5bWJvbCIpCgojRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgZW5zZW1ibF9nZW5lX2lkOj1nc3ViKCJcXC4uKiIsIiIsIEdlbmUpIF0KCgojUFBJX2RpZmZfYWdlX0hOTUYgPC0gbWVyZ2UoRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsLCBuZXVyb25hbF9NRV9nZW5lX25hbWVzX2RpZmZfYWdlLCBieT0iZW5zZW1ibF9nZW5lX2lkIikKCiNQUElfZGlmZl9hZ2VfSE5NRiA8LSB1bmlxdWUoUFBJX2RpZmZfYWdlX0hOTSkKCgoKUFBJX2RpZmZfYWdlX0hOTUZbICwgdHlwZTo9IkFubm90YXRlZCIgIF0KClBQSV9kaWZmX2FnZV9ITk1GWyFleG9uX0lEICVpbiUgbWljcm9leG9uc19WYXN0ZGIsIHR5cGU6PSJNaXNzaW5nIGluIFZhc3REQiIgICBdCgpQUElfZGlmZl9hZ2VfSE5NRlshZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSwgdHlwZTo9Ik1pc3NpbmcgaW4gR0VOQ09ERSIgICBdCgpQUElfZGlmZl9hZ2VfSE5NRlshZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSAmICFleG9uX0lEICVpbiUgbWljcm9leG9uc19WYXN0ZGIgLCB0eXBlOj0iTm92ZWwiICAgXQoKCgoKTDFpbnQgPC0gYygiQW5rMSIsICJBcDJtMSIsICJLY25xMiIsICJOZmFzYyIsICJTcmMiLCAiQW5rMiIsICJEbm0xIiwgIkwxY2FtIiwgIk5yY2FtIiwgIlZhdjIiLCAiQW5rMyIsICJEbm0zIiwgIk5jYW0xIiwgIlNwdGFuMSIpCiNQUElfZGlmZl9hZ2VfSE5NWywgTDFjYW1fYW5kX2ludGVyYWN0b3JzIDo9IG1naV9zeW1ib2wgJWluJSBMMWludF0KCgpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19IQyA8LSBQUElfZGlmZl9hZ2VfSE5NRlssICAuKG1pbl9kaWZfYWdlPW1pbihkaWZmX2FnZSksIE51bWJlcl9vZl9NRT0uTiksIGJ5PWMoImVuc2VtYmxfZ2VuZV9pZCIsICJoYXJtb25pY19jZW50cmFsaXR5IikgXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19IQ1ssIHJhbms6PWZyYW5rKC1oYXJtb25pY19jZW50cmFsaXR5KV0KUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfSENbICwgbWF4X3Jhbms6PW1heChyYW5rKV0KUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfSENbICwgcGVyY2VudGlsOj1yYW5rL21heF9yYW5rKjEwMF0KUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfSENbLCBjZW50cmFsOj1GQUxTRV0KUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfSENbcGVyY2VudGlsPDE1LCBjZW50cmFsOj1UUlVFXQoKClBQSV9kaWZmX2FnZV9ITk1GX3N0YXRzX0IgPC0gUFBJX2RpZmZfYWdlX0hOTUZbLCAgLihtaW5fZGlmX2FnZT1taW4oZGlmZl9hZ2UpLCBOdW1iZXJfb2ZfTUU9Lk4pLCBieT1jKCJlbnNlbWJsX2dlbmVfaWQiLCAiYmV0d2Vlbm5lc3MiKSBdClBQSV9kaWZmX2FnZV9ITk1GX3N0YXRzX0JbLCByYW5rOj1mcmFuaygtYmV0d2Vlbm5lc3MpXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19CWyAsIG1heF9yYW5rOj1tYXgocmFuayldClBQSV9kaWZmX2FnZV9ITk1GX3N0YXRzX0JbICwgcGVyY2VudGlsOj1yYW5rL21heF9yYW5rKjEwMF0KUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfQlssIGNlbnRyYWw6PUZBTFNFXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19CW3BlcmNlbnRpbDwxNSwgY2VudHJhbDo9VFJVRV0KCgpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19FQyA8LSBQUElfZGlmZl9hZ2VfSE5NRlssICAuKG1pbl9kaWZfYWdlPW1pbihkaWZmX2FnZSksIE51bWJlcl9vZl9NRT0uTiksIGJ5PWMoImVuc2VtYmxfZ2VuZV9pZCIsICJlaWdlbl9jZW50cmFsaXR5IiwgInR5cGUiLCAibWFwcGVkX2dlbmUiKSBdClBQSV9kaWZmX2FnZV9ITk1GX3N0YXRzX0VDWywgcmFuazo9ZnJhbmsoLWVpZ2VuX2NlbnRyYWxpdHkpXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19FQ1sgLCBtYXhfcmFuazo9bWF4KHJhbmspXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19FQ1sgLCBwZXJjZW50aWw6PXJhbmsvbWF4X3JhbmsqMTAwXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19FQ1ssIGNlbnRyYWw6PUZBTFNFXQpQUElfZGlmZl9hZ2VfSE5NRl9zdGF0c19FQ1twZXJjZW50aWw8MjUsIGNlbnRyYWw6PVRSVUVdCgoKUFBJX2RpZmZfYWdlX0hOTUZfY2VudHJhbCA8LSBtZXJnZShQUElfZGlmZl9hZ2VfSE5NRiwgUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfRUNbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiY2VudHJhbCIpXSwgYnk9ImVuc2VtYmxfZ2VuZV9pZCIgKQoKCkY2RiA8LSBnZ3Bsb3QoUFBJX2RpZmZfYWdlX0hOTUZfY2VudHJhbCkgKwogIGdlb21faml0dGVyKGFlcyhlaWdlbl9jZW50cmFsaXR5LCBkaWZmX2FnZSwgIGNvbG91cj0gdHlwZSAgKSwgd2lkdGg9MCwgaGVpZ2h0PTAuMSkgKyAKICB4bGFiKCJFaWdlbmNlbnRyYWxpdHkiKSArCiAgeWxhYigiRWFybGllc3QgbWljcm9leG9uIGRpZmZlcmVudGlhbCBpbmNsdXNpb24gZGV0ZWN0aW9uIChEUEMpIikgKwogICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICAgIGdlb21fdGV4dF9yZXBlbChkYXRhPVBQSV9kaWZmX2FnZV9ITk1GX2NlbnRyYWxbICBjZW50cmFsPT1UUlVFICBdLCAKICAgICAgICAgICAgICAgICAgYWVzKHg9ZWlnZW5fY2VudHJhbGl0eSwgeT1kaWZmX2FnZSwgY29sb3VyPSB0eXBlICksIAogICAgICAgICAgICAgICAgICBudWRnZV95ICAgICAgPSAwLjUsCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICAgYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgbGFiZWw9UFBJX2RpZmZfYWdlX0hOTUZfY2VudHJhbFtjZW50cmFsPT1UUlVFICAsIG1hcHBlZF9nZW5lXSwKICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCgoKCgoKUFBJX2RpZmZfYWdlX0hOTUZfY2VudHJhbCA8LSBtZXJnZShQUElfZGlmZl9hZ2VfSE5NRiwgUFBJX2RpZmZfYWdlX0hOTUZfc3RhdHNfSENbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiY2VudHJhbCIpXSwgYnk9ImVuc2VtYmxfZ2VuZV9pZCIgKQoKCkY2LnN1cC4xIDwtIGdncGxvdChQUElfZGlmZl9hZ2VfSE5NRl9jZW50cmFsKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKGhhcm1vbmljX2NlbnRyYWxpdHksIGRpZmZfYWdlLCAgY29sb3VyPSB0eXBlICApLCB3aWR0aD0wLCBoZWlnaHQ9MC4xKSArIAogIHhsYWIoIkhhcm1vbmljIENlbnRyYWxpdHkiKSArCiAgeWxhYigiRWFybGllc3QgbWljcm9leG9uIGRpZmZlcmVudGlhbCBpbmNsdXNpb24gZGV0ZWN0aW9uIChEUEMpIikgKwogICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICAgIGdlb21fdGV4dF9yZXBlbChkYXRhPVBQSV9kaWZmX2FnZV9ITk1GX2NlbnRyYWxbICBjZW50cmFsPT1UUlVFICBdLCAKICAgICAgICAgICAgICAgICAgYWVzKHg9aGFybW9uaWNfY2VudHJhbGl0eSwgeT1kaWZmX2FnZSwgY29sb3VyPSB0eXBlICksIAogICAgICAgICAgICAgICAgICBudWRnZV95ICAgICAgPSAwLjUsCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICAgYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgbGFiZWw9UFBJX2RpZmZfYWdlX0hOTUZfY2VudHJhbFtjZW50cmFsPT1UUlVFICAsIG1hcHBlZF9nZW5lXSwKICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBUUlVFKSArCiAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgpGNkYKYGBgCgoKYGBge3J9CgpQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0VDIDwtIFBQSV9kaWZmX2FnZV9ITk1GW2lzLm5hKGRpZmZfYWdlLngpIT1UUlVFXVssICAuKG1pbl9kaWZfYWdlPW1pbihkaWZmX2FnZS54KSwgTnVtYmVyX29mX01FPS5OKSwgYnk9YygiZW5zZW1ibF9nZW5lX2lkIiwgImVpZ2VuX2NlbnRyYWxpdHkiKSBdClBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfRUNbLCByYW5rOj1mcmFuaygtZWlnZW5fY2VudHJhbGl0eSldClBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfRUNbICwgbWF4X3Jhbms6PW1heChyYW5rKV0KUFBJX2RpZmZfYWdlX0hOTV9zdGF0c19FQ1sgLCBwZXJjZW50aWw6PXJhbmsvbWF4X3JhbmsqMTAwXQpQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0VDWywgY2VudHJhbDo9RkFMU0VdClBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfRUNbcGVyY2VudGlsPDE1LCBjZW50cmFsOj1UUlVFXQoKCgpnZ3Bsb3QoUFBJX2RpZmZfYWdlX0hOTV9zdGF0c19FQykgKwogIGdlb21fYmFyKGFlcyhtaW5fZGlmX2FnZSwgZmlsbD1jZW50cmFsKSwgc3RhdCA9ICJjb3VudCIsIHBvc2l0aW9uPSJmaWxsIiApICsKICB4bGFiKCJFYXJsaWVzdCBtaWNyb2V4b24gZGlmZmVyZW50aWFsIGluY2x1c2lvbiBkZXRlY3Rpb24gcGVyIGdlbmUgKERQQykiKSsKICB5bGFiKCJQcm90ZWluIHR5cGUgcHJvcG9ydGlvbiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiUHJvdGVpbiB0eXBlIiwgbGFiZWxzID0gYygiTm9uLWNlbnRyYWwiLCAiQ2VudHJhbCIpKSAgKwogICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgoKCgpQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0hDIDwtIFBQSV9kaWZmX2FnZV9ITk1GW2lzLm5hKGRpZmZfYWdlLngpIT1UUlVFXVssICAuKG1pbl9kaWZfYWdlPW1pbihkaWZmX2FnZS54KSwgTnVtYmVyX29mX01FPS5OKSwgYnk9YygiZW5zZW1ibF9nZW5lX2lkIiwgImhhcm1vbmljX2NlbnRyYWxpdHkiKSBdClBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfSENbLCByYW5rOj1mcmFuaygtaGFybW9uaWNfY2VudHJhbGl0eSldClBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfSENbICwgbWF4X3Jhbms6PW1heChyYW5rKV0KUFBJX2RpZmZfYWdlX0hOTV9zdGF0c19IQ1sgLCBwZXJjZW50aWw6PXJhbmsvbWF4X3JhbmsqMTAwXQpQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0hDWywgY2VudHJhbDo9RkFMU0VdClBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfSENbcGVyY2VudGlsPDE1LCBjZW50cmFsOj1UUlVFXQoKCgpnZ3Bsb3QoUFBJX2RpZmZfYWdlX0hOTV9zdGF0c19IQykgKwogIGdlb21fYmFyKGFlcyhtaW5fZGlmX2FnZSwgZmlsbD1jZW50cmFsKSwgc3RhdCA9ICJjb3VudCIsIHBvc2l0aW9uPSJmaWxsIiApICsKICB4bGFiKCJFYXJsaWVzdCBtaWNyb2V4b24gZGlmZmVyZW50aWFsIGluY2x1c2lvbiBkZXRlY3Rpb24gcGVyIGdlbmUgKERQQykiKSsKICB5bGFiKCJQcm90ZWluIHR5cGUgcHJvcG9ydGlvbiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiUHJvdGVpbiB0eXBlIiwgbGFiZWxzID0gYygiTm9uLWNlbnRyYWwiLCAiQ2VudHJhbCIpKSAgKwogICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgoKCgpjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb24gPC0gZ2xtKGZvcm11bGEgPSBjZW50cmFsIH4gbWluX2RpZl9hZ2UsIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSBQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0VDKQpzdW1tYXJ5KGNlbnRyYWxpdHlfbG9naXN0aWNfcmVncmVzc2lvbikKCgpjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb24gPC0gZ2xtKGZvcm11bGEgPSBjZW50cmFsIH4gbWluX2RpZl9hZ2UsIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSBQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0hDKQpzdW1tYXJ5KGNlbnRyYWxpdHlfbG9naXN0aWNfcmVncmVzc2lvbikKYGBgCgoKCgoKCgpgYGB7cn0KdmFyMnN0ciA8LSBmdW5jdGlvbih2MSkgewogIGRlcGFyc2Uoc3Vic3RpdHV0ZSh2MSkpCn0KCmBgYAoKCgoKCmBgYHtyfQojR09fUmVhY3RvbWUgPC0gZnJlYWQoIi4uL0ZpZ3VyZXMvTmV3X0ZpZ3VyZSA1L1NUUklORy9HTy9XaG9sZV9nZW5vbWVfYmFja2dyb3VuZC9SZWFjdG9tZSBQYXRod2F5cy50c3YiKQoKCgoKQXhvbl9ndWlkYW5jZSA8LSB1bmxpc3Qoc3Ryc3BsaXQoR09fUmVhY3RvbWVbYHRlcm0gZGVzY3JpcHRpb25gPT0iQXhvbiBndWlkYW5jZSJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQpMMUNBTV9pbnRlcmFjdGlvbnMgPC0gdW5saXN0KHN0cnNwbGl0KEdPX1JlYWN0b21lW2B0ZXJtIGRlc2NyaXB0aW9uYD09IkwxQ0FNIGludGVyYWN0aW9ucyJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQpQcm90ZWluX3Byb3RlaW5faW50ZXJhY3Rpb25zX2F0X3N5bmFwc2VzIDwtIHVubGlzdChzdHJzcGxpdChHT19SZWFjdG9tZVtgdGVybSBkZXNjcmlwdGlvbmA9PSJQcm90ZWluLXByb3RlaW4gaW50ZXJhY3Rpb25zIGF0IHN5bmFwc2VzIl0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCkVSX3RvX0dvbGdpX0FudGVyb2dyYWRlX1RyYW5zcG9ydCA8LSB1bmxpc3Qoc3Ryc3BsaXQoR09fUmVhY3RvbWVbYHRlcm0gZGVzY3JpcHRpb25gPT0iRVIgdG8gR29sZ2kgQW50ZXJvZ3JhZGUgVHJhbnNwb3J0Il0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCkNsYXRocmluX21lZGlhdGVkX2VuZG9jeXRvc2lzIDwtIHVubGlzdChzdHJzcGxpdChHT19SZWFjdG9tZVtgdGVybSBkZXNjcmlwdGlvbmA9PSJDbGF0aHJpbi1tZWRpYXRlZCBlbmRvY3l0b3NpcyJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQpHb2xnaV9Bc3NvY2lhdGVkX1Zlc2ljbGVfQmlvZ2VuZXNpcyA8LSB1bmxpc3Qoc3Ryc3BsaXQoR09fUmVhY3RvbWVbYHRlcm0gZGVzY3JpcHRpb25gPT0iR29sZ2kgQXNzb2NpYXRlZCBWZXNpY2xlIEJpb2dlbmVzaXMiXSRgbWF0Y2hpbmcgcHJvdGVpbnMgaW4geW91ciBuZXR3b3JrIChsYWJlbHMpYCwgIiwiKSkKTWVtYnJhbmVfVHJhZmZpY2tpbmcgPC0gdW5saXN0KHN0cnNwbGl0KEdPX1JlYWN0b21lW2B0ZXJtIGRlc2NyaXB0aW9uYD09Ik1lbWJyYW5lIFRyYWZmaWNraW5nIl0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCkludHJhX0dvbGdpX2FuZF9yZXRyb2dyYWRlX0dvbGdpX3RvX0VSX3RyYWZmaWMgPC0gdW5saXN0KHN0cnNwbGl0KEdPX1JlYWN0b21lW2B0ZXJtIGRlc2NyaXB0aW9uYD09IkludHJhLUdvbGdpIGFuZCByZXRyb2dyYWRlIEdvbGdpLXRvLUVSIHRyYWZmaWMiXSRgbWF0Y2hpbmcgcHJvdGVpbnMgaW4geW91ciBuZXR3b3JrIChsYWJlbHMpYCwgIiwiKSkKCkdPcyA8LSBsaXN0KEF4b25fZ3VpZGFuY2UsIEwxQ0FNX2ludGVyYWN0aW9ucykKClBQSV9jZW50cmFsaXR5X0dPIDwtIFBQSV9kaWZmX2FnZV9ITk1GWywgYygibWFwcGVkX2dlbmUiLCAiZXhvbl9JRCIsICJkaWZmX2FnZSIsICAiYmV0d2Vlbm5lc3MiLCAiZWlnZW5fY2VudHJhbGl0eSIsICJoYXJtb25pY19jZW50cmFsaXR5IiwgImRlZ3JlZV9jZW50cmFsaXR5IiwgInR5cGUiKSBdCgpQUElfY2VudHJhbGl0eV9HTyA8LQogIHJiaW5kKFBQSV9kaWZmX2FnZV9ITk1GWyBtYXBwZWRfZ2VuZSAlaW4lIEF4b25fZ3VpZGFuY2UsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCAgYmV0d2Vlbm5lc3MsIGVpZ2VuX2NlbnRyYWxpdHksIGhhcm1vbmljX2NlbnRyYWxpdHksIGRlZ3JlZV9jZW50cmFsaXR5LCB0eXBlLCBHTz12YXIyc3RyKEF4b25fZ3VpZGFuY2UpKSBdLApQUElfZGlmZl9hZ2VfSE5NRlsgbWFwcGVkX2dlbmUgJWluJSBMMUNBTV9pbnRlcmFjdGlvbnMsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCAgYmV0d2Vlbm5lc3MsIGVpZ2VuX2NlbnRyYWxpdHksIGhhcm1vbmljX2NlbnRyYWxpdHksIGRlZ3JlZV9jZW50cmFsaXR5LCB0eXBlLCBHTz12YXIyc3RyKEwxQ0FNX2ludGVyYWN0aW9ucykpIF0sClBQSV9kaWZmX2FnZV9ITk1GWyBtYXBwZWRfZ2VuZSAlaW4lIFByb3RlaW5fcHJvdGVpbl9pbnRlcmFjdGlvbnNfYXRfc3luYXBzZXMsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCAgYmV0d2Vlbm5lc3MsIGVpZ2VuX2NlbnRyYWxpdHksIGhhcm1vbmljX2NlbnRyYWxpdHksIGRlZ3JlZV9jZW50cmFsaXR5LCB0eXBlLCBHTz12YXIyc3RyKFByb3RlaW5fcHJvdGVpbl9pbnRlcmFjdGlvbnNfYXRfc3luYXBzZXMpKSBdLApQUElfZGlmZl9hZ2VfSE5NRlsgbWFwcGVkX2dlbmUgJWluJSBFUl90b19Hb2xnaV9BbnRlcm9ncmFkZV9UcmFuc3BvcnQsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCAgYmV0d2Vlbm5lc3MsIGVpZ2VuX2NlbnRyYWxpdHksIGhhcm1vbmljX2NlbnRyYWxpdHksIGRlZ3JlZV9jZW50cmFsaXR5LCB0eXBlLCBHTz12YXIyc3RyKEVSX3RvX0dvbGdpX0FudGVyb2dyYWRlX1RyYW5zcG9ydCkpIF0sClBQSV9kaWZmX2FnZV9ITk1GWyBtYXBwZWRfZ2VuZSAlaW4lIENsYXRocmluX21lZGlhdGVkX2VuZG9jeXRvc2lzLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgIGJldHdlZW5uZXNzLCBlaWdlbl9jZW50cmFsaXR5LCBoYXJtb25pY19jZW50cmFsaXR5LCBkZWdyZWVfY2VudHJhbGl0eSwgdHlwZSwgR089dmFyMnN0cihDbGF0aHJpbl9tZWRpYXRlZF9lbmRvY3l0b3NpcykpIF0sClBQSV9kaWZmX2FnZV9ITk1GWyBtYXBwZWRfZ2VuZSAlaW4lIEdvbGdpX0Fzc29jaWF0ZWRfVmVzaWNsZV9CaW9nZW5lc2lzLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgIGJldHdlZW5uZXNzLCBlaWdlbl9jZW50cmFsaXR5LCBoYXJtb25pY19jZW50cmFsaXR5LCBkZWdyZWVfY2VudHJhbGl0eSwgdHlwZSwgR089dmFyMnN0cihHb2xnaV9Bc3NvY2lhdGVkX1Zlc2ljbGVfQmlvZ2VuZXNpcykpIF0sClBQSV9kaWZmX2FnZV9ITk1GWyBtYXBwZWRfZ2VuZSAlaW4lIE1lbWJyYW5lX1RyYWZmaWNraW5nLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgIGJldHdlZW5uZXNzLCBlaWdlbl9jZW50cmFsaXR5LCBoYXJtb25pY19jZW50cmFsaXR5LCBkZWdyZWVfY2VudHJhbGl0eSwgdHlwZSwgR089dmFyMnN0cihNZW1icmFuZV9UcmFmZmlja2luZykpIF0sClBQSV9kaWZmX2FnZV9ITk1GWyBtYXBwZWRfZ2VuZSAlaW4lIEludHJhX0dvbGdpX2FuZF9yZXRyb2dyYWRlX0dvbGdpX3RvX0VSX3RyYWZmaWMsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCAgYmV0d2Vlbm5lc3MsIGVpZ2VuX2NlbnRyYWxpdHksIGhhcm1vbmljX2NlbnRyYWxpdHksIGRlZ3JlZV9jZW50cmFsaXR5LCB0eXBlLCBHTz12YXIyc3RyKEludHJhX0dvbGdpX2FuZF9yZXRyb2dyYWRlX0dvbGdpX3RvX0VSX3RyYWZmaWMpKSBdKQoKCgoKCgoKZ2dwbG90KFBQSV9jZW50cmFsaXR5X0dPLCBhZXMoR08sIGxvZyhiZXR3ZWVubmVzcykpKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMCkpCgoKUFBJX2NlbnRyYWxpdHlfR09fZ2VuZV9jZW50ZXJlZCA8LSBQUElfY2VudHJhbGl0eV9HT1sgLCAuKGRpZmZfYWdlPW1pbihkaWZmX2FnZSkpICwgYnk9YygibWFwcGVkX2dlbmUiLCAiYmV0d2Vlbm5lc3MiLCAiZWlnZW5fY2VudHJhbGl0eSIsICJoYXJtb25pY19jZW50cmFsaXR5IiwgImRlZ3JlZV9jZW50cmFsaXR5IiwgIkdPIildCgoKZ2dwbG90KFBQSV9jZW50cmFsaXR5X0dPX2dlbmVfY2VudGVyZWQgKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKGhhcm1vbmljX2NlbnRyYWxpdHksIGRpZmZfYWdlLCBjb2xvcj1HTyksIHdpZHRoPTAuNSwgaGVpZ2h0PTAuMSApICsKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKQoKYGBgCgpgYGB7cn0KZ2dwbG90KFBQSV9jZW50cmFsaXR5X0dPX2dlbmVfY2VudGVyZWQsIGFlcyhHTywgZGlmZl9hZ2UpKSArCisgICAgIGdlb21faml0dGVyKGhlaWdodCA9IDAuMSwgd2lkdGggPSAwLjEpICsKKyAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwKSkKCgpgYGAKCgpgYGB7cn0KClBQSV9jZW50cmFsaXR5X0dPX2dlbmVfY2VudGVyZWRfc3RhdHMgPC0gIFBQSV9jZW50cmFsaXR5X0dPX2dlbmVfY2VudGVyZWRbICwgLihOPS5OKSwgIGJ5PWMoIkdPIiwgImRpZmZfYWdlIildCgpQUElfY2VudHJhbGl0eV9HT19nZW5lX2NlbnRlcmVkX3N0YXRzWyAsIFRvdGFsOj1zdW0oTiksIGJ5ID0iR08iXQoKUFBJX2NlbnRyYWxpdHlfR09fZ2VuZV9jZW50ZXJlZF9zdGF0c1ssIGZyYWN0aW9uOj1OL1RvdGFsIF0KCmRpZmZfYWdlX2xldmVscyA8LSBQUElfY2VudHJhbGl0eV9HT19nZW5lX2NlbnRlcmVkX3N0YXRzWyAsIC4obWVhbj1tZWFuKGRpZmZfYWdlKSksIGJ5PSJHTyJdW29yZGVyKC1tZWFuKV0kR08KCgpQUElfY2VudHJhbGl0eV9HT19nZW5lX2NlbnRlcmVkX3N0YXRzJEdPIDwtIGZhY3RvcihQUElfY2VudHJhbGl0eV9HT19nZW5lX2NlbnRlcmVkX3N0YXRzJEdPLCBsZXZlbHM9IGRpZmZfYWdlX2xldmVscykKCmdncGxvdChQUElfY2VudHJhbGl0eV9HT19nZW5lX2NlbnRlcmVkX3N0YXRzKSArCiAgZ2VvbV90aWxlKGFlcyggZGlmZl9hZ2UsIEdPLCBmaWxsID0gZnJhY3Rpb24pKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImdyZXkiLCBoaWdoPSJyZWQiKSsKICB0aGVtZV9idygpKwogIGxhYnMoZmlsbCA9ICJHZW5lIGZyYWN0aW9uIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCgoKYGBge3J9CgpHT19SZWFjdG9tZV9hbGwgPC0gcmJpbmQoCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9QUElbIG1hcHBlZF9nZW5lICVpbiUgQXhvbl9ndWlkYW5jZSwgLihtYXBwZWRfZ2VuZSwgZXhvbl9JRCwgZGlmZl9hZ2UsIEdPPXZhcjJzdHIoQXhvbl9ndWlkYW5jZSkpIF0gLApEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJWyBtYXBwZWRfZ2VuZSAlaW4lIEwxQ0FNX2ludGVyYWN0aW9ucywgLihtYXBwZWRfZ2VuZSwgZXhvbl9JRCwgZGlmZl9hZ2UsIEdPPXZhcjJzdHIoTDFDQU1faW50ZXJhY3Rpb25zKSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBQcm90ZWluX3Byb3RlaW5faW50ZXJhY3Rpb25zX2F0X3N5bmFwc2VzLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgR089dmFyMnN0cihQcm90ZWluX3Byb3RlaW5faW50ZXJhY3Rpb25zX2F0X3N5bmFwc2VzKSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBFUl90b19Hb2xnaV9BbnRlcm9ncmFkZV9UcmFuc3BvcnQsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKEVSX3RvX0dvbGdpX0FudGVyb2dyYWRlX1RyYW5zcG9ydCkpIF0sCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9QUElbIG1hcHBlZF9nZW5lICVpbiUgQ2xhdGhyaW5fbWVkaWF0ZWRfZW5kb2N5dG9zaXMsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKENsYXRocmluX21lZGlhdGVkX2VuZG9jeXRvc2lzKSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBHb2xnaV9Bc3NvY2lhdGVkX1Zlc2ljbGVfQmlvZ2VuZXNpcywgLihtYXBwZWRfZ2VuZSwgZXhvbl9JRCwgZGlmZl9hZ2UsIEdPPXZhcjJzdHIoR29sZ2lfQXNzb2NpYXRlZF9WZXNpY2xlX0Jpb2dlbmVzaXMpKSBdLApEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJWyBtYXBwZWRfZ2VuZSAlaW4lIE1lbWJyYW5lX1RyYWZmaWNraW5nLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgR089dmFyMnN0cihNZW1icmFuZV9UcmFmZmlja2luZykpIF0sCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9QUElbIG1hcHBlZF9nZW5lICVpbiUgSW50cmFfR29sZ2lfYW5kX3JldHJvZ3JhZGVfR29sZ2lfdG9fRVJfdHJhZmZpYywgLihtYXBwZWRfZ2VuZSwgZXhvbl9JRCwgZGlmZl9hZ2UsIEdPPXZhcjJzdHIoSW50cmFfR29sZ2lfYW5kX3JldHJvZ3JhZGVfR29sZ2lfdG9fRVJfdHJhZmZpYykpXSApCgoKR09fUmVhY3RvbWVfYWxsX3N0YXRzIDwtICBHT19SZWFjdG9tZV9hbGxbICwgLihOPS5OKSwgIGJ5PWMoIkdPIiwgImRpZmZfYWdlIildCkdPX1JlYWN0b21lX2FsbF9zdGF0c1sgLCBUb3RhbDo9c3VtKE4pLCBieSA9IkdPIl0KR09fUmVhY3RvbWVfYWxsX3N0YXRzWywgZnJhY3Rpb246PU4vVG90YWwgXQpkaWZmX2FnZV9sZXZlbHMgPC0gR09fUmVhY3RvbWVfYWxsX3N0YXRzWyAsIC4obWVhbj1tZWFuKGRpZmZfYWdlKSksIGJ5PSJHTyJdW29yZGVyKC1tZWFuKV0kR08KCmRpZmZfYWdlX2xldmVscyA8LSBjKCJNZW1icmFuZV9UcmFmZmlja2luZyIsCiAgICAgICAgICAgICAgICAgICAgICJJbnRyYV9Hb2xnaV9hbmRfcmV0cm9ncmFkZV9Hb2xnaV90b19FUl90cmFmZmljIiwKICAgICAgICAgICAgICAgICAgICAgIkdvbGdpX0Fzc29jaWF0ZWRfVmVzaWNsZV9CaW9nZW5lc2lzIiwKICAgICAgICAgICAgICAgICAgICAgIkNsYXRocmluX21lZGlhdGVkX2VuZG9jeXRvc2lzIiwKICAgICAgICAgICAgICAgICAgICAgIkVSX3RvX0dvbGdpX0FudGVyb2dyYWRlX1RyYW5zcG9ydCIsCiAgICAgICAgICAgICAgICAgICAgICAiQXhvbl9ndWlkYW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAiTDFDQU1faW50ZXJhY3Rpb25zIiwKICAgICAgICAgICAgICAgICAgICAgICJQcm90ZWluX3Byb3RlaW5faW50ZXJhY3Rpb25zX2F0X3N5bmFwc2VzIikKCgpHT19SZWFjdG9tZV9hbGxfc3RhdHMkR08gPC0gZmFjdG9yKEdPX1JlYWN0b21lX2FsbF9zdGF0cyRHTywgbGV2ZWxzPSByZXYoZGlmZl9hZ2VfbGV2ZWxzKSkKCgpGNkcgPC0gZ2dwbG90KEdPX1JlYWN0b21lX2FsbF9zdGF0cykgKwogIGdlb21fdGlsZShhZXMoIGRpZmZfYWdlLCBHTywgZmlsbCA9IGZyYWN0aW9uKSkgKwogIGdlb21fdGV4dChhZXMoZGlmZl9hZ2UsIEdPLCBsYWJlbCA9IE4pLCBjb2xvcj0id2hpdGUiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImdyZXkiLCBoaWdoPSJyZWQiLCBsaW1pdHM9YygwLCAwLjcpICkrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICB0aGVtZV9idygpKwogIHhsYWIoIkRQQyIpICsKICB5bGFiKCIiKSArCiAgbGFicyhmaWxsID0gIkdlbmUgZnJhY3Rpb24iKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKQoKRjZHCgpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9NX0KRjZGRyA8LSBwbG90X2dyaWQoRjZGLCBGNkcsIG5jb2w9MSwgbGFiZWxzID0gYygiRiIsICJHIiksIHJlbF9oZWlnaHRzID0gYygxLjMsIDEpKQpgYGAKCgoKYGBge3J9CgoKQmlvbG9naWNhbF9Qcm9jZXNzIDwtIGZyZWFkKCIuLi9QUEkvZW5yaWNobWVudC5Qcm9jZXNzLnRzdiIpCkNlbGx1bGFyX0NvbXBvbmVudCA8LSBmcmVhZCgiLi4vUFBJL2VucmljaG1lbnQuQ29tcG9uZW50LnRzdiIpCkdPX1JlYWN0b21lIDwtIGZyZWFkKCIuLi9QUEkvZW5yaWNobWVudC5SQ1RNLnRzdiIpCgoKbmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQgPC0gdW5saXN0KHN0cnNwbGl0KEJpb2xvZ2ljYWxfUHJvY2Vzc1tgdGVybSBkZXNjcmlwdGlvbmA9PSJuZXJ2b3VzIHN5c3RlbSBkZXZlbG9wbWVudCJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQp2ZXNpY2xlX21lZGlhdGVkX3RyYW5zcG9ydCA8LSB1bmxpc3Qoc3Ryc3BsaXQoQmlvbG9naWNhbF9Qcm9jZXNzW2B0ZXJtIGRlc2NyaXB0aW9uYD09InZlc2ljbGUtbWVkaWF0ZWQgdHJhbnNwb3J0Il0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCmN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24gPC0gdW5saXN0KHN0cnNwbGl0KEJpb2xvZ2ljYWxfUHJvY2Vzc1tgdGVybSBkZXNjcmlwdGlvbmA9PSJjeXRvc2tlbGV0b24gb3JnYW5pemF0aW9uIl0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCnN5bmFwc2VfYXNzZW1ibHkgPC0gdW5saXN0KHN0cnNwbGl0KEJpb2xvZ2ljYWxfUHJvY2Vzc1tgdGVybSBkZXNjcmlwdGlvbmA9PSJzeW5hcHNlIGFzc2VtYmx5Il0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCnNpZ25hbF90cmFuc2R1Y3Rpb24gPC0gdW5saXN0KHN0cnNwbGl0KEJpb2xvZ2ljYWxfUHJvY2Vzc1tgdGVybSBkZXNjcmlwdGlvbmA9PSJzaWduYWwgdHJhbnNkdWN0aW9uIl0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCgpzeW5hcHNlIDwtIHVubGlzdChzdHJzcGxpdChDZWxsdWxhcl9Db21wb25lbnRbYHRlcm0gZGVzY3JpcHRpb25gPT0ic3luYXBzZSJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQpzb21hdG9kZW5kcml0aWNfY29tcGFydG1lbnQgPC0gdW5saXN0KHN0cnNwbGl0KENlbGx1bGFyX0NvbXBvbmVudFtgdGVybSBkZXNjcmlwdGlvbmA9PSJzb21hdG9kZW5kcml0aWMgY29tcGFydG1lbnQiXSRgbWF0Y2hpbmcgcHJvdGVpbnMgaW4geW91ciBuZXR3b3JrIChsYWJlbHMpYCwgIiwiKSkKcG9zdHN5bmFwc2UgPC0gdW5saXN0KHN0cnNwbGl0KENlbGx1bGFyX0NvbXBvbmVudFtgdGVybSBkZXNjcmlwdGlvbmA9PSJwb3N0c3luYXBzZSJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQpwcmVzeW5hcHNlIDwtIHVubGlzdChzdHJzcGxpdChDZWxsdWxhcl9Db21wb25lbnRbYHRlcm0gZGVzY3JpcHRpb25gPT0icHJlc3luYXBzZSJdJGBtYXRjaGluZyBwcm90ZWlucyBpbiB5b3VyIG5ldHdvcmsgKGxhYmVscylgLCAiLCIpKQpncm93dGhfY29uZSA8LSB1bmxpc3Qoc3Ryc3BsaXQoQ2VsbHVsYXJfQ29tcG9uZW50W2B0ZXJtIGRlc2NyaXB0aW9uYD09Imdyb3d0aCBjb25lIl0kYG1hdGNoaW5nIHByb3RlaW5zIGluIHlvdXIgbmV0d29yayAobGFiZWxzKWAsICIsIikpCgpHT19CaW9sb2dpY2FsX1Byb2Nlc3MgPC0gcmJpbmQoCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9QUElbIG1hcHBlZF9nZW5lICVpbiUgbmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKG5lcnZvdXNfc3lzdGVtX2RldmVsb3BtZW50KSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSB2ZXNpY2xlX21lZGlhdGVkX3RyYW5zcG9ydCwgLihtYXBwZWRfZ2VuZSwgZXhvbl9JRCwgZGlmZl9hZ2UsIEdPPXZhcjJzdHIodmVzaWNsZV9tZWRpYXRlZF90cmFuc3BvcnQpKSBdLApEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJWyBtYXBwZWRfZ2VuZSAlaW4lIGN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24sIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKGN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24pKSBdLApEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJWyBtYXBwZWRfZ2VuZSAlaW4lIHN5bmFwc2VfYXNzZW1ibHksIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKHN5bmFwc2VfYXNzZW1ibHkpKSBdLApEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJWyBtYXBwZWRfZ2VuZSAlaW4lIHNpZ25hbF90cmFuc2R1Y3Rpb24sIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKHNpZ25hbF90cmFuc2R1Y3Rpb24pKSBdICkKCkdPX0NlbGx1bGFyX0NvbXBvbmVudCA8LSByYmluZCgKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBzeW5hcHNlLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgR089dmFyMnN0cihzeW5hcHNlKSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBzb21hdG9kZW5kcml0aWNfY29tcGFydG1lbnQsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKHNvbWF0b2RlbmRyaXRpY19jb21wYXJ0bWVudCkpIF0sCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9QUElbIG1hcHBlZF9nZW5lICVpbiUgcG9zdHN5bmFwc2UsIC4obWFwcGVkX2dlbmUsIGV4b25fSUQsIGRpZmZfYWdlLCBHTz12YXIyc3RyKHBvc3RzeW5hcHNlKSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBwcmVzeW5hcHNlLCAuKG1hcHBlZF9nZW5lLCBleG9uX0lELCBkaWZmX2FnZSwgR089dmFyMnN0cihwcmVzeW5hcHNlKSkgXSwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgbWFwcGVkX2dlbmUgJWluJSBncm93dGhfY29uZSwgLihtYXBwZWRfZ2VuZSwgZXhvbl9JRCwgZGlmZl9hZ2UsIEdPPXZhcjJzdHIoZ3Jvd3RoX2NvbmUpKSBdICkKCgoKCkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19zdGF0cyA8LSAgR09fQmlvbG9naWNhbF9Qcm9jZXNzWyAsIC4oTj0uTiksICBieT1jKCJHTyIsICJkaWZmX2FnZSIpXQpHT19CaW9sb2dpY2FsX1Byb2Nlc3Nfc3RhdHNbICwgVG90YWw6PXN1bShOKSwgYnkgPSJHTyJdCkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19zdGF0c1ssIGZyYWN0aW9uOj1OL1RvdGFsIF0KZGlmZl9hZ2VfbGV2ZWxzIDwtIEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19zdGF0c1sgLCAuKG1lYW49bWVkaWFuKGRpZmZfYWdlKSksIGJ5PSJHTyJdW29yZGVyKC1tZWFuKV0kR08KR09fQmlvbG9naWNhbF9Qcm9jZXNzX3N0YXRzJEdPIDwtIGZhY3RvcihHT19CaW9sb2dpY2FsX1Byb2Nlc3Nfc3RhdHMkR08sIGxldmVscz0gZGlmZl9hZ2VfbGV2ZWxzKQoKCgpTdXBfR09fdGltZS5BIDwtIGdncGxvdChHT19CaW9sb2dpY2FsX1Byb2Nlc3Nfc3RhdHMpICsKICBnZW9tX3RpbGUoYWVzKCBkaWZmX2FnZSwgR08sIGZpbGwgPSBmcmFjdGlvbikpICsKICAgIGdlb21fdGV4dChhZXMoZGlmZl9hZ2UsIEdPLCBsYWJlbCA9IE4pLCBjb2xvcj0id2hpdGUiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImdyZXkiLCBoaWdoPSJyZWQiICkrCiAgdGhlbWVfYncoKSsKICBsYWJzKGZpbGwgPSAiR2VuZSBmcmFjdGlvbiIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDApLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSBOQSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCgoKR09fQ2VsbHVsYXJfQ29tcG9uZW50X3N0YXRzIDwtICBHT19DZWxsdWxhcl9Db21wb25lbnRbICwgLihOPS5OKSwgIGJ5PWMoIkdPIiwgImRpZmZfYWdlIildCkdPX0NlbGx1bGFyX0NvbXBvbmVudF9zdGF0c1sgLCBUb3RhbDo9c3VtKE4pLCBieSA9IkdPIl0KR09fQ2VsbHVsYXJfQ29tcG9uZW50X3N0YXRzWywgZnJhY3Rpb246PU4vVG90YWwgXQpkaWZmX2FnZV9sZXZlbHMgPC0gR09fQ2VsbHVsYXJfQ29tcG9uZW50X3N0YXRzWyAsIC4obWVhbj1tZWRpYW4oZGlmZl9hZ2UpKSwgYnk9IkdPIl1bb3JkZXIoLW1lYW4pXSRHTwpHT19DZWxsdWxhcl9Db21wb25lbnRfc3RhdHMkR08gPC0gZmFjdG9yKEdPX0NlbGx1bGFyX0NvbXBvbmVudF9zdGF0cyRHTywgbGV2ZWxzPSBkaWZmX2FnZV9sZXZlbHMpCgoKClN1cF9HT190aW1lLkIgPC0gZ2dwbG90KEdPX0NlbGx1bGFyX0NvbXBvbmVudF9zdGF0cykgKwogIGdlb21fdGlsZShhZXMoIGRpZmZfYWdlLCBHTywgZmlsbCA9IGZyYWN0aW9uKSkgKwogIGdlb21fdGV4dChhZXMoZGlmZl9hZ2UsIEdPLCBsYWJlbCA9IE4pLCBjb2xvcj0id2hpdGUiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9ImdyZXkiLCBoaWdoPSJyZWQiICkrCiAgdGhlbWVfYncoKSsKICBsYWJzKGZpbGwgPSAiR2VuZSBmcmFjdGlvbiIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDApLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSBOQSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCgoKYGBgCgoKCmBgYHtyfQoKbGlicmFyeShnZ3B1YnIpCgoKR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHkgPC0gIG1lcmdlKEdPX0Jpb2xvZ2ljYWxfUHJvY2VzcywgIFBQSV9kaWZmX2FnZV9ITk1GWywgYygiZXhvbl9JRCIsICJtYXBwZWRfZ2VuZSIsICJiZXR3ZWVubmVzcyIsICJlaWdlbl9jZW50cmFsaXR5IiwgImhhcm1vbmljX2NlbnRyYWxpdHkiLCAiZGVncmVlX2NlbnRyYWxpdHkiLCAidHlwZSIpIF0sIGJ5PWMoImV4b25fSUQiLCAibWFwcGVkX2dlbmUiKSkKCgpHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSA8LSB1bmlxdWUoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHlbLCBjKCJtYXBwZWRfZ2VuZSIsICJHTyIsICJiZXR3ZWVubmVzcyIsICJlaWdlbl9jZW50cmFsaXR5IiwgImhhcm1vbmljX2NlbnRyYWxpdHkiLCAiZGVncmVlX2NlbnRyYWxpdHkiKV0pW2hhcm1vbmljX2NlbnRyYWxpdHk+MTBdICAjRmlsdGVybmluZyBub2RlcyB0aGF0IGFyZSBub3QgY29uZWN0ZWQgdG8gdGhlIG1haW4gbmV0d29yawoKCkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5JEdPIDwtIGZhY3RvcihHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRHTywgIGxldmVscyA9IEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5WyAsIC4obWVkaWFuPW1lZGlhbihoYXJtb25pY19jZW50cmFsaXR5KSkgLCBieT0iR08iIF1bb3JkZXIoLW1lZGlhbildJEdPKQoKCmdncGxvdCh1bmlxdWUoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHlbLCBjKCJtYXBwZWRfZ2VuZSIsICJHTyIsICJiZXR3ZWVubmVzcyIsICJlaWdlbl9jZW50cmFsaXR5IiwgImhhcm1vbmljX2NlbnRyYWxpdHkiLCAiZGVncmVlX2NlbnRyYWxpdHkiKV0pW2hhcm1vbmljX2NlbnRyYWxpdHk+MTBdICkgICsKICBnZW9tX2JveHBsb3QoYWVzKEdPLCBoYXJtb25pY19jZW50cmFsaXR5ICApICkgKwogICAgeWxhYigiZWlnZW5jZW50cmFsaXR5IikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjYpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKCgpHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRHTyA8LSBmYWN0b3IoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHkkR08sICBsZXZlbHMgPSBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eVsgLCAuKG1lZGlhbj1tZWRpYW4oZWlnZW5fY2VudHJhbGl0eSkpICwgYnk9IkdPIiBdW29yZGVyKC1tZWRpYW4pXSRHTykKCgpnZ3Bsb3QoIEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5ICkgICsKICBnZW9tX2JveHBsb3QoYWVzKEdPLCBlaWdlbl9jZW50cmFsaXR5ICApICkgKwogICAgeWxhYigiZWlnZW5jZW50cmFsaXR5IikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjYpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHkkR08gPC0gZmFjdG9yKEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5JEdPLCAgbGV2ZWxzID0gR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHlbICwgLihtZWRpYW49bWVkaWFuKGJldHdlZW5uZXNzKSkgLCBieT0iR08iIF1bb3JkZXIoLW1lZGlhbildJEdPKQoKCmdncGxvdCh1bmlxdWUoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHlbLCBjKCJtYXBwZWRfZ2VuZSIsICJHTyIsICJiZXR3ZWVubmVzcyIsICJlaWdlbl9jZW50cmFsaXR5IiwgImhhcm1vbmljX2NlbnRyYWxpdHkiLCAiZGVncmVlX2NlbnRyYWxpdHkiKV0pW2hhcm1vbmljX2NlbnRyYWxpdHk+MTBdICkgICsKICBnZW9tX2JveHBsb3QoYWVzKEdPLCBsb2cxMChiZXR3ZWVubmVzcykpICAgKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuNiksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0gNywgZmlnLndpZHRoPTV9CkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5JEdPIDwtIGZhY3RvcihHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRHTywgIGxldmVscyA9IEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5WyAsIC4obWVkaWFuPW1lZGlhbihlaWdlbl9jZW50cmFsaXR5KSkgLCBieT0iR08iIF1bb3JkZXIoLW1lZGlhbildJEdPKQoKCgoKCm15X2NvbXBhcmlzb25zIDwtIGxpc3QoYygidmVzaWNsZV9tZWRpYXRlZF90cmFuc3BvcnQiLCAiY3l0b3NrZWxldG9uX29yZ2FuaXphdGlvbiIgKSwKICAgICAgICAgICAgICAgICAgICAgICBjKCJ2ZXNpY2xlX21lZGlhdGVkX3RyYW5zcG9ydCIsICJzaWduYWxfdHJhbnNkdWN0aW9uIiApLAogICAgICAgICAgICAgICAgICAgICAgIGMoInZlc2ljbGVfbWVkaWF0ZWRfdHJhbnNwb3J0IiwgIm5lcnZvdXNfc3lzdGVtX2RldmVsb3BtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgYygidmVzaWNsZV9tZWRpYXRlZF90cmFuc3BvcnQiLCAic3luYXBzZV9hc3NlbWJseSIgKSwKICAgICAgICAgICAgICAgICAgICAgICBjKCJjeXRvc2tlbGV0b25fb3JnYW5pemF0aW9uIiwgInNpZ25hbF90cmFuc2R1Y3Rpb24iICksCiAgICAgICAgICAgICAgICAgICAgICAgYygiY3l0b3NrZWxldG9uX29yZ2FuaXphdGlvbiIsICJuZXJ2b3VzX3N5c3RlbV9kZXZlbG9wbWVudCIgKSwKICAgICAgICAgICAgICAgICAgICAgICBjKCJjeXRvc2tlbGV0b25fb3JnYW5pemF0aW9uIiwgInN5bmFwc2VfYXNzZW1ibHkiKSwKICAgICAgICAgICAgICAgICAgICAgICBjKCJzaWduYWxfdHJhbnNkdWN0aW9uIiwgIm5lcnZvdXNfc3lzdGVtX2RldmVsb3BtZW50IiApLAogICAgICAgICAgICAgICAgICAgICAgIGMoInNpZ25hbF90cmFuc2R1Y3Rpb24iLCAibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiICksCiAgICAgICAgICAgICAgICAgICAgICAgYygibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiLCAic3luYXBzZV9hc3NlbWJseSIgKQogICAgICAgICAgICAgICAgICAgICAgICkKCgpnZ3Bsb3QoIEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5LCBhZXMoR08sIGVpZ2VuX2NlbnRyYWxpdHkgICkgICkgICsKICBnZW9tX2JveHBsb3QoKSArCiAgICB5bGFiKCJlaWdlbmNlbnRyYWxpdHkiKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNiksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3VyID0gTkEpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBnZW9tX3NpZ25pZihjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zLCAKICAgICAgICAgICAgICBtYXBfc2lnbmlmX2xldmVsPVRSVUUgLCB5X3Bvc2l0aW9uID0gIHNlcSgwLjksIDEuOSwgMC4xKSkKCmBgYAoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9IDcsIGZpZy53aWR0aD01fQpHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRHTyA8LSBmYWN0b3IoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHkkR08sICBsZXZlbHMgPSBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eVsgLCAuKG1lZGlhbj1tZWRpYW4oZWlnZW5fY2VudHJhbGl0eSkpICwgYnk9IkdPIiBdW29yZGVyKC1tZWRpYW4pXSRHTykKCgoKCgpteV9jb21wYXJpc29ucyA8LSBsaXN0KCNjKCJ2ZXNpY2xlX21lZGlhdGVkX3RyYW5zcG9ydCIsICJjeXRvc2tlbGV0b25fb3JnYW5pemF0aW9uIiApLAogICAgICAgICAgICAgICAgICAgICAgIGMoInZlc2ljbGVfbWVkaWF0ZWRfdHJhbnNwb3J0IiwgInNpZ25hbF90cmFuc2R1Y3Rpb24iICksCiAgICAgICAgICAgICAgICAgICAgICAgYygidmVzaWNsZV9tZWRpYXRlZF90cmFuc3BvcnQiLCAibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICBjKCJ2ZXNpY2xlX21lZGlhdGVkX3RyYW5zcG9ydCIsICJzeW5hcHNlX2Fzc2VtYmx5IiApLAogICAgICAgICAgICAgICAgICAgICAgIGMoImN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24iLCAic2lnbmFsX3RyYW5zZHVjdGlvbiIgKSwKICAgICAgICAgICAgICAgICAgICAgICBjKCJjeXRvc2tlbGV0b25fb3JnYW5pemF0aW9uIiwgIm5lcnZvdXNfc3lzdGVtX2RldmVsb3BtZW50IiApLAogICAgICAgICAgICAgICAgICAgICAgIGMoImN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24iLCAic3luYXBzZV9hc3NlbWJseSIpCiAgICAgICAgICAgICAgICAgICAgICAgI2MoInNpZ25hbF90cmFuc2R1Y3Rpb24iLCAibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiICksCiAgICAgICAgICAgICAgICAgICAgICAgI2MoInNpZ25hbF90cmFuc2R1Y3Rpb24iLCAibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiICksCiAgICAgICAgICAgICAgICAgICAgICAgI2MoIm5lcnZvdXNfc3lzdGVtX2RldmVsb3BtZW50IiwgInN5bmFwc2VfYXNzZW1ibHkiICkKICAgICAgICAgICAgICAgICAgICAgICApCgoKRjZIIDwtICBnZ3Bsb3QoIEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5LCBhZXMoR08sIGVpZ2VuX2NlbnRyYWxpdHkgICkgICkgICsKICBnZW9tX2JveHBsb3QoKSArCiAgICB5bGFiKCJFaWdlbmNlbnRyYWxpdHkiKSArCiAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjYpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9IE5BKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgZ2dzaWduaWY6Omdlb21fc2lnbmlmKHRlc3QgPSAid2lsY294LnRlc3QiLCBjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zLCBzdGVwX2luY3JlYXNlPTAuMTUgLCB0ZXN0LmFyZ3MgPSBsaXN0KGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBwYWlyZWQgPSBGQUxTRSksIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiVmVzaWNsZSBtZWRpYXRlZCB0cmFuc3BvcnR0IiwgIkN5dG9za2VsZXRvbiBvcmdhbml6YXRpb24iLCAiU2lnbmFsIHRyYW5zZHVjdGlvbiIsICJOZXJ2b3VzIHN5c3RlbSBkZXZlbG9wbWVudCIsICJTeW5hcHNlIGFzc2VtYmx5IikpCgpGNkgKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PSA3LCBmaWcud2lkdGg9NX0KCkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5X0hOTV9hZ2UgPC0gbWVyZ2UoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHksIERlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbF9QUElbaXMubmEoZGlmZl9hZ2UueCkhPVRSVUVdWyAsIC4obWluX2FnZV9ITk09bWluKGRpZmZfYWdlLngpKSAgLCBieT0ibWFwcGVkX2dlbmUiIF0sIGJ5PSJtYXBwZWRfZ2VuZSIpCgprcnVza2FsLnRlc3QoZGF0YSA9IEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5X0hOTV9hZ2UsICBtaW5fYWdlX0hOTSB+IEdPKQoKCm15X2NvbXBhcmlzb25zIDwtIGxpc3QoI2MoInZlc2ljbGVfbWVkaWF0ZWRfdHJhbnNwb3J0IiwgImN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24iICksCiAgICAgICAgICAgICAgICAgICAgICAgI2MoInZlc2ljbGVfbWVkaWF0ZWRfdHJhbnNwb3J0IiwgInNpZ25hbF90cmFuc2R1Y3Rpb24iICksCiAgICAgICAgICAgICAgICAgICAgICAgI2MoInZlc2ljbGVfbWVkaWF0ZWRfdHJhbnNwb3J0IiwgIm5lcnZvdXNfc3lzdGVtX2RldmVsb3BtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgI2MoInZlc2ljbGVfbWVkaWF0ZWRfdHJhbnNwb3J0IiwgInN5bmFwc2VfYXNzZW1ibHkiICksCiAgICAgICAgICAgICAgICAgICAgICAgYygiY3l0b3NrZWxldG9uX29yZ2FuaXphdGlvbiIsICJzaWduYWxfdHJhbnNkdWN0aW9uIiApLAogICAgICAgICAgICAgICAgICAgICAgIGMoImN5dG9za2VsZXRvbl9vcmdhbml6YXRpb24iLCAibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiICksCiAgICAgICAgICAgICAgICAgICAgICAgYygiY3l0b3NrZWxldG9uX29yZ2FuaXphdGlvbiIsICJzeW5hcHNlX2Fzc2VtYmx5IikKICAgICAgICAgICAgICAgICAgICAgICAjYygic2lnbmFsX3RyYW5zZHVjdGlvbiIsICJuZXJ2b3VzX3N5c3RlbV9kZXZlbG9wbWVudCIgKSwKICAgICAgICAgICAgICAgICAgICAgICAjYygic2lnbmFsX3RyYW5zZHVjdGlvbiIsICJuZXJ2b3VzX3N5c3RlbV9kZXZlbG9wbWVudCIgKSwKICAgICAgICAgICAgICAgICAgICAgICAjYygibmVydm91c19zeXN0ZW1fZGV2ZWxvcG1lbnQiLCAic3luYXBzZV9hc3NlbWJseSIgKQogICAgICAgICAgICAgICAgICAgICAgICkKCgpGNkkgPC0gZ2dwbG90KCBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eV9ITk1fYWdlLCBhZXMoR08sIG1pbl9hZ2VfSE5NICApICApICArCiAgZ2VvbV9ib3hwbG90KCkgKwogICAgeWxhYigiRWFybGllc3QgbWljcm9leG9uIGFsdGVybmF0aXZlIGluY2x1c2lvbiBwZXIgZ2VuZSIpICsKICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNiksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoY29sb3VyID0gTkEpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMTAuNSwxNi41LDEpKSArCiAgZ2dzaWduaWY6Omdlb21fc2lnbmlmKHRlc3QgPSAid2lsY294LnRlc3QiLCBjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zLCBzdGVwX2luY3JlYXNlPTAuMTUgLCB0ZXN0LmFyZ3MgPSBsaXN0KGFsdGVybmF0aXZlID0gImxlc3MiLCBwYWlyZWQgPSBGQUxTRSksIG1hcF9zaWduaWZfbGV2ZWwgPSBUUlVFKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiVmVzaWNsZSBtZWRpYXRlZCB0cmFuc3BvcnR0IiwgIkN5dG9za2VsZXRvbiBvcmdhbml6YXRpb24iLCAiU2lnbmFsIHRyYW5zZHVjdGlvbiIsICJOZXJ2b3VzIHN5c3RlbSBkZXZlbG9wbWVudCIsICJTeW5hcHNlIGFzc2VtYmx5IikpCgoKCmtydXNrYWwudGVzdChHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eV9ITk1fYWdlJG1pbl9hZ2VfSE5NLCBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eV9ITk1fYWdlJEdPKQpwYWlyd2lzZS53aWxjb3gudGVzdChHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eV9ITk1fYWdlJG1pbl9hZ2VfSE5NLCBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eV9ITk1fYWdlJEdPKQoKYGBgCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTE1LCBmaWcud2lkdGg9Ny41fQoKRjZISSA8LSBwbG90X2dyaWQoRjZIICwgRjZJICwgbGFiZWxzID0gYyggJ0gnLCAnSScpLCBucm93PTEpCgpGNi5ib3R0b20gPC0gcGxvdF9ncmlkKEY2RkcsIEY2SEksIG5jb2w9MSwgcmVsX2hlaWdodHMgICA9IGMoMiwxKSkKRjYuYm90dG9tCmBgYAoKCgpgYGB7cn0KbGlicmFyeShnZ3N0YXRzcGxvdCkKZGZfcGFpciA8LSBnZ3N0YXRzcGxvdDo6cGFpcndpc2VfcChHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSwgZWlnZW5fY2VudHJhbGl0eSwgIHR5cGUgPSAibm9ucGFyYW1ldHJpYyIsIEdPKQoKYGBgCgoKCmBgYHtyfQprcnVza2FsLnRlc3QoZGF0YSA9IEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5LCAgZWlnZW5fY2VudHJhbGl0eSB+IEdPKQprcnVza2FsLnRlc3QoZGF0YSA9IEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5LCAgaGFybW9uaWNfY2VudHJhbGl0eSB+IEdPKQoKCgpwYWlyd2lzZS53aWxjb3gudGVzdChHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRlaWdlbl9jZW50cmFsaXR5LCBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRHTykKcGFpcndpc2Uud2lsY294LnRlc3QoR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHkkaGFybW9uaWNfY2VudHJhbGl0eSwgR09fQmlvbG9naWNhbF9Qcm9jZXNzX2NlbnRyYWxpdHkkR08pCmBgYAoKYGBge3J9CnBhaXJ3aXNlLndpbGNveC50ZXN0KEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5JGVpZ2VuX2NlbnRyYWxpdHksIEdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc19jZW50cmFsaXR5JEdPKQpwYWlyd2lzZS53aWxjb3gudGVzdChHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRoYXJtb25pY19jZW50cmFsaXR5LCBHT19CaW9sb2dpY2FsX1Byb2Nlc3NfY2VudHJhbGl0eSRHTykKYGBgCgoKCgoKYGBge3J9CkJpb2xvZ2ljYWxfUHJvY2VzcyA8LSBmcmVhZCgiLi4vRmlndXJlcy9OZXdfRmlndXJlIDUvU1RSSU5HL0dPL01FX2dlbmVzX2JhY2tncm91bmQvQmlvbG9naWNhbF9Qcm9jZXNzLnRzdiIpCkNlbGx1bGFyX0NvbXBvbmVudCA8LSBmcmVhZCgiLi4vRmlndXJlcy9OZXdfRmlndXJlIDUvU1RSSU5HL0dPL01FX2dlbmVzX2JhY2tncm91bmQvQ2VsbHVsYXJfQ29tcG9uZW50LnRzdiIpClByb3RlaW5fRG9tYWlucyA8LSBmcmVhZCgiLi4vRmlndXJlcy9OZXdfRmlndXJlIDUvU1RSSU5HL0dPL01FX2dlbmVzX2JhY2tncm91bmQvSU5URVJQUk8gUHJvdGVpbiBEb21haW5zIGFuZCBGZWF0dXJlcy50c3YiKQoKCgpCaW9sb2dpY2FsX1Byb2Nlc3NbICwgYDo9YCggbWludXNfbG9nMTBfRkRSPS1sb2cxMChgZmFsc2UgZGlzY292ZXJ5IHJhdGVgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdPX3NpemU9KGBvYnNlcnZlZCBnZW5lIGNvdW50YCArIGBiYWNrZ3JvdW5kIGdlbmUgY291bnRgKSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHT19mcmFjdGlvbj0oYG9ic2VydmVkIGdlbmUgY291bnRgL2BiYWNrZ3JvdW5kIGdlbmUgY291bnRgKSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHT19jbGFzcz0iQmlvbG9naWNhbCBQcm9jZXNzIikgXQoKCgpDZWxsdWxhcl9Db21wb25lbnRbICwgYDo9YCggbWludXNfbG9nMTBfRkRSPS1sb2cxMChgZmFsc2UgZGlzY292ZXJ5IHJhdGVgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdPX3NpemU9KGBvYnNlcnZlZCBnZW5lIGNvdW50YCArIGBiYWNrZ3JvdW5kIGdlbmUgY291bnRgKSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHT19mcmFjdGlvbj0oYG9ic2VydmVkIGdlbmUgY291bnRgL2BiYWNrZ3JvdW5kIGdlbmUgY291bnRgKSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHT19jbGFzcz0iQ2VsbHVsYXIgQ29tcG9uZW50IikgXQoKClByb3RlaW5fRG9tYWluc1sgLCBgOj1gKCBtaW51c19sb2cxMF9GRFI9LWxvZzEwKGBmYWxzZSBkaXNjb3ZlcnkgcmF0ZWApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgR09fc2l6ZT0oYG9ic2VydmVkIGdlbmUgY291bnRgICsgYGJhY2tncm91bmQgZ2VuZSBjb3VudGApICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdPX2ZyYWN0aW9uPShgb2JzZXJ2ZWQgZ2VuZSBjb3VudGAvYGJhY2tncm91bmQgZ2VuZSBjb3VudGApICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdPX2NsYXNzPSJJTlRFUlBSTyBQcm90ZWluIERvbWFpbnMiKSBdCgoKVG90YWxfR08gPC0gcmJpbmQoQmlvbG9naWNhbF9Qcm9jZXNzLCBDZWxsdWxhcl9Db21wb25lbnQsIFByb3RlaW5fRG9tYWlucykKCgoKZ2dwbG90KFRvdGFsX0dPW0dPX3NpemU+MjBdKSArIAogIGdlb21fcG9pbnQoIGFlcyhHT19mcmFjdGlvbiwgbWludXNfbG9nMTBfRkRSLCBzaXplPWxvZzIoR09fc2l6ZSksIGNvbG91cj1HT19jbGFzcyksICBhbHBoYT0wLjIpICsKICBmYWNldF9ncmlkKCAuIH4gIEdPX2NsYXNzICkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikKYGBgCgoKCgoKCmBgYHtyfQpnZ3Bsb3QoUFBJX2RpZmZfYWdlX0hOTV9zdGF0c19FQykgKwogIGdlb21fYmFyKGFlcyhtaW5fZGlmX2FnZSwgZmlsbD1jZW50cmFsKSwgc3RhdCA9ICJjb3VudCIsIHBvc2l0aW9uPSJmaWxsIiApICsKICB4bGFiKCJFYXJsaWVzdCBtaWNyb2V4b24gZGlmZmVyZW50aWFsIGluY2x1c2lvbiBkZXRlY3Rpb24gcGVyIGdlbmUgKERQQykiKSsKICB5bGFiKCJQcm90ZWluIHR5cGUgcHJvcG9ydGlvbiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiUHJvdGVpbiB0eXBlIiwgbGFiZWxzID0gYygiTm9uLWNlbnRyYWwiLCAiQ2VudHJhbCIpKSAgKwogICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgoKZ2dwbG90KFBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfQikgKwogIGdlb21fYmFyKGFlcyhtaW5fZGlmX2FnZSwgZmlsbD1jZW50cmFsKSwgc3RhdCA9ICJjb3VudCIsIHBvc2l0aW9uPSJmaWxsIiApICsKICB4bGFiKCJFYXJsaWVzdCBtaWNyb2V4b24gZGlmZmVyZW50aWFsIGluY2x1c2lvbiBkZXRlY3Rpb24gcGVyIGdlbmUgKERQQykiKSsKICB5bGFiKCJQcm90ZWluIHR5cGUgcHJvcG9ydGlvbiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiUHJvdGVpbiB0eXBlIiwgbGFiZWxzID0gYygiTm9uLWNlbnRyYWwiLCAiQ2VudHJhbCIpKSAgKwogICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgpgYGAKCiNaZWJyYWZpc2gKCmBgYHtyLCBmaWd1cmV9Cgp0b3RhbF96ZWJyYSA8LSAgZnJlYWQoIi4uLy4uL1plYnJhZmlzaC9GaW5hbF9SZXBvcnQvb3V0X2ZpbHRlcmVkX01FLnR4dCIpCnRvdGFsX3plYnJhX2NvdiA8LSBmcmVhZCgiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9vdXRfZmlsdGVyZWRfTUUuY292LnR4dCIpCgoKZXhvbnMuemVicmEgPC0gZnJlYWQoIi4uLy4uL1plYnJhZmlzaC9kYW5SZXIxMS5lbnNlbWJsLmJlZDEyLmV4b25zIikKCgptb3VzZV90b196ZWJyYSA8LSBmcmVhZCgiLi4vLi4vWmVicmFmaXNoL0NvbnNlcnZlZC9vdXQuaGlnaF9xdWFsaXR5LnR4dC5tbTEwLmJlZC5saWZ0T3Zlcl9taW5NYXRjaF8wLjAxLmRhblJlcjExLmNsb3Nlc3RfZC5vdXQuaGlnaF9xdWFsaXR5LnR4dC5kYW5SZXIxMS5iZWQuZm9ybWF0dGVkIikKemVicmFfdG9fbW91c2UgPC0gZnJlYWQoIi4uLy4uL1plYnJhZmlzaC9Db25zZXJ2ZWQvb3V0LmhpZ2hfcXVhbGl0eS50eHQuZGFuUmVyMTEuYmVkLmxpZnRPdmVyX21pbk1hdGNoXzAuMDEubW0xMC5jbG9zZXN0X2Qub3V0LmhpZ2hfcXVhbGl0eS50eHQubW0xMC5mb3JtYXR0ZWQiKQoKCgptb3VzZV90b196ZWJyYSA8LSBmcmVhZCgiLi4vLi4vWmVicmFmaXNoL0NvbnNlcnZlZC9PbGQvb3V0LmhpZ2hfcXVhbGl0eS5tbTEwLmJlZF9saWZ0b3Zlcl9tbTEwdG9kYW5SZXIxMS5vdmVybGFwX3dvLm91dC5oaWdoX3F1YWxpdHkuYmVkIikKemVicmFfdG9fbW91c2UgPC0gZnJlYWQoIi4uLy4uL1plYnJhZmlzaC9Db25zZXJ2ZWQvT2xkL291dC5oaWdoX3F1YWxpdHkuYmVkLmxpZnRvdmVyXzAuMDAxX21tMTAub3ZlcmxhcF93by5vdXQuaGlnaF9xdWFsaXR5LmJlZC5saWZ0b3Zlcl8wLjAwMV9tbTEwIikKCk1vdXNlX1plYnJhLklEcyA8LSB1bmlxdWUocmJpbmQobW91c2VfdG9femVicmFbICAsIC4oTUUubW91c2U9VjQsIE1FLnplYnJhPVYxMCApIF0sIHplYnJhX3RvX21vdXNlWyAsIC4oTUUubW91c2U9VjEwLCBNRS56ZWJyYT1WNCkgXSApKSAgI0luIGhlcmUgd2UgYXJlIGFscmVhZHkgYXBwbHlpbmcgYSBmaWx0ZXIgb2YgMC44IGxlbmdoCgoKI1ZpZXcoTW91c2VfWmVicmEuSURzWywgLihtb3VzZS5sZW4sIHplYnJhLmxlbiwgYWJzKG1vdXNlLmxlbi1hYnMobW91c2UubGVuLXplYnJhLmxlbikpL21heChtb3VzZS5sZW4semVicmEubGVuKSApXSApCgoKbW91c2VfbGVuIDwtIGMobW91c2VfdG9femVicmFbLCBWMy1WMl0sIHplYnJhX3RvX21vdXNlWywgVjktVjhdKQpuYW1lcyhtb3VzZV9sZW4pIDwtIGMobW91c2VfdG9femVicmEkVjQsIHplYnJhX3RvX21vdXNlJFYxMCkKCgp6ZWJyYV9sZW4gPC0gIGMoemVicmFfdG9fbW91c2VbLCBWMy1WMl0sIG1vdXNlX3RvX3plYnJhWywgVjktVjhdKQpuYW1lcyh6ZWJyYV9sZW4pIDwtIGMoemVicmFfdG9fbW91c2UkVjQsIG1vdXNlX3RvX3plYnJhJFYxMCkKCgoKCk1vdXNlX1plYnJhLklEc1ssIG1vdXNlLmxlbjo9bW91c2VfbGVuW01FLm1vdXNlXV0KTW91c2VfWmVicmEuSURzWywgemVicmEubGVuOj16ZWJyYV9sZW5bTUUuemVicmFdXQoKCmdncGxvdChNb3VzZV9aZWJyYS5JRHMpICsKICBnZW9tX2JpbjJkKGFlcyhtb3VzZS5sZW4sIHplYnJhLmxlbiksIGJpbnMgPSAzMCwgY29sb3IgPSJ3aGl0ZSIpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICAiIzAwQUZCQiIsIGhpZ2ggPSAiI0ZDNEUwNyIpCgoKTW91c2VfWmVicmEuSURzIDwtIE1vdXNlX1plYnJhLklEc1ttb3VzZS5sZW49PXplYnJhLmxlbiwgXQoKTW91c2VfWmVicmEuSURzLnRhYmxlIDwtIG1lcmdlKE1vdXNlX1plYnJhLklEcywgTUVfY2x1c3Rlcl9uYW1lc1sgLCBjKCJNRV9jbHVzdGVyLm5hbWUiICwgIk1FX2NsdXN0ZXIudHlwZSIpXSwgYnk9Ik1FX2NsdXN0ZXIubmFtZSIsIGFsbCA9IFRSVUUpCgoKTW91c2VfWmVicmEuSURzLnRhYmxlIDwtIE1vdXNlX1plYnJhLklEcy50YWJsZVsgLCAuKG1vdXNlLmNvb3JkPU1FLm1vdXNlLCBtb3VzZS5sZW49bW91c2UubGVuLCBtb3VzZS5jbHVzdGVyX25hbWU9TUVfY2x1c3Rlci5uYW1lLCBtb3VzZS5jbHVzdGVyX3R5cGU9TUVfY2x1c3Rlci50eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbW91c2UuYW5ubz10eXBlLCBtb3VzZS5lbnNlbWJsPWVuc2VtYmxlX21vdXNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEuY29vcmQ9TUUuemVicmEsIHplYnJhLmxlbj16ZWJyYS5sZW4sIHplYnJhLmVuc2VtYmw9ZW5zZW1ibGVfemVicmEpXSAKCgppcy5kYXRhLnRhYmxlKE1vdXNlX1plYnJhLklEcy50YWJsZSkKCk1vdXNlX1plYnJhLklEcy50YWJsZSA8LSB1bmlxdWUobWVyZ2UoTW91c2VfWmVicmEuSURzLnRhYmxlLCBnZW5lX3RhYmxlLlRPVEFMWyAsIGMoIk1FIiwgIm1naV9zeW1ib2wiKV0sIGJ5Lng9Im1vdXNlLmNvb3JkIiAsIGJ5Lnk9Ik1FIiApKQoKZGl2XzMgPC0gZnVuY3Rpb24oeCkgeCAlJSAzID09IDBdCgpNb3VzZV9aZWJyYS5JRHMudGFibGVbICwgLihtb3VzZS5jb29yZCwgbWdpX3N5bWJvbCwgbW91c2UuY2x1c3Rlcl9uYW1lLCBtb3VzZS5jbHVzdGVyX3R5cGUsIG1vdXNlLmxlbiwgbW91c2Uuc3ltPShtb3VzZS5sZW4lJTMgPT0gMCksIG1vdXNlLmVuc2VtYmwsIHplYnJhLmNvb3JkLCB6ZWJyYS5sZW4sIHplYnJhLnN5bT0oemVicmEubGVuJSUzID09IDApLCB6ZWJyYS5lbnNlbWJsKSAgXQoKCk1vdXNlX1plYnJhLklEcy50aGVzaXMudGFibGUgPC0gdW5pcXVlKE1vdXNlX1plYnJhLklEcy50YWJsZVsgLCAuKG1vdXNlLmNvb3JkLCBtZ2lfc3ltYm9sLCBtb3VzZS5jbHVzdGVyX25hbWUsIG1vdXNlLmNsdXN0ZXJfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW91c2UubGVuLCBtb3VzZS5zeW09KG1vdXNlLmxlbiUlMyA9PSAwKSwgbW91c2UuZW5zZW1ibCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEubnVtPS5OLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6ZWJyYS5jb29yZHM9YXMuY2hhcmFjdGVyKGxpc3QoemVicmEuY29vcmQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEubGVucz1hcy5jaGFyYWN0ZXIobGlzdCh6ZWJyYS5sZW4pKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEuc3ltcz1hcy5jaGFyYWN0ZXIobGlzdCgoemVicmEubGVuJSUzID09IDApKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHplYnJhLmVuc2VtYmxzPWFzLmNoYXJhY3RlcihsaXN0KHplYnJhLmVuc2VtYmwpICkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSBtb3VzZS5jb29yZCAgXVtvcmRlcihtZ2lfc3ltYm9sLCBtb3VzZS5jb29yZCldKQoKCgpNb3VzZV9aZWJyYS5JRHMudGhlc2lzLnRhYmxlWyAsIGA6PWAoIHplYnJhLmNvb3Jkcz1nc3ViKCdeY1xcKHxcXCkkfFwgfFwiJyAsICIiLCB6ZWJyYS5jb29yZHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHplYnJhLmxlbnM9Z3N1YignXmNcXCh8XFwpJHxcIHxcIicgLCAiIiwgemVicmEubGVucyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEuc3ltcz1nc3ViKCdeY1xcKHxcXCkkfFwgfFwiJyAsICIiLCB6ZWJyYS5zeW1zKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6ZWJyYS5lbnNlbWJscz1nc3ViKCdeY1xcKHxcXCkkfFwgfFwiJyAsICIiLCB6ZWJyYS5lbnNlbWJscykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApXQoKCgoKZndyaXRlKE1vdXNlX1plYnJhLklEcy50YWJsZSwgIi4uL0ZpbmFsX0ZpZ3VyZXMvU3VwcGxlbWVudGFyeS9Nb3VzZV9aZWJyYV9taWNyb2V4b25zLnRzdiIsIGFwcGVuZCA9IEZBTFNFLCBxdW90ZSA9ICJhdXRvIiwgc2VwID0gIiwiLCAgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUgKQpmd3JpdGUoTW91c2VfWmVicmEuSURzLnRoZXNpcy50YWJsZSwgIn4vR29vZ2xlX0RyaXZlL1RoZXNpcy9Nb3VzZV96ZWJyYWZpc2gudHN2IiwgYXBwZW5kID0gRkFMU0UsIHF1b3RlID0gImF1dG8iLCBzZXAgPSAiXHQiLCAgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUgKQpgYGAKICAKYGBge3J9CgpNb3VzZV9aZWJyYS5JRHMudGFibGUuc3VtbWVyIDwtIG1lcmdlKE1vdXNlX1plYnJhLklEcy50YWJsZSwgRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgLihleG9uX0lELCBNSE4uZGlmZl9hZ2U9ZGlmZl9hZ2UsICBNSE4uY2hhbmdlX2Rpcj1jaGFuZ2VfZGlyKV0sIGJ5Lng9Im1vdXNlLmNvb3JkIiwgYnkueT0iZXhvbl9JRCIsIGFsbC54ID0gVCkKCgpNb3VzZV9aZWJyYS5JRHMudGFibGUuc3VtbWVyIDwtIG1lcmdlKE1vdXNlX1plYnJhLklEcy50YWJsZS5zdW1tZXIsIERlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFsgLCAuKGV4b25fSUQsIEYuZGlmZl9hZ2U9ZGlmZl9hZ2UsICBGLmNoYW5nZV9kaXI9Y2hhbmdlX2RpcildLCBieS54PSJtb3VzZS5jb29yZCIsIGJ5Lnk9ImV4b25fSUQiLCBhbGwueCA9IFQpCgoKZndyaXRlKE1vdXNlX1plYnJhLklEcy50YWJsZS5zdW1tZXIsICIuLi9GaW5hbF9GaWd1cmVzL1N1cHBsZW1lbnRhcnkvTW91c2VfWmVicmFfbWljcm9leG9ucy5zdW1tZXIudHN2IiwgYXBwZW5kID0gRkFMU0UsIHF1b3RlID0gImF1dG8iLCBzZXAgPSAiLCIsICByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSApCgpNb3VzZV9aZWJyYS5JRHMudGFibGUuc3VtbWVyWyFpcy5uYShtb3VzZS5jb29yZCksIF0KYGBgCgogIAoKYGBge3J9CgoKCk1vdXNlX1plYnJhLklEcwoKTUVfY2x1c3RlcnMuaW5mbwpgYGAKCgoKICAKICAKYGBge3J9ICAKTW91c2VfWmVicmEuSURzW01FLm1vdXNlICVpbiUgIG5hbWVzKE1FX2NsdXN0ZXJzKSwgTUVfY2x1c3Rlcjo9TUVfY2x1c3RlcnNbTUUubW91c2VdIF0KCgoKTW91c2VfWmVicmEuSURzPC0gbWVyZ2UoTW91c2VfWmVicmEuSURzICwgCk1FX2NsdXN0ZXJfbmFtZXNbLCBjKCJNRV9jbHVzdGVyIiwgIk1FX2NsdXN0ZXIubmFtZSIpXSAsIGJ5PSJNRV9jbHVzdGVyIiwgYWxsLng9VFJVRSApCgoKZ2dwbG90KE1vdXNlX1plYnJhLklEcykgKwogIGdlb21fYmFyKGFlcyh4PU1FX2NsdXN0ZXIubmFtZSksIHN0YXQ9ImNvdW50IikKCgoKCk1vdXNlX1plYnJhLklEc1sgLCB0eXBlOj0iQW5ub3RhdGVkIiAgXQoKTW91c2VfWmVicmEuSURzWyFNRS5tb3VzZSAlaW4lIG1pY3JvZXhvbnNfVmFzdGRiLCB0eXBlOj0iTWlzc2luZyBpbiBWYXN0REIiICAgXQpNb3VzZV9aZWJyYS5JRHNbIU1FLm1vdXNlICVpbiUgbWljcm9leG9uc19HRU5DT0RFLCB0eXBlOj0iTWlzc2luZyBpbiBHRU5DT0RFIiAgIF0KTW91c2VfWmVicmEuSURzWyFNRS5tb3VzZSAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSAmICFNRS5tb3VzZSAlaW4lIG1pY3JvZXhvbnNfVmFzdGRiICwgdHlwZTo9Ik5vdmVsIiAgIF0KCgpNb3VzZV9aZWJyYS5JRHNbICwgZW5zZW1ibGVfemVicmE6PUZBTFNFICBdCk1vdXNlX1plYnJhLklEc1tNRS56ZWJyYSAlaW4lICBleG9ucy56ZWJyYSRWNCwgZW5zZW1ibGVfemVicmE6PVRSVUUgXQoKTW91c2VfWmVicmEuSURzWyAsIGVuc2VtYmxlX21vdXNlOj1GQUxTRSAgXQpNb3VzZV9aZWJyYS5JRHNbTUUubW91c2UgJWluJSAgbWljcm9leG9uc19HRU5DT0RFLCBlbnNlbWJsZV9tb3VzZTo9VFJVRSBdCgoKCgoKCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbZXhvbl9JRCAlaW4lIE1vdXNlX1plYnJhLklEcyRNRS5tb3VzZV0KCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbXQoKCk1vdXNlX1plYnJhLklEc1tNRS5tb3VzZSAlaW4lIERlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRleG9uX0lEXVsgTUUuemVicmEgJWluJSBleG9ucy56ZWJyYSRWNF0KCiAKCmdncGxvdChNb3VzZV9aZWJyYS5JRHMpICsKICBnZW9tX2JhcihhZXMoeD1NRV9jbHVzdGVyLm5hbWUsIGZpbGw9dHlwZSksIHN0YXQ9ImNvdW50IiwgcG9zaXRpb249ImZpbGwiKQoKCmxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzJE1FLm1vdXNlKSkKCmxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzJE1FLnplYnJhKSkKClBQSV9kaWZmX2FnZV9ITk1GX2NlbnRyYWxbICwgY29uc2VydmVkOj1GQUxTRSBdClBQSV9kaWZmX2FnZV9ITk1GX2NlbnRyYWxbZXhvbl9JRCAlaW4lIE1vdXNlX1plYnJhLklEcyRNRS5tb3VzZSwgY29uc2VydmVkOj1UUlVFIF0KCmdncGxvdChQUElfZGlmZl9hZ2VfSE5NRl9jZW50cmFsKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKGhhcm1vbmljX2NlbnRyYWxpdHksIGRpZmZfYWdlLCAgc2hhcGU9IHR5cGUsIGNvbG91cj1jb25zZXJ2ZWQgICksIHdpZHRoPTAsIGhlaWdodD0wLjEpICsgCiAgeGxhYigiSGFybW9uaWMgQ2VudHJhbGl0eSIpICsKICB5bGFiKCJFYXJsaWVzdCBtaWNyb2V4b24gZGlmZmVyZW50aWFsIGluY2x1c2lvbiBkZXRlY3Rpb24gKERQQykiKSArCiAgIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDEwLjUsMTYuNSwxKSkgKwogICAgZ2VvbV90ZXh0X3JlcGVsKGRhdGE9UFBJX2RpZmZfYWdlX0hOTUZfY2VudHJhbFsgIGNlbnRyYWw9PVRSVUUgIF0sIAogICAgICAgICAgICAgICAgICBhZXMoeD1oYXJtb25pY19jZW50cmFsaXR5LCB5PWRpZmZfYWdlLCAgY29sb3VyPWNvbnNlcnZlZCAgKSwgCiAgICAgICAgICAgICAgICAgIG51ZGdlX3kgICAgICA9IDAuNSwKICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uICAgID0gIngiLAogICAgICAgICAgICAgICAgICBhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC4yLAogICAgICAgICAgICAgICAgICBsYWJlbD1QUElfZGlmZl9hZ2VfSE5NRl9jZW50cmFsW2NlbnRyYWw9PVRSVUUgICwgbWFwcGVkX2dlbmVdLAogICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgoKZ2dwbG90KFBQSV9kaWZmX2FnZV9ITk1GX2NlbnRyYWwpICsKICBnZW9tX2JveHBsb3QoYWVzKGNvbnNlcnZlZCwgbG9nMihiZXR3ZWVubmVzcykgKSkKCmBgYAoKCmBgYHtyfQpNb3VzZV9aZWJyYS5JRHNbZW5zZW1ibGVfemVicmE9PUZBTFNFXQoKCnplYnJhLnplYnJhIDwtICBnZ3Bsb3QoTW91c2VfWmVicmEuSURzKSArIAogIGdlb21fYmFyKGFlcyhNRV9jbHVzdGVyLm5hbWUsIGZpbGw9ZW5zZW1ibGVfemVicmEpLCBzdGF0PSJjb3VudCIgKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCgoKemVicmEubW91c2UgPC0gZ2dwbG90KE1vdXNlX1plYnJhLklEcykgKyAKICBnZW9tX2JhcihhZXMoTUVfY2x1c3Rlci5uYW1lLCBmaWxsPWVuc2VtYmxlX21vdXNlKSwgc3RhdD0iY291bnQiKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpCiAgCmBgYAoKYGBge3IsIH0KCgoKTW91c2VfWmVicmEuSURzLmNsdXN0ZXJfbmFtZXMgPC0gbWVyZ2UoTW91c2VfWmVicmEuSURzLCBNRV9jbHVzdGVyX25hbWVzWywgYygiTUVfY2x1c3Rlci5uYW1lIiwgIk1FX2NsdXN0ZXIudHlwZSIpXSwgYnk9Ik1FX2NsdXN0ZXIubmFtZSIpCk1vdXNlX1plYnJhX3N0YXRzICA8LSBNb3VzZV9aZWJyYS5JRHMuY2x1c3Rlcl9uYW1lc1sgLCAuTiAsIGJ5PWMoIk1FX2NsdXN0ZXIudHlwZSIsICJlbnNlbWJsZV96ZWJyYSIsICJlbnNlbWJsZV9tb3VzZSIpXQoKTW91c2VfWmVicmFfc3RhdHNbICwgVHlwZTo9cGFzdGUoZW5zZW1ibGVfemVicmEsIGVuc2VtYmxlX21vdXNlLCBzZXAgPSAiXyIpIF0KCk1vdXNlX1plYnJhX3N0YXRzJE1FX2NsdXN0ZXIudHlwZSA8LSBmYWN0b3IoTW91c2VfWmVicmFfc3RhdHMkTUVfY2x1c3Rlci50eXBlLCAgbGV2ZWxzPU1vdXNlX1plYnJhX3N0YXRzWyFlbnNlbWJsZV96ZWJyYSAgfCAhZW5zZW1ibGVfbW91c2UgLCBzdW0oTiksIGJ5PWMoIk1FX2NsdXN0ZXIudHlwZSIpXVtvcmRlcihWMSksIE1FX2NsdXN0ZXIudHlwZV0pCgogIAogIAoKRmlnNy5FIDwtIGdncGxvdChNb3VzZV9aZWJyYV9zdGF0c1shZW5zZW1ibGVfemVicmEgIHwgIWVuc2VtYmxlX21vdXNlXSkgKwogIGdlb21fYmFyKGFlcyh4PU1FX2NsdXN0ZXIudHlwZSwgeT1OLCBmaWxsPVR5cGUpLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb249InN0YWNrIiAgKSArIAogIHlsYWIoIk51bWJlciBvZiBtaWNyb2V4b25zIikgKwogIHhsYWIoIk1pY3JvZXhvbiBjbHVzdGVycyIpICsgCiAgIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJUeXBlIiwgbGFiZWxzID0gYygiTWlzc2luZyBpbiBib3RoIiwgIk1pc3NpbmcgaW4gemVicmFmaXNoIiwgIk1pc3NpbmcgaW4gbW91c2UiKSkgKwogICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICAgIHRoZW1lX2J3KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKCgpGaWc3LkUKCmBgYAoKCmBgYHtyfQpsZW5ndGgodW5pcXVlKE1vdXNlX1plYnJhLklEcyRNRS5tb3VzZSkpCmxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzJE1FLnplYnJhKSkKCnJvdW5kKChNb3VzZV9aZWJyYV9zdGF0c1tlbnNlbWJsZV9tb3VzZT09RkFMU0UsIHN1bShOKSBdICogMTAwKSAvIGxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzJE1FLm1vdXNlKSksIDEpCnJvdW5kKChNb3VzZV9aZWJyYV9zdGF0c1tlbnNlbWJsZV96ZWJyYT09RkFMU0UsIHN1bShOKSBdICogMTAwICkgLyBsZW5ndGgodW5pcXVlKE1vdXNlX1plYnJhLklEcyRNRS56ZWJyYSkpLCAxKQpgYGAKCgoKYGBge3J9CmxpYnJhcnkoZ2dzaWduaWYpCgojTW91c2VfWmVicmEuSURzWywgTUVfY2x1c3Rlci5uYW1lOj1NRV9jbHVzdGVyLm5hbWUueF0KCk1vdXNlX1plYnJhLmNvbnNlcnZlZF9mcmFjIDwtIHVuaXF1ZShNb3VzZV9aZWJyYS5JRHNbLCBjKCJNRS5tb3VzZSIsICJNRV9jbHVzdGVyLm5hbWUiKV0pWyAsLk4gLCBieT1NRV9jbHVzdGVyLm5hbWUgXQoKTW91c2VfWmVicmEuY29uc2VydmVkX2ZyYWMgPC0gIG1lcmdlKCBNb3VzZV9aZWJyYS5jb25zZXJ2ZWRfZnJhYyAsIE1FX2NsdXN0ZXJzLm5hbWVzWyAsIC4oVG90YWw9Lk4pICwgYnk9TUVfY2x1c3Rlci5uYW1lXSwgYnk9Ik1FX2NsdXN0ZXIubmFtZSIpCgpNb3VzZV9aZWJyYS5jb25zZXJ2ZWRfZnJhY1ssIHBlcmNldGFnZTo9KE4qMTAwL1RvdGFsKV0KCk1vdXNlX1plYnJhLmNvbnNlcnZlZF9mcmFjW29yZGVyKHBlcmNldGFnZSldCgpNb3VzZV9aZWJyYS5jb25zZXJ2ZWRfZnJhYyA8LSBtZXJnZShNb3VzZV9aZWJyYS5jb25zZXJ2ZWRfZnJhYywgTUVfY2x1c3Rlcl9uYW1lc1ssIGMoIk1FX2NsdXN0ZXIubmFtZSIsICJNRV9jbHVzdGVyLnR5cGUiKV0sIGJ5PSJNRV9jbHVzdGVyLm5hbWUiICkKCk1vdXNlX1plYnJhLmNvbnNlcnZlZF9mcmFjWywgYnJvYWRfY2xhc3M6PSJPdGhlciJdCk1vdXNlX1plYnJhLmNvbnNlcnZlZF9mcmFjW01FX2NsdXN0ZXIudHlwZSAlaW4lIGMoIk5ldXJvbmFsIiwgIk5ldXJvLU11c2N1bGFyIiwgIk5vbi1OZXVyb25hbCIsICJXZWFrLU5ldXJvbmFsIiksIGJyb2FkX2NsYXNzOj0iTmV1cm9uYWwiXQpNb3VzZV9aZWJyYS5jb25zZXJ2ZWRfZnJhY1tNRV9jbHVzdGVyLnR5cGUgJWluJSBjKCJOZXVyby1NdXNjdWxhciIpLCBicm9hZF9jbGFzczo9Ik5ldXJvLU11c2N1bGFyIl0KCkZpZzcuRCA8LSBnZ3Bsb3QoTW91c2VfWmVicmEuY29uc2VydmVkX2ZyYWMsIGFlcyh4ID0gYnJvYWRfY2xhc3MsICB5ID0gcGVyY2V0YWdlICkpICsKICBnZW9tX2ppdHRlciggYWVzKCBjb2xvdXIgPSBNRV9jbHVzdGVyLnR5cGUpLCB3aWR0aD0wLjEpICsKICBnZW9tX3NpZ25pZihjb21wYXJpc29ucyA9IGxpc3QoYygiTmV1cm9uYWwiLCAiT3RoZXIiKSksIG1hcF9zaWduaWZfbGV2ZWw9VFJVRSwgdGVzdD0id2lsY294LnRlc3QiLCBtYXJnaW5fdG9wPTUsICB5X3Bvc2l0aW9uPTM1LCB0ZXN0LmFyZ3MgPSBsaXN0KGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIsIHBhaXJlZCA9IEZBTFNFKSkgKwogIHhsYWIoIk1pY3JvZXhvbiBjbHVzdGVyIHdpdGggbmV1cm9uYWwgcGF0dGVybiIpICsKICB5bGFiKCJQZXJjZW50YWdlIG9mIGNvbnNlcnZlZCBtaWNyb2V4b25zIikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKCkZpZzcuRAoKYGBgCgoKRXhwbG9yaW5nIGxpZnQgemVicmEgdGhhdCBkbyBub3Qgb3ZlcmxhcCB3aXRoIG1vdXNlIG1pY3JvZXhvbnMKCmBgYHtyfQp6ZWJyYS50b3RhbF9saWZ0IDwtIGZyZWFkKCIuLi8uLi9aZWJyYWZpc2gvQ29uc2VydmVkL291dC5oaWdoX3F1YWxpdHkuYmVkLmxpZnRvdmVyXzAuMDAxX21tMTAiKQoKemVicmEudG90YWxfbGlmdFshVjQgJWluJSAgemVicmFfdG9fbW91c2UkVjQsIF0KYGBgCgoKCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQoKcGxvdF9ncmlkKEZpZzcuRCwgRmlnNy5FLCBuY29sPTEpCgpgYGAKCgoKIyMjIyBaZWJyYSBkaWZmCgoKYGBge3J9CgoKZGlmZi5XLmZpbGUgPC0gICIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvMTZNb192c180TW8tVE9UQUwuZGlmZi5taWNyb2V4b25zIgpkaWZmLk1FLmZpbGUgPC0gIi4uLy4uL1plYnJhZmlzaC9GaW5hbF9SZXBvcnQvV2hpcHBldC9EZWx0YS8xNk1vX3ZzXzRNby1UT1RBTC5kaWZmLk1FLm1pY3JvZXhvbnMiCmNvbXBfbmFtZSA9ICIxNk1vX3ZzXzRNby1UT1RBTCIKCgpkaWZmX3plYnJhIDwtIGZ1bmN0aW9uKGRpZmYuVy5maWxlLCBkaWZmLk1FLmZpbGUsIGNvbXBfbmFtZSkgewoKCmRpZmYuVyA8LSBmcmVhZChkaWZmLlcuZmlsZSkKZGlmZi5NRSA8LSBmcmVhZChkaWZmLk1FLmZpbGUpCgpkaWZmLldNRSA8LSBtZXJnZShkaWZmLlcsIGRpZmYuTUUsIGJ5PWMoImV4b25fSUQiLCAiR2VuZSIsICJOb2RlIiwgICJDb29yZCIsICJTdHJhbmQiLCAiVHlwZSIpKQoKZGlmZi5XTUVbLCBOYW1lOj1jb21wX25hbWVdCgpkaWZmLldNRVsgLCBkaWZmOj0iTkEiXQpkaWZmLldNRVsgKERlbHRhUHNpLng+PTAuMSAmICBQcm9iYWJpbGl0eS54ID49IDAuOSkgJiAgKERlbHRhUHNpLnk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSksIGRpZmY6PSJJbmNsdWRlZCJdCmRpZmYuV01FWyAoRGVsdGFQc2kueDw9LTAuMSAmICBQcm9iYWJpbGl0eS54ID49IDAuOSkgJiAgKERlbHRhUHNpLnk8PS0wLjEgJiAgUHJvYmFiaWxpdHkueSA+PSAwLjkpICAsIGRpZmY6PSJFeGNsdWRlZCIgXQoKcmV0dXJuKGRpZmYuV01FKQp9CmBgYAoKCgpgYGB7cn0KWmVicmEuMTZNb192c180TW8uVE9UQUwgPC0gZGlmZl96ZWJyYSgiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhLzE2TW9fdnNfNE1vLVRPVEFMLmRpZmYubWljcm9leG9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi4uLy4uL1plYnJhZmlzaC9GaW5hbF9SZXBvcnQvV2hpcHBldC9EZWx0YS8xNk1vX3ZzXzRNby1UT1RBTC5kaWZmLk1FLm1pY3JvZXhvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTZNb192c180TW8tVE9UQUwiKQoKCgpaZWJyYS4yME1vX3ZzXzE2TW8uWlQxNiA8LSBkaWZmX3plYnJhKCIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvMjBNb192c18xNk1vLVpUMTYuZGlmZi5taWNyb2V4b25zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhLzIwTW9fdnNfMTZNby1aVDE2LmRpZmYuTUUubWljcm9leG9ucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyME1vX3ZzXzE2TW8tWlQxNiIpCgoKWmVicmEuMjBNb192c180TS5aVDE2IDwtIGRpZmZfemVicmEoIi4uLy4uL1plYnJhZmlzaC9GaW5hbF9SZXBvcnQvV2hpcHBldC9EZWx0YS8yME1vX3ZzXzRNLVpUMTYuZGlmZi5taWNyb2V4b25zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhLzIwTW9fdnNfNE0tWlQxNi5kaWZmLk1FLm1pY3JvZXhvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjBNb192c180TS1aVDE2IikKCgoKWmVicmEuMTZNb192c180TW8uWlQxNiA8LSBkaWZmX3plYnJhKCIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvMTZNb192c180TW8tWlQxNi5kaWZmLm1pY3JvZXhvbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvMTZNb192c180TW8tWlQxNi5kaWZmLk1FLm1pY3JvZXhvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTZNb192c180TW8tWlQxNiIpCgoKClplYnJhLjIwTW9fdnNfMTZNby5aVDQgPC0gZGlmZl96ZWJyYSgiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhLzIwTW9fdnNfMTZNby1aVDQuZGlmZi5taWNyb2V4b25zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhLzIwTW9fdnNfMTZNby1aVDQuZGlmZi5NRS5taWNyb2V4b25zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwTW9fdnNfMTZNby1aVDQiKQoKClplYnJhLjIwTW9fdnNfNE0uWlQ0IDwtIGRpZmZfemVicmEoIi4uLy4uL1plYnJhZmlzaC9GaW5hbF9SZXBvcnQvV2hpcHBldC9EZWx0YS8yME1vX3ZzXzRNLVpUNC5kaWZmLm1pY3JvZXhvbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvMjBNb192c180TS1aVDQuZGlmZi5NRS5taWNyb2V4b25zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwTW9fdnNfNE0tWlQ0IikKCgoKWmVicmEuMTZNb192c180TW8uWlQ0IDwtIGRpZmZfemVicmEoIi4uLy4uL1plYnJhZmlzaC9GaW5hbF9SZXBvcnQvV2hpcHBldC9EZWx0YS8xNk1vX3ZzXzRNby1aVDQuZGlmZi5taWNyb2V4b25zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhLzE2TW9fdnNfNE1vLVpUNC5kaWZmLk1FLm1pY3JvZXhvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTZNb192c180TW8tWlQ0IikKCgoKClplYnJhLlpUMTZfdnNfWlQ0LjIwTSA8LSBkaWZmX3plYnJhKCIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvWlQxNl92c19aVDQtMjBNby5kaWZmLm1pY3JvZXhvbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvWlQxNl92c19aVDQtMjBNby5kaWZmLk1FLm1pY3JvZXhvbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiWlQxNl92c19aVDQtMjBNbyIpCgpaZWJyYS5aVDE2X3ZzX1pUNC4xNk0gPC0gZGlmZl96ZWJyYSgiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhL1pUMTZfdnNfWlQ0LTE2TW8uZGlmZi5taWNyb2V4b25zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhL1pUMTZfdnNfWlQ0LTE2TW8uZGlmZi5NRS5taWNyb2V4b25zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlpUMTZfdnNfWlQ0LTE2TW8iKQoKWmVicmEuWlQxNl92c19aVDQuNE0gPC0gZGlmZl96ZWJyYSgiLi4vLi4vWmVicmFmaXNoL0ZpbmFsX1JlcG9ydC9XaGlwcGV0L0RlbHRhL1pUMTZfdnNfWlQ0LTRNby5kaWZmLm1pY3JvZXhvbnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIuLi8uLi9aZWJyYWZpc2gvRmluYWxfUmVwb3J0L1doaXBwZXQvRGVsdGEvWlQxNl92c19aVDQtNE1vLmRpZmYuTUUubWljcm9leG9ucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJaVDE2X3ZzX1pUNC00TW8iKQoKCgoKWmVicmEuVE9UQUxfZGlmZiA8LSByYmluZCgKWmVicmEuMjBNb192c18xNk1vLlpUMTZbZGlmZiE9Ik5BIl0sClplYnJhLjIwTW9fdnNfNE0uWlQxNltkaWZmIT0iTkEiXSwKWmVicmEuMTZNb192c180TW8uWlQxNltkaWZmIT0iTkEiXSwKWmVicmEuMjBNb192c18xNk1vLlpUNFtkaWZmIT0iTkEiXSwKWmVicmEuMjBNb192c180TS5aVDRbZGlmZiE9Ik5BIl0sClplYnJhLjE2TW9fdnNfNE1vLlpUNFtkaWZmIT0iTkEiXSwKWmVicmEuWlQxNl92c19aVDQuMjBNW2RpZmYhPSJOQSJdLApaZWJyYS5aVDE2X3ZzX1pUNC4xNk1bZGlmZiE9Ik5BIl0sClplYnJhLlpUMTZfdnNfWlQ0LjRNW2RpZmYhPSJOQSJdICkKCgpaZWJyYS5UT1RBTF9kaWZmIDwtIFplYnJhLlRPVEFMX2RpZmZbICwgbGFwcGx5KC5TRCwgcGFzdGUwLCBjb2xsYXBzZT0iLCIpICwgYnk9ImV4b25fSUQiXQoKCk1vdXNlX1plYnJhLklEc1tNRS56ZWJyYSAlaW4lIFplYnJhLlRPVEFMX2RpZmYkZXhvbl9JRF0KCmBgYAoKCgpgYGB7cn0KRGVsdGFfSE5NX3doaXBwZXRfTUUgPC0gbWVyZ2UoRGVsdGFfSE5NX3doaXBwZXQsIERlbHRhX0hOTV9NRSwgYnk9YygiZXhvbl9JRCIsICJHZW5lIiwgIk5vZGUiLCAgIkNvb3JkIiwgIlN0cmFuZCIsICJUeXBlIiwgImFnZSIpICkKCkRlbHRhX0hOTV93aGlwcGV0X01FWyAoYWJzKERlbHRhUHNpLngpPj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChhYnMoRGVsdGFQc2kueSk+PTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSkgLCAuTiAsIGJ5PShhZ2UpXQoKRGVsdGFfSE5NX3doaXBwZXRfTUVfaW5jbHVkZWQgPC0gRGVsdGFfSE5NX3doaXBwZXRfTUVbIChEZWx0YVBzaS54PD0tMC4xICYgIFByb2JhYmlsaXR5LnggPj0gMC45KSAmICAoRGVsdGFQc2kueTw9LTAuMSAmICBQcm9iYWJpbGl0eS55ID49IDAuOSkgICwgLk4gLCBieT0oYWdlKV0KRGVsdGFfSE5NX3doaXBwZXRfTUVfZXhjbHVkZWQgPC0gRGVsdGFfSE5NX3doaXBwZXRfTUVbIChEZWx0YVBzaS54Pj0wLjEgJiAgUHJvYmFiaWxpdHkueCA+PSAwLjkpICYgIChEZWx0YVBzaS55Pj0wLjEgJiAgUHJvYmFiaWxpdHkueSA+PSAwLjkpICAsIC5OICwgYnk9KGFnZSldCgoKRGVsdGFfSE5NX2luY2x1ZGVkX3N0YXRzIDwtIGNiaW5kKERlbHRhX0hOTV93aGlwcGV0X2luY2x1ZGVkW29yZGVyKGFnZSldLCBEZWx0YV9ITk1fTUVfaW5jbHVkZWRbb3JkZXIoYWdlKSwgMl0sIERlbHRhX0hOTV93aGlwcGV0X01FX2luY2x1ZGVkW29yZGVyKGFnZSksIDJdKQpjb2xuYW1lcyhEZWx0YV9ITk1faW5jbHVkZWRfc3RhdHMpIDwtIGMoImFnZSIsICJXaGlwcGV0IiwgIk1pY3JvRXhvbmF0b3IiLCAiQm90aCIpCgpgYGAKCgoKCiMjIyMjCgoKYGBge3J9CgpjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb25fSEMgPC0gZ2xtKGZvcm11bGEgPSBjZW50cmFsIH4gbWluX2RpZl9hZ2UsIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSBQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0hDKQpzdW1tYXJ5KGNlbnRyYWxpdHlfbG9naXN0aWNfcmVncmVzc2lvbl9IQykKCgpjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb25fRUMgPC0gZ2xtKGZvcm11bGEgPSBjZW50cmFsIH4gbWluX2RpZl9hZ2UsIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSBQUElfZGlmZl9hZ2VfSE5NX3N0YXRzX0VDKQpzdW1tYXJ5KGNlbnRyYWxpdHlfbG9naXN0aWNfcmVncmVzc2lvbl9FQykKCgpjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb25fQiA8LSBnbG0oZm9ybXVsYSA9IGNlbnRyYWwgfiBtaW5fZGlmX2FnZSwgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IFBQSV9kaWZmX2FnZV9ITk1fc3RhdHNfQikKc3VtbWFyeShjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb25fQikKYGBgCgoKYGBge3J9CgpQUElfZGlmZl9hZ2VfSE5NJEwxY2FtX2FuZF9pbnRlcmFjdG9ycyA8LSBmYWN0b3IoUFBJX2RpZmZfYWdlX0hOTSRMMWNhbV9hbmRfaW50ZXJhY3RvcnMsIGxldmVscz1jKFRSVUUsIEZBTFNFKSkKCgpGNkcgPC0gZ2dwbG90KFBQSV9kaWZmX2FnZV9ITk0pICsKICBnZW9tX3BvaW50KGFlcyhlaWdlbl9jZW50cmFsaXR5LCBiZXR3ZWVubmVzcywgY29sb3VyPUwxY2FtX2FuZF9pbnRlcmFjdG9ycykpICsKICBmYWNldF93cmFwKCAuIH4gZGlmZl9hZ2UsIG5jb2wgPSAyKSAgKwogICAgICBnZW9tX3RleHRfcmVwZWwoZGF0YT1QUElfZGlmZl9hZ2VfSE5NWyBMMWNhbV9hbmRfaW50ZXJhY3RvcnM9PVRSVUUsICBdLCAKICAgICAgICAgICAgICAgICAgYWVzKHg9ZWlnZW5fY2VudHJhbGl0eSwgeT1iZXR3ZWVubmVzcywgY29sb3VyPUwxY2FtX2FuZF9pbnRlcmFjdG9ycyApLCAKICAgICAgICAgICAgICAgICAgbnVkZ2VfeSAgICAgID0gMzAwMCwKICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uICAgID0gIngiLAogICAgICAgICAgICAgICAgICBhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC4yLAogICAgICAgICAgICAgICAgICBsYWJlbD1QUElfZGlmZl9hZ2VfSE5NW0wxY2FtX2FuZF9pbnRlcmFjdG9ycz09VFJVRSAgLCBtZ2lfc3ltYm9sXSwKICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArCiAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTDFDQU0gcGF0aHdheSIsIGxhYmVscyA9IGMoIk1lbWJlciIsICJOb24tbWVtYmVyIikpICAKCgoKCmBgYAoKCgoKCgoKCgpgYGB7cn0KY2VudHJhbGl0eV9sb2dpc3RpY19yZWdyZXNzaW9uIDwtIGdsbShmb3JtdWxhID0gY2VudHJhbCB+IG1pbl9kaWZfYWdlLCBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gUFBJX2RpZmZfYWdlX0hOTV9zdGF0cykKc3VtbWFyeShjZW50cmFsaXR5X2xvZ2lzdGljX3JlZ3Jlc3Npb24pCmBgYAoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiBnZ3Bsb3QoUFBJX2RpZmZfYWdlX0hOTSkgKwogIGdlb21faml0dGVyKGFlcyhsb2coYmV0d2Vlbm5lc3MpLCBkaWZmX2FnZSwgY29sb3I9dHlwZSApLCB3aWR0aD0wLCBoZWlnaHQ9MC4xKSArCiAgeGxhYigiQmV0d2Vlbm5lc3MiKSArCiAgeWxhYigiRWFybGllc3QgbWljcm9leG9uIGRpZmZlcmVudGlhbCBpbmNsdXNpb24gZGV0ZWN0aW9uIChEUEMpIikgKwogICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxMC41LDE2LjUsMSkpICsKICAgIGdlb21fdGV4dF9yZXBlbChkYXRhPVBQSV9kaWZmX2FnZV9ITk1bICBsb2coYmV0d2Vlbm5lc3MpPjYsICBdLAogICAgICAgICAgICAgICAgICBhZXMoeD1sb2coYmV0d2Vlbm5lc3MpLCB5PWRpZmZfYWdlLCBjb2xvdXI9dHlwZSksIAogICAgICAgICAgICAgICAgICBudWRnZV95ICAgICAgPSAwLjUsCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICAgYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgbGFiZWw9UFBJX2RpZmZfYWdlX0hOTVtsb2coYmV0d2Vlbm5lc3MpPjYgICwgbWdpX3N5bWJvbF0gKSAKCgpgYGAKCgoKCiMjIFRhc2ljCgoKYGBge3J9CmVuc2VtYmwgPSB1c2VFbnNlbWJsKGJpb21hcnQ9ImVuc2VtYmwiLCBkYXRhc2V0PSJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIiwgaG9zdCA9ICJ3d3cuZW5zZW1ibC5vcmciKQoKCk1FX2ZpbmFsLnRyYW5zY3JpcHQgPC0gZ3N1YigiXFwuLioiLCIiLCBNRV9maW5hbCR0cmFuc2NyaXB0KQoKTUVfZmluYWwkZW5zZW1ibF90cmFuc2NyaXB0X2lkIDwtIGdzdWIoIlxcLi4qIiwiIiwgTUVfZmluYWwkdHJhbnNjcmlwdCkgCgpnZW5lX3RhYmxlLlRPVEFMIDwtIGRhdGEudGFibGUoZ2V0Qk0oYXR0cmlidXRlcz1jKCdlbnNlbWJsX3RyYW5zY3JpcHRfaWQnLCAnZW5zZW1ibF9nZW5lX2lkJywgIm1naV9zeW1ib2wiKSxmaWx0ZXJzID0gJ2Vuc2VtYmxfdHJhbnNjcmlwdF9pZCcsIHZhbHVlcyA9IE1FX2ZpbmFsLnRyYW5zY3JpcHRbbmNoYXIoTUVfZmluYWwudHJhbnNjcmlwdCkhPTBdLCBtYXJ0ID0gZW5zZW1ibCwgICkpCgoKZ2VuZV90YWJsZS5UT1RBTCA8LSBtZXJnZShnZW5lX3RhYmxlLlRPVEFMLCBNRV9maW5hbFssIGMoImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJNRSIpXSwgYnk9ImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIpCgoKCmBgYAoKCgoKYGBge3J9CgpQQ0FfbG9hZGluZ3NbLCBNRV9jbHVzdGVyOj1hcy5udW1lcmljKChhcy5jaGFyYWN0ZXIoTUVfY2x1c3RlcikpKV0KTUVfY2x1c3Rlcl9uYW1lc1ssIE1FX2NsdXN0ZXI6PWFzLm51bWVyaWMoKGFzLmNoYXJhY3RlcihNRV9jbHVzdGVyKSkpXQpNRV9jbHVzdGVycy5pbmZvIDwtIG1lcmdlKFBDQV9sb2FkaW5ncywgTUVfY2x1c3Rlcl9uYW1lcywgYnk9Ik1FX2NsdXN0ZXIiKQoKTUVfY2x1c3RlcnMuaW5mb1tNRV9jbHVzdGVyLnR5cGU9PSJOZXVyb25hbCIgfCBNRV9jbHVzdGVyLnR5cGU9PSJOZXVyb211c2N1bGFyIl0KCgpsaWJyYXJ5KHJlYWRyKQoKbGlicmFyeShIbWlzYykKCgpUYXNpY19zYW1wbGVfaW5mbyA8LSBkYXRhLnRhYmxlKHJlYWRfZGVsaW0oIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvU2luZ2xlX2NlbGwvVGFzaWMvR1NFNzE1ODUudHh0IiwgCiAgICAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKSkKCgpUYXNpY19jbHVzdGVyaW5nIDwtIGRhdGEudGFibGUocmVhZF9kZWxpbSgifi9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9TaW5nbGVfY2VsbC9UYXNpYy9HU0U3MTU4NV9DbHVzdGVyaW5nX1Jlc3VsdHMuY3N2IiwgCiAgICAiLCIsIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwgdHJpbV93cyA9IFRSVUUpKQoKdGFzaWNfZXRfYWxfU1QzIDwtIGRhdGEudGFibGUocmVhZF9jc3YoIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvU2luZ2xlX2NlbGwvVGFzaWMvdGFzaWNfZXRfYWwuU1QzLmNzdiIpKQoKCgp0YXNpY19tZXRhZGF0YSA8LSBtZXJnZShUYXNpY19zYW1wbGVfaW5mbywgdGFzaWNfZXRfYWxfU1QzLCBieS54PSJTYW1wbGVfTmFtZV9zIiwgYnkueT0iR0VPIFNhbXBsZSBBY2Nlc3Npb24iKQoKI3Rhc2ljX21ldGFkYXRhIDwtIHRhc2ljX21ldGFkYXRhWywgYygiUnVuX3MiLCAiR0VPIFNhbXBsZSBUaXRsZSIpIF0KCgp0YXNpY19tZXRhZGF0YSA8LSBtZXJnZSggVGFzaWNfY2x1c3RlcmluZywgdGFzaWNfbWV0YWRhdGEsIGJ5Lng9InNhbXBsZV90aXRsZSIsIGJ5Lnk9IkdFTyBTYW1wbGUgVGl0bGUiKQoKCgoKCk1FX2Nvdl9maWx0ZXJlZF90YXNpYyA8LSBtZXJnZSggTUVfY292LCAKICAgICAgIHRhc2ljX21ldGFkYXRhWywgYygic2FtcGxlX3RpdGxlIiwgImJyb2FkX3R5cGUiLCAiY29yZV9pbnRlcm1lZGlhdGUiLCAicHJpbWFyeV90eXBlIiwgIlJ1bl9zIildLAogICAgICAgYnkueD0iRklMRV9OQU1FIiwgYnkueSA9ICJSdW5fcyIpCgoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljIDwtICBNRV9jb3ZfZmlsdGVyZWRfdGFzaWNbTUUgJWluJSBNRV9maW5hbFssIE1FXSAgLCBdCgoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljJHN1bV9NRV9jb3ZlcmFnZSA8LSAgc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihNRV9jb3ZfZmlsdGVyZWRfdGFzaWMkTUVfY292ZXJhZ2VzKSwgIiwiLCBmaXhlZD1UKSwgZnVuY3Rpb24oeCkgc3VtKGFzLm51bWVyaWMoeCkpKQpNRV9jb3ZfZmlsdGVyZWRfdGFzaWMkc3VtX1NKX2NvdmVyYWdlIDwtICBzYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKE1FX2Nvdl9maWx0ZXJlZF90YXNpYyRTSl9jb3ZlcmFnZXMpLCAiLCIsIGZpeGVkPVQpLCBmdW5jdGlvbih4KSBzdW0oYXMubnVtZXJpYyh4KSkpCgoKI01FX2Nvdl9maWx0ZXJlZF90YXNpY1ssIGA6PWAoIHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfNT1BbHQ1X2NvdmVyYWdlcywgdG90YWxfY292X2FsdGVybmF0aXZlc18zPUFsdDNfY292ZXJhZ2VzKV0KTUVfY292X2ZpbHRlcmVkX3Rhc2ljWyBBbHQ1X2NvdmVyYWdlcz09Ik5vbmUiICwgYDo9YCggQWx0NV9jb3ZlcmFnZXM9MCldCk1FX2Nvdl9maWx0ZXJlZF90YXNpY1sgQWx0M19jb3ZlcmFnZXM9PSJOb25lIiAsIGA6PWAoIEFsdDNfY292ZXJhZ2VzPTApXQpNRV9jb3ZfZmlsdGVyZWRfdGFzaWMkdG90YWxfY292X2FsdGVybmF0aXZlc181IDwtICBzYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKE1FX2Nvdl9maWx0ZXJlZF90YXNpYyRBbHQ1X2NvdmVyYWdlcyksICIsIiwgZml4ZWQ9VCksIGZ1bmN0aW9uKHgpIHN1bShhcy5udW1lcmljKHgpKSkKTUVfY292X2ZpbHRlcmVkX3Rhc2ljJHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyA8LSAgc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihNRV9jb3ZfZmlsdGVyZWRfdGFzaWMkQWx0M19jb3ZlcmFnZXMpLCAiLCIsIGZpeGVkPVQpLCBmdW5jdGlvbih4KSBzdW0oYXMubnVtZXJpYyh4KSkpCgpNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlIDwtIE1FX2Nvdl9maWx0ZXJlZF90YXNpY1ssIC4oc3VtX01FX2NvdmVyYWdlPXN1bShzdW1fTUVfY292ZXJhZ2UpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHN1bV9TSl9jb3ZlcmFnZSA9c3VtKHN1bV9TSl9jb3ZlcmFnZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfY292X2FsdGVybmF0aXZlc18zID0gc3VtKHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfY292X2FsdGVybmF0aXZlc181ID0gc3VtKHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfNSkKICAgICAgICAgICAgICAgICAgICAgICAgICApLCBieT1jKCJwcmltYXJ5X3R5cGUiLCAiYnJvYWRfdHlwZSIsICJNRSIpIF0KCgoKCgoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVssUFNJOj0oc3VtX01FX2NvdmVyYWdlLyhzdW1fTUVfY292ZXJhZ2Urc3VtX1NKX2NvdmVyYWdlK3RvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyt0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzUpKV0KCm1pbl9QU0lfc3VtIDwtIDUKICAKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVtzdW1fTUVfY292ZXJhZ2Urc3VtX1NKX2NvdmVyYWdlK3RvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyt0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzU8bWluX1BTSV9zdW0sIFBTSTo9TmFOXQoKbGlicmFyeShIbWlzYyApCgpNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlWyAsIAogICAgICAgICAgICBgOj1gKAogICAgICAgICAgICAgIGxvd2VyPWJpbmNvbmYoeD1zdW1fTUVfY292ZXJhZ2UsIG49KHN1bV9NRV9jb3ZlcmFnZStzdW1fU0pfY292ZXJhZ2UrdG90YWxfY292X2FsdGVybmF0aXZlc18zK3RvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfNSkgKVssICJMb3dlciJdLAogICAgICAgICAgICAgIHVwcGVyPWJpbmNvbmYoeD1zdW1fTUVfY292ZXJhZ2UsIG49KHN1bV9NRV9jb3ZlcmFnZStzdW1fU0pfY292ZXJhZ2UrdG90YWxfY292X2FsdGVybmF0aXZlc18zK3RvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfNSkgKVssICJVcHBlciJdCiAgICAgICAgICAgICAgKSBdCgoKCk1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUgPC0gbWVyZ2UoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZSwgdW5pcXVlKGdlbmVfdGFibGUuVE9UQUwpLCBieT0iTUUiKQoKCk1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUuTUVfY2x1c3RlcnMgPC0gbWVyZ2UoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZSwgTUVfY2x1c3RlcnMuaW5mb1ssIGMoIk1FIiwgIk1FX2NsdXN0ZXIudHlwZSIsICJNRV9jbHVzdGVyLm5hbWUiKV0sIGJ5PSJNRSIpCgoKCgoKYGBgCgpgYGB7cn0KbGlicmFyeShzdHJpbmdyKQoKdGFibGUoZ3JlcGwoIkVOQyIsICB1bmlxdWUoTUVfY292X2ZpbHRlcmVkWywgRklMRV9OQU1FXSkpKQoKYGBgCgoKCgoKCmBgYHtyLCBmaWcud2lkdGg9MTUsICBmaWcuaGVpZ2h0PTIwfQoKCgoKCiNDN19pbnRlcmVzdGluZyA8LSBjKCJjaHIxXy1fOTMwMjY4MzFfOTMwMjY4NTUiLCAiY2hyMV8rXzExODUxMjcwNF8xMTg1MTI3MjgiLCAiY2hyMTFfLV8xMDYxODA5NTRfMTA2MTgwOTgzIiwgImNocjExXy1fMzM1Mjg5OV8zMzUyOTE3IiwgImNocjExXytfNTQ2NzE2NTRfNTQ2NzE2NzgiLCAiY2hyM18tXzE0ODgyNzIxMV8xNDg4MjcyMzgiLCIgY2hyNF8tXzc2MTM4NTU1Xzc2MTM4NTczIiwgImNocjVfK18xNDM3MDMzNzJfMTQzNzAzMzc1IiwgImNocjVfK180ODI2MzY0MF80ODI2MzY2NyIsICJjaHI4Xy1fNTQ2NDUzMzdfNTQ2NDUzNTgiKQoKCiNnZ3Bsb3QoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVsgTUUgJWluJSBDN19pbnRlcmVzdGluZywgXSAgKSArCiMgIGdlb21fcG9pbnRyYW5nZShhZXMoeD1wcmltYXJ5X3R5cGUsIHk9UFNJLCBjb2xvdXI9IGJyb2FkX3R5cGUsIGdyb3VwPWJyb2FkX3R5cGUsIHNoYXBlPWJyb2FkX3R5cGUsIHltaW49bG93ZXIsIHltYXg9dXBwZXIpKSsKIyAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSkpICsKIyAgZmFjZXRfZ3JpZCggZ2VuZV9uYW1lc1tNRV0gfiAuICkKCgp0YXJnZXRfZ2VuZXMgPC0gYygiS2lmMWEiLCAiRGN0bjEiLCAiS2RtMWEiLCAiS2RtMmEiLCAgIkl0c24xIiwgIkRubTEiLCAiRG5tMyIsICJUcnJhcCIsICJEY2xrMiIpCgp0YXJnZXRfZ2VuZXMgPC0gYygiS2lmMWEiLCAiRGN0bjEiLCAiS2RtMWEiLCAiS2RtMmEiLCAgIkl0c24xIiwgIkRubTEiLCAiRG5tMyIsICJUcnJhcCIsICJEY2xrMiIpCgoKCmdncGxvdChNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlWyBtZ2lfc3ltYm9sICVpbiUgdGFyZ2V0X2dlbmVzICYgIE1FICVpbiUgRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsJGV4b25fSUQgLCBdICApICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHg9cHJpbWFyeV90eXBlLCB5PVBTSSwgY29sb3VyPSBicm9hZF90eXBlLCBncm91cD1icm9hZF90eXBlLCBzaGFwZT1icm9hZF90eXBlLCB5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSkrCiAgZmFjZXRfZ3JpZCggcGFzdGUwKCBtZ2lfc3ltYm9sLCBNRSkgfiAuICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUpKQoKCgpnZ3Bsb3QoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVsgbWdpX3N5bWJvbCAlaW4lIHRhcmdldF9nZW5lcywgXSAgKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4PXByaW1hcnlfdHlwZSwgeT1QU0ksIGNvbG91cj0gYnJvYWRfdHlwZSwgZ3JvdXA9YnJvYWRfdHlwZSwgc2hhcGU9YnJvYWRfdHlwZSwgeW1pbj1sb3dlciwgeW1heD11cHBlcikpKwogIGZhY2V0X2dyaWQoIHBhc3RlMCggbWdpX3N5bWJvbCwgTUUpIH4gLiApICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDAsIHZqdXN0ID0gMC41KSkKCmBgYAoKCgojIyMjIyMKCiMjIE5ldyBUYXNpYyAjIyMKCgpgYGB7cn0KClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMgPC0gZnJlYWQoIi9Vc2Vycy9ncDcvR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvU2luZ2xlX2NlbGwvR0FCQS1lcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24uYWxsX25vZGVzLm1pY3JvZXhvbnMudHh0IikKCgoKVGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5taWNyb2V4b25zIDwtIG1lcmdlKCBUYXNpY190b3RhbF9kaWZmX25vZGVzW2lzLmRpZmY9PSJUUlVFIiAmICFpcy5uYShtaWNyb2V4b25fSUQpLCBdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUoZ2VuZV90YWJsZS5UT1RBTFssIGMoIk1FIiwgIm1naV9zeW1ib2wiKV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5Lng9Im1pY3JvZXhvbl9JRCIsIGJ5Lnk9Ik1FIikKClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMubWljcm9leG9uc1shbWljcm9leG9uX0lEICVpbiUgU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24kZXhvbl9JRCwgXQoKYGBgCgoKCmBgYHtyfQoKI3JlZiBTbGM0YTEwIGh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9hcnRpY2xlcy8xMC4zMzg5L2ZuY2VsLjIwMTUuMDAyMjMvZnVsbAojcmVmIEFuazMgaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMDg5NjYyNzMxNDAwOTA4OAojcmVmIEtDTk1BMSBodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MwODk2NjI3MzEzMDAxODUyCiNyZWYgS2lmM2EgaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMDg5NjYyNzMwMzAwMDYyWAojIHJlZiBETEdBUCBodHRwczovL21vbGVjdWxhcmJyYWluLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvczEzMDQxLTAxNy0wMzI0LTkKCgpQcmVfc3luYXB0aWMgPC0gYyggIlB0cHJkIiAsICJQcGZpYTIiLCAiRGxnYXAxIiwgIkdhYnJnMiIsICJLY25tYTEiLCAiS2lmM2EiLCAiQ2FkcHMiKSAKUG9zdF9zeW5hcHRpYyA8LSBjKCAiTnJ4bjMiICwgIk5yeG4xIikKUHJlUG9zdF9zeW5hcHRpYyA8LSBjKCJBbmszIiwiU2xjNGExMCIpCmBgYAoKCgoKCmBgYHtyfQpUYXNpY190b3RhbF9kaWZmX25vZGVzLm1pY3JvZXhvbnNbTG9jYXRpb25dCmBgYAoKCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KCgoKZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChkYXRhPVRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbIWlzLm5hKG1pY3JvZXhvbl9JRCkgLCAgXSwgYWVzKERlbHRhUHNpLm1lYW4sIFByb2JhYmlsaXR5Lm1lYW4pLCBjb2xvcj0iZ3JleSIpICsKICBnZW9tX3BvaW50KGRhdGE9VGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5taWNyb2V4b25zLCBhZXMoRGVsdGFQc2kubWVhbiwgUHJvYmFiaWxpdHkubWVhbiksIGNvbG9yPSJibGFjayIpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IFRhc2ljX3RvdGFsX2RpZmZfbm9kZXMubWljcm9leG9uc1shaXMubmEoTG9jYXRpb24pLF0sCiAgICAgICAgICAgICAgICAgIGFlcyh4PURlbHRhUHNpLm1lYW4sIHk9UHJvYmFiaWxpdHkubWVhbiwgY29sb3VyPUxvY2F0aW9uKSwgCiAgICAgICAgICAgICAgICAgIG51ZGdlX3kgICAgICA9IDMsCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICAgYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAgIHZqdXN0ICAgICAgICA9IDEsCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMSwKICAgICAgICAgICAgICAgICAgbGFiZWw9VGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5taWNyb2V4b25zWyFpcy5uYShMb2NhdGlvbikgLCBtZ2lfc3ltYm9sXSApICsKICAKCiAgCiAgeWxpbSgwLjUsIDEuMTUpICsKICB0aGVtZV9idygpICsKICB4bGFiKCIiKSArCiAgeGxhYigiTWVhbiBkZWx0YSBQU0kiKSArCiAgeWxhYigiTWVhbiBwcm9iYWJpbGl0eSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImRhcmtnb2xkZW5yb2QiICwgImZpcmVicmljazQiLCAiZm9yZXN0Z3JlZW4iKSkgKwoKCiAgdGhlbWUoIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgCgpgYGAKCgoKYGBge3J9CgpQQ0FfbG9hZGluZ3NbLCBNRV9jbHVzdGVyOj1hcy5udW1lcmljKChhcy5jaGFyYWN0ZXIoTUVfY2x1c3RlcikpKV0KTUVfY2x1c3Rlcl9uYW1lc1ssIE1FX2NsdXN0ZXI6PWFzLm51bWVyaWMoKGFzLmNoYXJhY3RlcihNRV9jbHVzdGVyKSkpXQpNRV9jbHVzdGVycy5pbmZvIDwtIG1lcmdlKFBDQV9sb2FkaW5ncywgTUVfY2x1c3Rlcl9uYW1lcywgYnk9Ik1FX2NsdXN0ZXIiKQoKbGlicmFyeShyZWFkcikKCmxpYnJhcnkoSG1pc2MpCgoKVGFzaWNfc2FtcGxlX2luZm8gPC0gZGF0YS50YWJsZShyZWFkX2RlbGltKCJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL1NpbmdsZV9jZWxsL1Rhc2ljL0dTRTcxNTg1LnR4dCIsIAogICAgIlx0IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkpCgoKVGFzaWNfY2x1c3RlcmluZyA8LSBkYXRhLnRhYmxlKHJlYWRfZGVsaW0oIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvU2luZ2xlX2NlbGwvVGFzaWMvR1NFNzE1ODVfQ2x1c3RlcmluZ19SZXN1bHRzLmNzdiIsIAogICAgIiwiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKSkKCnRhc2ljX2V0X2FsX1NUMyA8LSBkYXRhLnRhYmxlKHJlYWRfY3N2KCJ+L0dvb2dsZV9Ecml2ZS9SZXN1bHRzL01FL1NpbmdsZV9jZWxsL1Rhc2ljL3Rhc2ljX2V0X2FsLlNUMy5jc3YiKSkKCgoKdGFzaWNfbWV0YWRhdGEgPC0gbWVyZ2UoVGFzaWNfc2FtcGxlX2luZm8sIHRhc2ljX2V0X2FsX1NUMywgYnkueD0iU2FtcGxlX05hbWVfcyIsIGJ5Lnk9IkdFTyBTYW1wbGUgQWNjZXNzaW9uIikKCiN0YXNpY19tZXRhZGF0YSA8LSB0YXNpY19tZXRhZGF0YVssIGMoIlJ1bl9zIiwgIkdFTyBTYW1wbGUgVGl0bGUiKSBdCgoKdGFzaWNfbWV0YWRhdGEgPC0gbWVyZ2UoIFRhc2ljX2NsdXN0ZXJpbmcsIHRhc2ljX21ldGFkYXRhLCBieS54PSJzYW1wbGVfdGl0bGUiLCBieS55PSJHRU8gU2FtcGxlIFRpdGxlIikKCgoKCgpNRV9jb3ZfZmlsdGVyZWRfdGFzaWMgPC0gbWVyZ2UoIE1FX2NvdiwgCiAgICAgICB0YXNpY19tZXRhZGF0YVssIGMoInNhbXBsZV90aXRsZSIsICJicm9hZF90eXBlIiwgImNvcmVfaW50ZXJtZWRpYXRlIiwgInByaW1hcnlfdHlwZSIsICJSdW5fcyIpXSwKICAgICAgIGJ5Lng9IkZJTEVfTkFNRSIsIGJ5LnkgPSAiUnVuX3MiKQoKCk1FX2Nvdl9maWx0ZXJlZF90YXNpYyA8LSAgTUVfY292X2ZpbHRlcmVkX3Rhc2ljW01FICVpbiUgTUVfZmluYWxbLCBNRV0gICwgXQoKCk1FX2Nvdl9maWx0ZXJlZF90YXNpYyRzdW1fTUVfY292ZXJhZ2UgPC0gIHNhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoTUVfY292X2ZpbHRlcmVkX3Rhc2ljJE1FX2NvdmVyYWdlcyksICIsIiwgZml4ZWQ9VCksIGZ1bmN0aW9uKHgpIHN1bShhcy5udW1lcmljKHgpKSkKTUVfY292X2ZpbHRlcmVkX3Rhc2ljJHN1bV9TSl9jb3ZlcmFnZSA8LSAgc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihNRV9jb3ZfZmlsdGVyZWRfdGFzaWMkU0pfY292ZXJhZ2VzKSwgIiwiLCBmaXhlZD1UKSwgZnVuY3Rpb24oeCkgc3VtKGFzLm51bWVyaWMoeCkpKQoKCiNNRV9jb3ZfZmlsdGVyZWRfdGFzaWNbLCBgOj1gKCB0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzU9QWx0NV9jb3ZlcmFnZXMsIHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMz1BbHQzX2NvdmVyYWdlcyldCk1FX2Nvdl9maWx0ZXJlZF90YXNpY1sgQWx0NV9jb3ZlcmFnZXM9PSJOb25lIiAsIGA6PWAoIEFsdDVfY292ZXJhZ2VzPTApXQpNRV9jb3ZfZmlsdGVyZWRfdGFzaWNbIEFsdDNfY292ZXJhZ2VzPT0iTm9uZSIgLCBgOj1gKCBBbHQzX2NvdmVyYWdlcz0wKV0KTUVfY292X2ZpbHRlcmVkX3Rhc2ljJHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfNSA8LSAgc2FwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3RlcihNRV9jb3ZfZmlsdGVyZWRfdGFzaWMkQWx0NV9jb3ZlcmFnZXMpLCAiLCIsIGZpeGVkPVQpLCBmdW5jdGlvbih4KSBzdW0oYXMubnVtZXJpYyh4KSkpCk1FX2Nvdl9maWx0ZXJlZF90YXNpYyR0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzMgPC0gIHNhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoTUVfY292X2ZpbHRlcmVkX3Rhc2ljJEFsdDNfY292ZXJhZ2VzKSwgIiwiLCBmaXhlZD1UKSwgZnVuY3Rpb24oeCkgc3VtKGFzLm51bWVyaWMoeCkpKQoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZSA8LSBNRV9jb3ZfZmlsdGVyZWRfdGFzaWNbLCAuKHN1bV9NRV9jb3ZlcmFnZT1zdW0oc3VtX01FX2NvdmVyYWdlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1fU0pfY292ZXJhZ2UgPXN1bShzdW1fU0pfY292ZXJhZ2UpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyA9IHN1bSh0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzMpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfNSA9IHN1bSh0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgKSwgYnk9YygicHJpbWFyeV90eXBlIiwgImJyb2FkX3R5cGUiLCAiTUUiKSBdCgoKCgoKCk1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbLFBTSTo9KHN1bV9NRV9jb3ZlcmFnZS8oc3VtX01FX2NvdmVyYWdlK3N1bV9TSl9jb3ZlcmFnZSt0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzMrdG90YWxfY292X2FsdGVybmF0aXZlc181KSldCgptaW5fUFNJX3N1bSA8LSA1CiAgCk1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbc3VtX01FX2NvdmVyYWdlK3N1bV9TSl9jb3ZlcmFnZSt0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzMrdG90YWxfY292X2FsdGVybmF0aXZlc181PG1pbl9QU0lfc3VtLCBQU0k6PU5hTl0KCmxpYnJhcnkoSG1pc2MgKQoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVsgLCAKICAgICAgICAgICAgYDo9YCgKICAgICAgICAgICAgICBsb3dlcj1iaW5jb25mKHg9c3VtX01FX2NvdmVyYWdlLCBuPShzdW1fTUVfY292ZXJhZ2Urc3VtX1NKX2NvdmVyYWdlK3RvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyt0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzUpIClbLCAiTG93ZXIiXSwKICAgICAgICAgICAgICB1cHBlcj1iaW5jb25mKHg9c3VtX01FX2NvdmVyYWdlLCBuPShzdW1fTUVfY292ZXJhZ2Urc3VtX1NKX2NvdmVyYWdlK3RvdGFsX2Nvdl9hbHRlcm5hdGl2ZXNfMyt0b3RhbF9jb3ZfYWx0ZXJuYXRpdmVzXzUpIClbLCAiVXBwZXIiXQogICAgICAgICAgICAgICkgXQoKCgpNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlIDwtIG1lcmdlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUsIHVuaXF1ZShnZW5lX3RhYmxlLlRPVEFMKSwgYnk9Ik1FIikKCgpNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlLk1FX2NsdXN0ZXJzIDwtIG1lcmdlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUsIE1FX2NsdXN0ZXJzLmluZm9bLCBjKCJNRSIsICJNRV9jbHVzdGVyLnR5cGUiLCAiTUVfY2x1c3Rlci5uYW1lIildLCBieT0iTUUiKQpgYGAKCmBgYHtyfQpwcmltYXJ5X3R5cGVfbGV2ZWxzIDwtIGModW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbYnJvYWRfdHlwZT09IkVuZG90aGVsaWFsIENlbGwiLCBwcmltYXJ5X3R5cGVdKSwKdW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbYnJvYWRfdHlwZT09Ik9saWdvZGVuZHJvY3l0ZSIsIHByaW1hcnlfdHlwZV0pLAp1bmlxdWUoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVticm9hZF90eXBlPT0iTWljcm9nbGlhIiwgcHJpbWFyeV90eXBlXSksCnVuaXF1ZShNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlW2Jyb2FkX3R5cGU9PSJPbGlnb2RlbmRyb2N5dGUgUHJlY3Vyc29yIENlbGwiLCBwcmltYXJ5X3R5cGVdKSwKc29ydCh1bmlxdWUoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVticm9hZF90eXBlPT0iQXN0cm9jeXRlIiwgcHJpbWFyeV90eXBlXSkpLApzb3J0KHVuaXF1ZShNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlW2Jyb2FkX3R5cGU9PSJHbHV0YW1hdGVyZ2ljIE5ldXJvbiIsIHByaW1hcnlfdHlwZV0pKSwKdW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbYnJvYWRfdHlwZT09IkdBQkEtZXJnaWMgTmV1cm9uIiwgcHJpbWFyeV90eXBlXSkgKQoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZSRwcmltYXJ5X3R5cGUgPC0gZmFjdG9yKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUkcHJpbWFyeV90eXBlICwgbGV2ZWxzID0gcHJpbWFyeV90eXBlX2xldmVscykKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xMiwgIGZpZy5oZWlnaHQ9OX0KCnRhcmdldF9nZW5lcyA8LSBjKCJHYWJyZzIiLCAiTnJ4bjEiLCAiTnJ4bjMiLCAiUHRwcmQiKQoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVsobWdpX3N5bWJvbCAlaW4lIHRhcmdldF9nZW5lcykgJiAoTUUgJWluJSBTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbiRleG9uX0lEKV0KTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVtpcy5uYShQU0kpLCBgOj1gKGxvd2VyPU5BLCB1cHBlcj1OQSkgXQoKCkZpZzguYy50b3AgPC0gZ2dwbG90KE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbIG1naV9zeW1ib2wgJWluJSB0YXJnZXRfZ2VuZXMgJiBNRSAlaW4lIFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uJGV4b25fSUQsIF0gICkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeD1wcmltYXJ5X3R5cGUsIHk9UFNJLCBjb2xvdXI9IGJyb2FkX3R5cGUsIGdyb3VwPWJyb2FkX3R5cGUsIHltaW49bG93ZXIsIHltYXg9dXBwZXIpKSsKICBmYWNldF9ncmlkKCBwYXN0ZTAoIG1naV9zeW1ib2wsIE1FKSB+IC4gKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAwLCB2anVzdCA9IDAuNSkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKQoKCgoKRmlnOC5jLnRvcApgYGAKCgpgYGB7cn0KTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZQpgYGAKCgoKYGBge3IsIGZpZy53aWR0aD0xMiwgIGZpZy5oZWlnaHQ9Mn0KClRhc2ljX2NsdXN0ZXJpbmckcHJpbWFyeV90eXBlIDwtIGZhY3RvcihUYXNpY19jbHVzdGVyaW5nJHByaW1hcnlfdHlwZSAsIGxldmVscyA9IHByaW1hcnlfdHlwZV9sZXZlbHMpCgpGaWc4LmMuYm90dG9tIDwtIGdncGxvdChUYXNpY19jbHVzdGVyaW5nWyBicm9hZF90eXBlIT0iVW5jbGFzc2lmaWVkIiwgLk4gLCBieT1jKCJwcmltYXJ5X3R5cGUiLCAiYnJvYWRfdHlwZSIpIF0pICsKICBnZW9tX2JhciggYWVzKHg9cHJpbWFyeV90eXBlLCB5PU4sICBmaWxsPWJyb2FkX3R5cGUpICwgc3RhdD0iaWRlbnRpdHkiKSArCiAgICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDAsIHZqdXN0ID0gMC41KSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgpGaWc4LmMuYm90dG9tCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgIGZpZy5oZWlnaHQ9OX0KCnBsb3RfZ3JpZChGaWc4LmMudG9wLCBGaWc4LmMuYm90dG9tLCBuY29sPTEsIHJlbF9oZWlnaHRzID0gYyg3LDIpICkKCgpgYGAKCgoKCiMjIyMjCgpTaW5nbGUgY2VsbCBzdGFzdAoKYGBge3J9Cm5yb3coVGFzaWNfdG90YWxfZGlmZl9ub2RlcykKYGBgCgoKYGBge3J9CnRhYmxlKFRhc2ljX3RvdGFsX2RpZmZfbm9kZXMkaXMubWljcm9leG9uKQpgYGAKCgpgYGB7cn0KVGFzaWNfdG90YWxfZGlmZl9ub2Rlc1sgICwgaXMubWljcm9leG9uOj0haXMubmEobWljcm9leG9uX0lEKSBdCgpUYXNpY190b3RhbF9kaWZmX25vZGVzWyBpcy5uYShpcy5kaWZmKSAsIGlzLmRpZmY6PSJGQUxTRSIgIF0KClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMuc3RhdHMgPC0gVGFzaWNfdG90YWxfZGlmZl9ub2Rlc1sgLCAuTiAsIGJ5PWMoIlR5cGUiLCAiaXMuZGlmZiIsICJpcy5taWNyb2V4b24iKV0KClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMuc3RhdHNbICwgVG90YWw6PXN1bShOKSwgYnk9YygiVHlwZSIsICJpcy5taWNyb2V4b24iKV0KClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMuc3RhdHNbaXMuZGlmZj09IlRSVUUiLCBdCgoKVGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5zdGF0c1ssIHJhdGlvOj1OL1RvdGFsXQoKClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMuc3RhdHMgPC0gVGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5zdGF0c1tpcy5kaWZmPT0iVFJVRSIsIF0KClRhc2ljX3RvdGFsX2RpZmZfbm9kZXMuc3RhdHNbaXMuZGlmZj09IlRSVUUiLCBdCgpgYGAKCgpgYGB7cn0KCkNFLmNvbnQgPC0gbWF0cml4KG5yb3c9MiwgYyhUYXNpY190b3RhbF9kaWZmX25vZGVzLnN0YXRzW1R5cGU9PSJDRSIgJiBpcy5taWNyb2V4b249PSJUUlVFIiwgTiBdLApUYXNpY190b3RhbF9kaWZmX25vZGVzLnN0YXRzW1R5cGU9PSJDRSIgJiBpcy5taWNyb2V4b249PSJUUlVFIiwgVG90YWwtTiBdLApUYXNpY190b3RhbF9kaWZmX25vZGVzLnN0YXRzW1R5cGU9PSJDRSIgJiBpcy5taWNyb2V4b249PSJGQUxTRSIsIE4gXSwKVGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5zdGF0c1tUeXBlPT0iQ0UiICYgaXMubWljcm9leG9uPT0iRkFMU0UiLCBUb3RhbC1OIF0pKQoKY2hpc3EudGVzdChDRS5jb250KQpgYGAKCgpgYGB7cn0KQ0UuY29udC50b3RhbCA8LSBtYXRyaXgobnJvdz0yLCBjKHN1bShUYXNpY190b3RhbF9kaWZmX25vZGVzLnN0YXRzWyBpcy5taWNyb2V4b249PSJUUlVFIiwgTiBdKSwKc3VtKFRhc2ljX3RvdGFsX2RpZmZfbm9kZXMuc3RhdHNbIGlzLm1pY3JvZXhvbj09IlRSVUUiLCBUb3RhbC1OIF0pLApzdW0oVGFzaWNfdG90YWxfZGlmZl9ub2Rlcy5zdGF0c1tpcy5taWNyb2V4b249PSJGQUxTRSIsIE4gXSksCnN1bShUYXNpY190b3RhbF9kaWZmX25vZGVzLnN0YXRzWyBpcy5taWNyb2V4b249PSJGQUxTRSIsIFRvdGFsLU4gXSkpKQoKY2hpc3EudGVzdChDRS5jb250LnRvdGFsKQpgYGAKCgoKCmBgYHtyfQpuPW5yb3coVGFzaWNfdG90YWxfZGlmZl9ub2RlcykKYT1ucm93KFRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbIGlzLmRpZmY9PSJUUlVFIiwgXSkKYj1ucm93KFRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbIGlzLm1pY3JvZXhvbj09IlRSVUUiLCBdKQp0PW5yb3coVGFzaWNfdG90YWxfZGlmZl9ub2Rlc1sgaXMubWljcm9leG9uPT0iVFJVRSIgJiAgaXMuZGlmZj09IlRSVUUiLCBdKQoKZGh5cGVyKHQsIGEsIG4gLSBhLCBiKQpzdW0oZGh5cGVyKHQ6YiwgYSwgbiAtIGEsIGIpKQpgYGAKCgoKCgpgYGB7cn0Kbj1ucm93KFRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbVHlwZT09IkNFIiwgXSkKYT1ucm93KFRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbVHlwZT09IkNFIiAmIGlzLmRpZmY9PSJUUlVFIiwgXSkKYj1ucm93KFRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbVHlwZT09IkNFIiAmIGlzLm1pY3JvZXhvbj09IlRSVUUiLCBdKQp0PW5yb3coVGFzaWNfdG90YWxfZGlmZl9ub2Rlc1tUeXBlPT0iQ0UiICYgaXMubWljcm9leG9uPT0iVFJVRSIgJiAgaXMuZGlmZj09IlRSVUUiLCBdKQoKZGh5cGVyKHQsIGEsIG4gLSBhLCBiKQpzdW0oZGh5cGVyKHQ6YiwgYSwgbiAtIGEsIGIpKQpgYGAKCgoKYGBge3J9Cgpucm93KFRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbIGlzLm1pY3JvZXhvbj09IlRSVUUiICYgIGlzLmRpZmY9PSJUUlVFIiwgXSkKYGBgCgoKCgoKYGBge3J9CgprIDwtIDI4ICMjIFNpemUgb2YgdGhlIHNlbGVjdGlvbiwgaS5lLiBzdWJtaXR0ZWQgZ2VuZXMgd2l0aCBhdCBsZWFzdCBvbmUgYW5ub3RhdGlvbiBpbiBHTyBiaW9sb2dpY2FsIHByb2Nlc3NlcwptIDwtIDIyMDQgKzI4ICMjIE51bWJlciBvZiAibWFya2VkIiBlbGVtZW50cywgaS5lLiBnZW5lcyBhc3NvY2lhdGVkIHRvIHRoaXMgYmlvbG9naWNhbCBwcm9jZXNzCk4gPC0gMjIwNCArICAjIyBUb3RhbCBudW1iZXIgb2YgZ2VuZXMgd2l0aCBzb21lIGFubm90YXRpb24gaW4gR09URVJNX0JQX0ZBVC4gIApuIDwtIE4gLSBtICMjIE51bWJlciBvZiAibm9uLW1hcmtlZCIgZWxlbWVudHMsIGkuZS4gZ2VuZXMgbm90IGFzc29jaWF0ZWQgdG8gdGhpcyBiaW9sb2dpY2FsIHByb2Nlc3MKeCA8LSA1OCAjIyBOdW1iZXIgb2YgIm1hcmtlZCIgZWxlbWVudHMgaW4gdGhlIHNlbGVjdGlvbiwgaS5lLiBnZW5lcyBvZiB0aGUgZ3JvdXAgb2YgaW50ZXJlc3QgdGhhdCBhcmUgYXNzb2NpYXRlZCB0byB0aGlzIGJpb2xvZ2ljYWwgcHJvY2VzcwoKcC52YWx1ZSA8LSAgcGh5cGVyKHE9eCAtMSwgbT1tLCBuPW4sIGs9aywgbG93ZXIudGFpbD1UUlVFKQpgYGAKCgoKCmBgYHtyfQoKClRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbaXMuZGlmZj09VFJVRSAmIGlzLm1pY3JvZXhvbj09VFJVRSwgXQoKClRhc2ljX3VucG9vbGVkX2RpZmZfZXhvbnMgPC0gZnJlYWQoIi9Vc2Vycy9ncDcvR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvRmluYWxfUmVwb3J0L1JlcHMvUmVwMS9TaW5nbGVfQ2VsbC9VbnBvb2xlZC9HQUJBLWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbi5kaWZmLm1pY3JvZXhvbnMiKQoKVGFzaWNfdW5wb29sZWRfcG9vbGVkIDwtIG1lcmdlKFRhc2ljX3VucG9vbGVkX2RpZmZfZXhvbnNbICwgYygiZXhvbl9JRCIsICJQcm9iYWJpbGl0eSIsICJEZWx0YVBzaSIpXSwgClRhc2ljX3RvdGFsX2RpZmZfbm9kZXNbIGlzLm1pY3JvZXhvbj09VFJVRSAsIC4oZXhvbl9JRD1taWNyb2V4b25fSUQsIG1lYW5fUHJvYmFiaWxpdHk9UHJvYmFiaWxpdHkubWVhbiwgbWVhbl9EZWx0YVBzaT1EZWx0YVBzaS5tZWFuLCBzaWdfcG9vbD1pcy5kaWZmKSAgXSwKYnk9ImV4b25fSUQiKQoKVGFzaWNfdW5wb29sZWRfcG9vbGVkWyAsIHNpZ191bnBvb2w6PUZBTFNFIF0KVGFzaWNfdW5wb29sZWRfcG9vbGVkWyBhYnMoRGVsdGFQc2kpID49IDAuMSAmICBQcm9iYWJpbGl0eT49MC45LCBzaWdfdW5wb29sOj1UUlVFIF0KCgoKIFRhc2ljX3VucG9vbGVkX3Bvb2xlZFsgICwuTiwgYnk9YyggInNpZ191bnBvb2wiLCAic2lnX3Bvb2wiKSBdCgoKYGBgCgoKYGBge3J9CiBUYXNpY191bnBvb2xlZF9wb29sZWRbICAsLk4sIGJ5PWMoICJzaWdfdW5wb29sIiwgInNpZ19wb29sIikgXQpgYGAKCgoKIyMgVGFzaWMKCmBgYHtyfQojVGFzaWNfdW5wb29sZWRfZGlmZl9leG9ucyA8LSBkYXRhLnRhYmxlKHJlYWRfZGVsaW0oIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvTmV3X3JlcG9ydC9XaGlwcGV0X0RlbHRhL1Rhc2ljL0dBQkEtZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLmRpZmYuUG90ZW50aWFsX0V4b24uZXhvbl9JRC5vbmx5X01FLmRpZmYiLCAKIyAgICAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKSkKCgoKCiNUYXNpY19wb29sZWRfZGlmZl9leG9ucyA8LSBkYXRhLnRhYmxlKHJlYWRfZGVsaW0oIn4vR29vZ2xlX0RyaXZlL1Jlc3VsdHMvTUUvUGFwZXIvTmV3X3JlcG9ydC9XaGlwcGV0X0RlbHRhL1Rhc2ljL1Bvb2wvVE9UQUwuUG9vbC5vbmx5X01FLmRpZmYiLCAKIyAgICAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKSkKCgoKVGFzaWNfdW5wb29sZWRfZGlmZl9leG9ucyA8LSBmcmVhZCgiL1VzZXJzL2dwNy9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9QYXBlci9GaW5hbF9SZXBvcnQvUmVwcy9SZXAxL1NpbmdsZV9DZWxsL1VucG9vbGVkL0dBQkEtZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLmRpZmYubWljcm9leG9ucyIpCgpUYXNpY19wb29sZWRfZGlmZl9leG9ucyA8LSBkYXRhLnRhYmxlKCkKCmZvciAoIGkgaW4gc2VxKDE6MTApKXsKICAKICBwYXRoIDwtIHBhc3RlMCgiL1VzZXJzL2dwNy9Hb29nbGVfRHJpdmUvUmVzdWx0cy9NRS9QYXBlci9GaW5hbF9SZXBvcnQvUmVwcy9SZXAxL1NpbmdsZV9DZWxsL0dBQkEtZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uX3JlcF8iLCBpLCAiLmRpZmYubWljcm9leG9ucyIpCiAgZmlsZSA8LSBmcmVhZChwYXRoKQogIGZpbGVbLCBSZXA6PWldCiAgVGFzaWNfcG9vbGVkX2RpZmZfZXhvbnMgPC0gcmJpbmQoVGFzaWNfcG9vbGVkX2RpZmZfZXhvbnMsIGZpbGUpCiAgCn0KCgpgYGAKCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRhdGEudGFibGUpCgpnZ3Bsb3QoVGFzaWNfdW5wb29sZWRfZGlmZl9leG9ucykgKwogIGdlb21faGlzdG9ncmFtKGFlcyhFbnRyb3B5KSwgYmlud2lkdGg9MC4xKQoKYGBgCgoKYGBge3J9CgpUYXNpY191bnBvb2xlZF9wb29sZWQgPC0gbWVyZ2UoVGFzaWNfdW5wb29sZWRfZGlmZl9leG9uc1sgLCBjKCJleG9uX0lEIiwgIlByb2JhYmlsaXR5IiwgIkRlbHRhUHNpIildLCAKVGFzaWNfcG9vbGVkX2RpZmZfZXhvbnNbICwgLiggbWVhbl9Qcm9iYWJpbGl0eT1tZWFuKFByb2JhYmlsaXR5KSwgbWVhbl9EZWx0YVBzaT1tZWFuKERlbHRhUHNpKSkgLCBieT0iZXhvbl9JRCIgIF0sCmJ5PSJleG9uX0lEIikKClRhc2ljX3VucG9vbGVkX3Bvb2xlZFsgLCBzaWdfdW5wb29sOj1GQUxTRSBdClRhc2ljX3VucG9vbGVkX3Bvb2xlZFsgYWJzKERlbHRhUHNpKSA+PSAwLjEgJiAgUHJvYmFiaWxpdHk+PTAuOSwgc2lnX3VucG9vbDo9VFJVRSBdCgpUYXNpY191bnBvb2xlZF9wb29sZWRbICwgc2lnX3Bvb2w6PUZBTFNFIF0KVGFzaWNfdW5wb29sZWRfcG9vbGVkWyBhYnMobWVhbl9EZWx0YVBzaSkgPj0gMC4xICYgIG1lYW5fUHJvYmFiaWxpdHk+PTAuOSwgc2lnX3Bvb2w6PVRSVUUgXQoKVGFzaWNfcG9vbGVkX2RpZmZfZXhvbnNbLCBzZF9wcm9iYWJpbGl0eTo9c2QoUHJvYmFiaWxpdHkpICwgYnk9IkNvb3JkIl0KCmdncGxvdChUYXNpY19wb29sZWRfZGlmZl9leG9ucykgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PXNkX3Byb2JhYmlsaXR5KSkKYGBgCgoKYGBge3J9Cm5yb3coVGFzaWNfdW5wb29sZWRfcG9vbGVkW3NpZ191bnBvb2w9PSJUUlVFIl0pCm5yb3coVGFzaWNfdW5wb29sZWRfcG9vbGVkW3NpZ19wb29sPT0iVFJVRSJdKQpgYGAKCgpgYGB7cn0KZ2dwbG90KCkgKwogIAogIGdlb21fcG9pbnQoIGRhdGE9VGFzaWNfdW5wb29sZWRfcG9vbGVkLCBhZXMobWVhbl9EZWx0YVBzaSAtIERlbHRhUHNpICwgbWVhbl9Qcm9iYWJpbGl0eSAtUHJvYmFiaWxpdHkgKSkgKwogIGdlb21fcG9pbnQoIGRhdGE9VGFzaWNfdW5wb29sZWRfcG9vbGVkW3NpZ191bnBvb2w9PUZBTFNFICYgc2lnX3Bvb2w9PVRSVUVdICAsIGFlcyhtZWFuX0RlbHRhUHNpIC0gRGVsdGFQc2kgLCBtZWFuX1Byb2JhYmlsaXR5IC1Qcm9iYWJpbGl0eSApLCBjb2xvcj0icmVkIiApICsKICBnZW9tX3BvaW50KCBkYXRhPVRhc2ljX3VucG9vbGVkX3Bvb2xlZFtzaWdfdW5wb29sPT1UUlVFICYgc2lnX3Bvb2w9PVRSVUVdICAsIGFlcyhtZWFuX0RlbHRhUHNpIC0gRGVsdGFQc2kgLCBtZWFuX1Byb2JhYmlsaXR5IC1Qcm9iYWJpbGl0eSApLCBjb2xvcj0iZ3JlZW4iICkgKwogIGdlb21fcG9pbnQoIGRhdGE9VGFzaWNfdW5wb29sZWRfcG9vbGVkW3NpZ191bnBvb2w9PVRSVUUgJiBzaWdfcG9vbD09RkFMU0VdICAsIGFlcyhtZWFuX0RlbHRhUHNpIC0gRGVsdGFQc2kgLCBtZWFuX1Byb2JhYmlsaXR5IC1Qcm9iYWJpbGl0eSApLCBjb2xvcj0iYmx1ZSIgKSArCiAgdGhlbWVfYncoKQoKYGBgCgoKCmBgYHtyfQpTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbl9vbGQgPC0gU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24KClNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uX29sZFsgb3JkZXIoLWFicyhtZWFuX0RlbHRhUHNpKSksIGMoImV4b25fSUQiLCAibWdpX3N5bWJvbCIsICJ3aWtpZ2VuZV9kZXNjcmlwdGlvbiIsICJtZWFuX0RlbHRhUHNpIiwgIm1lYW5fUHJvYmFiaWxpdHkiKV0KYGBgCgoKCmBgYHtyfQoKU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24gPC0gVGFzaWNfdW5wb29sZWRfcG9vbGVkW2FicyhtZWFuX0RlbHRhUHNpIC0gRGVsdGFQc2kpIDw9MC4yNSAmICBzaWdfcG9vbD09VFJVRSwgXQoKU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24gPC0gbWVyZ2UoIFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLCB1bmlxdWUoZ2VuZV90YWJsZS5UT1RBTFssIGMoIk1FIiwgIm1naV9zeW1ib2wiKV0pLCBieS54PSJleG9uX0lEIiwgYnkueT0iTUUiKQoKI1NpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uIDwtIG1lcmdlKCBTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbiAsIHVuaXF1ZShnZW5lX2luZm9fdG90YWxbICwgYygibWdpX3N5bWJvbCIsICJ3aWtpZ2VuZV9kZXNjcmlwdGlvbiIpXSksIGJ5PSAibWdpX3N5bWJvbCIpCgoKClNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uWyBvcmRlcigtYWJzKG1lYW5fRGVsdGFQc2kpKV0KCmxlbmd0aCh1bmlxdWUoU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bLCBtZ2lfc3ltYm9sXSkpCmBgYAoKCgoKCmBgYHtyfQoKI3JlZiBTbGM0YTEwIGh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9hcnRpY2xlcy8xMC4zMzg5L2ZuY2VsLjIwMTUuMDAyMjMvZnVsbAojcmVmIEFuazMgaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMDg5NjYyNzMxNDAwOTA4OAojcmVmIEtDTk1BMSBodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MwODk2NjI3MzEzMDAxODUyCiNyZWYgS2lmM2EgaHR0cHM6Ly93d3cuc2NpZW5jZWRpcmVjdC5jb20vc2NpZW5jZS9hcnRpY2xlL3BpaS9TMDg5NjYyNzMwMzAwMDYyWAojIHJlZiBETEdBUCBodHRwczovL21vbGVjdWxhcmJyYWluLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvczEzMDQxLTAxNy0wMzI0LTkKCgpQcmVfc3luYXB0aWMgPC0gYyggIlB0cHJkIiAsICJQcGZpYTIiLCAiRGxnYXAxIiwgIkdhYnJnMiIsICJLY25tYTEiLCAiS2lmM2EiLCAiQ2FkcHMiKSAKUG9zdF9zeW5hcHRpYyA8LSBjKCAiTnJ4bjMiICwgIk5yeG4xIikKUHJlUG9zdF9zeW5hcHRpYyA8LSBjKCJBbmszIiwiU2xjNGExMCIpCmBgYAoKCgoKCmBgYHtyfQoKU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bICAhZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSAmICAhZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfVmFzdGRiICwgYygiZXhvbl9JRCIsICJtZ2lfc3ltYm9sIiwgIndpa2lnZW5lX2Rlc2NyaXB0aW9uIiwgIm1lYW5fRGVsdGFQc2kiLCAibWVhbl9Qcm9iYWJpbGl0eSIpXVtvcmRlcigtYWJzKG1lYW5fRGVsdGFQc2kpKV0KCm1pY3JvZXhvbnNfR0VOQ09ERQptaWNyb2V4b25zX1Zhc3RkYgpgYGAKCgpgYGB7cn0KQnJhaW5fc3RyaW5nX2ludGVyYWN0aW9uc19vdXRbbWdpX3N5bWJvbD09IkFrYXAxMyIsXQpgYGAKCgpgYGB7cn0Kd3JpdGUudGFibGUoU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24sIGZpbGUgPSAifi9EZXNrdG9wL1NpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLnR4dCIsIGFwcGVuZCA9IEZBTFNFLCBxdW90ZSA9IEYsIHNlcCA9ICJcdCIsCiAgICAgICAgICAgIGVvbCA9ICJcbiIsIG5hID0gIk5BIiwgZGVjID0gIi4iLCByb3cubmFtZXMgPSBGLAogICAgICAgICAgICBjb2wubmFtZXMgPSBUUlVFLCBxbWV0aG9kID0gYygiZXNjYXBlIiwgImRvdWJsZSIpLAogICAgICAgICAgICBmaWxlRW5jb2RpbmcgPSAiIikKYGBgCgoKYGBge3J9CgoKZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChkYXRhPVRhc2ljX3VucG9vbGVkX3Bvb2xlZCwgYWVzKG1lYW5fRGVsdGFQc2ksIG1lYW5fUHJvYmFiaWxpdHkpKSArCiAgZ2VvbV9wb2ludChkYXRhPVNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLCBhZXMobWVhbl9EZWx0YVBzaSwgbWVhbl9Qcm9iYWJpbGl0eSksIGNvbG9yPSJyZWQiKQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CmxpYnJhcnkoImdncmVwZWwiKQoKCgpTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvblttZ2lfc3ltYm9sICVpbiUgUHJlX3N5bmFwdGljLCBMb2NhdGlvbjo9IlByZXN5bmFwdGljIl0KU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bbWdpX3N5bWJvbCAlaW4lIFBvc3Rfc3luYXB0aWMsIExvY2F0aW9uOj0iUG9zdHN5bmFwdGljIl0KU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bbWdpX3N5bWJvbCAlaW4lIFByZVBvc3Rfc3luYXB0aWMsIExvY2F0aW9uOj0iQm90aCJdCgoKCiNTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbiA8LSBTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvblshZXhvbl9JRCAlaW4lIE1FX2JsYWNrbGlzdCRNRV0KCmdncGxvdCgpKwogIGdlb21fcG9pbnQoZGF0YT1UYXNpY191bnBvb2xlZF9wb29sZWQsIGFlcyhtZWFuX0RlbHRhUHNpLCBtZWFuX1Byb2JhYmlsaXR5KSwgY29sb3I9ImdyZXkiKSArCiAgZ2VvbV9wb2ludChkYXRhPVNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLCBhZXMobWVhbl9EZWx0YVBzaSwgbWVhbl9Qcm9iYWJpbGl0eSksIGNvbG9yPSJibGFjayIpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uW21naV9zeW1ib2wgJWluJSBQcmVfc3luYXB0aWNdLAogICAgICAgICAgICAgICAgICBjb2xvdXI9ImZvcmVzdGdyZWVuIiwgYWVzKHg9bWVhbl9EZWx0YVBzaSwgeT1tZWFuX1Byb2JhYmlsaXR5KSwgCiAgICAgICAgICAgICAgICAgIG51ZGdlX3kgICAgICA9IDMsCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgICAgICAgYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgICAgICAgIHZqdXN0ICAgICAgICA9IDEsCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgbGFiZWw9U2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bbWdpX3N5bWJvbCAlaW4lIFByZV9zeW5hcHRpYyAsIG1naV9zeW1ib2xdICkgKwogIAogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bbWdpX3N5bWJvbCAlaW4lIFBvc3Rfc3luYXB0aWNdLAogICAgICAgICAgICAgICAgICBjb2xvdXI9ImZpcmVicmljazQiLCBhZXMoeD1tZWFuX0RlbHRhUHNpLCB5PW1lYW5fUHJvYmFiaWxpdHkpLCAKICAgICAgICAgICAgICAgICAgbnVkZ2VfeSAgICAgID0gMywKICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uICAgID0gIngiLAogICAgICAgICAgICAgICAgICBhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICAgdmp1c3QgICAgICAgID0gMSwKICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC4yLAogICAgICAgICAgICAgICAgICBsYWJlbD1TaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvblttZ2lfc3ltYm9sICVpbiUgUG9zdF9zeW5hcHRpYyAsIG1naV9zeW1ib2xdICkgKwogIAogIAogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bbWdpX3N5bWJvbCAlaW4lIFByZVBvc3Rfc3luYXB0aWNdLAogICAgICAgICAgICAgICAgICBjb2xvdXI9ImRhcmtnb2xkZW5yb2QiLCBhZXMoeD1tZWFuX0RlbHRhUHNpLCB5PW1lYW5fUHJvYmFiaWxpdHkpLCAKICAgICAgICAgICAgICAgICAgbnVkZ2VfeSAgICAgID0gMywKICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uICAgID0gIngiLAogICAgICAgICAgICAgICAgICBhbmdsZSAgICAgICAgPSA5MCwKICAgICAgICAgICAgICAgICAgdmp1c3QgICAgICAgID0gMSwKICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC4yLAogICAgICAgICAgICAgICAgICBsYWJlbD1TaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvblttZ2lfc3ltYm9sICVpbiUgUHJlUG9zdF9zeW5hcHRpYyAsIG1naV9zeW1ib2xdICkgKwogICAgCiAgCiAgeWxpbSgwLjUsIDEuMTUpICsKICB0aGVtZV9idygpICsKICB4bGFiKCIiKSArCiAgeGxhYigiTWVhbiBkZWx0YSBQU0kiKSArCiAgeWxhYigiTWVhbiBwcm9iYWJpbGl0eSIpCgoKCgpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CgoKU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bbWdpX3N5bWJvbCAlaW4lIFByZV9zeW5hcHRpYywgTG9jYXRpb246PSJQcmVzeW5hcHRpYyJdClNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uW21naV9zeW1ib2wgJWluJSBQb3N0X3N5bmFwdGljLCBMb2NhdGlvbjo9IlBvc3RzeW5hcHRpYyJdClNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uW21naV9zeW1ib2wgJWluJSBQcmVQb3N0X3N5bmFwdGljLCBMb2NhdGlvbjo9IkJvdGgiXQoKCgpnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGRhdGE9VGFzaWNfdW5wb29sZWRfcG9vbGVkLCBhZXMobWVhbl9EZWx0YVBzaSwgbWVhbl9Qcm9iYWJpbGl0eSksIGNvbG9yPSJncmV5IikgKyAgIyBGaW5hbCB2ZXJzaW9uCiAgZ2VvbV9wb2ludChkYXRhPVNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLCBhZXMobWVhbl9EZWx0YVBzaSwgbWVhbl9Qcm9iYWJpbGl0eSksIGNvbG9yPSJibGFjayIpICsKICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uWyFpcy5uYShMb2NhdGlvbildLAogICAgICAgICAgICAgICAgICBhZXMoeD1tZWFuX0RlbHRhUHNpLCB5PW1lYW5fUHJvYmFiaWxpdHksIGNvbG91cj1Mb2NhdGlvbiksIAogICAgICAgICAgICAgICAgICBudWRnZV95ICAgICAgPSAzLAogICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gICAgPSAieCIsCiAgICAgICAgICAgICAgICAgIGFuZ2xlICAgICAgICA9IDkwLAogICAgICAgICAgICAgICAgICB2anVzdCAgICAgICAgPSAxLAogICAgICAgICAgICAgICAgICBzZWdtZW50LnNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgIGxhYmVsPVNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uWyFpcy5uYShMb2NhdGlvbiksIG1naV9zeW1ib2xdKSArCiAgCiAgeWxpbSgwLjUsIDEuMTUpICsKICB0aGVtZV9idygpICsKICB4bGFiKCIiKSArCiAgeGxhYigiTWVhbiBkZWx0YSBQU0kiKSArCiAgeWxhYigiTWVhbiBwcm9iYWJpbGl0eSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoICJkYXJrZ29sZGVucm9kIiwgICJmaXJlYnJpY2s0IiwgImZvcmVzdGdyZWVuIikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYCAKCgpgYGB7cn0KdW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUkYnJvYWRfdHlwZSkKYGBgCgoKCmBgYHtyfQpwcmltYXJ5X3R5cGVfbGV2ZWxzIDwtIGModW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbYnJvYWRfdHlwZT09IkVuZG90aGVsaWFsIENlbGwiLCBwcmltYXJ5X3R5cGVdKSwKdW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbYnJvYWRfdHlwZT09Ik9saWdvZGVuZHJvY3l0ZSIsIHByaW1hcnlfdHlwZV0pLAp1bmlxdWUoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVticm9hZF90eXBlPT0iTWljcm9nbGlhIiwgcHJpbWFyeV90eXBlXSksCnVuaXF1ZShNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlW2Jyb2FkX3R5cGU9PSJPbGlnb2RlbmRyb2N5dGUgUHJlY3Vyc29yIENlbGwiLCBwcmltYXJ5X3R5cGVdKSwKc29ydCh1bmlxdWUoTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVticm9hZF90eXBlPT0iQXN0cm9jeXRlIiwgcHJpbWFyeV90eXBlXSkpLApzb3J0KHVuaXF1ZShNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlW2Jyb2FkX3R5cGU9PSJHbHV0YW1hdGVyZ2ljIE5ldXJvbiIsIHByaW1hcnlfdHlwZV0pKSwKdW5pcXVlKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGVbYnJvYWRfdHlwZT09IkdBQkEtZXJnaWMgTmV1cm9uIiwgcHJpbWFyeV90eXBlXSkgKQoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZSRwcmltYXJ5X3R5cGUgPC0gZmFjdG9yKE1FX2Nvdl9maWx0ZXJlZF90YXNpY19wcmltYXJ5X3R5cGUkcHJpbWFyeV90eXBlICwgbGV2ZWxzID0gcHJpbWFyeV90eXBlX2xldmVscykKCmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoPTQuNSwgIGZpZy5oZWlnaHQ9Nn0KCnRhcmdldF9nZW5lcyA8LSBjKCJHYWJyZzIiLCAiTnJ4bjEiLCAiTnJ4bjMiLCAiUHRwcmQiKQoKTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVsobWdpX3N5bWJvbCAlaW4lIHRhcmdldF9nZW5lcykgJiAoTUUgJWluJSBTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbiRleG9uX0lEKV0KTUVfY292X2ZpbHRlcmVkX3Rhc2ljX3ByaW1hcnlfdHlwZVtpcy5uYShQU0kpLCBgOj1gKGxvd2VyPU5BLCB1cHBlcj1OQSkgXQoKCmdncGxvdChNRV9jb3ZfZmlsdGVyZWRfdGFzaWNfcHJpbWFyeV90eXBlWyBtZ2lfc3ltYm9sICVpbiUgdGFyZ2V0X2dlbmVzICYgTUUgJWluJSBTaWdfR0FCQWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbiRleG9uX0lELCBdICApICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHg9cHJpbWFyeV90eXBlLCB5PVBTSSwgY29sb3VyPSBicm9hZF90eXBlLCBncm91cD1icm9hZF90eXBlLCB5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSkrCiAgZmFjZXRfZ3JpZCggcGFzdGUwKCBtZ2lfc3ltYm9sLCBNRSkgfiAuICkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKQpgYGAKCgoKYGBge3J9CmNhdCggdW5pcXVlKFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uJG1naV9zeW1ib2wpLCBzZXA9J1xuJykKYGBgCgoKIyMjIyMjCgpOdW1iZXJzIApgYGB7cn0KCiMjI0Fic3RyYWN0CgoKQnVsa19STkFfU0VRLlRhYmxlIDwtICB0YWJsZShncmVwbCgiRU5DIiwgIHVuaXF1ZShNRV9jb3ZfZmlsdGVyZWRbLCBGSUxFX05BTUVdKSkpCgpUb3RhbF9CdWxrX1JOQV9zZXEgPC0gc3VtKEJ1bGtfUk5BX1NFUS5UYWJsZSkKVG90YWxfc2NSTkFfc2VxIDwtbnJvdyh0YXNpY19tZXRhZGF0YSkKClRvdGFsX21pY3JvZXhvbi5udW1iZXIgPC0gbGVuZ3RoKE1FX2ZpbmFsWyAsIHVuaXF1ZShNRSldKQojSE5NRl9taWNyb2V4b25zLm51bWJlciA8LSBsZW5ndGgoRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsX1BQSVsgLCB1bmlxdWUoZXhvbl9JRCldKQoKCgpkaWZmX3NwbGljZWQuYnJhaW5fZGV2IDwtIGxlbmd0aCh1bmlxdWUoRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRCAsIERlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbCRleG9uX0lEKSkKCgpkaWZmX3NwbGljZWQuYnJhaW5fZGV2Lm5vdmVsIDwtICBsZW5ndGgodW5pcXVlKERlbHRhX0hOTV93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWyAhIGV4b25fSUQgJWluJSBjKG1pY3JvZXhvbnNfVmFzdGRiLCBtaWNyb2V4b25zX0dFTkNPREUpICwgIGV4b25fSUQgIF0sIERlbHRhX0Zfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFsgISBleG9uX0lEICVpbiUgYyhtaWNyb2V4b25zX1Zhc3RkYiwgbWljcm9leG9uc19HRU5DT0RFKSAsICBleG9uX0lEICBdKSkKCgojIyMgSW50cm9kdWN0aW9uCgpUb3RhbF9taWNyb2V4b24ubnVtYmVyLm5vdF9nZW5jb2RlIDwtIGxlbmd0aChNRV9maW5hbFsgIU1FICVpbiUgbWljcm9leG9uc19HRU5DT0RFICwgdW5pcXVlKE1FKV0pClRvdGFsX21pY3JvZXhvbi5udW1iZXIubm90X2dlbmNvZGUucGVyY2VudGFnZSA8LSAoVG90YWxfbWljcm9leG9uLm51bWJlci5ub3RfZ2VuY29kZSAvIFRvdGFsX21pY3JvZXhvbi5udW1iZXIpKjEwMAoKCmRpZmZfc3BsaWNlZC5icmFpbl9kZXYubm90X3Zhc3RkYiA8LSAgbGVuZ3RoKHVuaXF1ZShEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFsgISBleG9uX0lEICVpbiUgYyhtaWNyb2V4b25zX1Zhc3RkYikgLCAgZXhvbl9JRCAgXSwgRGVsdGFfRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWyAhIGV4b25fSUQgJWluJSBjKG1pY3JvZXhvbnNfVmFzdGRiKSAsICBleG9uX0lEICBdKSkKCgpkaWZmX3NwbGljZWQuYnJhaW5fZGV2Lm5vdF92YXN0ZGIucGVyY2VudGFnZSA8LSAoZGlmZl9zcGxpY2VkLmJyYWluX2Rldi5ub3RfdmFzdGRiL2RpZmZfc3BsaWNlZC5icmFpbl9kZXYpKjEwMAoKCgpjb25zZXJ2ZWRfemVicmEgPC0gIGxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzWyAsIE1FLnplYnJhXSkpCgoKY29uc2VydmVkX3plYnJhLm5vdF9lbnNlbWJsIDwtIGxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzW2Vuc2VtYmxlX3plYnJhPT1GQUxTRSwgTUUuemVicmFdKSkKCgoKCiNSZXN1bHRzIAoKbWVfYWZ0ZXJfMTBfc2FtcGxlc19maWx0ZXIgPC0gcm93bmFtZXMoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3RbYXBwbHkoVGlzc3VlX1BTSV9tYXRyaXhfZGNhc3QsIDEsIGZ1bmN0aW9uKHgpIGxlbmd0aCh3aGljaChpcy5uYSh4KSkpKSA8IDI4OSowLjksIF0pCgpNRV9maW5hbC5vdXRbTUUgJWluJSBtZV9hZnRlcl8xMF9zYW1wbGVzX2ZpbHRlciwgLk4sICBieT0idHlwZSJdCgoKCnN5bV9wZXJjZW50YWdlLm5ldXJvbmFsX25ldXJvbXVzY3VsYXJfbXVzY3VsYXIgPC0gTUVfY2x1c3Rlcl9uYW1lc1sgTUVfY2x1c3Rlci50eXBlICVpbiUgYygiTmV1cm9uYWwiLCAiTmV1cm8tTXVzY3VsYXIiLCAiTXVzY3VsYXIiKSAsIDEwMC0gKHN1bShhc3ltKS9zdW0odG90YWwpKSoxMDBdCgoKRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsCgpITk1GX21pY3JvZXhvbnMubm90X3Zhc3RkYi5udW1iZXIgPC0gbnJvdyhEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxfUFBJWyFleG9uX0lEICVpbiUgbWljcm9leG9uc19WYXN0ZGIsIF0pCkhOTUZfbWljcm9leG9ucy5ub3RfdmFzdGRiLnBlcmNlbnRhZ2UgPC0gcm91bmQoKEhOTUZfbWljcm9leG9ucy5ub3RfdmFzdGRiLm51bWJlci9ITk1GX21pY3JvZXhvbnMubnVtYmVyKSoxMDAsIDIpCgoKTm92ZWxfZ2VuY29kZS5udW1iZXIgPC0gbnJvdyhNRV9maW5hbFsgLCAuTiwgYnk9TUUgXVsgIU1FICVpbiUgbWljcm9leG9uc19HRU5DT0RFLCBdKQpOb3ZlbF9nZW5jb2RlLnBlcmNlbnRhZ2UgPC0gKE5vdmVsX2dlbmNvZGUubnVtYmVyIC8gVG90YWxfbWljcm9leG9uLm51bWJlcikgKjEwMAoKCk5vdmVsX3Zhc3RkYi5udW1iZXIgPC0gbnJvdyhNRV9maW5hbFsgLCAuTiwgYnk9TUUgXVsgIU1FICVpbiUgbWljcm9leG9uc19WYXN0ZGIsIF0pCk5vdmVsX3Zhc3RkYi5wZXJjZW50YWdlIDwtIChOb3ZlbF92YXN0ZGIubnVtYmVyIC8gVG90YWxfbWljcm9leG9uLm51bWJlcikgKjEwMAoKCk1ITl9kaWZmLndoaXBwZXRfTUUgPC0gbGVuZ3RoKCB1bmlxdWUoRGVsdGFfSE5NX3doaXBwZXRbIGFicyhEZWx0YVBzaSk+PTAuMSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgJiBleG9uX0lEICVpbiUgIERlbHRhX0hOTV9NRVsgYWJzKERlbHRhUHNpKT49MC4xICYgIFByb2JhYmlsaXR5ID49IDAuOSAsICBleG9uX0lEIF0gICAsICBleG9uX0lEIF0pKQpGX2RpZmYud2hpcHBldF9NRSA8LSBsZW5ndGgoIHVuaXF1ZShEZWx0YV9GX3doaXBwZXRbIGFicyhEZWx0YVBzaSk+PTAuMSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgJiBleG9uX0lEICVpbiUgIERlbHRhX0ZfTUVbIGFicyhEZWx0YVBzaSk+PTAuMSAmICBQcm9iYWJpbGl0eSA+PSAwLjkgLCAgZXhvbl9JRCBdICAgLCAgZXhvbl9JRCBdKSkKCgpkaWZmX2hlYXJ0IDwtIG5yb3coRGVsdGFfSGVhcnRfd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUsIF0pCmRpZmZfU0tNIDwtIG5yb3coRGVsdGFfU0tNX3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFLCBdKQpkaWZmX0FHIDwtIG5yb3coRGVsdGFfQUdfd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUsIF0pCgoKCgpEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgdHlwZTo9IkFubm90YXRlZCIgIF0KRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWyFleG9uX0lEICVpbiUgbWljcm9leG9uc19WYXN0ZGIsIHR5cGU6PSJNaXNzaW5nIGluIFZhc3REQiIgICBdCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFshZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSwgdHlwZTo9Ik1pc3NpbmcgaW4gR0VOQ09ERSIgICBdCkRlbHRhX0hOTUZfd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFshZXhvbl9JRCAlaW4lIG1pY3JvZXhvbnNfR0VOQ09ERSAmICFleG9uX0lEICVpbiUgbWljcm9leG9uc19WYXN0ZGIgLCB0eXBlOj0iTm92ZWwiICAgXQoKdGFibGUoRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsJHR5cGUpCk1FX3NpemVzIDwtIE1FX2ZpbmFsLnJlcDEkbGVuX21pY3JvX2V4b25fc2VxX2ZvdW5kCm5hbWVzKE1FX3NpemVzKSA8LSBNRV9maW5hbC5yZXAxJE1FCgoKRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWyB0eXBlPT0iTm92ZWwiLCAuTiAsIGJ5PWMoInR5cGUiLCAiTUVfbGVuIikgXQoKCgoKU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb25bIHNpZ191bnBvb2w9PVRSVUUgLCAgXQpgYGAKCgpgYGB7ciwgZml9CmdncGxvdChEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1NRV9sZW4sIGZpbGw9dHlwZSksIGJpbndpZHRoPTEpICsKICBmYWNldF9ncmlkKCAgdHlwZSB+IC4pICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9Ik1pY3JvZXhvbiB0eXBlIikgKwogIHhsYWIoIk1pY3JvZXhvbiBsZW5ndGgiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkKICAKYGBgCgoKCmBgYHtyfQoKCgoKCk1pY3JvZXhvbnMuUFBDQS5udW1iZXIgPC0gbGVuZ3RoKHVuaXF1ZShoY19yb3dzJGxhYmVscykpCgpUaXNzdWVfY2x1c3RlcnMudGFibGUgPC0gVGlzc3VlX2NsdXN0ZXJzWyAsIC5OICwgYnk9Y2x1c3RlciBdCk1FX2NsdXN0ZXJzLnRhYmxlIDwtIE1FX2NsdXN0ZXJzLm5hbWVzWyAsIC5OICwgYnk9TUVfY2x1c3Rlci5uYW1lIF0KCgpzYW1wbGVzX2NvbnRyb2wuZGlmZi5udW1iZXIgPC0gVGlzc3VlX2NsdXN0ZXJzLnRhYmxlWyBjbHVzdGVyICVpbiUgYygxLCAzLCA4KSwgc3VtKE4pXQoKc2FtcGxlc19zaWcuZGlmZi50YWJsZSA8LSBUaXNzdWVfY2x1c3RlcnNbIEZpbGUuYWNjZXNzaW9uICVpbiUgbWV0YWRhdGFbIEJpb3NhbXBsZS50ZXJtLm5hbWUgJWluJSBjKCJmb3JlYnJhaW4iLCAiaGluZGJyYWluIiwgIm1pZGJyYWluIiwgIm5ldXJhbCB0dWJlIiwgImFkcmVuYWwgZ2xhbmQiLCAic2tlbGV0YWwgbXVzY2xlIHRpc3N1ZSIsICJoZWFydCIpLCAgRmlsZS5hY2Nlc3Npb25dLCAuTiwgYnk9Im5hbWUiICBdCnNhbXBsZXNfc2lnLmRpZmYubnVtYmVyIDwtIHNhbXBsZXNfc2lnLmRpZmYudGFibGVbLCBzdW0oTildCgoKdG90YWxfc2FtcGxlLmRpZmYubnVtYmVyIDwtIHNhbXBsZXNfc2lnLmRpZmYubnVtYmVyICsgc2FtcGxlc19jb250cm9sLmRpZmYubnVtYmVyCgpITk1GX21pY3JvZXhvbnMuR0VOQ09ERV9WQVNUREIudGFibGUgPC0gbmV1cm9uYWxfTUVfSE5NRlssIHVuaXF1ZShleG9uX0lEKSwgYnk9InR5cGUiXVsgLCAuTiwgYnk9InR5cGUiIF0KCgpOb3ZlbF9kaWZmLmxvbmdlcjQubnVtYmVyIDwtIGxlbmd0aCh1bmlxdWUoTUVfZmluYWxbIE1FICVpbiUgbmV1cm9uYWxfTUVfSE5NRlt0eXBlPT0iTm92ZWwiLCBleG9uX0lEXSAmIGxlbl9taWNyb19leG9uX3NlcV9mb3VuZD40LCBNRV0pKQoKCgoKClplYnJhX3NhbXBsZXMgPC0gbGVuZ3RoKHRvdGFsX3plYnJhX2NvdlsgLCB1bmlxdWUoRklMRV9OQU1FKV0pCgoKTm92ZWxfemVicmEgPC0gbGVuZ3RoKHVuaXF1ZShNb3VzZV9aZWJyYS5JRHNbIU1FLnplYnJhICVpbiUgZXhvbnMuemVicmEkVjQsIE1FLnplYnJhXSkpCgoKCmxlbmd0aCh1bmlxdWUoTW91c2VfWmVicmEuSURzWywgTUUuemVicmFdKSkKCgpUT1RBTF9NSE5fZXhvbnMubnVtYmVyIDwtIGxlbmd0aCh1bmlxdWUoRGVsdGFfSE5NX21lcmdlW2FicyhEZWx0YVBzaS54KT49MC4xICYgUHJvYmFiaWxpdHkueD4wLjkgJiBhYnMoRGVsdGFQc2kueSk+PTAuMSAmIFByb2JhYmlsaXR5Lnk+MC45LCBleG9uX0lEXSkpClRPVEFMX0ZfZXhvbnMubnVtYmVyIDwtIGxlbmd0aCh1bmlxdWUoRGVsdGFfRl9tZXJnZVthYnMoRGVsdGFQc2kueCk+PTAuMSAmIFByb2JhYmlsaXR5Lng+MC45ICYgYWJzKERlbHRhUHNpLnkpPj0wLjEgJiBQcm9iYWJpbGl0eS55PjAuOSwgZXhvbl9JRF0pKQoKVE9UQUxfTUhOX2V4b25zLnN1YnN0YWluZWQubnVtYmVyIDwtIGxlbmd0aCh1bmlxdWUoRGVsdGFfSE5NX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRCkpClRPVEFMX0ZfZXhvbnMuc3Vic3RhaW5lZC5udW1iZXIgPC0gbGVuZ3RoKHVuaXF1ZShEZWx0YV9GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRCkpCgoKRGlmZl9leG9uLkhlYXJ0Lm51bWJlciA8LSBsZW5ndGgodW5pcXVlKERlbHRhX0hlYXJ0X3doaXBwZXRfTUVbIWlzLm5hKGNoYW5nZV9kaXIpLCBleG9uX0lEIF0pKQpEaWZmX2V4b24uU0tNLm51bWJlciA8LSBsZW5ndGgodW5pcXVlKERlbHRhX1NLTV93aGlwcGV0X01FWyFpcy5uYShjaGFuZ2VfZGlyKSwgZXhvbl9JRCBdKSkKRGlmZl9leG9uLkFHLm51bWJlciA8LSBsZW5ndGgodW5pcXVlKERlbHRhX0FHX3doaXBwZXRfTUVbIWlzLm5hKGNoYW5nZV9kaXIpLCBleG9uX0lEIF0pKQoKCnJvdW5kKE1FX2NsdXN0ZXJfbmFtZXNbTUVfY2x1c3Rlci50eXBlICVpbiUgYygiTmV1cm8tTXVzY3VsYXIiLCAiTmV1cm9uYWwiLCAiTXVzY3VsYXIiKSwgbWVhbihtZWFuX1UyX3Njb3JlKV0sIDEpCmBgYAoKCgpgYGB7cn0KCiNyYXRpb25hbGU6IGh0dHBzOi8vd3d3Lmd1bmdvcmJ1ZGFrLmNvbS9ibG9nLzIwMTYvMDUvMjUvY29tcHV0aW5nLXNpZ25pZmljYW5jZS1vZi1vdmVybGFwLwoKQUdfYnJhaW4uaW50ZXJzZWN0Lm51bWJlciA8LSBsZW5ndGgoaW50ZXJzZWN0KERlbHRhX0FHX3doaXBwZXRfTUVbZGlmZl9oaWdoPT1UUlVFXSRleG9uX0lELCBEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWwkZXhvbl9JRCkpCgoKQUcubnVtYmVyIDwtIGxlbmd0aCh1bmlxdWUoRGVsdGFfQUdfd2hpcHBldF9NRVtkaWZmX2hpZ2g9PVRSVUUsIGV4b25fSURdKSkKYnJhaW4ubnVtYmVyIDwtIGxlbmd0aCh1bmlxdWUoRGVsdGFfSE5NRl93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsJGV4b25fSUQpKQoKTWljcm9leG9ucy5QUENBLm51bWJlcgoKcGh5cGVyKCBBR19icmFpbi5pbnRlcnNlY3QubnVtYmVyICwgQUcubnVtYmVyLCAgTWljcm9leG9ucy5QUENBLm51bWJlci1BRy5udW1iZXIsIGJyYWluLm51bWJlciwgbG93ZXIudGFpbCA9IEZBTFNFICApCmBgYAoKCgoKCiMjIyMjIFN1cHBsZW1lbnRhbCAKCgoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNH0KCgoKCk1FX2NsdXN0ZXJzX3RhYmxlIDwtIGRhdGEuZnJhbWUoTUVfY2x1c3RlcnMpCgpNRV9jbHVzdGVyc190YWJsZSRNRSA8LSByb3cubmFtZXMoTUVfY2x1c3RlcnNfdGFibGUpCk1FX2NsdXN0ZXJzX3RhYmxlIDwtIGRhdGEudGFibGUoTUVfY2x1c3RlcnNfdGFibGUpCgoKTUVfY2x1c3RlcnNfUFNJIDwtICBkYXRhLnRhYmxlKG1lcmdlKFRpc3N1ZV9QU0lfbWF0cml4X21lbHRfcHBjYSwgTUVfY2x1c3RlcnNfdGFibGUgLCBieT1jKCJNRSIpKSkKCgojTUVfY2x1c3RlcnNfUFNJIDwtIE1FX2NsdXN0ZXJzX1BTSVssIGMoIk1FIiwgIkZJTEVfTkFNRSIsICJNRV9jbHVzdGVycyIsICJQU0kiKV0KCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSTwtIG1lcmdlKE1FX2NsdXN0ZXJzX1BTSSwgUENBLCBieS54PSJGSUxFX05BTUUiLCBieS55PSJGaWxlLmFjY2Vzc2lvbiIpCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSVssIFRpc3N1ZV9jbHVzdGVyczo9Y2x1c3Rlcl0KClBDQV9sb2FkaW5nc19zdGF0cyRNRV9jbHVzdGVyIDwtIGZhY3RvcihQQ0FfbG9hZGluZ3Nfc3RhdHMkTUVfY2x1c3RlcikKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0kkTUVfY2x1c3RlcnMgPC0gZmFjdG9yKE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJJE1FX2NsdXN0ZXJzKQoKTUVfVGlzc3Vlc19jbHVzdGVyc19QU0kgPC0gbWVyZ2UoTUVfVGlzc3Vlc19jbHVzdGVyc19QU0ksIFBDQV9sb2FkaW5nc19zdGF0cywgYnkueD0iTUVfY2x1c3RlcnMiLCBieS55PSJNRV9jbHVzdGVyIiApCgpNRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSSRUaXNzdWVfY2x1c3RlcnMgPC0gZmFjdG9yKE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJJFRpc3N1ZV9jbHVzdGVycywgbGV2ZWxzPVBDQVssIG1lYW4oUEMxKSwgYnk9ImNsdXN0ZXIiIF1bb3JkZXIoVjEpXSRjbHVzdGVyKSAKCgoKc3ViX01FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJIDwtIE1FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJW2FicyhQQzFfbWVhbik+MCwgXQpzdWJfTUVfVGlzc3Vlc19jbHVzdGVyc19QU0kgPC0gZGF0YS50YWJsZShzdWJfTUVfVGlzc3Vlc19jbHVzdGVyc19QU0kpCnN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSSRNRV9jbHVzdGVycyA8LSBmYWN0b3Ioc3ViX01FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJJE1FX2NsdXN0ZXJzICwgbGV2ZWxzPU1FX2NsdXN0ZXJfbG9hZGluZ19vcmRlciApCgoKc3ViX01FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX2FnZ3JlZ2F0ZWQgPC0gIHN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSVssIGxpc3QoUFNJPW1lYW4oUFNJLCBuYS5ybSA9IFRSVUUpKSwgYnk9bGlzdChNRSwgTUVfY2x1c3RlcnMsICBUaXNzdWVfY2x1c3RlcnMpIF0Kc3ViX01FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX2FnZ3JlZ2F0ZWRfbWVhbiA8LSAgc3ViX01FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX2FnZ3JlZ2F0ZWRbLCBsaXN0KFBTST0gbWVhbihQU0ksIG5hLnJtPVRSVUUpICksIGJ5PWxpc3QoTUVfY2x1c3RlcnMsICBUaXNzdWVfY2x1c3RlcnMpIF0KCgpnZ3Bsb3QoICkgKwogICAgICAgIGdlb21fbGluZShkYXRhPSBzdWJfTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfYWdncmVnYXRlZCwgYWVzKGZhY3RvcihUaXNzdWVfY2x1c3RlcnMpLCBQU0ksIGdyb3VwPU1FKSwgY29sb3VyPSJncmV5IikgKwogICAgICAgIGdlb21fbGluZShkYXRhID0gc3ViX01FX1Rpc3N1ZXNfY2x1c3RlcnNfUFNJX2FnZ3JlZ2F0ZWRfbWVhbiwgYWVzKGZhY3RvcihUaXNzdWVfY2x1c3RlcnMpLCBQU0ksIGdyb3VwPU1FX2NsdXN0ZXJzKSwgIGNvbG91cj0icmVkIiApICsKICAgICAgICBmYWNldF9ncmlkKCBNRV9jbHVzdGVycyB+IC4pICsKICAgICAgICB4bGFiKCJTYW1wbGUgY2x1c3RlcnMgKHNvcnRlZCBieSBQQzEpIikgKwogICAgICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScsIGNvbG91ciA9ICdibGFjaycpKQoKCmNvbDEgPC0gYygiRTEiLCAiRTIiLCAiRTMiLCAiRTQiLCAiRTUiLCAiRTYiLCAiSTEiLCAiSTIiLCAiSTMiLCAiTTEiLCAiTTIiLCAiTTMiKQpjb2wyIDwtIGMoIk4xIiwgIk4yIiwgIk4zIiwgIk40IiwgIk5NMSIsICJOTTIiLCAiTk0zIiwgIk5OMSIsICJPMSIsICJPMiIsICJXTjEiLCAiV04yIikKCgpzdWJfTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfYWdncmVnYXRlZCRNRV9jbHVzdGVyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9hZ2dyZWdhdGVkJE1FX2NsdXN0ZXJzKSkgCnN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9hZ2dyZWdhdGVkX21lYW4kTUVfY2x1c3RlciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzdWJfTUVfVGlzc3Vlc19jbHVzdGVyc19QU0lfYWdncmVnYXRlZF9tZWFuJE1FX2NsdXN0ZXJzKSkgCgpwbG90X2dyaWQoCmdncGxvdCggKSArCiAgICAgICAgZ2VvbV9saW5lKGRhdGE9IG1lcmdlKHN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9hZ2dyZWdhdGVkLCBNRV9jbHVzdGVyX25hbWVzLCBieS54PSJNRV9jbHVzdGVyIiwgIGJ5Lnk9Ik1FX2NsdXN0ZXIiKVtNRV9jbHVzdGVyLm5hbWUgJWluJSBjb2wxXSAsIGFlcyhmYWN0b3IoVGlzc3VlX2NsdXN0ZXJzKSwgUFNJLCBncm91cD1NRSksIGNvbG91cj0iZ3JleSIpICsKICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IG1lcmdlKHN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9hZ2dyZWdhdGVkX21lYW4sIE1FX2NsdXN0ZXJfbmFtZXMsIGJ5Lng9Ik1FX2NsdXN0ZXIiLCAgYnkueT0iTUVfY2x1c3RlciIpW01FX2NsdXN0ZXIubmFtZSAlaW4lIGNvbDFdLCBhZXMoZmFjdG9yKFRpc3N1ZV9jbHVzdGVycyksIFBTSSwgZ3JvdXA9TUVfY2x1c3RlcnMpLCAgY29sb3VyPSJyZWQiICkgKwogICAgICAgIGZhY2V0X2dyaWQoIE1FX2NsdXN0ZXIubmFtZSB+IC4pICsKICAgICAgICB4bGFiKCJTYW1wbGUgY2x1c3RlcnMgKHNvcnRlZCBieSBQQzEpIikgKwogICAgICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScsIGNvbG91ciA9ICdibGFjaycpKSwKCmdncGxvdCggKSArCiAgICAgICAgZ2VvbV9saW5lKGRhdGE9IG1lcmdlKHN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9hZ2dyZWdhdGVkLCBNRV9jbHVzdGVyX25hbWVzLCBieS54PSJNRV9jbHVzdGVyIiwgIGJ5Lnk9Ik1FX2NsdXN0ZXIiKVtNRV9jbHVzdGVyLm5hbWUgJWluJSBjb2wyXSAsIGFlcyhmYWN0b3IoVGlzc3VlX2NsdXN0ZXJzKSwgUFNJLCBncm91cD1NRSksIGNvbG91cj0iZ3JleSIpICsKICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IG1lcmdlKHN1Yl9NRV9UaXNzdWVzX2NsdXN0ZXJzX1BTSV9hZ2dyZWdhdGVkX21lYW4sIE1FX2NsdXN0ZXJfbmFtZXMsIGJ5Lng9Ik1FX2NsdXN0ZXIiLCAgYnkueT0iTUVfY2x1c3RlciIpW01FX2NsdXN0ZXIubmFtZSAlaW4lIGNvbDJdLCBhZXMoZmFjdG9yKFRpc3N1ZV9jbHVzdGVycyksIFBTSSwgZ3JvdXA9TUVfY2x1c3RlcnMpLCAgY29sb3VyPSJyZWQiICkgKwogICAgICAgIGZhY2V0X2dyaWQoIE1FX2NsdXN0ZXIubmFtZSB+IC4pICsKICAgICAgICB4bGFiKCJTYW1wbGUgY2x1c3RlcnMgKHNvcnRlZCBieSBQQzEpIikgKwogICAgICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScsIGNvbG91ciA9ICdibGFjaycpKQoKKQoKCgoKYGBgCgoKCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTh9CgoKUENBX2xvYWRpbmdzJE1FX2NsdXN0ZXJzIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKFBDQV9sb2FkaW5ncyRNRV9jbHVzdGVyKSkgCgoKU3VwX2xvYWRpbmcuQSA8LSBnZ3Bsb3QobWVyZ2UoUENBX2xvYWRpbmdzLCBNRV9jbHVzdGVyX25hbWVzLCBieS54PSJNRV9jbHVzdGVycyIsICBieS55PSJNRV9jbHVzdGVyIikpICsKICBnZW9tX2JveHBsb3QoYWVzKE1FX2NsdXN0ZXIubmFtZSAsIC1QQzEpKSArCiAgeWxhYigiTG9hZGluZyBmYWN0b3JzIGluIFBDMSIpICsKICB4bGFiKCJNaWNyb2V4b24gY2x1c3RlciIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKCgoKU3VwX2xvYWRpbmcuQiA8LSAgZ2dwbG90KG1lcmdlKFBDQV9sb2FkaW5ncywgTUVfY2x1c3Rlcl9uYW1lcywgYnkueD0iTUVfY2x1c3RlcnMiLCAgYnkueT0iTUVfY2x1c3RlciIpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhNRV9jbHVzdGVyLm5hbWUgLCBQQzIpKSArCiAgeWxhYigiTG9hZGluZyBmYWN0b3JzIGluIFBDMiIpICsKICB4bGFiKCJNaWNyb2V4b24gY2x1c3RlciIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKCgoKU3VwX2xvYWRpbmcuQyA8LSAgZ2dwbG90KG1lcmdlKFBDQV9sb2FkaW5ncywgTUVfY2x1c3Rlcl9uYW1lcywgYnkueD0iTUVfY2x1c3RlcnMiLCAgYnkueT0iTUVfY2x1c3RlciIpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhNRV9jbHVzdGVyLm5hbWUgLCBQQzMpKSArCiAgeWxhYigiTG9hZGluZyBmYWN0b3JzIGluIFBDMyIpICsKICB4bGFiKCJNaWNyb2V4b24gY2x1c3RlciIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKCgpwbG90X2dyaWQoU3VwX2xvYWRpbmcuQSwgU3VwX2xvYWRpbmcuQiwgU3VwX2xvYWRpbmcuQywgbGFiZWxzID0gIkFVVE8iLCBuY29sPTEpCgoKUFBJX2NlbnRyYWxpdHlfR09bR089PSJBeG9uX2d1aWRhbmNlIiwgLk4sIGJ5PSJtYXBwZWRfZ2VuZSIgXQoKYGBgCgoKVGFibGVzCgoKYGBge3J9CgpUUzIgPC0gdW5pcXVlKG1lcmdlKFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLCBnZW5lX3RhYmxlLlRPVEFMLCBieS54PSJleG9uX0lEIiwgYnkueT0iTUUiICApKQoKCmNvbG5hbWVzKFRTMikgPC0gYygiQ29vcmRpbmF0ZXMiLCAiUHJvYmFiaWxpdHkiLCAiRGVsdGFQc2kiLCAiTWVhbiBQcm9iYWJpbGl0eSIsICJNZWFuIERlbHRhUHNpIiwgIlNpZ25pZmljYW5jZSB1bnBvb2wiLCAiU2lnbmlmaWNhbmNlIFBvb2wiLCAiRW5zZW1ibCB0cmFuc2NyaXB0IElEIiwgICAgIkVuc2VtYmwgZ2VuZSBJRCIsICJHZW5lIG5hbWUiKQoKZndyaXRlKFRTMiwgZmlsZSA9ICIuLi9GaW5hbF9GaWd1cmVzL1N1cHBsZW1lbnRhcnkvVGFibGVfUzIuY3N2IiwgYXBwZW5kID0gRkFMU0UsIHF1b3RlID0gImF1dG8iLCBzZXAgPSAiLCIsICByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSkKCgpgYGAKCgoKYGBge3J9CiNSIC1lICAncm1hcmtkb3duOjpyZW5kZXIoInNyYy9maW5hbF9maWx0ZXJzMi5SbWQiLHBhcmFtcyA9IGxpc3QoTUVfdGFibGU9Ii9sdXN0cmUvc2NyYXRjaDExNy9jZWxsZ2VuL3RlYW0yMTgvZ3A3L01pY3JvLWV4b25zL1J1bnMvUGFwZXIvTWljcm9FeG9uYXRvci9Sb3VuZDIvVE9UQUwuTUVfY2VudHJpYy50eHQiLCBNRV9jb3ZlcmFnZT0iL2x1c3RyZS9zY3JhdGNoMTE3L2NlbGxnZW4vdGVhbTIxOC9ncDcvTWljcm8tZXhvbnMvUnVucy9QYXBlci9NaWNyb0V4b25hdG9yL1JvdW5kMi9UT1RBTC5maWx0ZXIxLk1FX1NKX2NvdmVyYWdlIiwgTUVfbWF0Y2hlc19maWxlPSIvbHVzdHJlL3NjcmF0Y2gxMTcvY2VsbGdlbi90ZWFtMjE4L2dwNy9NaWNyby1leG9ucy9SdW5zL1BhcGVyL01pY3JvRXhvbmF0b3IvUm91bmQyL1RPVEFMLk1FX2NlbnRyaWMuTUVfbWF0Y2hlcy50eHQiLCBvdXRfZmlsdGVyZWRfTUU9Ii9sdXN0cmUvc2NyYXRjaDExNy9jZWxsZ2VuL3RlYW0yMTgvZ3A3L01pY3JvLWV4b25zL1J1bnMvUGFwZXIvTWljcm9FeG9uYXRvci9SZXBvcnQvdGVzdC9vdXRfZmlsdGVyZWRfTUUudHh0Iiwgb3V0X2xvd19zY29yZWRfTUU9Ii9sdXN0cmUvc2NyYXRjaDExNy9jZWxsZ2VuL3RlYW0yMTgvZ3A3L01pY3JvLWV4b25zL1J1bnMvUGFwZXIvTWljcm9FeG9uYXRvci9SZXBvcnQvdGVzdC9vdXRfbG93X3Njb3JlZF9NRS50eHQiLCBvdXRfc2hvcnRlcl90aGFuXzNfTUU9Ii9sdXN0cmUvc2NyYXRjaDExNy9jZWxsZ2VuL3RlYW0yMTgvZ3A3L01pY3JvLWV4b25zL1J1bnMvUGFwZXIvTWljcm9FeG9uYXRvci9SZXBvcnQvdGVzdC9vdXRfc2hvcnRlcl90aGFuXzNfTUUudHh0IiwgbWluX251bWJlcl9maWxlc19kZXRlY3RlZD0zLCBvdXRfZmlsdGVyZWRfTUVfY292PSIvbHVzdHJlL3NjcmF0Y2gxMTcvY2VsbGdlbi90ZWFtMjE4L2dwNy9NaWNyby1leG9ucy9SdW5zL1BhcGVyL01pY3JvRXhvbmF0b3IvUmVwb3J0L3Rlc3Qvb3V0X2ZpbHRlcmVkX01FLmNvdi50eHQiICksIG91dHB1dF9mb3JtYXQ9InBkZl9kb2N1bWVudCIsIG91dHB1dF9maWxlPSIvbHVzdHJlL3NjcmF0Y2gxMTcvY2VsbGdlbiAvdGVhbTIxOC9ncDcvTWljcm8tZXhvbnMvUnVucy9QYXBlci9NaWNyb0V4b25hdG9yL1JlcG9ydC9yZXBvcnQucGRmIiknCmBgYAoKIyMjIEJldGFEaXN0CgpgYGB7cn0KdGFzaWMuYmV0YWRpc3QgPC0gZnJlYWQoIi4uLy4uL1NpbmdsZV9jZWxsL0JldGFEaXN0L1NpZ19ub2Rlcy9HQUJBLWVyZ2ljX05ldXJvbl92c19HbHV0YW1hdGVyZ2ljX05ldXJvbi50eHQiKQpNRV9maW5hbFssIC4oIHN0cmlfc3BsaXRfZml4ZWQoTUUsICJfIikpIF0KU2lnX0dBQkFlcmdpY19OZXVyb25fdnNfR2x1dGFtYXRlcmdpY19OZXVyb24KCmxpYnJhcnkoc3BsaXRzdGFja3NoYXBlKQpNRV9maW5hbC5jaG9yZHMgPC0gY1NwbGl0KE1FX2ZpbmFsLCAnTUUnLCAnXycpWyBpcy5uYShNRV81KSAsIC4oIHBhc3RlMChNRV8xLCAiOiIsIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKE1FXzMpKSsxLCAgIi0iLCBNRV80KSApIF0kVjEKCgpNRV9maW5hbC5jaG9yZHMgPC0gY1NwbGl0KFNpZ19HQUJBZXJnaWNfTmV1cm9uX3ZzX0dsdXRhbWF0ZXJnaWNfTmV1cm9uLCAnZXhvbl9JRCcsICdfJylbICAsIC4oIHBhc3RlMChleG9uX0lEXzEsICI6IiwgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZXhvbl9JRF8zKSkrMSwgICItIiwgZXhvbl9JRF80KSApIF0kVjEKCnRhc2ljLmJldGFkaXN0WyBDb29yZCAlaW4lICBNRV9maW5hbC5jaG9yZHMsXQoKY1NwbGl0KE1FX2ZpbmFsLCAnTUUnLCAnXycpWyBpcy5uYShNRV81KSAsIC4oIHBhc3RlMChNRV8xLCAiOiIsIE1FXzMsICAiLSIsIE1FXzQpICkgXQoKCk1FX2ZpbmFsLmNob3Jkc1ssIC4oYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoTUVfMykpLCApIF0KCk1FX2ZpbmFsWyAuKE1FKV0KYGBgCgoKIyBTdXBwbGVtZW50YXJ5IHRhYmxlcy4gCgpgYGB7cn0KCk1ITi5kaWZmIDwtIHVuaXF1ZShEZWx0YV9ITk1fbWVyZ2VbYWJzKERlbHRhUHNpLngpPj0wLjEgJiBQcm9iYWJpbGl0eS54PjAuOSAmIGFicyhEZWx0YVBzaS55KT49MC4xICYgUHJvYmFiaWxpdHkueT4wLjksIGV4b25fSURdKQpGLmRpZmYgPC0gdW5pcXVlKERlbHRhX0ZfbWVyZ2VbYWJzKERlbHRhUHNpLngpPj0wLjEgJiBQcm9iYWJpbGl0eS54PjAuOSAmIGFicyhEZWx0YVBzaS55KT49MC4xICYgUHJvYmFiaWxpdHkueT4wLjksIGV4b25fSURdKQpEZWx0YV9ITk1fd2hpcHBldF9NRV9hZ2VfZGlmZl90b3RhbFsgLCAuKE1FPWV4b25fSUQsIEhOTS5kaWZmX2FnZT1kaWZmX2FnZSwgSE5NLmNoYW5nZV9kaXI9Y2hhbmdlX2RpcildIApEZWx0YV9GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgLihNRT1leG9uX0lELCBGLmRpZmZfYWdlPWRpZmZfYWdlLCBGLmNoYW5nZV9kaXI9Y2hhbmdlX2RpcildIApEZWx0YV9TS01fd2hpcHBldF9NRVsgLCAuKE1FPWV4b25fSUQsIFNLTS5kaWZmX2FnZT1kaWZmX2hpZ2gpXSAKRGVsdGFfSGVhcnRfd2hpcHBldF9NRVsgLCAuKE1FPWV4b25fSUQsIEhlYXJ0LmRpZmZfYWdlPWRpZmZfaGlnaCldIApEZWx0YV9BR193aGlwcGV0X01FWyAsIC4oTUU9ZXhvbl9JRCwgQUcuZGlmZl9hZ2U9ZGlmZl9oaWdoKV0gCgpUUzEgPC0gTUVfZmluYWwub3V0WywgLihNRSwKICAgICAgICAgICAgIHRyYW5zY3JpcHQsCiAgICAgICAgICAgICBzdW1fdG90YWxfY292ZXJhZ2UsCiAgICAgICAgICAgICB0b3RhbF9TSnMsCiAgICAgICAgICAgICB0b3RhbF9jb3ZlcmFnZXMsCiAgICAgICAgICAgICBsZW5fbWljcm9fZXhvbl9zZXFfZm91bmQsCiAgICAgICAgICAgICBtaWNyb19leG9uX3NlcV9mb3VuZCwKICAgICAgICAgICAgIHRvdGFsX251bWJlcl9vZl9taWNyb19leG9uc19tYXRjaGVzLAogICAgICAgICAgICAgVTJfc2NvcmVzLAogICAgICAgICAgICAgbWVhbl9jb25zZXJ2YXRpb25zX3ZlcnRlYnJhdGVzLAogICAgICAgICAgICAgUF9NRXMsCiAgICAgICAgICAgICB0b3RhbF9NRSwKICAgICAgICAgICAgIE1FX1BfdmFsdWUsCiAgICAgICAgICAgICBNRV90eXBlLAogICAgICAgICAgICAgZW5zZW1ibF90cmFuc2NyaXB0X2lkLAogICAgICAgICAgICAgdHlwZSwKICAgICAgICAgICAgIEFsdDVfMywKICAgICAgICAgICAgIE1FX2NsdXN0ZXIudHlwZSwKICAgICAgICAgICAgIE1FX2NsdXN0ZXIubmFtZSwKICAgICAgICAgICAgIE1FX2NsdXN0ZXIubnVtYmVyLAogICAgICAgICAgICAgUEMxLAogICAgICAgICAgICAgUEMyLAogICAgICAgICAgICAgUEMzLCAKICAgICAgICAgICAgIEluLjEwX3BlcmNlbnRfb2ZfYnVsayldCgoKVFMxWyAsIE1ITi5kaWZmOj0oTUUgJWluJSBNSE4uZGlmZikgXQpUUzFbICwgRi5kaWZmOj0oTUUgJWluJSBGLmRpZmYpIF0KClRTMSA8LSBtZXJnZShUUzEsIERlbHRhX0hOTV93aGlwcGV0X01FX2FnZV9kaWZmX3RvdGFsWyAsIC4oTUU9ZXhvbl9JRCwgSE5NLmRpZmZfYWdlPWRpZmZfYWdlLCBITk0uY2hhbmdlX2Rpcj1jaGFuZ2VfZGlyKV0sIGJ5PSJNRSIsIGFsbC54PVRSVUUpIApUUzEgPC0gbWVyZ2UoVFMxLCBEZWx0YV9GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbICwgLihNRT1leG9uX0lELCBGLmRpZmZfYWdlPWRpZmZfYWdlLCBGLmNoYW5nZV9kaXI9Y2hhbmdlX2RpcildICwgYnk9Ik1FIiwgYWxsLng9VFJVRSkgClRTMSA8LSBtZXJnZShUUzEsIERlbHRhX1NLTV93aGlwcGV0X01FWyAsIC4oTUU9ZXhvbl9JRCwgU0tNLmRpZmY9ZGlmZl9oaWdoKV0gLCBieT0iTUUiLCBhbGwueD1UUlVFKQpUUzEgPC0gbWVyZ2UoVFMxLCBEZWx0YV9IZWFydF93aGlwcGV0X01FWyAsIC4oTUU9ZXhvbl9JRCwgSGVhcnQuZGlmZj1kaWZmX2hpZ2gpXSAsIGJ5PSJNRSIsIGFsbC54PVRSVUUgKQpUUzEgPC0gbWVyZ2UoVFMxLCBEZWx0YV9BR193aGlwcGV0X01FWyAsIC4oTUU9ZXhvbl9JRCwgQUcuZGlmZj1kaWZmX2hpZ2gpXSAsIGJ5PSJNRSIsIGFsbC54PVRSVUUpCgpUUzFbaXMubmEoU0tNLmRpZmYpLCBTS00uZGlmZjo9RkFMU0UgXQpUUzFbaXMubmEoSGVhcnQuZGlmZiksIEhlYXJ0LmRpZmY6PUZBTFNFIF0KVFMxW2lzLm5hKEFHLmRpZmYpLCBBRy5kaWZmOj1GQUxTRSBdCgpUUzQgPC0gdG90YWxfemVicmEKClRTNSA8LSBNb3VzZV9aZWJyYS5JRHMudGFibGUuc3VtbWVyWyFpcy5uYShtb3VzZS5jb29yZCksIC4obW91c2UuY29vcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb3VzZS5sZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb3VzZS5jbHVzdGVyX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb3VzZS5jbHVzdGVyX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb3VzZS5hbm5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW91c2UuZW5zZW1ibCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHplYnJhLmNvb3JkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEubGVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgemVicmEuZW5zZW1ibCldCgoKbm9uX3B1Ymxpc2hlZCA8LSBEZWx0YV9ITk1GX3doaXBwZXRfTUVfYWdlX2RpZmZfdG90YWxbLCAuKCBFTlNFTUJMX2dlbmVfaWQ9ZW5zZW1ibF9nZW5lX2lkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZ2lfc3ltYm9sPW1naV9zeW1ib2wueCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhvbl9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWljcm9leG9uLmxlbmd0aD1NRV9sZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoYW5nZS5kaXJlY3Rpb249Y2hhbmdlX2RpciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1ITi5kaWZmX3N0YXJ0PWRpZmZfYWdlLngsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEYuTUhOLmRpZmZfc3RhcnQ9ZGlmZl9hZ2UueSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbi5zdGF0dXM9dHlwZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdCgoKVFM2IDwtIFRhc2ljX3RvdGFsX2RpZmZfbm9kZXMKCgpFTkNPREVfbWV0YWRhdGEKCgpUaXNzdWVfcG9vbC50YWJsZSA8LSBUaXNzdWVfY2x1c3RlcnNbICwgLihGaWxlLmFjY2Vzc2lvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlzc3VlPW5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWdlLkRQQz1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlzc3VlLmNsdXN0ZXI9Y2x1c3RlcildCgoKVGlzc3VlX3Bvb2wudGFibGVbIFRpc3N1ZSAlaW4lIGMoImhpbmRicmFpbiIsICJuZXVyYWwgdHViZSIsICJtaWRicmFpbiIpICYgQWdlLkRQQyAlaW4lIGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSksCiAgICAgICAgICAgICAgICAgICBCdWxrLnNhbXBsZS5ncm91cDo9cGFzdGUoIk1ITiIsIEFnZS5EUEMsIHNlcD0iXyIpIF0KVGlzc3VlX3Bvb2wudGFibGVbIFRpc3N1ZSAlaW4lIGMoImZvcmVicmFpbiIpICYgQWdlLkRQQyAlaW4lIGMoMTAuNSwgMTEuNSwgMTIuNSwgMTMuNSwgMTQuNSwgMTUuNSwgMTYuNSwgMjEpICwgCiAgICAgICAgICAgICAgICAgICBCdWxrLnNhbXBsZS5ncm91cDo9cGFzdGUoIkYiLCBBZ2UuRFBDLCBzZXA9Il8iKSBdCgpUaXNzdWVfcG9vbC50YWJsZVtUaXNzdWUuY2x1c3RlciAlaW4lIGMoMSwgOCwgNiksIEJ1bGsuc2FtcGxlLmdyb3VwOj0iQ29udHJvbCJdCgpUaXNzdWVfcG9vbC50YWJsZVtUaXNzdWU9PSJoZWFydCIgLCBCdWxrLnNhbXBsZS5ncm91cDo9IkhlYXJ0IiBdClRpc3N1ZV9wb29sLnRhYmxlW1Rpc3N1ZT09InNrZWxldGFsIG11c2NsZSB0aXNzdWUiICwgQnVsay5zYW1wbGUuZ3JvdXA6PSJTS00iIF0KVGlzc3VlX3Bvb2wudGFibGVbVGlzc3VlPT0iYWRyZW5hbCBnbGFuZCIgLCBCdWxrLnNhbXBsZS5ncm91cDo9IkFEIiBdCgpUUzIgPC0gVGlzc3VlX3Bvb2wudGFibGUKVmlldyhUaXNzdWVfcG9vbC50YWJsZSkKCmBgYAoKCgoKCgpgYGB7cn0KVFMxIApUUzIKVFMzClRTNApUUzUKVFM2WyFpcy5uYShtaWNyb2V4b25fSUQpICYgaXMuZGlmZj09VFJVRSwgXQoKCgpmd3JpdGUoVFMxLCBmaWxlID0gIi4uL0ZpbmFsX0ZpZ3VyZXMvU3VwcGxlbWVudGFyeS9UUzEudHN2IiwgYXBwZW5kID0gRkFMU0UsIHF1b3RlID0gImF1dG8iLCBzZXAgPSAiXHQiLCAgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpCmZ3cml0ZShUUzIsIGZpbGUgPSAiLi4vRmluYWxfRmlndXJlcy9TdXBwbGVtZW50YXJ5L1RTMi50c3YiLCBhcHBlbmQgPSBGQUxTRSwgcXVvdGUgPSAiYXV0byIsIHNlcCA9ICJcdCIsICByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSkKZndyaXRlKFRTNCwgZmlsZSA9ICIuLi9GaW5hbF9GaWd1cmVzL1N1cHBsZW1lbnRhcnkvVFM0LnRzdiIsIGFwcGVuZCA9IEZBTFNFLCBxdW90ZSA9ICJhdXRvIiwgc2VwID0gIlx0IiwgIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBUUlVFKQpmd3JpdGUoVFM1LCBmaWxlID0gIi4uL0ZpbmFsX0ZpZ3VyZXMvU3VwcGxlbWVudGFyeS9UUzUudHN2IiwgYXBwZW5kID0gRkFMU0UsIHF1b3RlID0gImF1dG8iLCBzZXAgPSAiXHQiLCAgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpCmZ3cml0ZShUUzYsIGZpbGUgPSAiLi4vRmluYWxfRmlndXJlcy9TdXBwbGVtZW50YXJ5L1RTNi50c3YiLCBhcHBlbmQgPSBGQUxTRSwgcXVvdGUgPSAiYXV0byIsIHNlcCA9ICJcdCIsICByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSkKCmBgYAoK