library(ggplot2)
library(pheatmap)
library(RColorBrewer)
#display.brewer.all()
library(tidyverse)
library(ggpubr)
library(ggsignif)
library(openxlsx)
library(viridis)
library(data.table)
library(readxl)
library(janitor)
library(dplyr)
library(jcolors)
library(stringr)

Importing data

setwd("//atlas.uni.lux/users/isabel.rosety/GBA/Stainings/Plots/")
The working directory was changed to //atlas.uni.lux/users/isabel.rosety/GBA/Stainings/Plots inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
#setwd("//atlas.uni.lux/LCSB_Cellular_Biology/16-Our Papers/In Preparation/GBA hMO_Isabel/Scripts/Data analysis/Image analysis data processing and plotting")

dir(path="//atlas.uni.lux/users/isabel.rosety/GBA/Stainings/Plots/DataFromImageAnalysis",full.names = TRUE) %>%
  map(~fread(.)) -> mytables #fread needs the whole path

#Merge list to merge all the tables of mytables into one big table
Table_All = bind_rows(mytables) 

#Adding column for condition
tmp=do.call(rbind,strsplit(Table_All$AreaName,"_")) #stringsplit will take the column Areaname and will split this depending on the underscore, then we put them otgeter one ofter the other
#tmp is a matrix, it is neither a dataframe nor a table, in a table you have to have column names, adding a row in a matrix is easier than in a table
#some areanames 2 underscores, others have 4 underscores, the number of maximum underscores defines the number of columns, so when only 2 underscores, it will fill the other 2 columns by repeating the value
Table_All$Condition = tmp[,1]

Table_All %>% 
   mutate(Condition = str_replace_all(Condition, 
            pattern = "MUT", replacement = "GBA-PD")) %>%
     mutate(Condition = str_replace_all(Condition, 
            pattern = "WT", replacement = "CTRL")) ->Table_All

#Selecting columns Markers
toselect = c("Barcode","AreaName","Condition","Day", "Well","Batch", "Tuj1ByNucAlive","THByNucAlive","THandTuj1ByTuj1","THFragmentation","THandTuj1ByNucAlive","THandMAP2ByMAP2","FOXA2ByNucAlive","THFragmentation","LinksBySkel","NodesBySkel","MAP2ByNucAlive","Ki67ByNucAlive", "Sox2ByNucAlive", "GFAPByNucAlive", "s100bByNucAlive", "MAP2ByNucAlive", "GFAPByS100b", "THMask","THMFI","MAP2Mask", "Sox2Mask","Ki67andSox2BySox2", "Sox2MFI", "OLIG2ByNucAlive", "OLIG2CytoPByNucAlive", "CNPaseByNucAlive" , "OLIG2NuclearByNucAlive", "DCXandNestinByDCX",  "DCX_NodesBySkel",  "DCX_LinksBySkel","DCXFragmentation", "NestinByNucAlive",   "DCXByNucAlive", "NestinAndDCXByNestin", "TotalNucMask", "DCXandNestinByNuc", "THMFI")


Table_All %>% #same 
  dplyr::select(toselect)->Table_All

Normalizing to the mean of the controls per feature

#Mean of replicates
feature_names <- colnames(Table_All[,7:ncol(Table_All)])
  Table_All%>%
    pivot_longer(feature_names,names_to = "Features", values_to = "Measure") -> Table_all_long
Table_all_long2 = drop_na(Table_all_long)  

Table_all_long2 %>%
  group_by(Day,Condition,AreaName,Batch,Features, Barcode) %>%
  summarize(MeanFeatures = mean(Measure)) -> Table_Mean
`summarise()` has grouped output by 'Day', 'Condition', 'AreaName', 'Batch', 'Features'. You can override using the `.groups` argument.
#  ungroup() %>% 
#  dplyr::select(-AreaName) %>% 
#  full_join(Table_all_long2, by="Features" ) 
    #full_join(Table_all_long2, by=c("Features")) %>% #if I wanted to normalize per WB membrane


#Normalizing to mean of controls
Table_Mean %>%
    dplyr::filter(Condition=="CTRL") %>% 
    #group_by(WB, Batch, Condition,Features) %>% 
    group_by(Condition, Day, Features,Batch) %>% 
    summarise(baseline = median(MeanFeatures)) %>% 
    ungroup() %>% 
    dplyr::select(-Condition) %>% 
    #dplyr::select(-Batch) %>%
    full_join(Table_Mean, by=c("Day","Features","Batch")) %>% 
    #full_join(Table_all_long2, by=c("Features")) %>% #if I wanted to normalize per WB membrane
    mutate(Foldchange = MeanFeatures /baseline) ->Table_all_based
`summarise()` has grouped output by 'Condition', 'Day', 'Features'. You can override using the `.groups` argument.
included_vars =c("Day", "AreaName", "Condition","Batch","Barcode") # here we already have the mean of each section
Table_all_based %>% 
    pivot_wider(all_of(included_vars),names_from = Features,values_from = Foldchange)->Table_all_based_wide2

write.csv(Table_all_based_wide2, file = 'Table_all_based_wide2.csv')

Table_all_based_wide2=Table_all_based_wide2[!grepl("D0",Table_all_based_wide2$Day),]

Table_all_based_wide15<-filter(Table_all_based_wide2,Day=="d15")
Table_all_based_wide30<-filter(Table_all_based_wide2,Day=="d30")
Table_all_based_wide60<-filter(Table_all_based_wide2,Day=="d60")
Table_all_based_wide90<-filter(Table_all_based_wide2,Day=="d90")



