if (!require("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

BiocManager::install("DESeq2")

library(Matrix)
library(data.table)
library(dplyr)
library(DESeq2)

RNGkind("L'Ecuyer-CMRG")

data.dir = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/Data"

# ------------------------------------------------------------------------
# read in cell information
# ------------------------------------------------------------------------

cell_info = fread(file.path(data.dir, "meta_lung.tsv"), 
                  stringsAsFactors=TRUE)
dim(cell_info)
cell_info[1:2,]

read in processed count data as a single matrix

# ------------------------------------------------------------------------
# read in count data of one celltype
# ------------------------------------------------------------------------

dat = readRDS(file.path(data.dir, sprintf("ct_mtx/combinedCountMatrix.rds"))) #, grp
dim(dat)
[1]  25146 173551
class(dat)
[1] "dgCMatrix"
attr(,"package")
[1] "Matrix"
dat[1:5,1:4]
5 x 4 sparse Matrix of class "dgCMatrix"
                AAACCAAAGAACCTAT-1_1 AAACCAAAGATTGCAT-1_1 AAACCAAAGATTGCGC-1_1 AAACCAAAGGCTACTA-1_1
ENSG00000238009                    .                    .                    .                    .
ENSG00000241860                    .                    .                    .                    .
ENSG00000290385                    .                    .                    .                    .
ENSG00000291215                    .                    .                    .                    .
LINC01409                          .                    .                    .                    .
gc()
            used   (Mb) gc trigger   (Mb)   max used    (Mb)
Ncells   7520060  401.7   11612667  620.2   11612667   620.2
Vcells 879478856 6709.9 1269052289 9682.2 3738572678 28523.1

————————————————————————

subset cell information

————————————————————————


table(colnames(dat) %in% cell_info$cell)

  TRUE 
173551 
meta = cell_info[match(colnames(dat), cell_info$cell),]
dim(meta) #173551     19
[1] 173551     19
meta[1:2,]

#names(meta_cell)[11:12] = c("PMI", "RIN")
#names(meta_cell)[15:16] = c("mitoPercent", "riboPercent")
#dim(meta_cell)
#meta_cell[1:2,]

#summary(meta)
#meta_cell$age = scale(meta_cell$age)
#meta_cell$PMI = scale(meta_cell$PMI)
#meta_cell$RIN = scale(meta_cell$RIN)
#meta_cell$Capbatch = droplevels(meta_cell$Capbatch)
#meta_cell$Seqbatch = droplevels(meta_cell$Seqbatch)
#meta_cell$individual = as.factor(meta_cell$individual)

#meta_cell$age = scale(meta$Aage)

meta$subject_ID = as.factor(meta$subject_ID)

adjust certain column names in meta2kp to match the requirement

of ideas and for the ease of later processing


meta2kp <- meta

gc()
            used   (Mb) gc trigger   (Mb)   max used    (Mb)
Ncells   7519744  401.6   11612667  620.2   11612667   620.2
Vcells 879353253 6709.0 1269052289 9682.2 3738572678 28523.1

original 1b_DESeq2 does not have this section - why??


# adjust certain column names in meta2kp to match the requirement 
# of ideas and for the ease of later processing

# colnames_meta2kp = names(meta2kp)
colnames_meta2kp = names(meta2kp)
names(meta2kp)[which(colnames_meta2kp=="cell")] = "cell_id"

#names(meta2kp)[which(colnames_meta2kp=="donor")] = "individual"
names(meta2kp)[which(colnames_meta2kp=="subject_ID")] = "individual"

names(meta2kp)[which(colnames_meta2kp=="Disease")] = "diagnosis"

names(meta2kp)[which(colnames_meta2kp=="Sex")] = "sex"

names(meta2kp)[which(colnames_meta2kp=="Age")] = "age"
#'age',
meta_ind = distinct(meta2kp[,c('individual', 'diagnosis',  'age', 'sex')])
table(meta_ind$diagnosis, meta_ind$sex)
        
         Female Male
  Asthma      1    3
  Normal      1    3

————————————————————————

collect count data

————————————————————————


trec1 = matrix(NA, nrow=nrow(dat), ncol=nrow(meta_ind))
colnames(trec1) = meta_ind$subject_ID

rownames(trec1) = rownames(dat)
dim(trec1)
[1] 25146     8
trec1[1:2,1:3]
                [,1] [,2] [,3]
ENSG00000238009   NA   NA   NA
ENSG00000241860   NA   NA   NA

trec1 = matrix(NA, nrow=nrow(dat), ncol=nrow(meta_ind)) colnames(trec1) = meta_ind$subject_ID

rownames(trec1) = rownames(dat) dim(trec1) [1] 25146 8 trec1[1:2,1:3] [,1] [,2] [,3] ENSG00000238009 NA NA NA ENSG00000241860 NA NA NA

#dat$subject_ID
for(i in 1:ncol(trec1)){
  wi = which(meta2kp$individual == meta_ind$individual[i])
  #trec1[,i] = rowSums(dat1[,wi])
  trec1[,i] = rowSums(dat[,wi])
}

dim(trec1)
[1] 25146     8
trec1[1:2,1:3]
                [,1] [,2] [,3]
ENSG00000238009   51   58   49
ENSG00000241860  194  237  176

for(i in 1:ncol(trec1)){ + wi = which(meta2kp\(individual == meta_ind\)individual[i]) + #trec1[,i] = rowSums(dat1[,wi]) + trec1[,i] = rowSums(dat[,wi]) + }

dim(trec1) [1] 25146 8 trec1[1:2,1:3] [,1] [,2] [,3] ENSG00000238009 51 58 49 ENSG00000241860 194 237 176

————————————————————————

run DESeq2

————————————————————————


colData = meta_ind
colnames(colData)[2] = 'diagnosis'
# keep the age column being numeric
for(i in 1:(ncol(colData)-1)){
  if(is.character(colData[[i]])){
    colData[[i]] = as.factor(colData[[i]])
  }
}
dim(colData)
[1] 8 4
colData[1:2,]
NA

colData = meta_ind colnames(colData)[2] = ‘diagnosis’ # keep the age column being numeric for(i in 1:(ncol(colData)-1)){ + if(is.character(colData[[i]])){ + colData[[i]] = as.factor(colData[[i]]) + } + } dim(colData) [1] 8 3 colData[1:2,] individual diagnosis sex 1: N04091813 Normal Female 2: A510101913 Asthma Female


summary(colData)
      individual  diagnosis      age           sex   
 A502061813:1    Asthma:4   Min.   :11.0   Female:2  
 A504262313:1    Normal:4   1st Qu.:14.0   Male  :6  
 A507182213:1               Median :17.0             
 A510101913:1               Mean   :17.5             
 N011118413:1               3rd Qu.:22.0             
 N04091813 :1               Max.   :23.0             
 (Other)   :2                                        

summary(colData) individual diagnosis age sex
A502061813:1 Asthma:4 Min. :11.0 Female:2
A504262313:1 Normal:4 1st Qu.:14.0 Male :6
A507182213:1 Median :17.0
A510101913:1 Mean :17.5
N011118413:1 3rd Qu.:22.0
N04091813 :1 Max. :23.0
(Other) :2

#colData$diagnosis = factor(colData$diagnosis, levels=c("mild", "severe"))
colData$diagnosis = factor(colData$diagnosis, levels=c("Normal", "Asthma"))

————————————————————————

add to colData donor level covariates to adjust for

————————————————————————

total read depth across all cells under each individual


total_rd = c()

for (i in c(1:dim(meta_ind)[1])){
  wi = which(meta2kp$individual == meta_ind$individual[i])
  #wi = which(meta2kp$donor == meta_ind$donor[i])
  #total_rd = c(total_rd, sum(apply(dat1[,wi], 2, sum)))
  total_rd = c(total_rd, sum(apply(dat[,wi], 2, sum)))
}

colData$totalrd = total_rd

for (i in c(1:dim(meta_ind)[1])){ + wi = which(meta2kp\(individual == meta_ind\)individual[i]) + #wi = which(meta2kp\(donor == meta_ind\)donor[i]) + #total_rd = c(total_rd, sum(apply(dat1[,wi], 2, sum))) + total_rd = c(total_rd, sum(apply(dat[,wi], 2, sum))) + } Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 4.7 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 4.3 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 4.1 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 4.2 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 3.0 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 3.3 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 4.3 GiB Warning in asMethod(object) : sparse->dense coercion: allocating vector of size 4.6 GiB

colData$totalrd = total_rd

first, null model

rm(dat)
dd0 = DESeqDataSetFromMatrix(countData = trec1, 
                             colData = colData,
                             design = ~ diagnosis)
dd0  = DESeq(dd0)

dd0 = DESeqDataSetFromMatrix(countData = trec1, + colData = colData, + design = ~ diagnosis) Warning in S4Vectors:::anyMissing(runValue(x_seqnames)) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) Warning in S4Vectors:::anyMissing(runValue(strand(x))) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) converting counts to integer mode dd0 = DESeq(dd0) estimating size factors estimating dispersions gene-wise dispersion estimates mean-dispersion relationship final dispersion estimates fitting model and testing

dd0 = LargeDESeqDataset

res0 = results(dd0)
dim(res0)
[1] 25146     6
head(res0)
log2 fold change (MLE): diagnosis Asthma vs Normal 
Wald test p-value: diagnosis Asthma vs Normal 
DataFrame with 6 rows and 6 columns
                 baseMean log2FoldChange     lfcSE       stat    pvalue      padj
                <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
ENSG00000238009   44.5001      0.1716105  0.349439  0.4911034  0.623353   0.99998
ENSG00000241860  181.5093      0.0318759  0.281603  0.1131947  0.909876   0.99998
ENSG00000290385  161.3508     -0.0211281  0.319833 -0.0660597  0.947330   0.99998
ENSG00000291215  493.8922      0.1484186  0.250274  0.5930242  0.553165   0.99998
LINC01409       2259.0088      0.0204456  0.140824  0.1451854  0.884565   0.99998
ENSG00000290784  302.8115     -0.0585569  0.131504 -0.4452862  0.656113   0.99998
summary(res0)

out of 25146 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 14, 0.056%
LFC < 0 (down)     : 19, 0.076%
outliers [1]       : 130, 0.52%
low counts [2]     : 0, 0%
(mean count < 1)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

res0 = results(dd0) dim(res0) [1] 25146 6 head(res0) log2 fold change (MLE): diagnosis Asthma vs Normal Wald test p-value: diagnosis Asthma vs Normal DataFrame with 6 rows and 6 columns baseMean log2FoldChange lfcSE stat pvalue padj ENSG00000238009 44.5001 0.1716105 0.349439 0.4911034 0.623353 0.99998 ENSG00000241860 181.5093 0.0318759 0.281603 0.1131947 0.909876 0.99998 ENSG00000290385 161.3508 -0.0211281 0.319833 -0.0660597 0.947330 0.99998 ENSG00000291215 493.8922 0.1484186 0.250274 0.5930242 0.553165 0.99998 LINC01409 2259.0088 0.0204456 0.140824 0.1451854 0.884565 0.99998 ENSG00000290784 302.8115 -0.0585569 0.131504 -0.4452862 0.656113 0.99998 summary(res0)

out of 25146 with nonzero total read count adjusted p-value < 0.1 LFC > 0 (up) : 14, 0.056% LFC < 0 (down) : 19, 0.076% outliers [1] : 130, 0.52% low counts [2] : 0, 0% (mean count < 1) [1] see ‘cooksCutoff’ argument of ?results [2] see ‘independentFiltering’ argument of ?results

save

saveRDS(dd0, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd0.rds")
saveRDS(res0, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd0_res0.rds")
nm0 = resultsNames(dd0)
nm0

nm0 = resultsNames(dd0) nm0 [1] “Intercept” “diagnosis_Asthma_vs_Normal”

nm0 = nm0[-1]

nm0 [1] “diagnosis_Asthma_vs_Normal”

pvals0 = matrix(NA, nrow=nrow(trec1), ncol=length(nm0))

for(k in 1:length(nm0)){
  rk = results(dd0, name=nm0[k])
  pvals0[,k] = rk$pvalue
}
colnames(pvals0) = nm0
dim(pvals0)
head(pvals0)
summary(pvals0)

colnames(pvals0) = nm0 dim(pvals0) [1] 25146 1 head(pvals0) diagnosis_Asthma_vs_Normal [1,] 0.6233533 [2,] 0.9098762 [3,] 0.9473303 [4,] 0.5531649 [5,] 0.8845645 [6,] 0.6561129 summary(pvals0) diagnosis_Asthma_vs_Normal Min. :0.0000
1st Qu.:0.3147
Median :0.5727
Mean :0.5520
3rd Qu.:0.7959
Max. :1.0000
NA’s :130

second, only include donor level total read depth as covariate

what is log(totalrd) = total read depth

dd1 = DESeqDataSetFromMatrix(countData = trec1, 
                             colData = colData,
                             design = ~ log(totalrd) + diagnosis)
dd1 = DESeq(dd1)

dd1 = DESeqDataSetFromMatrix(countData = trec1, + colData = colData, + design = ~ log(totalrd) + diagnosis) Warning in S4Vectors:::anyMissing(runValue(x_seqnames)) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) Warning in S4Vectors:::anyMissing(runValue(strand(x))) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) converting counts to integer mode the design formula contains one or more numeric variables with integer values, specifying a model with increasing fold change for higher values. did you mean for this to be a factor? if so, first convert this variable to a factor using the factor() function the design formula contains one or more numeric variables that have mean or standard deviation larger than 5 (an arbitrary threshold to trigger this message). Including numeric variables with large mean can induce collinearity with the intercept. Users should center and scale numeric variables in the design to improve GLM convergence. dd1 = DESeq(dd1) estimating size factors estimating dispersions gene-wise dispersion estimates mean-dispersion relationship final dispersion estimates fitting model and testing 45 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest

res1 = results(dd1)
dim(res1)
[1] 25146     6
head(res1)
log2 fold change (MLE): diagnosis Asthma vs Normal 
Wald test p-value: diagnosis Asthma vs Normal 
DataFrame with 6 rows and 6 columns
                 baseMean log2FoldChange     lfcSE       stat    pvalue      padj
                <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
ENSG00000238009   44.5001      0.1676752 0.3947612  0.4247510  0.671018  0.999995
ENSG00000241860  181.5093      0.0552185 0.2745308  0.2011378  0.840591  0.999995
ENSG00000290385  161.3508      0.0107464 0.3420452  0.0314181  0.974936  0.999995
ENSG00000291215  493.8922      0.0799207 0.2263560  0.3530751  0.724032  0.999995
LINC01409       2259.0088     -0.0122597 0.0776207 -0.1579435  0.874501  0.999995
ENSG00000290784  302.8115     -0.0628565 0.1485842 -0.4230361  0.672269  0.999995
summary(res1)

out of 25146 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 677, 2.7%
LFC < 0 (down)     : 617, 2.5%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 1)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

res1 = results(dd1) dim(res1) [1] 25146 6 head(res1) log2 fold change (MLE): diagnosis Asthma vs Normal Wald test p-value: diagnosis Asthma vs Normal DataFrame with 6 rows and 6 columns baseMean log2FoldChange lfcSE stat pvalue padj ENSG00000238009 44.5001 0.1676752 0.3947612 0.4247510 0.671018 0.999995 ENSG00000241860 181.5093 0.0552185 0.2745308 0.2011378 0.840591 0.999995 ENSG00000290385 161.3508 0.0107464 0.3420452 0.0314181 0.974936 0.999995 ENSG00000291215 493.8922 0.0799207 0.2263560 0.3530751 0.724032 0.999995 LINC01409 2259.0088 -0.0122597 0.0776207 -0.1579435 0.874501 0.999995 ENSG00000290784 302.8115 -0.0628565 0.1485842 -0.4230361 0.672269 0.999995 summary(res1)

out of 25146 with nonzero total read count adjusted p-value < 0.1 LFC > 0 (up) : 677, 2.7% LFC < 0 (down) : 617, 2.5% outliers [1] : 0, 0% low counts [2] : 0, 0% (mean count < 1) [1] see ‘cooksCutoff’ argument of ?results [2] see ‘independentFiltering’ argument of ?results

save

saveRDS(dd1, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd1.rds")
saveRDS(res1, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd1_res1.rds")
nm1 = resultsNames(dd1)
nm1
[1] "Intercept"                  "log.totalrd."               "diagnosis_Asthma_vs_Normal"
nm1 = nm1[-1]
nm1
[1] "log.totalrd."               "diagnosis_Asthma_vs_Normal"

“log.totalrd.” “diagnosis_Asthma_vs_Normal”

pvals1 = matrix(NA, nrow=nrow(trec1), ncol=length(nm1))

for(k in 1:length(nm1)){
  rk = results(dd1, name=nm1[k])
  pvals1[,k] = rk$pvalue
}
colnames(pvals1) = nm1
dim(pvals1)
[1] 25146     2
head(pvals1)
     log.totalrd. diagnosis_Asthma_vs_Normal
[1,] 0.8532099534                  0.6710182
[2,] 0.2215338620                  0.8405908
[3,] 0.5474593215                  0.9749361
[4,] 0.1151434580                  0.7240321
[5,] 0.0002114418                  0.8745013
[6,] 0.7701444422                  0.6722689
summary(pvals1)
  log.totalrd.       diagnosis_Asthma_vs_Normal
 Min.   :3.000e-08   Min.   :0.0000            
 1st Qu.:2.740e-01   1st Qu.:0.3046            
 Median :5.582e-01   Median :0.5690            
 Mean   :5.351e-01   Mean   :0.5395            
 3rd Qu.:8.169e-01   3rd Qu.:0.7951            
 Max.   :9.999e-01   Max.   :1.0000            

colnames(pvals1) = nm1 dim(pvals1) [1] 25146 2 head(pvals1) log.totalrd. diagnosis_Asthma_vs_Normal [1,] 0.8532099534 0.6710182 [2,] 0.2215338620 0.8405908 [3,] 0.5474593215 0.9749361 [4,] 0.1151434580 0.7240321 [5,] 0.0002114418 0.8745013 [6,] 0.7701444422 0.6722689 summary(pvals1) log.totalrd. diagnosis_Asthma_vs_Normal Min. :3.000e-08 Min. :0.0000
1st Qu.:2.740e-01 1st Qu.:0.3046
Median :5.582e-01 Median :0.5690
Mean :5.351e-01 Mean :0.5395
3rd Qu.:8.169e-01 3rd Qu.:0.7951
Max. :9.999e-01 Max. :1.0000

third, include sex and age as covariates

Sex + Age + Dx


dd2 = DESeqDataSetFromMatrix(countData = trec1, 
                             colData = colData,
                             design = ~ sex + age + diagnosis)
dd2 = DESeq(dd2)

dd2 = DESeqDataSetFromMatrix(countData = trec1, + colData = colData, + design = ~ sex + age + diagnosis) Warning in S4Vectors:::anyMissing(runValue(x_seqnames)) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) Warning in S4Vectors:::anyMissing(runValue(strand(x))) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) converting counts to integer mode the design formula contains one or more numeric variables with integer values, specifying a model with increasing fold change for higher values. did you mean for this to be a factor? if so, first convert this variable to a factor using the factor() function the design formula contains one or more numeric variables that have mean or standard deviation larger than 5 (an arbitrary threshold to trigger this message). Including numeric variables with large mean can induce collinearity with the intercept. Users should center and scale numeric variables in the design to improve GLM convergence. dd2 = DESeq(dd2) estimating size factors estimating dispersions gene-wise dispersion estimates mean-dispersion relationship final dispersion estimates fitting model and testing

res2 = results(dd2)
dim(res2)
[1] 25146     6
head(res2)
log2 fold change (MLE): diagnosis Asthma vs Normal 
Wald test p-value: diagnosis Asthma vs Normal 
DataFrame with 6 rows and 6 columns
                 baseMean log2FoldChange     lfcSE       stat    pvalue      padj
                <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
ENSG00000238009   44.5001      0.1594950  0.424258  0.3759392  0.706962  0.999977
ENSG00000241860  181.5093      0.0123845  0.320962  0.0385856  0.969221  0.999977
ENSG00000290385  161.3508     -0.0213933  0.297474 -0.0719167  0.942668  0.999977
ENSG00000291215  493.8922      0.0985977  0.238604  0.4132272  0.679440  0.999977
LINC01409       2259.0088      0.0151563  0.121460  0.1247840  0.900695  0.999977
ENSG00000290784  302.8115     -0.0594934  0.146352 -0.4065089  0.684369  0.999977
summary(res2)

out of 25146 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 47, 0.19%
LFC < 0 (down)     : 53, 0.21%
outliers [1]       : 0, 0%
low counts [2]     : 1463, 5.8%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

res2 = results(dd2) dim(res2) [1] 25146 6 head(res2) log2 fold change (MLE): diagnosis Asthma vs Normal Wald test p-value: diagnosis Asthma vs Normal DataFrame with 6 rows and 6 columns baseMean log2FoldChange lfcSE stat pvalue padj ENSG00000238009 44.5001 0.1594950 0.424258 0.3759392 0.706962 0.999977 ENSG00000241860 181.5093 0.0123845 0.320962 0.0385856 0.969221 0.999977 ENSG00000290385 161.3508 -0.0213933 0.297474 -0.0719167 0.942668 0.999977 ENSG00000291215 493.8922 0.0985977 0.238604 0.4132272 0.679440 0.999977 LINC01409 2259.0088 0.0151563 0.121460 0.1247840 0.900695 0.999977 ENSG00000290784 302.8115 -0.0594934 0.146352 -0.4065089 0.684369 0.999977 summary(res2)

out of 25146 with nonzero total read count adjusted p-value < 0.1 LFC > 0 (up) : 47, 0.19% LFC < 0 (down) : 53, 0.21% outliers [1] : 0, 0% low counts [2] : 1463, 5.8% (mean count < 4) [1] see ‘cooksCutoff’ argument of ?results [2] see ‘independentFiltering’ argument of ?results

save

saveRDS(dd2, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd2.rds")
saveRDS(res2, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd2_res2.rds")
nm2 = resultsNames(dd2)
nm2
[1] "Intercept"                  "sex_Male_vs_Female"         "age"                        "diagnosis_Asthma_vs_Normal"

nm2 = resultsNames(dd2) nm2 [1] “Intercept” “sex_Male_vs_Female” “age” “diagnosis_Asthma_vs_Normal”

nm2 = nm2[-1]
nm2
[1] "sex_Male_vs_Female"         "age"                        "diagnosis_Asthma_vs_Normal"

nm2 [1] “sex_Male_vs_Female” “age” “diagnosis_Asthma_vs_Normal”

pvals2 = matrix(NA, nrow=nrow(trec1), ncol=length(nm2))

for(k in 1:length(nm2)){
  rk = results(dd2, name=nm2[k])
  pvals2[,k] = rk$pvalue
}
dim(pvals2)
[1] 25146     3
head(pvals2)
           [,1]      [,2]      [,3]
[1,] 0.54767163 0.7094586 0.7069621
[2,] 0.53425963 0.6699251 0.9692208
[3,] 0.14058974 0.5334659 0.9426682
[4,] 0.23248508 0.1610069 0.6794402
[5,] 0.05961753 0.2183867 0.9006945
[6,] 0.53383192 0.2004347 0.6843688
summary(pvals2)
       V1               V2               V3        
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.1387   1st Qu.:0.2782   1st Qu.:0.3209  
 Median :0.3938   Median :0.5191   Median :0.5694  
 Mean   :0.4228   Mean   :0.5175   Mean   :0.5457  
 3rd Qu.:0.6856   3rd Qu.:0.7708   3rd Qu.:0.7865  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  

dim(pvals2) [1] 25146 3 head(pvals2) [,1] [,2] [,3] [1,] 0.54767163 0.7094586 0.7069621 [2,] 0.53425963 0.6699251 0.9692208 [3,] 0.14058974 0.5334659 0.9426682 [4,] 0.23248508 0.1610069 0.6794402 [5,] 0.05961753 0.2183867 0.9006945 [6,] 0.53383192 0.2004347 0.6843688 summary(pvals2) V1 V2 V3
Min. :0.0000 Min. :0.0000 Min. :0.0000
1st Qu.:0.1387 1st Qu.:0.2782 1st Qu.:0.3209
Median :0.3938 Median :0.5191 Median :0.5694
Mean :0.4228 Mean :0.5175 Mean :0.5457
3rd Qu.:0.6856 3rd Qu.:0.7708 3rd Qu.:0.7865
Max. :1.0000 Max. :1.0000 Max. :1.0000

fourth, include both donor level total read depth, sex and age

Sex + Age + Dx


dd3 = DESeqDataSetFromMatrix(countData = trec1, 
                             colData = colData,
                             design = ~ log(totalrd) + sex + age + diagnosis)
dd3 = DESeq(dd3)

dd3 = DESeqDataSetFromMatrix(countData = trec1, + colData = colData, + design = ~ log(totalrd) + sex + age + diagnosis) Warning in S4Vectors:::anyMissing(runValue(x_seqnames)) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) Warning in S4Vectors:::anyMissing(runValue(strand(x))) : ‘S4Vectors:::anyMissing()’ is deprecated. Use ‘anyNA()’ instead. See help(“Deprecated”) converting counts to integer mode the design formula contains one or more numeric variables with integer values, specifying a model with increasing fold change for higher values. did you mean for this to be a factor? if so, first convert this variable to a factor using the factor() function the design formula contains one or more numeric variables that have mean or standard deviation larger than 5 (an arbitrary threshold to trigger this message). Including numeric variables with large mean can induce collinearity with the intercept. Users should center and scale numeric variables in the design to improve GLM convergence. dd3 = DESeq(dd3) estimating size factors estimating dispersions gene-wise dispersion estimates mean-dispersion relationship – note: fitType=‘parametric’, but the dispersion trend was not well captured by the function: y = a/x + b, and a local regression fit was automatically substituted. specify fitType=‘local’ or ‘mean’ to avoid this message next time. final dispersion estimates fitting model and testing 4 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest

res3 = results(dd3)
dim(res3)
[1] 25146     6
head(res3)
log2 fold change (MLE): diagnosis Asthma vs Normal 
Wald test p-value: diagnosis Asthma vs Normal 
DataFrame with 6 rows and 6 columns
                 baseMean log2FoldChange     lfcSE       stat    pvalue      padj
                <numeric>      <numeric> <numeric>  <numeric> <numeric> <numeric>
ENSG00000238009   44.5001     0.15774965 0.3873647  0.4072381  0.683833  0.999999
ENSG00000241860  181.5093     0.03811529 0.2555879  0.1491279  0.881453  0.999999
ENSG00000290385  161.3508     0.00350413 0.3019385  0.0116054  0.990740  0.999999
ENSG00000291215  493.8922     0.08072926 0.2470384  0.3267883  0.743828  0.999999
LINC01409       2259.0088    -0.00636910 0.0478966 -0.1329760  0.894212  0.999999
ENSG00000290784  302.8115    -0.04893732 0.1037474 -0.4716970  0.637143  0.999999
summary(res3)

out of 25146 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 419, 1.7%
LFC < 0 (down)     : 398, 1.6%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 1)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

res3 = results(dd3) dim(res3) [1] 25146 6 head(res3) log2 fold change (MLE): diagnosis Asthma vs Normal Wald test p-value: diagnosis Asthma vs Normal DataFrame with 6 rows and 6 columns baseMean log2FoldChange lfcSE stat pvalue padj ENSG00000238009 44.5001 0.15774965 0.3873647 0.4072381 0.683833 0.999999 ENSG00000241860 181.5093 0.03811529 0.2555879 0.1491279 0.881453 0.999999 ENSG00000290385 161.3508 0.00350413 0.3019385 0.0116054 0.990740 0.999999 ENSG00000291215 493.8922 0.08072926 0.2470384 0.3267883 0.743828 0.999999 LINC01409 2259.0088 -0.00636910 0.0478966 -0.1329760 0.894212 0.999999 ENSG00000290784 302.8115 -0.04893732 0.1037474 -0.4716970 0.637143 0.999999 summary(res3)

out of 25146 with nonzero total read count adjusted p-value < 0.1 LFC > 0 (up) : 419, 1.7% LFC < 0 (down) : 398, 1.6% outliers [1] : 0, 0% low counts [2] : 0, 0% (mean count < 1) [1] see ‘cooksCutoff’ argument of ?results [2] see ‘independentFiltering’ argument of ?results

save

saveRDS(dd3, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd3.rds")
saveRDS(res3, file = "/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/modeldd3_res3.rds")
nm3 = resultsNames(dd3)
nm3
[1] "Intercept"                  "log.totalrd."               "sex_Male_vs_Female"         "age"                        "diagnosis_Asthma_vs_Normal"

nm3 [1] “Intercept” “log.totalrd.” “sex_Male_vs_Female” “age” “diagnosis_Asthma_vs_Normal”

nm3 = nm3[-1]
nm3
[1] "log.totalrd."               "sex_Male_vs_Female"         "age"                        "diagnosis_Asthma_vs_Normal"

nm3 [1] “log.totalrd.” “sex_Male_vs_Female” “age” “diagnosis_Asthma_vs_Normal”

pvals3 = matrix(NA, nrow=nrow(trec1), ncol=length(nm3))

for(k in 1:length(nm3)){
  rk = results(dd3, name=nm3[k])
  pvals3[,k] = rk$pvalue
}
colnames(pvals3) = nm3
dim(pvals3)
[1] 25146     4
head(pvals3)
     log.totalrd. sex_Male_vs_Female        age diagnosis_Asthma_vs_Normal
[1,] 0.6596686991         0.42048228 0.92466368                  0.6838331
[2,] 0.0991147453         0.84091133 0.15748019                  0.8814527
[3,] 0.7224578509         0.29331661 0.48120531                  0.9907404
[4,] 0.5556609110         0.49513670 0.41864739                  0.7438280
[5,] 0.0001679168         0.04330512 0.51021470                  0.8942123
[6,] 0.4236755584         0.23992254 0.05113285                  0.6371431
summary(pvals3)
  log.totalrd.    sex_Male_vs_Female      age         diagnosis_Asthma_vs_Normal
 Min.   :0.0000   Min.   :0.0000     Min.   :0.0000   Min.   :0.0000            
 1st Qu.:0.3875   1st Qu.:0.2110     1st Qu.:0.2836   1st Qu.:0.3173            
 Median :0.6666   Median :0.5251     Median :0.5868   Median :0.6198            
 Mean   :0.6087   Mean   :0.5108     Mean   :0.5502   Mean   :0.5682            
 3rd Qu.:0.8753   3rd Qu.:0.8151     3rd Qu.:0.8282   3rd Qu.:0.8368            
 Max.   :0.9999   Max.   :1.0000     Max.   :1.0000   Max.   :1.0000            

colnames(pvals3) = nm3 dim(pvals3) [1] 25146 4 head(pvals3) log.totalrd. sex_Male_vs_Female age diagnosis_Asthma_vs_Normal [1,] 0.6596686991 0.42048228 0.92466368 0.6838331 [2,] 0.0991147453 0.84091133 0.15748019 0.8814527 [3,] 0.7224578509 0.29331661 0.48120531 0.9907404 [4,] 0.5556609110 0.49513670 0.41864739 0.7438280 [5,] 0.0001679168 0.04330512 0.51021470 0.8942123 [6,] 0.4236755584 0.23992254 0.05113285 0.6371431 summary(pvals3) log.totalrd. sex_Male_vs_Female age diagnosis_Asthma_vs_Normal Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.0000
1st Qu.:0.3875 1st Qu.:0.2110 1st Qu.:0.2836 1st Qu.:0.3173
Median :0.6666 Median :0.5251 Median :0.5868 Median :0.6198
Mean :0.6087 Mean :0.5108 Mean :0.5502 Mean :0.5682
3rd Qu.:0.8753 3rd Qu.:0.8151 3rd Qu.:0.8282 3rd Qu.:0.8368
Max. :0.9999 Max. :1.0000 Max. :1.0000 Max. :1.0000

results

pdf(sprintf("/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/1b_DESeq2_pval_hists.pdf"), 
    width=18, height=3.5)
par(mfrow=c(1,4), bty="n", mar=c(5,4,2,1))
k = length(nm0)
hist(pvals0[,k], main="null", xlab="p-value", breaks=50)
k = length(nm1)
hist(pvals1[,k], main="log(totalrd)", xlab="p-value", breaks=50)
k = length(nm2)
hist(pvals2[,k], main="sex+age", xlab="p-value", breaks=50)
k = length(nm3)
hist(pvals3[,k], main="log(totalrd)+sex+age", xlab="p-value", breaks=50)
dev.off()
null device 
          1 
par(mfrow=c(1,4), bty="n", mar=c(5,4,2,1))
k = length(nm0)
hist(pvals0[,k], main="null", xlab="p-value", breaks=50)
k = length(nm1)
hist(pvals1[,k], main="log(totalrd)", xlab="p-value", breaks=50)
k = length(nm2)
hist(pvals2[,k], main="sex+age", xlab="p-value", breaks=50)
k = length(nm3)
hist(pvals3[,k], main="log(totalrd)+sex+age", xlab="p-value", breaks=50)

pdf(sprintf("/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/1b_DESeq2_pval_hists_full.pdf"), 
    width=9, height=7)
par(mfrow=c(2,2), bty="n", mar=c(5,4,2,1))
for(k in 1:length(nm3)){
  hist(pvals3[,k], main=nm3[k], xlab="p-value", breaks=50)
}

dev.off()
null device 
          1 

par(mfrow=c(2,2), bty="n", mar=c(5,4,2,1))
for(k in 1:length(nm3)){
  hist(pvals3[,k], main=nm3[k], xlab="p-value", breaks=50)
}

NA
NA

————————————————————————

summarize p-value distribution

————————————————————————

pdf(sprintf("/scratch/as5916/Projects/Rutgers_asthma_smc_scSeq/res/deseq2/1b_DESeq2_compare_pval.pdf"), 
    width=9, height=3)
par(mfrow=c(1,3), bty="n", mar=c(5,4,1,1))

plot(-log10(res0$pvalue), -log10(res1$pvalue), main="-log10(p-value)", 
     xlab="null", ylab="log(totalrd)", 
     pch=20, cex=0.2, col=rgb(0.8, 0.1, 0.1, 0.5))
abline(0, 1, col="darkblue")

plot(-log10(res0$pvalue), -log10(res2$pvalue), main="-log10(p-value)", 
     xlab="null", ylab="sex+age", 
     pch=20, cex=0.2, col=rgb(0.8, 0.1, 0.1, 0.5))
abline(0, 1, col="darkblue")

plot(-log10(res0$pvalue), -log10(res3$pvalue), main="-log10(p-value)", 
     xlab="null", ylab="log(totalrd)+sex+age", 
     pch=20, cex=0.2, col=rgb(0.8, 0.1, 0.1, 0.5))
abline(0, 1, col="darkblue")

dev.off()
null device 
          1 
par(mfrow=c(1,3), bty="n", mar=c(5,4,1,1))

plot(-log10(res0$pvalue), -log10(res1$pvalue), main="-log10(p-value)", 
     xlab="null", ylab="log(totalrd)", 
     pch=20, cex=0.2, col=rgb(0.8, 0.1, 0.1, 0.5))
abline(0, 1, col="darkblue")

plot(-log10(res0$pvalue), -log10(res2$pvalue), main="-log10(p-value)", 
     xlab="null", ylab="sex+age", 
     pch=20, cex=0.2, col=rgb(0.8, 0.1, 0.1, 0.5))
abline(0, 1, col="darkblue")

plot(-log10(res0$pvalue), -log10(res3$pvalue), main="-log10(p-value)", 
     xlab="null", ylab="log(totalrd)+sex+age", 
     pch=20, cex=0.2, col=rgb(0.8, 0.1, 0.1, 0.5))
abline(0, 1, col="darkblue")

LS0tCnRpdGxlOiAiMWJfREVTZXEyX1NNIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKYGBge3J9CmlmICghcmVxdWlyZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCgpCaW9jTWFuYWdlcjo6aW5zdGFsbCgiREVTZXEyIikKCgpgYGAKCmBgYHtyfQoKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShERVNlcTIpCgpgYGAKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpgYGB7cn0KUk5Ha2luZCgiTCdFY3V5ZXItQ01SRyIpCgpkYXRhLmRpciA9ICIvc2NyYXRjaC9hczU5MTYvUHJvamVjdHMvUnV0Z2Vyc19hc3RobWFfc21jX3NjU2VxL0RhdGEiCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIHJlYWQgaW4gY2VsbCBpbmZvcm1hdGlvbgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKY2VsbF9pbmZvID0gZnJlYWQoZmlsZS5wYXRoKGRhdGEuZGlyLCAibWV0YV9sdW5nLnRzdiIpLCAKICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1UUlVFKQpkaW0oY2VsbF9pbmZvKQpjZWxsX2luZm9bMToyLF0KCmBgYAoKIyByZWFkIGluIHByb2Nlc3NlZCBjb3VudCBkYXRhIGFzIGEgc2luZ2xlIG1hdHJpeAoKCmBgYHtyfQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIHJlYWQgaW4gY291bnQgZGF0YSBvZiBvbmUgY2VsbHR5cGUKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmRhdCA9IHJlYWRSRFMoZmlsZS5wYXRoKGRhdGEuZGlyLCBzcHJpbnRmKCJjdF9tdHgvY29tYmluZWRDb3VudE1hdHJpeC5yZHMiKSkpICMsIGdycApkaW0oZGF0KQpjbGFzcyhkYXQpCmRhdFsxOjUsMTo0XQoKZ2MoKQoKYGBgCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIHN1YnNldCBjZWxsIGluZm9ybWF0aW9uCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpgYGB7cn0KCnRhYmxlKGNvbG5hbWVzKGRhdCkgJWluJSBjZWxsX2luZm8kY2VsbCkKCmBgYAoKYGBge3J9Cm1ldGEgPSBjZWxsX2luZm9bbWF0Y2goY29sbmFtZXMoZGF0KSwgY2VsbF9pbmZvJGNlbGwpLF0KZGltKG1ldGEpICMxNzM1NTEgICAgIDE5Cm1ldGFbMToyLF0KCiNuYW1lcyhtZXRhX2NlbGwpWzExOjEyXSA9IGMoIlBNSSIsICJSSU4iKQojbmFtZXMobWV0YV9jZWxsKVsxNToxNl0gPSBjKCJtaXRvUGVyY2VudCIsICJyaWJvUGVyY2VudCIpCiNkaW0obWV0YV9jZWxsKQojbWV0YV9jZWxsWzE6MixdCgpgYGAKCgpgYGB7cn0KCiNzdW1tYXJ5KG1ldGEpCiNtZXRhX2NlbGwkYWdlID0gc2NhbGUobWV0YV9jZWxsJGFnZSkKI21ldGFfY2VsbCRQTUkgPSBzY2FsZShtZXRhX2NlbGwkUE1JKQojbWV0YV9jZWxsJFJJTiA9IHNjYWxlKG1ldGFfY2VsbCRSSU4pCiNtZXRhX2NlbGwkQ2FwYmF0Y2ggPSBkcm9wbGV2ZWxzKG1ldGFfY2VsbCRDYXBiYXRjaCkKI21ldGFfY2VsbCRTZXFiYXRjaCA9IGRyb3BsZXZlbHMobWV0YV9jZWxsJFNlcWJhdGNoKQojbWV0YV9jZWxsJGluZGl2aWR1YWwgPSBhcy5mYWN0b3IobWV0YV9jZWxsJGluZGl2aWR1YWwpCgojbWV0YV9jZWxsJGFnZSA9IHNjYWxlKG1ldGEkQWFnZSkKCm1ldGEkc3ViamVjdF9JRCA9IGFzLmZhY3RvcihtZXRhJHN1YmplY3RfSUQpCgpgYGAKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIGFkanVzdCBjZXJ0YWluIGNvbHVtbiBuYW1lcyBpbiBtZXRhMmtwIHRvIG1hdGNoIHRoZSByZXF1aXJlbWVudCAKIyBvZiBpZGVhcyBhbmQgZm9yIHRoZSBlYXNlIG9mIGxhdGVyIHByb2Nlc3NpbmcKCmBgYHtyfQoKbWV0YTJrcCA8LSBtZXRhCgpnYygpCmBgYAoKIyBvcmlnaW5hbCAxYl9ERVNlcTIgZG9lcyBub3QgaGF2ZSB0aGlzIHNlY3Rpb24gLSB3aHk/PwoKYGBge3J9CgojIGFkanVzdCBjZXJ0YWluIGNvbHVtbiBuYW1lcyBpbiBtZXRhMmtwIHRvIG1hdGNoIHRoZSByZXF1aXJlbWVudCAKIyBvZiBpZGVhcyBhbmQgZm9yIHRoZSBlYXNlIG9mIGxhdGVyIHByb2Nlc3NpbmcKCiMgY29sbmFtZXNfbWV0YTJrcCA9IG5hbWVzKG1ldGEya3ApCmNvbG5hbWVzX21ldGEya3AgPSBuYW1lcyhtZXRhMmtwKQpuYW1lcyhtZXRhMmtwKVt3aGljaChjb2xuYW1lc19tZXRhMmtwPT0iY2VsbCIpXSA9ICJjZWxsX2lkIgoKI25hbWVzKG1ldGEya3ApW3doaWNoKGNvbG5hbWVzX21ldGEya3A9PSJkb25vciIpXSA9ICJpbmRpdmlkdWFsIgpuYW1lcyhtZXRhMmtwKVt3aGljaChjb2xuYW1lc19tZXRhMmtwPT0ic3ViamVjdF9JRCIpXSA9ICJpbmRpdmlkdWFsIgoKbmFtZXMobWV0YTJrcClbd2hpY2goY29sbmFtZXNfbWV0YTJrcD09IkRpc2Vhc2UiKV0gPSAiZGlhZ25vc2lzIgoKbmFtZXMobWV0YTJrcClbd2hpY2goY29sbmFtZXNfbWV0YTJrcD09IlNleCIpXSA9ICJzZXgiCgpuYW1lcyhtZXRhMmtwKVt3aGljaChjb2xuYW1lc19tZXRhMmtwPT0iQWdlIildID0gImFnZSIKCmBgYAoKYGBge3J9CiMnYWdlJywKbWV0YV9pbmQgPSBkaXN0aW5jdChtZXRhMmtwWyxjKCdpbmRpdmlkdWFsJywgJ2RpYWdub3NpcycsICAnYWdlJywgJ3NleCcpXSkKdGFibGUobWV0YV9pbmQkZGlhZ25vc2lzLCBtZXRhX2luZCRzZXgpCgpgYGAKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgY29sbGVjdCBjb3VudCBkYXRhCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpgYGB7cn0KCnRyZWMxID0gbWF0cml4KE5BLCBucm93PW5yb3coZGF0KSwgbmNvbD1ucm93KG1ldGFfaW5kKSkKY29sbmFtZXModHJlYzEpID0gbWV0YV9pbmQkc3ViamVjdF9JRAoKcm93bmFtZXModHJlYzEpID0gcm93bmFtZXMoZGF0KQpkaW0odHJlYzEpCnRyZWMxWzE6MiwxOjNdCmBgYAoKPiB0cmVjMSA9IG1hdHJpeChOQSwgbnJvdz1ucm93KGRhdCksIG5jb2w9bnJvdyhtZXRhX2luZCkpCj4gY29sbmFtZXModHJlYzEpID0gbWV0YV9pbmQkc3ViamVjdF9JRAo+IAo+IHJvd25hbWVzKHRyZWMxKSA9IHJvd25hbWVzKGRhdCkKPiBkaW0odHJlYzEpClsxXSAyNTE0NiAgICAgOAo+IHRyZWMxWzE6MiwxOjNdCiAgICAgICAgICAgICAgICBbLDFdIFssMl0gWywzXQpFTlNHMDAwMDAyMzgwMDkgICBOQSAgIE5BICAgTkEKRU5TRzAwMDAwMjQxODYwICAgTkEgICBOQSAgIE5BCgpgYGB7cn0KI2RhdCRzdWJqZWN0X0lECmZvcihpIGluIDE6bmNvbCh0cmVjMSkpewogIHdpID0gd2hpY2gobWV0YTJrcCRpbmRpdmlkdWFsID09IG1ldGFfaW5kJGluZGl2aWR1YWxbaV0pCiAgI3RyZWMxWyxpXSA9IHJvd1N1bXMoZGF0MVssd2ldKQogIHRyZWMxWyxpXSA9IHJvd1N1bXMoZGF0Wyx3aV0pCn0KCmRpbSh0cmVjMSkKdHJlYzFbMToyLDE6M10KCmBgYAoKPiBmb3IoaSBpbiAxOm5jb2wodHJlYzEpKXsKKyAgICAgd2kgPSB3aGljaChtZXRhMmtwJGluZGl2aWR1YWwgPT0gbWV0YV9pbmQkaW5kaXZpZHVhbFtpXSkKKyAgICAgI3RyZWMxWyxpXSA9IHJvd1N1bXMoZGF0MVssd2ldKQorICAgICB0cmVjMVssaV0gPSByb3dTdW1zKGRhdFssd2ldKQorIH0KPiAKPiBkaW0odHJlYzEpClsxXSAyNTE0NiAgICAgOAo+IHRyZWMxWzE6MiwxOjNdCiAgICAgICAgICAgICAgICBbLDFdIFssMl0gWywzXQpFTlNHMDAwMDAyMzgwMDkgICA1MSAgIDU4ICAgNDkKRU5TRzAwMDAwMjQxODYwICAxOTQgIDIzNyAgMTc2CgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIHJ1biBERVNlcTIKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpgYGB7cn0KCmNvbERhdGEgPSBtZXRhX2luZApjb2xuYW1lcyhjb2xEYXRhKVsyXSA9ICdkaWFnbm9zaXMnCiMga2VlcCB0aGUgYWdlIGNvbHVtbiBiZWluZyBudW1lcmljCmZvcihpIGluIDE6KG5jb2woY29sRGF0YSktMSkpewogIGlmKGlzLmNoYXJhY3Rlcihjb2xEYXRhW1tpXV0pKXsKICAgIGNvbERhdGFbW2ldXSA9IGFzLmZhY3Rvcihjb2xEYXRhW1tpXV0pCiAgfQp9CmRpbShjb2xEYXRhKQpjb2xEYXRhWzE6MixdCgpgYGAKCj4gY29sRGF0YSA9IG1ldGFfaW5kCj4gY29sbmFtZXMoY29sRGF0YSlbMl0gPSAnZGlhZ25vc2lzJwo+ICMga2VlcCB0aGUgYWdlIGNvbHVtbiBiZWluZyBudW1lcmljCj4gZm9yKGkgaW4gMToobmNvbChjb2xEYXRhKS0xKSl7CisgICAgIGlmKGlzLmNoYXJhY3Rlcihjb2xEYXRhW1tpXV0pKXsKKyAgICAgICAgIGNvbERhdGFbW2ldXSA9IGFzLmZhY3Rvcihjb2xEYXRhW1tpXV0pCisgICAgIH0KKyB9Cj4gZGltKGNvbERhdGEpClsxXSA4IDMKPiBjb2xEYXRhWzE6MixdCiAgIGluZGl2aWR1YWwgZGlhZ25vc2lzICAgIHNleAogICAgICAgPGZjdHI+ICAgIDxmY3RyPiA8ZmN0cj4KMTogIE4wNDA5MTgxMyAgICBOb3JtYWwgRmVtYWxlCjI6IEE1MTAxMDE5MTMgICAgQXN0aG1hIEZlbWFsZQoKYGBge3J9CgpzdW1tYXJ5KGNvbERhdGEpCgpgYGAKCj4gc3VtbWFyeShjb2xEYXRhKQogICAgICBpbmRpdmlkdWFsICBkaWFnbm9zaXMgICAgICBhZ2UgICAgICAgICAgIHNleCAgIAogQTUwMjA2MTgxMzoxICAgIEFzdGhtYTo0ICAgTWluLiAgIDoxMS4wICAgRmVtYWxlOjIgIAogQTUwNDI2MjMxMzoxICAgIE5vcm1hbDo0ICAgMXN0IFF1LjoxNC4wICAgTWFsZSAgOjYgIAogQTUwNzE4MjIxMzoxICAgICAgICAgICAgICAgTWVkaWFuIDoxNy4wICAgICAgICAgICAgIAogQTUxMDEwMTkxMzoxICAgICAgICAgICAgICAgTWVhbiAgIDoxNy41ICAgICAgICAgICAgIAogTjAxMTExODQxMzoxICAgICAgICAgICAgICAgM3JkIFF1LjoyMi4wICAgICAgICAgICAgIAogTjA0MDkxODEzIDoxICAgICAgICAgICAgICAgTWF4LiAgIDoyMy4wICAgICAgICAgICAgIAogKE90aGVyKSAgIDoyIAogCmBgYHtyfQojY29sRGF0YSRkaWFnbm9zaXMgPSBmYWN0b3IoY29sRGF0YSRkaWFnbm9zaXMsIGxldmVscz1jKCJtaWxkIiwgInNldmVyZSIpKQpjb2xEYXRhJGRpYWdub3NpcyA9IGZhY3Rvcihjb2xEYXRhJGRpYWdub3NpcywgbGV2ZWxzPWMoIk5vcm1hbCIsICJBc3RobWEiKSkKCgpgYGAKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgYWRkIHRvIGNvbERhdGEgZG9ub3IgbGV2ZWwgY292YXJpYXRlcyB0byBhZGp1c3QgZm9yIAojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyB0b3RhbCByZWFkIGRlcHRoIGFjcm9zcyBhbGwgY2VsbHMgdW5kZXIgZWFjaCBpbmRpdmlkdWFsCgpgYGB7cn0KCnRvdGFsX3JkID0gYygpCgpmb3IgKGkgaW4gYygxOmRpbShtZXRhX2luZClbMV0pKXsKICB3aSA9IHdoaWNoKG1ldGEya3AkaW5kaXZpZHVhbCA9PSBtZXRhX2luZCRpbmRpdmlkdWFsW2ldKQogICN3aSA9IHdoaWNoKG1ldGEya3AkZG9ub3IgPT0gbWV0YV9pbmQkZG9ub3JbaV0pCiAgI3RvdGFsX3JkID0gYyh0b3RhbF9yZCwgc3VtKGFwcGx5KGRhdDFbLHdpXSwgMiwgc3VtKSkpCiAgdG90YWxfcmQgPSBjKHRvdGFsX3JkLCBzdW0oYXBwbHkoZGF0Wyx3aV0sIDIsIHN1bSkpKQp9Cgpjb2xEYXRhJHRvdGFscmQgPSB0b3RhbF9yZAoKYGBgCgo+IGZvciAoaSBpbiBjKDE6ZGltKG1ldGFfaW5kKVsxXSkpeworICAgICB3aSA9IHdoaWNoKG1ldGEya3AkaW5kaXZpZHVhbCA9PSBtZXRhX2luZCRpbmRpdmlkdWFsW2ldKQorICAgICAjd2kgPSB3aGljaChtZXRhMmtwJGRvbm9yID09IG1ldGFfaW5kJGRvbm9yW2ldKQorICAgICAjdG90YWxfcmQgPSBjKHRvdGFsX3JkLCBzdW0oYXBwbHkoZGF0MVssd2ldLCAyLCBzdW0pKSkKKyAgICAgdG90YWxfcmQgPSBjKHRvdGFsX3JkLCBzdW0oYXBwbHkoZGF0Wyx3aV0sIDIsIHN1bSkpKQorIH0KV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDQuNyBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDQuMyBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDQuMSBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDQuMiBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDMuMCBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDMuMyBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDQuMyBHaUIKV2FybmluZyBpbiBhc01ldGhvZChvYmplY3QpIDoKICBzcGFyc2UtPmRlbnNlIGNvZXJjaW9uOiBhbGxvY2F0aW5nIHZlY3RvciBvZiBzaXplIDQuNiBHaUIKPiAKPiBjb2xEYXRhJHRvdGFscmQgPSB0b3RhbF9yZAoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBmaXJzdCwgbnVsbCBtb2RlbAoKYGBge3J9CnJtKGRhdCkKCmBgYAoKYGBge3J9CmRkMCA9IERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gdHJlYzEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gZGlhZ25vc2lzKQpkZDAgID0gREVTZXEoZGQwKQpgYGAKCj4gZGQwID0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSB0cmVjMSwgCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gY29sRGF0YSwKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gZGlhZ25vc2lzKQpXYXJuaW5nIGluIFM0VmVjdG9yczo6OmFueU1pc3NpbmcocnVuVmFsdWUoeF9zZXFuYW1lcykpIDoKICAnUzRWZWN0b3JzOjo6YW55TWlzc2luZygpJyBpcyBkZXByZWNhdGVkLgpVc2UgJ2FueU5BKCknIGluc3RlYWQuClNlZSBoZWxwKCJEZXByZWNhdGVkIikKV2FybmluZyBpbiBTNFZlY3RvcnM6OjphbnlNaXNzaW5nKHJ1blZhbHVlKHN0cmFuZCh4KSkpIDoKICAnUzRWZWN0b3JzOjo6YW55TWlzc2luZygpJyBpcyBkZXByZWNhdGVkLgpVc2UgJ2FueU5BKCknIGluc3RlYWQuClNlZSBoZWxwKCJEZXByZWNhdGVkIikKY29udmVydGluZyBjb3VudHMgdG8gaW50ZWdlciBtb2RlCj4gZGQwICA9IERFU2VxKGRkMCkKZXN0aW1hdGluZyBzaXplIGZhY3RvcnMKZXN0aW1hdGluZyBkaXNwZXJzaW9ucwpnZW5lLXdpc2UgZGlzcGVyc2lvbiBlc3RpbWF0ZXMKbWVhbi1kaXNwZXJzaW9uIHJlbGF0aW9uc2hpcApmaW5hbCBkaXNwZXJzaW9uIGVzdGltYXRlcwpmaXR0aW5nIG1vZGVsIGFuZCB0ZXN0aW5nCgpkZDAgPSBMYXJnZURFU2VxRGF0YXNldAoKYGBge3J9CnJlczAgPSByZXN1bHRzKGRkMCkKZGltKHJlczApCmhlYWQocmVzMCkKc3VtbWFyeShyZXMwKQoKYGBgCj4gcmVzMCA9IHJlc3VsdHMoZGQwKQo+IGRpbShyZXMwKQpbMV0gMjUxNDYgICAgIDYKPiBoZWFkKHJlczApCmxvZzIgZm9sZCBjaGFuZ2UgKE1MRSk6IGRpYWdub3NpcyBBc3RobWEgdnMgTm9ybWFsIApXYWxkIHRlc3QgcC12YWx1ZTogZGlhZ25vc2lzIEFzdGhtYSB2cyBOb3JtYWwgCkRhdGFGcmFtZSB3aXRoIDYgcm93cyBhbmQgNiBjb2x1bW5zCiAgICAgICAgICAgICAgICAgYmFzZU1lYW4gbG9nMkZvbGRDaGFuZ2UgICAgIGxmY1NFICAgICAgIHN0YXQgICAgcHZhbHVlICAgICAgcGFkagogICAgICAgICAgICAgICAgPG51bWVyaWM+ICAgICAgPG51bWVyaWM+IDxudW1lcmljPiAgPG51bWVyaWM+IDxudW1lcmljPiA8bnVtZXJpYz4KRU5TRzAwMDAwMjM4MDA5ICAgNDQuNTAwMSAgICAgIDAuMTcxNjEwNSAgMC4zNDk0MzkgIDAuNDkxMTAzNCAgMC42MjMzNTMgICAwLjk5OTk4CkVOU0cwMDAwMDI0MTg2MCAgMTgxLjUwOTMgICAgICAwLjAzMTg3NTkgIDAuMjgxNjAzICAwLjExMzE5NDcgIDAuOTA5ODc2ICAgMC45OTk5OApFTlNHMDAwMDAyOTAzODUgIDE2MS4zNTA4ICAgICAtMC4wMjExMjgxICAwLjMxOTgzMyAtMC4wNjYwNTk3ICAwLjk0NzMzMCAgIDAuOTk5OTgKRU5TRzAwMDAwMjkxMjE1ICA0OTMuODkyMiAgICAgIDAuMTQ4NDE4NiAgMC4yNTAyNzQgIDAuNTkzMDI0MiAgMC41NTMxNjUgICAwLjk5OTk4CkxJTkMwMTQwOSAgICAgICAyMjU5LjAwODggICAgICAwLjAyMDQ0NTYgIDAuMTQwODI0ICAwLjE0NTE4NTQgIDAuODg0NTY1ICAgMC45OTk5OApFTlNHMDAwMDAyOTA3ODQgIDMwMi44MTE1ICAgICAtMC4wNTg1NTY5ICAwLjEzMTUwNCAtMC40NDUyODYyICAwLjY1NjExMyAgIDAuOTk5OTgKPiBzdW1tYXJ5KHJlczApCgpvdXQgb2YgMjUxNDYgd2l0aCBub256ZXJvIHRvdGFsIHJlYWQgY291bnQKYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQpMRkMgPiAwICh1cCkgICAgICAgOiAxNCwgMC4wNTYlCkxGQyA8IDAgKGRvd24pICAgICA6IDE5LCAwLjA3NiUKb3V0bGllcnMgWzFdICAgICAgIDogMTMwLCAwLjUyJQpsb3cgY291bnRzIFsyXSAgICAgOiAwLCAwJQoobWVhbiBjb3VudCA8IDEpClsxXSBzZWUgJ2Nvb2tzQ3V0b2ZmJyBhcmd1bWVudCBvZiA/cmVzdWx0cwpbMl0gc2VlICdpbmRlcGVuZGVudEZpbHRlcmluZycgYXJndW1lbnQgb2YgP3Jlc3VsdHMKCiMgc2F2ZQpgYGB7cn0Kc2F2ZVJEUyhkZDAsIGZpbGUgPSAiL3NjcmF0Y2gvYXM1OTE2L1Byb2plY3RzL1J1dGdlcnNfYXN0aG1hX3NtY19zY1NlcS9yZXMvZGVzZXEyL21vZGVsZGQwLnJkcyIpCnNhdmVSRFMocmVzMCwgZmlsZSA9ICIvc2NyYXRjaC9hczU5MTYvUHJvamVjdHMvUnV0Z2Vyc19hc3RobWFfc21jX3NjU2VxL3Jlcy9kZXNlcTIvbW9kZWxkZDBfcmVzMC5yZHMiKQoKYGBgCgpgYGB7cn0Kbm0wID0gcmVzdWx0c05hbWVzKGRkMCkKbm0wCmBgYAoKPiBubTAgPSByZXN1bHRzTmFtZXMoZGQwKQo+IG5tMApbMV0gIkludGVyY2VwdCIgICAgICAgICAgICAgICAgICAiZGlhZ25vc2lzX0FzdGhtYV92c19Ob3JtYWwiCgpgYGB7cn0Kbm0wID0gbm0wWy0xXQpgYGAKPiBubTAKWzFdICJkaWFnbm9zaXNfQXN0aG1hX3ZzX05vcm1hbCIKCmBgYHtyfQpwdmFsczAgPSBtYXRyaXgoTkEsIG5yb3c9bnJvdyh0cmVjMSksIG5jb2w9bGVuZ3RoKG5tMCkpCgpmb3IoayBpbiAxOmxlbmd0aChubTApKXsKICByayA9IHJlc3VsdHMoZGQwLCBuYW1lPW5tMFtrXSkKICBwdmFsczBbLGtdID0gcmskcHZhbHVlCn0KCgpgYGAKCgpgYGB7cn0KY29sbmFtZXMocHZhbHMwKSA9IG5tMApkaW0ocHZhbHMwKQpoZWFkKHB2YWxzMCkKc3VtbWFyeShwdmFsczApCgpgYGAKCj4gY29sbmFtZXMocHZhbHMwKSA9IG5tMAo+IGRpbShwdmFsczApClsxXSAyNTE0NiAgICAgMQo+IGhlYWQocHZhbHMwKQogICAgIGRpYWdub3Npc19Bc3RobWFfdnNfTm9ybWFsClsxLF0gICAgICAgICAgICAgICAgICAwLjYyMzM1MzMKWzIsXSAgICAgICAgICAgICAgICAgIDAuOTA5ODc2MgpbMyxdICAgICAgICAgICAgICAgICAgMC45NDczMzAzCls0LF0gICAgICAgICAgICAgICAgICAwLjU1MzE2NDkKWzUsXSAgICAgICAgICAgICAgICAgIDAuODg0NTY0NQpbNixdICAgICAgICAgICAgICAgICAgMC42NTYxMTI5Cj4gc3VtbWFyeShwdmFsczApCiBkaWFnbm9zaXNfQXN0aG1hX3ZzX05vcm1hbAogTWluLiAgIDowLjAwMDAgICAgICAgICAgICAKIDFzdCBRdS46MC4zMTQ3ICAgICAgICAgICAgCiBNZWRpYW4gOjAuNTcyNyAgICAgICAgICAgIAogTWVhbiAgIDowLjU1MjAgICAgICAgICAgICAKIDNyZCBRdS46MC43OTU5ICAgICAgICAgICAgCiBNYXguICAgOjEuMDAwMCAgICAgICAgICAgIAogTkEncyAgIDoxMzAgICAgICAgCiAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBzZWNvbmQsIG9ubHkgaW5jbHVkZSBkb25vciBsZXZlbCB0b3RhbCByZWFkIGRlcHRoIGFzIGNvdmFyaWF0ZQojIHdoYXQgaXMgbG9nKHRvdGFscmQpID0gdG90YWwgcmVhZCBkZXB0aAoKYGBge3J9CmRkMSA9IERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gdHJlYzEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gbG9nKHRvdGFscmQpICsgZGlhZ25vc2lzKQpkZDEgPSBERVNlcShkZDEpCgpgYGAKPiBkZDEgPSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IHRyZWMxLCAKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xEYXRhLAorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiBsb2codG90YWxyZCkgKyBkaWFnbm9zaXMpCldhcm5pbmcgaW4gUzRWZWN0b3JzOjo6YW55TWlzc2luZyhydW5WYWx1ZSh4X3NlcW5hbWVzKSkgOgogICdTNFZlY3RvcnM6OjphbnlNaXNzaW5nKCknIGlzIGRlcHJlY2F0ZWQuClVzZSAnYW55TkEoKScgaW5zdGVhZC4KU2VlIGhlbHAoIkRlcHJlY2F0ZWQiKQpXYXJuaW5nIGluIFM0VmVjdG9yczo6OmFueU1pc3NpbmcocnVuVmFsdWUoc3RyYW5kKHgpKSkgOgogICdTNFZlY3RvcnM6OjphbnlNaXNzaW5nKCknIGlzIGRlcHJlY2F0ZWQuClVzZSAnYW55TkEoKScgaW5zdGVhZC4KU2VlIGhlbHAoIkRlcHJlY2F0ZWQiKQpjb252ZXJ0aW5nIGNvdW50cyB0byBpbnRlZ2VyIG1vZGUKICB0aGUgZGVzaWduIGZvcm11bGEgY29udGFpbnMgb25lIG9yIG1vcmUgbnVtZXJpYyB2YXJpYWJsZXMgd2l0aCBpbnRlZ2VyIHZhbHVlcywKICBzcGVjaWZ5aW5nIGEgbW9kZWwgd2l0aCBpbmNyZWFzaW5nIGZvbGQgY2hhbmdlIGZvciBoaWdoZXIgdmFsdWVzLgogIGRpZCB5b3UgbWVhbiBmb3IgdGhpcyB0byBiZSBhIGZhY3Rvcj8gaWYgc28sIGZpcnN0IGNvbnZlcnQKICB0aGlzIHZhcmlhYmxlIHRvIGEgZmFjdG9yIHVzaW5nIHRoZSBmYWN0b3IoKSBmdW5jdGlvbgogIHRoZSBkZXNpZ24gZm9ybXVsYSBjb250YWlucyBvbmUgb3IgbW9yZSBudW1lcmljIHZhcmlhYmxlcyB0aGF0IGhhdmUgbWVhbiBvcgogIHN0YW5kYXJkIGRldmlhdGlvbiBsYXJnZXIgdGhhbiA1IChhbiBhcmJpdHJhcnkgdGhyZXNob2xkIHRvIHRyaWdnZXIgdGhpcyBtZXNzYWdlKS4KICBJbmNsdWRpbmcgbnVtZXJpYyB2YXJpYWJsZXMgd2l0aCBsYXJnZSBtZWFuIGNhbiBpbmR1Y2UgY29sbGluZWFyaXR5IHdpdGggdGhlIGludGVyY2VwdC4KICBVc2VycyBzaG91bGQgY2VudGVyIGFuZCBzY2FsZSBudW1lcmljIHZhcmlhYmxlcyBpbiB0aGUgZGVzaWduIHRvIGltcHJvdmUgR0xNIGNvbnZlcmdlbmNlLgo+IGRkMSA9IERFU2VxKGRkMSkKZXN0aW1hdGluZyBzaXplIGZhY3RvcnMKZXN0aW1hdGluZyBkaXNwZXJzaW9ucwpnZW5lLXdpc2UgZGlzcGVyc2lvbiBlc3RpbWF0ZXMKbWVhbi1kaXNwZXJzaW9uIHJlbGF0aW9uc2hpcApmaW5hbCBkaXNwZXJzaW9uIGVzdGltYXRlcwpmaXR0aW5nIG1vZGVsIGFuZCB0ZXN0aW5nCjQ1IHJvd3MgZGlkIG5vdCBjb252ZXJnZSBpbiBiZXRhLCBsYWJlbGxlZCBpbiBtY29scyhvYmplY3QpJGJldGFDb252LiBVc2UgbGFyZ2VyIG1heGl0IGFyZ3VtZW50IHdpdGggbmJpbm9tV2FsZFRlc3QKCmBgYHtyfQpyZXMxID0gcmVzdWx0cyhkZDEpCmRpbShyZXMxKQpoZWFkKHJlczEpCnN1bW1hcnkocmVzMSkKCmBgYAo+IHJlczEgPSByZXN1bHRzKGRkMSkKPiBkaW0ocmVzMSkKWzFdIDI1MTQ2ICAgICA2Cj4gaGVhZChyZXMxKQpsb2cyIGZvbGQgY2hhbmdlIChNTEUpOiBkaWFnbm9zaXMgQXN0aG1hIHZzIE5vcm1hbCAKV2FsZCB0ZXN0IHAtdmFsdWU6IGRpYWdub3NpcyBBc3RobWEgdnMgTm9ybWFsIApEYXRhRnJhbWUgd2l0aCA2IHJvd3MgYW5kIDYgY29sdW1ucwogICAgICAgICAgICAgICAgIGJhc2VNZWFuIGxvZzJGb2xkQ2hhbmdlICAgICBsZmNTRSAgICAgICBzdGF0ICAgIHB2YWx1ZSAgICAgIHBhZGoKICAgICAgICAgICAgICAgIDxudW1lcmljPiAgICAgIDxudW1lcmljPiA8bnVtZXJpYz4gIDxudW1lcmljPiA8bnVtZXJpYz4gPG51bWVyaWM+CkVOU0cwMDAwMDIzODAwOSAgIDQ0LjUwMDEgICAgICAwLjE2NzY3NTIgMC4zOTQ3NjEyICAwLjQyNDc1MTAgIDAuNjcxMDE4ICAwLjk5OTk5NQpFTlNHMDAwMDAyNDE4NjAgIDE4MS41MDkzICAgICAgMC4wNTUyMTg1IDAuMjc0NTMwOCAgMC4yMDExMzc4ICAwLjg0MDU5MSAgMC45OTk5OTUKRU5TRzAwMDAwMjkwMzg1ICAxNjEuMzUwOCAgICAgIDAuMDEwNzQ2NCAwLjM0MjA0NTIgIDAuMDMxNDE4MSAgMC45NzQ5MzYgIDAuOTk5OTk1CkVOU0cwMDAwMDI5MTIxNSAgNDkzLjg5MjIgICAgICAwLjA3OTkyMDcgMC4yMjYzNTYwICAwLjM1MzA3NTEgIDAuNzI0MDMyICAwLjk5OTk5NQpMSU5DMDE0MDkgICAgICAgMjI1OS4wMDg4ICAgICAtMC4wMTIyNTk3IDAuMDc3NjIwNyAtMC4xNTc5NDM1ICAwLjg3NDUwMSAgMC45OTk5OTUKRU5TRzAwMDAwMjkwNzg0ICAzMDIuODExNSAgICAgLTAuMDYyODU2NSAwLjE0ODU4NDIgLTAuNDIzMDM2MSAgMC42NzIyNjkgIDAuOTk5OTk1Cj4gc3VtbWFyeShyZXMxKQoKb3V0IG9mIDI1MTQ2IHdpdGggbm9uemVybyB0b3RhbCByZWFkIGNvdW50CmFkanVzdGVkIHAtdmFsdWUgPCAwLjEKTEZDID4gMCAodXApICAgICAgIDogNjc3LCAyLjclCkxGQyA8IDAgKGRvd24pICAgICA6IDYxNywgMi41JQpvdXRsaWVycyBbMV0gICAgICAgOiAwLCAwJQpsb3cgY291bnRzIFsyXSAgICAgOiAwLCAwJQoobWVhbiBjb3VudCA8IDEpClsxXSBzZWUgJ2Nvb2tzQ3V0b2ZmJyBhcmd1bWVudCBvZiA/cmVzdWx0cwpbMl0gc2VlICdpbmRlcGVuZGVudEZpbHRlcmluZycgYXJndW1lbnQgb2YgP3Jlc3VsdHMKCgojIHNhdmUKYGBge3J9CnNhdmVSRFMoZGQxLCBmaWxlID0gIi9zY3JhdGNoL2FzNTkxNi9Qcm9qZWN0cy9SdXRnZXJzX2FzdGhtYV9zbWNfc2NTZXEvcmVzL2Rlc2VxMi9tb2RlbGRkMS5yZHMiKQpzYXZlUkRTKHJlczEsIGZpbGUgPSAiL3NjcmF0Y2gvYXM1OTE2L1Byb2plY3RzL1J1dGdlcnNfYXN0aG1hX3NtY19zY1NlcS9yZXMvZGVzZXEyL21vZGVsZGQxX3JlczEucmRzIikKCmBgYAoKYGBge3J9Cm5tMSA9IHJlc3VsdHNOYW1lcyhkZDEpCm5tMQpgYGAKCmBgYHtyfQpubTEgPSBubTFbLTFdCm5tMQpgYGAKICJsb2cudG90YWxyZC4iICAgICAgICAgICAgICAgImRpYWdub3Npc19Bc3RobWFfdnNfTm9ybWFsIgogCmBgYHtyfQpwdmFsczEgPSBtYXRyaXgoTkEsIG5yb3c9bnJvdyh0cmVjMSksIG5jb2w9bGVuZ3RoKG5tMSkpCgpmb3IoayBpbiAxOmxlbmd0aChubTEpKXsKICByayA9IHJlc3VsdHMoZGQxLCBuYW1lPW5tMVtrXSkKICBwdmFsczFbLGtdID0gcmskcHZhbHVlCn0KYGBgCgpgYGB7cn0KY29sbmFtZXMocHZhbHMxKSA9IG5tMQpkaW0ocHZhbHMxKQpoZWFkKHB2YWxzMSkKc3VtbWFyeShwdmFsczEpCmBgYAoKPiBjb2xuYW1lcyhwdmFsczEpID0gbm0xCj4gZGltKHB2YWxzMSkKWzFdIDI1MTQ2ICAgICAyCj4gaGVhZChwdmFsczEpCiAgICAgbG9nLnRvdGFscmQuIGRpYWdub3Npc19Bc3RobWFfdnNfTm9ybWFsClsxLF0gMC44NTMyMDk5NTM0ICAgICAgICAgICAgICAgICAgMC42NzEwMTgyClsyLF0gMC4yMjE1MzM4NjIwICAgICAgICAgICAgICAgICAgMC44NDA1OTA4ClszLF0gMC41NDc0NTkzMjE1ICAgICAgICAgICAgICAgICAgMC45NzQ5MzYxCls0LF0gMC4xMTUxNDM0NTgwICAgICAgICAgICAgICAgICAgMC43MjQwMzIxCls1LF0gMC4wMDAyMTE0NDE4ICAgICAgICAgICAgICAgICAgMC44NzQ1MDEzCls2LF0gMC43NzAxNDQ0NDIyICAgICAgICAgICAgICAgICAgMC42NzIyNjg5Cj4gc3VtbWFyeShwdmFsczEpCiAgbG9nLnRvdGFscmQuICAgICAgIGRpYWdub3Npc19Bc3RobWFfdnNfTm9ybWFsCiBNaW4uICAgOjMuMDAwZS0wOCAgIE1pbi4gICA6MC4wMDAwICAgICAgICAgICAgCiAxc3QgUXUuOjIuNzQwZS0wMSAgIDFzdCBRdS46MC4zMDQ2ICAgICAgICAgICAgCiBNZWRpYW4gOjUuNTgyZS0wMSAgIE1lZGlhbiA6MC41NjkwICAgICAgICAgICAgCiBNZWFuICAgOjUuMzUxZS0wMSAgIE1lYW4gICA6MC41Mzk1ICAgICAgICAgICAgCiAzcmQgUXUuOjguMTY5ZS0wMSAgIDNyZCBRdS46MC43OTUxICAgICAgICAgICAgCiBNYXguICAgOjkuOTk5ZS0wMSAgIE1heC4gICA6MS4wMDAwIAogCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgdGhpcmQsIGluY2x1ZGUgc2V4IGFuZCBhZ2UgYXMgY292YXJpYXRlcwojIFNleCArIEFnZSArIER4CmBgYHtyfQoKZGQyID0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSB0cmVjMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiBzZXggKyBhZ2UgKyBkaWFnbm9zaXMpCmRkMiA9IERFU2VxKGRkMikKYGBgCj4gZGQyID0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSB0cmVjMSwgCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gY29sRGF0YSwKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gc2V4ICsgYWdlICsgZGlhZ25vc2lzKQpXYXJuaW5nIGluIFM0VmVjdG9yczo6OmFueU1pc3NpbmcocnVuVmFsdWUoeF9zZXFuYW1lcykpIDoKICAnUzRWZWN0b3JzOjo6YW55TWlzc2luZygpJyBpcyBkZXByZWNhdGVkLgpVc2UgJ2FueU5BKCknIGluc3RlYWQuClNlZSBoZWxwKCJEZXByZWNhdGVkIikKV2FybmluZyBpbiBTNFZlY3RvcnM6OjphbnlNaXNzaW5nKHJ1blZhbHVlKHN0cmFuZCh4KSkpIDoKICAnUzRWZWN0b3JzOjo6YW55TWlzc2luZygpJyBpcyBkZXByZWNhdGVkLgpVc2UgJ2FueU5BKCknIGluc3RlYWQuClNlZSBoZWxwKCJEZXByZWNhdGVkIikKY29udmVydGluZyBjb3VudHMgdG8gaW50ZWdlciBtb2RlCiAgdGhlIGRlc2lnbiBmb3JtdWxhIGNvbnRhaW5zIG9uZSBvciBtb3JlIG51bWVyaWMgdmFyaWFibGVzIHdpdGggaW50ZWdlciB2YWx1ZXMsCiAgc3BlY2lmeWluZyBhIG1vZGVsIHdpdGggaW5jcmVhc2luZyBmb2xkIGNoYW5nZSBmb3IgaGlnaGVyIHZhbHVlcy4KICBkaWQgeW91IG1lYW4gZm9yIHRoaXMgdG8gYmUgYSBmYWN0b3I/IGlmIHNvLCBmaXJzdCBjb252ZXJ0CiAgdGhpcyB2YXJpYWJsZSB0byBhIGZhY3RvciB1c2luZyB0aGUgZmFjdG9yKCkgZnVuY3Rpb24KICB0aGUgZGVzaWduIGZvcm11bGEgY29udGFpbnMgb25lIG9yIG1vcmUgbnVtZXJpYyB2YXJpYWJsZXMgdGhhdCBoYXZlIG1lYW4gb3IKICBzdGFuZGFyZCBkZXZpYXRpb24gbGFyZ2VyIHRoYW4gNSAoYW4gYXJiaXRyYXJ5IHRocmVzaG9sZCB0byB0cmlnZ2VyIHRoaXMgbWVzc2FnZSkuCiAgSW5jbHVkaW5nIG51bWVyaWMgdmFyaWFibGVzIHdpdGggbGFyZ2UgbWVhbiBjYW4gaW5kdWNlIGNvbGxpbmVhcml0eSB3aXRoIHRoZSBpbnRlcmNlcHQuCiAgVXNlcnMgc2hvdWxkIGNlbnRlciBhbmQgc2NhbGUgbnVtZXJpYyB2YXJpYWJsZXMgaW4gdGhlIGRlc2lnbiB0byBpbXByb3ZlIEdMTSBjb252ZXJnZW5jZS4KPiBkZDIgPSBERVNlcShkZDIpCmVzdGltYXRpbmcgc2l6ZSBmYWN0b3JzCmVzdGltYXRpbmcgZGlzcGVyc2lvbnMKZ2VuZS13aXNlIGRpc3BlcnNpb24gZXN0aW1hdGVzCm1lYW4tZGlzcGVyc2lvbiByZWxhdGlvbnNoaXAKZmluYWwgZGlzcGVyc2lvbiBlc3RpbWF0ZXMKZml0dGluZyBtb2RlbCBhbmQgdGVzdGluZwoKYGBge3J9CnJlczIgPSByZXN1bHRzKGRkMikKZGltKHJlczIpCmhlYWQocmVzMikKc3VtbWFyeShyZXMyKQpgYGAKPiByZXMyID0gcmVzdWx0cyhkZDIpCj4gZGltKHJlczIpClsxXSAyNTE0NiAgICAgNgo+IGhlYWQocmVzMikKbG9nMiBmb2xkIGNoYW5nZSAoTUxFKTogZGlhZ25vc2lzIEFzdGhtYSB2cyBOb3JtYWwgCldhbGQgdGVzdCBwLXZhbHVlOiBkaWFnbm9zaXMgQXN0aG1hIHZzIE5vcm1hbCAKRGF0YUZyYW1lIHdpdGggNiByb3dzIGFuZCA2IGNvbHVtbnMKICAgICAgICAgICAgICAgICBiYXNlTWVhbiBsb2cyRm9sZENoYW5nZSAgICAgbGZjU0UgICAgICAgc3RhdCAgICBwdmFsdWUgICAgICBwYWRqCiAgICAgICAgICAgICAgICA8bnVtZXJpYz4gICAgICA8bnVtZXJpYz4gPG51bWVyaWM+ICA8bnVtZXJpYz4gPG51bWVyaWM+IDxudW1lcmljPgpFTlNHMDAwMDAyMzgwMDkgICA0NC41MDAxICAgICAgMC4xNTk0OTUwICAwLjQyNDI1OCAgMC4zNzU5MzkyICAwLjcwNjk2MiAgMC45OTk5NzcKRU5TRzAwMDAwMjQxODYwICAxODEuNTA5MyAgICAgIDAuMDEyMzg0NSAgMC4zMjA5NjIgIDAuMDM4NTg1NiAgMC45NjkyMjEgIDAuOTk5OTc3CkVOU0cwMDAwMDI5MDM4NSAgMTYxLjM1MDggICAgIC0wLjAyMTM5MzMgIDAuMjk3NDc0IC0wLjA3MTkxNjcgIDAuOTQyNjY4ICAwLjk5OTk3NwpFTlNHMDAwMDAyOTEyMTUgIDQ5My44OTIyICAgICAgMC4wOTg1OTc3ICAwLjIzODYwNCAgMC40MTMyMjcyICAwLjY3OTQ0MCAgMC45OTk5NzcKTElOQzAxNDA5ICAgICAgIDIyNTkuMDA4OCAgICAgIDAuMDE1MTU2MyAgMC4xMjE0NjAgIDAuMTI0Nzg0MCAgMC45MDA2OTUgIDAuOTk5OTc3CkVOU0cwMDAwMDI5MDc4NCAgMzAyLjgxMTUgICAgIC0wLjA1OTQ5MzQgIDAuMTQ2MzUyIC0wLjQwNjUwODkgIDAuNjg0MzY5ICAwLjk5OTk3Nwo+IHN1bW1hcnkocmVzMikKCm91dCBvZiAyNTE0NiB3aXRoIG5vbnplcm8gdG90YWwgcmVhZCBjb3VudAphZGp1c3RlZCBwLXZhbHVlIDwgMC4xCkxGQyA+IDAgKHVwKSAgICAgICA6IDQ3LCAwLjE5JQpMRkMgPCAwIChkb3duKSAgICAgOiA1MywgMC4yMSUKb3V0bGllcnMgWzFdICAgICAgIDogMCwgMCUKbG93IGNvdW50cyBbMl0gICAgIDogMTQ2MywgNS44JQoobWVhbiBjb3VudCA8IDQpClsxXSBzZWUgJ2Nvb2tzQ3V0b2ZmJyBhcmd1bWVudCBvZiA/cmVzdWx0cwpbMl0gc2VlICdpbmRlcGVuZGVudEZpbHRlcmluZycgYXJndW1lbnQgb2YgP3Jlc3VsdHMKCgojIHNhdmUKYGBge3J9CnNhdmVSRFMoZGQyLCBmaWxlID0gIi9zY3JhdGNoL2FzNTkxNi9Qcm9qZWN0cy9SdXRnZXJzX2FzdGhtYV9zbWNfc2NTZXEvcmVzL2Rlc2VxMi9tb2RlbGRkMi5yZHMiKQpzYXZlUkRTKHJlczIsIGZpbGUgPSAiL3NjcmF0Y2gvYXM1OTE2L1Byb2plY3RzL1J1dGdlcnNfYXN0aG1hX3NtY19zY1NlcS9yZXMvZGVzZXEyL21vZGVsZGQyX3JlczIucmRzIikKCmBgYAoKYGBge3J9Cm5tMiA9IHJlc3VsdHNOYW1lcyhkZDIpCm5tMgpgYGAKCj4gbm0yID0gcmVzdWx0c05hbWVzKGRkMikKPiBubTIKWzFdICJJbnRlcmNlcHQiICAgICAgICAgICAgICAgICAgInNleF9NYWxlX3ZzX0ZlbWFsZSIgICAgICAgICAiYWdlIiAgICAgICAgICAgICAgICAgICAgICAgICJkaWFnbm9zaXNfQXN0aG1hX3ZzX05vcm1hbCIKCmBgYHtyfQpubTIgPSBubTJbLTFdCm5tMgpgYGAKCj4gbm0yClsxXSAic2V4X01hbGVfdnNfRmVtYWxlIiAgICAgICAgICJhZ2UiICAgICAgICAgICAgICAgICAgICAgICAgImRpYWdub3Npc19Bc3RobWFfdnNfTm9ybWFsIgoKYGBge3J9CnB2YWxzMiA9IG1hdHJpeChOQSwgbnJvdz1ucm93KHRyZWMxKSwgbmNvbD1sZW5ndGgobm0yKSkKCmZvcihrIGluIDE6bGVuZ3RoKG5tMikpewogIHJrID0gcmVzdWx0cyhkZDIsIG5hbWU9bm0yW2tdKQogIHB2YWxzMlssa10gPSByayRwdmFsdWUKfQpgYGAKCmBgYHtyfQpkaW0ocHZhbHMyKQpoZWFkKHB2YWxzMikKc3VtbWFyeShwdmFsczIpCmBgYAoKPiBkaW0ocHZhbHMyKQpbMV0gMjUxNDYgICAgIDMKPiBoZWFkKHB2YWxzMikKICAgICAgICAgICBbLDFdICAgICAgWywyXSAgICAgIFssM10KWzEsXSAwLjU0NzY3MTYzIDAuNzA5NDU4NiAwLjcwNjk2MjEKWzIsXSAwLjUzNDI1OTYzIDAuNjY5OTI1MSAwLjk2OTIyMDgKWzMsXSAwLjE0MDU4OTc0IDAuNTMzNDY1OSAwLjk0MjY2ODIKWzQsXSAwLjIzMjQ4NTA4IDAuMTYxMDA2OSAwLjY3OTQ0MDIKWzUsXSAwLjA1OTYxNzUzIDAuMjE4Mzg2NyAwLjkwMDY5NDUKWzYsXSAwLjUzMzgzMTkyIDAuMjAwNDM0NyAwLjY4NDM2ODgKPiBzdW1tYXJ5KHB2YWxzMikKICAgICAgIFYxICAgICAgICAgICAgICAgVjIgICAgICAgICAgICAgICBWMyAgICAgICAgCiBNaW4uICAgOjAuMDAwMCAgIE1pbi4gICA6MC4wMDAwICAgTWluLiAgIDowLjAwMDAgIAogMXN0IFF1LjowLjEzODcgICAxc3QgUXUuOjAuMjc4MiAgIDFzdCBRdS46MC4zMjA5ICAKIE1lZGlhbiA6MC4zOTM4ICAgTWVkaWFuIDowLjUxOTEgICBNZWRpYW4gOjAuNTY5NCAgCiBNZWFuICAgOjAuNDIyOCAgIE1lYW4gICA6MC41MTc1ICAgTWVhbiAgIDowLjU0NTcgIAogM3JkIFF1LjowLjY4NTYgICAzcmQgUXUuOjAuNzcwOCAgIDNyZCBRdS46MC43ODY1ICAKIE1heC4gICA6MS4wMDAwICAgTWF4LiAgIDoxLjAwMDAgICBNYXguICAgOjEuMDAwMCAgCiAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBmb3VydGgsIGluY2x1ZGUgYm90aCBkb25vciBsZXZlbCB0b3RhbCByZWFkIGRlcHRoLCBzZXggYW5kIGFnZQojIFNleCArIEFnZSArIER4CmBgYHtyfQoKZGQzID0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSB0cmVjMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiBsb2codG90YWxyZCkgKyBzZXggKyBhZ2UgKyBkaWFnbm9zaXMpCmRkMyA9IERFU2VxKGRkMykKCmBgYAo+IGRkMyA9IERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gdHJlYzEsIAorICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbERhdGEsCisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IGxvZyh0b3RhbHJkKSArIHNleCArIGFnZSArIGRpYWdub3NpcykKV2FybmluZyBpbiBTNFZlY3RvcnM6OjphbnlNaXNzaW5nKHJ1blZhbHVlKHhfc2VxbmFtZXMpKSA6CiAgJ1M0VmVjdG9yczo6OmFueU1pc3NpbmcoKScgaXMgZGVwcmVjYXRlZC4KVXNlICdhbnlOQSgpJyBpbnN0ZWFkLgpTZWUgaGVscCgiRGVwcmVjYXRlZCIpCldhcm5pbmcgaW4gUzRWZWN0b3JzOjo6YW55TWlzc2luZyhydW5WYWx1ZShzdHJhbmQoeCkpKSA6CiAgJ1M0VmVjdG9yczo6OmFueU1pc3NpbmcoKScgaXMgZGVwcmVjYXRlZC4KVXNlICdhbnlOQSgpJyBpbnN0ZWFkLgpTZWUgaGVscCgiRGVwcmVjYXRlZCIpCmNvbnZlcnRpbmcgY291bnRzIHRvIGludGVnZXIgbW9kZQogIHRoZSBkZXNpZ24gZm9ybXVsYSBjb250YWlucyBvbmUgb3IgbW9yZSBudW1lcmljIHZhcmlhYmxlcyB3aXRoIGludGVnZXIgdmFsdWVzLAogIHNwZWNpZnlpbmcgYSBtb2RlbCB3aXRoIGluY3JlYXNpbmcgZm9sZCBjaGFuZ2UgZm9yIGhpZ2hlciB2YWx1ZXMuCiAgZGlkIHlvdSBtZWFuIGZvciB0aGlzIHRvIGJlIGEgZmFjdG9yPyBpZiBzbywgZmlyc3QgY29udmVydAogIHRoaXMgdmFyaWFibGUgdG8gYSBmYWN0b3IgdXNpbmcgdGhlIGZhY3RvcigpIGZ1bmN0aW9uCiAgdGhlIGRlc2lnbiBmb3JtdWxhIGNvbnRhaW5zIG9uZSBvciBtb3JlIG51bWVyaWMgdmFyaWFibGVzIHRoYXQgaGF2ZSBtZWFuIG9yCiAgc3RhbmRhcmQgZGV2aWF0aW9uIGxhcmdlciB0aGFuIDUgKGFuIGFyYml0cmFyeSB0aHJlc2hvbGQgdG8gdHJpZ2dlciB0aGlzIG1lc3NhZ2UpLgogIEluY2x1ZGluZyBudW1lcmljIHZhcmlhYmxlcyB3aXRoIGxhcmdlIG1lYW4gY2FuIGluZHVjZSBjb2xsaW5lYXJpdHkgd2l0aCB0aGUgaW50ZXJjZXB0LgogIFVzZXJzIHNob3VsZCBjZW50ZXIgYW5kIHNjYWxlIG51bWVyaWMgdmFyaWFibGVzIGluIHRoZSBkZXNpZ24gdG8gaW1wcm92ZSBHTE0gY29udmVyZ2VuY2UuCj4gZGQzID0gREVTZXEoZGQzKQplc3RpbWF0aW5nIHNpemUgZmFjdG9ycwplc3RpbWF0aW5nIGRpc3BlcnNpb25zCmdlbmUtd2lzZSBkaXNwZXJzaW9uIGVzdGltYXRlcwptZWFuLWRpc3BlcnNpb24gcmVsYXRpb25zaGlwCi0tIG5vdGU6IGZpdFR5cGU9J3BhcmFtZXRyaWMnLCBidXQgdGhlIGRpc3BlcnNpb24gdHJlbmQgd2FzIG5vdCB3ZWxsIGNhcHR1cmVkIGJ5IHRoZQogICBmdW5jdGlvbjogeSA9IGEveCArIGIsIGFuZCBhIGxvY2FsIHJlZ3Jlc3Npb24gZml0IHdhcyBhdXRvbWF0aWNhbGx5IHN1YnN0aXR1dGVkLgogICBzcGVjaWZ5IGZpdFR5cGU9J2xvY2FsJyBvciAnbWVhbicgdG8gYXZvaWQgdGhpcyBtZXNzYWdlIG5leHQgdGltZS4KZmluYWwgZGlzcGVyc2lvbiBlc3RpbWF0ZXMKZml0dGluZyBtb2RlbCBhbmQgdGVzdGluZwo0IHJvd3MgZGlkIG5vdCBjb252ZXJnZSBpbiBiZXRhLCBsYWJlbGxlZCBpbiBtY29scyhvYmplY3QpJGJldGFDb252LiBVc2UgbGFyZ2VyIG1heGl0IGFyZ3VtZW50IHdpdGggbmJpbm9tV2FsZFRlc3QKCgpgYGB7cn0KcmVzMyA9IHJlc3VsdHMoZGQzKQpkaW0ocmVzMykKaGVhZChyZXMzKQpzdW1tYXJ5KHJlczMpCmBgYAo+IHJlczMgPSByZXN1bHRzKGRkMykKPiBkaW0ocmVzMykKWzFdIDI1MTQ2ICAgICA2Cj4gaGVhZChyZXMzKQpsb2cyIGZvbGQgY2hhbmdlIChNTEUpOiBkaWFnbm9zaXMgQXN0aG1hIHZzIE5vcm1hbCAKV2FsZCB0ZXN0IHAtdmFsdWU6IGRpYWdub3NpcyBBc3RobWEgdnMgTm9ybWFsIApEYXRhRnJhbWUgd2l0aCA2IHJvd3MgYW5kIDYgY29sdW1ucwogICAgICAgICAgICAgICAgIGJhc2VNZWFuIGxvZzJGb2xkQ2hhbmdlICAgICBsZmNTRSAgICAgICBzdGF0ICAgIHB2YWx1ZSAgICAgIHBhZGoKICAgICAgICAgICAgICAgIDxudW1lcmljPiAgICAgIDxudW1lcmljPiA8bnVtZXJpYz4gIDxudW1lcmljPiA8bnVtZXJpYz4gPG51bWVyaWM+CkVOU0cwMDAwMDIzODAwOSAgIDQ0LjUwMDEgICAgIDAuMTU3NzQ5NjUgMC4zODczNjQ3ICAwLjQwNzIzODEgIDAuNjgzODMzICAwLjk5OTk5OQpFTlNHMDAwMDAyNDE4NjAgIDE4MS41MDkzICAgICAwLjAzODExNTI5IDAuMjU1NTg3OSAgMC4xNDkxMjc5ICAwLjg4MTQ1MyAgMC45OTk5OTkKRU5TRzAwMDAwMjkwMzg1ICAxNjEuMzUwOCAgICAgMC4wMDM1MDQxMyAwLjMwMTkzODUgIDAuMDExNjA1NCAgMC45OTA3NDAgIDAuOTk5OTk5CkVOU0cwMDAwMDI5MTIxNSAgNDkzLjg5MjIgICAgIDAuMDgwNzI5MjYgMC4yNDcwMzg0ICAwLjMyNjc4ODMgIDAuNzQzODI4ICAwLjk5OTk5OQpMSU5DMDE0MDkgICAgICAgMjI1OS4wMDg4ICAgIC0wLjAwNjM2OTEwIDAuMDQ3ODk2NiAtMC4xMzI5NzYwICAwLjg5NDIxMiAgMC45OTk5OTkKRU5TRzAwMDAwMjkwNzg0ICAzMDIuODExNSAgICAtMC4wNDg5MzczMiAwLjEwMzc0NzQgLTAuNDcxNjk3MCAgMC42MzcxNDMgIDAuOTk5OTk5Cj4gc3VtbWFyeShyZXMzKQoKb3V0IG9mIDI1MTQ2IHdpdGggbm9uemVybyB0b3RhbCByZWFkIGNvdW50CmFkanVzdGVkIHAtdmFsdWUgPCAwLjEKTEZDID4gMCAodXApICAgICAgIDogNDE5LCAxLjclCkxGQyA8IDAgKGRvd24pICAgICA6IDM5OCwgMS42JQpvdXRsaWVycyBbMV0gICAgICAgOiAwLCAwJQpsb3cgY291bnRzIFsyXSAgICAgOiAwLCAwJQoobWVhbiBjb3VudCA8IDEpClsxXSBzZWUgJ2Nvb2tzQ3V0b2ZmJyBhcmd1bWVudCBvZiA/cmVzdWx0cwpbMl0gc2VlICdpbmRlcGVuZGVudEZpbHRlcmluZycgYXJndW1lbnQgb2YgP3Jlc3VsdHMKCiMgc2F2ZQpgYGB7cn0Kc2F2ZVJEUyhkZDMsIGZpbGUgPSAiL3NjcmF0Y2gvYXM1OTE2L1Byb2plY3RzL1J1dGdlcnNfYXN0aG1hX3NtY19zY1NlcS9yZXMvZGVzZXEyL21vZGVsZGQzLnJkcyIpCnNhdmVSRFMocmVzMywgZmlsZSA9ICIvc2NyYXRjaC9hczU5MTYvUHJvamVjdHMvUnV0Z2Vyc19hc3RobWFfc21jX3NjU2VxL3Jlcy9kZXNlcTIvbW9kZWxkZDNfcmVzMy5yZHMiKQoKYGBgCgoKYGBge3J9Cm5tMyA9IHJlc3VsdHNOYW1lcyhkZDMpCm5tMwpgYGAKCj4gbm0zClsxXSAiSW50ZXJjZXB0IiAgICAgICAgICAgICAgICAgICJsb2cudG90YWxyZC4iICAgICAgICAgICAgICAgInNleF9NYWxlX3ZzX0ZlbWFsZSIgICAgICAgICAiYWdlIiAgICAgICAgICAgICAgICAgICAgICAgICJkaWFnbm9zaXNfQXN0aG1hX3ZzX05vcm1hbCIKCmBgYHtyfQpubTMgPSBubTNbLTFdCm5tMwpgYGAKCj4gbm0zClsxXSAibG9nLnRvdGFscmQuIiAgICAgICAgICAgICAgICJzZXhfTWFsZV92c19GZW1hbGUiICAgICAgICAgImFnZSIgICAgICAgICAgICAgICAgICAgICAgICAiZGlhZ25vc2lzX0FzdGhtYV92c19Ob3JtYWwiCgpgYGB7cn0KcHZhbHMzID0gbWF0cml4KE5BLCBucm93PW5yb3codHJlYzEpLCBuY29sPWxlbmd0aChubTMpKQoKZm9yKGsgaW4gMTpsZW5ndGgobm0zKSl7CiAgcmsgPSByZXN1bHRzKGRkMywgbmFtZT1ubTNba10pCiAgcHZhbHMzWyxrXSA9IHJrJHB2YWx1ZQp9CgpgYGAKCgpgYGB7cn0KY29sbmFtZXMocHZhbHMzKSA9IG5tMwpkaW0ocHZhbHMzKQpoZWFkKHB2YWxzMykKc3VtbWFyeShwdmFsczMpCgpgYGAKCj4gY29sbmFtZXMocHZhbHMzKSA9IG5tMwo+IGRpbShwdmFsczMpClsxXSAyNTE0NiAgICAgNAo+IGhlYWQocHZhbHMzKQogICAgIGxvZy50b3RhbHJkLiBzZXhfTWFsZV92c19GZW1hbGUgICAgICAgIGFnZSBkaWFnbm9zaXNfQXN0aG1hX3ZzX05vcm1hbApbMSxdIDAuNjU5NjY4Njk5MSAgICAgICAgIDAuNDIwNDgyMjggMC45MjQ2NjM2OCAgICAgICAgICAgICAgICAgIDAuNjgzODMzMQpbMixdIDAuMDk5MTE0NzQ1MyAgICAgICAgIDAuODQwOTExMzMgMC4xNTc0ODAxOSAgICAgICAgICAgICAgICAgIDAuODgxNDUyNwpbMyxdIDAuNzIyNDU3ODUwOSAgICAgICAgIDAuMjkzMzE2NjEgMC40ODEyMDUzMSAgICAgICAgICAgICAgICAgIDAuOTkwNzQwNApbNCxdIDAuNTU1NjYwOTExMCAgICAgICAgIDAuNDk1MTM2NzAgMC40MTg2NDczOSAgICAgICAgICAgICAgICAgIDAuNzQzODI4MApbNSxdIDAuMDAwMTY3OTE2OCAgICAgICAgIDAuMDQzMzA1MTIgMC41MTAyMTQ3MCAgICAgICAgICAgICAgICAgIDAuODk0MjEyMwpbNixdIDAuNDIzNjc1NTU4NCAgICAgICAgIDAuMjM5OTIyNTQgMC4wNTExMzI4NSAgICAgICAgICAgICAgICAgIDAuNjM3MTQzMQo+IHN1bW1hcnkocHZhbHMzKQogIGxvZy50b3RhbHJkLiAgICBzZXhfTWFsZV92c19GZW1hbGUgICAgICBhZ2UgICAgICAgICBkaWFnbm9zaXNfQXN0aG1hX3ZzX05vcm1hbAogTWluLiAgIDowLjAwMDAgICBNaW4uICAgOjAuMDAwMCAgICAgTWluLiAgIDowLjAwMDAgICBNaW4uICAgOjAuMDAwMCAgICAgICAgICAgIAogMXN0IFF1LjowLjM4NzUgICAxc3QgUXUuOjAuMjExMCAgICAgMXN0IFF1LjowLjI4MzYgICAxc3QgUXUuOjAuMzE3MyAgICAgICAgICAgIAogTWVkaWFuIDowLjY2NjYgICBNZWRpYW4gOjAuNTI1MSAgICAgTWVkaWFuIDowLjU4NjggICBNZWRpYW4gOjAuNjE5OCAgICAgICAgICAgIAogTWVhbiAgIDowLjYwODcgICBNZWFuICAgOjAuNTEwOCAgICAgTWVhbiAgIDowLjU1MDIgICBNZWFuICAgOjAuNTY4MiAgICAgICAgICAgIAogM3JkIFF1LjowLjg3NTMgICAzcmQgUXUuOjAuODE1MSAgICAgM3JkIFF1LjowLjgyODIgICAzcmQgUXUuOjAuODM2OCAgICAgICAgICAgIAogTWF4LiAgIDowLjk5OTkgICBNYXguICAgOjEuMDAwMCAgICAgTWF4LiAgIDoxLjAwMDAgICBNYXguICAgOjEuMDAwMCAgICAgICAgICAgIAo+IAoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyByZXN1bHRzCgpgYGB7cn0KcGRmKHNwcmludGYoIi9zY3JhdGNoL2FzNTkxNi9Qcm9qZWN0cy9SdXRnZXJzX2FzdGhtYV9zbWNfc2NTZXEvcmVzL2Rlc2VxMi8xYl9ERVNlcTJfcHZhbF9oaXN0cy5wZGYiKSwgCiAgICB3aWR0aD0xOCwgaGVpZ2h0PTMuNSkKcGFyKG1mcm93PWMoMSw0KSwgYnR5PSJuIiwgbWFyPWMoNSw0LDIsMSkpCmsgPSBsZW5ndGgobm0wKQpoaXN0KHB2YWxzMFssa10sIG1haW49Im51bGwiLCB4bGFiPSJwLXZhbHVlIiwgYnJlYWtzPTUwKQprID0gbGVuZ3RoKG5tMSkKaGlzdChwdmFsczFbLGtdLCBtYWluPSJsb2codG90YWxyZCkiLCB4bGFiPSJwLXZhbHVlIiwgYnJlYWtzPTUwKWNkY2QKayA9IGxlbmd0aChubTIpCmhpc3QocHZhbHMyWyxrXSwgbWFpbj0ic2V4K2FnZSIsIHhsYWI9InAtdmFsdWUiLCBicmVha3M9NTApCmsgPSBsZW5ndGgobm0zKQpoaXN0KHB2YWxzM1ssa10sIG1haW49ImxvZyh0b3RhbHJkKStzZXgrYWdlIiwgeGxhYj0icC12YWx1ZSIsIGJyZWFrcz01MCkKZGV2Lm9mZigpCmBgYAoKYGBge3J9CnBhcihtZnJvdz1jKDEsNCksIGJ0eT0ibiIsIG1hcj1jKDUsNCwyLDEpKQprID0gbGVuZ3RoKG5tMCkKaGlzdChwdmFsczBbLGtdLCBtYWluPSJudWxsIiwgeGxhYj0icC12YWx1ZSIsIGJyZWFrcz01MCkKayA9IGxlbmd0aChubTEpCmhpc3QocHZhbHMxWyxrXSwgbWFpbj0ibG9nKHRvdGFscmQpIiwgeGxhYj0icC12YWx1ZSIsIGJyZWFrcz01MCkKayA9IGxlbmd0aChubTIpCmhpc3QocHZhbHMyWyxrXSwgbWFpbj0ic2V4K2FnZSIsIHhsYWI9InAtdmFsdWUiLCBicmVha3M9NTApCmsgPSBsZW5ndGgobm0zKQpoaXN0KHB2YWxzM1ssa10sIG1haW49ImxvZyh0b3RhbHJkKStzZXgrYWdlIiwgeGxhYj0icC12YWx1ZSIsIGJyZWFrcz01MCkKYGBgCgpgYGB7cn0KcGRmKHNwcmludGYoIi9zY3JhdGNoL2FzNTkxNi9Qcm9qZWN0cy9SdXRnZXJzX2FzdGhtYV9zbWNfc2NTZXEvcmVzL2Rlc2VxMi8xYl9ERVNlcTJfcHZhbF9oaXN0c19mdWxsLnBkZiIpLCAKICAgIHdpZHRoPTksIGhlaWdodD03KQpwYXIobWZyb3c9YygyLDIpLCBidHk9Im4iLCBtYXI9Yyg1LDQsMiwxKSkKZm9yKGsgaW4gMTpsZW5ndGgobm0zKSl7CiAgaGlzdChwdmFsczNbLGtdLCBtYWluPW5tM1trXSwgeGxhYj0icC12YWx1ZSIsIGJyZWFrcz01MCkKfQoKZGV2Lm9mZigpCgpgYGAKCgpgYGB7cn0KCnBhcihtZnJvdz1jKDIsMiksIGJ0eT0ibiIsIG1hcj1jKDUsNCwyLDEpKQpmb3IoayBpbiAxOmxlbmd0aChubTMpKXsKICBoaXN0KHB2YWxzM1ssa10sIG1haW49bm0zW2tdLCB4bGFiPSJwLXZhbHVlIiwgYnJlYWtzPTUwKQp9CgoKYGBgCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIHN1bW1hcml6ZSBwLXZhbHVlIGRpc3RyaWJ1dGlvbgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCmBgYHtyfQpwZGYoc3ByaW50ZigiL3NjcmF0Y2gvYXM1OTE2L1Byb2plY3RzL1J1dGdlcnNfYXN0aG1hX3NtY19zY1NlcS9yZXMvZGVzZXEyLzFiX0RFU2VxMl9jb21wYXJlX3B2YWwucGRmIiksIAogICAgd2lkdGg9OSwgaGVpZ2h0PTMpCnBhcihtZnJvdz1jKDEsMyksIGJ0eT0ibiIsIG1hcj1jKDUsNCwxLDEpKQoKcGxvdCgtbG9nMTAocmVzMCRwdmFsdWUpLCAtbG9nMTAocmVzMSRwdmFsdWUpLCBtYWluPSItbG9nMTAocC12YWx1ZSkiLCAKICAgICB4bGFiPSJudWxsIiwgeWxhYj0ibG9nKHRvdGFscmQpIiwgCiAgICAgcGNoPTIwLCBjZXg9MC4yLCBjb2w9cmdiKDAuOCwgMC4xLCAwLjEsIDAuNSkpCmFibGluZSgwLCAxLCBjb2w9ImRhcmtibHVlIikKCnBsb3QoLWxvZzEwKHJlczAkcHZhbHVlKSwgLWxvZzEwKHJlczIkcHZhbHVlKSwgbWFpbj0iLWxvZzEwKHAtdmFsdWUpIiwgCiAgICAgeGxhYj0ibnVsbCIsIHlsYWI9InNleCthZ2UiLCAKICAgICBwY2g9MjAsIGNleD0wLjIsIGNvbD1yZ2IoMC44LCAwLjEsIDAuMSwgMC41KSkKYWJsaW5lKDAsIDEsIGNvbD0iZGFya2JsdWUiKQoKcGxvdCgtbG9nMTAocmVzMCRwdmFsdWUpLCAtbG9nMTAocmVzMyRwdmFsdWUpLCBtYWluPSItbG9nMTAocC12YWx1ZSkiLCAKICAgICB4bGFiPSJudWxsIiwgeWxhYj0ibG9nKHRvdGFscmQpK3NleCthZ2UiLCAKICAgICBwY2g9MjAsIGNleD0wLjIsIGNvbD1yZ2IoMC44LCAwLjEsIDAuMSwgMC41KSkKYWJsaW5lKDAsIDEsIGNvbD0iZGFya2JsdWUiKQoKZGV2Lm9mZigpCgoKCmBgYAoKYGBge3J9CnBhcihtZnJvdz1jKDEsMyksIGJ0eT0ibiIsIG1hcj1jKDUsNCwxLDEpKQoKcGxvdCgtbG9nMTAocmVzMCRwdmFsdWUpLCAtbG9nMTAocmVzMSRwdmFsdWUpLCBtYWluPSItbG9nMTAocC12YWx1ZSkiLCAKICAgICB4bGFiPSJudWxsIiwgeWxhYj0ibG9nKHRvdGFscmQpIiwgCiAgICAgcGNoPTIwLCBjZXg9MC4yLCBjb2w9cmdiKDAuOCwgMC4xLCAwLjEsIDAuNSkpCmFibGluZSgwLCAxLCBjb2w9ImRhcmtibHVlIikKCnBsb3QoLWxvZzEwKHJlczAkcHZhbHVlKSwgLWxvZzEwKHJlczIkcHZhbHVlKSwgbWFpbj0iLWxvZzEwKHAtdmFsdWUpIiwgCiAgICAgeGxhYj0ibnVsbCIsIHlsYWI9InNleCthZ2UiLCAKICAgICBwY2g9MjAsIGNleD0wLjIsIGNvbD1yZ2IoMC44LCAwLjEsIDAuMSwgMC41KSkKYWJsaW5lKDAsIDEsIGNvbD0iZGFya2JsdWUiKQoKcGxvdCgtbG9nMTAocmVzMCRwdmFsdWUpLCAtbG9nMTAocmVzMyRwdmFsdWUpLCBtYWluPSItbG9nMTAocC12YWx1ZSkiLCAKICAgICB4bGFiPSJudWxsIiwgeWxhYj0ibG9nKHRvdGFscmQpK3NleCthZ2UiLCAKICAgICBwY2g9MjAsIGNleD0wLjIsIGNvbD1yZ2IoMC44LCAwLjEsIDAuMSwgMC41KSkKYWJsaW5lKDAsIDEsIGNvbD0iZGFya2JsdWUiKQpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQoKYGBgCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAK