###This section for drafting up the script students will run
require(tidyverse)
Loading required package: tidyverse
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ----------------------------------------------------------------------------- tidyverse 1.3.1 --
√ ggplot2 3.3.5     √ purrr   0.3.4
√ tibble  3.1.6     √ dplyr   1.0.8
√ tidyr   1.2.0     √ stringr 1.4.0
√ readr   2.1.2     √ forcats 0.5.1
-- Conflicts -------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
require(openxlsx)
Loading required package: openxlsx
require(ggplot2)
require(ggpubr)
Loading required package: ggpubr
PhenoGeno<-read.xlsx("Data_final.xlsx",1 )%>% 
  as.data.frame(stringsAsFactors=FALSE) ## Read the phenotype and genotypes within 1Mb of the CXCL10 gene into memory.

##Explore the dataset:

#what is the dataset size?
dim(PhenoGeno)
[1]  527 4107
#which populations are included in the study?
unique(PhenoGeno$Population)
[1] "IBS" "KHV" "GWD" "ESN"
#are they equally represented?
table(PhenoGeno$Population)

ESN GWD IBS KHV 
129 179 157  62 
#what's the frequency/range of CXCL10 values?
ggplot(data = PhenoGeno)+
  geom_boxplot(aes(y= Chlamydia_IP10, x = Population, fill = Sex))+
  #geom_histogram(aes(x=Chlamydia_IP10), binwidth = 10)+
  theme_bw()


#how frequently do variants occur in the region?
PhenoGeno[-c(1:4)] %>%
  colSums() %>%
  enframe() %>%
  na.omit()-> variant_freq

ggplot(data = variant_freq)+
  geom_histogram(aes(x=value), binwidth = 10)+
  xlim(100,600)+
  theme_bw()
Warning: Removed 2 rows containing missing values (geom_bar).

#what is the most common variant?
max(variant_freq$value)
[1] 533
variant_freq[variant_freq$value == 533,]
#How many cells lines from men and women are there?
table(PhenoGeno$Sex)

female   male 
   248    279 
#Is that equally represented by population? Modify/add to the below code to calculate the % of cell lines from male or female individuals in each population.
PhenoGeno %>%
  group_by(Population) %>% add_count(name = "cell lines") %>%
  group_by(Population, `cell lines`) %>%
  count(Sex, name = "donors") %>% 
  mutate("%" = donors/`cell lines`)
  
##Use the below data.frame to answer the following questions. 
PhenoGeno.long <- pivot_longer(PhenoGeno[-4], cols = !c(LCL_ID, Sex, Population), names_to = "variant", values_to = "value") 

#Which population has the most variants? Describe the data transformations that occur to come to an answer.
PhenoGeno.long[PhenoGeno.long == 2] <- 1

PhenoGeno.long %>%
  group_by(Population, LCL_ID) %>%
  summarise("variant.sum" = sum(value)) %>%
  group_by(Population) %>%
  summarise("avg.variant" = mean(variant.sum),
            "sd" = sd(variant.sum))
`summarise()` has grouped output by 'Population'. You can override using the `.groups` argument.
#How many unique variants occur in each population? How many occur in 2 of 4 populations?
PhenoGeno.long[PhenoGeno.long == 0] <- NA

na.omit(PhenoGeno.long) %>%
  group_by(variant) %>%
  count(Population) %>%
  pivot_wider(id_cols = Population, names_from = variant, values_from = n) -> variants_by_pop

variants_by_pop[,colSums(is.na(variants_by_pop))==3]
variants_by_pop[,colSums(is.na(variants_by_pop))==2]

Explore other data analysis questions you have! Be careful not to overwrite the PhenoGeno data frame.

##Determine if the phenotype should be used for association testing [why we check for normality]

#add density plot of normal distribution overlap to plots. 
ggplot(PhenoGeno, aes(x = Chlamydia_IP10)) + geom_density() + 
  theme_bw(base_size = 14) ##Data are severely skewed, let's see if we can transform it into something usable


ggplot(PhenoGeno, aes(x = Chlamydia_IP10)) + geom_density() + 
  theme_bw(base_size = 14) + scale_x_continuous(trans = "log2") ##Data now fit a normal distribution, acceptable for association testing