#Doing the mean if same marker is used for same timepoint in different barcodes
Table_all_based%>%
  group_by(Day,Condition,AreaName,Batch,Features) %>%
  summarize(MeanFeatures = mean(Foldchange)) -> Table_Mean_of_different_Barcodes
`summarise()` has grouped output by 'Day', 'Condition', 'AreaName', 'Batch'. You can override using the `.groups` argument.
included_vars =c("Day", "AreaName", "Condition","Batch") # here we already have the mean of each section
Table_Mean_of_different_Barcodes%>% 
    pivot_wider(all_of(included_vars),names_from = Features,values_from = MeanFeatures)->Table_Mean_of_different_Barcodes

write.csv(Table_Mean_of_different_Barcodes, file = 'Table_Mean_of_different_Barcodes.csv')

Plots for all the features one timepoint (loop)


feature_names <- colnames(Table_all_based_wide30[,6:ncol(Table_all_based_wide30)])

#Table_all_based_wide2=Table_all_based_wide2[!grepl("IR_20211129_488TH_568DCX_647MAP2_RS_e45e46e47d30_20211129_174319",Table_all_based_wide2$Barcode),]

#subset = c("Barcode","AreaName","Condition","Day","Batch","DCXandNestinByNuc")
#Table_all_based_wide2%>% #same 
#  dplyr::select(subset)->Table_all_based_wide3
#feature_names <- colnames(Table_all_based_wide3[,6:ncol(Table_all_based_wide3)])



for (i in 1:length(feature_names)) {
Table_all_based_wide30 %>%
  pivot_longer(cols=feature_names, names_to = "feature", values_to = "value") %>%
  filter(feature %in% feature_names[i]) %>%
ggplot( aes(x=factor(Condition, level = c("CTRL", "GBA-PD")), y=value)) +
  #geom_violin( aes(fill=Condition),show.legend = T, trim=T)+
  #scale_fill_manual(values= c("#bdd7e7","#2171b5"),name = "Condition", guide = FALSE)+
    scale_fill_manual(values= c("#FFFFFF","#999999"),name = "Condition", guide = "none")+ #guide false will remove the legend for the condition
    geom_boxplot(aes(fill=Condition),show.legend = FALSE,width=0.5)+ #show.legend will remove box around the points of the legend
    geom_point(aes(color=AreaName),size=3,show.legend = T,alpha = 0.5)+
    scale_color_jcolors("pal7")+
    theme(legend.key=element_blank()) +
  geom_signif(comparisons = list(c("CTRL", "GBA-PD")), test='wilcox.test',
              vjust=0.5, size=0.5, textsize=9, map_signif_level=c("***"=0.001, "**"=0.01, "*"=0.05,  " "=2) ) +
  #facet_grid(~fct_relevel(Day, "d15", "d30","d60", "d90"), scales="free") +
      labs(x     = "",
       y     = paste(feature_names[i]),
       #y     = paste(names[i]),
       fill  = "Condition",
       #title = paste(feature_names[i])) +
       title = "" )+
  theme_bw() +
  theme(
    axis.line = element_line(colour = 'black', size = 0.5) ,
    axis.title.x = element_blank(),
    axis.text.x = element_text(size=21, color="black"),
    axis.title.y = element_text(size = 21),
    axis.text.y = element_text(size=15, color="black"),
    axis.ticks.y = element_line(),
    axis.ticks.length=unit(.25, "cm"),
    #change legend text font size)
    #legend.key.size = unit(0.7, "cm"),
    #legend.key.width = unit(0.6,"cm"),
    legend.key=element_blank(),
    panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(),
    panel.border = element_blank(),
    plot.title = element_text(size = 20, hjust=0.5, vjust= 1, face = "bold"),
    plot.subtitle = element_blank(),#element_text(size = 2, hjust=0.5)
    strip.text = element_text(size=12, vjust=0.5),
    strip.background = element_rect(fill="lightgray"),
   # panel.border = element_rect(fill = NA, color = "black"),
    panel.spacing.y = unit(0.8, "lines"),
    strip.switch.pad.wrap=unit(20, "lines"),
    legend.position="right",
    legend.text = element_text(size=17),
    legend.title = element_text(size=19)
    
  )  -> p
  print(p)
#ggsave(paste0(Sys.Date(),(sprintf("Plot_%s_DIV30.pdf",feature_names[i]))),height=3.5)
}

Plots for all features all timepoints (loop)

#Table_all_based_wide2<-filter(Table_all_based_wide2,Barcode=="IR_20211016_488MAP2_568TUJ1_647TH_RS_e40e41e42d30_20211016_144439")

Table_all_based_wideT=Table_all_based_wide2[!grepl("D0",Table_all_based_wide2$Day),]
feature_names <- colnames(Table_all_based_wideT[,6:ncol(Table_all_based_wideT)])

#subset = c("Barcode","AreaName","Condition","Day","Batch","Tuj1ByNucAlive")
#Table_all_based_wideT%>% #same 
#  dplyr::select(subset)->Table_all_based_wideT2




