Description of dataset

Our data comes from an investigation of CD4+ T-cell differentiation. This study examined differences in the differentiation of Tfh and Th1 T-helper cells in the presence and absence of Aiolos. The data set originally had 12 samples composed of 4 treatments with 3 replications per treatment. There were 6 samples grown in Tfh polarizing conditions and 6 in Th1 polarizing conditions. The Th1-Ikzf3-02 sample was removed prior to running the nf-core/rnaseq pipeline due to unresolvable issues with files related to that sample. Subsequent analyses comparing differential expression between wild-type and aiolos deficient cells were performed only on the 6 samples in Tfh-polarizing conditions.

GEO accession number

GSE203065

Reference genome

mm10

Citation

Read, K. A., Jones, D. M., Pokhrel, S., Hales, E. D. S., Varkey, A., Tuazon, J. A., Eisele, C. D., Abdouni, O., Saadey, A., Leonard, M. R., Warren, R. T., Powell, M. D., Boss, J. M., Hemann, E. A., Yount, J. S., Xin, G., Ghoneim, H. E., Lio, C. J., Freud, A. G., Collins, P. L., … Oestreich, K. J. (2023). Aiolos represses CD4+ T cell cytotoxic programming via reciprocal regulation of TFH transcription factors and IL-2 sensitivity. Nature communications, 14(1), 1652. https://doi.org/10.1038/s41467-023-37420-0

Analysis

Libraries loaded

Loading the packages required for subsequent analyses.

# loading required packages 
pacman::p_load(DESeq2, dplyr, tidyr, ggplot2, genekitr, pheatmap, RColorBrewer, EnhancedVolcano, clusterProfiler, DOSE, ggnewscale, enrichplot, knitr, cowplot, msigdbr, pathview, patchwork, ggplotify)

DESeq Analysis

Reading in our un-normalized counts matrix

The input file for our DESeq analysis was the un-normalised count matrix.

# load count matrix
counts <- read.table("salmon/salmon.merged.gene_counts.tsv", header = T)

# keep gene_id col as names of rows 
row.names(counts) <- counts$gene_id

# preview counts matrix with all samples 
head(counts)

# create separate counts matrix for Tfh samples only
counts_tfh <- counts |>
  dplyr::select(3:8) |> 
  round()

# preview to make sure as expected
head(counts_tfh)

Coldata object

We now need to create a coldata object with treatment and replicate information in order to make the dds object.

# treatment vector for coldata df
treatment <- 
  rep(c("WT","KO"), 3) |>
  factor() |>
  sort()

# replicate vector for coldata df
replicate <- rep(c(1,2,3), 2) |>
  factor()

# coldata to create dds object 
coldata <- data.frame(treatment, replicate)

Creating the dds object

# create the dds object
dds <- DESeqDataSetFromMatrix(countData = counts_tfh,
                              colData = coldata,
                              design = ~ treatment)

Filtering the dds object by counts

# filtering dds, keep rows with at least 10 reads total
keep <- dds |>
  counts() |>
  rowSums() >= 10

dds <- dds[keep,]

# re-level the treatment variable to make wild type the reference 
dds$treatment <- 
  dds$treatment |>
  relevel(ref = "WT")

Using filtered dds object to perform DESeq analysis

# DESeq analysis
dds <- dds |>
  DESeq()

# extract results from DESeq 
res <- dds |>
  results(contrast = c("treatment",
                        "KO",
                        "WT"))

res |>
  dim() # 20531 x 6 
[1] 20531     6
# order results from smallest to largest p-adjusted value 
result <- res[res$padj |>
  order(), ]

head(result)
log2 fold change (MLE): treatment KO vs WT 
Wald test p-value: treatment KO vs WT 
DataFrame with 6 rows and 6 columns
                       baseMean log2FoldChange     lfcSE      stat       pvalue         padj
                      <numeric>      <numeric> <numeric> <numeric>    <numeric>    <numeric>
ENSMUSG00000020143.16  5858.095       -2.72621 0.0677903  -40.2154  0.00000e+00  0.00000e+00
ENSMUSG00000004105.9   8816.018       -1.02557 0.0397834  -25.7788 1.53385e-146 1.08558e-142
ENSMUSG00000049109.16  2812.993        1.84731 0.0754677   24.4782 2.52451e-132 1.19115e-128
ENSMUSG00000032053.9   4909.934       -1.22529 0.0505739  -24.2277 1.13541e-129 4.01792e-126
ENSMUSG00000031765.9   1539.002        2.03377 0.0917571   22.1648 7.51775e-109 2.12828e-105
ENSMUSG00000023132.9    348.358        5.10500 0.2385279   21.4021 1.27692e-101  3.01247e-98
# number significant/non-significant padj, alpha = .05
(result$padj < .05) |>
  table()

FALSE  TRUE 
11096  3059 
# merge the result object and counts data frame 
resdata <- merge(as.data.frame(result),
                  as.data.frame(counts(dds, normalized = T)),
                  by = "row.names",
                  sort = F)

names(resdata)[1] <- "Gene_id"
head(resdata)

# write resdata to file called unfiltered results 
resdata |>
  write.csv(file = "Tfh_KOvsWT_unfiltered_matrix.csv")
# get up/down DEG lists 
resdata <- as.data.frame(result) |>
  dplyr::filter(abs(log2FoldChange) > 1 & padj < 0.05) |> 
  tibble::rownames_to_column("Gene_id")

head(resdata)

# save to file DEG list file 
write.csv(resdata, "Tfh_KOvsWT_log2fc1_fdr05_DEGlist.csv", row.names = FALSE)

PCA plot using dds object

# variance stabilizing transformation on counts for PCA 
vst_counts <- dds |>
  vst(blind = F)

# pca data for plot
vst_counts |>
  plotPCA(intgroup = "treatment", 
          returnData = T) -> pca_dat

# calc proportion of variance each PC accounts for 
pc_var_percent <- pca_dat |>
  attr("percentVar") |>
  round(digits = 2) * 100

# customize plot 
pca_dat |>
  ggplot(mapping = aes(PC1, PC2, color = treatment)) + 

  geom_point(size = 2) + 

  labs(title = "PCA Plot for Aiolos-deficient and Naive WT CD4+ T cells in Tfh-polarizing Conditions",
        x = paste("PC1: ",pc_var_percent[1],"% variance"),
       y = paste("PC2: ",pc_var_percent[2],"% variance")) + 

  ylim(-8,8) + 

  scale_x_continuous(breaks = seq(-8, 8, 2)) + 

  scale_color_discrete(labels = c("Aiolos-deficient", "WT")) + 

  theme_bw() + 

  theme(plot.title = element_text(hjust = 0.5, size = 10))

Figure 1. Principal component analysis for Aiolos-deficient and Naive wild-type samples in Tfh polarized conditions. A majority of the variance, 79%, in the samples was accounted for by the first principal component. The samples are well separated in variance by treatment. A small amount of variance separates the three samples within each treatment.

# correlation heatmap
dds |>
  rlog(blind = F) |> # transform dds data to log2 scale
  assay() |> 
  cor() |>
  pheatmap(clustering_distance_rows = "euclidean", 
          fontsize = 8,
          cellwidth = 40, 
          show_rownames = F, 
          color = colorRampPalette(brewer.pal(n=6, "PuBuGn"))(400))

Figure 2: Correlation heatmap for Tfh polarized samples, demonstrating the strength of correlations between each pair of samples. The correlations between the wild type samples are very strong and the correlations between the Aiolos-deficient samples are very strong, while the correlation between the wild type and Aiolos-deficient samples are weaker.

Heatmap Visualization

# prepping data for heatmap visualization
# read in unfiltered matrix that was created earlier 
unfilter_matrix <- read.csv("Tfh_KOvsWT_unfiltered_matrix.csv", header = T)

head(unfilter_matrix)
str(unfilter_matrix)
'data.frame':   20531 obs. of  14 variables:
 $ X              : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Gene_id        : chr  "ENSMUSG00000020143.16" "ENSMUSG00000004105.9" "ENSMUSG00000049109.16" "ENSMUSG00000032053.9" ...
 $ baseMean       : num  5858 8816 2813 4910 1539 ...
 $ log2FoldChange : num  -2.73 -1.03 1.85 -1.23 2.03 ...
 $ lfcSE          : num  0.0678 0.0398 0.0755 0.0506 0.0918 ...
 $ stat           : num  -40.2 -25.8 24.5 -24.2 22.2 ...
 $ pvalue         : num  0.00 1.53e-146 2.52e-132 1.14e-129 7.52e-109 ...
 $ padj           : num  0.00 1.09e-142 1.19e-128 4.02e-126 2.13e-105 ...
 $ Tfh_._Ikzf3_KO1: num  1631 5933 4407 2877 2487 ...
 $ Tfh_._Ikzf3_KO2: num  1408 5723 4615 2972 2466 ...
 $ Tfh_._Ikzf3_KO3: num  1577 5765 4181 2979 2467 ...
 $ Tfh_._WT1      : num  9448 11813 1367 6594 653 ...
 $ Tfh_._WT2      : num  10296 11803 1151 6939 510 ...
 $ Tfh_._WT3      : num  10789 11857 1156 7099 650 ...
# add column of determining if gene is diff expressed
threshold_padj <- unfilter_matrix$padj < 0.05 

# number of diff expressed genes = 3059
threshold_padj |>
  which() |>
  length()
[1] 3059
# add col determining diff expression to unfilter_matrix 
unfilter_matrix$threshold <- threshold_padj

str(unfilter_matrix)
'data.frame':   20531 obs. of  15 variables:
 $ X              : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Gene_id        : chr  "ENSMUSG00000020143.16" "ENSMUSG00000004105.9" "ENSMUSG00000049109.16" "ENSMUSG00000032053.9" ...
 $ baseMean       : num  5858 8816 2813 4910 1539 ...
 $ log2FoldChange : num  -2.73 -1.03 1.85 -1.23 2.03 ...
 $ lfcSE          : num  0.0678 0.0398 0.0755 0.0506 0.0918 ...
 $ stat           : num  -40.2 -25.8 24.5 -24.2 22.2 ...
 $ pvalue         : num  0.00 1.53e-146 2.52e-132 1.14e-129 7.52e-109 ...
 $ padj           : num  0.00 1.09e-142 1.19e-128 4.02e-126 2.13e-105 ...
 $ Tfh_._Ikzf3_KO1: num  1631 5933 4407 2877 2487 ...
 $ Tfh_._Ikzf3_KO2: num  1408 5723 4615 2972 2466 ...
 $ Tfh_._Ikzf3_KO3: num  1577 5765 4181 2979 2467 ...
 $ Tfh_._WT1      : num  9448 11813 1367 6594 653 ...
 $ Tfh_._WT2      : num  10296 11803 1151 6939 510 ...
 $ Tfh_._WT3      : num  10789 11857 1156 7099 650 ...
 $ threshold      : logi  TRUE TRUE TRUE TRUE TRUE TRUE ...
# add col with gene symbol 
unfilter_matrix$Gene_id <- sub("\\.\\d+", "", unfilter_matrix$Gene_id)

ids <- unfilter_matrix$Gene_id

gene_symbol_map <- ids |>
  transId(transTo = "symbol",
          org = "mouse")

names(unfilter_matrix)[2] = "input_id"

resdata_gene <- merge(unfilter_matrix, gene_symbol_map, by.x = "input_id", by.y = "input_id")

str(resdata_gene)
'data.frame':   18970 obs. of  16 variables:
 $ input_id       : chr  "ENSMUSG00000000001" "ENSMUSG00000000028" "ENSMUSG00000000031" "ENSMUSG00000000037" ...
 $ X              : int  12096 2028 9766 4222 1756 4845 362 3799 3337 10583 ...
 $ baseMean       : num  6756.6 2666 91.5 22.8 1369.9 ...
 $ log2FoldChange : num  0.0141 0.1829 0.6925 -0.9898 -0.2512 ...
 $ lfcSE          : num  0.0469 0.0544 1.0746 0.5032 0.0687 ...
 $ stat           : num  0.3 3.36 0.644 -1.967 -3.657 ...
 $ pvalue         : num  0.763828 0.00078 0.519269 0.049161 0.000255 ...
 $ padj           : num  0.89377 0.00544 0.75256 0.16478 0.00206 ...
 $ Tfh_._Ikzf3_KO1: num  6977.6 2893 52.6 11.5 1280.5 ...
 $ Tfh_._Ikzf3_KO2: num  6863.9 2850.2 200.5 12.5 1219.9 ...
 $ Tfh_._Ikzf3_KO3: num  6523 2759.9 86.2 22.2 1252.6 ...
 $ Tfh_._WT1      : num  6822.1 2457 59.9 27.4 1466.9 ...
 $ Tfh_._WT2      : num  6529.5 2531.2 8.7 33.1 1507.1 ...
 $ Tfh_._WT3      : num  6823.4 2504.8 141.4 29.9 1492.8 ...
 $ threshold      : logi  FALSE TRUE FALSE FALSE TRUE FALSE ...
 $ symbol         : chr  "Gnai3" "Cdc45" "H19" "Scml2" ...
head(resdata_gene)

# add a column to specify up/down-reg
resdata_gene$diffexpressed <- "Unchanged"

# if log2FC > 1 and padj < 0.05 set as upregulated
resdata_gene$diffexpressed[resdata_gene$padj < 0.05 & resdata_gene$log2FoldChange > 1] <- "Upregulated"

# if log2FC > -1 and padj < 0.05 set as downregulated
resdata_gene$diffexpressed[resdata_gene$padj < 0.05 & resdata_gene$log2FoldChange > -1] <- "Downregulated"

resdata_sig <- as.data.frame(resdata_gene) |>
  dplyr::filter(abs(log2FoldChange) > 1 & padj < 0.05)

head(resdata_sig)

# save DEGS to file 
write.csv(resdata_sig, file="Tfh_KO_vs_WT_DEG.csv")
# load the DEG.csv file
all_matrix <- read.csv("Tfh_KO_vs_WT_DEG.csv", header = T) |>
  data.frame()

head(all_matrix)

heatmap_matrix <- all_matrix |>
  select(symbol, Tfh_._Ikzf3_KO1:Tfh_._WT3) |>
  data.frame() 

# remove non-unique rows based on symbol so that I can use symbol var as name of rows, I had to remove the duplicated rows (only 2)

heatmap_matrix <- heatmap_matrix |> distinct(symbol, .keep_all = T)
head(heatmap_matrix)

# keep symbol col as names of rows 
row.names(heatmap_matrix) <- heatmap_matrix$symbol # having issues bc I had duplicate row names

heatmap_matrix <- heatmap_matrix |> 
  select(2:7)

head(heatmap_matrix)

names(heatmap_matrix)
[1] "Tfh_._Ikzf3_KO1" "Tfh_._Ikzf3_KO2" "Tfh_._Ikzf3_KO3" "Tfh_._WT1"       "Tfh_._WT2"       "Tfh_._WT3"      
# add col to coldata with sample names that match col names of count data 
coldata$sample_id <- c("Tfh_Ikzf3.KO1", "Tfh_Ikzf3.KO2", "Tfh_Ikzf3.KO3", "Tfh_WT1", "Tfh_WT2", "Tfh_WT3") 

rownames(coldata) <- coldata$sample_id

heatmap_meta <- coldata |>
  select(treatment)

