Paths
dir.single.cohort <- "../DATASETS"
dir.gasparoni <- file.path(dir.single.cohort, "GASPARONI/step9_single_cpg_pval")
dir.london <- file.path(dir.single.cohort, "LONDON/step7_single_cpg_pval")
dir.mtsinai <- file.path(dir.single.cohort, "MtSinai/step7_single_cpg_pval")
dir.rosmap <- file.path(dir.single.cohort, "ROSMAP/step9_single_cpg_pval")
dir.meta.single.cpg <- "../meta_analysis_single_cpg_results/"
dir.data <- "./DATASETS"
dir.fig <- "./FIGURES"
Estimation of inflation
library(dplyr)
library(bacon)
library(GWASTools)
Auxiliary functions
estimation_of_inflation <- function(data){
### 1. Compute genomic inflation factor before bacon adjustment
data$zvalue <- data$Estimate / data$StdErr
data$chisq <- (data$zvalue) ^ 2
# inflation factor - last term is median from chisq distrn with 1 df
inflationFactor <- median(data$chisq,na.rm = TRUE) / qchisq(0.5, 1)
print("lambda")
print(inflationFactor)
# genome-wide sig cpgs
sig <- ifelse(data$pValue < 2.4e-7, 1, 0)
# table(sig) # 1 sig
### 2. bacon analysis
bc <- bacon(
teststatistics = NULL,
effectsizes = data$Estimate,
standarderrors = data$StdErr,
na.exclude = TRUE
)
# inflation factor
print("lambda.bacon")
print(inflation(bc))
### 3. Create final dataset
data.with.inflation <- data.frame(
data,
Estimate.bacon = bacon::es(bc),
StdErr.bacon = bacon::se(bc),
pValue.bacon = pval(bc),
fdr.bacon = p.adjust(pval(bc), method = "fdr"),
stringsAsFactors = FALSE
)
data.with.inflation <- data.with.inflation %>% select(-c(zvalue, chisq))
return(
list("data.with.inflation" = data.with.inflation,
"inflationFactor" = inflationFactor,
"estimatedInflation" = inflation(bc)
)
)
}
GASPARONI
est.inflation <- estimation_of_inflation(res)
## [1] "lambda"
## [1] 1.002218
## [1] "lambda.bacon"
## sigma.0
## 0.9852269
res.with.inflation <- est.inflation$data.with.inflation
cohort <- "GASPARONI"
write.csv(
res.with.inflation,
file.path(dir.data, cohort, "single_cpg_pVal_df.csv"),
row.names = FALSE
)
# genome-wide sig cpgs
sig.fdr <- ifelse(res.with.inflation$fdr.bacon < 0.05, 1, 0)
# table(sig.fdr) # 2 sig
LONDON
est.inflation <- estimation_of_inflation(res)
## [1] "lambda"
## [1] 1.208283
## [1] "lambda.bacon"
## sigma.0
## 1.082232
res.with.inflation <- est.inflation$data.with.inflation
cohort <- "LONDON"
write.csv(
res.with.inflation,
file.path(dir.data, cohort, "single_cpg_pVal_df.csv"),
row.names = FALSE
)
# genome-wide sig cpgs
sig.fdr <- ifelse(res.with.inflation$fdr.bacon < 0.05, 1, 0)
# table(sig.fdr) # 11 sig
MTSINAI
est.inflation <- estimation_of_inflation(res)
## [1] "lambda"
## [1] 1.248826
## [1] "lambda.bacon"
## sigma.0
## 1.077693
res.with.inflation <- est.inflation$data.with.inflation
cohort <- "MTSINAI"
write.csv(
res.with.inflation,
file.path(dir.data, cohort, "single_cpg_pVal_df.csv"),
row.names = FALSE
)
# genome-wide sig cpgs
sig.fdr <- ifelse(res.with.inflation$fdr.bacon < 0.05, 1, 0)
# table(sig.fdr) # 0 sig
ROSMAP
est.inflation <- estimation_of_inflation(res)
## [1] "lambda"
## [1] 1.015642
## [1] "lambda.bacon"
## sigma.0
## 1.001666
res.with.inflation <- est.inflation$data.with.inflation
cohort <- "ROSMAP"
write.csv(
res.with.inflation,
file.path(dir.data, cohort, "single_cpg_pVal_df.csv"),
row.names = FALSE
)
# genome-wide sig cpgs
sig.fdr <- ifelse(res.with.inflation$fdr.bacon < 0.05, 1, 0)
# table(sig.fdr) # 34 sig
LS0tDQp0aXRsZTogIlNlbnNpdGl2aXR5IEFuYWx5c2lzIC0gZXN0aW1hdGlvbiBvZiBnZW5vbWljIGluZmxhdGlvbiINCmF1dGhvcjogIkxhbnl1IFpoYW5nLCBUaWFnbyBDLiBTaWx2YSwgTGlseSBXYW5nIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBybWFya2Rvd246Omh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGx1bWVuDQogICAgdG9jOiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQogICAgdG9jX2RlcHRoOiAzDQplZGl0b3Jfb3B0aW9uczoNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZSAgICANCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFKQ0KYGBgDQoNCiMgUGF0aHMNCg0KYGBge1J9DQpkaXIuc2luZ2xlLmNvaG9ydCA8LSAiLi4vREFUQVNFVFMiDQpkaXIuZ2FzcGFyb25pIDwtIGZpbGUucGF0aChkaXIuc2luZ2xlLmNvaG9ydCwgIkdBU1BBUk9OSS9zdGVwOV9zaW5nbGVfY3BnX3B2YWwiKQ0KZGlyLmxvbmRvbiA8LSBmaWxlLnBhdGgoZGlyLnNpbmdsZS5jb2hvcnQsICJMT05ET04vc3RlcDdfc2luZ2xlX2NwZ19wdmFsIikNCmRpci5tdHNpbmFpIDwtIGZpbGUucGF0aChkaXIuc2luZ2xlLmNvaG9ydCwgIk10U2luYWkvc3RlcDdfc2luZ2xlX2NwZ19wdmFsIikNCmRpci5yb3NtYXAgPC0gZmlsZS5wYXRoKGRpci5zaW5nbGUuY29ob3J0LCAiUk9TTUFQL3N0ZXA5X3NpbmdsZV9jcGdfcHZhbCIpDQpkaXIubWV0YS5zaW5nbGUuY3BnIDwtICIuLi9tZXRhX2FuYWx5c2lzX3NpbmdsZV9jcGdfcmVzdWx0cy8iDQpkaXIuZGF0YSA8LSAiLi9EQVRBU0VUUyINCmRpci5maWcgPC0gIi4vRklHVVJFUyINCmBgYA0KDQojIEVzdGltYXRpb24gb2YgaW5mbGF0aW9uDQoNCmBgYHtSLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0ID0gImhpZGUifQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoYmFjb24pDQpsaWJyYXJ5KEdXQVNUb29scykNCmBgYA0KDQojIyBBdXhpbGlhcnkgZnVuY3Rpb25zDQoNCmBgYHtSfQ0KZXN0aW1hdGlvbl9vZl9pbmZsYXRpb24gPC0gZnVuY3Rpb24oZGF0YSl7DQogICMjIyAxLiBDb21wdXRlIGdlbm9taWMgaW5mbGF0aW9uIGZhY3RvciBiZWZvcmUgYmFjb24gYWRqdXN0bWVudA0KICBkYXRhJHp2YWx1ZSA8LSBkYXRhJEVzdGltYXRlIC8gZGF0YSRTdGRFcnINCiAgZGF0YSRjaGlzcSA8LSAoZGF0YSR6dmFsdWUpIF4gMg0KDQogICMgaW5mbGF0aW9uIGZhY3RvciAtIGxhc3QgdGVybSBpcyBtZWRpYW4gZnJvbSBjaGlzcSBkaXN0cm4gd2l0aCAxIGRmICANCiAgaW5mbGF0aW9uRmFjdG9yIDwtIG1lZGlhbihkYXRhJGNoaXNxLG5hLnJtID0gVFJVRSkgLyBxY2hpc3EoMC41LCAxKQ0KICBwcmludCgibGFtYmRhIikNCiAgcHJpbnQoaW5mbGF0aW9uRmFjdG9yKQ0KDQogICMgZ2Vub21lLXdpZGUgc2lnIGNwZ3MNCiAgc2lnIDwtIGlmZWxzZShkYXRhJHBWYWx1ZSA8IDIuNGUtNywgMSwgMCkNCiAgIyB0YWJsZShzaWcpICAjIDEgc2lnDQoNCiAgIyMjIDIuIGJhY29uIGFuYWx5c2lzDQogIGJjIDwtIGJhY29uKA0KICAgIHRlc3RzdGF0aXN0aWNzID0gTlVMTCwNCiAgICBlZmZlY3RzaXplcyA9ICBkYXRhJEVzdGltYXRlLA0KICAgIHN0YW5kYXJkZXJyb3JzID0gZGF0YSRTdGRFcnIsDQogICAgbmEuZXhjbHVkZSA9IFRSVUUNCiAgKQ0KDQogICMgaW5mbGF0aW9uIGZhY3Rvcg0KICBwcmludCgibGFtYmRhLmJhY29uIikNCiAgcHJpbnQoaW5mbGF0aW9uKGJjKSkNCiAgDQogICMjIyAzLiBDcmVhdGUgZmluYWwgZGF0YXNldA0KICBkYXRhLndpdGguaW5mbGF0aW9uIDwtIGRhdGEuZnJhbWUoDQogICAgZGF0YSwNCiAgICBFc3RpbWF0ZS5iYWNvbiA9IGJhY29uOjplcyhiYyksDQogICAgU3RkRXJyLmJhY29uID0gYmFjb246OnNlKGJjKSwNCiAgICBwVmFsdWUuYmFjb24gPSBwdmFsKGJjKSwNCiAgICBmZHIuYmFjb24gPSBwLmFkanVzdChwdmFsKGJjKSwgbWV0aG9kID0gImZkciIpLA0KICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KICApDQogIGRhdGEud2l0aC5pbmZsYXRpb24gPC0gZGF0YS53aXRoLmluZmxhdGlvbiAlPiUgc2VsZWN0KC1jKHp2YWx1ZSwgY2hpc3EpKQ0KICByZXR1cm4oDQogICAgbGlzdCgiZGF0YS53aXRoLmluZmxhdGlvbiIgPSBkYXRhLndpdGguaW5mbGF0aW9uLCANCiAgICAgICAgICAiaW5mbGF0aW9uRmFjdG9yIiA9ICAgaW5mbGF0aW9uRmFjdG9yLA0KICAgICAgICAgICJlc3RpbWF0ZWRJbmZsYXRpb24iID0gaW5mbGF0aW9uKGJjKQ0KICAgICAgICAgKQ0KICAgICkNCn0NCiAgDQpgYGANCg0KIyMgR0FTUEFST05JDQoNCmBgYHtSLCBpbmNsdWRlID0gRkFMU0V9DQpyZXMgPC0gcmVhZC5jc3YoDQogICAgZmlsZS5wYXRoKGRpci5nYXNwYXJvbmksICJHYXNwYXJvbmlfc2luZ2xlX2NwZ19wVmFsX2RmLmNzdiIpDQopDQpgYGANCg0KYGBge1J9DQplc3QuaW5mbGF0aW9uIDwtIGVzdGltYXRpb25fb2ZfaW5mbGF0aW9uKHJlcykNCnJlcy53aXRoLmluZmxhdGlvbiA8LSBlc3QuaW5mbGF0aW9uJGRhdGEud2l0aC5pbmZsYXRpb24NCg0KDQpjb2hvcnQgPC0gIkdBU1BBUk9OSSINCndyaXRlLmNzdigNCiAgICByZXMud2l0aC5pbmZsYXRpb24sDQogICAgZmlsZS5wYXRoKGRpci5kYXRhLCBjb2hvcnQsICJzaW5nbGVfY3BnX3BWYWxfZGYuY3N2IiksDQogICAgcm93Lm5hbWVzID0gRkFMU0UNCikNCg0KIyBnZW5vbWUtd2lkZSBzaWcgY3Bncw0Kc2lnLmZkciA8LSBpZmVsc2UocmVzLndpdGguaW5mbGF0aW9uJGZkci5iYWNvbiA8IDAuMDUsIDEsIDApDQojIHRhYmxlKHNpZy5mZHIpICAgIyAyIHNpZw0KDQpgYGANCg0KYGBge1IsIGluY2x1ZGUgPSBGQUxTRSwgZXZhbD1GQUxTRX0NCiMjIyA1LiBQbG90cw0KcFZhbHVlIDwtIGRhdGEuZnJhbWUoDQogIHBWYWx1ZSA9IHJlcy53aXRoLmluZmxhdGlvbiRwVmFsdWUsDQogIHR5cGUgPSAicFZhbHVlIiwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQoNCnBWYWx1ZS5iYWNvbiA8LSBkYXRhLmZyYW1lKA0KICBwVmFsdWUgPSByZXMud2l0aC5pbmZsYXRpb24kcFZhbHVlLmJhY29uLA0KICB0eXBlID0gInBWYWx1ZS5iYWNvbiIsDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQ0KcGxvdF9kZiA8LSByYmluZChwVmFsdWUsIHBWYWx1ZS5iYWNvbikNCg0KDQpoaXN0Lmdhc3Bhcm9uaSA8LSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHBWYWx1ZSwgZmlsbCA9IHR5cGUpKSArDQogIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC4zLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9IHBhc3RlMCgiSGlzdG9ncmFtIG9mIHB2YWx1ZXMgaW4gIiwgY29ob3J0LCAiIGNvaG9ydCIpKSArDQogIHRoZW1lX2J3KCkNCg0KIyBwZGYocGFzdGUwKGRpci5maWcsICIvIiwgY29ob3J0LCAiX3B2YWxIaXN0LnBkZiIpKQ0KaGlzdC5nYXNwYXJvbmkNCiMgZGV2Lm9mZigpDQoNCnFxUGxvdChyZXMud2l0aC5pbmZsYXRpb24kcFZhbHVlLCBjaSA9IFRSVUUsIG1haW4gPSBwYXN0ZTAoY29ob3J0LCAiIGNvaG9ydCIpKSArDQp0ZXh0KA0KICB4ID0gMC41LCANCiAgeSA9IDYuMiwNCiAgbGFiZWxzID0gYnF1b3RlKGxhbWJkYSA9PSAuKGZvcm1hdChlc3QuaW5mbGF0aW9uJGluZmxhdGlvbkZhY3RvcixkaWdpdHMgPSA0KSkpLA0KICBwb3MgPSA0DQopICsNCnRleHQoDQogIHggPSAwLjUsIA0KICB5ID0gNS40LA0KIGxhYmVscyA9IGJxdW90ZShsYW1iZGFbYmFjb25dID09IC4oZm9ybWF0KGVzdC5pbmZsYXRpb24kZXN0aW1hdGVkSW5mbGF0aW9uLGRpZ2l0cyA9IDQpKSksDQogIHBvcyA9IDQNCikNCnFxcGxvdC5nYXNwYXJvbmkgPC0gcmVjb3JkUGxvdCgpDQoNCnBkZihwYXN0ZTAoZGlyLmZpZywgIi8iLCBjb2hvcnQsICJfcXFQbG90cy5wZGYiKSkNCnFxcGxvdC5nYXNwYXJvbmkNCmRldi5vZmYoKQ0KYGBgDQoNCiMjIExPTkRPTg0KDQpgYGB7UiwgaW5jbHVkZSA9IEZBTFNFfQ0KcmVzIDwtIHJlYWQuY3N2KA0KICAgIGZpbGUucGF0aChkaXIubG9uZG9uLCAiTG9uZG9uX1BGQ19zaW5nbGVfY3BnX3BWYWxfZGYuY3N2IikNCikNCmBgYA0KDQpgYGB7Un0NCmVzdC5pbmZsYXRpb24gPC0gZXN0aW1hdGlvbl9vZl9pbmZsYXRpb24ocmVzKQ0KcmVzLndpdGguaW5mbGF0aW9uIDwtIGVzdC5pbmZsYXRpb24kZGF0YS53aXRoLmluZmxhdGlvbg0KDQpjb2hvcnQgPC0gIkxPTkRPTiINCg0Kd3JpdGUuY3N2KA0KICAgIHJlcy53aXRoLmluZmxhdGlvbiwNCiAgICBmaWxlLnBhdGgoZGlyLmRhdGEsIGNvaG9ydCwgInNpbmdsZV9jcGdfcFZhbF9kZi5jc3YiKSwNCiAgICByb3cubmFtZXMgPSBGQUxTRQ0KKQ0KDQojIGdlbm9tZS13aWRlIHNpZyBjcGdzDQpzaWcuZmRyIDwtIGlmZWxzZShyZXMud2l0aC5pbmZsYXRpb24kZmRyLmJhY29uIDwgMC4wNSwgMSwgMCkNCiMgdGFibGUoc2lnLmZkcikgICAjIDExIHNpZw0KDQpgYGANCg0KYGBge1IsaW5jbHVkZSA9IEZBTFNFLCBldmFsPUZBTFNFfQ0KIyMjIDUuIFBsb3RzDQpwVmFsdWUgPC0gZGF0YS5mcmFtZSgNCiAgcFZhbHVlID0gcmVzLndpdGguaW5mbGF0aW9uJHBWYWx1ZSwNCiAgdHlwZSA9ICJwVmFsdWUiLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRikNCg0KcFZhbHVlLmJhY29uIDwtIGRhdGEuZnJhbWUoDQogIHBWYWx1ZSA9IHJlcy53aXRoLmluZmxhdGlvbiRwVmFsdWUuYmFjb24sDQogIHR5cGUgPSAicFZhbHVlLmJhY29uIiwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQpwbG90X2RmIDwtIHJiaW5kKHBWYWx1ZSwgcFZhbHVlLmJhY29uKQ0KDQpoaXN0LmxvbmRvbiA8LSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHBWYWx1ZSwgZmlsbCA9IHR5cGUpKSArDQogIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC4zLHBvc2l0aW9uPSJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9IHBhc3RlMCgiSGlzdG9ncmFtIG9mIHB2YWx1ZXMgaW4gIiwgY29ob3J0LCAiIGNvaG9ydCIpKSArDQogIHRoZW1lX2J3KCkNCg0KIyBwZGYocGFzdGUwKGRpci5maWcsICIvIiwgY29ob3J0LCAiX3B2YWxIaXN0LnBkZiIpKQ0KaGlzdC5sb25kb24NCiNkZXYub2ZmKCkNCg0KDQpwIDwtIGdncGxvdChyZXMud2l0aC5pbmZsYXRpb24sIGFlcyhzYW1wbGUgPSBwVmFsdWUpKQ0KcCArIHN0YXRfcXEoKSArIHN0YXRfcXFfbGluZSgpDQoNCnFxUGxvdChyZXMud2l0aC5pbmZsYXRpb24kcFZhbHVlLCBjaSA9IFRSVUUsIG1haW4gPSBwYXN0ZTAoY29ob3J0LCAiIGNvaG9ydCIpKSArDQp0ZXh0KA0KICB4ID0gMC41LCANCiAgeSA9IDcuNSwNCiAgbGFiZWxzID0gYnF1b3RlKGxhbWJkYSA9PSAuKGZvcm1hdChlc3QuaW5mbGF0aW9uJGluZmxhdGlvbkZhY3RvcixkaWdpdHMgPSA0KSkpLA0KICBwb3MgPSA0DQopICsgdGV4dCgNCiAgeCA9IDAuNSwgDQogIHkgPSA2LjUsDQogbGFiZWxzID0gYnF1b3RlKGxhbWJkYVtiYWNvbl0gPT0gLihmb3JtYXQoZXN0LmluZmxhdGlvbiRlc3RpbWF0ZWRJbmZsYXRpb24sZGlnaXRzID0gNCkpKSwNCiAgcG9zID0gNA0KKQ0KcXFwbG90LmxvbmRvbiA8LSByZWNvcmRQbG90KCkNCg0KIyBTYXZlDQpwZGYocGFzdGUwKGRpci5maWcsICIvIiwgY29ob3J0LCAiX3FxUGxvdHMucGRmIikpDQpxcXBsb3QubG9uZG9uDQpkZXYub2ZmKCkNCmBgYA0KDQojIyBNVFNJTkFJDQoNCmBgYHtSLCBpbmNsdWRlID0gRkFMU0V9DQpyZXMgPC0gcmVhZC5jc3YoDQogICAgZmlsZS5wYXRoKGRpci5tdHNpbmFpLCAiTXRTaW5haV9zaW5nbGVfY3BnX3BWYWxfZGYuY3N2IikNCikNCmBgYA0KDQpgYGB7Un0NCmVzdC5pbmZsYXRpb24gPC0gZXN0aW1hdGlvbl9vZl9pbmZsYXRpb24ocmVzKQ0KcmVzLndpdGguaW5mbGF0aW9uIDwtIGVzdC5pbmZsYXRpb24kZGF0YS53aXRoLmluZmxhdGlvbg0KDQpjb2hvcnQgPC0gIk1UU0lOQUkiDQoNCndyaXRlLmNzdigNCiAgICByZXMud2l0aC5pbmZsYXRpb24sDQogICAgZmlsZS5wYXRoKGRpci5kYXRhLCBjb2hvcnQsICJzaW5nbGVfY3BnX3BWYWxfZGYuY3N2IiksDQogICAgcm93Lm5hbWVzID0gRkFMU0UNCikNCg0KIyBnZW5vbWUtd2lkZSBzaWcgY3Bncw0Kc2lnLmZkciA8LSBpZmVsc2UocmVzLndpdGguaW5mbGF0aW9uJGZkci5iYWNvbiA8IDAuMDUsIDEsIDApDQojIHRhYmxlKHNpZy5mZHIpICAgIyAwIHNpZw0KDQpgYGANCg0KYGBge1IsaW5jbHVkZSA9IEZBTFNFLCBldmFsPUZBTFNFfQ0KIyMjIDUuIFBsb3RzDQpwVmFsdWUgPC0gZGF0YS5mcmFtZSgNCiAgcFZhbHVlID0gcmVzLndpdGguaW5mbGF0aW9uJHBWYWx1ZSwNCiAgdHlwZSA9ICJwVmFsdWUiLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRikNCg0KcFZhbHVlLmJhY29uIDwtIGRhdGEuZnJhbWUoDQogIHBWYWx1ZSA9IHJlcy53aXRoLmluZmxhdGlvbiRwVmFsdWUuYmFjb24sDQogIHR5cGUgPSAicFZhbHVlLmJhY29uIiwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQpwbG90X2RmIDwtIHJiaW5kKHBWYWx1ZSwgcFZhbHVlLmJhY29uKQ0KDQoNCmhpc3QubXRzaW5haSA8LSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHBWYWx1ZSwgZmlsbCA9IHR5cGUpKSArDQogIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC4zLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9IHBhc3RlMCgiSGlzdG9ncmFtIG9mIHB2YWx1ZXMgaW4gIiwgY29ob3J0LCAiIGNvaG9ydCIpKSArDQogIHRoZW1lX2J3KCkNCg0KIyBwZGYocGFzdGUwKGRpci5maWcsICIvIiwgY29ob3J0LCAiX3B2YWxIaXN0LnBkZiIpKQ0KaGlzdC5tdHNpbmFpDQojIGRldi5vZmYoKQ0KDQoNCnFxUGxvdChyZXMud2l0aC5pbmZsYXRpb24kcFZhbHVlLCBjaSA9IFRSVUUsIG1haW4gPSBwYXN0ZTAoY29ob3J0LCAiIGNvaG9ydCIpKSArDQp0ZXh0KA0KICB4ID0gMC41LCANCiAgeSA9IDYuMiwNCiAgbGFiZWxzID0gYnF1b3RlKGxhbWJkYSA9PSAuKGZvcm1hdChlc3QuaW5mbGF0aW9uJGluZmxhdGlvbkZhY3RvcixkaWdpdHMgPSA0KSkpLA0KICBwb3MgPSA0DQopICsgdGV4dCgNCiAgeCA9IDAuNSwgDQogIHkgPSA1LjQsDQogbGFiZWxzID0gYnF1b3RlKGxhbWJkYVtiYWNvbl0gPT0gLihmb3JtYXQoZXN0LmluZmxhdGlvbiRlc3RpbWF0ZWRJbmZsYXRpb24sZGlnaXRzID0gNCkpKSwNCiAgcG9zID0gNA0KKQ0KcXFQbG90Lm10c2luYWkgPC0gcmVjb3JkUGxvdCgpDQoNCnBkZihwYXN0ZTAoZGlyLmZpZywgIi8iLCBjb2hvcnQsICJfcXFQbG90cy5wZGYiKSkNCnFxUGxvdC5tdHNpbmFpDQpkZXYub2ZmKCkNCmBgYA0KDQojIyBST1NNQVANCg0KYGBge1IsIGluY2x1ZGUgPSBGQUxTRX0NCnJlcyA8LSByZWFkLmNzdigNCiAgICBmaWxlLnBhdGgoZGlyLnJvc21hcCwgIlJPU01BUF9QRkNfc2luZ2xlX2NwZ19wVmFsX2RmLmNzdiIpDQopDQpgYGANCg0KYGBge1Igcm9zbWFwfQ0KZXN0LmluZmxhdGlvbiA8LSBlc3RpbWF0aW9uX29mX2luZmxhdGlvbihyZXMpDQpyZXMud2l0aC5pbmZsYXRpb24gPC0gZXN0LmluZmxhdGlvbiRkYXRhLndpdGguaW5mbGF0aW9uDQoNCmNvaG9ydCA8LSAiUk9TTUFQIg0KDQp3cml0ZS5jc3YoDQogICAgcmVzLndpdGguaW5mbGF0aW9uLA0KICAgIGZpbGUucGF0aChkaXIuZGF0YSwgY29ob3J0LCAic2luZ2xlX2NwZ19wVmFsX2RmLmNzdiIpLA0KICAgIHJvdy5uYW1lcyA9IEZBTFNFDQopDQoNCiMgZ2Vub21lLXdpZGUgc2lnIGNwZ3MNCnNpZy5mZHIgPC0gaWZlbHNlKHJlcy53aXRoLmluZmxhdGlvbiRmZHIuYmFjb24gPCAwLjA1LCAxLCAwKQ0KIyB0YWJsZShzaWcuZmRyKSAgICMgMzQgc2lnDQpgYGANCg0KYGBge1IsaW5jbHVkZSA9IEZBTFNFLCBldmFsPUZBTFNFfQ0KIyMjIDUuIFBsb3RzDQpwVmFsdWUgPC0gZGF0YS5mcmFtZSgNCiAgcFZhbHVlID0gcmVzLndpdGguaW5mbGF0aW9uJHBWYWx1ZSwNCiAgdHlwZSA9ICJwVmFsdWUiLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRikNCg0KcFZhbHVlLmJhY29uIDwtIGRhdGEuZnJhbWUoDQogIHBWYWx1ZSA9IHJlcy53aXRoLmluZmxhdGlvbiRwVmFsdWUuYmFjb24sDQogIHR5cGUgPSAicFZhbHVlLmJhY29uIiwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQoNCnBsb3RfZGYgPC0gcmJpbmQocFZhbHVlLCBwVmFsdWUuYmFjb24pDQoNCmhpc3Qucm9zbWFwIDwtIGdncGxvdChwbG90X2RmLCBhZXMocFZhbHVlLCBmaWxsID0gdHlwZSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWxwaGEgPSAwLjMscG9zaXRpb249ImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gcGFzdGUwKCJIaXN0b2dyYW0gb2YgcHZhbHVlcyBpbiAiLCBjb2hvcnQsICIgY29ob3J0IikpICsNCiAgdGhlbWVfYncoKQ0KDQojIHBkZihwYXN0ZTAoZGlyLmZpZywgIi8iLCBjb2hvcnQsICJfcHZhbEhpc3QucGRmIikpDQpoaXN0LnJvc21hcA0KIyBkZXYub2ZmKCkNCg0KDQpxcVBsb3QocmVzLndpdGguaW5mbGF0aW9uJHBWYWx1ZSwgY2kgPSBUUlVFLCBtYWluID0gcGFzdGUwKGNvaG9ydCwgIiBjb2hvcnQiKSkgKw0KdGV4dCgNCiAgeCA9IDAuNSwgDQogIHkgPSA5LA0KICBsYWJlbHMgPSBicXVvdGUobGFtYmRhID09IC4oZm9ybWF0KGVzdC5pbmZsYXRpb24kaW5mbGF0aW9uRmFjdG9yLGRpZ2l0cyA9IDQpKSksDQogIHBvcyA9IDQNCikgKyB0ZXh0KA0KICB4ID0gMC41LA0KICB5ID0gOCwNCiAgbGFiZWxzID0gYnF1b3RlKGxhbWJkYVtiYWNvbl0gPT0gLihmb3JtYXQoZXN0LmluZmxhdGlvbiRlc3RpbWF0ZWRJbmZsYXRpb24sZGlnaXRzID0gNCkpKSwNCiAgcG9zID0gNA0KKQ0KcXFQbG90LnJvc21hcCA8LSByZWNvcmRQbG90KCkNCg0KcGRmKHBhc3RlMChkaXIuZmlnLCAiLyIsIGNvaG9ydCwgIl9xcVBsb3RzLnBkZiIpKQ0KcXFQbG90LnJvc21hcA0KZGV2Lm9mZigpDQpgYGANCg0KDQpgYGB7UiBzaW5nbGVfY3BnX21ldGEsIGluY2x1ZGUgPSBGQUxTRSwgZXZhbCA9IEZBTFNFfQ0KIyMgU2luZ2xlLWNwZyBtZXRhDQpyZXMgPC0gcmVhZC5jc3YoDQogICAgZmlsZS5wYXRoKGRpci5tZXRhLnNpbmdsZS5jcGcsICJtZXRhX2FuYWx5c2lzX3NpbmdsZV9jcGdfZGYuY3N2IikNCikNCmBgYA0KDQpgYGB7UiwgaW5jbHVkZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9DQplc3QuaW5mbGF0aW9uIDwtIGVzdGltYXRpb25fb2ZfaW5mbGF0aW9uKHJlcykNCnJlcy53aXRoLmluZmxhdGlvbiA8LSBlc3QuaW5mbGF0aW9uJGRhdGEud2l0aC5pbmZsYXRpb24NCg0KcmVzLndpdGguaW5mbGF0aW9uIDwtIHJlcy53aXRoLmluZmxhdGlvblsNCiAgICAsYyhncmVwKCJHQVNQQVJPTkl8TVRTSU5BSXxMT05ET058Uk9TTUFQIiwgY29sbmFtZXMocmVzLndpdGguaW5mbGF0aW9uKSwgaWdub3JlLmNhc2UgPSBULCBpbnZlcnQgPSBUKSwNCiAgICAgICBncmVwKCJHQVNQQVJPTkl8TVRTSU5BSXxMT05ET058Uk9TTUFQIiwgY29sbmFtZXMocmVzLndpdGguaW5mbGF0aW9uKSwgaWdub3JlLmNhc2UgPSBULCBpbnZlcnQgPSBGKQ0KICAgICAgKV0NCndyaXRlLmNzdigNCiAgICByZXMud2l0aC5pbmZsYXRpb24sDQogICAgZmlsZS5wYXRoKGRpci5kYXRhLCAibWV0YV9hbmFseXNpc19zaW5nbGVfY3BnX2RmLmNzdiIpLA0KICAgIHJvdy5uYW1lcyA9IEZBTFNFDQopDQoNCiMgZ2Vub21lLXdpZGUgc2lnIGNwZ3MNCnNpZy5mZHIgPC0gaWZlbHNlKHJlcy53aXRoLmluZmxhdGlvbiRmZHIuYmFjb24gPCAwLjA1LCAxLCAwKQ0KIyB0YWJsZShzaWcuZmRyKSAgICMgMjQ1OSBzaWcNCmBgYA0KDQpgYGB7UiwgaW5jbHVkZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9DQojIyMgNS4gUGxvdHMNCnBWYWx1ZSA8LSBkYXRhLmZyYW1lKA0KICBwVmFsdWUgPSByZXMud2l0aC5pbmZsYXRpb24kcFZhbC5maW5hbCwNCiAgdHlwZSA9ICJwVmFsdWUiLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRikNCg0KcFZhbHVlLmJhY29uIDwtIGRhdGEuZnJhbWUoDQogIHBWYWx1ZSA9IHJlcy53aXRoLmluZmxhdGlvbiRwVmFsLmZpbmFsLmJhY29uLA0KICB0eXBlID0gInBWYWx1ZS5iYWNvbiIsDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQ0KcGxvdF9kZiA8LSByYmluZChwVmFsdWUsIHBWYWx1ZS5iYWNvbikNCg0KIyBwZGYoZmlsZS5wYXRoKGRpci5maWcsIm1ldGFfcHZhbEhpc3QucGRmIikpDQpnZ3Bsb3QocGxvdF9kZiwgYWVzKHBWYWx1ZSwgZmlsbCA9IHR5cGUpKSArDQogIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC4zLHBvc2l0aW9uPSJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgcHZhbHVlcyBpbiBtZXRhIGFuYWx5c2lzIikgKw0KICB0aGVtZV9idygpDQojIGRldi5vZmYoKQ0KDQoNCnFxcGxvdC5tZXRhIDwtIHFxUGxvdChyZXMud2l0aC5pbmZsYXRpb24kcFZhbC5maW5hbCwgY2kgPSBUUlVFLCBtYWluID0gIk1ldGEgYW5hbHlzaXMiKSArDQp0ZXh0KA0KICB4ID0gMC41LCANCiAgeSA9IDE1LA0KICBsYWJlbHMgPSBicXVvdGUobGFtYmRhID09IC4oZm9ybWF0KGVzdC5pbmZsYXRpb24kaW5mbGF0aW9uRmFjdG9yLGRpZ2l0cyA9IDQpKSksDQogIHBvcyA9IDQNCikgKyB0ZXh0KA0KICB4ID0gMC41LA0KICB5ID0gMTQsDQogbGFiZWxzID0gYnF1b3RlKGxhbWJkYVtiYWNvbl0gPT0gLihmb3JtYXQoZXN0LmluZmxhdGlvbiRlc3RpbWF0ZWRJbmZsYXRpb24sZGlnaXRzID0gNCkpKSwNCiAgcG9zID0gNA0KKQ0KcXFwbG90Lm1ldGEgPC0gcmVjb3JkUGxvdCgpDQpgYGANCg0KYGBge1IsIGV2YWwgPSBGQUxTRSwgaW5jbHVkZSA9IEZBTFNFfQ0KcGRmKGZpbGUucGF0aChkaXIuZmlnLCJtZXRhX3FxUGxvdHMucGRmIikpDQpxcXBsb3QubWV0YQ0KZGV2Lm9mZigpDQpgYGANCg0KDQpgYGB7UiBmaW5hbF9wbG90LCBpbmNsdWRlID0gRkFMU0UsIGV2YWwgPSBGQUxTRX0NCmxpYnJhcnkoY293cGxvdCkNCnNhdmUocXFQbG90LnJvc21hcCxxcXBsb3QuZ2FzcGFyb25pLHFxcGxvdC5sb25kb24scXFQbG90Lm10c2luYWksZmlsZSA9ICJxcXBsb3RzLnJkYSIpDQpwZGYoIlN1cHBsZW1lbnRhcnlfRmlndXJlXzEucGRmIix3aWR0aCA9IDksIGhlaWdodCA9IDkpDQpwbG90X2dyaWQocXFwbG90Lmdhc3Bhcm9uaSwgcXFwbG90LmxvbmRvbixxcVBsb3QubXRzaW5haSwgcXFQbG90LnJvc21hcCwgbmNvbCA9IDIsbnJvdyA9IDIsc2NhbGUgPSAwLjgpDQpkZXYub2ZmKCkNCmBgYA0KDQojIFNlc3Npb24gaW5mb3JtYXRpb24NCmBgYHtSfQ0KZGV2dG9vbHM6OnNlc3Npb25faW5mbygpDQpgYGA=