PhenoGeno$log2_Chlamydia_IP10<-log2(PhenoGeno$Chlamydia_IP10) ##Create a column of the data frame with the log2transformed phenotype

#statistical test for normality
shapiro.test(PhenoGeno$Chlamydia_IP10)

    Shapiro-Wilk normality test

data:  PhenoGeno$Chlamydia_IP10
W = 0.67467, p-value < 2.2e-16
shapiro.test(PhenoGeno$log2_Chlamydia_IP10)

    Shapiro-Wilk normality test

data:  PhenoGeno$log2_Chlamydia_IP10
W = 0.98031, p-value = 1.506e-06
#QQ plots: QQ plots compare the distribution of our data against a normal distribution but looking at estimated quantiles. 
ggqqplot(PhenoGeno$Chlamydia_IP10)

ggqqplot(PhenoGeno$log2_Chlamydia_IP10)

##Determine if the phenotype is confounded by other variables

ggplot(PhenoGeno, aes(x = Sex, y = log2_Chlamydia_IP10, fill = Sex)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +  
  stat_compare_means(method = "t.test") + theme_bw(base_size = 14) + theme(legend.position = "none") ##LCLs from female donors secrete more CXCL10 in response to Chlamydia infection


ggplot(PhenoGeno, aes(x = Population, y = log2_Chlamydia_IP10, fill = Population)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + stat_compare_means(method = "anova") + theme(legend.position = "none") ##Data may also be confounded by Population effect


#would we interpret this differently if we hadn't normalized?
ggplot(data = PhenoGeno, aes(y = Chlamydia_IP10, x = Population, fill = Sex))+
  geom_boxplot(outlier.shape = NA, position = position_dodge2(0.85, preserve = "single")) + geom_point(size = 1, position=position_jitterdodge(0.1)) +
  #stat_compare_means(method = "t.test")+
  theme_bw(base_size = 12)

#Break here to talk about how association testing works, linear regression, covariates, etc.

Results<-read.xlsx("Data_final.xlsx",2) ##Read the results of association testing into memory

ggplot(Results, aes(x = Pos, y = -log10(Pvalue))) + geom_point() +
  theme_bw(base_size = 14) + geom_hline(yintercept = 7.3, color = "red") ## Can pause for discussion of why the threshold for significance is so high. multiple testing burden over 1M independent tests, etc.

##Instruct students to click the “Results” object and sort by “p-value” to find the top-associated SNP.

##Plot the top associated SNP
PhenoGeno$rs2869462<-as.factor(PhenoGeno$rs2869462) ##recode this as factor instead of numeric

ggplot(PhenoGeno, aes(x = rs2869462, y = log2_Chlamydia_IP10, fill = rs2869462)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + theme(legend.position = "none") ##Individuals with the alternate/minor allele produce less CXCL10/IP10 than those with the reference/major allele


ggplot(PhenoGeno, aes(x = rs2869462, y = log2_Chlamydia_IP10, fill = rs2869462)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + facet_grid(. ~ Sex) + theme(legend.position = "none") ## Regardless of Sex


ggplot(PhenoGeno, aes(x = rs2869462, y = log2_Chlamydia_IP10, fill = rs2869462)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + facet_grid(. ~ Population) + theme(legend.position = "none") ## Regardless of Population

Do the same for the 2nd most significant SNPs

##Plot the top associated SNP
PhenoGeno$rs13130917<-as.factor(PhenoGeno$rs13130917) ##recode this as factor instead of numeric

ggplot(PhenoGeno, aes(x = rs13130917, y = log2_Chlamydia_IP10, fill = rs13130917)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + theme(legend.position = "none") ##Individuals with the alternate/minor allele produce less CXCL10/IP10 than those with the reference/major allele


ggplot(PhenoGeno, aes(x = rs13130917, y = log2_Chlamydia_IP10, fill = rs13130917)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + facet_grid(. ~ Sex) + theme(legend.position = "none") ## Regardless of Sex


ggplot(PhenoGeno, aes(x = rs13130917, y = log2_Chlamydia_IP10, fill = rs13130917)) + geom_boxplot(outlier.shape = NA) + geom_jitter(width = 0.2) +
  theme_bw(base_size = 14) + facet_grid(. ~ Population) + theme(legend.position = "none") ## Regardless of Population

Those graphs look really similar. Do the two alleles primarily co-occur?

PhenoGeno$rs2869462 == PhenoGeno$rs13130917 #it looks like yes
  [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [19]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [37]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [55]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [73]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [91]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[109]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[127]  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[145]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[163]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[181]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[199]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[217]  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[235]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[253]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[271]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[289]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[307]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[325]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[343]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[361]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
[379]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[397]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[415]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[433]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[451]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[469]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[487]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[505]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[523]  TRUE  TRUE  TRUE  TRUE  TRUE

Where are the 2 highly significant SNPs located in the genome?

Results %>%
  filter(SNP == "rs13130917" | SNP == "rs2869462")
LS0tDQp0aXRsZTogIkRhdGFfZXhwZWRpdGlvbnMgQmlvNDMyUyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KYXV0aG9yczogIkJlbiBTY2hvdHQgJiBSeWxlZSBIYWNrbGV5Ig0KLS0tDQoNCmBgYHtyIGxvYWRfcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9DQojIyNUaGlzIHNlY3Rpb24gZm9yIGRyYWZ0aW5nIHVwIHRoZSBzY3JpcHQgc3R1ZGVudHMgd2lsbCBydW4NCnJlcXVpcmUodGlkeXZlcnNlKQ0KcmVxdWlyZShvcGVueGxzeCkNCnJlcXVpcmUoZ2dwbG90MikNCnJlcXVpcmUoZ2dwdWJyKQ0KDQpQaGVub0dlbm88LXJlYWQueGxzeCgiRGF0YV9maW5hbC54bHN4IiwxICklPiUgDQogIGFzLmRhdGEuZnJhbWUoc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkgIyMgUmVhZCB0aGUgcGhlbm90eXBlIGFuZCBnZW5vdHlwZXMgd2l0aGluIDFNYiBvZiB0aGUgQ1hDTDEwIGdlbmUgaW50byBtZW1vcnkuDQpgYGANCg0KIyNFeHBsb3JlIHRoZSBkYXRhc2V0Og0KYGBge3J9DQojd2hhdCBpcyB0aGUgZGF0YXNldCBzaXplPw0KZGltKFBoZW5vR2VubykNCg0KI3doaWNoIHBvcHVsYXRpb25zIGFyZSBpbmNsdWRlZCBpbiB0aGUgc3R1ZHk/DQp1bmlxdWUoUGhlbm9HZW5vJFBvcHVsYXRpb24pDQoNCiNhcmUgdGhleSBlcXVhbGx5IHJlcHJlc2VudGVkPw0KdGFibGUoUGhlbm9HZW5vJFBvcHVsYXRpb24pDQoNCiN3aGF0J3MgdGhlIGZyZXF1ZW5jeS9yYW5nZSBvZiBDWENMMTAgdmFsdWVzPw0KZ2dwbG90KGRhdGEgPSBQaGVub0dlbm8pKw0KICBnZW9tX2JveHBsb3QoYWVzKHk9IENobGFteWRpYV9JUDEwLCB4ID0gUG9wdWxhdGlvbiwgZmlsbCA9IFNleCkpKw0KICAjZ2VvbV9oaXN0b2dyYW0oYWVzKHg9Q2hsYW15ZGlhX0lQMTApLCBiaW53aWR0aCA9IDEwKSsNCiAgdGhlbWVfYncoKQ0KDQojaG93IGZyZXF1ZW50bHkgZG8gdmFyaWFudHMgb2NjdXIgaW4gdGhlIHJlZ2lvbj8NClBoZW5vR2Vub1stYygxOjQpXSAlPiUNCiAgY29sU3VtcygpICU+JQ0KICBlbmZyYW1lKCkgJT4lDQogIG5hLm9taXQoKS0+IHZhcmlhbnRfZnJlcQ0KDQpnZ3Bsb3QoZGF0YSA9IHZhcmlhbnRfZnJlcSkrDQogIGdlb21faGlzdG9ncmFtKGFlcyh4PXZhbHVlKSwgYmlud2lkdGggPSAxMCkrDQogIHhsaW0oMTAwLDYwMCkrDQogIHRoZW1lX2J3KCkNCg0KI3doYXQgaXMgdGhlIG1vc3QgY29tbW9uIHZhcmlhbnQ/DQptYXgodmFyaWFudF9mcmVxJHZhbHVlKQ0KdmFyaWFudF9mcmVxW3ZhcmlhbnRfZnJlcSR2YWx1ZSA9PSA1MzMsXQ0KYGBgDQoNCmBgYHtyfQ0KI0hvdyBtYW55IGNlbGxzIGxpbmVzIGZyb20gbWVuIGFuZCB3b21lbiBhcmUgdGhlcmU/DQp0YWJsZShQaGVub0dlbm8kU2V4KQ0KDQojSXMgdGhhdCBlcXVhbGx5IHJlcHJlc2VudGVkIGJ5IHBvcHVsYXRpb24/IE1vZGlmeS9hZGQgdG8gdGhlIGJlbG93IGNvZGUgdG8gY2FsY3VsYXRlIHRoZSAlIG9mIGNlbGwgbGluZXMgZnJvbSBtYWxlIG9yIGZlbWFsZSBpbmRpdmlkdWFscyBpbiBlYWNoIHBvcHVsYXRpb24uDQpQaGVub0dlbm8gJT4lDQogIGdyb3VwX2J5KFBvcHVsYXRpb24pICU+JSBhZGRfY291bnQobmFtZSA9ICJjZWxsIGxpbmVzIikgJT4lDQogIGdyb3VwX2J5KFBvcHVsYXRpb24sIGBjZWxsIGxpbmVzYCkgJT4lDQogIGNvdW50KFNleCwgbmFtZSA9ICJkb25vcnMiKSAlPiUgDQogIG11dGF0ZSgiJSIgPSBkb25vcnMvYGNlbGwgbGluZXNgKQ0KICANCiMjVXNlIHRoZSBiZWxvdyBkYXRhLmZyYW1lIHRvIGFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucy4gDQpQaGVub0dlbm8ubG9uZyA8LSBwaXZvdF9sb25nZXIoUGhlbm9HZW5vWy00XSwgY29scyA9ICFjKExDTF9JRCwgU2V4LCBQb3B1bGF0aW9uKSwgbmFtZXNfdG8gPSAidmFyaWFudCIsIHZhbHVlc190byA9ICJ2YWx1ZSIpIA0KDQojV2hpY2ggcG9wdWxhdGlvbiBoYXMgdGhlIG1vc3QgdmFyaWFudHM/IERlc2NyaWJlIHRoZSBkYXRhIHRyYW5zZm9ybWF0aW9ucyB0aGF0IG9jY3VyIHRvIGNvbWUgdG8gYW4gYW5zd2VyLg0KUGhlbm9HZW5vLmxvbmdbUGhlbm9HZW5vLmxvbmcgPT0gMl0gPC0gMQ0KDQpQaGVub0dlbm8ubG9uZyAlPiUNCiAgZ3JvdXBfYnkoUG9wdWxhdGlvbiwgTENMX0lEKSAlPiUNCiAgc3VtbWFyaXNlKCJ2YXJpYW50LnN1bSIgPSBzdW0odmFsdWUpKSAlPiUNCiAgZ3JvdXBfYnkoUG9wdWxhdGlvbikgJT4lDQogIHN1bW1hcmlzZSgiYXZnLnZhcmlhbnQiID0gbWVhbih2YXJpYW50LnN1bSksDQogICAgICAgICAgICAic2QiID0gc2QodmFyaWFudC5zdW0pKQ0KDQojSG93IG1hbnkgdW5pcXVlIHZhcmlhbnRzIG9jY3VyIGluIGVhY2ggcG9wdWxhdGlvbj8gSG93IG1hbnkgb2NjdXIgaW4gMiBvZiA0IHBvcHVsYXRpb25zPw0KUGhlbm9HZW5vLmxvbmdbUGhlbm9HZW5vLmxvbmcgPT0gMF0gPC0gTkENCg0KbmEub21pdChQaGVub0dlbm8ubG9uZykgJT4lDQogIGdyb3VwX2J5KHZhcmlhbnQpICU+JQ0KICBjb3VudChQb3B1bGF0aW9uKSAlPiUNCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IFBvcHVsYXRpb24sIG5hbWVzX2Zyb20gPSB2YXJpYW50LCB2YWx1ZXNfZnJvbSA9IG4pIC0+IHZhcmlhbnRzX2J5X3BvcA0KDQp2YXJpYW50c19ieV9wb3BbLGNvbFN1bXMoaXMubmEodmFyaWFudHNfYnlfcG9wKSk9PTNdDQp2YXJpYW50c19ieV9wb3BbLGNvbFN1bXMoaXMubmEodmFyaWFudHNfYnlfcG9wKSk9PTJdDQpgYGANCg0KRXhwbG9yZSBvdGhlciBkYXRhIGFuYWx5c2lzIHF1ZXN0aW9ucyB5b3UgaGF2ZSEgQmUgY2FyZWZ1bCBub3QgdG8gb3ZlcndyaXRlIHRoZSBQaGVub0dlbm8gZGF0YSBmcmFtZS4NCmBgYHtyfQ0KDQpgYGANCg0KDQojI0RldGVybWluZSBpZiB0aGUgcGhlbm90eXBlIHNob3VsZCBiZSB1c2VkIGZvciBhc3NvY2lhdGlvbiB0ZXN0aW5nDQpbd2h5IHdlIGNoZWNrIGZvciBub3JtYWxpdHldDQpgYGB7cn0NCiNhZGQgZGVuc2l0eSBwbG90IG9mIG5vcm1hbCBkaXN0cmlidXRpb24gb3ZlcmxhcCB0byBwbG90cy4gDQpnZ3Bsb3QoUGhlbm9HZW5vLCBhZXMoeCA9IENobGFteWRpYV9JUDEwKSkgKyBnZW9tX2RlbnNpdHkoKSArIA0KICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgIyNEYXRhIGFyZSBzZXZlcmVseSBza2V3ZWQsIGxldCdzIHNlZSBpZiB3ZSBjYW4gdHJhbnNmb3JtIGl0IGludG8gc29tZXRoaW5nIHVzYWJsZQ0KDQpnZ3Bsb3QoUGhlbm9HZW5vLCBhZXMoeCA9IENobGFteWRpYV9JUDEwKSkgKyBnZW9tX2RlbnNpdHkoKSArIA0KICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyBzY2FsZV94X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMiIpICMjRGF0YSBub3cgZml0IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiwgYWNjZXB0YWJsZSBmb3IgYXNzb2NpYXRpb24gdGVzdGluZw0KDQpQaGVub0dlbm8kbG9nMl9DaGxhbXlkaWFfSVAxMDwtbG9nMihQaGVub0dlbm8kQ2hsYW15ZGlhX0lQMTApICMjQ3JlYXRlIGEgY29sdW1uIG9mIHRoZSBkYXRhIGZyYW1lIHdpdGggdGhlIGxvZzJ0cmFuc2Zvcm1lZCBwaGVub3R5cGUNCg0KI3N0YXRpc3RpY2FsIHRlc3QgZm9yIG5vcm1hbGl0eQ0Kc2hhcGlyby50ZXN0KFBoZW5vR2VubyRDaGxhbXlkaWFfSVAxMCkNCnNoYXBpcm8udGVzdChQaGVub0dlbm8kbG9nMl9DaGxhbXlkaWFfSVAxMCkNCg0KI1FRIHBsb3RzOiBRUSBwbG90cyBjb21wYXJlIHRoZSBkaXN0cmlidXRpb24gb2Ygb3VyIGRhdGEgYWdhaW5zdCBhIG5vcm1hbCBkaXN0cmlidXRpb24gYnV0IGxvb2tpbmcgYXQgZXN0aW1hdGVkIHF1YW50aWxlcy4gDQpnZ3FxcGxvdChQaGVub0dlbm8kQ2hsYW15ZGlhX0lQMTApDQpnZ3FxcGxvdChQaGVub0dlbm8kbG9nMl9DaGxhbXlkaWFfSVAxMCkNCmBgYA0KDQojI0RldGVybWluZSBpZiB0aGUgcGhlbm90eXBlIGlzIGNvbmZvdW5kZWQgYnkgb3RoZXIgdmFyaWFibGVzDQpgYGB7cn0NCmdncGxvdChQaGVub0dlbm8sIGFlcyh4ID0gU2V4LCB5ID0gbG9nMl9DaGxhbXlkaWFfSVAxMCwgZmlsbCA9IFNleCkpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMikgKyAgDQogIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IikgKyB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICMjTENMcyBmcm9tIGZlbWFsZSBkb25vcnMgc2VjcmV0ZSBtb3JlIENYQ0wxMCBpbiByZXNwb25zZSB0byBDaGxhbXlkaWEgaW5mZWN0aW9uDQoNCmdncGxvdChQaGVub0dlbm8sIGFlcyh4ID0gUG9wdWxhdGlvbiwgeSA9IGxvZzJfQ2hsYW15ZGlhX0lQMTAsIGZpbGwgPSBQb3B1bGF0aW9uKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAiYW5vdmEiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgIyNEYXRhIG1heSBhbHNvIGJlIGNvbmZvdW5kZWQgYnkgUG9wdWxhdGlvbiBlZmZlY3QNCg0KI3dvdWxkIHdlIGludGVycHJldCB0aGlzIGRpZmZlcmVudGx5IGlmIHdlIGhhZG4ndCBub3JtYWxpemVkPw0KZ2dwbG90KGRhdGEgPSBQaGVub0dlbm8sIGFlcyh5ID0gQ2hsYW15ZGlhX0lQMTAsIHggPSBQb3B1bGF0aW9uLCBmaWxsID0gU2V4KSkrDQogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UyKDAuODUsIHByZXNlcnZlID0gInNpbmdsZSIpKSArIGdlb21fcG9pbnQoc2l6ZSA9IDEsIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcmRvZGdlKDAuMSkpICsNCiAgI3N0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IikrDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKQ0KYGBgDQoNCiNCcmVhayBoZXJlIHRvIHRhbGsgYWJvdXQgaG93IGFzc29jaWF0aW9uIHRlc3Rpbmcgd29ya3MsIGxpbmVhciByZWdyZXNzaW9uLCBjb3ZhcmlhdGVzLCBldGMuDQpgYGB7cn0NClJlc3VsdHM8LXJlYWQueGxzeCgiRGF0YV9maW5hbC54bHN4IiwyKSAjI1JlYWQgdGhlIHJlc3VsdHMgb2YgYXNzb2NpYXRpb24gdGVzdGluZyBpbnRvIG1lbW9yeQ0KDQpnZ3Bsb3QoUmVzdWx0cywgYWVzKHggPSBQb3MsIHkgPSAtbG9nMTAoUHZhbHVlKSkpICsgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNy4zLCBjb2xvciA9ICJyZWQiKSAjIyBDYW4gcGF1c2UgZm9yIGRpc2N1c3Npb24gb2Ygd2h5IHRoZSB0aHJlc2hvbGQgZm9yIHNpZ25pZmljYW5jZSBpcyBzbyBoaWdoLiBtdWx0aXBsZSB0ZXN0aW5nIGJ1cmRlbiBvdmVyIDFNIGluZGVwZW5kZW50IHRlc3RzLCBldGMuDQpgYGANCg0KIyNJbnN0cnVjdCBzdHVkZW50cyB0byBjbGljayB0aGUgIlJlc3VsdHMiIG9iamVjdCBhbmQgc29ydCBieSAicC12YWx1ZSIgdG8gZmluZCB0aGUgdG9wLWFzc29jaWF0ZWQgU05QLg0KYGBge3J9DQojI1Bsb3QgdGhlIHRvcCBhc3NvY2lhdGVkIFNOUA0KUGhlbm9HZW5vJHJzMjg2OTQ2MjwtYXMuZmFjdG9yKFBoZW5vR2VubyRyczI4Njk0NjIpICMjcmVjb2RlIHRoaXMgYXMgZmFjdG9yIGluc3RlYWQgb2YgbnVtZXJpYw0KDQpnZ3Bsb3QoUGhlbm9HZW5vLCBhZXMoeCA9IHJzMjg2OTQ2MiwgeSA9IGxvZzJfQ2hsYW15ZGlhX0lQMTAsIGZpbGwgPSByczI4Njk0NjIpKSArIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIpICsNCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAjI0luZGl2aWR1YWxzIHdpdGggdGhlIGFsdGVybmF0ZS9taW5vciBhbGxlbGUgcHJvZHVjZSBsZXNzIENYQ0wxMC9JUDEwIHRoYW4gdGhvc2Ugd2l0aCB0aGUgcmVmZXJlbmNlL21ham9yIGFsbGVsZQ0KDQpnZ3Bsb3QoUGhlbm9HZW5vLCBhZXMoeCA9IHJzMjg2OTQ2MiwgeSA9IGxvZzJfQ2hsYW15ZGlhX0lQMTAsIGZpbGwgPSByczI4Njk0NjIpKSArIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIpICsNCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgZmFjZXRfZ3JpZCguIH4gU2V4KSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgIyMgUmVnYXJkbGVzcyBvZiBTZXgNCg0KZ2dwbG90KFBoZW5vR2VubywgYWVzKHggPSByczI4Njk0NjIsIHkgPSBsb2cyX0NobGFteWRpYV9JUDEwLCBmaWxsID0gcnMyODY5NDYyKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIGZhY2V0X2dyaWQoLiB+IFBvcHVsYXRpb24pICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAjIyBSZWdhcmRsZXNzIG9mIFBvcHVsYXRpb24NCmBgYA0KDQpEbyB0aGUgc2FtZSBmb3IgdGhlIDJuZCBtb3N0IHNpZ25pZmljYW50IFNOUHMNCmBgYHtyfQ0KIyNQbG90IHRoZSB0b3AgYXNzb2NpYXRlZCBTTlANClBoZW5vR2VubyRyczEzMTMwOTE3PC1hcy5mYWN0b3IoUGhlbm9HZW5vJHJzMTMxMzA5MTcpICMjcmVjb2RlIHRoaXMgYXMgZmFjdG9yIGluc3RlYWQgb2YgbnVtZXJpYw0KDQpnZ3Bsb3QoUGhlbm9HZW5vLCBhZXMoeCA9IHJzMTMxMzA5MTcsIHkgPSBsb2cyX0NobGFteWRpYV9JUDEwLCBmaWxsID0gcnMxMzEzMDkxNykpICsgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMikgKw0KICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICMjSW5kaXZpZHVhbHMgd2l0aCB0aGUgYWx0ZXJuYXRlL21pbm9yIGFsbGVsZSBwcm9kdWNlIGxlc3MgQ1hDTDEwL0lQMTAgdGhhbiB0aG9zZSB3aXRoIHRoZSByZWZlcmVuY2UvbWFqb3IgYWxsZWxlDQoNCmdncGxvdChQaGVub0dlbm8sIGFlcyh4ID0gcnMxMzEzMDkxNywgeSA9IGxvZzJfQ2hsYW15ZGlhX0lQMTAsIGZpbGwgPSByczEzMTMwOTE3KSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIGZhY2V0X2dyaWQoLiB+IFNleCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICMjIFJlZ2FyZGxlc3Mgb2YgU2V4DQoNCmdncGxvdChQaGVub0dlbm8sIGFlcyh4ID0gcnMxMzEzMDkxNywgeSA9IGxvZzJfQ2hsYW15ZGlhX0lQMTAsIGZpbGwgPSByczEzMTMwOTE3KSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArIGdlb21faml0dGVyKHdpZHRoID0gMC4yKSArDQogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIGZhY2V0X2dyaWQoLiB+IFBvcHVsYXRpb24pICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAjIyBSZWdhcmRsZXNzIG9mIFBvcHVsYXRpb24NCmBgYA0KDQoNClRob3NlIGdyYXBocyBsb29rIHJlYWxseSBzaW1pbGFyLiBEbyB0aGUgdHdvIGFsbGVsZXMgcHJpbWFyaWx5IGNvLW9jY3VyPw0KYGBge3J9DQpQaGVub0dlbm8kcnMyODY5NDYyID09IFBoZW5vR2VubyRyczEzMTMwOTE3ICNpdCBsb29rcyBsaWtlIHllcw0KYGBgDQoNCldoZXJlIGFyZSB0aGUgMiBoaWdobHkgc2lnbmlmaWNhbnQgU05QcyBsb2NhdGVkIGluIHRoZSBnZW5vbWU/DQpgYGB7cn0NClJlc3VsdHMgJT4lDQogIGZpbHRlcihTTlAgPT0gInJzMTMxMzA5MTciIHwgU05QID09ICJyczI4Njk0NjIiKQ0KYGBg