# re-level factors
heatmap_meta$genotype <- factor(heatmap_meta$treatment, 
                                levels = c("WT", "KO"))

heatmap_meta <- heatmap_meta |> 
  select(2)
# colors for heatmap
heatmap_colors <- brewer.pal(10, "RdBu") |>
  rev() 
# rename meta genotypes to be more descriptive
heatmap_meta_rename <- heatmap_meta 

# add col with correct labels
heatmap_meta_rename$Genotype <- ifelse(heatmap_meta_rename$genotype == "KO", "Aiolos_deficient", "WT") 

heatmap_meta_rename <- heatmap_meta_rename |> 
  select("Genotype")

# colors for annotations 
ann_colors <- list(Genotype = c(Aiolos_deficient = "#B0F6F9", WT = "#A66EF4"))

# make plot 
heatmap_matrix |> 
  pheatmap(color = heatmap_colors,
            annotation_col = heatmap_meta_rename,
            annotation_colors = ann_colors,
            show_rownames = F,
            show_colnames = F,
            scale = "row",
            annotation_names_col = F,
            cellwidth = 20,
            cellheight = 0.4,
            treeheight_row = 10,
            treeheight_col = 20) |>
  as.ggplot() -> heatmap


#heatmap

# # save plot as image 
# ggsave(filename = "heatmap_figure.png",
#       plot = heatmap,
#       units = "in", 
#       width = 5, 
#       height = 6, 
#       dpi = 300)

Figure 3. Heatmap demonstrating significant differentially expressed genes in wild-type vs. Aiolos-deficient mice.

Volcano Plot

Pre-processing for plot (Sets up data correctly for boxplots)

# load count matrix
counts <- read.table("salmon/salmon.merged.gene_counts.tsv", header = T)

# keep gene_id col as names of rows 
row.names(counts) <- counts$gene_id

head(counts)

# create separate matrix for Tfh counts 
counts_tfh <- counts |>
  dplyr::select(3:8) |> 
  round()
  
# preview to make sure as expected
head(counts_tfh)

treatment <- 
  rep(c("WT","KO"), 3) |>
  factor() |>
  sort()

# replicate vector for coldata df
replicate <- rep(c(1,2,3), 2) |>
   factor()

# coldata to create dds object 
coldata <- data.frame(treatment, replicate)

coldata

# create dds object
dds <- DESeqDataSetFromMatrix(countData = counts_tfh, 
                              colData = coldata,
                              design = ~ treatment)

dds
class: DESeqDataSet 
dim: 55941 6 
metadata(1): version
assays(1): counts
rownames(55941): ENSMUSG00000000001.5 ENSMUSG00000000003.16 ...
  ENSMUSG00002076991.1 ENSMUSG00002076992.1
rowData names(0):
colnames(6): Tfh_._Ikzf3_KO1 Tfh_._Ikzf3_KO2 ... Tfh_._WT2 Tfh_._WT3
colData names(2): treatment replicate
# filtering dds
# keep rows with at least 10 reads total
keep <- dds |>
  counts() |>
  rowSums() >= 10

dds <- dds[keep,]
dds
class: DESeqDataSet 
dim: 20531 6 
metadata(1): version
assays(1): counts
rownames(20531): ENSMUSG00000000001.5 ENSMUSG00000000028.16 ...
  ENSMUSG00002076304.1 ENSMUSG00002076896.1
rowData names(0):
colnames(6): Tfh_._Ikzf3_KO1 Tfh_._Ikzf3_KO2 ... Tfh_._WT2 Tfh_._WT3
colData names(2): treatment replicate
# re-level the treatment variable
dds$treatment <- 
  dds$treatment |>
  relevel(ref = "WT")
dds <- dds |>
  DESeq()

# extract results from DESeq 
res <- dds |>
  results(contrast = c("treatment",
                       "KO",
                       "WT"))

res |>
  head()
log2 fold change (MLE): treatment KO vs WT 
Wald test p-value: treatment KO vs WT 
DataFrame with 6 rows and 6 columns
                       baseMean log2FoldChange     lfcSE      stat      pvalue       padj
                      <numeric>      <numeric> <numeric> <numeric>   <numeric>  <numeric>
ENSMUSG00000000001.5  6756.5893      0.0141043 0.0469427  0.300458 0.763828202 0.89377434
ENSMUSG00000000028.16 2666.0388      0.1829078 0.0544402  3.359795 0.000780003 0.00544157
ENSMUSG00000000031.18   91.5497      0.6925470 1.0745956  0.644472 0.519269299 0.75256035
ENSMUSG00000000037.18   22.7692     -0.9898316 0.5031701 -1.967191 0.049161194 0.16478255
ENSMUSG00000000056.8  1369.9485     -0.2512007 0.0686897 -3.657038 0.000255147 0.00205672
ENSMUSG00000000058.7    31.5859     -0.8224517 0.4740733 -1.734862 0.082765275 0.24175453
res |>
  dim() # 20531 x 6 
[1] 20531     6
# order results from smallest to largest p-adjusted value 
result <- res[res$padj |>
  order(), ]

head(result)
log2 fold change (MLE): treatment KO vs WT 
Wald test p-value: treatment KO vs WT 
DataFrame with 6 rows and 6 columns
                       baseMean log2FoldChange     lfcSE      stat       pvalue         padj
                      <numeric>      <numeric> <numeric> <numeric>    <numeric>    <numeric>
ENSMUSG00000020143.16  5858.095       -2.72621 0.0677903  -40.2154  0.00000e+00  0.00000e+00
ENSMUSG00000004105.9   8816.018       -1.02557 0.0397834  -25.7788 1.53385e-146 1.08558e-142
ENSMUSG00000049109.16  2812.993        1.84731 0.0754677   24.4782 2.52451e-132 1.19115e-128
ENSMUSG00000032053.9   4909.934       -1.22529 0.0505739  -24.2277 1.13541e-129 4.01792e-126
ENSMUSG00000031765.9   1539.002        2.03377 0.0917571   22.1648 7.51775e-109 2.12828e-105
ENSMUSG00000023132.9    348.358        5.10500 0.2385279   21.4021 1.27692e-101  3.01247e-98
# merge the result object and counts data frame 
resdata <- merge(as.data.frame(result),
                 as.data.frame(counts(dds, normalized = T)),
                 by = "row.names",
                 sort = F)

names(resdata)[1] <- "Gene_id"
head(resdata)

# write resdata to file called unfiltered results 
resdata |>
  write.csv(file = "Tfh_KOvsWT_unfiltered_matrix.csv")

threshold_padj <- resdata$padj < 0.05 
length(which(threshold_padj)) 
[1] 3059
resdata$threshold <- threshold_padj ## Add vector as a column (threshold) to the resdata
str(resdata)
'data.frame':   20531 obs. of  14 variables:
 $ Gene_id        : 'AsIs' chr  "ENSMUSG00000020143.16" "ENSMUSG00000004105.9" "ENSMUSG00000049109.16" "ENSMUSG00000032053.9" ...
 $ baseMean       : num  5858 8816 2813 4910 1539 ...
 $ log2FoldChange : num  -2.73 -1.03 1.85 -1.23 2.03 ...
 $ lfcSE          : num  0.0678 0.0398 0.0755 0.0506 0.0918 ...
 $ stat           : num  -40.2 -25.8 24.5 -24.2 22.2 ...
 $ pvalue         : num  0.00 1.53e-146 2.52e-132 1.14e-129 7.52e-109 ...
 $ padj           : num  0.00 1.09e-142 1.19e-128 4.02e-126 2.13e-105 ...
 $ Tfh_._Ikzf3_KO1: num  1631 5933 4407 2877 2487 ...
 $ Tfh_._Ikzf3_KO2: num  1408 5723 4615 2972 2466 ...
 $ Tfh_._Ikzf3_KO3: num  1577 5765 4181 2979 2467 ...
 $ Tfh_._WT1      : num  9448 11813 1367 6594 653 ...
 $ Tfh_._WT2      : num  10296 11803 1151 6939 510 ...
 $ Tfh_._WT3      : num  10789 11857 1156 7099 650 ...
 $ threshold      : logi  TRUE TRUE TRUE TRUE TRUE TRUE ...
resdata$Gene_id <- sub("\\.\\d+", "", resdata$Gene_id)
ids <- resdata$Gene_id
gene_symbol_map <- transId(ids, transTo = "symbol", org = "mouse")

names(resdata)[1] = "input_id"

resdata_gene <- merge(resdata, gene_symbol_map, by.x = "input_id", by.y = "input_id")

head(resdata_gene)

#Add a column to dataframe to specify up or down regulated
resdata_gene$diffexpressed <- "Unchanged"

#if log2FC > 1 and padj < 0.05 set as upregulated
resdata_gene$diffexpressed[resdata_gene$padj < 0.05 & resdata_gene$log2FoldChange > 1] <- "Upregulated"

#if log2FC > -1 and padj < 0.05 set as downregulated
resdata_gene$diffexpressed[resdata_gene$padj < 0.05 & resdata_gene$log2FoldChange < -1] <- "Downregulated"

# MAke data det to use for ggplots later
resdata_sig <- as.data.frame(resdata_gene) %>% dplyr::filter(abs(log2FoldChange) > 1 & padj < 0.05)
head(resdata_sig)
write.csv(resdata_sig, file="Tfh_ko_versus_wt_DEG.csv")

Making the plot

keyvals <- ifelse(
  resdata_gene$log2FoldChange < -1, 'blue',
  ifelse(resdata_gene$log2FoldChange > 1, 'red',
         'grey'))
keyvals[is.na(keyvals)] <- 'black'
names(keyvals)[keyvals == 'red'] <- '> 2-fold up'
names(keyvals)[keyvals == 'grey'] <- 'n.s.'
names(keyvals)[keyvals == 'blue'] <- '> 2-fold down'

EnhancedVolcano(resdata_gene,
  lab = as.character(resdata_gene$symbol),
  x = 'log2FoldChange',
  y = 'padj', 
  selectLab = c('Tbc1d4', 'Tox', 'Tox2', 'Spp1', 'Pou2af1', 'Il2ra', 'Pdcd1', 'Il2rb', "Bcl6", "Il6st", "Prdm1", "Cd40lg", "Zfp831"),
  #selectLab = rownames(resdata_gene)[which(names(keyvals) %in%
  #                                           c('Upregulated','Downregulated'))],
  xlab = bquote(~Log[2]~ 'fold change'),
  colCustom = keyvals,
  title = "Ikzf3+/- vs. WT",
  subtitle = "Differential expression", 
  FCcutoff = 1,
  pCutoff = 0.05,
  labSize = 5, 
  axisLabSize = 12,
  legendLabels=c('Not sig.','Log2FC','padj', 'padj & Log2FC'),
  legendPosition = 'left',
  legendLabSize = 8,
  legendIconSize = 4.0,
  gridlines.major = FALSE,
  gridlines.minor = FALSE) +
  scale_x_continuous(limits = c(-8, 8)) + 
  coord_cartesian(ylim=c(0, 150), clip = "off") +
  annotate("text", x = 6, y = 75, label = "270", colour = "red", size = 5, hjust = 0, fontface = "bold") +
  annotate("text", x = -6, y = 75, label = "181", colour = "blue", size = 5, hjust = 1, fontface = "bold") + 
  annotate("text", x = 6, y = 65, label = "up", colour = "black", size = 5, hjust = 0, fontface = "bold") +
  annotate("text", x = -6, y = 65, label = "down", colour = "black", size = 5, hjust = 1, fontface = "bold")

Figure 4. Volcano plot of up and down regulated genes comparing the wild-type and aiolos-deficient samples. There were a total of 270 significantly up-regulated genes and 181 significantly down-regulated genes in the Aiolos-deficient samples compared to the wild-type samples. Significant differences in expression were determined on a greater than 2 log-fold change and a p-value less than 0.05.

GO Enrich

Creating dot and bar plots

# we want the log2 fold change
original_gene_list <- resdata$log2FoldChange
head(original_gene_list)
[1] -2.726210 -1.025566  1.847310 -1.225292  2.033774  5.105001
# name the vector
names(original_gene_list) <- resdata$input_id
head(original_gene_list)
ENSMUSG00000020143 ENSMUSG00000004105 ENSMUSG00000049109 ENSMUSG00000032053 ENSMUSG00000031765 ENSMUSG00000023132 
         -2.726210          -1.025566           1.847310          -1.225292           2.033774           5.105001 
# omit any NA values
background_gene_list<-na.omit(original_gene_list)

# sort the list in decreasing order (required for clusterProfiler)
background_gene_list = sort(background_gene_list, decreasing = TRUE)

# Extract significant results (padj < 0.05) using subset()
sig_genes_df = subset(resdata, padj < 0.05)

# From significant results, we want to filter on log2fold change
sig_genes <- sig_genes_df$log2FoldChange

# Name the vector 
names(sig_genes) <- sig_genes_df$input_id

# omit NA values
sig_genes <- na.omit(sig_genes)

# filter on min log2fold change (log2FoldChange > 1)
sig_genes <- names(sig_genes)[abs(sig_genes) > 1]

### Uncomment to run since takes so long to run
# go_enrich <- enrichGO(gene = sig_genes,
#   universe = background_gene_list, # not sure if i need to do names(background_gene_list)
#   OrgDb = "org.Mm.eg.db",
#   keyType = 'ENSEMBL',
#   readable = T,
#   ont = "BP",
#   pvalueCutoff = 0.05,
#   qvalueCutoff = 0.05)
# 
# saveRDS(go_enrich, file = "enrichGO_cd8.rds")

go_enrich <- readRDS("enrichGO_cd8.rds")

## Output results from GO analysis to a table
cluster_summary <- data.frame(go_enrich)

write.csv(cluster_summary, "clusterProfiler_TCF7ko.csv")

head(cluster_summary)

barplot <- barplot(go_enrich, 
                   showCategory = 10,
                   title = "GO Biological Pathways",
                   font.size = 8)

barplot

Figure 5:The bar plot highlights the GO Enrich database by counts, as well as organizing by p-values. The positive regulation of leukocyte activation has both a high count and is highly statistically significant to the rest.

dot <- dotplot(go_enrich, 
               showCategory = 10, 
               font.size = 8)
dot

Figure 6: The dot plot uses the GO Enrich database to show the top 10 pathways in Aiolos that are the most enriched by gene ratio. Positive regulation of cell activation is the most enriched pathway by gene ratio, a significant topic disussed by authors.

Creating CNET plot

plot_color <- cnetplot(go_enrich, 
                       showCategory = 5, 
                       categorySize="pvalue", 
                       foldChange=background_gene_list, 
                       vertex.label.font=6, 
                       cex_label_gene = 0.5,
                       cex_label_category= 0.8) + 
  scale_color_gradient2(name='fold change', low='darkgreen', high='firebrick')

plot_color

Figure 7: The figure highlights significant genes and biological concepts from GO Enrich as the network. The 5 main categories were: interferon-gamma production, T cell differentiation, lymphocyte activation involved in immune response, cell activation involved in immune response, and leukocyte activation involved in immune response. Aiolos has a known relationship to all of these pathways that were found, significant genes liked include Pou2af1, Bcl6, and Tox; which were discussed at length by the authors.

GSEA

ENTREZ ID for KEGG analysis

# Convert gene IDs for enrichKEGG function
# We will lose some genes here because not all IDs will be converted
ids<-bitr(names(original_gene_list), 
          fromType = "ENSEMBL", 
          toType = "ENTREZID", 
          OrgDb="org.Mm.eg.db") 