for (i in 1:length(feature_names)) {
Table_all_based_wideT %>%
  pivot_longer(cols=feature_names, names_to = "feature", values_to = "value") %>%
  filter(feature %in% feature_names[i]) %>%
ggplot( aes(x=factor(Condition, level = c("CTRL", "GBA-PD")), y=value)) +
  #geom_violin( aes(fill=Condition),show.legend = T, trim=T)+

  #scale_fill_manual(values= c("#bdd7e7","#2171b5"),name = "Condition", guide = FALSE)+
    scale_fill_manual(values= c("#FFFFFF","#999999"),name = "Condition", guide = "none")+ #guide false will remove the legend for the condition
    #geom_boxplot(width=0.07, fill="white") + 
    geom_boxplot(aes(fill=Condition),show.legend = FALSE,width=0.7)+ #show.legend will remove box around the points of the legend
    geom_point(aes(color=AreaName),size=3,show.legend = T,alpha = 0.5)+
    #scale_color_manual(values = rev(brewer.pal(n=6, name="OrRd")))+
    scale_color_jcolors("pal7")+
    #scale_color_viridis(option = "D", discrete=TRUE)+
    #geom_point(shape = 1,size = 3,colour = "black")+
    theme(legend.key=element_blank()) +
    
  geom_signif(comparisons = list(c("CTRL", "GBA-PD")), test='wilcox.test',
              vjust=0.6, size=0.5, textsize=9, map_signif_level=c("***"=0.001, "**"=0.01, "*"=0.05,  " "=2) ) +
  facet_grid(~fct_relevel(Day, "d15", "d30","d60", "d90"), scales="free") +
      labs(x     = "",
       y     = paste(feature_names[i]),
       fill  = "Condition",
       title = "" )+
  theme_bw() +
  theme(
    axis.line = element_line(colour = 'black', size = 0.5) ,
    axis.title.x = element_blank(),
    axis.text.x = element_text(size=12, color="black",angle=30,vjust = 1.1, hjust = 0.95),
    axis.title.y = element_text(size = 15),
    axis.text.y = element_text(size=15, color="black"),
    axis.ticks.y = element_line(),
    axis.ticks.length=unit(.25, "cm"),
    #change legend text font size)
    #legend.key.size = unit(0.7, "cm"),
    #legend.key.width = unit(0.6,"cm"),
    legend.key=element_blank(),
    panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(),
    #panel.border = element_blank(),
    plot.title = element_text(size = 20, hjust=0.5, vjust= 1, face = "bold"),
    plot.subtitle = element_blank(),#element_text(size = 2, hjust=0.5)
    strip.text = element_text(size=12, vjust=0.5),
    strip.background = element_rect(fill="lightgray"),
   # panel.border = element_rect(fill = NA, color = "black"),
    panel.spacing.y = unit(0.8, "lines"),
    strip.switch.pad.wrap=unit(20, "lines"),
    legend.position="right",
    legend.text = element_text(size=17),
    legend.title = element_text(size=19)
    
  )  -> p

  print(p)
 
ggsave(paste0(Sys.Date(),(sprintf("Plot_%s_DIV60 and DIV90.pdf",feature_names[i]))),height=4)
}

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KLS0tDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGhlYXRtYXApDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCiNkaXNwbGF5LmJyZXdlci5hbGwoKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkoZ2dzaWduaWYpDQpsaWJyYXJ5KG9wZW54bHN4KQ0KbGlicmFyeSh2aXJpZGlzKQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShqY29sb3JzKQ0KbGlicmFyeShzdHJpbmdyKQ0KYGBgDQoNCkltcG9ydGluZyBkYXRhDQpgYGB7cn0NCnNldHdkKCIvL2F0bGFzLnVuaS5sdXgvdXNlcnMvaXNhYmVsLnJvc2V0eS9HQkEvU3RhaW5pbmdzL1Bsb3RzLyIpDQojc2V0d2QoIi8vYXRsYXMudW5pLmx1eC9MQ1NCX0NlbGx1bGFyX0Jpb2xvZ3kvMTYtT3VyIFBhcGVycy9JbiBQcmVwYXJhdGlvbi9HQkEgaE1PX0lzYWJlbC9TY3JpcHRzL0RhdGEgYW5hbHlzaXMvSW1hZ2UgYW5hbHlzaXMgZGF0YSBwcm9jZXNzaW5nIGFuZCBwbG90dGluZyIpDQoNCmRpcihwYXRoPSIvL2F0bGFzLnVuaS5sdXgvdXNlcnMvaXNhYmVsLnJvc2V0eS9HQkEvU3RhaW5pbmdzL1Bsb3RzL0RhdGFGcm9tSW1hZ2VBbmFseXNpcyIsZnVsbC5uYW1lcyA9IFRSVUUpICU+JQ0KICBtYXAofmZyZWFkKC4pKSAtPiBteXRhYmxlcyAjZnJlYWQgbmVlZHMgdGhlIHdob2xlIHBhdGgNCg0KI01lcmdlIGxpc3QgdG8gbWVyZ2UgYWxsIHRoZSB0YWJsZXMgb2YgbXl0YWJsZXMgaW50byBvbmUgYmlnIHRhYmxlDQpUYWJsZV9BbGwgPSBiaW5kX3Jvd3MobXl0YWJsZXMpIA0KDQojQWRkaW5nIGNvbHVtbiBmb3IgY29uZGl0aW9uDQp0bXA9ZG8uY2FsbChyYmluZCxzdHJzcGxpdChUYWJsZV9BbGwkQXJlYU5hbWUsIl8iKSkgI3N0cmluZ3NwbGl0IHdpbGwgdGFrZSB0aGUgY29sdW1uIEFyZWFuYW1lIGFuZCB3aWxsIHNwbGl0IHRoaXMgZGVwZW5kaW5nIG9uIHRoZSB1bmRlcnNjb3JlLCB0aGVuIHdlIHB1dCB0aGVtIG90Z2V0ZXIgb25lIG9mdGVyIHRoZSBvdGhlcg0KI3RtcCBpcyBhIG1hdHJpeCwgaXQgaXMgbmVpdGhlciBhIGRhdGFmcmFtZSBub3IgYSB0YWJsZSwgaW4gYSB0YWJsZSB5b3UgaGF2ZSB0byBoYXZlIGNvbHVtbiBuYW1lcywgYWRkaW5nIGEgcm93IGluIGEgbWF0cml4IGlzIGVhc2llciB0aGFuIGluIGEgdGFibGUNCiNzb21lIGFyZWFuYW1lcyAyIHVuZGVyc2NvcmVzLCBvdGhlcnMgaGF2ZSA0IHVuZGVyc2NvcmVzLCB0aGUgbnVtYmVyIG9mIG1heGltdW0gdW5kZXJzY29yZXMgZGVmaW5lcyB0aGUgbnVtYmVyIG9mIGNvbHVtbnMsIHNvIHdoZW4gb25seSAyIHVuZGVyc2NvcmVzLCBpdCB3aWxsIGZpbGwgdGhlIG90aGVyIDIgY29sdW1ucyBieSByZXBlYXRpbmcgdGhlIHZhbHVlDQpUYWJsZV9BbGwkQ29uZGl0aW9uID0gdG1wWywxXQ0KDQpUYWJsZV9BbGwgJT4lIA0KICAgbXV0YXRlKENvbmRpdGlvbiA9IHN0cl9yZXBsYWNlX2FsbChDb25kaXRpb24sIA0KICAgICAgICAgICAgcGF0dGVybiA9ICJNVVQiLCByZXBsYWNlbWVudCA9ICJHQkEtUEQiKSkgJT4lDQogICAgIG11dGF0ZShDb25kaXRpb24gPSBzdHJfcmVwbGFjZV9hbGwoQ29uZGl0aW9uLCANCiAgICAgICAgICAgIHBhdHRlcm4gPSAiV1QiLCByZXBsYWNlbWVudCA9ICJDVFJMIikpIC0+VGFibGVfQWxsDQoNCiNTZWxlY3RpbmcgY29sdW1ucyBNYXJrZXJzDQp0b3NlbGVjdCA9IGMoIkJhcmNvZGUiLCJBcmVhTmFtZSIsIkNvbmRpdGlvbiIsIkRheSIsICJXZWxsIiwiQmF0Y2giLCAiVHVqMUJ5TnVjQWxpdmUiLCJUSEJ5TnVjQWxpdmUiLCJUSGFuZFR1ajFCeVR1ajEiLCJUSEZyYWdtZW50YXRpb24iLCJUSGFuZFR1ajFCeU51Y0FsaXZlIiwiVEhhbmRNQVAyQnlNQVAyIiwiRk9YQTJCeU51Y0FsaXZlIiwiVEhGcmFnbWVudGF0aW9uIiwiTGlua3NCeVNrZWwiLCJOb2Rlc0J5U2tlbCIsIk1BUDJCeU51Y0FsaXZlIiwiS2k2N0J5TnVjQWxpdmUiLCAiU294MkJ5TnVjQWxpdmUiLCAiR0ZBUEJ5TnVjQWxpdmUiLCAiczEwMGJCeU51Y0FsaXZlIiwgIk1BUDJCeU51Y0FsaXZlIiwgIkdGQVBCeVMxMDBiIiwgIlRITWFzayIsIlRITUZJIiwiTUFQMk1hc2siLCAiU294Mk1hc2siLCJLaTY3YW5kU294MkJ5U294MiIsICJTb3gyTUZJIiwgIk9MSUcyQnlOdWNBbGl2ZSIsICJPTElHMkN5dG9QQnlOdWNBbGl2ZSIsICJDTlBhc2VCeU51Y0FsaXZlIiAsICJPTElHMk51Y2xlYXJCeU51Y0FsaXZlIiwgIkRDWGFuZE5lc3RpbkJ5RENYIiwJIkRDWF9Ob2Rlc0J5U2tlbCIsCSJEQ1hfTGlua3NCeVNrZWwiLCJEQ1hGcmFnbWVudGF0aW9uIiwgIk5lc3RpbkJ5TnVjQWxpdmUiLAkiRENYQnlOdWNBbGl2ZSIsICJOZXN0aW5BbmREQ1hCeU5lc3RpbiIsICJUb3RhbE51Y01hc2siLCAiRENYYW5kTmVzdGluQnlOdWMiLCAiVEhNRkkiKQ0KDQoNClRhYmxlX0FsbCAlPiUgI3NhbWUgDQogIGRwbHlyOjpzZWxlY3QodG9zZWxlY3QpLT5UYWJsZV9BbGwNCg0KYGBgDQoNCk5vcm1hbGl6aW5nIHRvIHRoZSBtZWFuIG9mIHRoZSBjb250cm9scyBwZXIgZmVhdHVyZQ0KYGBge3J9IA0KI01lYW4gb2YgcmVwbGljYXRlcw0KZmVhdHVyZV9uYW1lcyA8LSBjb2xuYW1lcyhUYWJsZV9BbGxbLDc6bmNvbChUYWJsZV9BbGwpXSkNCiAgVGFibGVfQWxsJT4lDQogICAgcGl2b3RfbG9uZ2VyKGZlYXR1cmVfbmFtZXMsbmFtZXNfdG8gPSAiRmVhdHVyZXMiLCB2YWx1ZXNfdG8gPSAiTWVhc3VyZSIpIC0+IFRhYmxlX2FsbF9sb25nDQpUYWJsZV9hbGxfbG9uZzIgPSBkcm9wX25hKFRhYmxlX2FsbF9sb25nKSAgDQoNClRhYmxlX2FsbF9sb25nMiAlPiUNCiAgZ3JvdXBfYnkoRGF5LENvbmRpdGlvbixBcmVhTmFtZSxCYXRjaCxGZWF0dXJlcywgQmFyY29kZSkgJT4lDQogIHN1bW1hcml6ZShNZWFuRmVhdHVyZXMgPSBtZWFuKE1lYXN1cmUpKSAtPiBUYWJsZV9NZWFuDQoNCg0KIyAgdW5ncm91cCgpICU+JSANCiMgIGRwbHlyOjpzZWxlY3QoLUFyZWFOYW1lKSAlPiUgDQojICBmdWxsX2pvaW4oVGFibGVfYWxsX2xvbmcyLCBieT0iRmVhdHVyZXMiICkgDQogICAgI2Z1bGxfam9pbihUYWJsZV9hbGxfbG9uZzIsIGJ5PWMoIkZlYXR1cmVzIikpICU+JSAjaWYgSSB3YW50ZWQgdG8gbm9ybWFsaXplIHBlciBXQiBtZW1icmFuZQ0KDQoNCiNOb3JtYWxpemluZyB0byBtZWFuIG9mIGNvbnRyb2xzDQpUYWJsZV9NZWFuICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXIoQ29uZGl0aW9uPT0iQ1RSTCIpICU+JSANCiAgICAjZ3JvdXBfYnkoV0IsIEJhdGNoLCBDb25kaXRpb24sRmVhdHVyZXMpICU+JSANCiAgICBncm91cF9ieShDb25kaXRpb24sIERheSwgRmVhdHVyZXMsQmF0Y2gpICU+JSANCiAgICBzdW1tYXJpc2UoYmFzZWxpbmUgPSBtZWRpYW4oTWVhbkZlYXR1cmVzKSkgJT4lIA0KICAgIHVuZ3JvdXAoKSAlPiUgDQogICAgZHBseXI6OnNlbGVjdCgtQ29uZGl0aW9uKSAlPiUgDQogICAgI2RwbHlyOjpzZWxlY3QoLUJhdGNoKSAlPiUNCiAgICBmdWxsX2pvaW4oVGFibGVfTWVhbiwgYnk9YygiRGF5IiwiRmVhdHVyZXMiLCJCYXRjaCIpKSAlPiUgDQogICAgI2Z1bGxfam9pbihUYWJsZV9hbGxfbG9uZzIsIGJ5PWMoIkZlYXR1cmVzIikpICU+JSAjaWYgSSB3YW50ZWQgdG8gbm9ybWFsaXplIHBlciBXQiBtZW1icmFuZQ0KICAgIG11dGF0ZShGb2xkY2hhbmdlID0gTWVhbkZlYXR1cmVzIC9iYXNlbGluZSkgLT5UYWJsZV9hbGxfYmFzZWQNCg0KaW5jbHVkZWRfdmFycyA9YygiRGF5IiwgIkFyZWFOYW1lIiwgIkNvbmRpdGlvbiIsIkJhdGNoIiwiQmFyY29kZSIpICMgaGVyZSB3ZSBhbHJlYWR5IGhhdmUgdGhlIG1lYW4gb2YgZWFjaCBzZWN0aW9uDQpUYWJsZV9hbGxfYmFzZWQgJT4lIA0KICAgIHBpdm90X3dpZGVyKGFsbF9vZihpbmNsdWRlZF92YXJzKSxuYW1lc19mcm9tID0gRmVhdHVyZXMsdmFsdWVzX2Zyb20gPSBGb2xkY2hhbmdlKS0+VGFibGVfYWxsX2Jhc2VkX3dpZGUyDQoNCiN3cml0ZS5jc3YoVGFibGVfYWxsX2Jhc2VkX3dpZGUyLCBmaWxlID0gJ1RhYmxlX2FsbF9iYXNlZF93aWRlMi5jc3YnKQ0KDQpUYWJsZV9hbGxfYmFzZWRfd2lkZTI9VGFibGVfYWxsX2Jhc2VkX3dpZGUyWyFncmVwbCgiRDAiLFRhYmxlX2FsbF9iYXNlZF93aWRlMiREYXkpLF0NCg0KVGFibGVfYWxsX2Jhc2VkX3dpZGUxNTwtZmlsdGVyKFRhYmxlX2FsbF9iYXNlZF93aWRlMixEYXk9PSJkMTUiKQ0KVGFibGVfYWxsX2Jhc2VkX3dpZGUzMDwtZmlsdGVyKFRhYmxlX2FsbF9iYXNlZF93aWRlMixEYXk9PSJkMzAiKQ0KVGFibGVfYWxsX2Jhc2VkX3dpZGU2MDwtZmlsdGVyKFRhYmxlX2FsbF9iYXNlZF93aWRlMixEYXk9PSJkNjAiKQ0KVGFibGVfYWxsX2Jhc2VkX3dpZGU5MDwtZmlsdGVyKFRhYmxlX2FsbF9iYXNlZF93aWRlMixEYXk9PSJkOTAiKQ0KDQoNCg0KI0RvaW5nIHRoZSBtZWFuIGlmIHNhbWUgbWFya2VyIGlzIHVzZWQgZm9yIHNhbWUgdGltZXBvaW50IGluIGRpZmZlcmVudCBiYXJjb2Rlcw0KVGFibGVfYWxsX2Jhc2VkJT4lDQogIGdyb3VwX2J5KERheSxDb25kaXRpb24sQXJlYU5hbWUsQmF0Y2gsRmVhdHVyZXMpICU+JQ0KICBzdW1tYXJpemUoTWVhbkZlYXR1cmVzID0gbWVhbihGb2xkY2hhbmdlKSkgLT4gVGFibGVfTWVhbl9vZl9kaWZmZXJlbnRfQmFyY29kZXMNCmluY2x1ZGVkX3ZhcnMgPWMoIkRheSIsICJBcmVhTmFtZSIsICJDb25kaXRpb24iLCJCYXRjaCIpICMgaGVyZSB3ZSBhbHJlYWR5IGhhdmUgdGhlIG1lYW4gb2YgZWFjaCBzZWN0aW9uDQpUYWJsZV9NZWFuX29mX2RpZmZlcmVudF9CYXJjb2RlcyU+JSANCiAgICBwaXZvdF93aWRlcihhbGxfb2YoaW5jbHVkZWRfdmFycyksbmFtZXNfZnJvbSA9IEZlYXR1cmVzLHZhbHVlc19mcm9tID0gTWVhbkZlYXR1cmVzKS0+VGFibGVfTWVhbl9vZl9kaWZmZXJlbnRfQmFyY29kZXMNCg0KI3dyaXRlLmNzdihUYWJsZV9NZWFuX29mX2RpZmZlcmVudF9CYXJjb2RlcywgZmlsZSA9ICdUYWJsZV9NZWFuX29mX2RpZmZlcmVudF9CYXJjb2Rlcy5jc3YnKQ0KDQpgYGANCg0KUGxvdHMgZm9yIGFsbCB0aGUgZmVhdHVyZXMgb25lIHRpbWVwb2ludCAobG9vcCkNCmBgYHtyfQ0KDQpmZWF0dXJlX25hbWVzIDwtIGNvbG5hbWVzKFRhYmxlX2FsbF9iYXNlZF93aWRlMzBbLDY6bmNvbChUYWJsZV9hbGxfYmFzZWRfd2lkZTMwKV0pDQoNCiNUYWJsZV9hbGxfYmFzZWRfd2lkZTI9VGFibGVfYWxsX2Jhc2VkX3dpZGUyWyFncmVwbCgiSVJfMjAyMTExMjlfNDg4VEhfNTY4RENYXzY0N01BUDJfUlNfZTQ1ZTQ2ZTQ3ZDMwXzIwMjExMTI5XzE3NDMxOSIsVGFibGVfYWxsX2Jhc2VkX3dpZGUyJEJhcmNvZGUpLF0NCg0KI3N1YnNldCA9IGMoIkJhcmNvZGUiLCJBcmVhTmFtZSIsIkNvbmRpdGlvbiIsIkRheSIsIkJhdGNoIiwiRENYYW5kTmVzdGluQnlOdWMiKQ0KI1RhYmxlX2FsbF9iYXNlZF93aWRlMiU+JSAjc2FtZSANCiMgIGRwbHlyOjpzZWxlY3Qoc3Vic2V0KS0+VGFibGVfYWxsX2Jhc2VkX3dpZGUzDQojZmVhdHVyZV9uYW1lcyA8LSBjb2xuYW1lcyhUYWJsZV9hbGxfYmFzZWRfd2lkZTNbLDY6bmNvbChUYWJsZV9hbGxfYmFzZWRfd2lkZTMpXSkNCg0KDQoNCmZvciAoaSBpbiAxOmxlbmd0aChmZWF0dXJlX25hbWVzKSkgew0KVGFibGVfYWxsX2Jhc2VkX3dpZGUzMCAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHM9ZmVhdHVyZV9uYW1lcywgbmFtZXNfdG8gPSAiZmVhdHVyZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQ0KICBmaWx0ZXIoZmVhdHVyZSAlaW4lIGZlYXR1cmVfbmFtZXNbaV0pICU+JQ0KZ2dwbG90KCBhZXMoeD1mYWN0b3IoQ29uZGl0aW9uLCBsZXZlbCA9IGMoIkNUUkwiLCAiR0JBLVBEIikpLCB5PXZhbHVlKSkgKw0KICAjZ2VvbV92aW9saW4oIGFlcyhmaWxsPUNvbmRpdGlvbiksc2hvdy5sZWdlbmQgPSBULCB0cmltPVQpKw0KICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKCIjYmRkN2U3IiwiIzIxNzFiNSIpLG5hbWUgPSAiQ29uZGl0aW9uIiwgZ3VpZGUgPSBGQUxTRSkrDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjKCIjRkZGRkZGIiwiIzk5OTk5OSIpLG5hbWUgPSAiQ29uZGl0aW9uIiwgZ3VpZGUgPSAibm9uZSIpKyAjZ3VpZGUgZmFsc2Ugd2lsbCByZW1vdmUgdGhlIGxlZ2VuZCBmb3IgdGhlIGNvbmRpdGlvbg0KICAgIGdlb21fYm94cGxvdChhZXMoZmlsbD1Db25kaXRpb24pLHNob3cubGVnZW5kID0gRkFMU0Usd2lkdGg9MC41KSsgI3Nob3cubGVnZW5kIHdpbGwgcmVtb3ZlIGJveCBhcm91bmQgdGhlIHBvaW50cyBvZiB0aGUgbGVnZW5kDQogICAgZ2VvbV9wb2ludChhZXMoY29sb3I9QXJlYU5hbWUpLHNpemU9MyxzaG93LmxlZ2VuZCA9IFQsYWxwaGEgPSAwLjUpKw0KICAgIHNjYWxlX2NvbG9yX2pjb2xvcnMoInBhbDciKSsNCiAgICB0aGVtZShsZWdlbmQua2V5PWVsZW1lbnRfYmxhbmsoKSkgKw0KICBnZW9tX3NpZ25pZihjb21wYXJpc29ucyA9IGxpc3QoYygiQ1RSTCIsICJHQkEtUEQiKSksIHRlc3Q9J3dpbGNveC50ZXN0JywNCiAgICAgICAgICAgICAgdmp1c3Q9MC41LCBzaXplPTAuNSwgdGV4dHNpemU9OSwgbWFwX3NpZ25pZl9sZXZlbD1jKCIqKioiPTAuMDAxLCAiKioiPTAuMDEsICIqIj0wLjA1LCAgIiAiPTIpICkgKw0KICAjZmFjZXRfZ3JpZCh+ZmN0X3JlbGV2ZWwoRGF5LCAiZDE1IiwgImQzMCIsImQ2MCIsICJkOTAiKSwgc2NhbGVzPSJmcmVlIikgKw0KICAgICAgbGFicyh4ICAgICA9ICIiLA0KICAgICAgIHkgICAgID0gcGFzdGUoZmVhdHVyZV9uYW1lc1tpXSksDQogICAgICAgI3kgICAgID0gcGFzdGUobmFtZXNbaV0pLA0KICAgICAgIGZpbGwgID0gIkNvbmRpdGlvbiIsDQogICAgICAgI3RpdGxlID0gcGFzdGUoZmVhdHVyZV9uYW1lc1tpXSkpICsNCiAgICAgICB0aXRsZSA9ICIiICkrDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gJ2JsYWNrJywgc2l6ZSA9IDAuNSkgLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTIxLCBjb2xvcj0iYmxhY2siKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIxKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTE1LCBjb2xvcj0iYmxhY2siKSwNCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2xpbmUoKSwNCiAgICBheGlzLnRpY2tzLmxlbmd0aD11bml0KC4yNSwgImNtIiksDQogICAgI2NoYW5nZSBsZWdlbmQgdGV4dCBmb250IHNpemUpDQogICAgI2xlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43LCAiY20iKSwNCiAgICAjbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC42LCJjbSIpLA0KICAgIGxlZ2VuZC5rZXk9ZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBoanVzdD0wLjUsIHZqdXN0PSAxLCBmYWNlID0gImJvbGQiKSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCNlbGVtZW50X3RleHQoc2l6ZSA9IDIsIGhqdXN0PTAuNSkNCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIHZqdXN0PTAuNSksDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJsaWdodGdyYXkiKSwNCiAgICMgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgY29sb3IgPSAiYmxhY2siKSwNCiAgICBwYW5lbC5zcGFjaW5nLnkgPSB1bml0KDAuOCwgImxpbmVzIiksDQogICAgc3RyaXAuc3dpdGNoLnBhZC53cmFwPXVuaXQoMjAsICJsaW5lcyIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTcpLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE5KQ0KICAgIA0KICApICAtPiBwDQogIHByaW50KHApDQojZ2dzYXZlKHBhc3RlMChTeXMuRGF0ZSgpLChzcHJpbnRmKCJQbG90XyVzX0RJVjMwLnBkZiIsZmVhdHVyZV9uYW1lc1tpXSkpKSxoZWlnaHQ9My41KQ0KfQ0KYGBgDQoNClBsb3RzIGZvciBhbGwgZmVhdHVyZXMgYWxsIHRpbWVwb2ludHMgKGxvb3ApDQpgYGB7cn0NCiNUYWJsZV9hbGxfYmFzZWRfd2lkZTI8LWZpbHRlcihUYWJsZV9hbGxfYmFzZWRfd2lkZTIsQmFyY29kZT09IklSXzIwMjExMDE2XzQ4OE1BUDJfNTY4VFVKMV82NDdUSF9SU19lNDBlNDFlNDJkMzBfMjAyMTEwMTZfMTQ0NDM5IikNCg0KVGFibGVfYWxsX2Jhc2VkX3dpZGVUPVRhYmxlX2FsbF9iYXNlZF93aWRlMlshZ3JlcGwoIkQwIixUYWJsZV9hbGxfYmFzZWRfd2lkZTIkRGF5KSxdDQpmZWF0dXJlX25hbWVzIDwtIGNvbG5hbWVzKFRhYmxlX2FsbF9iYXNlZF93aWRlVFssNjpuY29sKFRhYmxlX2FsbF9iYXNlZF93aWRlVCldKQ0KDQojc3Vic2V0ID0gYygiQmFyY29kZSIsIkFyZWFOYW1lIiwiQ29uZGl0aW9uIiwiRGF5IiwiQmF0Y2giLCJUdWoxQnlOdWNBbGl2ZSIpDQojVGFibGVfYWxsX2Jhc2VkX3dpZGVUJT4lICNzYW1lIA0KIyAgZHBseXI6OnNlbGVjdChzdWJzZXQpLT5UYWJsZV9hbGxfYmFzZWRfd2lkZVQyDQoNCg0KDQoNCmZvciAoaSBpbiAxOmxlbmd0aChmZWF0dXJlX25hbWVzKSkgew0KVGFibGVfYWxsX2Jhc2VkX3dpZGVUICU+JQ0KICBwaXZvdF9sb25nZXIoY29scz1mZWF0dXJlX25hbWVzLCBuYW1lc190byA9ICJmZWF0dXJlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lDQogIGZpbHRlcihmZWF0dXJlICVpbiUgZmVhdHVyZV9uYW1lc1tpXSkgJT4lDQpnZ3Bsb3QoIGFlcyh4PWZhY3RvcihDb25kaXRpb24sIGxldmVsID0gYygiQ1RSTCIsICJHQkEtUEQiKSksIHk9dmFsdWUpKSArDQogICNnZW9tX3Zpb2xpbiggYWVzKGZpbGw9Q29uZGl0aW9uKSxzaG93LmxlZ2VuZCA9IFQsIHRyaW09VCkrDQoNCiAgI3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gYygiI2JkZDdlNyIsIiMyMTcxYjUiKSxuYW1lID0gIkNvbmRpdGlvbiIsIGd1aWRlID0gRkFMU0UpKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gYygiI0ZGRkZGRiIsIiM5OTk5OTkiKSxuYW1lID0gIkNvbmRpdGlvbiIsIGd1aWRlID0gIm5vbmUiKSsgI2d1aWRlIGZhbHNlIHdpbGwgcmVtb3ZlIHRoZSBsZWdlbmQgZm9yIHRoZSBjb25kaXRpb24NCiAgICAjZ2VvbV9ib3hwbG90KHdpZHRoPTAuMDcsIGZpbGw9IndoaXRlIikgKyANCiAgICBnZW9tX2JveHBsb3QoYWVzKGZpbGw9Q29uZGl0aW9uKSxzaG93LmxlZ2VuZCA9IEZBTFNFLHdpZHRoPTAuNykrICNzaG93LmxlZ2VuZCB3aWxsIHJlbW92ZSBib3ggYXJvdW5kIHRoZSBwb2ludHMgb2YgdGhlIGxlZ2VuZA0KICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPUFyZWFOYW1lKSxzaXplPTMsc2hvdy5sZWdlbmQgPSBULGFscGhhID0gMC41KSsNCiAgICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihicmV3ZXIucGFsKG49NiwgbmFtZT0iT3JSZCIpKSkrDQogICAgc2NhbGVfY29sb3JfamNvbG9ycygicGFsNyIpKw0KICAgICNzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbiA9ICJEIiwgZGlzY3JldGU9VFJVRSkrDQogICAgI2dlb21fcG9pbnQoc2hhcGUgPSAxLHNpemUgPSAzLGNvbG91ciA9ICJibGFjayIpKw0KICAgIHRoZW1lKGxlZ2VuZC5rZXk9ZWxlbWVudF9ibGFuaygpKSArDQogICAgDQogIGdlb21fc2lnbmlmKGNvbXBhcmlzb25zID0gbGlzdChjKCJDVFJMIiwgIkdCQS1QRCIpKSwgdGVzdD0nd2lsY294LnRlc3QnLA0KICAgICAgICAgICAgICB2anVzdD0wLjYsIHNpemU9MC41LCB0ZXh0c2l6ZT05LCBtYXBfc2lnbmlmX2xldmVsPWMoIioqKiI9MC4wMDEsICIqKiI9MC4wMSwgIioiPTAuMDUsICAiICI9MikgKSArDQogIGZhY2V0X2dyaWQofmZjdF9yZWxldmVsKERheSwgImQxNSIsICJkMzAiLCJkNjAiLCAiZDkwIiksIHNjYWxlcz0iZnJlZSIpICsNCiAgICAgIGxhYnMoeCAgICAgPSAiIiwNCiAgICAgICB5ICAgICA9IHBhc3RlKGZlYXR1cmVfbmFtZXNbaV0pLA0KICAgICAgIGZpbGwgID0gIkNvbmRpdGlvbiIsDQogICAgICAgdGl0bGUgPSAiIiApKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAwLjUpICwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMiwgY29sb3I9ImJsYWNrIixhbmdsZT0zMCx2anVzdCA9IDEuMSwgaGp1c3QgPSAwLjk1KSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTE1LCBjb2xvcj0iYmxhY2siKSwNCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2xpbmUoKSwNCiAgICBheGlzLnRpY2tzLmxlbmd0aD11bml0KC4yNSwgImNtIiksDQogICAgI2NoYW5nZSBsZWdlbmQgdGV4dCBmb250IHNpemUpDQogICAgI2xlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43LCAiY20iKSwNCiAgICAjbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC42LCJjbSIpLA0KICAgIGxlZ2VuZC5rZXk9ZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgI3BhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgaGp1c3Q9MC41LCB2anVzdD0gMSwgZmFjZSA9ICJib2xkIiksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwjZWxlbWVudF90ZXh0KHNpemUgPSAyLCBoanVzdD0wLjUpDQogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCB2anVzdD0wLjUpLA0KICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ibGlnaHRncmF5IiksDQogICAjIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIGNvbG9yID0gImJsYWNrIiksDQogICAgcGFuZWwuc3BhY2luZy55ID0gdW5pdCgwLjgsICJsaW5lcyIpLA0KICAgIHN0cmlwLnN3aXRjaC5wYWQud3JhcD11bml0KDIwLCAibGluZXMiKSwNCiAgICBsZWdlbmQucG9zaXRpb249InJpZ2h0IiwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE3KSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xOSkNCiAgICANCiAgKSAgLT4gcA0KDQogIHByaW50KHApDQogDQojZ2dzYXZlKHBhc3RlMChTeXMuRGF0ZSgpLChzcHJpbnRmKCJQbG90XyVzX0FsbCB0aW1lcG9pbnRzLnBkZiIsZmVhdHVyZV9uYW1lc1tpXSkpKSxoZWlnaHQ9NCkNCn0NCmBgYA0KDQo=