# remove duplicate IDS (here I use "ENSEMBL", but it should be whatever was selected as keyType)

dedup_ids = ids[!duplicated(ids[c("ENSEMBL")]),]

# Create a new dataframe df2 which has only the genes which were successfully mapped using the bitr function above
df2 = resdata[resdata$input_id %in% dedup_ids$ENSEMBL,]

# Create a new column in df2 with the corresponding ENTREZ IDs
df2 <- merge(resdata, dedup_ids, by.x = "input_id", by.y = "ENSEMBL")

str(df2)
'data.frame':   17044 obs. of  15 variables:
 $ input_id       : 'AsIs' chr  "ENSMUSG00000000001" "ENSMUSG00000000028" "ENSMUSG00000000031" "ENSMUSG00000000037" ...
 $ baseMean       : num  6756.6 2666 91.5 22.8 1369.9 ...
 $ log2FoldChange : num  0.0141 0.1829 0.6925 -0.9898 -0.2512 ...
 $ lfcSE          : num  0.0469 0.0544 1.0746 0.5032 0.0687 ...
 $ stat           : num  0.3 3.36 0.644 -1.967 -3.657 ...
 $ pvalue         : num  0.763828 0.00078 0.519269 0.049161 0.000255 ...
 $ padj           : num  0.89377 0.00544 0.75256 0.16478 0.00206 ...
 $ Tfh_._Ikzf3_KO1: num  6977.6 2893 52.6 11.5 1280.5 ...
 $ Tfh_._Ikzf3_KO2: num  6863.9 2850.2 200.5 12.5 1219.9 ...
 $ Tfh_._Ikzf3_KO3: num  6523 2759.9 86.2 22.2 1252.6 ...
 $ Tfh_._WT1      : num  6822.1 2457 59.9 27.4 1466.9 ...
 $ Tfh_._WT2      : num  6529.5 2531.2 8.7 33.1 1507.1 ...
 $ Tfh_._WT3      : num  6823.4 2504.8 141.4 29.9 1492.8 ...
 $ threshold      : logi  FALSE TRUE FALSE FALSE TRUE FALSE ...
 $ ENTREZID       : chr  "14679" "12544" "14955" "107815" ...
# Create a vector of the gene universe
kegg_gene_list <- df2$log2FoldChange

# Name vector with ENTREZ ids
names(kegg_gene_list) <- df2$ENTREZID

head(kegg_gene_list)
     14679      12544      14955     107815      67608      12390 
 0.0141043  0.1829078  0.6925470 -0.9898316 -0.2512007 -0.8224517 
# omit any NA values 
kegg_gene_list<-na.omit(kegg_gene_list)


# sort the list in decreasing order (required for clusterProfiler)
kegg_gene_list = sort(kegg_gene_list, decreasing = TRUE)

Making the plot

## GSEA using gene sets from KEGG pathways
gseaKEGG <- gseKEGG(geneList = kegg_gene_list, # ordered named vector of fold changes 
                    organism = "mmu", # supported organisms listed below
                    nPerm = 1000, # default number permutations
                    minGSSize = 20, # minimum gene set size (# genes in set)
                    pvalueCutoff = 0.05, # padj cutoff value
                    verbose = FALSE)

### Uncomment when running since take a long time
#saveRDS(gseaKEGG, file = "gseaKEGG.RDS")

#gseaKEGG <- readRDS("gseaKEGG.RDS")

## Extract the GSEA results
gseaKEGG_results <- gseaKEGG@result

## Write GSEA results to file
write.csv(gseaKEGG_results, "gsea_kegg_results.csv", quote=F)

# View(gseaKEGG_results)

enrich_gsea <- gseaplot2(gseaKEGG, 
                         title = gseaKEGG_results$Description[1], 
                         geneSetID = 1)
enrich_gsea

Figure 8. The JAK-STAT pathway had an enrichment score of 0.6. This plot demonstrates that genes associated with this pathway were up-regulated in the Aiolos-deficient samples compared to the wild-type samples.

gseaKEGG_top5 <- gseaplot2(gseaKEGG, geneSetID = 1:5)
gseaKEGG_top5

Figure 9: This plot highlights the top 5 most upregulated pathways in the Aiolos-deficient samples. The JAK-STAT pathway enrichment has a score of 0.6, as opposed to the other top 5 GSEA Kegg pathways which had a score of approximately 0.7. The other significant pathways are allograft rejection, autoimmune thyroid disorder, graft-versus host disease, and type 1 diabetes melltus.

GOBP Analysis

all_gene_sets <- msigdbr(species = "Mus musculus")

saveRDS(all_gene_sets, file = "all_gene_sets.RDS")

head(all_gene_sets)

msigdbr_collections()

GOBP_gene_sets <- msigdbr(species = "mouse", category = "C5",
                            subcategory = "GO:BP") %>% 
  dplyr::select(gs_name, entrez_gene)

head(GOBP_gene_sets)

saveRDS(GOBP_gene_sets, "GOBP_gene_sets.RDS")

GOBP_gene_sets <- readRDS("GOBP_gene_sets.RDS")

# Run GSEA
### Uncomment to run, will tkae a long time
#msig_GOBP_GSEA <- GSEA(kegg_gene_list, TERM2GENE = GOBP_gene_sets, verbose = FALSE)

#saveRDS(msig_GOBP_GSEA, "msig_GOBP_GSEA.RDS")

msig_GOBP_GSEA <- readRDS("msig_GOBP_GSEA.RDS")

## Extract the GSEA results
gseaGOBP_results <- msig_GOBP_GSEA@result

## Write GSEA results to file
write.csv(gseaGOBP_results, "gseaGOBP_results.csv", quote=F)

View(gseaGOBP_results)

## Plot the GSEA plot for a single enriched pathway
gseaplot2(msig_GOBP_GSEA, title = 'Leukocyte Mediated Cytotoxicity', geneSetID = 'GOBP_REGULATION_OF_LEUKOCYTE_MEDIATED_CYTOTOXICITY')

Figure 10. The leukocyte mediated cytotoxicity pathway had an enrichment score of about 0.7. This plot demonstrates that this pathway was upregulated in the Aiolos-deficient samples as the peak of the enrichment score is to the left side of the x-axis. This pathway is also down-regulated in the wild-type samples as the enrichment score on the right side of the graph is very low.

gseaplot2(msig_GOBP_GSEA, title = 'Interferon Gamma Response', geneSetID = 'GOBP_RESPONSE_TO_INTERFERON_GAMMA')

Figure 11. Interferon gamma response pathway had an enrichment score just below 0.6. This plot demonstrates that this pathway was upregulated in the Aiolos-deficient samples as the peak of the enrichment score is to the right side of the x-axis.

Barplot

Making and plotting the figure

name = c("Tfh_._Ikzf3_KO1", "Tfh_._Ikzf3_KO2", "Tfh_._Ikzf3_KO3", "Tfh_._WT1", "Tfh_._WT2", "Tfh_._WT3")
meta <- data.frame(name, coldata)

order_matrix <- arrange(resdata_sig, padj) 
#order_matrix
head(resdata_sig)
symbol_deg <- order_matrix %>% select(symbol, 8:13)
head(symbol_deg)
top_20_deg <- slice(symbol_deg, 1:20)
head(top_20_deg)

expression_plot <- pivot_longer(top_20_deg,
                                cols = 2:7,
                                values_to = "normalized_counts")

expression_plot3 <- pivot_longer(symbol_deg,
                                cols = 2:7,
                                values_to = "normalized_counts")

# View(expression_plot)

# Join metadata for visualizing groups or features
expression_plot2 <- left_join(x = expression_plot, 
                             y = meta, 
                             by = "name")

expression_plot4 <- left_join(x = expression_plot3, 
                             y = meta, 
                             by = "name")


Tox_exp <- expression_plot4 %>%
filter(symbol == "Tox")
Tox_exp$treatment <- factor(Tox_exp$treatment, levels = c("WT", "KO"))
boxplot_Tox <- ggplot(Tox_exp) +
  geom_boxplot(aes(x=treatment, 
                   y=normalized_counts, 
                   fill=treatment)) + 
  theme_bw() + scale_fill_manual(values = c("blue", "red")) +
        ggtitle("Tox") +
        xlab("Condition") + 
        ylab("Normalized Counts") +
        theme(legend.position = "right",
              panel.grid = element_blank(), 
              plot.title = element_text(size = rel(1.25), hjust = 0.5), #title
              axis.title = element_text(size = rel(0.75)),
              axis.text = element_text(size = rel(0.75))) #axis

Prf1_exp <- expression_plot2 %>%
  filter(symbol == "Prf1")
Prf1_exp$treatment <- factor(Prf1_exp$treatment, levels = c("WT", "KO"))
boxplot_Prf1 <- ggplot(Prf1_exp) +
  geom_boxplot(aes(x=treatment, 
                   y=normalized_counts, 
                   fill=treatment)) + 
  theme_bw() + scale_fill_manual(values = c("blue", "red")) +
        ggtitle("Prf1") +
        xlab("Condition") + 
        ylab("Normalized Counts") +
        theme(legend.position = "right",
              panel.grid = element_blank(), 
              plot.title = element_text(size = rel(1.25), hjust = 0.5), #title
              axis.title = element_text(size = rel(0.75)),
              axis.text = element_text(size = rel(0.75))) #axis

Pou2af1_exp <- expression_plot2 %>%
  filter(symbol == "Pou2af1")
Pou2af1_exp$treatment <- factor(Pou2af1_exp$treatment, levels = c("WT", "KO"))
boxplot_Pou2af1 <- ggplot(Pou2af1_exp) +
  geom_boxplot(aes(x=treatment, 
                   y=normalized_counts, 
                   fill=treatment)) + 
  theme_bw() + scale_fill_manual(values = c("blue", "red")) +
        ggtitle("Pou2af1") +
        xlab("Condition") + 
        ylab("Normalized Counts") +
        theme(legend.position = "right",
              panel.grid = element_blank(), 
              plot.title = element_text(size = rel(1.25), hjust = 0.5), #title
              axis.title = element_text(size = rel(0.75)),
              axis.text = element_text(size = rel(0.75))) #axis

Nkg7_exp <- expression_plot2 %>%
  filter(symbol == "Nkg7")
Nkg7_exp$treatment <- factor(Nkg7_exp$treatment, levels = c("WT", "KO"))
boxplot_Nkg7 <- ggplot(Nkg7_exp) +
  geom_boxplot(aes(x=treatment, 
                   y=normalized_counts, 
                   fill=treatment)) + 
  theme_bw() + scale_fill_manual(values = c("blue", "red")) +
        ggtitle("Nkg7") +
        xlab("Condition") + 
        ylab("Normalized Counts") +
        theme(legend.position = "right",
              panel.grid = element_blank(), 
              plot.title = element_text(size = rel(1.25), hjust = 0.5), #title
              axis.title = element_text(size = rel(0.75)),
              axis.text = element_text(size = rel(0.75))) #axis

Dock2_exp <- expression_plot2 %>%
  filter(symbol == "Dock2")
Dock2_exp$treatment <- factor(Dock2_exp$treatment, levels = c("WT", "KO"))
boxplot_Dock2 <- ggplot(Dock2_exp) +
  geom_boxplot(aes(x=treatment, 
                   y=normalized_counts, 
                   fill=treatment)) + 
  theme_bw() + scale_fill_manual(values = c("blue", "red")) +
        ggtitle("Dock2") +
        xlab("Condition") + 
        ylab("Normalized Counts") +
        theme(legend.position = "right",
              panel.grid = element_blank(), 
              plot.title = element_text(size = rel(1.25), hjust = 0.5), #title
              axis.title = element_text(size = rel(0.75)),
              axis.text = element_text(size = rel(0.75))) #axis

Il2ra_exp <- expression_plot4 %>%
  filter(symbol == "Il2ra")
Il2ra_exp$treatment <- factor(Il2ra_exp$treatment, levels = c("WT", "KO"))
boxplot_Il2ra <- ggplot(Il2ra_exp) +
  geom_boxplot(aes(x=treatment, 
                   y=normalized_counts, 
                   fill=treatment)) + 
  theme_bw() + scale_fill_manual(values = c("blue", "red")) +
        ggtitle("Il2ra") +
        xlab("Condition") + 
        ylab("Normalized Counts") +
        theme(legend.position = "right",
              panel.grid = element_blank(), 
              plot.title = element_text(size = rel(1.25), hjust = 0.5), #title
              axis.title = element_text(size = rel(0.75)),
              axis.text = element_text(size = rel(0.75))) #axis

boxplot_grid <- plot_grid(boxplot_Tox,
                          boxplot_Dock2, 
                          boxplot_Pou2af1,
                          boxplot_Nkg7,
                          boxplot_Prf1, 
                          boxplot_Il2ra,
                          ncol = 3)
boxplot_grid

Figure 12: The boxplots highlight the normalized counts of significant genes in the data set (Prf1, Pou2af1, Nkg7, and Dock2), as well as genes discussed heavily in the paper (Tox and Il2ra). Nkg7, Prf1, and Il2ra are up regulated. Tox, Dox2, and Pou2af are down regulated. Il2ra has high normalized counts for both WT and KO as compared to the other genes.

sessionInfo()
LS0tCnRpdGxlOiAiVGhlIG5mLWNvcmUvcm5hc2VxIFBpcGVsaW5lOiBBaW9sb3MgYXMgYSByZWd1bGF0b3Igb2YgQ0Q0KyBULWNlbGwgZGlmZmVyZW50aWF0aW9uICIKc3VidGl0bGU6ICJMaWxpZSBDb3JyZWEgYW5kIEZyYW5raWUgTWFydGluIgpvdXRwdXQ6CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCiMjIERlc2NyaXB0aW9uIG9mIGRhdGFzZXQKT3VyIGRhdGEgY29tZXMgZnJvbSBhbiBpbnZlc3RpZ2F0aW9uIG9mIENENCsgVC1jZWxsIGRpZmZlcmVudGlhdGlvbi4gVGhpcyBzdHVkeSBleGFtaW5lZCBkaWZmZXJlbmNlcyBpbiB0aGUgZGlmZmVyZW50aWF0aW9uIG9mIFRmaCBhbmQgVGgxIFQtaGVscGVyIGNlbGxzIGluIHRoZSBwcmVzZW5jZSBhbmQgYWJzZW5jZSBvZiBBaW9sb3MuIFRoZSBkYXRhIHNldCBvcmlnaW5hbGx5IGhhZCAxMiBzYW1wbGVzIGNvbXBvc2VkIG9mIDQgdHJlYXRtZW50cyB3aXRoIDMgcmVwbGljYXRpb25zIHBlciB0cmVhdG1lbnQuIFRoZXJlIHdlcmUgNiBzYW1wbGVzIGdyb3duIGluIFRmaCBwb2xhcml6aW5nIGNvbmRpdGlvbnMgYW5kIDYgaW4gVGgxIHBvbGFyaXppbmcgY29uZGl0aW9ucy4gVGhlIFRoMS1Ja3pmMy0wMiBzYW1wbGUgd2FzIHJlbW92ZWQgcHJpb3IgdG8gcnVubmluZyB0aGUgbmYtY29yZS9ybmFzZXEgcGlwZWxpbmUgZHVlIHRvIHVucmVzb2x2YWJsZSBpc3N1ZXMgd2l0aCBmaWxlcyByZWxhdGVkIHRvIHRoYXQgc2FtcGxlLiBTdWJzZXF1ZW50IGFuYWx5c2VzIGNvbXBhcmluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiZXR3ZWVuIHdpbGQtdHlwZSBhbmQgYWlvbG9zIGRlZmljaWVudCBjZWxscyB3ZXJlIHBlcmZvcm1lZCBvbmx5IG9uIHRoZSA2IHNhbXBsZXMgaW4gVGZoLXBvbGFyaXppbmcgY29uZGl0aW9ucy4gCgojIyBHRU8gYWNjZXNzaW9uIG51bWJlcgpHU0UyMDMwNjUKCiMjIFJlZmVyZW5jZSBnZW5vbWUgCm1tMTAKCiMjIENpdGF0aW9uClJlYWQsIEsuIEEuLCBKb25lcywgRC4gTS4sIFBva2hyZWwsIFMuLCBIYWxlcywgRS4gRC4gUy4sIFZhcmtleSwgQS4sIFR1YXpvbiwgSi4gQS4sIEVpc2VsZSwgQy4gRC4sIEFiZG91bmksIE8uLCBTYWFkZXksIEEuLCBMZW9uYXJkLCBNLiBSLiwgV2FycmVuLCBSLiBULiwgUG93ZWxsLCBNLiBELiwgQm9zcywgSi4gTS4sIEhlbWFubiwgRS4gQS4sIFlvdW50LCBKLiBTLiwgWGluLCBHLiwgR2hvbmVpbSwgSC4gRS4sIExpbywgQy4gSi4sIEZyZXVkLCBBLiBHLiwgQ29sbGlucywgUC4gTC4sIOKApiBPZXN0cmVpY2gsIEsuIEouICgyMDIzKS4gQWlvbG9zIHJlcHJlc3NlcyBDRDQrIFQgY2VsbCBjeXRvdG94aWMgcHJvZ3JhbW1pbmcgdmlhIHJlY2lwcm9jYWwgcmVndWxhdGlvbiBvZiBURkggdHJhbnNjcmlwdGlvbiBmYWN0b3JzIGFuZCBJTC0yIHNlbnNpdGl2aXR5LiBOYXR1cmUgY29tbXVuaWNhdGlvbnMsIDE0KDEpLCAxNjUyLiBodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE0NjctMDIzLTM3NDIwLTAKCiMgQW5hbHlzaXMKCiMjIExpYnJhcmllcyBsb2FkZWQKTG9hZGluZyB0aGUgcGFja2FnZXMgcmVxdWlyZWQgZm9yIHN1YnNlcXVlbnQgYW5hbHlzZXMuIApgYGB7ciBsb2FkIHBhY2thZ2VzfQojIGxvYWRpbmcgcmVxdWlyZWQgcGFja2FnZXMgCnBhY21hbjo6cF9sb2FkKERFU2VxMiwgZHBseXIsIHRpZHlyLCBnZ3Bsb3QyLCBnZW5la2l0ciwgcGhlYXRtYXAsIAogICAgICAgICAgICAgICBSQ29sb3JCcmV3ZXIsIEVuaGFuY2VkVm9sY2FubywgY2x1c3RlclByb2ZpbGVyLCBET1NFLCAKICAgICAgICAgICAgICAgZ2duZXdzY2FsZSwgZW5yaWNocGxvdCwga25pdHIsIGNvd3Bsb3QsIG1zaWdkYnIsIHBhdGh2aWV3LCAKICAgICAgICAgICAgICAgcGF0Y2h3b3JrLCBnZ3Bsb3RpZnkpCmBgYAoKIyMgREVTZXEgQW5hbHlzaXMgCgojIyMgUmVhZGluZyBpbiBvdXIgdW4tbm9ybWFsaXplZCBjb3VudHMgbWF0cml4IApUaGUgaW5wdXQgZmlsZSBmb3Igb3VyIERFU2VxIGFuYWx5c2lzIHdhcyB0aGUgdW4tbm9ybWFsaXNlZCBjb3VudCBtYXRyaXguIApgYGB7ciBjb3VudHMgbWF0cml4fQojIGxvYWQgY291bnQgbWF0cml4CmNvdW50cyA8LSByZWFkLnRhYmxlKCJzYWxtb24vc2FsbW9uLm1lcmdlZC5nZW5lX2NvdW50cy50c3YiLCBoZWFkZXIgPSBUKQoKIyBrZWVwIGdlbmVfaWQgY29sIGFzIG5hbWVzIG9mIHJvd3MgCnJvdy5uYW1lcyhjb3VudHMpIDwtIGNvdW50cyRnZW5lX2lkCgojIHByZXZpZXcgY291bnRzIG1hdHJpeCB3aXRoIGFsbCBzYW1wbGVzIApoZWFkKGNvdW50cykKCiMgY3JlYXRlIHNlcGFyYXRlIGNvdW50cyBtYXRyaXggZm9yIFRmaCBzYW1wbGVzIG9ubHkKY291bnRzX3RmaCA8LSBjb3VudHMgfD4KICBkcGx5cjo6c2VsZWN0KDM6OCkgfD4gCiAgcm91bmQoKQoKIyBwcmV2aWV3IHRvIG1ha2Ugc3VyZSBhcyBleHBlY3RlZApoZWFkKGNvdW50c190ZmgpCmBgYAoKIyMjIENvbGRhdGEgb2JqZWN0CldlIG5vdyBuZWVkIHRvIGNyZWF0ZSBhIGNvbGRhdGEgb2JqZWN0IHdpdGggdHJlYXRtZW50IGFuZCByZXBsaWNhdGUgaW5mb3JtYXRpb24gaW4gb3JkZXIgdG8gbWFrZSB0aGUgZGRzIG9iamVjdC4gCmBgYHtyIGNvbGRhdGF9CiMgdHJlYXRtZW50IHZlY3RvciBmb3IgY29sZGF0YSBkZgp0cmVhdG1lbnQgPC0gCiAgcmVwKGMoIldUIiwiS08iKSwgMykgfD4KICBmYWN0b3IoKSB8PgogIHNvcnQoKQoKIyByZXBsaWNhdGUgdmVjdG9yIGZvciBjb2xkYXRhIGRmCnJlcGxpY2F0ZSA8LSByZXAoYygxLDIsMyksIDIpIHw+CiAgZmFjdG9yKCkKCiMgY29sZGF0YSB0byBjcmVhdGUgZGRzIG9iamVjdCAKY29sZGF0YSA8LSBkYXRhLmZyYW1lKHRyZWF0bWVudCwgcmVwbGljYXRlKQpgYGAKCiMjIyBDcmVhdGluZyB0aGUgZGRzIG9iamVjdApgYGB7ciBkZHMgb2JqZWN0LCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBjcmVhdGUgdGhlIGRkcyBvYmplY3QKZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzX3RmaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gdHJlYXRtZW50KQpgYGAKCiMjIyBGaWx0ZXJpbmcgdGhlIGRkcyBvYmplY3QgYnkgY291bnRzCmBgYHtyIHByZS1maWx0ZXIgZGRzfQojIGZpbHRlcmluZyBkZHMsIGtlZXAgcm93cyB3aXRoIGF0IGxlYXN0IDEwIHJlYWRzIHRvdGFsCmtlZXAgPC0gZGRzIHw+CiAgY291bnRzKCkgfD4KICByb3dTdW1zKCkgPj0gMTAKCmRkcyA8LSBkZHNba2VlcCxdCgojIHJlLWxldmVsIHRoZSB0cmVhdG1lbnQgdmFyaWFibGUgdG8gbWFrZSB3aWxkIHR5cGUgdGhlIHJlZmVyZW5jZSAKZGRzJHRyZWF0bWVudCA8LSAKICBkZHMkdHJlYXRtZW50IHw+CiAgcmVsZXZlbChyZWYgPSAiV1QiKQpgYGAKCiMjIyMgVXNpbmcgZmlsdGVyZWQgZGRzIG9iamVjdCB0byBwZXJmb3JtIERFU2VxIGFuYWx5c2lzCmBgYHtyIERFU2VxLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBERVNlcSBhbmFseXNpcwpkZHMgPC0gZGRzIHw+CiAgREVTZXEoKQoKIyBleHRyYWN0IHJlc3VsdHMgZnJvbSBERVNlcSAKcmVzIDwtIGRkcyB8PgogIHJlc3VsdHMoY29udHJhc3QgPSBjKCJ0cmVhdG1lbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAiS08iLAogICAgICAgICAgICAgICAgICAgICAgICAiV1QiKSkKCnJlcyB8PgogIGRpbSgpICMgMjA1MzEgeCA2IApgYGAKCmBgYHtyIG9yZGVyIERFU2VxLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBvcmRlciByZXN1bHRzIGZyb20gc21hbGxlc3QgdG8gbGFyZ2VzdCBwLWFkanVzdGVkIHZhbHVlIApyZXN1bHQgPC0gcmVzW3JlcyRwYWRqIHw+CiAgb3JkZXIoKSwgXQoKaGVhZChyZXN1bHQpCgojIG51bWJlciBzaWduaWZpY2FudC9ub24tc2lnbmlmaWNhbnQgcGFkaiwgYWxwaGEgPSAuMDUKKHJlc3VsdCRwYWRqIDwgLjA1KSB8PgogIHRhYmxlKCkKYGBgCgpgYGB7ciB1bmZpbHRlcmVkIG1hdHJpeH0KIyBtZXJnZSB0aGUgcmVzdWx0IG9iamVjdCBhbmQgY291bnRzIGRhdGEgZnJhbWUgCnJlc2RhdGEgPC0gbWVyZ2UoYXMuZGF0YS5mcmFtZShyZXN1bHQpLAogICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKGNvdW50cyhkZHMsIG5vcm1hbGl6ZWQgPSBUKSksCiAgICAgICAgICAgICAgICAgIGJ5ID0gInJvdy5uYW1lcyIsCiAgICAgICAgICAgICAgICAgIHNvcnQgPSBGKQoKbmFtZXMocmVzZGF0YSlbMV0gPC0gIkdlbmVfaWQiCmhlYWQocmVzZGF0YSkKCiMgd3JpdGUgcmVzZGF0YSB0byBmaWxlIGNhbGxlZCB1bmZpbHRlcmVkIHJlc3VsdHMgCnJlc2RhdGEgfD4KICB3cml0ZS5jc3YoZmlsZSA9ICJUZmhfS092c1dUX3VuZmlsdGVyZWRfbWF0cml4LmNzdiIpCmBgYAoKYGBge3IgREVHIGxpc3R9CiMgZ2V0IHVwL2Rvd24gREVHIGxpc3RzIApyZXNkYXRhIDwtIGFzLmRhdGEuZnJhbWUocmVzdWx0KSB8PgogIGRwbHlyOjpmaWx0ZXIoYWJzKGxvZzJGb2xkQ2hhbmdlKSA+IDEgJiBwYWRqIDwgMC4wNSkgfD4gCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIkdlbmVfaWQiKQoKaGVhZChyZXNkYXRhKQoKIyBzYXZlIHRvIGZpbGUgREVHIGxpc3QgZmlsZSAKd3JpdGUuY3N2KHJlc2RhdGEsICJUZmhfS092c1dUX2xvZzJmYzFfZmRyMDVfREVHbGlzdC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyBQQ0EgcGxvdCB1c2luZyBkZHMgb2JqZWN0CmBgYHtyIFBDQSBwbG90fQojIHZhcmlhbmNlIHN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uIG9uIGNvdW50cyBmb3IgUENBIAp2c3RfY291bnRzIDwtIGRkcyB8PgogIHZzdChibGluZCA9IEYpCgojIHBjYSBkYXRhIGZvciBwbG90CnZzdF9jb3VudHMgfD4KICBwbG90UENBKGludGdyb3VwID0gInRyZWF0bWVudCIsIAogICAgICAgICAgcmV0dXJuRGF0YSA9IFQpIC0+IHBjYV9kYXQKCiMgY2FsYyBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGVhY2ggUEMgYWNjb3VudHMgZm9yIApwY192YXJfcGVyY2VudCA8LSBwY2FfZGF0IHw+CiAgYXR0cigicGVyY2VudFZhciIpIHw+CiAgcm91bmQoZGlnaXRzID0gMikgKiAxMDAKCiMgY3VzdG9taXplIHBsb3QgCnBjYV9kYXQgfD4KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyhQQzEsIFBDMiwgY29sb3IgPSB0cmVhdG1lbnQpKSArIAoKICBnZW9tX3BvaW50KHNpemUgPSAyKSArIAoKICBsYWJzKHRpdGxlID0gIlBDQSBQbG90IGZvciBBaW9sb3MtZGVmaWNpZW50IGFuZCBOYWl2ZSBXVCBDRDQrIFQgY2VsbHMgaW4gVGZoLXBvbGFyaXppbmcgQ29uZGl0aW9ucyIsCiAgICAgICAgeCA9IHBhc3RlKCJQQzE6ICIscGNfdmFyX3BlcmNlbnRbMV0sIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSBwYXN0ZSgiUEMyOiAiLHBjX3Zhcl9wZXJjZW50WzJdLCIlIHZhcmlhbmNlIikpICsgCgogIHlsaW0oLTgsOCkgKyAKCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgtOCwgOCwgMikpICsgCgogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKGxhYmVscyA9IGMoIkFpb2xvcy1kZWZpY2llbnQiLCAiV1QiKSkgKyAKCiAgdGhlbWVfYncoKSArIAoKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTApKQoKYGBgCkZpZ3VyZSAxLiBQcmluY2lwYWwgY29tcG9uZW50IGFuYWx5c2lzIGZvciBBaW9sb3MtZGVmaWNpZW50IGFuZCBOYWl2ZSB3aWxkLXR5cGUgc2FtcGxlcyBpbiBUZmggcG9sYXJpemVkIGNvbmRpdGlvbnMuIEEgbWFqb3JpdHkgb2YgdGhlIHZhcmlhbmNlLCA3OSUsIGluIHRoZSBzYW1wbGVzIHdhcyBhY2NvdW50ZWQgZm9yIGJ5IHRoZSBmaXJzdCBwcmluY2lwYWwgY29tcG9uZW50LiBUaGUgc2FtcGxlcyBhcmUgd2VsbCBzZXBhcmF0ZWQgaW4gdmFyaWFuY2UgYnkgdHJlYXRtZW50LiBBIHNtYWxsIGFtb3VudCBvZiB2YXJpYW5jZSBzZXBhcmF0ZXMgdGhlIHRocmVlIHNhbXBsZXMgd2l0aGluIGVhY2ggdHJlYXRtZW50LiAKCmBgYHtyIGNvcnJlbGF0aW9uIGhlYXRtYXB9CiMgY29ycmVsYXRpb24gaGVhdG1hcApkZHMgfD4KICBybG9nKGJsaW5kID0gRikgfD4gIyB0cmFuc2Zvcm0gZGRzIGRhdGEgdG8gbG9nMiBzY2FsZQogIGFzc2F5KCkgfD4gCiAgY29yKCkgfD4KICBwaGVhdG1hcChjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgICBmb250c2l6ZSA9IDgsCiAgICAgICAgICBjZWxsd2lkdGggPSA0MCwgCiAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwgCiAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuPTYsICJQdUJ1R24iKSkoNDAwKSkKYGBgCkZpZ3VyZSAyOiBDb3JyZWxhdGlvbiBoZWF0bWFwIGZvciBUZmggcG9sYXJpemVkIHNhbXBsZXMsIGRlbW9uc3RyYXRpbmcgdGhlIHN0cmVuZ3RoIG9mIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGVhY2ggcGFpciBvZiBzYW1wbGVzLiBUaGUgY29ycmVsYXRpb25zIGJldHdlZW4gdGhlIHdpbGQgdHlwZSBzYW1wbGVzIGFyZSB2ZXJ5IHN0cm9uZyBhbmQgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBBaW9sb3MtZGVmaWNpZW50IHNhbXBsZXMgYXJlIHZlcnkgc3Ryb25nLCB3aGlsZSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgd2lsZCB0eXBlIGFuZCBBaW9sb3MtZGVmaWNpZW50IHNhbXBsZXMgYXJlIHdlYWtlci4gCgojIyBIZWF0bWFwIFZpc3VhbGl6YXRpb24gCmBgYHtyIGRhdGEgcHJlcCBoZWF0bWFwLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBwcmVwcGluZyBkYXRhIGZvciBoZWF0bWFwIHZpc3VhbGl6YXRpb24KIyByZWFkIGluIHVuZmlsdGVyZWQgbWF0cml4IHRoYXQgd2FzIGNyZWF0ZWQgZWFybGllciAKdW5maWx0ZXJfbWF0cml4IDwtIHJlYWQuY3N2KCJUZmhfS092c1dUX3VuZmlsdGVyZWRfbWF0cml4LmNzdiIsIGhlYWRlciA9IFQpCgpoZWFkKHVuZmlsdGVyX21hdHJpeCkKc3RyKHVuZmlsdGVyX21hdHJpeCkKCiMgYWRkIGNvbHVtbiBvZiBkZXRlcm1pbmluZyBpZiBnZW5lIGlzIGRpZmYgZXhwcmVzc2VkCnRocmVzaG9sZF9wYWRqIDwtIHVuZmlsdGVyX21hdHJpeCRwYWRqIDwgMC4wNSAKCiMgbnVtYmVyIG9mIGRpZmYgZXhwcmVzc2VkIGdlbmVzID0gMzA1OQp0aHJlc2hvbGRfcGFkaiB8PgogIHdoaWNoKCkgfD4KICBsZW5ndGgoKQoKIyBhZGQgY29sIGRldGVybWluaW5nIGRpZmYgZXhwcmVzc2lvbiB0byB1bmZpbHRlcl9tYXRyaXggCnVuZmlsdGVyX21hdHJpeCR0aHJlc2hvbGQgPC0gdGhyZXNob2xkX3BhZGoKCnN0cih1bmZpbHRlcl9tYXRyaXgpCgojIGFkZCBjb2wgd2l0aCBnZW5lIHN5bWJvbCAKdW5maWx0ZXJfbWF0cml4JEdlbmVfaWQgPC0gc3ViKCJcXC5cXGQrIiwgIiIsIHVuZmlsdGVyX21hdHJpeCRHZW5lX2lkKQoKaWRzIDwtIHVuZmlsdGVyX21hdHJpeCRHZW5lX2lkCgpnZW5lX3N5bWJvbF9tYXAgPC0gaWRzIHw+CiAgdHJhbnNJZCh0cmFuc1RvID0gInN5bWJvbCIsCiAgICAgICAgICBvcmcgPSAibW91c2UiKQoKbmFtZXModW5maWx0ZXJfbWF0cml4KVsyXSA9ICJpbnB1dF9pZCIKCnJlc2RhdGFfZ2VuZSA8LSBtZXJnZSh1bmZpbHRlcl9tYXRyaXgsIGdlbmVfc3ltYm9sX21hcCwgYnkueCA9ICJpbnB1dF9pZCIsIGJ5LnkgPSAiaW5wdXRfaWQiKQoKc3RyKHJlc2RhdGFfZ2VuZSkKCmhlYWQocmVzZGF0YV9nZW5lKQoKIyBhZGQgYSBjb2x1bW4gdG8gc3BlY2lmeSB1cC9kb3duLXJlZwpyZXNkYXRhX2dlbmUkZGlmZmV4cHJlc3NlZCA8LSAiVW5jaGFuZ2VkIgoKIyBpZiBsb2cyRkMgPiAxIGFuZCBwYWRqIDwgMC4wNSBzZXQgYXMgdXByZWd1bGF0ZWQKcmVzZGF0YV9nZW5lJGRpZmZleHByZXNzZWRbcmVzZGF0YV9nZW5lJHBhZGogPCAwLjA1ICYgcmVzZGF0YV9nZW5lJGxvZzJGb2xkQ2hhbmdlID4gMV0gPC0gIlVwcmVndWxhdGVkIgoKIyBpZiBsb2cyRkMgPiAtMSBhbmQgcGFkaiA8IDAuMDUgc2V0IGFzIGRvd25yZWd1bGF0ZWQKcmVzZGF0YV9nZW5lJGRpZmZleHByZXNzZWRbcmVzZGF0YV9nZW5lJHBhZGogPCAwLjA1ICYgcmVzZGF0YV9nZW5lJGxvZzJGb2xkQ2hhbmdlID4gLTFdIDwtICJEb3ducmVndWxhdGVkIgoKcmVzZGF0YV9zaWcgPC0gYXMuZGF0YS5mcmFtZShyZXNkYXRhX2dlbmUpIHw+CiAgZHBseXI6OmZpbHRlcihhYnMobG9nMkZvbGRDaGFuZ2UpID4gMSAmIHBhZGogPCAwLjA1KQoKaGVhZChyZXNkYXRhX3NpZykKCiMgc2F2ZSBERUdTIHRvIGZpbGUgCndyaXRlLmNzdihyZXNkYXRhX3NpZywgZmlsZT0iVGZoX0tPX3ZzX1dUX0RFRy5jc3YiKQpgYGAKCmBgYHtyIG1vcmUgaGVhdG1hcCBwcmVwLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBsb2FkIHRoZSBERUcuY3N2IGZpbGUKYWxsX21hdHJpeCA8LSByZWFkLmNzdigiVGZoX0tPX3ZzX1dUX0RFRy5jc3YiLCBoZWFkZXIgPSBUKSB8PgogIGRhdGEuZnJhbWUoKQoKaGVhZChhbGxfbWF0cml4KQoKaGVhdG1hcF9tYXRyaXggPC0gYWxsX21hdHJpeCB8PgogIHNlbGVjdChzeW1ib2wsIFRmaF8uX0lremYzX0tPMTpUZmhfLl9XVDMpIHw+CiAgZGF0YS5mcmFtZSgpIAoKIyByZW1vdmUgbm9uLXVuaXF1ZSByb3dzIGJhc2VkIG9uIHN5bWJvbCBzbyB0aGF0IEkgY2FuIHVzZSBzeW1ib2wgdmFyIGFzIG5hbWUgb2Ygcm93cywgSSBoYWQgdG8gcmVtb3ZlIHRoZSBkdXBsaWNhdGVkIHJvd3MgKG9ubHkgMikKCmhlYXRtYXBfbWF0cml4IDwtIGhlYXRtYXBfbWF0cml4IHw+IGRpc3RpbmN0KHN5bWJvbCwgLmtlZXBfYWxsID0gVCkKaGVhZChoZWF0bWFwX21hdHJpeCkKCiMga2VlcCBzeW1ib2wgY29sIGFzIG5hbWVzIG9mIHJvd3MgCnJvdy5uYW1lcyhoZWF0bWFwX21hdHJpeCkgPC0gaGVhdG1hcF9tYXRyaXgkc3ltYm9sICMgaGF2aW5nIGlzc3VlcyBiYyBJIGhhZCBkdXBsaWNhdGUgcm93IG5hbWVzCgpoZWF0bWFwX21hdHJpeCA8LSBoZWF0bWFwX21hdHJpeCB8PiAKICBzZWxlY3QoMjo3KQoKaGVhZChoZWF0bWFwX21hdHJpeCkKCm5hbWVzKGhlYXRtYXBfbWF0cml4KQoKIyBhZGQgY29sIHRvIGNvbGRhdGEgd2l0aCBzYW1wbGUgbmFtZXMgdGhhdCBtYXRjaCBjb2wgbmFtZXMgb2YgY291bnQgZGF0YSAKY29sZGF0YSRzYW1wbGVfaWQgPC0gYygiVGZoX0lremYzLktPMSIsICJUZmhfSWt6ZjMuS08yIiwgIlRmaF9Ja3pmMy5LTzMiLCAiVGZoX1dUMSIsICJUZmhfV1QyIiwgIlRmaF9XVDMiKSAKCnJvd25hbWVzKGNvbGRhdGEpIDwtIGNvbGRhdGEkc2FtcGxlX2lkCgpoZWF0bWFwX21ldGEgPC0gY29sZGF0YSB8PgogIHNlbGVjdCh0cmVhdG1lbnQpCgojIHJlLWxldmVsIGZhY3RvcnMKaGVhdG1hcF9tZXRhJGdlbm90eXBlIDwtIGZhY3RvcihoZWF0bWFwX21ldGEkdHJlYXRtZW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJXVCIsICJLTyIpKQoKaGVhdG1hcF9tZXRhIDwtIGhlYXRtYXBfbWV0YSB8PiAKICBzZWxlY3QoMikKYGBgCgpgYGB7ciBoZWF0bWFwIGNvbG9yc30KIyBjb2xvcnMgZm9yIGhlYXRtYXAKaGVhdG1hcF9jb2xvcnMgPC0gYnJld2VyLnBhbCgxMCwgIlJkQnUiKSB8PgogIHJldigpIApgYGAKCmBgYHtyIHBsb3QgaGVhdG1hcH0KIyByZW5hbWUgbWV0YSBnZW5vdHlwZXMgdG8gYmUgbW9yZSBkZXNjcmlwdGl2ZQpoZWF0bWFwX21ldGFfcmVuYW1lIDwtIGhlYXRtYXBfbWV0YSAKCiMgYWRkIGNvbCB3aXRoIGNvcnJlY3QgbGFiZWxzCmhlYXRtYXBfbWV0YV9yZW5hbWUkR2Vub3R5cGUgPC0gaWZlbHNlKGhlYXRtYXBfbWV0YV9yZW5hbWUkZ2Vub3R5cGUgPT0gIktPIiwgIkFpb2xvc19kZWZpY2llbnQiLCAiV1QiKSAKCmhlYXRtYXBfbWV0YV9yZW5hbWUgPC0gaGVhdG1hcF9tZXRhX3JlbmFtZSB8PiAKICBzZWxlY3QoIkdlbm90eXBlIikKCiMgY29sb3JzIGZvciBhbm5vdGF0aW9ucyAKYW5uX2NvbG9ycyA8LSBsaXN0KEdlbm90eXBlID0gYyhBaW9sb3NfZGVmaWNpZW50ID0gIiNCMEY2RjkiLCBXVCA9ICIjQTY2RUY0IikpCgojIG1ha2UgcGxvdCAKaGVhdG1hcF9tYXRyaXggfD4gCiAgcGhlYXRtYXAoY29sb3IgPSBoZWF0bWFwX2NvbG9ycywKICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBoZWF0bWFwX21ldGFfcmVuYW1lLAogICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubl9jb2xvcnMsCiAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRiwKICAgICAgICAgICAgc2NhbGUgPSAicm93IiwKICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lc19jb2wgPSBGLAogICAgICAgICAgICBjZWxsd2lkdGggPSAyMCwKICAgICAgICAgICAgY2VsbGhlaWdodCA9IDAuNCwKICAgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSAxMCwKICAgICAgICAgICAgdHJlZWhlaWdodF9jb2wgPSAyMCkgfD4KICBhcy5nZ3Bsb3QoKSAtPiBoZWF0bWFwCgojaGVhdG1hcAoKIyAjIHNhdmUgcGxvdCBhcyBpbWFnZSAKIyBnZ3NhdmUoZmlsZW5hbWUgPSAiaGVhdG1hcF9maWd1cmUucG5nIiwKIyAgICAgICBwbG90ID0gaGVhdG1hcCwKIyAgICAgICB1bml0cyA9ICJpbiIsIAojICAgICAgIHdpZHRoID0gNSwgCiMgICAgICAgaGVpZ2h0ID0gNiwgCiMgICAgICAgZHBpID0gMzAwKQpgYGAKRmlndXJlIDMuIEhlYXRtYXAgZGVtb25zdHJhdGluZyBzaWduaWZpY2FudCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgaW4gd2lsZC10eXBlIHZzLiBBaW9sb3MtZGVmaWNpZW50IG1pY2UuIAoKIyMgVm9sY2FubyBQbG90CiMjIyBQcmUtcHJvY2Vzc2luZyBmb3IgcGxvdCAoU2V0cyB1cCBkYXRhIGNvcnJlY3RseSBmb3IgYm94cGxvdHMpCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBsb2FkIGNvdW50IG1hdHJpeApjb3VudHMgPC0gcmVhZC50YWJsZSgic2FsbW9uL3NhbG1vbi5tZXJnZWQuZ2VuZV9jb3VudHMudHN2IiwgaGVhZGVyID0gVCkKCiMga2VlcCBnZW5lX2lkIGNvbCBhcyBuYW1lcyBvZiByb3dzIApyb3cubmFtZXMoY291bnRzKSA8LSBjb3VudHMkZ2VuZV9pZAoKaGVhZChjb3VudHMpCgojIGNyZWF0ZSBzZXBhcmF0ZSBtYXRyaXggZm9yIFRmaCBjb3VudHMgCmNvdW50c190ZmggPC0gY291bnRzIHw+CiAgZHBseXI6OnNlbGVjdCgzOjgpIHw+IAogIHJvdW5kKCkKICAKIyBwcmV2aWV3IHRvIG1ha2Ugc3VyZSBhcyBleHBlY3RlZApoZWFkKGNvdW50c190ZmgpCgp0cmVhdG1lbnQgPC0gCiAgcmVwKGMoIldUIiwiS08iKSwgMykgfD4KICBmYWN0b3IoKSB8PgogIHNvcnQoKQoKIyByZXBsaWNhdGUgdmVjdG9yIGZvciBjb2xkYXRhIGRmCnJlcGxpY2F0ZSA8LSByZXAoYygxLDIsMyksIDIpIHw+CiAgIGZhY3RvcigpCgojIGNvbGRhdGEgdG8gY3JlYXRlIGRkcyBvYmplY3QgCmNvbGRhdGEgPC0gZGF0YS5mcmFtZSh0cmVhdG1lbnQsIHJlcGxpY2F0ZSkKCmNvbGRhdGEKCiMgY3JlYXRlIGRkcyBvYmplY3QKZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzX3RmaCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBjb2xkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IHRyZWF0bWVudCkKCmRkcwoKIyBmaWx0ZXJpbmcgZGRzCiMga2VlcCByb3dzIHdpdGggYXQgbGVhc3QgMTAgcmVhZHMgdG90YWwKa2VlcCA8LSBkZHMgfD4KICBjb3VudHMoKSB8PgogIHJvd1N1bXMoKSA+PSAxMAoKZGRzIDwtIGRkc1trZWVwLF0KZGRzCgojIHJlLWxldmVsIHRoZSB0cmVhdG1lbnQgdmFyaWFibGUKZGRzJHRyZWF0bWVudCA8LSAKICBkZHMkdHJlYXRtZW50IHw+CiAgcmVsZXZlbChyZWYgPSAiV1QiKQoKCmBgYAoKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQpkZHMgPC0gZGRzIHw+CiAgREVTZXEoKQoKIyBleHRyYWN0IHJlc3VsdHMgZnJvbSBERVNlcSAKcmVzIDwtIGRkcyB8PgogIHJlc3VsdHMoY29udHJhc3QgPSBjKCJ0cmVhdG1lbnQiLAogICAgICAgICAgICAgICAgICAgICAgICJLTyIsCiAgICAgICAgICAgICAgICAgICAgICAgIldUIikpCgpyZXMgfD4KICBoZWFkKCkKCnJlcyB8PgogIGRpbSgpICMgMjA1MzEgeCA2IApgYGAKCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KIyBvcmRlciByZXN1bHRzIGZyb20gc21hbGxlc3QgdG8gbGFyZ2VzdCBwLWFkanVzdGVkIHZhbHVlIApyZXN1bHQgPC0gcmVzW3JlcyRwYWRqIHw+CiAgb3JkZXIoKSwgXQoKaGVhZChyZXN1bHQpCgojIG1lcmdlIHRoZSByZXN1bHQgb2JqZWN0IGFuZCBjb3VudHMgZGF0YSBmcmFtZSAKcmVzZGF0YSA8LSBtZXJnZShhcy5kYXRhLmZyYW1lKHJlc3VsdCksCiAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZShjb3VudHMoZGRzLCBub3JtYWxpemVkID0gVCkpLAogICAgICAgICAgICAgICAgIGJ5ID0gInJvdy5uYW1lcyIsCiAgICAgICAgICAgICAgICAgc29ydCA9IEYpCgpuYW1lcyhyZXNkYXRhKVsxXSA8LSAiR2VuZV9pZCIKaGVhZChyZXNkYXRhKQoKIyB3cml0ZSByZXNkYXRhIHRvIGZpbGUgY2FsbGVkIHVuZmlsdGVyZWQgcmVzdWx0cyAKcmVzZGF0YSB8PgogIHdyaXRlLmNzdihmaWxlID0gIlRmaF9LT3ZzV1RfdW5maWx0ZXJlZF9tYXRyaXguY3N2IikKCnRocmVzaG9sZF9wYWRqIDwtIHJlc2RhdGEkcGFkaiA8IDAuMDUgCmxlbmd0aCh3aGljaCh0aHJlc2hvbGRfcGFkaikpIAoKcmVzZGF0YSR0aHJlc2hvbGQgPC0gdGhyZXNob2xkX3BhZGogIyMgQWRkIHZlY3RvciBhcyBhIGNvbHVtbiAodGhyZXNob2xkKSB0byB0aGUgcmVzZGF0YQpzdHIocmVzZGF0YSkKCnJlc2RhdGEkR2VuZV9pZCA8LSBzdWIoIlxcLlxcZCsiLCAiIiwgcmVzZGF0YSRHZW5lX2lkKQppZHMgPC0gcmVzZGF0YSRHZW5lX2lkCmdlbmVfc3ltYm9sX21hcCA8LSB0cmFuc0lkKGlkcywgdHJhbnNUbyA9ICJzeW1ib2wiLCBvcmcgPSAibW91c2UiKQoKbmFtZXMocmVzZGF0YSlbMV0gPSAiaW5wdXRfaWQiCgpyZXNkYXRhX2dlbmUgPC0gbWVyZ2UocmVzZGF0YSwgZ2VuZV9zeW1ib2xfbWFwLCBieS54ID0gImlucHV0X2lkIiwgYnkueSA9ICJpbnB1dF9pZCIpCgpoZWFkKHJlc2RhdGFfZ2VuZSkKCiNBZGQgYSBjb2x1bW4gdG8gZGF0YWZyYW1lIHRvIHNwZWNpZnkgdXAgb3IgZG93biByZWd1bGF0ZWQKcmVzZGF0YV9nZW5lJGRpZmZleHByZXNzZWQgPC0gIlVuY2hhbmdlZCIKCiNpZiBsb2cyRkMgPiAxIGFuZCBwYWRqIDwgMC4wNSBzZXQgYXMgdXByZWd1bGF0ZWQKcmVzZGF0YV9nZW5lJGRpZmZleHByZXNzZWRbcmVzZGF0YV9nZW5lJHBhZGogPCAwLjA1ICYgcmVzZGF0YV9nZW5lJGxvZzJGb2xkQ2hhbmdlID4gMV0gPC0gIlVwcmVndWxhdGVkIgoKI2lmIGxvZzJGQyA+IC0xIGFuZCBwYWRqIDwgMC4wNSBzZXQgYXMgZG93bnJlZ3VsYXRlZApyZXNkYXRhX2dlbmUkZGlmZmV4cHJlc3NlZFtyZXNkYXRhX2dlbmUkcGFkaiA8IDAuMDUgJiByZXNkYXRhX2dlbmUkbG9nMkZvbGRDaGFuZ2UgPCAtMV0gPC0gIkRvd25yZWd1bGF0ZWQiCgojIE1Ba2UgZGF0YSBkZXQgdG8gdXNlIGZvciBnZ3Bsb3RzIGxhdGVyCnJlc2RhdGFfc2lnIDwtIGFzLmRhdGEuZnJhbWUocmVzZGF0YV9nZW5lKSAlPiUgZHBseXI6OmZpbHRlcihhYnMobG9nMkZvbGRDaGFuZ2UpID4gMSAmIHBhZGogPCAwLjA1KQpoZWFkKHJlc2RhdGFfc2lnKQp3cml0ZS5jc3YocmVzZGF0YV9zaWcsIGZpbGU9IlRmaF9rb192ZXJzdXNfd3RfREVHLmNzdiIpCmBgYAoKIyMjIE1ha2luZyB0aGUgcGxvdApgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZ9CmtleXZhbHMgPC0gaWZlbHNlKAogIHJlc2RhdGFfZ2VuZSRsb2cyRm9sZENoYW5nZSA8IC0xLCAnYmx1ZScsCiAgaWZlbHNlKHJlc2RhdGFfZ2VuZSRsb2cyRm9sZENoYW5nZSA+IDEsICdyZWQnLAogICAgICAgICAnZ3JleScpKQprZXl2YWxzW2lzLm5hKGtleXZhbHMpXSA8LSAnYmxhY2snCm5hbWVzKGtleXZhbHMpW2tleXZhbHMgPT0gJ3JlZCddIDwtICc+IDItZm9sZCB1cCcKbmFtZXMoa2V5dmFscylba2V5dmFscyA9PSAnZ3JleSddIDwtICduLnMuJwpuYW1lcyhrZXl2YWxzKVtrZXl2YWxzID09ICdibHVlJ10gPC0gJz4gMi1mb2xkIGRvd24nCgpFbmhhbmNlZFZvbGNhbm8ocmVzZGF0YV9nZW5lLAogIGxhYiA9IGFzLmNoYXJhY3RlcihyZXNkYXRhX2dlbmUkc3ltYm9sKSwKICB4ID0gJ2xvZzJGb2xkQ2hhbmdlJywKICB5ID0gJ3BhZGonLCAKICBzZWxlY3RMYWIgPSBjKCdUYmMxZDQnLCAnVG94JywgJ1RveDInLCAnU3BwMScsICdQb3UyYWYxJywgJ0lsMnJhJywgJ1BkY2QxJywgJ0lsMnJiJywgIkJjbDYiLCAiSWw2c3QiLCAiUHJkbTEiLCAiQ2Q0MGxnIiwgIlpmcDgzMSIpLAogICNzZWxlY3RMYWIgPSByb3duYW1lcyhyZXNkYXRhX2dlbmUpW3doaWNoKG5hbWVzKGtleXZhbHMpICVpbiUKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoJ1VwcmVndWxhdGVkJywnRG93bnJlZ3VsYXRlZCcpKV0sCiAgeGxhYiA9IGJxdW90ZSh+TG9nWzJdfiAnZm9sZCBjaGFuZ2UnKSwKICBjb2xDdXN0b20gPSBrZXl2YWxzLAogIHRpdGxlID0gIklremYzLS8tIHZzLiBXVCIsCiAgc3VidGl0bGUgPSAiRGlmZmVyZW50aWFsIGV4cHJlc3Npb24iLCAKICBGQ2N1dG9mZiA9IDEsCiAgcEN1dG9mZiA9IDAuMDUsCiAgbGFiU2l6ZSA9IDUsIAogIGF4aXNMYWJTaXplID0gMTIsCiAgbGVnZW5kTGFiZWxzPWMoJ05vdCBzaWcuJywnTG9nMkZDJywncGFkaicsICdwYWRqICYgTG9nMkZDJyksCiAgbGVnZW5kUG9zaXRpb24gPSAnbGVmdCcsCiAgbGVnZW5kTGFiU2l6ZSA9IDgsCiAgbGVnZW5kSWNvblNpemUgPSA0LjAsCiAgZ3JpZGxpbmVzLm1ham9yID0gRkFMU0UsCiAgZ3JpZGxpbmVzLm1pbm9yID0gRkFMU0UpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtOCwgOCkpICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCAxNTApLCBjbGlwID0gIm9mZiIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSA2LCB5ID0gNzUsIGxhYmVsID0gIjI3MCIsIGNvbG91ciA9ICJyZWQiLCBzaXplID0gNSwgaGp1c3QgPSAwLCBmb250ZmFjZSA9ICJib2xkIikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IC02LCB5ID0gNzUsIGxhYmVsID0gIjE4MSIsIGNvbG91ciA9ICJibHVlIiwgc2l6ZSA9IDUsIGhqdXN0ID0gMSwgZm9udGZhY2UgPSAiYm9sZCIpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gNiwgeSA9IDY1LCBsYWJlbCA9ICJ1cCIsIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA1LCBoanVzdCA9IDAsIGZvbnRmYWNlID0gImJvbGQiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gLTYsIHkgPSA2NSwgbGFiZWwgPSAiZG93biIsIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA1LCBoanVzdCA9IDEsIGZvbnRmYWNlID0gImJvbGQiKQpgYGAKRmlndXJlIDQuIFZvbGNhbm8gcGxvdCBvZiB1cCBhbmQgZG93biByZWd1bGF0ZWQgZ2VuZXMgY29tcGFyaW5nIHRoZSB3aWxkLXR5cGUgYW5kIGFpb2xvcy1kZWZpY2llbnQgc2FtcGxlcy4gVGhlcmUgd2VyZSBhIHRvdGFsIG9mIDI3MCBzaWduaWZpY2FudGx5IHVwLXJlZ3VsYXRlZCBnZW5lcyBhbmQgMTgxIHNpZ25pZmljYW50bHkgZG93bi1yZWd1bGF0ZWQgZ2VuZXMgaW4gdGhlIEFpb2xvcy1kZWZpY2llbnQgc2FtcGxlcyBjb21wYXJlZCB0byB0aGUgd2lsZC10eXBlIHNhbXBsZXMuIFNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIGV4cHJlc3Npb24gd2VyZSBkZXRlcm1pbmVkIG9uIGEgZ3JlYXRlciB0aGFuIDIgbG9nLWZvbGQgY2hhbmdlIGFuZCBhIHAtdmFsdWUgbGVzcyB0aGFuIDAuMDUuIAoKIyMgR08gRW5yaWNoCgojIyMgQ3JlYXRpbmcgZG90IGFuZCBiYXIgcGxvdHMKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIHdlIHdhbnQgdGhlIGxvZzIgZm9sZCBjaGFuZ2UKb3JpZ2luYWxfZ2VuZV9saXN0IDwtIHJlc2RhdGEkbG9nMkZvbGRDaGFuZ2UKaGVhZChvcmlnaW5hbF9nZW5lX2xpc3QpCgojIG5hbWUgdGhlIHZlY3RvcgpuYW1lcyhvcmlnaW5hbF9nZW5lX2xpc3QpIDwtIHJlc2RhdGEkaW5wdXRfaWQKaGVhZChvcmlnaW5hbF9nZW5lX2xpc3QpCgojIG9taXQgYW55IE5BIHZhbHVlcwpiYWNrZ3JvdW5kX2dlbmVfbGlzdDwtbmEub21pdChvcmlnaW5hbF9nZW5lX2xpc3QpCgojIHNvcnQgdGhlIGxpc3QgaW4gZGVjcmVhc2luZyBvcmRlciAocmVxdWlyZWQgZm9yIGNsdXN0ZXJQcm9maWxlcikKYmFja2dyb3VuZF9nZW5lX2xpc3QgPSBzb3J0KGJhY2tncm91bmRfZ2VuZV9saXN0LCBkZWNyZWFzaW5nID0gVFJVRSkKCiMgRXh0cmFjdCBzaWduaWZpY2FudCByZXN1bHRzIChwYWRqIDwgMC4wNSkgdXNpbmcgc3Vic2V0KCkKc2lnX2dlbmVzX2RmID0gc3Vic2V0KHJlc2RhdGEsIHBhZGogPCAwLjA1KQoKIyBGcm9tIHNpZ25pZmljYW50IHJlc3VsdHMsIHdlIHdhbnQgdG8gZmlsdGVyIG9uIGxvZzJmb2xkIGNoYW5nZQpzaWdfZ2VuZXMgPC0gc2lnX2dlbmVzX2RmJGxvZzJGb2xkQ2hhbmdlCgojIE5hbWUgdGhlIHZlY3RvciAKbmFtZXMoc2lnX2dlbmVzKSA8LSBzaWdfZ2VuZXNfZGYkaW5wdXRfaWQKCiMgb21pdCBOQSB2YWx1ZXMKc2lnX2dlbmVzIDwtIG5hLm9taXQoc2lnX2dlbmVzKQoKIyBmaWx0ZXIgb24gbWluIGxvZzJmb2xkIGNoYW5nZSAobG9nMkZvbGRDaGFuZ2UgPiAxKQpzaWdfZ2VuZXMgPC0gbmFtZXMoc2lnX2dlbmVzKVthYnMoc2lnX2dlbmVzKSA+IDFdCgojIyMgVW5jb21tZW50IHRvIHJ1biBzaW5jZSB0YWtlcyBzbyBsb25nIHRvIHJ1bgojIGdvX2VucmljaCA8LSBlbnJpY2hHTyhnZW5lID0gc2lnX2dlbmVzLAojICAgdW5pdmVyc2UgPSBiYWNrZ3JvdW5kX2dlbmVfbGlzdCwgIyBub3Qgc3VyZSBpZiBpIG5lZWQgdG8gZG8gbmFtZXMoYmFja2dyb3VuZF9nZW5lX2xpc3QpCiMgICBPcmdEYiA9ICJvcmcuTW0uZWcuZGIiLAojICAga2V5VHlwZSA9ICdFTlNFTUJMJywKIyAgIHJlYWRhYmxlID0gVCwKIyAgIG9udCA9ICJCUCIsCiMgICBwdmFsdWVDdXRvZmYgPSAwLjA1LAojICAgcXZhbHVlQ3V0b2ZmID0gMC4wNSkKIyAKIyBzYXZlUkRTKGdvX2VucmljaCwgZmlsZSA9ICJlbnJpY2hHT19jZDgucmRzIikKCmdvX2VucmljaCA8LSByZWFkUkRTKCJlbnJpY2hHT19jZDgucmRzIikKCiMjIE91dHB1dCByZXN1bHRzIGZyb20gR08gYW5hbHlzaXMgdG8gYSB0YWJsZQpjbHVzdGVyX3N1bW1hcnkgPC0gZGF0YS5mcmFtZShnb19lbnJpY2gpCgp3cml0ZS5jc3YoY2x1c3Rlcl9zdW1tYXJ5LCAiY2x1c3RlclByb2ZpbGVyX1RDRjdrby5jc3YiKQoKaGVhZChjbHVzdGVyX3N1bW1hcnkpCgpiYXJwbG90IDwtIGJhcnBsb3QoZ29fZW5yaWNoLCAKICAgICAgICAgICAgICAgICAgIHNob3dDYXRlZ29yeSA9IDEwLAogICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiR08gQmlvbG9naWNhbCBQYXRod2F5cyIsCiAgICAgICAgICAgICAgICAgICBmb250LnNpemUgPSA4KQoKYmFycGxvdApgYGAKRmlndXJlIDU6VGhlIGJhciBwbG90IGhpZ2hsaWdodHMgdGhlIEdPIEVucmljaCBkYXRhYmFzZSBieSBjb3VudHMsIGFzIHdlbGwgYXMgb3JnYW5pemluZyBieSBwLXZhbHVlcy4gVGhlIHBvc2l0aXZlIHJlZ3VsYXRpb24gb2YgbGV1a29jeXRlIGFjdGl2YXRpb24gaGFzIGJvdGggYSBoaWdoIGNvdW50IGFuZCBpcyBoaWdobHkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB0byB0aGUgcmVzdC4gCgpgYGB7cn0KZG90IDwtIGRvdHBsb3QoZ29fZW5yaWNoLCAKICAgICAgICAgICAgICAgc2hvd0NhdGVnb3J5ID0gMTAsIAogICAgICAgICAgICAgICBmb250LnNpemUgPSA4KQpkb3QKYGBgCkZpZ3VyZSA2OiBUaGUgZG90IHBsb3QgdXNlcyB0aGUgR08gRW5yaWNoIGRhdGFiYXNlIHRvIHNob3cgdGhlIHRvcCAxMCBwYXRod2F5cyBpbiBBaW9sb3MgdGhhdCBhcmUgdGhlIG1vc3QgZW5yaWNoZWQgYnkgZ2VuZSByYXRpby4gUG9zaXRpdmUgcmVndWxhdGlvbiBvZiBjZWxsIGFjdGl2YXRpb24gaXMgdGhlIG1vc3QgZW5yaWNoZWQgcGF0aHdheSBieSBnZW5lIHJhdGlvLCBhIHNpZ25pZmljYW50IHRvcGljIGRpc3Vzc2VkIGJ5IGF1dGhvcnMuIAoKIyMjIENyZWF0aW5nIENORVQgcGxvdApgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZ9CnBsb3RfY29sb3IgPC0gY25ldHBsb3QoZ29fZW5yaWNoLCAKICAgICAgICAgICAgICAgICAgICAgICBzaG93Q2F0ZWdvcnkgPSA1LCAKICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeVNpemU9InB2YWx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgIGZvbGRDaGFuZ2U9YmFja2dyb3VuZF9nZW5lX2xpc3QsIAogICAgICAgICAgICAgICAgICAgICAgIHZlcnRleC5sYWJlbC5mb250PTYsIAogICAgICAgICAgICAgICAgICAgICAgIGNleF9sYWJlbF9nZW5lID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgIGNleF9sYWJlbF9jYXRlZ29yeT0gMC44KSArIAogIHNjYWxlX2NvbG9yX2dyYWRpZW50MihuYW1lPSdmb2xkIGNoYW5nZScsIGxvdz0nZGFya2dyZWVuJywgaGlnaD0nZmlyZWJyaWNrJykKCnBsb3RfY29sb3IKYGBgCkZpZ3VyZSA3OiBUaGUgZmlndXJlIGhpZ2hsaWdodHMgc2lnbmlmaWNhbnQgZ2VuZXMgYW5kIGJpb2xvZ2ljYWwgY29uY2VwdHMgZnJvbSBHTyBFbnJpY2ggYXMgdGhlIG5ldHdvcmsuIFRoZSA1IG1haW4gY2F0ZWdvcmllcyB3ZXJlOiBpbnRlcmZlcm9uLWdhbW1hIHByb2R1Y3Rpb24sIFQgY2VsbCBkaWZmZXJlbnRpYXRpb24sIGx5bXBob2N5dGUgYWN0aXZhdGlvbiBpbnZvbHZlZCBpbiBpbW11bmUgcmVzcG9uc2UsIGNlbGwgYWN0aXZhdGlvbiBpbnZvbHZlZCBpbiBpbW11bmUgcmVzcG9uc2UsIGFuZCBsZXVrb2N5dGUgYWN0aXZhdGlvbiBpbnZvbHZlZCBpbiBpbW11bmUgcmVzcG9uc2UuIEFpb2xvcyBoYXMgYSBrbm93biByZWxhdGlvbnNoaXAgdG8gYWxsIG9mIHRoZXNlIHBhdGh3YXlzIHRoYXQgd2VyZSBmb3VuZCwgc2lnbmlmaWNhbnQgZ2VuZXMgbGlrZWQgaW5jbHVkZSBQb3UyYWYxLCBCY2w2LCBhbmQgVG94OyB3aGljaCB3ZXJlIGRpc2N1c3NlZCBhdCBsZW5ndGggYnkgdGhlIGF1dGhvcnMuIAoKIyMgR1NFQQoKIyMjIEVOVFJFWiBJRCBmb3IgS0VHRyBhbmFseXNpcwpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZ9CiMgQ29udmVydCBnZW5lIElEcyBmb3IgZW5yaWNoS0VHRyBmdW5jdGlvbgojIFdlIHdpbGwgbG9zZSBzb21lIGdlbmVzIGhlcmUgYmVjYXVzZSBub3QgYWxsIElEcyB3aWxsIGJlIGNvbnZlcnRlZAppZHM8LWJpdHIobmFtZXMob3JpZ2luYWxfZ2VuZV9saXN0KSwgCiAgICAgICAgICBmcm9tVHlwZSA9ICJFTlNFTUJMIiwgCiAgICAgICAgICB0b1R5cGUgPSAiRU5UUkVaSUQiLCAKICAgICAgICAgIE9yZ0RiPSJvcmcuTW0uZWcuZGIiKSAKCiMgcmVtb3ZlIGR1cGxpY2F0ZSBJRFMgKGhlcmUgSSB1c2UgIkVOU0VNQkwiLCBidXQgaXQgc2hvdWxkIGJlIHdoYXRldmVyIHdhcyBzZWxlY3RlZCBhcyBrZXlUeXBlKQoKZGVkdXBfaWRzID0gaWRzWyFkdXBsaWNhdGVkKGlkc1tjKCJFTlNFTUJMIildKSxdCgojIENyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgZGYyIHdoaWNoIGhhcyBvbmx5IHRoZSBnZW5lcyB3aGljaCB3ZXJlIHN1Y2Nlc3NmdWxseSBtYXBwZWQgdXNpbmcgdGhlIGJpdHIgZnVuY3Rpb24gYWJvdmUKZGYyID0gcmVzZGF0YVtyZXNkYXRhJGlucHV0X2lkICVpbiUgZGVkdXBfaWRzJEVOU0VNQkwsXQoKIyBDcmVhdGUgYSBuZXcgY29sdW1uIGluIGRmMiB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIEVOVFJFWiBJRHMKZGYyIDwtIG1lcmdlKHJlc2RhdGEsIGRlZHVwX2lkcywgYnkueCA9ICJpbnB1dF9pZCIsIGJ5LnkgPSAiRU5TRU1CTCIpCgpzdHIoZGYyKQoKIyBDcmVhdGUgYSB2ZWN0b3Igb2YgdGhlIGdlbmUgdW5pdmVyc2UKa2VnZ19nZW5lX2xpc3QgPC0gZGYyJGxvZzJGb2xkQ2hhbmdlCgojIE5hbWUgdmVjdG9yIHdpdGggRU5UUkVaIGlkcwpuYW1lcyhrZWdnX2dlbmVfbGlzdCkgPC0gZGYyJEVOVFJFWklECgpoZWFkKGtlZ2dfZ2VuZV9saXN0KQoKIyBvbWl0IGFueSBOQSB2YWx1ZXMgCmtlZ2dfZ2VuZV9saXN0PC1uYS5vbWl0KGtlZ2dfZ2VuZV9saXN0KQoKCiMgc29ydCB0aGUgbGlzdCBpbiBkZWNyZWFzaW5nIG9yZGVyIChyZXF1aXJlZCBmb3IgY2x1c3RlclByb2ZpbGVyKQprZWdnX2dlbmVfbGlzdCA9IHNvcnQoa2VnZ19nZW5lX2xpc3QsIGRlY3JlYXNpbmcgPSBUUlVFKQpgYGAKCiMjIyBNYWtpbmcgdGhlIHBsb3QKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIyBHU0VBIHVzaW5nIGdlbmUgc2V0cyBmcm9tIEtFR0cgcGF0aHdheXMKZ3NlYUtFR0cgPC0gZ3NlS0VHRyhnZW5lTGlzdCA9IGtlZ2dfZ2VuZV9saXN0LCAjIG9yZGVyZWQgbmFtZWQgdmVjdG9yIG9mIGZvbGQgY2hhbmdlcyAKICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXUiLCAjIHN1cHBvcnRlZCBvcmdhbmlzbXMgbGlzdGVkIGJlbG93CiAgICAgICAgICAgICAgICAgICAgblBlcm0gPSAxMDAwLCAjIGRlZmF1bHQgbnVtYmVyIHBlcm11dGF0aW9ucwogICAgICAgICAgICAgICAgICAgIG1pbkdTU2l6ZSA9IDIwLCAjIG1pbmltdW0gZ2VuZSBzZXQgc2l6ZSAoIyBnZW5lcyBpbiBzZXQpCiAgICAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmID0gMC4wNSwgIyBwYWRqIGN1dG9mZiB2YWx1ZQogICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKCiMjIyBVbmNvbW1lbnQgd2hlbiBydW5uaW5nIHNpbmNlIHRha2UgYSBsb25nIHRpbWUKI3NhdmVSRFMoZ3NlYUtFR0csIGZpbGUgPSAiZ3NlYUtFR0cuUkRTIikKCiNnc2VhS0VHRyA8LSByZWFkUkRTKCJnc2VhS0VHRy5SRFMiKQoKIyMgRXh0cmFjdCB0aGUgR1NFQSByZXN1bHRzCmdzZWFLRUdHX3Jlc3VsdHMgPC0gZ3NlYUtFR0dAcmVzdWx0CgojIyBXcml0ZSBHU0VBIHJlc3VsdHMgdG8gZmlsZQp3cml0ZS5jc3YoZ3NlYUtFR0dfcmVzdWx0cywgImdzZWFfa2VnZ19yZXN1bHRzLmNzdiIsIHF1b3RlPUYpCgojIFZpZXcoZ3NlYUtFR0dfcmVzdWx0cykKCmVucmljaF9nc2VhIDwtIGdzZWFwbG90Mihnc2VhS0VHRywgCiAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IGdzZWFLRUdHX3Jlc3VsdHMkRGVzY3JpcHRpb25bMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZVNldElEID0gMSkKZW5yaWNoX2dzZWEKYGBgCkZpZ3VyZSA4LiBUaGUgSkFLLVNUQVQgcGF0aHdheSBoYWQgYW4gZW5yaWNobWVudCBzY29yZSBvZiAwLjYuIFRoaXMgcGxvdCBkZW1vbnN0cmF0ZXMgdGhhdCBnZW5lcyBhc3NvY2lhdGVkIHdpdGggdGhpcyBwYXRod2F5IHdlcmUgdXAtcmVndWxhdGVkIGluIHRoZSBBaW9sb3MtZGVmaWNpZW50IHNhbXBsZXMgY29tcGFyZWQgdG8gdGhlIHdpbGQtdHlwZSBzYW1wbGVzLgoKYGBge3J9CmdzZWFLRUdHX3RvcDUgPC0gZ3NlYXBsb3QyKGdzZWFLRUdHLCBnZW5lU2V0SUQgPSAxOjUpCmdzZWFLRUdHX3RvcDUKYGBgCkZpZ3VyZSA5OiBUaGlzIHBsb3QgaGlnaGxpZ2h0cyB0aGUgdG9wIDUgbW9zdCB1cHJlZ3VsYXRlZCBwYXRod2F5cyBpbiB0aGUgQWlvbG9zLWRlZmljaWVudCBzYW1wbGVzLiBUaGUgSkFLLVNUQVQgcGF0aHdheSBlbnJpY2htZW50IGhhcyBhIHNjb3JlIG9mIDAuNiwgYXMgb3Bwb3NlZCB0byB0aGUgb3RoZXIgdG9wIDUgIEdTRUEgS2VnZyBwYXRod2F5cyB3aGljaCBoYWQgYSBzY29yZSBvZiBhcHByb3hpbWF0ZWx5IDAuNy4gVGhlIG90aGVyIHNpZ25pZmljYW50IHBhdGh3YXlzIGFyZSBhbGxvZ3JhZnQgcmVqZWN0aW9uLCBhdXRvaW1tdW5lIHRoeXJvaWQgZGlzb3JkZXIsIGdyYWZ0LXZlcnN1cyBob3N0IGRpc2Vhc2UsIGFuZCB0eXBlIDEgZGlhYmV0ZXMgbWVsbHR1cy4gCgojIyMgR09CUCBBbmFseXNpcyAKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQphbGxfZ2VuZV9zZXRzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJNdXMgbXVzY3VsdXMiKQoKc2F2ZVJEUyhhbGxfZ2VuZV9zZXRzLCBmaWxlID0gImFsbF9nZW5lX3NldHMuUkRTIikKCmhlYWQoYWxsX2dlbmVfc2V0cykKCm1zaWdkYnJfY29sbGVjdGlvbnMoKQoKR09CUF9nZW5lX3NldHMgPC0gbXNpZ2RicihzcGVjaWVzID0gIm1vdXNlIiwgY2F0ZWdvcnkgPSAiQzUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViY2F0ZWdvcnkgPSAiR086QlAiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChnc19uYW1lLCBlbnRyZXpfZ2VuZSkKCmhlYWQoR09CUF9nZW5lX3NldHMpCgpzYXZlUkRTKEdPQlBfZ2VuZV9zZXRzLCAiR09CUF9nZW5lX3NldHMuUkRTIikKCkdPQlBfZ2VuZV9zZXRzIDwtIHJlYWRSRFMoIkdPQlBfZ2VuZV9zZXRzLlJEUyIpCgojIFJ1biBHU0VBCiMjIyBVbmNvbW1lbnQgdG8gcnVuLCB3aWxsIHRrYWUgYSBsb25nIHRpbWUKI21zaWdfR09CUF9HU0VBIDwtIEdTRUEoa2VnZ19nZW5lX2xpc3QsIFRFUk0yR0VORSA9IEdPQlBfZ2VuZV9zZXRzLCB2ZXJib3NlID0gRkFMU0UpCgojc2F2ZVJEUyhtc2lnX0dPQlBfR1NFQSwgIm1zaWdfR09CUF9HU0VBLlJEUyIpCgptc2lnX0dPQlBfR1NFQSA8LSByZWFkUkRTKCJtc2lnX0dPQlBfR1NFQS5SRFMiKQoKIyMgRXh0cmFjdCB0aGUgR1NFQSByZXN1bHRzCmdzZWFHT0JQX3Jlc3VsdHMgPC0gbXNpZ19HT0JQX0dTRUFAcmVzdWx0CgojIyBXcml0ZSBHU0VBIHJlc3VsdHMgdG8gZmlsZQp3cml0ZS5jc3YoZ3NlYUdPQlBfcmVzdWx0cywgImdzZWFHT0JQX3Jlc3VsdHMuY3N2IiwgcXVvdGU9RikKCiMgVmlldyhnc2VhR09CUF9yZXN1bHRzKQoKIyMgUGxvdCB0aGUgR1NFQSBwbG90IGZvciBhIHNpbmdsZSBlbnJpY2hlZCBwYXRod2F5CmdzZWFwbG90Mihtc2lnX0dPQlBfR1NFQSwgdGl0bGUgPSAnTGV1a29jeXRlIE1lZGlhdGVkIEN5dG90b3hpY2l0eScsIGdlbmVTZXRJRCA9ICdHT0JQX1JFR1VMQVRJT05fT0ZfTEVVS09DWVRFX01FRElBVEVEX0NZVE9UT1hJQ0lUWScpCmBgYApGaWd1cmUgMTAuIFRoZSBsZXVrb2N5dGUgbWVkaWF0ZWQgY3l0b3RveGljaXR5IHBhdGh3YXkgaGFkIGFuIGVucmljaG1lbnQgc2NvcmUgb2YgYWJvdXQgMC43LiBUaGlzIHBsb3QgZGVtb25zdHJhdGVzIHRoYXQgdGhpcyBwYXRod2F5IHdhcyB1cHJlZ3VsYXRlZCBpbiB0aGUgQWlvbG9zLWRlZmljaWVudCBzYW1wbGVzIGFzIHRoZSBwZWFrIG9mIHRoZSBlbnJpY2htZW50IHNjb3JlIGlzIHRvIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIHgtYXhpcy4gVGhpcyBwYXRod2F5IGlzIGFsc28gZG93bi1yZWd1bGF0ZWQgaW4gdGhlIHdpbGQtdHlwZSBzYW1wbGVzIGFzIHRoZSBlbnJpY2htZW50IHNjb3JlIG9uIHRoZSByaWdodCBzaWRlIG9mIHRoZSBncmFwaCBpcyB2ZXJ5IGxvdy4gCgpgYGB7cn0KZ3NlYXBsb3QyKG1zaWdfR09CUF9HU0VBLCB0aXRsZSA9ICdJbnRlcmZlcm9uIEdhbW1hIFJlc3BvbnNlJywgZ2VuZVNldElEID0gJ0dPQlBfUkVTUE9OU0VfVE9fSU5URVJGRVJPTl9HQU1NQScpCmBgYApGaWd1cmUgMTEuIEludGVyZmVyb24gZ2FtbWEgcmVzcG9uc2UgcGF0aHdheSBoYWQgYW4gZW5yaWNobWVudCBzY29yZSBqdXN0IGJlbG93IDAuNi4gVGhpcyBwbG90IGRlbW9uc3RyYXRlcyB0aGF0IHRoaXMgcGF0aHdheSB3YXMgdXByZWd1bGF0ZWQgaW4gdGhlIEFpb2xvcy1kZWZpY2llbnQgc2FtcGxlcyBhcyB0aGUgcGVhayBvZiB0aGUgZW5yaWNobWVudCBzY29yZSBpcyB0byB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgeC1heGlzLgoKIyMgQmFycGxvdCAKCiMjIE1ha2luZyBhbmQgcGxvdHRpbmcgdGhlIGZpZ3VyZQpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZ9Cm5hbWUgPSBjKCJUZmhfLl9Ja3pmM19LTzEiLCAiVGZoXy5fSWt6ZjNfS08yIiwgIlRmaF8uX0lremYzX0tPMyIsICJUZmhfLl9XVDEiLCAiVGZoXy5fV1QyIiwgIlRmaF8uX1dUMyIpCm1ldGEgPC0gZGF0YS5mcmFtZShuYW1lLCBjb2xkYXRhKQoKb3JkZXJfbWF0cml4IDwtIGFycmFuZ2UocmVzZGF0YV9zaWcsIHBhZGopIAojb3JkZXJfbWF0cml4CmhlYWQocmVzZGF0YV9zaWcpCnN5bWJvbF9kZWcgPC0gb3JkZXJfbWF0cml4ICU+JSBzZWxlY3Qoc3ltYm9sLCA4OjEzKQpoZWFkKHN5bWJvbF9kZWcpCnRvcF8yMF9kZWcgPC0gc2xpY2Uoc3ltYm9sX2RlZywgMToyMCkKaGVhZCh0b3BfMjBfZGVnKQoKZXhwcmVzc2lvbl9wbG90IDwtIHBpdm90X2xvbmdlcih0b3BfMjBfZGVnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSAyOjcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIm5vcm1hbGl6ZWRfY291bnRzIikKCmV4cHJlc3Npb25fcGxvdDMgPC0gcGl2b3RfbG9uZ2VyKHN5bWJvbF9kZWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29scyA9IDI6NywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAibm9ybWFsaXplZF9jb3VudHMiKQoKIyBWaWV3KGV4cHJlc3Npb25fcGxvdCkKCiMgSm9pbiBtZXRhZGF0YSBmb3IgdmlzdWFsaXppbmcgZ3JvdXBzIG9yIGZlYXR1cmVzCmV4cHJlc3Npb25fcGxvdDIgPC0gbGVmdF9qb2luKHggPSBleHByZXNzaW9uX3Bsb3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtZXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJuYW1lIikKCmV4cHJlc3Npb25fcGxvdDQgPC0gbGVmdF9qb2luKHggPSBleHByZXNzaW9uX3Bsb3QzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWV0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAibmFtZSIpCgoKVG94X2V4cCA8LSBleHByZXNzaW9uX3Bsb3Q0ICU+JQpmaWx0ZXIoc3ltYm9sID09ICJUb3giKQpUb3hfZXhwJHRyZWF0bWVudCA8LSBmYWN0b3IoVG94X2V4cCR0cmVhdG1lbnQsIGxldmVscyA9IGMoIldUIiwgIktPIikpCmJveHBsb3RfVG94IDwtIGdncGxvdChUb3hfZXhwKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4PXRyZWF0bWVudCwgCiAgICAgICAgICAgICAgICAgICB5PW5vcm1hbGl6ZWRfY291bnRzLCAKICAgICAgICAgICAgICAgICAgIGZpbGw9dHJlYXRtZW50KSkgKyAKICB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkgKwogICAgICAgIGdndGl0bGUoIlRveCIpICsKICAgICAgICB4bGFiKCJDb25kaXRpb24iKSArIAogICAgICAgIHlsYWIoIk5vcm1hbGl6ZWQgQ291bnRzIikgKwogICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMjUpLCBoanVzdCA9IDAuNSksICN0aXRsZQogICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjc1KSksCiAgICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43NSkpKSAjYXhpcwoKUHJmMV9leHAgPC0gZXhwcmVzc2lvbl9wbG90MiAlPiUKICBmaWx0ZXIoc3ltYm9sID09ICJQcmYxIikKUHJmMV9leHAkdHJlYXRtZW50IDwtIGZhY3RvcihQcmYxX2V4cCR0cmVhdG1lbnQsIGxldmVscyA9IGMoIldUIiwgIktPIikpCmJveHBsb3RfUHJmMSA8LSBnZ3Bsb3QoUHJmMV9leHApICsKICBnZW9tX2JveHBsb3QoYWVzKHg9dHJlYXRtZW50LCAKICAgICAgICAgICAgICAgICAgIHk9bm9ybWFsaXplZF9jb3VudHMsIAogICAgICAgICAgICAgICAgICAgZmlsbD10cmVhdG1lbnQpKSArIAogIHRoZW1lX2J3KCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArCiAgICAgICAgZ2d0aXRsZSgiUHJmMSIpICsKICAgICAgICB4bGFiKCJDb25kaXRpb24iKSArIAogICAgICAgIHlsYWIoIk5vcm1hbGl6ZWQgQ291bnRzIikgKwogICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMjUpLCBoanVzdCA9IDAuNSksICN0aXRsZQogICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjc1KSksCiAgICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43NSkpKSAjYXhpcwoKUG91MmFmMV9leHAgPC0gZXhwcmVzc2lvbl9wbG90MiAlPiUKICBmaWx0ZXIoc3ltYm9sID09ICJQb3UyYWYxIikKUG91MmFmMV9leHAkdHJlYXRtZW50IDwtIGZhY3RvcihQb3UyYWYxX2V4cCR0cmVhdG1lbnQsIGxldmVscyA9IGMoIldUIiwgIktPIikpCmJveHBsb3RfUG91MmFmMSA8LSBnZ3Bsb3QoUG91MmFmMV9leHApICsKICBnZW9tX2JveHBsb3QoYWVzKHg9dHJlYXRtZW50LCAKICAgICAgICAgICAgICAgICAgIHk9bm9ybWFsaXplZF9jb3VudHMsIAogICAgICAgICAgICAgICAgICAgZmlsbD10cmVhdG1lbnQpKSArIAogIHRoZW1lX2J3KCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArCiAgICAgICAgZ2d0aXRsZSgiUG91MmFmMSIpICsKICAgICAgICB4bGFiKCJDb25kaXRpb24iKSArIAogICAgICAgIHlsYWIoIk5vcm1hbGl6ZWQgQ291bnRzIikgKwogICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMjUpLCBoanVzdCA9IDAuNSksICN0aXRsZQogICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjc1KSksCiAgICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43NSkpKSAjYXhpcwoKTmtnN19leHAgPC0gZXhwcmVzc2lvbl9wbG90MiAlPiUKICBmaWx0ZXIoc3ltYm9sID09ICJOa2c3IikKTmtnN19leHAkdHJlYXRtZW50IDwtIGZhY3RvcihOa2c3X2V4cCR0cmVhdG1lbnQsIGxldmVscyA9IGMoIldUIiwgIktPIikpCmJveHBsb3RfTmtnNyA8LSBnZ3Bsb3QoTmtnN19leHApICsKICBnZW9tX2JveHBsb3QoYWVzKHg9dHJlYXRtZW50LCAKICAgICAgICAgICAgICAgICAgIHk9bm9ybWFsaXplZF9jb3VudHMsIAogICAgICAgICAgICAgICAgICAgZmlsbD10cmVhdG1lbnQpKSArIAogIHRoZW1lX2J3KCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArCiAgICAgICAgZ2d0aXRsZSgiTmtnNyIpICsKICAgICAgICB4bGFiKCJDb25kaXRpb24iKSArIAogICAgICAgIHlsYWIoIk5vcm1hbGl6ZWQgQ291bnRzIikgKwogICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMjUpLCBoanVzdCA9IDAuNSksICN0aXRsZQogICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjc1KSksCiAgICAgICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43NSkpKSAjYXhpcwoKRG9jazJfZXhwIDwtIGV4cHJlc3Npb25fcGxvdDIgJT4lCiAgZmlsdGVyKHN5bWJvbCA9PSAiRG9jazIiKQpEb2NrMl9leHAkdHJlYXRtZW50IDwtIGZhY3RvcihEb2NrMl9leHAkdHJlYXRtZW50LCBsZXZlbHMgPSBjKCJXVCIsICJLTyIpKQpib3hwbG90X0RvY2syIDwtIGdncGxvdChEb2NrMl9leHApICsKICBnZW9tX2JveHBsb3QoYWVzKHg9dHJlYXRtZW50LCAKICAgICAgICAgICAgICAgICAgIHk9bm9ybWFsaXplZF9jb3VudHMsIAogICAgICAgICAgICAgICAgICAgZmlsbD10cmVhdG1lbnQpKSArIAogIHRoZW1lX2J3KCkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArCiAgICAgICAgZ2d0aXRsZSgiRG9jazIiKSArCiAgICAgICAgeGxhYigiQ29uZGl0aW9uIikgKyAKICAgICAgICB5bGFiKCJOb3JtYWxpemVkIENvdW50cyIpICsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgICAgICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjI1KSwgaGp1c3QgPSAwLjUpLCAjdGl0bGUKICAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43NSkpLAogICAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNzUpKSkgI2F4aXMKCklsMnJhX2V4cCA8LSBleHByZXNzaW9uX3Bsb3Q0ICU+JQogIGZpbHRlcihzeW1ib2wgPT0gIklsMnJhIikKSWwycmFfZXhwJHRyZWF0bWVudCA8LSBmYWN0b3IoSWwycmFfZXhwJHRyZWF0bWVudCwgbGV2ZWxzID0gYygiV1QiLCAiS08iKSkKYm94cGxvdF9JbDJyYSA8LSBnZ3Bsb3QoSWwycmFfZXhwKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4PXRyZWF0bWVudCwgCiAgICAgICAgICAgICAgICAgICB5PW5vcm1hbGl6ZWRfY291bnRzLCAKICAgICAgICAgICAgICAgICAgIGZpbGw9dHJlYXRtZW50KSkgKyAKICB0aGVtZV9idygpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkgKwogICAgICAgIGdndGl0bGUoIklsMnJhIikgKwogICAgICAgIHhsYWIoIkNvbmRpdGlvbiIpICsgCiAgICAgICAgeWxhYigiTm9ybWFsaXplZCBDb3VudHMiKSArCiAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yNSksIGhqdXN0ID0gMC41KSwgI3RpdGxlCiAgICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNzUpKSwKICAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjc1KSkpICNheGlzCgpib3hwbG90X2dyaWQgPC0gcGxvdF9ncmlkKGJveHBsb3RfVG94LAogICAgICAgICAgICAgICAgICAgICAgICAgIGJveHBsb3RfRG9jazIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGJveHBsb3RfUG91MmFmMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBib3hwbG90X05rZzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYm94cGxvdF9QcmYxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBib3hwbG90X0lsMnJhLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzKQpib3hwbG90X2dyaWQKYGBgCkZpZ3VyZSAxMjogVGhlIGJveHBsb3RzIGhpZ2hsaWdodCB0aGUgbm9ybWFsaXplZCBjb3VudHMgb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgaW4gdGhlIGRhdGEgc2V0IChQcmYxLCBQb3UyYWYxLCBOa2c3LCBhbmQgRG9jazIpLCBhcyB3ZWxsIGFzIGdlbmVzIGRpc2N1c3NlZCBoZWF2aWx5IGluIHRoZSBwYXBlciAoVG94IGFuZCBJbDJyYSkuIE5rZzcsIFByZjEsIGFuZCBJbDJyYSBhcmUgdXAgcmVndWxhdGVkLiBUb3gsIERveDIsIGFuZCBQb3UyYWYgYXJlIGRvd24gcmVndWxhdGVkLiBJbDJyYSBoYXMgaGlnaCBub3JtYWxpemVkIGNvdW50cyBmb3IgYm90aCBXVCBhbmQgS08gYXMgY29tcGFyZWQgdG8gdGhlIG90aGVyIGdlbmVzLiAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoK