Differential gene expression analysis for Pacific cod RNAseq data.

  • trimmed reads generated in 05-cod-RNAseq-trimming

  • Reads aligned to transcriptome downloaded from NCBI, stored here as a part of lab genomic resources.

0.0.1 Install and load packages

## clear
rm(list=ls())

## Install Rtools directly from (https://cran.r-project.org/bin/windows/Rtools/), then install these on first run:
# install.packages("BiocManager")
# BiocManager::install("DESeq2")
# BiocManager::install("vsn")
# BiocManager::install("tidybulk")
# BiocManager::install("goseq")
# BiocManager::install("affycoretools")
# BiocManager::install("EnhancedVolcano")
# BiocManager::install("pcaExplorer")
# BiocManager::install("apeglm")
# BiocManager::install("PCAtools")


# List of packages we want to install (run every time)
load.lib<-c("DESeq2","edgeR","goseq","dplyr","GenomicFeatures","data.table","calibrate","affycoretools","data.table","vsn","tidybulk","ggplot2","cowplot","pheatmap","gplots","RColorBrewer","EnhancedVolcano","pcaExplorer","readxl","apeglm","ashr","tibble","plotly","sqldf","PCAtools","ggpubr","beepr","genefilter","ComplexHeatmap","circlize","scales", "tidyverse", "gridextra'")

# Select only the packages that aren't currently installed (run every time)
# install.lib <- load.lib[!load.lib %in% installed.packages()]

# And finally we install the missing packages, including their dependency.
# for(lib in install.lib) install.packages(lib,dependencies=TRUE)
# After the installation process completes, we load all packages.
sapply(load.lib,require,character=TRUE)
         DESeq2           edgeR           goseq           dplyr GenomicFeatures 
           TRUE            TRUE            TRUE            TRUE            TRUE 
     data.table       calibrate   affycoretools      data.table             vsn 
           TRUE            TRUE            TRUE            TRUE            TRUE 
       tidybulk         ggplot2         cowplot        pheatmap          gplots 
           TRUE            TRUE            TRUE            TRUE            TRUE 
   RColorBrewer EnhancedVolcano     pcaExplorer          readxl          apeglm 
           TRUE            TRUE            TRUE            TRUE            TRUE 
           ashr          tibble          plotly           sqldf        PCAtools 
           TRUE            TRUE            TRUE            TRUE            TRUE 
         ggpubr           beepr      genefilter  ComplexHeatmap        circlize 
           TRUE            TRUE            TRUE           FALSE            TRUE 
         scales       tidyverse      gridextra' 
           TRUE            TRUE           FALSE 

I found the DESeq2 vignette and the HBC DGE training workshop super helpful in figuring out how to use the DESeq2 package!

1 Load data

1.1 Load count data

Load in the count matrix we generated after kallisto pseudoalignment using the Trinity abundance_estimates_to_matrix.pl script. We also need to slightly reformat the count matrix to make all of the estimated counts integers, as required for DESeq2.

# Read in counts data. This is a gene-level counts matrix generated from kallisto transcript abundances using Trinity
cod_counts_data_OG <- read_delim("../output/06-cod-RNAseq-alignment/kallisto/kallisto.isoform.counts.matrix") 
head(cod_counts_data_OG)
# A tibble: 6 × 81
  ...1           kallisto_quant_100 kallisto_quant_107 kallisto_quant_108
  <chr>                       <dbl>              <dbl>              <dbl>
1 XR_009522893.1               6                    1               15.7 
2 XM_060040253.1            2959                 1479             3329   
3 XM_060042128.1             242                  372              272   
4 XM_060040193.1               0                    0                0   
5 XR_009528221.1               2.40                 0                3.62
6 XM_060066729.1            1310.                 307.            1094.  
# ℹ 77 more variables: kallisto_quant_109 <dbl>, kallisto_quant_10 <dbl>,
#   kallisto_quant_110 <dbl>, kallisto_quant_117 <dbl>,
#   kallisto_quant_118 <dbl>, kallisto_quant_119 <dbl>,
#   kallisto_quant_11 <dbl>, kallisto_quant_120 <dbl>,
#   kallisto_quant_121 <dbl>, kallisto_quant_127 <dbl>,
#   kallisto_quant_128 <dbl>, kallisto_quant_129 <dbl>,
#   kallisto_quant_12 <dbl>, kallisto_quant_131 <dbl>, …

1.2 Count data munging

# # We need to modify this data frame so that the row names are actually row names, instead of comprising the first column
cod_counts_data <- cod_counts_data_OG %>% 
  column_to_rownames(var = "...1")

# Additional formatting
# Round all estimated counts to integers
cod_counts_data <- round(cod_counts_data, digits = 0)

# Remove the "kallisto_quant_" portion of the column names, to leave just the sample names
colnames(cod_counts_data) <- sub("kallisto_quant_", "sample_", colnames(cod_counts_data))

# Reorder the coumns into alphabetical order (to make it easier to create an associated metadata spreadsheet)
cod_counts_data <- cod_counts_data[, order(colnames(cod_counts_data))]

cod_sample_names <- names(cod_counts_data)

head(cod_counts_data)
               sample_1 sample_10 sample_100 sample_107 sample_108 sample_109
XR_009522893.1        5        67          6          1         16          0
XM_060040253.1     1848      4159       2959       1479       3329       2901
XM_060042128.1      260       216        242        372        272        339
XM_060040193.1        0         0          0          0          0          0
XR_009528221.1        1         3          2          0          4          1
XM_060066729.1     4870      1382       1310        307       1094        961
               sample_11 sample_110 sample_117 sample_118 sample_119 sample_12
XR_009522893.1         4          2          7          3         10        12
XM_060040253.1      3118       2775       5439       2523       3603      2938
XM_060042128.1       228        295        247        215        337       210
XM_060040193.1         0          1          0          0          0         0
XR_009528221.1         0          0          0          2          2         6
XM_060066729.1       663        829        734       2147        271       691
               sample_120 sample_121 sample_127 sample_128 sample_129 sample_13
XR_009522893.1          9          1          2          0          6        26
XM_060040253.1       5525       2720       4464       1931        244      2544
XM_060042128.1        210        255        283        219         51       213
XM_060040193.1          0          0          0          0          0         0
XR_009528221.1          1          0          5          7         16         0
XM_060066729.1        390        302       1266        566         81       914
               sample_131 sample_137 sample_138 sample_139 sample_140
XR_009522893.1         22          2          6          0          5
XM_060040253.1       1966       1482        555       1666       3106
XM_060042128.1        116        149        131        128        131
XM_060040193.1          0          0          0          0          0
XR_009528221.1          0          0          0          1          2
XM_060066729.1        506        156        133        425        300
               sample_147 sample_148 sample_149 sample_150 sample_18 sample_19
XR_009522893.1          4          1        101         40        29         5
XM_060040253.1       1260       3560       8866       3845      2018      2227
XM_060042128.1        147        407       1075        404       183       259
XM_060040193.1          0          0          2          1         0         0
XR_009528221.1          0          0         29          2         6         3
XM_060066729.1        670       1848       2158       1251      1961       310
               sample_19-G sample_19-S sample_2 sample_20 sample_20-G
XR_009522893.1          17           6       10        14          91
XM_060040253.1         759         520     2352      3003         785
XM_060042128.1         672         392      211       171         673
XM_060040193.1          37           5        0         1          54
XR_009528221.1           0           3        0         0           9
XM_060066729.1         169          72      915      1616         233
               sample_20-S sample_21 sample_28 sample_29 sample_3 sample_30
XR_009522893.1          27         1         6         1        3         9
XM_060040253.1         376      1852      2449      4368     2739      4588
XM_060042128.1         334       184       203       170      204       248
XM_060040193.1           0         0         0         0        0         0
XR_009528221.1           1         3         1         4        1         2
XM_060066729.1          99      1029       500       967      621       860
               sample_31 sample_37 sample_38 sample_39 sample_4 sample_40
XR_009522893.1         1         1        11         1        2         1
XM_060040253.1      2309      2899      4284      3392     2915      3570
XM_060042128.1       200       355       425       397      190       425
XM_060040193.1         0         0         0         0        0         0
XR_009528221.1        34         0         0         0        2         1
XM_060066729.1     17829       365       329       348     4537       279
               sample_41 sample_47 sample_48 sample_49 sample_5 sample_50
XR_009522893.1        11         1         1        30       74         2
XM_060040253.1      2806      5470      1262      4381     1772      5604
XM_060042128.1       191       304       439       251      227       226
XM_060040193.1         0         0         0         0        0         0
XR_009528221.1         4         0         0         4        0         0
XM_060066729.1      1242       468       315      1067     3191       408
               sample_57 sample_57-G sample_57-S sample_58 sample_58-G
XR_009522893.1         3          43           3         7          11
XM_060040253.1      4808         939         132      4099         934
XM_060042128.1       260         945          57       229         972
XM_060040193.1         0           8           0         0           8
XR_009528221.1         0           0          33         6           8
XM_060066729.1       578         140          78       650         161
               sample_58-S sample_59 sample_60 sample_67 sample_68 sample_69
XR_009522893.1           0         2        35        26         3         3
XM_060040253.1         245      3161      6914      7081      8208      5075
XM_060042128.1         377       413       203       307       287       252
XM_060040193.1           0         0         0         0         0         0
XR_009528221.1           0         1         8         1        13         2
XM_060066729.1          65       471       659       530       798       434
               sample_70 sample_78 sample_79 sample_80 sample_83 sample_88
XR_009522893.1         2         0         7        29         5         1
XM_060040253.1      3281      1860      2683      2548      1171      1734
XM_060042128.1       247       221       211       219       236       257
XM_060040193.1         0         0         0         0         0         0
XR_009528221.1         4         0         1         1         0         1
XM_060066729.1       686       495       910       751       389       340
               sample_90 sample_91 sample_92 sample_97 sample_98 sample_99
XR_009522893.1         4         5         1         4        17         2
XM_060040253.1      2380      2404      2205       422       684      1176
XM_060042128.1       350       219       150       386       367       135
XM_060040193.1         0         0         0         0         0         0
XR_009528221.1         0        11         1         1        13         2
XM_060066729.1       152      1469       617       508       236      2265
               sample_RESUB-116 sample_RESUB-156 sample_RESUB-36
XR_009522893.1                3                6               7
XM_060040253.1             3164             2599            1391
XM_060042128.1              124              172             172
XM_060040193.1                0                0               1
XR_009528221.1                6                4               7
XM_060066729.1             1943             2065             222
               sample_RESUB-76 sample_RESUB-94
XR_009522893.1               2              25
XM_060040253.1            6760            3726
XM_060042128.1             195             161
XM_060040193.1               1               0
XR_009528221.1               2               0
XM_060066729.1             586            1696
cod_sample_names
 [1] "sample_1"         "sample_10"        "sample_100"       "sample_107"      
 [5] "sample_108"       "sample_109"       "sample_11"        "sample_110"      
 [9] "sample_117"       "sample_118"       "sample_119"       "sample_12"       
[13] "sample_120"       "sample_121"       "sample_127"       "sample_128"      
[17] "sample_129"       "sample_13"        "sample_131"       "sample_137"      
[21] "sample_138"       "sample_139"       "sample_140"       "sample_147"      
[25] "sample_148"       "sample_149"       "sample_150"       "sample_18"       
[29] "sample_19"        "sample_19-G"      "sample_19-S"      "sample_2"        
[33] "sample_20"        "sample_20-G"      "sample_20-S"      "sample_21"       
[37] "sample_28"        "sample_29"        "sample_3"         "sample_30"       
[41] "sample_31"        "sample_37"        "sample_38"        "sample_39"       
[45] "sample_4"         "sample_40"        "sample_41"        "sample_47"       
[49] "sample_48"        "sample_49"        "sample_5"         "sample_50"       
[53] "sample_57"        "sample_57-G"      "sample_57-S"      "sample_58"       
[57] "sample_58-G"      "sample_58-S"      "sample_59"        "sample_60"       
[61] "sample_67"        "sample_68"        "sample_69"        "sample_70"       
[65] "sample_78"        "sample_79"        "sample_80"        "sample_83"       
[69] "sample_88"        "sample_90"        "sample_91"        "sample_92"       
[73] "sample_97"        "sample_98"        "sample_99"        "sample_RESUB-116"
[77] "sample_RESUB-156" "sample_RESUB-36"  "sample_RESUB-76"  "sample_RESUB-94" 

1.3 Import sample metadata sheets

# Read in the csv file as a data frame
cod_sample_info_OG <- read.csv("~/project-cod-temperature/data/DESeq2_Sample_Information.csv")
cod_experiment_alldata_OG <- read.csv("~/project-cod-temperature/data/temp-experiment.csv")
head(cod_sample_info_OG)
  sample_name sample_number tank temp_treatment tissue_type
1    sample_1             1    1             16       Liver
2   sample_10            10    2             16       Liver
3  sample_100           100   15              9       Liver
4  sample_107           107   16              9       Liver
5  sample_108           108   16              9       Liver
6  sample_109           109   16              9       Liver
head(cod_experiment_alldata_OG)
  Microchip.ID SL_11212022 WWT_11212022 Tank Temperature SL_12272022
1          620          93         8.53    1          16         101
2         1164          88         7.06    1          16          96
3         1476         102        10.70    1          16         108
4         9387          87         7.83    1          16          95
5         9407         100        11.51    1          16         117
6         9415          92         8.68    1          16         100
  WWT_12272022 MortDate DissectionDate SL_mm WholeBodyWW_g TOTAL_Liver_WW_mg
1        11.12                  2/8/23   119         16.15            0.4945
2         8.64                  2/8/23   105         10.89            0.1997
3        12.25                  2/8/23   110         12.97            0.1715
4        10.16                  2/8/23   116         15.40            0.3625
5        14.98                  2/8/23   127         17.98            0.3482
6        10.96                  2/8/23   114         14.02            0.2343
  LiverforLipids_WW_mg MuscleWWforLipids_mg GeneticSamplingCount
1               0.1546               0.3495                    8
2               0.1091               0.3328                    5
3               0.1107               0.3834                    4
4               0.1681               0.3262                    6
5               0.1210               0.3434                    2
6               0.1342               0.2776                    9
  DissectionComments
1                   
2                   
3                   
4                   
5                   
6                   
# Rename the "GeneticSamplingCount" column of the experimental data to "sample_number"
cod_experiment_alldata <- cod_experiment_alldata_OG
names(cod_experiment_alldata)[names(cod_experiment_alldata) == "GeneticSamplingCount"] <- "sample_number"

# Calculate length difference and weight difference (end-beginning)
cod_experiment_alldata$SL_diff_mm <- cod_experiment_alldata$SL_mm - cod_experiment_alldata$SL_11212022
cod_experiment_alldata$WWT_diff_g <- cod_experiment_alldata$WholeBodyWW_g - cod_experiment_alldata$WWT_11212022

# Merge the two data frames to get experimental data for all of our RNAseq'd samples.
# This should include all rows from cod_sample_info_OG and matching rows from cod_experiment_alldata based on the shared sample_number column. Sample number duplicates (e.g. from different tissue types) should be retained.
cod_sample_info <- merge(cod_sample_info_OG, cod_experiment_alldata, by = "sample_number", all.x = TRUE)

# Reorder the data frame into alphabetical order by the sample names, so that the rows are in the same order as our count matrix columns
cod_sample_info <- cod_sample_info[order(cod_sample_info$sample_name), ]

# Again, we need to reformat so that the data in the first column becomes the row names
rownames(cod_sample_info) <- cod_sample_info$sample_name

# Remove duplicate columns (artifact of merging data frames with multiple shared columns and of making sample_name the rownames instead of a variable)
cod_sample_info <- subset(cod_sample_info, select=-Temperature)
cod_sample_info <- subset(cod_sample_info, select=-Tank)
#cod_sample_info <- subset(cod_sample_info, select=-sample_name)


head(cod_sample_info)
           sample_number sample_name tank temp_treatment tissue_type
sample_1               1    sample_1    1             16       Liver
sample_10             10   sample_10    2             16       Liver
sample_100           100  sample_100   15              9       Liver
sample_107           107  sample_107   16              9       Liver
sample_108           108  sample_108   16              9       Liver
sample_109           109  sample_109   16              9       Liver
           Microchip.ID SL_11212022 WWT_11212022 SL_12272022 WWT_12272022
sample_1           9443          99        10.54         108        12.94
sample_10          9518          95         9.45         105        12.67
sample_100         9483          70         4.54          78         5.23
sample_107         4236          94         9.15         104        11.44
sample_108         9416          81         6.26          91         7.87
sample_109         9481          89         7.77          95         9.49
           MortDate DissectionDate SL_mm WholeBodyWW_g TOTAL_Liver_WW_mg
sample_1                    2/8/23   114         14.39            0.0896
sample_10                   2/8/23   120         16.22            0.3854
sample_100                  2/9/23    93          8.33            0.2558
sample_107                  2/9/23   119         16.41            0.5612
sample_108                  2/9/23   106         11.67            0.3650
sample_109                  2/9/23   116         11.45            0.3088
           LiverforLipids_WW_mg MuscleWWforLipids_mg DissectionComments
sample_1                 0.0704               0.3899      lipid inserts
sample_10                0.1285               0.2967                   
sample_100               0.1143               0.3483                   
sample_107               0.1503               0.3322                   
sample_108               0.1125               0.3612                   
sample_109               0.1090               0.3062                   
           SL_diff_mm WWT_diff_g
sample_1           15       3.85
sample_10          25       6.77
sample_100         23       3.79
sample_107         25       7.26
sample_108         25       5.41
sample_109         27       3.68

1.4 Sample metadata munging

# Factor variables
cod_sample_info$temp_treatment <- factor(cod_sample_info$temp_treatment)
cod_sample_info$tank <- factor(cod_sample_info$tank)
cod_sample_info$tissue_type <- factor(cod_sample_info$tissue_type)

# Remove bad samples
# MuliQC report: 149, 129
# PCA outliers: 31, 41 (per Laura)
cod_sample_info <- cod_sample_info[!(row.names(cod_sample_info) %in% c("sample_149", "sample_129", "sample_31", "sample_41")),]
cod_counts_data <- as.matrix(subset(cod_counts_data, select=-c(sample_149, sample_129, sample_31, sample_41)))

# Check that the column names of our count data match the row names of our sample info sheet
ncol(cod_counts_data)
[1] 76
nrow(cod_sample_info)
[1] 76
all(colnames(cod_counts_data) %in% rownames(cod_sample_info))
[1] TRUE
all(colnames(cod_counts_data) == rownames(cod_sample_info))
[1] TRUE

Combine counts data and sample metadata for later analyses

# Melt cod_counts_data to long format
cod_counts_data_long <- as.data.frame(cod_counts_data)
cod_counts_data_long$gene <- rownames(cod_counts_data_long)
cod_counts_data_long <- cod_counts_data_long %>% 
  pivot_longer(cols = starts_with("sample"), 
               names_to = "sample_name", 
               values_to = "count")

colnames(cod_counts_data_long)
[1] "gene"        "sample_name" "count"      
colnames(cod_sample_info)
 [1] "sample_number"        "sample_name"          "tank"                
 [4] "temp_treatment"       "tissue_type"          "Microchip.ID"        
 [7] "SL_11212022"          "WWT_11212022"         "SL_12272022"         
[10] "WWT_12272022"         "MortDate"             "DissectionDate"      
[13] "SL_mm"                "WholeBodyWW_g"        "TOTAL_Liver_WW_mg"   
[16] "LiverforLipids_WW_mg" "MuscleWWforLipids_mg" "DissectionComments"  
[19] "SL_diff_mm"           "WWT_diff_g"          
# Merge cod_counts_data_long with df_C to get treatment info
cod_countsdata_plus_sampleinfo <- left_join(cod_counts_data_long, cod_sample_info, by = "sample_name")

2 Preliminary PCA visualization (liver tissue)

2.1 DESeq object

# Filter data
infosub_L <- cod_sample_info %>% filter(tissue_type == "Liver")
countsub_L <- subset(cod_counts_data, select=row.names(infosub_L))

# Calculate DESeq object
dds_L <- DESeqDataSetFromMatrix(countData = countsub_L,
                              colData = infosub_L,
                              design = ~ temp_treatment) 

# Run differential expression analysis 
# (Note that this DESeq() function runs all necessary steps, including data normalization, 
# estimating size factors, estimating dispersions, gene-wise dispersion estimates, mean-dispersion 
# relationship, final dispersion estimates, fitting model, and testing)
dds_L <- DESeq(dds_L)
resultsNames(dds_L) # lists the coefficients
[1] "Intercept"              "temp_treatment_5_vs_0"  "temp_treatment_9_vs_0" 
[4] "temp_treatment_16_vs_0"
plotDispEsts(dds_L)

2.2 PCA visualization

# Generate PCAs
# top 500 most variable genes
pca_L_500<- plotPCA(vst(dds_L), intgroup = c("temp_treatment"), returnData=TRUE)
percentVar_L_500 <- round(100*attr(pca_L_500, "percentVar"))
# merge with metadata sheet so we can plot using other features
pca_L_500 <- subset(pca_L_500, select=-temp_treatment) #remove the temp_treatment column, which will be a duplicate post-merge
pca_L_500 <- merge(pca_L_500, cod_sample_info, by.x = "name", by.y = "row.names")

# top 1000 most variable genes
pca_L_1000 <- plotPCA(vst(dds_L), intgroup = c("temp_treatment"), returnData=TRUE, ntop=1000)
percentVar_L_1000 <- round(100*attr(pca_L_1000, "percentVar"))
# merge with metadata sheet so we can plot using other features
pca_L_1000 <- subset(pca_L_1000, select=-temp_treatment) #remove the temp_treatment column, which will be a duplicate post-merge
pca_L_1000 <- merge(pca_L_1000, cod_sample_info, by.x = "name", by.y = "row.names")

# all genes
pca_L_all <- plotPCA(vst(dds_L), intgroup = c("temp_treatment"), returnData=TRUE, ntop=nrow(assay(vst(dds_L))))
percentVar_L_all <- round(100*attr(pca_L_all, "percentVar"))
# merge with metadata sheet so we can plot using other features
pca_L_all <- subset(pca_L_all, select=-temp_treatment) #remove the temp_treatment column, which will be a duplicate post-merge
pca_L_all <- merge(pca_L_all, cod_sample_info, by.x = "name", by.y = "row.names")

# Assign specific colors to each temperature treatment level
temp_colors <- c(
  "0" = "darkblue",
  "5" = "royalblue1",
  "9" = "green",
  "16" = "orangered") 

# Plot PCAs
p.L.500 <- ggplot(pca_L_500, aes(PC1, PC2, color=temp_treatment)) + 
  geom_point(size=4, alpha = 5/10) +
  ggtitle("Liver, top 500 most variable genes") +
  xlab(paste0("PC1: ",percentVar_L_500[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar_L_500[2],"% variance")) + 
  coord_fixed() +
  scale_color_manual(values=temp_colors)+
  stat_ellipse()

p.L.500.SLdiff <- ggplot(pca_L_500, aes(PC1, PC2, color=temp_treatment, size=SL_diff_mm)) + 
  geom_point(alpha = 0.5) +
  ggtitle("Liver, top 500 most variable genes") +
  xlab(paste0("PC1: ", percentVar_L_500[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar_L_500[2], "% variance")) + 
  coord_fixed() +
  scale_color_manual(values = temp_colors) +
  scale_size_continuous() +  # Add this line to control the size of points
  stat_ellipse()

p.L.500.WWTdiff <- ggplot(pca_L_500, aes(PC1, PC2, color=temp_treatment, size=WWT_diff_g)) + 
  geom_point(alpha = 0.5) +
  ggtitle("Liver, top 500 most variable genes") +
  xlab(paste0("PC1: ", percentVar_L_500[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar_L_500[2], "% variance")) + 
  coord_fixed() +
  scale_color_manual(values = temp_colors) +
  scale_size_continuous() +  # Add this line to control the size of points
  stat_ellipse()

p.L.1000 <- ggplot(pca_L_1000, aes(PC1, PC2, color=temp_treatment)) + 
  geom_point(size=4, alpha = 5/10) +
  ggtitle("Liver, top 1000 most variable genes") +
  xlab(paste0("PC1: ",percentVar_L_1000[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar_L_1000[2],"% variance")) + 
  coord_fixed() +
  scale_color_manual(values=temp_colors)+
  stat_ellipse()

p.L.1000.SLdiff <- ggplot(pca_L_1000, aes(PC1, PC2, color=temp_treatment, size=SL_diff_mm)) + 
  geom_point(alpha = 0.5) +
  ggtitle("Liver, top 1000 most variable genes") +
  xlab(paste0("PC1: ", percentVar_L_500[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar_L_500[2], "% variance")) + 
  coord_fixed() +
  scale_color_manual(values = temp_colors) +
  scale_size_continuous() +  # Add this line to control the size of points
  stat_ellipse()

p.L.1000.WWTdiff <- ggplot(pca_L_1000, aes(PC1, PC2, color=temp_treatment, size=WWT_diff_g)) + 
  geom_point(alpha = 0.5) +
  ggtitle("Liver, top 1000 most variable genes") +
  xlab(paste0("PC1: ", percentVar_L_500[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar_L_500[2], "% variance")) + 
  coord_fixed() +
  scale_color_manual(values = temp_colors) +
  scale_size_continuous() +  # Add this line to control the size of points
  stat_ellipse()

p.L.all <- ggplot(pca_L_all, aes(PC1, PC2, color=temp_treatment)) + 
  geom_point(size=4, alpha = 5/10) +
  ggtitle("Liver, all genes") +
  xlab(paste0("PC1: ",percentVar_L_all[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar_L_all[2],"% variance")) + 
  coord_fixed() +
  scale_color_manual(values=temp_colors)+
  stat_ellipse()

p.L.all.SLdiff <- ggplot(pca_L_all, aes(PC1, PC2, color=temp_treatment, size=SL_diff_mm)) + 
  geom_point(alpha = 0.5) +
  ggtitle("Liver, all genes") +
  xlab(paste0("PC1: ", percentVar_L_500[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar_L_500[2], "% variance")) + 
  coord_fixed() +
  scale_color_manual(values = temp_colors) +
  scale_size_continuous() +  # Add this line to control the size of points
  stat_ellipse()

p.L.all.WWTdiff <- ggplot(pca_L_all, aes(PC1, PC2, color=temp_treatment, size=WWT_diff_g)) + 
  geom_point(alpha = 0.5) +
  ggtitle("Liver, all genes") +
  xlab(paste0("PC1: ", percentVar_L_500[1], "% variance")) +
  ylab(paste0("PC2: ", percentVar_L_500[2], "% variance")) + 
  coord_fixed() +
  scale_color_manual(values = temp_colors) +
  scale_size_continuous() +  # Add this line to control the size of points
  stat_ellipse()

# View PCAs
p.L.500

p.L.500.SLdiff

p.L.500.WWTdiff

p.L.1000

p.L.1000.SLdiff

p.L.1000.WWTdiff

p.L.all

p.L.all.SLdiff

p.L.all.WWTdiff

# Export PCAs as pngs
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/PCA_L_500.png",
         plot   = p.L.500,
         res    = 600,
         width  = 6000,
         height = 4000)

ggexport(filename = "../output/07-cod-RNAseq-DESeq2/PCA_L_1000.png",
         plot   = p.L.1000,
         res    = 600,
         width  = 6000,
         height = 4000)

ggexport(filename = "../output/07-cod-RNAseq-DESeq2/PCA_L_all.png",
         plot   = p.L.all,
         res    = 600,
         width  = 6000,
         height = 4000)

3 Liver tissue, 9C v. 16C

The 9*C temperature treatment is effectively our “control,” as it represents the ambient temperature that wild juvenile Pacific cod would experience.

# liver tissue, temperatures 9 vs. 16 

# Filter data
infosub_L.9.16 <- cod_sample_info %>% filter(tissue_type == "Liver" & (temp_treatment == "9" | temp_treatment == "16"))
countsub_L.9.16 <- subset(cod_counts_data, select=row.names(infosub_L.9.16))

# Calculate DESeq object
dds_L.9.16 <- DESeqDataSetFromMatrix(countData = countsub_L.9.16,
                              colData = infosub_L.9.16,
                              design = ~ temp_treatment)

dds_L.9.16 <- DESeq(dds_L.9.16)
resultsNames(dds_L.9.16) # lists the coefficients
[1] "Intercept"              "temp_treatment_16_vs_9"
plotDispEsts(dds_L.9.16)

# Filtering: keep genes that have at least 10 counts across 1/3 of the samples - https://support.bioconductor.org/p/110307/
keep <- rowSums(DESeq2::counts(dds_L.9.16) >= 10) >= ncol(countsub_L.9.16)/3
dds_L.9.16<- dds_L.9.16[keep,]

# Generate Contrasts
contrast_list_L.9.16        <- c("temp_treatment", "16", "9") # order is important: factor, treatment group, control
res_table_L.9.16_noshrink <- results(dds_L.9.16, contrast=contrast_list_L.9.16, alpha = 0.05)

res_table_L.9.16_norm     <- lfcShrink(dds_L.9.16,
                                       coef=2,
                                       type="normal") # lfcThreshold = 0.585)  # a lfc threshold of 1 = 2-fold change, 0.585 = 1.5-fold change
res_table_L.9.16_apeglm   <- lfcShrink(dds_L.9.16,
                                       coef=2, 
                                       type="apeglm") # lfcThreshold = 0.585)  # a lfc threshold of 1 = 2-fold change, 0.585 = 1.5-fold change
res_table_L.9.16_ashr     <- lfcShrink(dds_L.9.16,
                                       coef=2, 
                                       type="ashr")
# Generate MA plots
par(mfrow=c(2,2), mar=c(4,4,2,1))
xlim <- c(1,1e5); ylim <- c(-4,4)
DESeq2::plotMA(res_table_L.9.16_noshrink, xlim=xlim, ylim=ylim, main="no shrink")
DESeq2::plotMA(res_table_L.9.16_norm, xlim=xlim, ylim=ylim, main="normal")
DESeq2::plotMA(res_table_L.9.16_apeglm, xlim=xlim, ylim=ylim, main="apeglm")
DESeq2::plotMA(res_table_L.9.16_ashr, xlim=xlim, ylim=ylim, main="ashr")

# Examine results formatting
res_table_L.9.16_norm %>% data.frame() %>% head()
                baseMean log2FoldChange     lfcSE        stat      pvalue
XM_060040253.1 2327.5126    0.165359455 0.1639051  1.00886280 0.313040436
XM_060042128.1  235.2778   -0.480849032 0.1613357 -2.98063209 0.002876542
XM_060066729.1 1102.9999    0.463245207 0.2728022  1.69785341 0.089535433
XM_060048268.1   87.8240   -0.006211092 0.2620379 -0.02370511 0.981087830
XM_060056224.1   14.5507    0.020946723 0.3001896  0.06977496 0.944372781
XM_060067663.1  249.9426    0.005196508 0.1283411  0.04048782 0.967704216
                     padj
XM_060040253.1 0.56255857
XM_060042128.1 0.02019223
XM_060066729.1 0.24954575
XM_060048268.1 0.99295424
XM_060056224.1 0.97937829
XM_060067663.1 0.98886396

Note that the metric we want to use to identify significantly expressed genes is the padj values, NOT the pvalue. padj are p-values corrected for multiple testing (default method is the Benjamini and Hochberg method).

summary(res_table_L.9.16_noshrink)

out of 21414 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 1785, 8.3%
LFC < 0 (down)     : 2320, 11%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.16_norm)

out of 21414 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2315, 11%
LFC < 0 (down)     : 2929, 14%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.16_apeglm)

out of 21414 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2315, 11%
LFC < 0 (down)     : 2929, 14%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.16_ashr)

out of 21414 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2316, 11%
LFC < 0 (down)     : 2928, 14%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

3.1 Extracting significantly expressed genes

padj.cutoff <- 0.05
lfc.cutoff <- 0.58

# Convert results table into tibble
res_table_L.9.16_norm_tb <- res_table_L.9.16_norm %>%
  data.frame() %>%
  rownames_to_column(var="gene") %>%
  as_tibble()

# subset that table to only keep the significant genes using our pre-defined thresholds:
sig_L.9.16_norm_noLFCcutoff <- res_table_L.9.16_norm_tb %>%
  filter(padj < padj.cutoff)

sig_L.9.16_norm <- sig_L.9.16_norm_noLFCcutoff %>% 
  filter(abs(log2FoldChange) > lfc.cutoff)

head(sig_L.9.16_norm_noLFCcutoff)
# A tibble: 6 × 7
  gene           baseMean log2FoldChange lfcSE  stat        pvalue        padj
  <chr>             <dbl>          <dbl> <dbl> <dbl>         <dbl>       <dbl>
1 XM_060042128.1    235.          -0.481 0.161 -2.98 0.00288       0.0202     
2 XM_060072015.1    216.           0.765 0.128  5.96 0.00000000245 0.000000192
3 XM_060048303.1     92.0         -1.00  0.317 -3.19 0.00143       0.0119     
4 XM_060038104.1    369.           0.634 0.212  2.99 0.00281       0.0199     
5 XM_060068449.1     95.9          0.580 0.120  4.85 0.00000123    0.0000384  
6 XM_060038440.1    226.           0.971 0.192  5.07 0.000000408   0.0000152  
paste("Number of significant DEGs for 9C v 16C:", nrow(sig_L.9.16_norm_noLFCcutoff), "(padj<", padj.cutoff, ")")
[1] "Number of significant DEGs for 9C v 16C: 4105 (padj< 0.05 )"
head(sig_L.9.16_norm)
# A tibble: 6 × 7
  gene           baseMean log2FoldChange lfcSE  stat        pvalue        padj
  <chr>             <dbl>          <dbl> <dbl> <dbl>         <dbl>       <dbl>
1 XM_060072015.1    216.           0.765 0.128  5.96 0.00000000245 0.000000192
2 XM_060048303.1     92.0         -1.00  0.317 -3.19 0.00143       0.0119     
3 XM_060038104.1    369.           0.634 0.212  2.99 0.00281       0.0199     
4 XM_060068449.1     95.9          0.580 0.120  4.85 0.00000123    0.0000384  
5 XM_060038440.1    226.           0.971 0.192  5.07 0.000000408   0.0000152  
6 XM_060056947.1     38.7         -0.584 0.157 -3.72 0.000202      0.00252    
paste("Number of significant DEGs for 9C v 16C:", nrow(sig_L.9.16_norm), "(padj<", padj.cutoff, ", log-fold change >", lfc.cutoff, ")")
[1] "Number of significant DEGs for 9C v 16C: 2790 (padj< 0.05 , log-fold change > 0.58 )"
write.table(sig_L.9.16_norm_noLFCcutoff, file = "../output/07-cod-RNAseq-DESeq2/Gmac_DEGs_sig_L.9.16_norm_noLFCcutoff.tab", sep = "\t",
            row.names = TRUE, col.names = NA)

write.table(sig_L.9.16_norm, file = "../output/07-cod-RNAseq-DESeq2/Gmac_DEGs_sig_L.9.16_norm.tab", sep = "\t",
            row.names = TRUE, col.names = NA)

3.2 Heatmap

For DEGs based on adjusted p-value and log fold-change

# Retrieve normalized counts matrix
dds_L.9.16_norm_counts <- counts(dds_L.9.16, normalized=TRUE)

# Extract normalized expression for significant genes
norm_sig_L.9.16 <- dds_L.9.16_norm_counts %>% 
  data.frame() %>%
  filter(row.names(dds_L.9.16_norm_counts) %in% sig_L.9.16_norm$gene)

head(norm_sig_L.9.16)
                 sample_1 sample_10 sample_100 sample_107 sample_108 sample_109
XM_060072015.1  380.28252 277.19091  205.48115  114.72825  182.94008  136.36096
XM_060048303.1   26.41963  16.73331   81.99488  168.55137  128.45949  198.93756
XM_060038104.1 1320.98138 345.57921  321.06429  175.63336  132.47385  346.50627
XM_060068449.1  124.09219 122.95345   81.99488   52.40673   94.05070   71.91640
XM_060038440.1  208.15464 123.68098  193.62646  127.47583   90.03634  239.09867
XM_060056947.1   23.21725  27.64634   37.53982   42.49194   51.61319   50.43487
               sample_11 sample_110 sample_12 sample_13 sample_18 sample_19
XM_060072015.1 264.85604  230.05618 253.69608 250.76618 296.20392 202.79083
XM_060048303.1  39.59642  215.56445  24.77167  25.32167  23.61759  29.26878
XM_060038104.1 437.32044  214.65872 289.57229 416.58225 575.67872 277.00809
XM_060068449.1 124.06878  117.74529 124.71255 146.21220 127.92861  70.03601
XM_060038440.1 233.17891  211.03578 232.34119 369.20623 295.21986 249.82994
XM_060056947.1  34.31690   48.00385  35.02202  32.67312  30.50605  30.31409
                sample_2 sample_20 sample_21 sample_28 sample_29  sample_3
XM_060072015.1 378.08611 255.72267 258.99186 286.39780 237.48616 224.62210
XM_060048303.1 103.11439  17.41091  28.77687  78.69077  48.44718  14.20535
XM_060038104.1 348.92244 375.42264 259.92015 267.18262 318.23145 213.96809
XM_060068449.1 131.23650 103.37725 122.53378 134.50632  78.84540 133.17516
XM_060038440.1 218.72750 207.84268 241.35442 570.96559 189.03898 614.38139
XM_060056947.1  44.78706  28.29272  25.99201  43.00542  13.29922  29.29853
               sample_30   sample_4  sample_5 sample_78 sample_79 sample_80
XM_060072015.1 242.03005  295.29212 304.52826 152.17854 160.56004 144.73819
XM_060048303.1  87.87553   74.05739  77.20435  77.14607 154.42398 114.93915
XM_060038104.1 257.66892 1343.34477 522.41609 283.22118 294.53051 266.06285
XM_060068449.1 109.47205  147.17734 105.51261  68.69170  65.45122 107.48939
XM_060038440.1 192.87933  285.91776 223.03478 136.32661  93.06346 100.03963
XM_060056947.1  19.36240   37.49741  24.87696  36.98784  38.86166  51.08407
               sample_83 sample_88 sample_90 sample_91 sample_92 sample_97
XM_060072015.1 227.38728  84.49904  88.17124 165.19670 202.95145 135.94380
XM_060048303.1 151.16808   0.00000   0.00000  70.01193 179.07481 172.48784
XM_060038104.1 308.68777 224.52603 490.09470 368.15264 168.33032 339.12863
XM_060068449.1  73.67856  48.28517  74.43027 106.98453  74.01759  43.85284
XM_060038440.1 196.89960  97.77746 182.06789 124.29085 105.05722 238.26710
XM_060056947.1  67.32696  21.72833  53.81881  40.90585  41.78412  46.77636
               sample_98 sample_99 sample_RESUB.116 sample_RESUB.36
XM_060072015.1  59.76367 181.06706         213.3480       293.43784
XM_060048303.1   0.00000 243.17727         215.2032        91.16515
XM_060038104.1 106.37933 307.39291         309.8184       280.61774
XM_060068449.1  50.20148  70.53193          95.5428        74.07169
XM_060038440.1 154.19026 154.74917         115.9500       787.72391
XM_060056947.1 111.16042  34.73961          24.1176        35.61139
               sample_RESUB.94
XM_060072015.1       179.49963
XM_060048303.1       242.37006
XM_060038104.1       413.66921
XM_060068449.1        78.36025
XM_060038440.1        93.85006
XM_060056947.1        39.18012
# Annotate heatmap
annotation <- infosub_L.9.16 %>% 
    dplyr::select(temp_treatment)

# Set a color palette
heat_colors <- rev(brewer.pal(12, "RdYlBu"))

# Run pheatmap
h.L.9.16 <- pheatmap(norm_sig_L.9.16, 
                     color = heat_colors, 
                     cluster_rows = T, 
                     show_rownames = F,
                     annotation = annotation, 
                     border_color = NA, 
                     fontsize = 10,
                     scale = "row", 
                     fontsize_row = 10, 
                     height = 30,
                     main = "Normalized Significant Expression, Liver, 9*C and 16*C")

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/heatmap_L.9.16_norm_sig.png",
         plot   = h.L.9.16,
         res    = 600,
         width  = 5000,
         height = 5000)

Note the argument scale="row" was included, so the values plotted in the heat map are Z-scores, rather thn the normalized count value. This vastly improves the color visualization.

For DEGs based on adjusted p-value only

# Extract normalized expression for significant genes
norm_sig_L.9.16_noLFCcutoff <- dds_L.9.16_norm_counts %>% 
  data.frame() %>%
  filter(row.names(dds_L.9.16_norm_counts) %in% sig_L.9.16_norm_noLFCcutoff$gene)

head(norm_sig_L.9.16_noLFCcutoff)
                 sample_1 sample_10 sample_100 sample_107 sample_108 sample_109
XM_060042128.1  208.15464 157.14760  239.06941  526.90009  155.98652   316.6189
XM_060072015.1  380.28252 277.19091  205.48115  114.72825  182.94008   136.3610
XM_060048303.1   26.41963  16.73331   81.99488  168.55137  128.45949   198.9376
XM_060038104.1 1320.98138 345.57921  321.06429  175.63336  132.47385   346.5063
XM_060068449.1  124.09219 122.95345   81.99488   52.40673   94.05070    71.9164
XM_060038440.1  208.15464 123.68098  193.62646  127.47583   90.03634   239.0987
               sample_11 sample_110 sample_12 sample_13 sample_18 sample_19
XM_060042128.1 200.62185   267.1912 179.38107 173.98435 180.08411 270.73621
XM_060072015.1 264.85604   230.0562 253.69608 250.76618 296.20392 202.79083
XM_060048303.1  39.59642   215.5644  24.77167  25.32167  23.61759  29.26878
XM_060038104.1 437.32044   214.6587 289.57229 416.58225 575.67872 277.00809
XM_060068449.1 124.06878   117.7453 124.71255 146.21220 127.92861  70.03601
XM_060038440.1 233.17891   211.0358 232.34119 369.20623 295.21986 249.82994
               sample_2 sample_20 sample_21 sample_28 sample_29  sample_3
XM_060042128.1 219.7691 186.07905 170.80467 185.74682 161.49059 181.11821
XM_060072015.1 378.0861 255.72267 258.99186 286.39780 237.48616 224.62210
XM_060048303.1 103.1144  17.41091  28.77687  78.69077  48.44718  14.20535
XM_060038104.1 348.9224 375.42264 259.92015 267.18262 318.23145 213.96809
XM_060068449.1 131.2365 103.37725 122.53378 134.50632  78.84540 133.17516
XM_060038440.1 218.7275 207.84268 241.35442 570.96559 189.03898 614.38139
               sample_30   sample_4  sample_5 sample_78 sample_79 sample_80
XM_060042128.1 184.68755  178.11271 194.72652 233.55179 215.78451  233.0711
XM_060072015.1 242.03005  295.29212 304.52826 152.17854 160.56004  144.7382
XM_060048303.1  87.87553   74.05739  77.20435  77.14607 154.42398  114.9392
XM_060038104.1 257.66892 1343.34477 522.41609 283.22118 294.53051  266.0629
XM_060068449.1 109.47205  147.17734 105.51261  68.69170  65.45122  107.4894
XM_060038440.1 192.87933  285.91776 223.03478 136.32661  93.06346  100.0396
               sample_83 sample_88 sample_90 sample_91 sample_92 sample_97
XM_060042128.1 299.79553 310.23220 400.77838 172.27656 179.07481 564.23987
XM_060072015.1 227.38728  84.49904  88.17124 165.19670 202.95145 135.94380
XM_060048303.1 151.16808   0.00000   0.00000  70.01193 179.07481 172.48784
XM_060038104.1 308.68777 224.52603 490.09470 368.15264 168.33032 339.12863
XM_060068449.1  73.67856  48.28517  74.43027 106.98453  74.01759  43.85284
XM_060038440.1 196.89960  97.77746 182.06789 124.29085 105.05722 238.26710
               sample_98 sample_99 sample_RESUB.116 sample_RESUB.36
XM_060042128.1 438.66533 142.11658         115.0224       245.00635
XM_060072015.1  59.76367 181.06706         213.3480       293.43784
XM_060048303.1   0.00000 243.17727         215.2032        91.16515
XM_060038104.1 106.37933 307.39291         309.8184       280.61774
XM_060068449.1  50.20148  70.53193          95.5428        74.07169
XM_060038440.1 154.19026 154.74917         115.9500       787.72391
               sample_RESUB.94
XM_060042128.1       146.69767
XM_060072015.1       179.49963
XM_060048303.1       242.37006
XM_060038104.1       413.66921
XM_060068449.1        78.36025
XM_060038440.1        93.85006
# Annotate heatmap
annotation <- infosub_L.9.16 %>% 
    dplyr::select(temp_treatment)

# Set a color palette
heat_colors <- rev(brewer.pal(12, "RdYlBu"))

# Run pheatmap
h.L.9.16 <- pheatmap(norm_sig_L.9.16_noLFCcutoff, 
                     color = heat_colors, 
                     cluster_rows = T, 
                     show_rownames = F,
                     annotation = annotation, 
                     border_color = NA, 
                     fontsize = 10,
                     scale = "row", 
                     fontsize_row = 10, 
                     height = 30,
                     main = "Normalized Significant Expression (no LFC cutoff), Liver, 9*C and 16*C")

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/heatmap_L.9.16_norm_sig_noLFCcutoff.png",
         plot   = h.L.9.16,
         res    = 600,
         width  = 5000,
         height = 5000)

Note the argument scale="row" was included, so the values plotted in the heat map are Z-scores, rather thn the normalized count value. This vastly improves the color visualization.

3.3 Volcano plot

# Generate plot
v.L.9.16 <- 
  ggplot(res_table_L.9.16_norm_tb) +
  # Plot all
  geom_point(aes(x=log2FoldChange, y=-log10(padj),color="unchanged"),
             size=.5) +
  # Overlay all significantly upregulated in red
  geom_point(data = sig_L.9.16_norm[sig_L.9.16_norm$log2FoldChange > 0, ], 
             aes(x=log2FoldChange, y=-log10(padj), color="upregulated"), 
             size=.5) +
  # Overlay all significantly downregulated in blue
  geom_point(data = sig_L.9.16_norm[sig_L.9.16_norm$log2FoldChange < 0, ], 
             aes(x=log2FoldChange, y=-log10(padj), color="downregulated"), 
             size=.5) +
  ggtitle("Liver, 9*C and 16*C") +
  xlab("log2 fold change") + 
  ylab("-log10 adjusted p-value") +
  scale_x_continuous(limits = c(-4,4)) +
  scale_y_continuous(limits = c(0,30)) +
  scale_color_manual(values = c("unchanged" = "darkgrey", "upregulated" = "red", "downregulated" = "blue"),
                     labels = c("unchanged" = "Unchanged", "upregulated" = "Upregulated", "downregulated" = "Downregulated"),
                     name = NULL) +
  theme(legend.position = "top",
        plot.title = element_text(size = rel(1.5), hjust = 0.5),
        axis.title = element_text(size = rel(1.25)))

v.L.9.16

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/volcano_L.9.16.png",
         plot   = v.L.9.16,
         res    = 600,
         width  = 6000,
         height = 4000)

3.4 Plot expression of top DEGs across treatments

top15DEGs_L.9.16 <- sig_L.9.16_norm_noLFCcutoff %>%
  arrange(padj) %>%
  slice_head(n=15)

plot_gene_data <- function(geneName) {
  gene_data <- cod_countsdata_plus_sampleinfo %>%
    filter(gene == geneName)
  
  ggplot(data = gene_data, 
         aes(x = temp_treatment, y = count, color = factor(temp_treatment))) +
    geom_boxplot() +
    geom_point(position = position_jitter(width = 0.1), size = 2) +
    labs(title = geneName, x = "Sample", y = "Count", color = "Treatment") +
  scale_color_manual(values = temp_colors) +
    theme_minimal()
}


L.9.16_DEG1 <- plot_gene_data(top15DEGs_L.9.16[1, ]$gene)
L.9.16_DEG1

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG1.",top15DEGs_L.9.16[1, ]$gene,".png"), plot = L.9.16_DEG1, res = 600, width = 5000, height = 5000)

L.9.16_DEG2 <- plot_gene_data(top15DEGs_L.9.16[2, ]$gene)
L.9.16_DEG2

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG2.",top15DEGs_L.9.16[2, ]$gene,".png"), plot = L.9.16_DEG2, res = 600, width = 5000, height = 5000)

L.9.16_DEG3 <- plot_gene_data(top15DEGs_L.9.16[3, ]$gene)
L.9.16_DEG3

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG3.",top15DEGs_L.9.16[3, ]$gene,".png"), plot = L.9.16_DEG3, res = 600, width = 5000, height = 5000)

L.9.16_DEG4 <- plot_gene_data(top15DEGs_L.9.16[4, ]$gene)
L.9.16_DEG4

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG4.",top15DEGs_L.9.16[4, ]$gene,".png"), plot = L.9.16_DEG4, res = 600, width = 5000, height = 5000)

L.9.16_DEG5 <- plot_gene_data(top15DEGs_L.9.16[5, ]$gene)
L.9.16_DEG5

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG5.",top15DEGs_L.9.16[5, ]$gene,".png"), plot = L.9.16_DEG5, res = 600, width = 5000, height = 5000)

L.9.16_DEG6 <- plot_gene_data(top15DEGs_L.9.16[6, ]$gene)
L.9.16_DEG6

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG6.",top15DEGs_L.9.16[6, ]$gene,".png"), plot = L.9.16_DEG6, res = 600, width = 5000, height = 5000)

L.9.16_DEG7 <- plot_gene_data(top15DEGs_L.9.16[7, ]$gene)
L.9.16_DEG7

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG7.",top15DEGs_L.9.16[7, ]$gene,".png"), plot = L.9.16_DEG7, res = 600, width = 5000, height = 5000)

L.9.16_DEG8 <- plot_gene_data(top15DEGs_L.9.16[8, ]$gene)
L.9.16_DEG8

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG8.",top15DEGs_L.9.16[8, ]$gene,".png"), plot = L.9.16_DEG8, res = 600, width = 5000, height = 5000)

L.9.16_DEG9 <- plot_gene_data(top15DEGs_L.9.16[9, ]$gene)
L.9.16_DEG9

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG9.",top15DEGs_L.9.16[9, ]$gene,".png"), plot = L.9.16_DEG9, res = 600, width = 5000, height = 5000)

L.9.16_DEG10 <- plot_gene_data(top15DEGs_L.9.16[10, ]$gene)
L.9.16_DEG10

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG10.",top15DEGs_L.9.16[10, ]$gene,".png"), plot = L.9.16_DEG10, res = 600, width = 5000, height = 5000)

L.9.16_DEG11 <- plot_gene_data(top15DEGs_L.9.16[11, ]$gene)
L.9.16_DEG11

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG11.",top15DEGs_L.9.16[11, ]$gene,".png"), plot = L.9.16_DEG11, res = 600, width = 5000, height = 5000)

L.9.16_DEG12 <- plot_gene_data(top15DEGs_L.9.16[12, ]$gene)
L.9.16_DEG12

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG12.",top15DEGs_L.9.16[12, ]$gene,".png"), plot = L.9.16_DEG12, res = 600, width = 5000, height = 5000)

L.9.16_DEG13 <- plot_gene_data(top15DEGs_L.9.16[13, ]$gene)
L.9.16_DEG13

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG13.",top15DEGs_L.9.16[13, ]$gene,".png"), plot = L.9.16_DEG13, res = 600, width = 5000, height = 5000)

L.9.16_DEG14 <- plot_gene_data(top15DEGs_L.9.16[14, ]$gene)
L.9.16_DEG14

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG14.",top15DEGs_L.9.16[14, ]$gene,".png"), plot = L.9.16_DEG14, res = 600, width = 5000, height = 5000)

L.9.16_DEG15 <- plot_gene_data(top15DEGs_L.9.16[15, ]$gene)
L.9.16_DEG15

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.16_DEG15.",top15DEGs_L.9.16[15, ]$gene,".png"), plot = L.9.16_DEG15, res = 600, width = 5000, height = 5000)

4 Liver tissue, 9C v. 0C

The 9*C temperature treatment is effectively our “control,” as it represents the ambient temperature that wild juvenile Pacific cod would experience.

# liver tissue, temperatures 9 vs. 0 

# Filter data
infosub_L.9.0 <- cod_sample_info %>% filter(tissue_type == "Liver" & (temp_treatment == "9" | temp_treatment == "0"))
countsub_L.9.0 <- subset(cod_counts_data, select=row.names(infosub_L.9.0))

# Calculate DESeq object
dds_L.9.0 <- DESeqDataSetFromMatrix(countData = countsub_L.9.0,
                              colData = infosub_L.9.0,
                              design = ~ temp_treatment)

dds_L.9.0 <- DESeq(dds_L.9.0)
resultsNames(dds_L.9.0) # lists the coefficients
[1] "Intercept"             "temp_treatment_9_vs_0"
plotDispEsts(dds_L.9.0)

# Filtering: keep genes that have at least 10 counts across 1/3 of the samples - https://support.bioconductor.org/p/110307/
keep <- rowSums(DESeq2::counts(dds_L.9.0) >= 10) >= ncol(countsub_L.9.0)/3
dds_L.9.0<- dds_L.9.0[keep,]

# Generate Contrasts
contrast_list_L.9.0        <- c("temp_treatment", "0", "9") # order is important: factor, treatment group, control
res_table_L.9.0_noshrink <- results(dds_L.9.0, contrast=contrast_list_L.9.0, alpha = 0.05)

res_table_L.9.0_norm     <- lfcShrink(dds_L.9.0,
                                       coef=2,
                                       type="normal") # lfcThreshold = 0.585)  # a lfc threshold of 1 = 2-fold change, 0.585 = 1.5-fold change
res_table_L.9.0_apeglm   <- lfcShrink(dds_L.9.0,
                                       coef=2, 
                                       type="apeglm") # lfcThreshold = 0.585)  # a lfc threshold of 1 = 2-fold change, 0.585 = 1.5-fold change
res_table_L.9.0_ashr     <- lfcShrink(dds_L.9.0,
                                       coef=2, 
                                       type="ashr")
# Generate MA plots
par(mfrow=c(2,2), mar=c(4,4,2,1))
xlim <- c(1,1e5); ylim <- c(-4,4)
DESeq2::plotMA(res_table_L.9.0_noshrink, xlim=xlim, ylim=ylim, main="no shrink")
DESeq2::plotMA(res_table_L.9.0_norm, xlim=xlim, ylim=ylim, main="normal")
DESeq2::plotMA(res_table_L.9.0_apeglm, xlim=xlim, ylim=ylim, main="apeglm")
DESeq2::plotMA(res_table_L.9.0_ashr, xlim=xlim, ylim=ylim, main="ashr")

# Examine results formatting
res_table_L.9.0_norm %>% data.frame() %>% head()
                 baseMean log2FoldChange     lfcSE       stat       pvalue
XM_060040253.1 3122.82259     -0.7256493 0.1776386 -4.0848913 4.409746e-05
XM_060042128.1  285.77569      0.0649712 0.2031898  0.3197811 7.491343e-01
XM_060066729.1  702.36692      1.0038553 0.2230834  4.5001294 6.791210e-06
XM_060048268.1  164.24708     -0.4572041 0.4019688 -1.1534333 2.487326e-01
XM_060056224.1   13.64937      0.2793657 0.3190532  0.8748907 3.816334e-01
XM_060067663.1  306.31256     -0.3855980 0.1401494 -2.7512012 5.937717e-03
                       padj
XM_060040253.1 3.599217e-04
XM_060042128.1 8.706335e-01
XM_060066729.1 6.778697e-05
XM_060048268.1 4.511504e-01
XM_060056224.1 5.962076e-01
XM_060067663.1 2.490951e-02

Note that the metric we want to use to identify significantly expressed genes is the padj values, NOT the pvalue. padj are p-values corrected for multiple testing (default method is the Benjamini and Hochberg method).

summary(res_table_L.9.0_noshrink)

out of 21670 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 2955, 14%
LFC < 0 (down)     : 3025, 14%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.0_norm)

out of 21670 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3646, 17%
LFC < 0 (down)     : 3441, 16%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.0_apeglm)

out of 21670 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3646, 17%
LFC < 0 (down)     : 3441, 16%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.0_ashr)

out of 21670 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3645, 17%
LFC < 0 (down)     : 3442, 16%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

4.1 Extracting significantly expressed genes

padj.cutoff <- 0.05
lfc.cutoff <- 0.58

# Convert results table into tibble
res_table_L.9.0_norm_tb <- res_table_L.9.0_norm %>%
  data.frame() %>%
  rownames_to_column(var="gene") %>%
  as_tibble()

# subset that table to only keep the significant genes using our pre-defined thresholds:
sig_L.9.0_norm_noLFCcutoff <- res_table_L.9.0_norm_tb %>%
  filter(padj < padj.cutoff)

sig_L.9.0_norm <- sig_L.9.0_norm_noLFCcutoff %>% 
  filter(abs(log2FoldChange) > lfc.cutoff)

head(sig_L.9.0_norm_noLFCcutoff)
# A tibble: 6 × 7
  gene           baseMean log2FoldChange lfcSE   stat   pvalue     padj
  <chr>             <dbl>          <dbl> <dbl>  <dbl>    <dbl>    <dbl>
1 XM_060040253.1   3123.          -0.726 0.178  -4.08 4.41e- 5 3.60e- 4
2 XM_060066729.1    702.           1.00  0.223   4.50 6.79e- 6 6.78e- 5
3 XM_060067663.1    306.          -0.386 0.140  -2.75 5.94e- 3 2.49e- 2
4 XM_060068449.1    174.          -1.70  0.123 -13.8  2.94e-43 1.68e-40
5 XM_060038440.1    289.          -1.42  0.136 -10.4  3.03e-25 3.98e-23
6 XM_060041661.1     23.6         -1.14  0.419  -2.84 4.55e- 3 2.00e- 2
paste("Number of significant DEGs for 9C v 0C:", nrow(sig_L.9.0_norm_noLFCcutoff), "(padj<", padj.cutoff, ")")
[1] "Number of significant DEGs for 9C v 0C: 5980 (padj< 0.05 )"
head(sig_L.9.0_norm)
# A tibble: 6 × 7
  gene           baseMean log2FoldChange lfcSE   stat   pvalue     padj
  <chr>             <dbl>          <dbl> <dbl>  <dbl>    <dbl>    <dbl>
1 XM_060040253.1   3123.          -0.726 0.178  -4.08 4.41e- 5 3.60e- 4
2 XM_060066729.1    702.           1.00  0.223   4.50 6.79e- 6 6.78e- 5
3 XM_060068449.1    174.          -1.70  0.123 -13.8  2.94e-43 1.68e-40
4 XM_060038440.1    289.          -1.42  0.136 -10.4  3.03e-25 3.98e-23
5 XM_060041661.1     23.6         -1.14  0.419  -2.84 4.55e- 3 2.00e- 2
6 XM_060071337.1    770.           1.06  0.365   2.90 3.70e- 3 1.69e- 2
paste("Number of significant DEGs for 9C v 0C:", nrow(sig_L.9.0_norm), "(padj<", padj.cutoff, ", log-fold change >", lfc.cutoff, ")")
[1] "Number of significant DEGs for 9C v 0C: 4703 (padj< 0.05 , log-fold change > 0.58 )"
write.table(sig_L.9.0_norm_noLFCcutoff, file = "../output/07-cod-RNAseq-DESeq2/Gmac_DEGs_sig_L.9.0_norm_noLFCcutoff.tab", sep = "\t",
            row.names = TRUE, col.names = NA)

write.table(sig_L.9.0_norm, file = "../output/07-cod-RNAseq-DESeq2/Gmac_DEGs_sig_L.9.0_norm.tab", sep = "\t",
            row.names = TRUE, col.names = NA)

4.2 Heatmap

For DEGs based on adjusted p-value and LFC cutoff

# Retrieve normalized counts matrix
dds_L.9.0_norm_counts <- counts(dds_L.9.0, normalized=TRUE)

# Extract normalized expression for significant genes
norm_sig_L.9.0 <- dds_L.9.0_norm_counts %>% 
  data.frame() %>%
  filter(row.names(dds_L.9.0_norm_counts) %in% sig_L.9.0_norm$gene)

head(norm_sig_L.9.0)
               sample_100 sample_107 sample_108 sample_109 sample_110
XM_060040253.1 3154.38405 2218.39508 1975.71558 2884.64070  2727.0654
XM_060066729.1 1396.49987  460.47822  649.27391  955.58074   814.6801
XM_060068449.1   88.48053   55.49738   97.33174   76.56578   127.7544
XM_060038440.1  208.94196  134.99362   93.17733  254.55637   228.9752
XM_060041661.1    0.00000    0.00000   36.20266   24.85902     0.0000
XM_060071337.1 1300.55713  580.47255  794.67803 1603.90398  1375.8168
                 sample_37  sample_38  sample_39 sample_40  sample_47 sample_48
XM_060040253.1 2925.553844 3678.59851 3415.75582 4110.9561 4871.97351 1484.6904
XM_060066729.1  368.343275  282.50675  350.43721  321.2764  416.83430  370.5844
XM_060068449.1  360.269997  204.36658  307.13606  278.6699  255.62274  295.2910
XM_060038440.1  443.021089  435.35234  537.73986  365.0345  481.85332  530.5827
XM_060041661.1   40.366386   19.74971   62.43422    0.0000  103.31790    0.0000
XM_060071337.1    6.054958 1233.92765  118.82641  673.6441   73.92574  119.9987
                sample_49  sample_50  sample_57  sample_58  sample_59
XM_060040253.1 2887.89685 4224.67414 3721.09905 3249.34617 3302.17448
XM_060066729.1  703.35219  307.57799  447.33678  515.26592  492.03549
XM_060068449.1  363.21186  260.83820  246.88656  250.49851  189.08370
XM_060038440.1  543.16983  317.37827  340.53319  514.47320  351.00621
XM_060041661.1   41.52876   39.95498   50.30604   42.01399   48.05442
XM_060071337.1  107.44743 1076.52296  129.24782   89.57700  688.43182
                sample_60  sample_67  sample_68  sample_69  sample_70
XM_060040253.1 4580.17338 4591.08604 5428.83855 3998.64605 3333.77677
XM_060066729.1  436.55399  343.63446  527.80375  341.95318  697.03470
XM_060068449.1  269.61680  267.12716  249.35089  261.58630  171.71846
XM_060038440.1  313.33844  393.55871  472.24546  293.89064  443.01331
XM_060041661.1   71.54451   35.01181   98.54982   14.18239   46.73994
XM_060071337.1  490.21237  334.55732  868.42897  647.66247  227.60317
                sample_78  sample_79 sample_80 sample_83  sample_88  sample_90
XM_060040253.1 2074.17667 2948.81439 2879.1082 1578.5019 2220.99585 2883.29832
XM_060066729.1  551.99863 1000.15695  848.5911  524.3700  435.48938  184.14342
XM_060068449.1   72.48467   70.34071  114.1248   78.1837   51.23405   78.74554
XM_060038440.1  143.85419  100.01569  106.2151  208.9392  103.74894  192.62371
XM_060041661.1   16.72723    0.00000    0.0000    0.0000    0.00000    0.00000
XM_060071337.1 4413.75873  242.89526  446.3296  373.3946  190.84682   38.76704
                sample_91  sample_92  sample_97 sample_98  sample_99
XM_060040253.1 2021.36914 2841.31441  647.84286 862.39177 1288.42338
XM_060066729.1 1235.18772  795.05260  779.86771 297.55038 2481.52972
XM_060068449.1  114.35366   79.89183   46.05518  52.95388   73.40507
XM_060038440.1  132.85205  113.39486  250.23314 162.64406  161.05292
XM_060041661.1   21.02089    0.00000    0.00000   0.00000    0.00000
XM_060071337.1 2751.21457  403.32490 1097.64844 148.77519 2643.67824
               sample_RESUB.116 sample_RESUB.76 sample_RESUB.94
XM_060040253.1       3133.42480       7466.3389      3687.34971
XM_060066729.1       1924.22389        647.2300      1678.40717
XM_060068449.1        102.00466        399.8247        85.10791
XM_060038440.1        123.79207        518.0049       101.93157
XM_060041661.1         14.85505          0.0000         0.00000
XM_060071337.1        875.45750        175.6136       613.56866
# Annotate heatmap
annotation <- infosub_L.9.0 %>% 
    dplyr::select(temp_treatment)

# Set a color palette
heat_colors <- rev(brewer.pal(12, "RdYlBu"))

# Run pheatmap
h.L.9.0 <- pheatmap(norm_sig_L.9.0, 
                     color = heat_colors, 
                     cluster_rows = T, 
                     show_rownames = F,
                     annotation = annotation, 
                     border_color = NA, 
                     fontsize = 10,
                     scale = "row", 
                     fontsize_row = 10, 
                     height = 30,
                     main = "Normalized Significant Expression, Liver, 9*C and 0*C")

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/heatmap_L.9.0_norm_sig.png",
         plot   = h.L.9.0,
         res    = 600,
         width  = 5000,
         height = 5000)

Note the argument scale="row" was included, so the values plotted in the heat map are Z-scores, rather thn the normalized count value. This vastly improves the color visualization.

For DEGs based on adjusted p-value only

# Extract normalized expression for significant genes
norm_sig_L.9.0_noLFCcutoff <- dds_L.9.0_norm_counts %>% 
  data.frame() %>%
  filter(row.names(dds_L.9.0_norm_counts) %in% sig_L.9.0_norm_noLFCcutoff$gene)

head(norm_sig_L.9.0_noLFCcutoff)
               sample_100 sample_107 sample_108 sample_109 sample_110
XM_060040253.1 3154.38405 2218.39508 1975.71558 2884.64070  2727.0654
XM_060066729.1 1396.49987  460.47822  649.27391  955.58074   814.6801
XM_060067663.1  356.05416  113.99461  283.09292  256.54509   294.8179
XM_060068449.1   88.48053   55.49738   97.33174   76.56578   127.7544
XM_060038440.1  208.94196  134.99362   93.17733  254.55637   228.9752
XM_060041661.1    0.00000    0.00000   36.20266   24.85902     0.0000
                sample_37  sample_38  sample_39 sample_40 sample_47 sample_48
XM_060040253.1 2925.55384 3678.59851 3415.75582 4110.9561 4871.9735 1484.6904
XM_060066729.1  368.34327  282.50675  350.43721  321.2764  416.8343  370.5844
XM_060067663.1  250.27159  249.87679  391.72436  392.6712  401.6929  142.3515
XM_060068449.1  360.27000  204.36658  307.13606  278.6699  255.6227  295.2910
XM_060038440.1  443.02109  435.35234  537.73986  365.0345  481.8533  530.5827
XM_060041661.1   40.36639   19.74971   62.43422    0.0000  103.3179    0.0000
                sample_49  sample_50  sample_57  sample_58  sample_59
XM_060040253.1 2887.89685 4224.67414 3721.09905 3249.34617 3302.17448
XM_060066729.1  703.35219  307.57799  447.33678  515.26592  492.03549
XM_060067663.1  341.45870  430.45841  321.95865  493.86257  267.43330
XM_060068449.1  363.21186  260.83820  246.88656  250.49851  189.08370
XM_060038440.1  543.16983  317.37827  340.53319  514.47320  351.00621
XM_060041661.1   41.52876   39.95498   50.30604   42.01399   48.05442
                sample_60  sample_67  sample_68  sample_69  sample_70
XM_060040253.1 4580.17338 4591.08604 5428.83855 3998.64605 3333.77677
XM_060066729.1  436.55399  343.63446  527.80375  341.95318  697.03470
XM_060067663.1  431.91684  359.84363  423.30125  364.01467  338.35650
XM_060068449.1  269.61680  267.12716  249.35089  261.58630  171.71846
XM_060038440.1  313.33844  393.55871  472.24546  293.89064  443.01331
XM_060041661.1   71.54451   35.01181   98.54982   14.18239   46.73994
                sample_78  sample_79 sample_80 sample_83  sample_88  sample_90
XM_060040253.1 2074.17667 2948.81439 2879.1082 1578.5019 2220.99585 2883.29832
XM_060066729.1  551.99863 1000.15695  848.5911  524.3700  435.48938  184.14342
XM_060067663.1  307.78105  268.17395  270.0576  233.2031  192.12767  212.00723
XM_060068449.1   72.48467   70.34071  114.1248   78.1837   51.23405   78.74554
XM_060038440.1  143.85419  100.01569  106.2151  208.9392  103.74894  192.62371
XM_060041661.1   16.72723    0.00000    0.0000    0.0000    0.00000    0.00000
                sample_91  sample_92 sample_97 sample_98  sample_99
XM_060040253.1 2021.36914 2841.31441 647.84286 862.39177 1288.42338
XM_060066729.1 1235.18772  795.05260 779.86771 297.55038 2481.52972
XM_060067663.1  369.12689  282.19857 216.45934 127.34148  341.82661
XM_060068449.1  114.35366   79.89183  46.05518  52.95388   73.40507
XM_060038440.1  132.85205  113.39486 250.23314 162.64406  161.05292
XM_060041661.1   21.02089    0.00000   0.00000   0.00000    0.00000
               sample_RESUB.116 sample_RESUB.76 sample_RESUB.94
XM_060040253.1       3133.42480       7466.3389      3687.34971
XM_060066729.1       1924.22389        647.2300      1678.40717
XM_060067663.1        374.34721        343.4958       277.09552
XM_060068449.1        102.00466        399.8247        85.10791
XM_060038440.1        123.79207        518.0049       101.93157
XM_060041661.1         14.85505          0.0000         0.00000
# Annotate heatmap
annotation <- infosub_L.9.0 %>% 
    dplyr::select(temp_treatment)

# Set a color palette
heat_colors <- rev(brewer.pal(12, "RdYlBu"))

# Run pheatmap
h.L.9.0 <- pheatmap(norm_sig_L.9.0_noLFCcutoff, 
                     color = heat_colors, 
                     cluster_rows = T, 
                     show_rownames = F,
                     annotation = annotation, 
                     border_color = NA, 
                     fontsize = 10,
                     scale = "row", 
                     fontsize_row = 10, 
                     height = 30,
                     main = "Normalized Significant Expression (no LFC cutoff), Liver, 9*C and 0*C")

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/heatmap_L.9.0_norm_sig_noLFCcutoff.png",
         plot   = h.L.9.0,
         res    = 600,
         width  = 5000,
         height = 5000)

4.3 Volcano plot

# Generate plot
v.L.9.0 <- 
  ggplot(res_table_L.9.0_norm_tb) +
  # Plot all
  geom_point(aes(x=log2FoldChange, y=-log10(padj),color="unchanged"),
             size=.5) +
  # Overlay all significantly upregulated in red
  geom_point(data = sig_L.9.0_norm[sig_L.9.0_norm$log2FoldChange > 0, ], 
             aes(x=log2FoldChange, y=-log10(padj), color="upregulated"), 
             size=.5) +
  # Overlay all significantly downregulated in blue
  geom_point(data = sig_L.9.0_norm[sig_L.9.0_norm$log2FoldChange < 0, ], 
             aes(x=log2FoldChange, y=-log10(padj), color="downregulated"), 
             size=.5) +
  ggtitle("Liver, 9*C and 0*C") +
  xlab("log2 fold change") + 
  ylab("-log10 adjusted p-value") +
  scale_x_continuous(limits = c(-4,4)) +
  scale_y_continuous(limits = c(0,30)) +
  scale_color_manual(values = c("unchanged" = "darkgrey", "upregulated" = "red", "downregulated" = "blue"),
                     labels = c("unchanged" = "Unchanged", "upregulated" = "Upregulated", "downregulated" = "Downregulated"),
                     name = NULL) +
  theme(legend.position = "top",
        plot.title = element_text(size = rel(1.5), hjust = 0.5),
        axis.title = element_text(size = rel(1.25)))

v.L.9.0

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/volcano_L.9.0.png",
         plot   = v.L.9.0,
         res    = 600,
         width  = 6000,
         height = 4000)

4.4 Plot expression of top DEGs across treatments

top15DEGs_L.9.0 <- sig_L.9.0_norm_noLFCcutoff %>%
  arrange(padj) %>%
  slice_head(n=15)

L.9.0_DEG1 <- plot_gene_data(top15DEGs_L.9.0[1, ]$gene)
L.9.0_DEG1

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG1.",top15DEGs_L.9.0[1, ]$gene,".png"), plot = L.9.0_DEG1, res = 600, width = 5000, height = 5000)

L.9.0_DEG2 <- plot_gene_data(top15DEGs_L.9.0[2, ]$gene)
L.9.0_DEG2

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG2.",top15DEGs_L.9.0[2, ]$gene,".png"), plot = L.9.0_DEG2, res = 600, width = 5000, height = 5000)

L.9.0_DEG3 <- plot_gene_data(top15DEGs_L.9.0[3, ]$gene)
L.9.0_DEG3

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG3.",top15DEGs_L.9.0[3, ]$gene,".png"), plot = L.9.0_DEG3, res = 600, width = 5000, height = 5000)

L.9.0_DEG4 <- plot_gene_data(top15DEGs_L.9.0[4, ]$gene)
L.9.0_DEG4

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG4.",top15DEGs_L.9.0[4, ]$gene,".png"), plot = L.9.0_DEG4, res = 600, width = 5000, height = 5000)

L.9.0_DEG5 <- plot_gene_data(top15DEGs_L.9.0[5, ]$gene)
L.9.0_DEG5

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG5.",top15DEGs_L.9.0[5, ]$gene,".png"), plot = L.9.0_DEG5, res = 600, width = 5000, height = 5000)

L.9.0_DEG6 <- plot_gene_data(top15DEGs_L.9.0[6, ]$gene)
L.9.0_DEG6

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG6.",top15DEGs_L.9.0[6, ]$gene,".png"), plot = L.9.0_DEG6, res = 600, width = 5000, height = 5000)

L.9.0_DEG7 <- plot_gene_data(top15DEGs_L.9.0[7, ]$gene)
L.9.0_DEG7

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG7.",top15DEGs_L.9.0[7, ]$gene,".png"), plot = L.9.0_DEG7, res = 600, width = 5000, height = 5000)

L.9.0_DEG8 <- plot_gene_data(top15DEGs_L.9.0[8, ]$gene)
L.9.0_DEG8

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG8.",top15DEGs_L.9.0[8, ]$gene,".png"), plot = L.9.0_DEG8, res = 600, width = 5000, height = 5000)

L.9.0_DEG9 <- plot_gene_data(top15DEGs_L.9.0[9, ]$gene)
L.9.0_DEG9

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG9.",top15DEGs_L.9.0[9, ]$gene,".png"), plot = L.9.0_DEG9, res = 600, width = 5000, height = 5000)

L.9.0_DEG10 <- plot_gene_data(top15DEGs_L.9.0[10, ]$gene)
L.9.0_DEG10

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG10.",top15DEGs_L.9.0[10, ]$gene,".png"), plot = L.9.0_DEG10, res = 600, width = 5000, height = 5000)

L.9.0_DEG11 <- plot_gene_data(top15DEGs_L.9.0[11, ]$gene)
L.9.0_DEG11

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG11.",top15DEGs_L.9.0[11, ]$gene,".png"), plot = L.9.0_DEG11, res = 600, width = 5000, height = 5000)

L.9.0_DEG12 <- plot_gene_data(top15DEGs_L.9.0[12, ]$gene)
L.9.0_DEG12

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG12.",top15DEGs_L.9.0[12, ]$gene,".png"), plot = L.9.0_DEG12, res = 600, width = 5000, height = 5000)

L.9.0_DEG13 <- plot_gene_data(top15DEGs_L.9.0[13, ]$gene)
L.9.0_DEG13

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG13.",top15DEGs_L.9.0[13, ]$gene,".png"), plot = L.9.0_DEG13, res = 600, width = 5000, height = 5000)

L.9.0_DEG14 <- plot_gene_data(top15DEGs_L.9.0[14, ]$gene)
L.9.0_DEG14

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG14.",top15DEGs_L.9.0[14, ]$gene,".png"), plot = L.9.0_DEG14, res = 600, width = 5000, height = 5000)

L.9.0_DEG15 <- plot_gene_data(top15DEGs_L.9.0[15, ]$gene)
L.9.0_DEG15

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.0_DEG15.",top15DEGs_L.9.0[15, ]$gene,".png"), plot = L.9.0_DEG15, res = 600, width = 5000, height = 5000)

5 Liver tissue, 9C v. 5C

The 9*C temperature treatment is effectively our “control,” as it represents the ambient temperature that wild juvenile Pacific cod would experience.

# liver tissue, temperatures 9 vs. 5 

# Filter data
infosub_L.9.5 <- cod_sample_info %>% filter(tissue_type == "Liver" & (temp_treatment == "9" | temp_treatment == "5"))
countsub_L.9.5 <- subset(cod_counts_data, select=row.names(infosub_L.9.5))

# Calculate DESeq object
dds_L.9.5 <- DESeqDataSetFromMatrix(countData = countsub_L.9.5,
                              colData = infosub_L.9.5,
                              design = ~ temp_treatment)

dds_L.9.5 <- DESeq(dds_L.9.5)
resultsNames(dds_L.9.5) # lists the coefficients
[1] "Intercept"             "temp_treatment_9_vs_5"
plotDispEsts(dds_L.9.5)

# Filtering: keep genes that have at least 10 counts across 1/3 of the samples - https://support.bioconductor.org/p/110307/
keep <- rowSums(DESeq2::counts(dds_L.9.5) >= 10) >= ncol(countsub_L.9.5)/3
dds_L.9.5<- dds_L.9.5[keep,]

# Generate Contrasts
contrast_list_L.9.5        <- c("temp_treatment", "5", "9") # order is important: factor, treatment group, control
res_table_L.9.5_noshrink <- results(dds_L.9.5, contrast=contrast_list_L.9.5, alpha = 0.05)

res_table_L.9.5_norm     <- lfcShrink(dds_L.9.5,
                                       coef=2,
                                       type="normal") # lfcThreshold = 0.585)  # a lfc threshold of 1 = 2-fold change, 0.585 = 1.5-fold change
res_table_L.9.5_apeglm   <- lfcShrink(dds_L.9.5,
                                       coef=2, 
                                       type="apeglm") # lfcThreshold = 0.585)  # a lfc threshold of 1 = 2-fold change, 0.585 = 1.5-fold change
res_table_L.9.5_ashr     <- lfcShrink(dds_L.9.5,
                                       coef=2, 
                                       type="ashr")
# Generate MA plots
par(mfrow=c(2,2), mar=c(4,4,2,1))
xlim <- c(1,1e5); ylim <- c(-4,4)
DESeq2::plotMA(res_table_L.9.5_noshrink, xlim=xlim, ylim=ylim, main="no shrink")
DESeq2::plotMA(res_table_L.9.5_norm, xlim=xlim, ylim=ylim, main="normal")
DESeq2::plotMA(res_table_L.9.5_apeglm, xlim=xlim, ylim=ylim, main="apeglm")
DESeq2::plotMA(res_table_L.9.5_ashr, xlim=xlim, ylim=ylim, main="ashr")

# Examine results formatting
res_table_L.9.5_norm %>% data.frame() %>% head()
                 baseMean log2FoldChange     lfcSE       stat     pvalue
XM_060040253.1 2306.40103    -0.35416518 0.1643030 -2.1554052 0.03113014
XM_060042128.1  236.38023     0.19703304 0.1788232  1.1022592 0.27034900
XM_060066729.1  762.06956     0.16619727 0.2334513  0.7120654 0.47642427
XM_060048268.1   92.04034    -0.05113841 0.1973887 -0.2584982 0.79602241
XM_060056224.1   11.59796     0.30174249 0.2626236  1.1522189 0.24923112
XM_060067663.1  250.22583    -0.24689780 0.1284776 -1.9214078 0.05468032
                    padj
XM_060040253.1 0.2135309
XM_060042128.1 0.6701601
XM_060066729.1 0.8338922
XM_060048268.1 0.9584280
XM_060056224.1 0.6468082
XM_060067663.1 0.2991018

Note that the metric we want to use to identify significantly expressed genes is the padj values, NOT the pvalue. padj are p-values corrected for multiple testing (default method is the Benjamini and Hochberg method).

summary(res_table_L.9.5_noshrink)

out of 21090 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 730, 3.5%
LFC < 0 (down)     : 697, 3.3%
outliers [1]       : 0, 0%
low counts [2]     : 409, 1.9%
(mean count < 8)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.5_norm)

out of 21090 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1015, 4.8%
LFC < 0 (down)     : 976, 4.6%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.5_apeglm)

out of 21090 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1015, 4.8%
LFC < 0 (down)     : 976, 4.6%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.5_ashr)

out of 21090 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1017, 4.8%
LFC < 0 (down)     : 974, 4.6%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

5.1 Extracting significantly expressed genes

padj.cutoff <- 0.05
lfc.cutoff <- 0.58

# Convert results table into tibble
res_table_L.9.5_norm_tb <- res_table_L.9.5_norm %>%
  data.frame() %>%
  rownames_to_column(var="gene") %>%
  as_tibble()

# subset that table to only keep the significant genes using our pre-defined thresholds:
sig_L.9.5_norm_noLFCcutoff <- res_table_L.9.5_norm_tb %>%
  filter(padj < padj.cutoff)

sig_L.9.5_norm <- sig_L.9.5_norm_noLFCcutoff %>% 
  filter(abs(log2FoldChange) > lfc.cutoff)

head(sig_L.9.5_norm)
# A tibble: 6 × 7
  gene           baseMean log2FoldChange lfcSE  stat   pvalue        padj
  <chr>             <dbl>          <dbl> <dbl> <dbl>    <dbl>       <dbl>
1 XM_060038104.1    342.          -0.692 0.148 -4.66 3.15e- 6 0.000283   
2 XM_060064921.1     84.2         -0.804 0.206 -3.91 9.23e- 5 0.00375    
3 XM_060038440.1    214.          -1.02  0.177 -5.75 8.73e- 9 0.00000242 
4 XM_060039114.1    115.          -0.939 0.182 -5.17 2.35e- 7 0.0000346  
5 XM_060057878.1     81.9          0.752 0.234  3.22 1.28e- 3 0.0254     
6 XM_060051825.1    118.           0.965 0.151  6.37 1.85e-10 0.000000106
paste("Number of significant DEGs for 9C v 5C:", nrow(sig_L.9.5_norm_noLFCcutoff), "(padj<", padj.cutoff, ")")
[1] "Number of significant DEGs for 9C v 5C: 1422 (padj< 0.05 )"
head(sig_L.9.5_norm)
# A tibble: 6 × 7
  gene           baseMean log2FoldChange lfcSE  stat   pvalue        padj
  <chr>             <dbl>          <dbl> <dbl> <dbl>    <dbl>       <dbl>
1 XM_060038104.1    342.          -0.692 0.148 -4.66 3.15e- 6 0.000283   
2 XM_060064921.1     84.2         -0.804 0.206 -3.91 9.23e- 5 0.00375    
3 XM_060038440.1    214.          -1.02  0.177 -5.75 8.73e- 9 0.00000242 
4 XM_060039114.1    115.          -0.939 0.182 -5.17 2.35e- 7 0.0000346  
5 XM_060057878.1     81.9          0.752 0.234  3.22 1.28e- 3 0.0254     
6 XM_060051825.1    118.           0.965 0.151  6.37 1.85e-10 0.000000106
paste("Number of significant DEGs for 9C v 5C:", nrow(sig_L.9.5_norm), "(padj<", padj.cutoff, ", log-fold change >", lfc.cutoff, ")")
[1] "Number of significant DEGs for 9C v 5C: 989 (padj< 0.05 , log-fold change > 0.58 )"
write.table(sig_L.9.5_norm_noLFCcutoff, file = "../output/07-cod-RNAseq-DESeq2/Gmac_DEGs_sig_L.9.5_norm_noLFCcutoff.tab", sep = "\t",
            row.names = TRUE, col.names = NA)

write.table(sig_L.9.5_norm, file = "../output/07-cod-RNAseq-DESeq2/Gmac_DEGs_sig_L.9.5_norm.tab", sep = "\t",
            row.names = TRUE, col.names = NA)

5.2 Heatmap

For DEGs based on adjusted p-value and LFC cutoff

# Retrieve normalized counts matrix
dds_L.9.5_norm_counts <- counts(dds_L.9.5, normalized=TRUE)

# Extract normalized expression for significant genes
norm_sig_L.9.5 <- dds_L.9.5_norm_counts %>% 
  data.frame() %>%
  filter(row.names(dds_L.9.5_norm_counts) %in% sig_L.9.5_norm$gene)

head(norm_sig_L.9.5)
               sample_100 sample_107 sample_108 sample_109 sample_110
XM_060038104.1  295.71554  159.60607  121.97567  313.89296  194.35918
XM_060064921.1   62.78268   46.33725   41.71462   91.37585  113.17117
XM_060038440.1  178.33922  115.84312   82.90121  216.59461  191.07886
XM_060039114.1   76.43109   97.82308   83.95728   63.45545   79.54785
XM_060057878.1   36.39576  203.36903  110.88697  118.45017   65.60648
XM_060051825.1  104.63781  126.14028   84.48531  117.60410  127.93263
               sample_117 sample_118 sample_119 sample_120 sample_121
XM_060038104.1  536.85118   505.8675  435.66389  473.00778  480.92812
XM_060064921.1   63.41247   120.1435  239.49696   66.00108  335.92919
XM_060038440.1  379.24349   411.0174  402.57549  411.28454   86.45899
XM_060039114.1   96.04218   119.4409  274.16100  199.83662  106.27250
XM_060057878.1   32.01406    67.4490  106.35556   32.38942   71.14854
XM_060051825.1   81.88212    79.3931   73.26716   72.72342   37.82581
               sample_127 sample_128 sample_131 sample_137 sample_138
XM_060038104.1  278.35595  395.18488  326.85770  409.26949  792.68997
XM_060064921.1   86.34934   70.89194   60.24436  132.79489   90.51477
XM_060038440.1  315.89915  461.55180  174.32411  304.77515  521.14565
XM_060039114.1   80.44970  312.22622  129.46129  124.08703   57.60031
XM_060057878.1   23.59858   40.72516   44.86282   43.53931  126.17211
XM_060051825.1   75.08638   66.36693   80.75308   54.42413   90.51477
               sample_139 sample_140 sample_147 sample_148 sample_150 sample_78
XM_060038104.1  359.46526  406.55133  377.09249  368.93588  389.59040 258.64896
XM_060064921.1  173.53495  128.30327   82.65041   42.60554   37.54433  39.56943
XM_060038440.1  382.48520  148.39896  189.40719  191.49083  237.78073 124.49894
XM_060039114.1  148.74424  205.59440  167.02270   66.95156  247.03078  97.47591
XM_060057878.1   37.18606   54.10379   53.37839   77.25180   25.02955  94.58059
XM_060051825.1  115.09971   75.74530   63.70969   83.80650   77.80926 155.38240
               sample_79 sample_80 sample_83 sample_88 sample_90 sample_91
XM_060038104.1 270.38098 245.58561 280.54998 208.73175 453.67964 339.49663
XM_060064921.1  73.22818  60.90523  47.33559  41.52191  47.69996  60.20987
XM_060038440.1  85.43288  92.34019 178.95163  90.89931 168.53987 114.61638
XM_060039114.1  66.65642 105.11064  66.96255  84.16603  65.71995  82.69790
XM_060057878.1 124.86344 102.16361  58.88086 221.07611  91.15993  62.38613
XM_060051825.1 138.94578 160.12182 177.79710 359.10840 277.71978 123.32143
               sample_92 sample_97 sample_98 sample_99 sample_RESUB.116
XM_060038104.1 154.77261 311.91541 100.45049 283.30844       282.496273
XM_060064921.1  81.22818  59.15637  32.73106  32.01773        62.588995
XM_060038440.1  96.59567 219.14746 145.59678 142.62445       105.724653
XM_060039114.1  98.79103  37.64496  20.31583  73.73781        85.425520
XM_060057878.1 185.50759  79.32331 215.57353 118.36860         8.457972
XM_060051825.1 154.77261 141.16861 223.47413 110.60672       118.411612
               sample_RESUB.156 sample_RESUB.94
XM_060038104.1        440.38384       382.77616
XM_060064921.1         87.73931        52.27340
XM_060038440.1        214.28639        86.84129
XM_060039114.1        206.69356        75.03762
XM_060057878.1         30.37130        21.07798
XM_060051825.1         76.77190       111.29175
# Annotate heatmap
annotation <- infosub_L.9.5 %>% 
    dplyr::select(temp_treatment)

# Set a color palette
heat_colors <- rev(brewer.pal(12, "RdYlBu"))

# Run pheatmap
h.L.9.5 <- pheatmap(norm_sig_L.9.5, 
                     color = heat_colors, 
                     cluster_rows = T, 
                     show_rownames = F,
                     annotation = annotation, 
                     border_color = NA, 
                     fontsize = 10,
                     scale = "row", 
                     fontsize_row = 10, 
                     height = 30,
                     main = "Normalized Significant Expression, Liver, 9*C and 5*C")

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/heatmap_L.9.5_norm_sig.png",
         plot   = h.L.9.5,
         res    = 600,
         width  = 5000,
         height = 5000)

Note the argument scale="row" was included, so the values plotted in the heat map are Z-scores, rather thn the normalized count value. This vastly improves the color visualization.

For DEGs based on adjusted p-value only

# Extract normalized expression for significant genes
norm_sig_L.9.5_noLFCcutoff <- dds_L.9.5_norm_counts %>% 
  data.frame() %>%
  filter(row.names(dds_L.9.5_norm_counts) %in% sig_L.9.5_norm_noLFCcutoff$gene)

head(norm_sig_L.9.5_noLFCcutoff)
               sample_100 sample_107 sample_108 sample_109 sample_110
XM_060038104.1  295.71554  159.60607  121.97567  313.89296  194.35918
XM_060064921.1   62.78268   46.33725   41.71462   91.37585  113.17117
XM_060068449.1   75.52120   47.62439   86.59744   65.14760  106.61052
XM_060038440.1  178.33922  115.84312   82.90121  216.59461  191.07886
XM_060072995.1  223.83392  200.79473  214.90951  197.98101  270.62671
XM_060039114.1   76.43109   97.82308   83.95728   63.45545   79.54785
               sample_117 sample_118 sample_119 sample_120 sample_121
XM_060038104.1  536.85118   505.8675   435.6639  473.00778  480.92812
XM_060064921.1   63.41247   120.1435   239.4970   66.00108  335.92919
XM_060068449.1  110.20225   135.6006   215.0746  137.50226  124.28479
XM_060038440.1  379.24349   411.0174   402.5755  411.28454   86.45899
XM_060072995.1  226.56105   346.3787   567.2297  526.17532  228.75607
XM_060039114.1   96.04218   119.4409   274.1610  199.83662  106.27250
               sample_127 sample_128 sample_131 sample_137 sample_138
XM_060038104.1  278.35595  395.18488  326.85770  409.26949  792.68997
XM_060064921.1   86.34934   70.89194   60.24436  132.79489   90.51477
XM_060068449.1  169.48070  122.17548   88.44385   87.07862   35.65733
XM_060038440.1  315.89915  461.55180  174.32411  304.77515  521.14565
XM_060072995.1  264.94767  404.23491  329.42129  283.00550  181.02954
XM_060039114.1   80.44970  312.22622  129.46129  124.08703   57.60031
               sample_139 sample_140 sample_147 sample_148 sample_150 sample_78
XM_060038104.1  359.46526  406.55133  377.09249  368.93588  389.59040 258.64896
XM_060064921.1  173.53495  128.30327   82.65041   42.60554   37.54433  39.56943
XM_060068449.1   51.35218   80.38277   63.70969   85.21108   84.33870  62.73202
XM_060038440.1  382.48520  148.39896  189.40719  191.49083  237.78073 124.49894
XM_060072995.1  304.57155  471.47588  223.84486  169.48577  347.14899 200.74248
XM_060039114.1  148.74424  205.59440  167.02270   66.95156  247.03078  97.47591
               sample_79 sample_80 sample_83 sample_88 sample_90 sample_91
XM_060038104.1 270.38098 245.58561 280.54998 208.73175 453.67964 339.49663
XM_060064921.1  73.22818  60.90523  47.33559  41.52191  47.69996  60.20987
XM_060068449.1  60.08466  99.21659  66.96255  44.88855  68.89995  98.65714
XM_060038440.1  85.43288  92.34019 178.95163  90.89931 168.53987 114.61638
XM_060072995.1 225.31748 272.10885 162.78826 234.54267 213.05983 195.13802
XM_060039114.1  66.65642 105.11064  66.96255  84.16603  65.71995  82.69790
               sample_92 sample_97 sample_98 sample_99 sample_RESUB.116
XM_060038104.1 154.77261 311.91541 100.45049 283.30844        282.49627
XM_060064921.1  81.22818  59.15637  32.73106  32.01773         62.58899
XM_060068449.1  68.05604  40.33389  47.40360  65.00570         87.11711
XM_060038440.1  96.59567 219.14746 145.59678 142.62445        105.72465
XM_060072995.1 295.27540 317.29326 117.38035 186.28500        223.29047
XM_060039114.1  98.79103  37.64496  20.31583  73.73781         85.42552
               sample_RESUB.156 sample_RESUB.94
XM_060038104.1        440.38384       382.77616
XM_060064921.1         87.73931        52.27340
XM_060068449.1        128.23437        72.50826
XM_060038440.1        214.28639        86.84129
XM_060072995.1        396.51419       225.95597
XM_060039114.1        206.69356        75.03762
# Annotate heatmap
annotation <- infosub_L.9.5 %>% 
    dplyr::select(temp_treatment)

# Set a color palette
heat_colors <- rev(brewer.pal(12, "RdYlBu"))

# Run pheatmap
h.L.9.5 <- pheatmap(norm_sig_L.9.5_noLFCcutoff, 
                     color = heat_colors, 
                     cluster_rows = T, 
                     show_rownames = F,
                     annotation = annotation, 
                     border_color = NA, 
                     fontsize = 10,
                     scale = "row", 
                     fontsize_row = 10, 
                     height = 30,
                     main = "Normalized Significant Expression (no LFC cutoff), Liver, 9*C and 5*C")

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/heatmap_L.9.5_norm_sig_noLFCcutoff.png",
         plot   = h.L.9.5,
         res    = 600,
         width  = 5000,
         height = 5000)

5.3 Volcano plot

# Generate plot
v.L.9.5 <- 
  ggplot(res_table_L.9.5_norm_tb) +
  # Plot all
  geom_point(aes(x=log2FoldChange, y=-log10(padj),color="unchanged"),
             size=.5) +
  # Overlay all significantly upregulated in red
  geom_point(data = sig_L.9.5_norm[sig_L.9.5_norm$log2FoldChange > 0, ], 
             aes(x=log2FoldChange, y=-log10(padj), color="upregulated"), 
             size=.5) +
  # Overlay all significantly downregulated in blue
  geom_point(data = sig_L.9.5_norm[sig_L.9.5_norm$log2FoldChange < 0, ], 
             aes(x=log2FoldChange, y=-log10(padj), color="downregulated"), 
             size=.5) +
  ggtitle("Liver, 9*C and 5*C") +
  xlab("log2 fold change") + 
  ylab("-log10 adjusted p-value") +
  scale_x_continuous(limits = c(-4,4)) +
  scale_y_continuous(limits = c(0,30)) +
  scale_color_manual(values = c("unchanged" = "darkgrey", "upregulated" = "red", "downregulated" = "blue"),
                     labels = c("unchanged" = "Unchanged", "upregulated" = "Upregulated", "downregulated" = "Downregulated"),
                     name = NULL) +
  theme(legend.position = "top",
        plot.title = element_text(size = rel(1.5), hjust = 0.5),
        axis.title = element_text(size = rel(1.25)))

v.L.9.5

# Save plot
ggexport(filename = "../output/07-cod-RNAseq-DESeq2/volcano_L.9.5.png",
         plot   = v.L.9.0,
         res    = 600,
         width  = 6000,
         height = 4000)

5.4 Plot expression of top DEGs across treatments

top15DEGs_L.9.5 <- sig_L.9.5_norm_noLFCcutoff %>%
  arrange(padj) %>%
  slice_head(n=15)

L.9.5_DEG1 <- plot_gene_data(top15DEGs_L.9.5[1, ]$gene)
L.9.5_DEG1

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG1.",top15DEGs_L.9.5[1, ]$gene,".png"), plot = L.9.5_DEG1, res = 600, width = 5000, height = 5000)

L.9.5_DEG2 <- plot_gene_data(top15DEGs_L.9.5[2, ]$gene)
L.9.5_DEG2

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG2.",top15DEGs_L.9.5[2, ]$gene,".png"), plot = L.9.5_DEG2, res = 600, width = 5000, height = 5000)

L.9.5_DEG3 <- plot_gene_data(top15DEGs_L.9.5[3, ]$gene)
L.9.5_DEG3

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG3.",top15DEGs_L.9.5[3, ]$gene,".png"), plot = L.9.5_DEG3, res = 600, width = 5000, height = 5000)

L.9.5_DEG4 <- plot_gene_data(top15DEGs_L.9.5[4, ]$gene)
L.9.5_DEG4

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG4.",top15DEGs_L.9.5[4, ]$gene,".png"), plot = L.9.5_DEG4, res = 600, width = 5000, height = 5000)

L.9.5_DEG5 <- plot_gene_data(top15DEGs_L.9.5[5, ]$gene)
L.9.5_DEG5

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG5.",top15DEGs_L.9.5[5, ]$gene,".png"), plot = L.9.5_DEG5, res = 600, width = 5000, height = 5000)

L.9.5_DEG6 <- plot_gene_data(top15DEGs_L.9.5[6, ]$gene)
L.9.5_DEG6

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG6.",top15DEGs_L.9.5[6, ]$gene,".png"), plot = L.9.5_DEG6, res = 600, width = 5000, height = 5000)

L.9.5_DEG7 <- plot_gene_data(top15DEGs_L.9.5[7, ]$gene)
L.9.5_DEG7

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG7.",top15DEGs_L.9.5[7, ]$gene,".png"), plot = L.9.5_DEG7, res = 600, width = 5000, height = 5000)

L.9.5_DEG8 <- plot_gene_data(top15DEGs_L.9.5[8, ]$gene)
L.9.5_DEG8

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG8.",top15DEGs_L.9.5[8, ]$gene,".png"), plot = L.9.5_DEG8, res = 600, width = 5000, height = 5000)

L.9.5_DEG9 <- plot_gene_data(top15DEGs_L.9.5[9, ]$gene)
L.9.5_DEG9

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG9.",top15DEGs_L.9.5[9, ]$gene,".png"), plot = L.9.5_DEG9, res = 600, width = 5000, height = 5000)

L.9.5_DEG10 <- plot_gene_data(top15DEGs_L.9.5[10, ]$gene)
L.9.5_DEG10

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG10.",top15DEGs_L.9.5[10, ]$gene,".png"), plot = L.9.5_DEG10, res = 600, width = 5000, height = 5000)

L.9.5_DEG11 <- plot_gene_data(top15DEGs_L.9.5[11, ]$gene)
L.9.5_DEG11

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG11.",top15DEGs_L.9.5[11, ]$gene,".png"), plot = L.9.5_DEG11, res = 600, width = 5000, height = 5000)

L.9.5_DEG12 <- plot_gene_data(top15DEGs_L.9.5[12, ]$gene)
L.9.5_DEG12

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG12.",top15DEGs_L.9.5[12, ]$gene,".png"), plot = L.9.5_DEG12, res = 600, width = 5000, height = 5000)

L.9.5_DEG13 <- plot_gene_data(top15DEGs_L.9.5[13, ]$gene)
L.9.5_DEG13

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG13.",top15DEGs_L.9.5[13, ]$gene,".png"), plot = L.9.5_DEG13, res = 600, width = 5000, height = 5000)

L.9.5_DEG14 <- plot_gene_data(top15DEGs_L.9.5[14, ]$gene)
L.9.5_DEG14

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG14.",top15DEGs_L.9.5[14, ]$gene,".png"), plot = L.9.5_DEG14, res = 600, width = 5000, height = 5000)

L.9.5_DEG15 <- plot_gene_data(top15DEGs_L.9.5[15, ]$gene)
L.9.5_DEG15

ggexport(filename = paste("../output/07-cod-RNAseq-DESeq2/L.9.5_DEG15.",top15DEGs_L.9.5[15, ]$gene,".png"), plot = L.9.5_DEG15, res = 600, width = 5000, height = 5000)
LS0tCnRpdGxlOiAiMDctY29kLVJOQXNlcS1ERVNlcTIiCmF1dGhvcjogIkthdGhsZWVuIER1cmtpbiIKZGF0ZTogIjIwMjQtMDMtMTkiCmFsd2F5c19hbGxvd19odG1sOiB0cnVlCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBodG1sX3ByZXZpZXc6IHRydWUgCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICAjIERpc3BsYXkgY29kZSBjaHVua3MKICBldmFsID0gVFJVRSwgICAgICAgICAjIEV2YWx1YXRlIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAgIyBIaWRlIHdhcm5pbmdzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAgIyBIaWRlIG1lc3NhZ2VzCiAgY29tbWVudCA9ICIiICAgICAgICAgIyBQcmV2ZW50cyBhcHBlbmRpbmcgJyMjJyB0byBiZWdpbm5pbmcgb2YgbGluZXMgaW4gY29kZSBvdXRwdXQKKQpgYGAKCkRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMgZm9yIFtQYWNpZmljIGNvZCBSTkFzZXEgZGF0YV0oaHR0cHM6Ly9zaGVkdXJraW4uZ2l0aHViLmlvL1JvYmVydHMtTGFiTm90ZWJvb2svcG9zdHMvcHJvamVjdHMvcGFjaWZpY19jb2QvMjAyM18xMl8xM19wYWNpZmljX2NvZC5odG1sKS4KCi0gICB0cmltbWVkIHJlYWRzIGdlbmVyYXRlZCBpbiBgMDUtY29kLVJOQXNlcS10cmltbWluZ2AKCi0gICBSZWFkcyBhbGlnbmVkIHRvIHRyYW5zY3JpcHRvbWUgZG93bmxvYWRlZCBmcm9tIFtOQ0JJXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2RhdGFzZXRzL2dlbm9tZS9HQ0ZfMDMxMTY4OTU1LjEvKSwgc3RvcmVkIFtoZXJlXShodHRwczovL293bC5maXNoLndhc2hpbmd0b24uZWR1L2hhbGZzaGVsbC9nZW5vbWljLWRhdGFiYW5rL0dDRl8wMzExNjg5NTUuMV9BU00zMTE2ODk1djFfcm5hLmZuYSkgYXMgYSBwYXJ0IG9mIGxhYiBbZ2Vub21pYyByZXNvdXJjZXNdKGh0dHBzOi8vcm9iZXJ0c2xhYi5naXRodWIuaW8vcmVzb3VyY2VzL0dlbm9taWMtUmVzb3VyY2VzLyNnYWR1cy1tYWNyb2NlcGhhbHVzLXBhY2lmaWMtY29kKS4KCiMjIyBJbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgaW5sY3VkZSA9IFRSVUV9CgojIyBjbGVhcgpybShsaXN0PWxzKCkpCgojIyBJbnN0YWxsIFJ0b29scyBkaXJlY3RseSBmcm9tIChodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9iaW4vd2luZG93cy9SdG9vbHMvKSwgdGhlbiBpbnN0YWxsIHRoZXNlIG9uIGZpcnN0IHJ1bjoKIyBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoInZzbiIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoInRpZHlidWxrIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZ29zZXEiKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJhZmZ5Y29yZXRvb2xzIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiRW5oYW5jZWRWb2xjYW5vIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgicGNhRXhwbG9yZXIiKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJhcGVnbG0iKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJQQ0F0b29scyIpCgoKIyBMaXN0IG9mIHBhY2thZ2VzIHdlIHdhbnQgdG8gaW5zdGFsbCAocnVuIGV2ZXJ5IHRpbWUpCmxvYWQubGliPC1jKCJERVNlcTIiLCJlZGdlUiIsImdvc2VxIiwiZHBseXIiLCJHZW5vbWljRmVhdHVyZXMiLCJkYXRhLnRhYmxlIiwiY2FsaWJyYXRlIiwiYWZmeWNvcmV0b29scyIsImRhdGEudGFibGUiLCJ2c24iLCJ0aWR5YnVsayIsImdncGxvdDIiLCJjb3dwbG90IiwicGhlYXRtYXAiLCJncGxvdHMiLCJSQ29sb3JCcmV3ZXIiLCJFbmhhbmNlZFZvbGNhbm8iLCJwY2FFeHBsb3JlciIsInJlYWR4bCIsImFwZWdsbSIsImFzaHIiLCJ0aWJibGUiLCJwbG90bHkiLCJzcWxkZiIsIlBDQXRvb2xzIiwiZ2dwdWJyIiwiYmVlcHIiLCJnZW5lZmlsdGVyIiwiQ29tcGxleEhlYXRtYXAiLCJjaXJjbGl6ZSIsInNjYWxlcyIsICJ0aWR5dmVyc2UiLCAiZ3JpZGV4dHJhJyIpCgojIFNlbGVjdCBvbmx5IHRoZSBwYWNrYWdlcyB0aGF0IGFyZW4ndCBjdXJyZW50bHkgaW5zdGFsbGVkIChydW4gZXZlcnkgdGltZSkKIyBpbnN0YWxsLmxpYiA8LSBsb2FkLmxpYlshbG9hZC5saWIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKV0KCiMgQW5kIGZpbmFsbHkgd2UgaW5zdGFsbCB0aGUgbWlzc2luZyBwYWNrYWdlcywgaW5jbHVkaW5nIHRoZWlyIGRlcGVuZGVuY3kuCiMgZm9yKGxpYiBpbiBpbnN0YWxsLmxpYikgaW5zdGFsbC5wYWNrYWdlcyhsaWIsZGVwZW5kZW5jaWVzPVRSVUUpCiMgQWZ0ZXIgdGhlIGluc3RhbGxhdGlvbiBwcm9jZXNzIGNvbXBsZXRlcywgd2UgbG9hZCBhbGwgcGFja2FnZXMuCnNhcHBseShsb2FkLmxpYixyZXF1aXJlLGNoYXJhY3Rlcj1UUlVFKQogICAgICAgICAgICAgICAgICAgICAgICAKYGBgCgpJIGZvdW5kIHRoZSBbREVTZXEyIHZpZ25ldHRlXShodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvREVTZXEyL2luc3QvZG9jL0RFU2VxMi5odG1sKSBhbmQgdGhlIFtIQkMgREdFIHRyYWluaW5nIHdvcmtzaG9wXShodHRwczovL2dpdGh1Yi5jb20vaGJjdHJhaW5pbmcvREdFX3dvcmtzaG9wKSBzdXBlciBoZWxwZnVsIGluIGZpZ3VyaW5nIG91dCBob3cgdG8gdXNlIHRoZSBERVNlcTIgcGFja2FnZSEKCiMgTG9hZCBkYXRhCgojIyBMb2FkIGNvdW50IGRhdGEKCkxvYWQgaW4gdGhlIGNvdW50IG1hdHJpeCB3ZSBnZW5lcmF0ZWQgYWZ0ZXIga2FsbGlzdG8gcHNldWRvYWxpZ25tZW50IHVzaW5nIHRoZSBUcmluaXR5IGFidW5kYW5jZV9lc3RpbWF0ZXNfdG9fbWF0cml4LnBsIHNjcmlwdC4gV2UgYWxzbyBuZWVkIHRvIHNsaWdodGx5IHJlZm9ybWF0IHRoZSBjb3VudCBtYXRyaXggdG8gbWFrZSBhbGwgb2YgdGhlIGVzdGltYXRlZCBjb3VudHMgaW50ZWdlcnMsIGFzIHJlcXVpcmVkIGZvciBERVNlcTIuCgpgYGB7cn0KIyBSZWFkIGluIGNvdW50cyBkYXRhLiBUaGlzIGlzIGEgZ2VuZS1sZXZlbCBjb3VudHMgbWF0cml4IGdlbmVyYXRlZCBmcm9tIGthbGxpc3RvIHRyYW5zY3JpcHQgYWJ1bmRhbmNlcyB1c2luZyBUcmluaXR5CmNvZF9jb3VudHNfZGF0YV9PRyA8LSByZWFkX2RlbGltKCIuLi9vdXRwdXQvMDYtY29kLVJOQXNlcS1hbGlnbm1lbnQva2FsbGlzdG8va2FsbGlzdG8uaXNvZm9ybS5jb3VudHMubWF0cml4IikgCmhlYWQoY29kX2NvdW50c19kYXRhX09HKQpgYGAKCiMjIENvdW50IGRhdGEgbXVuZ2luZwoKYGBge3J9CiMgIyBXZSBuZWVkIHRvIG1vZGlmeSB0aGlzIGRhdGEgZnJhbWUgc28gdGhhdCB0aGUgcm93IG5hbWVzIGFyZSBhY3R1YWxseSByb3cgbmFtZXMsIGluc3RlYWQgb2YgY29tcHJpc2luZyB0aGUgZmlyc3QgY29sdW1uCmNvZF9jb3VudHNfZGF0YSA8LSBjb2RfY291bnRzX2RhdGFfT0cgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiLi4uMSIpCgojIEFkZGl0aW9uYWwgZm9ybWF0dGluZwojIFJvdW5kIGFsbCBlc3RpbWF0ZWQgY291bnRzIHRvIGludGVnZXJzCmNvZF9jb3VudHNfZGF0YSA8LSByb3VuZChjb2RfY291bnRzX2RhdGEsIGRpZ2l0cyA9IDApCgojIFJlbW92ZSB0aGUgImthbGxpc3RvX3F1YW50XyIgcG9ydGlvbiBvZiB0aGUgY29sdW1uIG5hbWVzLCB0byBsZWF2ZSBqdXN0IHRoZSBzYW1wbGUgbmFtZXMKY29sbmFtZXMoY29kX2NvdW50c19kYXRhKSA8LSBzdWIoImthbGxpc3RvX3F1YW50XyIsICJzYW1wbGVfIiwgY29sbmFtZXMoY29kX2NvdW50c19kYXRhKSkKCiMgUmVvcmRlciB0aGUgY291bW5zIGludG8gYWxwaGFiZXRpY2FsIG9yZGVyICh0byBtYWtlIGl0IGVhc2llciB0byBjcmVhdGUgYW4gYXNzb2NpYXRlZCBtZXRhZGF0YSBzcHJlYWRzaGVldCkKY29kX2NvdW50c19kYXRhIDwtIGNvZF9jb3VudHNfZGF0YVssIG9yZGVyKGNvbG5hbWVzKGNvZF9jb3VudHNfZGF0YSkpXQoKY29kX3NhbXBsZV9uYW1lcyA8LSBuYW1lcyhjb2RfY291bnRzX2RhdGEpCgpoZWFkKGNvZF9jb3VudHNfZGF0YSkKY29kX3NhbXBsZV9uYW1lcwpgYGAKCiMjIEltcG9ydCBzYW1wbGUgbWV0YWRhdGEgc2hlZXRzCgpgYGB7cn0KIyBSZWFkIGluIHRoZSBjc3YgZmlsZSBhcyBhIGRhdGEgZnJhbWUKY29kX3NhbXBsZV9pbmZvX09HIDwtIHJlYWQuY3N2KCJ+L3Byb2plY3QtY29kLXRlbXBlcmF0dXJlL2RhdGEvREVTZXEyX1NhbXBsZV9JbmZvcm1hdGlvbi5jc3YiKQpjb2RfZXhwZXJpbWVudF9hbGxkYXRhX09HIDwtIHJlYWQuY3N2KCJ+L3Byb2plY3QtY29kLXRlbXBlcmF0dXJlL2RhdGEvdGVtcC1leHBlcmltZW50LmNzdiIpCmhlYWQoY29kX3NhbXBsZV9pbmZvX09HKQpoZWFkKGNvZF9leHBlcmltZW50X2FsbGRhdGFfT0cpCgojIFJlbmFtZSB0aGUgIkdlbmV0aWNTYW1wbGluZ0NvdW50IiBjb2x1bW4gb2YgdGhlIGV4cGVyaW1lbnRhbCBkYXRhIHRvICJzYW1wbGVfbnVtYmVyIgpjb2RfZXhwZXJpbWVudF9hbGxkYXRhIDwtIGNvZF9leHBlcmltZW50X2FsbGRhdGFfT0cKbmFtZXMoY29kX2V4cGVyaW1lbnRfYWxsZGF0YSlbbmFtZXMoY29kX2V4cGVyaW1lbnRfYWxsZGF0YSkgPT0gIkdlbmV0aWNTYW1wbGluZ0NvdW50Il0gPC0gInNhbXBsZV9udW1iZXIiCgojIENhbGN1bGF0ZSBsZW5ndGggZGlmZmVyZW5jZSBhbmQgd2VpZ2h0IGRpZmZlcmVuY2UgKGVuZC1iZWdpbm5pbmcpCmNvZF9leHBlcmltZW50X2FsbGRhdGEkU0xfZGlmZl9tbSA8LSBjb2RfZXhwZXJpbWVudF9hbGxkYXRhJFNMX21tIC0gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSRTTF8xMTIxMjAyMgpjb2RfZXhwZXJpbWVudF9hbGxkYXRhJFdXVF9kaWZmX2cgPC0gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSRXaG9sZUJvZHlXV19nIC0gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSRXV1RfMTEyMTIwMjIKCiMgTWVyZ2UgdGhlIHR3byBkYXRhIGZyYW1lcyB0byBnZXQgZXhwZXJpbWVudGFsIGRhdGEgZm9yIGFsbCBvZiBvdXIgUk5Bc2VxJ2Qgc2FtcGxlcy4KIyBUaGlzIHNob3VsZCBpbmNsdWRlIGFsbCByb3dzIGZyb20gY29kX3NhbXBsZV9pbmZvX09HIGFuZCBtYXRjaGluZyByb3dzIGZyb20gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSBiYXNlZCBvbiB0aGUgc2hhcmVkIHNhbXBsZV9udW1iZXIgY29sdW1uLiBTYW1wbGUgbnVtYmVyIGR1cGxpY2F0ZXMgKGUuZy4gZnJvbSBkaWZmZXJlbnQgdGlzc3VlIHR5cGVzKSBzaG91bGQgYmUgcmV0YWluZWQuCmNvZF9zYW1wbGVfaW5mbyA8LSBtZXJnZShjb2Rfc2FtcGxlX2luZm9fT0csIGNvZF9leHBlcmltZW50X2FsbGRhdGEsIGJ5ID0gInNhbXBsZV9udW1iZXIiLCBhbGwueCA9IFRSVUUpCgojIFJlb3JkZXIgdGhlIGRhdGEgZnJhbWUgaW50byBhbHBoYWJldGljYWwgb3JkZXIgYnkgdGhlIHNhbXBsZSBuYW1lcywgc28gdGhhdCB0aGUgcm93cyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgb3VyIGNvdW50IG1hdHJpeCBjb2x1bW5zCmNvZF9zYW1wbGVfaW5mbyA8LSBjb2Rfc2FtcGxlX2luZm9bb3JkZXIoY29kX3NhbXBsZV9pbmZvJHNhbXBsZV9uYW1lKSwgXQoKIyBBZ2Fpbiwgd2UgbmVlZCB0byByZWZvcm1hdCBzbyB0aGF0IHRoZSBkYXRhIGluIHRoZSBmaXJzdCBjb2x1bW4gYmVjb21lcyB0aGUgcm93IG5hbWVzCnJvd25hbWVzKGNvZF9zYW1wbGVfaW5mbykgPC0gY29kX3NhbXBsZV9pbmZvJHNhbXBsZV9uYW1lCgojIFJlbW92ZSBkdXBsaWNhdGUgY29sdW1ucyAoYXJ0aWZhY3Qgb2YgbWVyZ2luZyBkYXRhIGZyYW1lcyB3aXRoIG11bHRpcGxlIHNoYXJlZCBjb2x1bW5zIGFuZCBvZiBtYWtpbmcgc2FtcGxlX25hbWUgdGhlIHJvd25hbWVzIGluc3RlYWQgb2YgYSB2YXJpYWJsZSkKY29kX3NhbXBsZV9pbmZvIDwtIHN1YnNldChjb2Rfc2FtcGxlX2luZm8sIHNlbGVjdD0tVGVtcGVyYXR1cmUpCmNvZF9zYW1wbGVfaW5mbyA8LSBzdWJzZXQoY29kX3NhbXBsZV9pbmZvLCBzZWxlY3Q9LVRhbmspCiNjb2Rfc2FtcGxlX2luZm8gPC0gc3Vic2V0KGNvZF9zYW1wbGVfaW5mbywgc2VsZWN0PS1zYW1wbGVfbmFtZSkKCgpoZWFkKGNvZF9zYW1wbGVfaW5mbykKYGBgCgojIyBTYW1wbGUgbWV0YWRhdGEgbXVuZ2luZwoKYGBge3J9CiMgRmFjdG9yIHZhcmlhYmxlcwpjb2Rfc2FtcGxlX2luZm8kdGVtcF90cmVhdG1lbnQgPC0gZmFjdG9yKGNvZF9zYW1wbGVfaW5mbyR0ZW1wX3RyZWF0bWVudCkKY29kX3NhbXBsZV9pbmZvJHRhbmsgPC0gZmFjdG9yKGNvZF9zYW1wbGVfaW5mbyR0YW5rKQpjb2Rfc2FtcGxlX2luZm8kdGlzc3VlX3R5cGUgPC0gZmFjdG9yKGNvZF9zYW1wbGVfaW5mbyR0aXNzdWVfdHlwZSkKCiMgUmVtb3ZlIGJhZCBzYW1wbGVzCiMgTXVsaVFDIHJlcG9ydDogMTQ5LCAxMjkKIyBQQ0Egb3V0bGllcnM6IDMxLCA0MSAocGVyIExhdXJhKQpjb2Rfc2FtcGxlX2luZm8gPC0gY29kX3NhbXBsZV9pbmZvWyEocm93Lm5hbWVzKGNvZF9zYW1wbGVfaW5mbykgJWluJSBjKCJzYW1wbGVfMTQ5IiwgInNhbXBsZV8xMjkiLCAic2FtcGxlXzMxIiwgInNhbXBsZV80MSIpKSxdCmNvZF9jb3VudHNfZGF0YSA8LSBhcy5tYXRyaXgoc3Vic2V0KGNvZF9jb3VudHNfZGF0YSwgc2VsZWN0PS1jKHNhbXBsZV8xNDksIHNhbXBsZV8xMjksIHNhbXBsZV8zMSwgc2FtcGxlXzQxKSkpCgojIENoZWNrIHRoYXQgdGhlIGNvbHVtbiBuYW1lcyBvZiBvdXIgY291bnQgZGF0YSBtYXRjaCB0aGUgcm93IG5hbWVzIG9mIG91ciBzYW1wbGUgaW5mbyBzaGVldApuY29sKGNvZF9jb3VudHNfZGF0YSkKbnJvdyhjb2Rfc2FtcGxlX2luZm8pCgphbGwoY29sbmFtZXMoY29kX2NvdW50c19kYXRhKSAlaW4lIHJvd25hbWVzKGNvZF9zYW1wbGVfaW5mbykpCmFsbChjb2xuYW1lcyhjb2RfY291bnRzX2RhdGEpID09IHJvd25hbWVzKGNvZF9zYW1wbGVfaW5mbykpCmBgYAoKQ29tYmluZSBjb3VudHMgZGF0YSBhbmQgc2FtcGxlIG1ldGFkYXRhIGZvciBsYXRlciBhbmFseXNlcwpgYGB7cn0KIyBNZWx0IGNvZF9jb3VudHNfZGF0YSB0byBsb25nIGZvcm1hdApjb2RfY291bnRzX2RhdGFfbG9uZyA8LSBhcy5kYXRhLmZyYW1lKGNvZF9jb3VudHNfZGF0YSkKY29kX2NvdW50c19kYXRhX2xvbmckZ2VuZSA8LSByb3duYW1lcyhjb2RfY291bnRzX2RhdGFfbG9uZykKY29kX2NvdW50c19kYXRhX2xvbmcgPC0gY29kX2NvdW50c19kYXRhX2xvbmcgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoInNhbXBsZSIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2FtcGxlX25hbWUiLCAKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImNvdW50IikKCmNvbG5hbWVzKGNvZF9jb3VudHNfZGF0YV9sb25nKQpjb2xuYW1lcyhjb2Rfc2FtcGxlX2luZm8pCgojIE1lcmdlIGNvZF9jb3VudHNfZGF0YV9sb25nIHdpdGggZGZfQyB0byBnZXQgdHJlYXRtZW50IGluZm8KY29kX2NvdW50c2RhdGFfcGx1c19zYW1wbGVpbmZvIDwtIGxlZnRfam9pbihjb2RfY291bnRzX2RhdGFfbG9uZywgY29kX3NhbXBsZV9pbmZvLCBieSA9ICJzYW1wbGVfbmFtZSIpCmBgYAoKIyBQcmVsaW1pbmFyeSBQQ0EgdmlzdWFsaXphdGlvbiAobGl2ZXIgdGlzc3VlKQoKIyMgREVTZXEgb2JqZWN0CgpgYGB7ciwgY2FjaGU9VFJVRX0KIyBGaWx0ZXIgZGF0YQppbmZvc3ViX0wgPC0gY29kX3NhbXBsZV9pbmZvICU+JSBmaWx0ZXIodGlzc3VlX3R5cGUgPT0gIkxpdmVyIikKY291bnRzdWJfTCA8LSBzdWJzZXQoY29kX2NvdW50c19kYXRhLCBzZWxlY3Q9cm93Lm5hbWVzKGluZm9zdWJfTCkpCgojIENhbGN1bGF0ZSBERVNlcSBvYmplY3QKZGRzX0wgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHN1Yl9MLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gaW5mb3N1Yl9MLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IHRlbXBfdHJlYXRtZW50KSAKCiMgUnVuIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIAojIChOb3RlIHRoYXQgdGhpcyBERVNlcSgpIGZ1bmN0aW9uIHJ1bnMgYWxsIG5lY2Vzc2FyeSBzdGVwcywgaW5jbHVkaW5nIGRhdGEgbm9ybWFsaXphdGlvbiwgCiMgZXN0aW1hdGluZyBzaXplIGZhY3RvcnMsIGVzdGltYXRpbmcgZGlzcGVyc2lvbnMsIGdlbmUtd2lzZSBkaXNwZXJzaW9uIGVzdGltYXRlcywgbWVhbi1kaXNwZXJzaW9uIAojIHJlbGF0aW9uc2hpcCwgZmluYWwgZGlzcGVyc2lvbiBlc3RpbWF0ZXMsIGZpdHRpbmcgbW9kZWwsIGFuZCB0ZXN0aW5nKQpkZHNfTCA8LSBERVNlcShkZHNfTCkKcmVzdWx0c05hbWVzKGRkc19MKSAjIGxpc3RzIHRoZSBjb2VmZmljaWVudHMKYGBgCgpgYGB7cn0KcGxvdERpc3BFc3RzKGRkc19MKQpgYGAKCiMjIFBDQSB2aXN1YWxpemF0aW9uCgpgYGB7cn0KIyBHZW5lcmF0ZSBQQ0FzCiMgdG9wIDUwMCBtb3N0IHZhcmlhYmxlIGdlbmVzCnBjYV9MXzUwMDwtIHBsb3RQQ0EodnN0KGRkc19MKSwgaW50Z3JvdXAgPSBjKCJ0ZW1wX3RyZWF0bWVudCIpLCByZXR1cm5EYXRhPVRSVUUpCnBlcmNlbnRWYXJfTF81MDAgPC0gcm91bmQoMTAwKmF0dHIocGNhX0xfNTAwLCAicGVyY2VudFZhciIpKQojIG1lcmdlIHdpdGggbWV0YWRhdGEgc2hlZXQgc28gd2UgY2FuIHBsb3QgdXNpbmcgb3RoZXIgZmVhdHVyZXMKcGNhX0xfNTAwIDwtIHN1YnNldChwY2FfTF81MDAsIHNlbGVjdD0tdGVtcF90cmVhdG1lbnQpICNyZW1vdmUgdGhlIHRlbXBfdHJlYXRtZW50IGNvbHVtbiwgd2hpY2ggd2lsbCBiZSBhIGR1cGxpY2F0ZSBwb3N0LW1lcmdlCnBjYV9MXzUwMCA8LSBtZXJnZShwY2FfTF81MDAsIGNvZF9zYW1wbGVfaW5mbywgYnkueCA9ICJuYW1lIiwgYnkueSA9ICJyb3cubmFtZXMiKQoKIyB0b3AgMTAwMCBtb3N0IHZhcmlhYmxlIGdlbmVzCnBjYV9MXzEwMDAgPC0gcGxvdFBDQSh2c3QoZGRzX0wpLCBpbnRncm91cCA9IGMoInRlbXBfdHJlYXRtZW50IiksIHJldHVybkRhdGE9VFJVRSwgbnRvcD0xMDAwKQpwZXJjZW50VmFyX0xfMTAwMCA8LSByb3VuZCgxMDAqYXR0cihwY2FfTF8xMDAwLCAicGVyY2VudFZhciIpKQojIG1lcmdlIHdpdGggbWV0YWRhdGEgc2hlZXQgc28gd2UgY2FuIHBsb3QgdXNpbmcgb3RoZXIgZmVhdHVyZXMKcGNhX0xfMTAwMCA8LSBzdWJzZXQocGNhX0xfMTAwMCwgc2VsZWN0PS10ZW1wX3RyZWF0bWVudCkgI3JlbW92ZSB0aGUgdGVtcF90cmVhdG1lbnQgY29sdW1uLCB3aGljaCB3aWxsIGJlIGEgZHVwbGljYXRlIHBvc3QtbWVyZ2UKcGNhX0xfMTAwMCA8LSBtZXJnZShwY2FfTF8xMDAwLCBjb2Rfc2FtcGxlX2luZm8sIGJ5LnggPSAibmFtZSIsIGJ5LnkgPSAicm93Lm5hbWVzIikKCiMgYWxsIGdlbmVzCnBjYV9MX2FsbCA8LSBwbG90UENBKHZzdChkZHNfTCksIGludGdyb3VwID0gYygidGVtcF90cmVhdG1lbnQiKSwgcmV0dXJuRGF0YT1UUlVFLCBudG9wPW5yb3coYXNzYXkodnN0KGRkc19MKSkpKQpwZXJjZW50VmFyX0xfYWxsIDwtIHJvdW5kKDEwMCphdHRyKHBjYV9MX2FsbCwgInBlcmNlbnRWYXIiKSkKIyBtZXJnZSB3aXRoIG1ldGFkYXRhIHNoZWV0IHNvIHdlIGNhbiBwbG90IHVzaW5nIG90aGVyIGZlYXR1cmVzCnBjYV9MX2FsbCA8LSBzdWJzZXQocGNhX0xfYWxsLCBzZWxlY3Q9LXRlbXBfdHJlYXRtZW50KSAjcmVtb3ZlIHRoZSB0ZW1wX3RyZWF0bWVudCBjb2x1bW4sIHdoaWNoIHdpbGwgYmUgYSBkdXBsaWNhdGUgcG9zdC1tZXJnZQpwY2FfTF9hbGwgPC0gbWVyZ2UocGNhX0xfYWxsLCBjb2Rfc2FtcGxlX2luZm8sIGJ5LnggPSAibmFtZSIsIGJ5LnkgPSAicm93Lm5hbWVzIikKCiMgQXNzaWduIHNwZWNpZmljIGNvbG9ycyB0byBlYWNoIHRlbXBlcmF0dXJlIHRyZWF0bWVudCBsZXZlbAp0ZW1wX2NvbG9ycyA8LSBjKAogICIwIiA9ICJkYXJrYmx1ZSIsCiAgIjUiID0gInJveWFsYmx1ZTEiLAogICI5IiA9ICJncmVlbiIsCiAgIjE2IiA9ICJvcmFuZ2VyZWQiKSAKCiMgUGxvdCBQQ0FzCnAuTC41MDAgPC0gZ2dwbG90KHBjYV9MXzUwMCwgYWVzKFBDMSwgUEMyLCBjb2xvcj10ZW1wX3RyZWF0bWVudCkpICsgCiAgZ2VvbV9wb2ludChzaXplPTQsIGFscGhhID0gNS8xMCkgKwogIGdndGl0bGUoIkxpdmVyLCB0b3AgNTAwIG1vc3QgdmFyaWFibGUgZ2VuZXMiKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyX0xfNTAwWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRWYXJfTF81MDBbMl0sIiUgdmFyaWFuY2UiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXRlbXBfY29sb3JzKSsKICBzdGF0X2VsbGlwc2UoKQoKcC5MLjUwMC5TTGRpZmYgPC0gZ2dwbG90KHBjYV9MXzUwMCwgYWVzKFBDMSwgUEMyLCBjb2xvcj10ZW1wX3RyZWF0bWVudCwgc2l6ZT1TTF9kaWZmX21tKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgZ2d0aXRsZSgiTGl2ZXIsIHRvcCA1MDAgbW9zdCB2YXJpYWJsZSBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyX0xfNTAwWzFdLCAiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhcl9MXzUwMFsyXSwgIiUgdmFyaWFuY2UiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGVtcF9jb2xvcnMpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoKSArICAjIEFkZCB0aGlzIGxpbmUgdG8gY29udHJvbCB0aGUgc2l6ZSBvZiBwb2ludHMKICBzdGF0X2VsbGlwc2UoKQoKcC5MLjUwMC5XV1RkaWZmIDwtIGdncGxvdChwY2FfTF81MDAsIGFlcyhQQzEsIFBDMiwgY29sb3I9dGVtcF90cmVhdG1lbnQsIHNpemU9V1dUX2RpZmZfZykpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKwogIGdndGl0bGUoIkxpdmVyLCB0b3AgNTAwIG1vc3QgdmFyaWFibGUgZ2VuZXMiKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhcl9MXzUwMFsxXSwgIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRWYXJfTF81MDBbMl0sICIlIHZhcmlhbmNlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHRlbXBfY29sb3JzKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKCkgKyAgIyBBZGQgdGhpcyBsaW5lIHRvIGNvbnRyb2wgdGhlIHNpemUgb2YgcG9pbnRzCiAgc3RhdF9lbGxpcHNlKCkKCnAuTC4xMDAwIDwtIGdncGxvdChwY2FfTF8xMDAwLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50KSkgKyAKICBnZW9tX3BvaW50KHNpemU9NCwgYWxwaGEgPSA1LzEwKSArCiAgZ2d0aXRsZSgiTGl2ZXIsIHRvcCAxMDAwIG1vc3QgdmFyaWFibGUgZ2VuZXMiKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyX0xfMTAwMFsxXSwiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIixwZXJjZW50VmFyX0xfMTAwMFsyXSwiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dGVtcF9jb2xvcnMpKwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuMTAwMC5TTGRpZmYgPC0gZ2dwbG90KHBjYV9MXzEwMDAsIGFlcyhQQzEsIFBDMiwgY29sb3I9dGVtcF90cmVhdG1lbnQsIHNpemU9U0xfZGlmZl9tbSkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKwogIGdndGl0bGUoIkxpdmVyLCB0b3AgMTAwMCBtb3N0IHZhcmlhYmxlIGdlbmVzIikgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJfTF81MDBbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyX0xfNTAwWzJdLCAiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ZW1wX2NvbG9ycykgKwogIHNjYWxlX3NpemVfY29udGludW91cygpICsgICMgQWRkIHRoaXMgbGluZSB0byBjb250cm9sIHRoZSBzaXplIG9mIHBvaW50cwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuMTAwMC5XV1RkaWZmIDwtIGdncGxvdChwY2FfTF8xMDAwLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50LCBzaXplPVdXVF9kaWZmX2cpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBnZ3RpdGxlKCJMaXZlciwgdG9wIDEwMDAgbW9zdCB2YXJpYWJsZSBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyX0xfNTAwWzFdLCAiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhcl9MXzUwMFsyXSwgIiUgdmFyaWFuY2UiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGVtcF9jb2xvcnMpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoKSArICAjIEFkZCB0aGlzIGxpbmUgdG8gY29udHJvbCB0aGUgc2l6ZSBvZiBwb2ludHMKICBzdGF0X2VsbGlwc2UoKQoKcC5MLmFsbCA8LSBnZ3Bsb3QocGNhX0xfYWxsLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50KSkgKyAKICBnZW9tX3BvaW50KHNpemU9NCwgYWxwaGEgPSA1LzEwKSArCiAgZ2d0aXRsZSgiTGl2ZXIsIGFsbCBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLHBlcmNlbnRWYXJfTF9hbGxbMV0sIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIscGVyY2VudFZhcl9MX2FsbFsyXSwiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dGVtcF9jb2xvcnMpKwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuYWxsLlNMZGlmZiA8LSBnZ3Bsb3QocGNhX0xfYWxsLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50LCBzaXplPVNMX2RpZmZfbW0pKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBnZ3RpdGxlKCJMaXZlciwgYWxsIGdlbmVzIikgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJfTF81MDBbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyX0xfNTAwWzJdLCAiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ZW1wX2NvbG9ycykgKwogIHNjYWxlX3NpemVfY29udGludW91cygpICsgICMgQWRkIHRoaXMgbGluZSB0byBjb250cm9sIHRoZSBzaXplIG9mIHBvaW50cwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuYWxsLldXVGRpZmYgPC0gZ2dwbG90KHBjYV9MX2FsbCwgYWVzKFBDMSwgUEMyLCBjb2xvcj10ZW1wX3RyZWF0bWVudCwgc2l6ZT1XV1RfZGlmZl9nKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgZ2d0aXRsZSgiTGl2ZXIsIGFsbCBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyX0xfNTAwWzFdLCAiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhcl9MXzUwMFsyXSwgIiUgdmFyaWFuY2UiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGVtcF9jb2xvcnMpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoKSArICAjIEFkZCB0aGlzIGxpbmUgdG8gY29udHJvbCB0aGUgc2l6ZSBvZiBwb2ludHMKICBzdGF0X2VsbGlwc2UoKQoKIyBWaWV3IFBDQXMKcC5MLjUwMApwLkwuNTAwLlNMZGlmZgpwLkwuNTAwLldXVGRpZmYKcC5MLjEwMDAKcC5MLjEwMDAuU0xkaWZmCnAuTC4xMDAwLldXVGRpZmYKcC5MLmFsbApwLkwuYWxsLlNMZGlmZgpwLkwuYWxsLldXVGRpZmYKCiMgRXhwb3J0IFBDQXMgYXMgcG5ncwpnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvUENBX0xfNTAwLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IHAuTC41MDAsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNjAwMCwKICAgICAgICAgaGVpZ2h0ID0gNDAwMCkKCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9QQ0FfTF8xMDAwLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IHAuTC4xMDAwLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDYwMDAsCiAgICAgICAgIGhlaWdodCA9IDQwMDApCgpnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvUENBX0xfYWxsLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IHAuTC5hbGwsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNjAwMCwKICAgICAgICAgaGVpZ2h0ID0gNDAwMCkKYGBgCgojIExpdmVyIHRpc3N1ZSwgOSpDIHYuIDE2KkMKClRoZSA5XCpDIHRlbXBlcmF0dXJlIHRyZWF0bWVudCBpcyBlZmZlY3RpdmVseSBvdXIgImNvbnRyb2wsIiBhcyBpdCByZXByZXNlbnRzIHRoZSBhbWJpZW50IHRlbXBlcmF0dXJlIHRoYXQgd2lsZCBqdXZlbmlsZSBQYWNpZmljIGNvZCB3b3VsZCBleHBlcmllbmNlLgoKYGBge3IsIGNhY2hlPVRSVUV9CiMgbGl2ZXIgdGlzc3VlLCB0ZW1wZXJhdHVyZXMgOSB2cy4gMTYgCgojIEZpbHRlciBkYXRhCmluZm9zdWJfTC45LjE2IDwtIGNvZF9zYW1wbGVfaW5mbyAlPiUgZmlsdGVyKHRpc3N1ZV90eXBlID09ICJMaXZlciIgJiAodGVtcF90cmVhdG1lbnQgPT0gIjkiIHwgdGVtcF90cmVhdG1lbnQgPT0gIjE2IikpCmNvdW50c3ViX0wuOS4xNiA8LSBzdWJzZXQoY29kX2NvdW50c19kYXRhLCBzZWxlY3Q9cm93Lm5hbWVzKGluZm9zdWJfTC45LjE2KSkKCiMgQ2FsY3VsYXRlIERFU2VxIG9iamVjdApkZHNfTC45LjE2IDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzdWJfTC45LjE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gaW5mb3N1Yl9MLjkuMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gdGVtcF90cmVhdG1lbnQpCgpkZHNfTC45LjE2IDwtIERFU2VxKGRkc19MLjkuMTYpCnJlc3VsdHNOYW1lcyhkZHNfTC45LjE2KSAjIGxpc3RzIHRoZSBjb2VmZmljaWVudHMKYGBgCgpgYGB7cn0KcGxvdERpc3BFc3RzKGRkc19MLjkuMTYpCmBgYAoKYGBge3IsIGNhY2hlPVRSVUV9CiMgRmlsdGVyaW5nOiBrZWVwIGdlbmVzIHRoYXQgaGF2ZSBhdCBsZWFzdCAxMCBjb3VudHMgYWNyb3NzIDEvMyBvZiB0aGUgc2FtcGxlcyAtIGh0dHBzOi8vc3VwcG9ydC5iaW9jb25kdWN0b3Iub3JnL3AvMTEwMzA3LwprZWVwIDwtIHJvd1N1bXMoREVTZXEyOjpjb3VudHMoZGRzX0wuOS4xNikgPj0gMTApID49IG5jb2woY291bnRzdWJfTC45LjE2KS8zCmRkc19MLjkuMTY8LSBkZHNfTC45LjE2W2tlZXAsXQoKIyBHZW5lcmF0ZSBDb250cmFzdHMKY29udHJhc3RfbGlzdF9MLjkuMTYgICAgICAgIDwtIGMoInRlbXBfdHJlYXRtZW50IiwgIjE2IiwgIjkiKSAjIG9yZGVyIGlzIGltcG9ydGFudDogZmFjdG9yLCB0cmVhdG1lbnQgZ3JvdXAsIGNvbnRyb2wKcmVzX3RhYmxlX0wuOS4xNl9ub3NocmluayA8LSByZXN1bHRzKGRkc19MLjkuMTYsIGNvbnRyYXN0PWNvbnRyYXN0X2xpc3RfTC45LjE2LCBhbHBoYSA9IDAuMDUpCgpyZXNfdGFibGVfTC45LjE2X25vcm0gICAgIDwtIGxmY1NocmluayhkZHNfTC45LjE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9Im5vcm1hbCIpICMgbGZjVGhyZXNob2xkID0gMC41ODUpICAjIGEgbGZjIHRocmVzaG9sZCBvZiAxID0gMi1mb2xkIGNoYW5nZSwgMC41ODUgPSAxLjUtZm9sZCBjaGFuZ2UKcmVzX3RhYmxlX0wuOS4xNl9hcGVnbG0gICA8LSBsZmNTaHJpbmsoZGRzX0wuOS4xNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZj0yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0iYXBlZ2xtIikgIyBsZmNUaHJlc2hvbGQgPSAwLjU4NSkgICMgYSBsZmMgdGhyZXNob2xkIG9mIDEgPSAyLWZvbGQgY2hhbmdlLCAwLjU4NSA9IDEuNS1mb2xkIGNoYW5nZQpyZXNfdGFibGVfTC45LjE2X2FzaHIgICAgIDwtIGxmY1NocmluayhkZHNfTC45LjE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPSJhc2hyIikKYGBgCgpgYGB7cn0KIyBHZW5lcmF0ZSBNQSBwbG90cwpwYXIobWZyb3c9YygyLDIpLCBtYXI9Yyg0LDQsMiwxKSkKeGxpbSA8LSBjKDEsMWU1KTsgeWxpbSA8LSBjKC00LDQpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMTZfbm9zaHJpbmssIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJubyBzaHJpbmsiKQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjE2X25vcm0sIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJub3JtYWwiKQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjE2X2FwZWdsbSwgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49ImFwZWdsbSIpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMTZfYXNociwgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49ImFzaHIiKQpgYGAKCmBgYHtyfQojIEV4YW1pbmUgcmVzdWx0cyBmb3JtYXR0aW5nCnJlc190YWJsZV9MLjkuMTZfbm9ybSAlPiUgZGF0YS5mcmFtZSgpICU+JSBoZWFkKCkKYGBgCgpOb3RlIHRoYXQgdGhlIG1ldHJpYyB3ZSB3YW50IHRvIHVzZSB0byBpZGVudGlmeSBzaWduaWZpY2FudGx5IGV4cHJlc3NlZCBnZW5lcyBpcyB0aGUgYHBhZGpgIHZhbHVlcywgKipOT1QqKiB0aGUgYHB2YWx1ZWAuIGBwYWRqYCBhcmUgcC12YWx1ZXMgY29ycmVjdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nIChkZWZhdWx0IG1ldGhvZCBpcyB0aGUgQmVuamFtaW5pIGFuZCBIb2NoYmVyZyBtZXRob2QpLgoKYGBge3J9CnN1bW1hcnkocmVzX3RhYmxlX0wuOS4xNl9ub3NocmluaykKc3VtbWFyeShyZXNfdGFibGVfTC45LjE2X25vcm0pCnN1bW1hcnkocmVzX3RhYmxlX0wuOS4xNl9hcGVnbG0pCnN1bW1hcnkocmVzX3RhYmxlX0wuOS4xNl9hc2hyKQpgYGAKCiMjIEV4dHJhY3Rpbmcgc2lnbmlmaWNhbnRseSBleHByZXNzZWQgZ2VuZXMKCmBgYHtyfQpwYWRqLmN1dG9mZiA8LSAwLjA1CmxmYy5jdXRvZmYgPC0gMC41OAoKIyBDb252ZXJ0IHJlc3VsdHMgdGFibGUgaW50byB0aWJibGUKcmVzX3RhYmxlX0wuOS4xNl9ub3JtX3RiIDwtIHJlc190YWJsZV9MLjkuMTZfbm9ybSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhcj0iZ2VuZSIpICU+JQogIGFzX3RpYmJsZSgpCgojIHN1YnNldCB0aGF0IHRhYmxlIHRvIG9ubHkga2VlcCB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgdXNpbmcgb3VyIHByZS1kZWZpbmVkIHRocmVzaG9sZHM6CnNpZ19MLjkuMTZfbm9ybV9ub0xGQ2N1dG9mZiA8LSByZXNfdGFibGVfTC45LjE2X25vcm1fdGIgJT4lCiAgZmlsdGVyKHBhZGogPCBwYWRqLmN1dG9mZikKCnNpZ19MLjkuMTZfbm9ybSA8LSBzaWdfTC45LjE2X25vcm1fbm9MRkNjdXRvZmYgJT4lIAogIGZpbHRlcihhYnMobG9nMkZvbGRDaGFuZ2UpID4gbGZjLmN1dG9mZikKCmhlYWQoc2lnX0wuOS4xNl9ub3JtX25vTEZDY3V0b2ZmKQpwYXN0ZSgiTnVtYmVyIG9mIHNpZ25pZmljYW50IERFR3MgZm9yIDlDIHYgMTZDOiIsIG5yb3coc2lnX0wuOS4xNl9ub3JtX25vTEZDY3V0b2ZmKSwgIihwYWRqPCIsIHBhZGouY3V0b2ZmLCAiKSIpCgpoZWFkKHNpZ19MLjkuMTZfbm9ybSkKcGFzdGUoIk51bWJlciBvZiBzaWduaWZpY2FudCBERUdzIGZvciA5QyB2IDE2QzoiLCBucm93KHNpZ19MLjkuMTZfbm9ybSksICIocGFkajwiLCBwYWRqLmN1dG9mZiwgIiwgbG9nLWZvbGQgY2hhbmdlID4iLCBsZmMuY3V0b2ZmLCAiKSIpCgp3cml0ZS50YWJsZShzaWdfTC45LjE2X25vcm1fbm9MRkNjdXRvZmYsIGZpbGUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0dtYWNfREVHc19zaWdfTC45LjE2X25vcm1fbm9MRkNjdXRvZmYudGFiIiwgc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gTkEpCgp3cml0ZS50YWJsZShzaWdfTC45LjE2X25vcm0sIGZpbGUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0dtYWNfREVHc19zaWdfTC45LjE2X25vcm0udGFiIiwgc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gTkEpCmBgYAoKIyMgSGVhdG1hcAoKRm9yIERFR3MgYmFzZWQgb24gYWRqdXN0ZWQgcC12YWx1ZSAqYW5kKiBsb2cgZm9sZC1jaGFuZ2UKYGBge3J9CiMgUmV0cmlldmUgbm9ybWFsaXplZCBjb3VudHMgbWF0cml4CmRkc19MLjkuMTZfbm9ybV9jb3VudHMgPC0gY291bnRzKGRkc19MLjkuMTYsIG5vcm1hbGl6ZWQ9VFJVRSkKCiMgRXh0cmFjdCBub3JtYWxpemVkIGV4cHJlc3Npb24gZm9yIHNpZ25pZmljYW50IGdlbmVzCm5vcm1fc2lnX0wuOS4xNiA8LSBkZHNfTC45LjE2X25vcm1fY291bnRzICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lCiAgZmlsdGVyKHJvdy5uYW1lcyhkZHNfTC45LjE2X25vcm1fY291bnRzKSAlaW4lIHNpZ19MLjkuMTZfbm9ybSRnZW5lKQoKaGVhZChub3JtX3NpZ19MLjkuMTYpCgojIEFubm90YXRlIGhlYXRtYXAKYW5ub3RhdGlvbiA8LSBpbmZvc3ViX0wuOS4xNiAlPiUgCglkcGx5cjo6c2VsZWN0KHRlbXBfdHJlYXRtZW50KQoKIyBTZXQgYSBjb2xvciBwYWxldHRlCmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCgojIFJ1biBwaGVhdG1hcApoLkwuOS4xNiA8LSBwaGVhdG1hcChub3JtX3NpZ19MLjkuMTYsIAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwgCiAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uID0gYW5ub3RhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgIGJvcmRlcl9jb2xvciA9IE5BLCAKICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSAicm93IiwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMzAsCiAgICAgICAgICAgICAgICAgICAgIG1haW4gPSAiTm9ybWFsaXplZCBTaWduaWZpY2FudCBFeHByZXNzaW9uLCBMaXZlciwgOSpDIGFuZCAxNipDIikKCiMgU2F2ZSBwbG90CmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9oZWF0bWFwX0wuOS4xNl9ub3JtX3NpZy5wbmciLAogICAgICAgICBwbG90ICAgPSBoLkwuOS4xNiwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA1MDAwLAogICAgICAgICBoZWlnaHQgPSA1MDAwKQpgYGAKCk5vdGUgdGhlIGFyZ3VtZW50IGBzY2FsZT0icm93ImAgd2FzIGluY2x1ZGVkLCBzbyB0aGUgdmFsdWVzIHBsb3R0ZWQgaW4gdGhlIGhlYXQgbWFwIGFyZSAqWi1zY29yZXMqLCByYXRoZXIgdGhuIHRoZSBub3JtYWxpemVkIGNvdW50IHZhbHVlLiBUaGlzIHZhc3RseSBpbXByb3ZlcyB0aGUgY29sb3IgdmlzdWFsaXphdGlvbi4KCkZvciBERUdzIGJhc2VkIG9uIGFkanVzdGVkIHAtdmFsdWUgKm9ubHkqCmBgYHtyfQojIEV4dHJhY3Qgbm9ybWFsaXplZCBleHByZXNzaW9uIGZvciBzaWduaWZpY2FudCBnZW5lcwpub3JtX3NpZ19MLjkuMTZfbm9MRkNjdXRvZmYgPC0gZGRzX0wuOS4xNl9ub3JtX2NvdW50cyAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JQogIGZpbHRlcihyb3cubmFtZXMoZGRzX0wuOS4xNl9ub3JtX2NvdW50cykgJWluJSBzaWdfTC45LjE2X25vcm1fbm9MRkNjdXRvZmYkZ2VuZSkKCmhlYWQobm9ybV9zaWdfTC45LjE2X25vTEZDY3V0b2ZmKQoKIyBBbm5vdGF0ZSBoZWF0bWFwCmFubm90YXRpb24gPC0gaW5mb3N1Yl9MLjkuMTYgJT4lIAoJZHBseXI6OnNlbGVjdCh0ZW1wX3RyZWF0bWVudCkKCiMgU2V0IGEgY29sb3IgcGFsZXR0ZQpoZWF0X2NvbG9ycyA8LSByZXYoYnJld2VyLnBhbCgxMiwgIlJkWWxCdSIpKQoKIyBSdW4gcGhlYXRtYXAKaC5MLjkuMTYgPC0gcGhlYXRtYXAobm9ybV9zaWdfTC45LjE2X25vTEZDY3V0b2ZmLCAKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgCiAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsIAogICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbiA9IGFubm90YXRpb24sIAogICAgICAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsIAogICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDMwLAogICAgICAgICAgICAgICAgICAgICBtYWluID0gIk5vcm1hbGl6ZWQgU2lnbmlmaWNhbnQgRXhwcmVzc2lvbiAobm8gTEZDIGN1dG9mZiksIExpdmVyLCA5KkMgYW5kIDE2KkMiKQoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL2hlYXRtYXBfTC45LjE2X25vcm1fc2lnX25vTEZDY3V0b2ZmLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGguTC45LjE2LAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDUwMDAsCiAgICAgICAgIGhlaWdodCA9IDUwMDApCmBgYAoKTm90ZSB0aGUgYXJndW1lbnQgYHNjYWxlPSJyb3ciYCB3YXMgaW5jbHVkZWQsIHNvIHRoZSB2YWx1ZXMgcGxvdHRlZCBpbiB0aGUgaGVhdCBtYXAgYXJlICpaLXNjb3JlcyosIHJhdGhlciB0aG4gdGhlIG5vcm1hbGl6ZWQgY291bnQgdmFsdWUuIFRoaXMgdmFzdGx5IGltcHJvdmVzIHRoZSBjb2xvciB2aXN1YWxpemF0aW9uLgoKIyMgVm9sY2FubyBwbG90CgpgYGB7cn0KIyBHZW5lcmF0ZSBwbG90CnYuTC45LjE2IDwtIAogIGdncGxvdChyZXNfdGFibGVfTC45LjE2X25vcm1fdGIpICsKICAjIFBsb3QgYWxsCiAgZ2VvbV9wb2ludChhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksY29sb3I9InVuY2hhbmdlZCIpLAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogICMgT3ZlcmxheSBhbGwgc2lnbmlmaWNhbnRseSB1cHJlZ3VsYXRlZCBpbiByZWQKICBnZW9tX3BvaW50KGRhdGEgPSBzaWdfTC45LjE2X25vcm1bc2lnX0wuOS4xNl9ub3JtJGxvZzJGb2xkQ2hhbmdlID4gMCwgXSwgCiAgICAgICAgICAgICBhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksIGNvbG9yPSJ1cHJlZ3VsYXRlZCIpLCAKICAgICAgICAgICAgIHNpemU9LjUpICsKICAjIE92ZXJsYXkgYWxsIHNpZ25pZmljYW50bHkgZG93bnJlZ3VsYXRlZCBpbiBibHVlCiAgZ2VvbV9wb2ludChkYXRhID0gc2lnX0wuOS4xNl9ub3JtW3NpZ19MLjkuMTZfbm9ybSRsb2cyRm9sZENoYW5nZSA8IDAsIF0sIAogICAgICAgICAgICAgYWVzKHg9bG9nMkZvbGRDaGFuZ2UsIHk9LWxvZzEwKHBhZGopLCBjb2xvcj0iZG93bnJlZ3VsYXRlZCIpLCAKICAgICAgICAgICAgIHNpemU9LjUpICsKICBnZ3RpdGxlKCJMaXZlciwgOSpDIGFuZCAxNipDIikgKwogIHhsYWIoImxvZzIgZm9sZCBjaGFuZ2UiKSArIAogIHlsYWIoIi1sb2cxMCBhZGp1c3RlZCBwLXZhbHVlIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC00LDQpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwzMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygidW5jaGFuZ2VkIiA9ICJkYXJrZ3JleSIsICJ1cHJlZ3VsYXRlZCIgPSAicmVkIiwgImRvd25yZWd1bGF0ZWQiID0gImJsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygidW5jaGFuZ2VkIiA9ICJVbmNoYW5nZWQiLCAidXByZWd1bGF0ZWQiID0gIlVwcmVndWxhdGVkIiwgImRvd25yZWd1bGF0ZWQiID0gIkRvd25yZWd1bGF0ZWQiKSwKICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IE5VTEwpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSwgaGp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjI1KSkpCgp2LkwuOS4xNgoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL3ZvbGNhbm9fTC45LjE2LnBuZyIsCiAgICAgICAgIHBsb3QgICA9IHYuTC45LjE2LAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDYwMDAsCiAgICAgICAgIGhlaWdodCA9IDQwMDApCmBgYAoKIyMgUGxvdCBleHByZXNzaW9uIG9mIHRvcCBERUdzIGFjcm9zcyB0cmVhdG1lbnRzCgpgYGB7cn0KdG9wMTVERUdzX0wuOS4xNiA8LSBzaWdfTC45LjE2X25vcm1fbm9MRkNjdXRvZmYgJT4lCiAgYXJyYW5nZShwYWRqKSAlPiUKICBzbGljZV9oZWFkKG49MTUpCgpwbG90X2dlbmVfZGF0YSA8LSBmdW5jdGlvbihnZW5lTmFtZSkgewogIGdlbmVfZGF0YSA8LSBjb2RfY291bnRzZGF0YV9wbHVzX3NhbXBsZWluZm8gJT4lCiAgICBmaWx0ZXIoZ2VuZSA9PSBnZW5lTmFtZSkKICAKICBnZ3Bsb3QoZGF0YSA9IGdlbmVfZGF0YSwgCiAgICAgICAgIGFlcyh4ID0gdGVtcF90cmVhdG1lbnQsIHkgPSBjb3VudCwgY29sb3IgPSBmYWN0b3IodGVtcF90cmVhdG1lbnQpKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMSksIHNpemUgPSAyKSArCiAgICBsYWJzKHRpdGxlID0gZ2VuZU5hbWUsIHggPSAiU2FtcGxlIiwgeSA9ICJDb3VudCIsIGNvbG9yID0gIlRyZWF0bWVudCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGVtcF9jb2xvcnMpICsKICAgIHRoZW1lX21pbmltYWwoKQp9CgoKTC45LjE2X0RFRzEgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4xNlsxLCBdJGdlbmUpCkwuOS4xNl9ERUcxCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMTZfREVHMS4iLHRvcDE1REVHc19MLjkuMTZbMSwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMTZfREVHMSwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMTZfREVHMiA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjE2WzIsIF0kZ2VuZSkKTC45LjE2X0RFRzIKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4xNl9ERUcyLiIsdG9wMTVERUdzX0wuOS4xNlsyLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4xNl9ERUcyLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4xNl9ERUczIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMTZbMywgXSRnZW5lKQpMLjkuMTZfREVHMwpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjE2X0RFRzMuIix0b3AxNURFR3NfTC45LjE2WzMsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjE2X0RFRzMsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjE2X0RFRzQgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4xNls0LCBdJGdlbmUpCkwuOS4xNl9ERUc0CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMTZfREVHNC4iLHRvcDE1REVHc19MLjkuMTZbNCwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMTZfREVHNCwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMTZfREVHNSA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjE2WzUsIF0kZ2VuZSkKTC45LjE2X0RFRzUKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4xNl9ERUc1LiIsdG9wMTVERUdzX0wuOS4xNls1LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4xNl9ERUc1LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4xNl9ERUc2IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMTZbNiwgXSRnZW5lKQpMLjkuMTZfREVHNgpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjE2X0RFRzYuIix0b3AxNURFR3NfTC45LjE2WzYsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjE2X0RFRzYsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjE2X0RFRzcgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4xNls3LCBdJGdlbmUpCkwuOS4xNl9ERUc3CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMTZfREVHNy4iLHRvcDE1REVHc19MLjkuMTZbNywgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMTZfREVHNywgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMTZfREVHOCA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjE2WzgsIF0kZ2VuZSkKTC45LjE2X0RFRzgKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4xNl9ERUc4LiIsdG9wMTVERUdzX0wuOS4xNls4LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4xNl9ERUc4LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4xNl9ERUc5IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMTZbOSwgXSRnZW5lKQpMLjkuMTZfREVHOQpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjE2X0RFRzkuIix0b3AxNURFR3NfTC45LjE2WzksIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjE2X0RFRzksIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjE2X0RFRzEwIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMTZbMTAsIF0kZ2VuZSkKTC45LjE2X0RFRzEwCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMTZfREVHMTAuIix0b3AxNURFR3NfTC45LjE2WzEwLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4xNl9ERUcxMCwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMTZfREVHMTEgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4xNlsxMSwgXSRnZW5lKQpMLjkuMTZfREVHMTEKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4xNl9ERUcxMS4iLHRvcDE1REVHc19MLjkuMTZbMTEsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjE2X0RFRzExLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4xNl9ERUcxMiA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjE2WzEyLCBdJGdlbmUpCkwuOS4xNl9ERUcxMgpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjE2X0RFRzEyLiIsdG9wMTVERUdzX0wuOS4xNlsxMiwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMTZfREVHMTIsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjE2X0RFRzEzIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMTZbMTMsIF0kZ2VuZSkKTC45LjE2X0RFRzEzCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMTZfREVHMTMuIix0b3AxNURFR3NfTC45LjE2WzEzLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4xNl9ERUcxMywgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMTZfREVHMTQgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4xNlsxNCwgXSRnZW5lKQpMLjkuMTZfREVHMTQKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4xNl9ERUcxNC4iLHRvcDE1REVHc19MLjkuMTZbMTQsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjE2X0RFRzE0LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4xNl9ERUcxNSA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjE2WzE1LCBdJGdlbmUpCkwuOS4xNl9ERUcxNQpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjE2X0RFRzE1LiIsdG9wMTVERUdzX0wuOS4xNlsxNSwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMTZfREVHMTUsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKYGBgCiMgTGl2ZXIgdGlzc3VlLCA5KkMgdi4gMCpDCgpUaGUgOVwqQyB0ZW1wZXJhdHVyZSB0cmVhdG1lbnQgaXMgZWZmZWN0aXZlbHkgb3VyICJjb250cm9sLCIgYXMgaXQgcmVwcmVzZW50cyB0aGUgYW1iaWVudCB0ZW1wZXJhdHVyZSB0aGF0IHdpbGQganV2ZW5pbGUgUGFjaWZpYyBjb2Qgd291bGQgZXhwZXJpZW5jZS4KCmBgYHtyLCBjYWNoZT1UUlVFfQojIGxpdmVyIHRpc3N1ZSwgdGVtcGVyYXR1cmVzIDkgdnMuIDAgCgojIEZpbHRlciBkYXRhCmluZm9zdWJfTC45LjAgPC0gY29kX3NhbXBsZV9pbmZvICU+JSBmaWx0ZXIodGlzc3VlX3R5cGUgPT0gIkxpdmVyIiAmICh0ZW1wX3RyZWF0bWVudCA9PSAiOSIgfCB0ZW1wX3RyZWF0bWVudCA9PSAiMCIpKQpjb3VudHN1Yl9MLjkuMCA8LSBzdWJzZXQoY29kX2NvdW50c19kYXRhLCBzZWxlY3Q9cm93Lm5hbWVzKGluZm9zdWJfTC45LjApKQoKIyBDYWxjdWxhdGUgREVTZXEgb2JqZWN0CmRkc19MLjkuMCA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGNvdW50c3ViX0wuOS4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gaW5mb3N1Yl9MLjkuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiB0ZW1wX3RyZWF0bWVudCkKCmRkc19MLjkuMCA8LSBERVNlcShkZHNfTC45LjApCnJlc3VsdHNOYW1lcyhkZHNfTC45LjApICMgbGlzdHMgdGhlIGNvZWZmaWNpZW50cwpgYGAKCmBgYHtyfQpwbG90RGlzcEVzdHMoZGRzX0wuOS4wKQpgYGAKCmBgYHtyLCBjYWNoZT1UUlVFfQojIEZpbHRlcmluZzoga2VlcCBnZW5lcyB0aGF0IGhhdmUgYXQgbGVhc3QgMTAgY291bnRzIGFjcm9zcyAxLzMgb2YgdGhlIHNhbXBsZXMgLSBodHRwczovL3N1cHBvcnQuYmlvY29uZHVjdG9yLm9yZy9wLzExMDMwNy8Ka2VlcCA8LSByb3dTdW1zKERFU2VxMjo6Y291bnRzKGRkc19MLjkuMCkgPj0gMTApID49IG5jb2woY291bnRzdWJfTC45LjApLzMKZGRzX0wuOS4wPC0gZGRzX0wuOS4wW2tlZXAsXQoKIyBHZW5lcmF0ZSBDb250cmFzdHMKY29udHJhc3RfbGlzdF9MLjkuMCAgICAgICAgPC0gYygidGVtcF90cmVhdG1lbnQiLCAiMCIsICI5IikgIyBvcmRlciBpcyBpbXBvcnRhbnQ6IGZhY3RvciwgdHJlYXRtZW50IGdyb3VwLCBjb250cm9sCnJlc190YWJsZV9MLjkuMF9ub3NocmluayA8LSByZXN1bHRzKGRkc19MLjkuMCwgY29udHJhc3Q9Y29udHJhc3RfbGlzdF9MLjkuMCwgYWxwaGEgPSAwLjA1KQoKcmVzX3RhYmxlX0wuOS4wX25vcm0gICAgIDwtIGxmY1NocmluayhkZHNfTC45LjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0ibm9ybWFsIikgIyBsZmNUaHJlc2hvbGQgPSAwLjU4NSkgICMgYSBsZmMgdGhyZXNob2xkIG9mIDEgPSAyLWZvbGQgY2hhbmdlLCAwLjU4NSA9IDEuNS1mb2xkIGNoYW5nZQpyZXNfdGFibGVfTC45LjBfYXBlZ2xtICAgPC0gbGZjU2hyaW5rKGRkc19MLjkuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZj0yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0iYXBlZ2xtIikgIyBsZmNUaHJlc2hvbGQgPSAwLjU4NSkgICMgYSBsZmMgdGhyZXNob2xkIG9mIDEgPSAyLWZvbGQgY2hhbmdlLCAwLjU4NSA9IDEuNS1mb2xkIGNoYW5nZQpyZXNfdGFibGVfTC45LjBfYXNociAgICAgPC0gbGZjU2hyaW5rKGRkc19MLjkuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZj0yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0iYXNociIpCmBgYAoKYGBge3J9CiMgR2VuZXJhdGUgTUEgcGxvdHMKcGFyKG1mcm93PWMoMiwyKSwgbWFyPWMoNCw0LDIsMSkpCnhsaW0gPC0gYygxLDFlNSk7IHlsaW0gPC0gYygtNCw0KQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjBfbm9zaHJpbmssIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJubyBzaHJpbmsiKQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjBfbm9ybSwgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49Im5vcm1hbCIpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMF9hcGVnbG0sIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJhcGVnbG0iKQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjBfYXNociwgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49ImFzaHIiKQpgYGAKCmBgYHtyfQojIEV4YW1pbmUgcmVzdWx0cyBmb3JtYXR0aW5nCnJlc190YWJsZV9MLjkuMF9ub3JtICU+JSBkYXRhLmZyYW1lKCkgJT4lIGhlYWQoKQpgYGAKCk5vdGUgdGhhdCB0aGUgbWV0cmljIHdlIHdhbnQgdG8gdXNlIHRvIGlkZW50aWZ5IHNpZ25pZmljYW50bHkgZXhwcmVzc2VkIGdlbmVzIGlzIHRoZSBgcGFkamAgdmFsdWVzLCAqKk5PVCoqIHRoZSBgcHZhbHVlYC4gYHBhZGpgIGFyZSBwLXZhbHVlcyBjb3JyZWN0ZWQgZm9yIG11bHRpcGxlIHRlc3RpbmcgKGRlZmF1bHQgbWV0aG9kIGlzIHRoZSBCZW5qYW1pbmkgYW5kIEhvY2hiZXJnIG1ldGhvZCkuCgpgYGB7cn0Kc3VtbWFyeShyZXNfdGFibGVfTC45LjBfbm9zaHJpbmspCnN1bW1hcnkocmVzX3RhYmxlX0wuOS4wX25vcm0pCnN1bW1hcnkocmVzX3RhYmxlX0wuOS4wX2FwZWdsbSkKc3VtbWFyeShyZXNfdGFibGVfTC45LjBfYXNocikKYGBgCgojIyBFeHRyYWN0aW5nIHNpZ25pZmljYW50bHkgZXhwcmVzc2VkIGdlbmVzCgpgYGB7cn0KcGFkai5jdXRvZmYgPC0gMC4wNQpsZmMuY3V0b2ZmIDwtIDAuNTgKCiMgQ29udmVydCByZXN1bHRzIHRhYmxlIGludG8gdGliYmxlCnJlc190YWJsZV9MLjkuMF9ub3JtX3RiIDwtIHJlc190YWJsZV9MLjkuMF9ub3JtICU+JQogIGRhdGEuZnJhbWUoKSAlPiUKICByb3duYW1lc190b19jb2x1bW4odmFyPSJnZW5lIikgJT4lCiAgYXNfdGliYmxlKCkKCiMgc3Vic2V0IHRoYXQgdGFibGUgdG8gb25seSBrZWVwIHRoZSBzaWduaWZpY2FudCBnZW5lcyB1c2luZyBvdXIgcHJlLWRlZmluZWQgdGhyZXNob2xkczoKc2lnX0wuOS4wX25vcm1fbm9MRkNjdXRvZmYgPC0gcmVzX3RhYmxlX0wuOS4wX25vcm1fdGIgJT4lCiAgZmlsdGVyKHBhZGogPCBwYWRqLmN1dG9mZikKCnNpZ19MLjkuMF9ub3JtIDwtIHNpZ19MLjkuMF9ub3JtX25vTEZDY3V0b2ZmICU+JSAKICBmaWx0ZXIoYWJzKGxvZzJGb2xkQ2hhbmdlKSA+IGxmYy5jdXRvZmYpCgpoZWFkKHNpZ19MLjkuMF9ub3JtX25vTEZDY3V0b2ZmKQpwYXN0ZSgiTnVtYmVyIG9mIHNpZ25pZmljYW50IERFR3MgZm9yIDlDIHYgMEM6IiwgbnJvdyhzaWdfTC45LjBfbm9ybV9ub0xGQ2N1dG9mZiksICIocGFkajwiLCBwYWRqLmN1dG9mZiwgIikiKQoKaGVhZChzaWdfTC45LjBfbm9ybSkKcGFzdGUoIk51bWJlciBvZiBzaWduaWZpY2FudCBERUdzIGZvciA5QyB2IDBDOiIsIG5yb3coc2lnX0wuOS4wX25vcm0pLCAiKHBhZGo8IiwgcGFkai5jdXRvZmYsICIsIGxvZy1mb2xkIGNoYW5nZSA+IiwgbGZjLmN1dG9mZiwgIikiKQoKd3JpdGUudGFibGUoc2lnX0wuOS4wX25vcm1fbm9MRkNjdXRvZmYsIGZpbGUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0dtYWNfREVHc19zaWdfTC45LjBfbm9ybV9ub0xGQ2N1dG9mZi50YWIiLCBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBOQSkKCndyaXRlLnRhYmxlKHNpZ19MLjkuMF9ub3JtLCBmaWxlID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9HbWFjX0RFR3Nfc2lnX0wuOS4wX25vcm0udGFiIiwgc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gTkEpCmBgYAoKIyMgSGVhdG1hcAoKRm9yIERFR3MgYmFzZWQgb24gYWRqdXN0ZWQgcC12YWx1ZSAqYW5kKiBMRkMgY3V0b2ZmCmBgYHtyfQojIFJldHJpZXZlIG5vcm1hbGl6ZWQgY291bnRzIG1hdHJpeApkZHNfTC45LjBfbm9ybV9jb3VudHMgPC0gY291bnRzKGRkc19MLjkuMCwgbm9ybWFsaXplZD1UUlVFKQoKIyBFeHRyYWN0IG5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBmb3Igc2lnbmlmaWNhbnQgZ2VuZXMKbm9ybV9zaWdfTC45LjAgPC0gZGRzX0wuOS4wX25vcm1fY291bnRzICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lCiAgZmlsdGVyKHJvdy5uYW1lcyhkZHNfTC45LjBfbm9ybV9jb3VudHMpICVpbiUgc2lnX0wuOS4wX25vcm0kZ2VuZSkKCmhlYWQobm9ybV9zaWdfTC45LjApCgojIEFubm90YXRlIGhlYXRtYXAKYW5ub3RhdGlvbiA8LSBpbmZvc3ViX0wuOS4wICU+JSAKCWRwbHlyOjpzZWxlY3QodGVtcF90cmVhdG1lbnQpCgojIFNldCBhIGNvbG9yIHBhbGV0dGUKaGVhdF9jb2xvcnMgPC0gcmV2KGJyZXdlci5wYWwoMTIsICJSZFlsQnUiKSkKCiMgUnVuIHBoZWF0bWFwCmguTC45LjAgPC0gcGhlYXRtYXAobm9ybV9zaWdfTC45LjAsIAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwgCiAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uID0gYW5ub3RhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgIGJvcmRlcl9jb2xvciA9IE5BLCAKICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSAicm93IiwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMzAsCiAgICAgICAgICAgICAgICAgICAgIG1haW4gPSAiTm9ybWFsaXplZCBTaWduaWZpY2FudCBFeHByZXNzaW9uLCBMaXZlciwgOSpDIGFuZCAwKkMiKQoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL2hlYXRtYXBfTC45LjBfbm9ybV9zaWcucG5nIiwKICAgICAgICAgcGxvdCAgID0gaC5MLjkuMCwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA1MDAwLAogICAgICAgICBoZWlnaHQgPSA1MDAwKQpgYGAKCk5vdGUgdGhlIGFyZ3VtZW50IGBzY2FsZT0icm93ImAgd2FzIGluY2x1ZGVkLCBzbyB0aGUgdmFsdWVzIHBsb3R0ZWQgaW4gdGhlIGhlYXQgbWFwIGFyZSAqWi1zY29yZXMqLCByYXRoZXIgdGhuIHRoZSBub3JtYWxpemVkIGNvdW50IHZhbHVlLiBUaGlzIHZhc3RseSBpbXByb3ZlcyB0aGUgY29sb3IgdmlzdWFsaXphdGlvbi4KCkZvciBERUdzIGJhc2VkIG9uIGFkanVzdGVkIHAtdmFsdWUgKm9ubHkqCmBgYHtyfQojIEV4dHJhY3Qgbm9ybWFsaXplZCBleHByZXNzaW9uIGZvciBzaWduaWZpY2FudCBnZW5lcwpub3JtX3NpZ19MLjkuMF9ub0xGQ2N1dG9mZiA8LSBkZHNfTC45LjBfbm9ybV9jb3VudHMgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUKICBmaWx0ZXIocm93Lm5hbWVzKGRkc19MLjkuMF9ub3JtX2NvdW50cykgJWluJSBzaWdfTC45LjBfbm9ybV9ub0xGQ2N1dG9mZiRnZW5lKQoKaGVhZChub3JtX3NpZ19MLjkuMF9ub0xGQ2N1dG9mZikKCiMgQW5ub3RhdGUgaGVhdG1hcAphbm5vdGF0aW9uIDwtIGluZm9zdWJfTC45LjAgJT4lIAoJZHBseXI6OnNlbGVjdCh0ZW1wX3RyZWF0bWVudCkKCiMgU2V0IGEgY29sb3IgcGFsZXR0ZQpoZWF0X2NvbG9ycyA8LSByZXYoYnJld2VyLnBhbCgxMiwgIlJkWWxCdSIpKQoKIyBSdW4gcGhlYXRtYXAKaC5MLjkuMCA8LSBwaGVhdG1hcChub3JtX3NpZ19MLjkuMF9ub0xGQ2N1dG9mZiwgCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gaGVhdF9jb2xvcnMsIAogICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULCAKICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3duYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb24gPSBhbm5vdGF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgYm9yZGVyX2NvbG9yID0gTkEsIAogICAgICAgICAgICAgICAgICAgICBmb250c2l6ZSA9IDEwLAogICAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJyb3ciLCAKICAgICAgICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gMTAsIAogICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMCwKICAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICJOb3JtYWxpemVkIFNpZ25pZmljYW50IEV4cHJlc3Npb24gKG5vIExGQyBjdXRvZmYpLCBMaXZlciwgOSpDIGFuZCAwKkMiKQoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL2hlYXRtYXBfTC45LjBfbm9ybV9zaWdfbm9MRkNjdXRvZmYucG5nIiwKICAgICAgICAgcGxvdCAgID0gaC5MLjkuMCwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA1MDAwLAogICAgICAgICBoZWlnaHQgPSA1MDAwKQpgYGAKCiMjIFZvbGNhbm8gcGxvdAoKYGBge3J9CiMgR2VuZXJhdGUgcGxvdAp2LkwuOS4wIDwtIAogIGdncGxvdChyZXNfdGFibGVfTC45LjBfbm9ybV90YikgKwogICMgUGxvdCBhbGwKICBnZW9tX3BvaW50KGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwYWRqKSxjb2xvcj0idW5jaGFuZ2VkIiksCiAgICAgICAgICAgICBzaXplPS41KSArCiAgIyBPdmVybGF5IGFsbCBzaWduaWZpY2FudGx5IHVwcmVndWxhdGVkIGluIHJlZAogIGdlb21fcG9pbnQoZGF0YSA9IHNpZ19MLjkuMF9ub3JtW3NpZ19MLjkuMF9ub3JtJGxvZzJGb2xkQ2hhbmdlID4gMCwgXSwgCiAgICAgICAgICAgICBhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksIGNvbG9yPSJ1cHJlZ3VsYXRlZCIpLCAKICAgICAgICAgICAgIHNpemU9LjUpICsKICAjIE92ZXJsYXkgYWxsIHNpZ25pZmljYW50bHkgZG93bnJlZ3VsYXRlZCBpbiBibHVlCiAgZ2VvbV9wb2ludChkYXRhID0gc2lnX0wuOS4wX25vcm1bc2lnX0wuOS4wX25vcm0kbG9nMkZvbGRDaGFuZ2UgPCAwLCBdLCAKICAgICAgICAgICAgIGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwYWRqKSwgY29sb3I9ImRvd25yZWd1bGF0ZWQiKSwgCiAgICAgICAgICAgICBzaXplPS41KSArCiAgZ2d0aXRsZSgiTGl2ZXIsIDkqQyBhbmQgMCpDIikgKwogIHhsYWIoImxvZzIgZm9sZCBjaGFuZ2UiKSArIAogIHlsYWIoIi1sb2cxMCBhZGp1c3RlZCBwLXZhbHVlIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC00LDQpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwzMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygidW5jaGFuZ2VkIiA9ICJkYXJrZ3JleSIsICJ1cHJlZ3VsYXRlZCIgPSAicmVkIiwgImRvd25yZWd1bGF0ZWQiID0gImJsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygidW5jaGFuZ2VkIiA9ICJVbmNoYW5nZWQiLCAidXByZWd1bGF0ZWQiID0gIlVwcmVndWxhdGVkIiwgImRvd25yZWd1bGF0ZWQiID0gIkRvd25yZWd1bGF0ZWQiKSwKICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IE5VTEwpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSwgaGp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjI1KSkpCgp2LkwuOS4wCgojIFNhdmUgcGxvdApnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvdm9sY2Fub19MLjkuMC5wbmciLAogICAgICAgICBwbG90ICAgPSB2LkwuOS4wLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDYwMDAsCiAgICAgICAgIGhlaWdodCA9IDQwMDApCmBgYAojIyBQbG90IGV4cHJlc3Npb24gb2YgdG9wIERFR3MgYWNyb3NzIHRyZWF0bWVudHMKCmBgYHtyfQp0b3AxNURFR3NfTC45LjAgPC0gc2lnX0wuOS4wX25vcm1fbm9MRkNjdXRvZmYgJT4lCiAgYXJyYW5nZShwYWRqKSAlPiUKICBzbGljZV9oZWFkKG49MTUpCgpMLjkuMF9ERUcxIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMFsxLCBdJGdlbmUpCkwuOS4wX0RFRzEKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4wX0RFRzEuIix0b3AxNURFR3NfTC45LjBbMSwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMF9ERUcxLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4wX0RFRzIgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4wWzIsIF0kZ2VuZSkKTC45LjBfREVHMgpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjBfREVHMi4iLHRvcDE1REVHc19MLjkuMFsyLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4wX0RFRzIsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjBfREVHMyA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjBbMywgXSRnZW5lKQpMLjkuMF9ERUczCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMF9ERUczLiIsdG9wMTVERUdzX0wuOS4wWzMsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjBfREVHMywgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMF9ERUc0IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMFs0LCBdJGdlbmUpCkwuOS4wX0RFRzQKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4wX0RFRzQuIix0b3AxNURFR3NfTC45LjBbNCwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMF9ERUc0LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4wX0RFRzUgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4wWzUsIF0kZ2VuZSkKTC45LjBfREVHNQpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjBfREVHNS4iLHRvcDE1REVHc19MLjkuMFs1LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4wX0RFRzUsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjBfREVHNiA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjBbNiwgXSRnZW5lKQpMLjkuMF9ERUc2CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMF9ERUc2LiIsdG9wMTVERUdzX0wuOS4wWzYsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjBfREVHNiwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMF9ERUc3IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMFs3LCBdJGdlbmUpCkwuOS4wX0RFRzcKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4wX0RFRzcuIix0b3AxNURFR3NfTC45LjBbNywgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMF9ERUc3LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4wX0RFRzggPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4wWzgsIF0kZ2VuZSkKTC45LjBfREVHOApnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjBfREVHOC4iLHRvcDE1REVHc19MLjkuMFs4LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4wX0RFRzgsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjBfREVHOSA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjBbOSwgXSRnZW5lKQpMLjkuMF9ERUc5CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMF9ERUc5LiIsdG9wMTVERUdzX0wuOS4wWzksIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjBfREVHOSwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMF9ERUcxMCA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjBbMTAsIF0kZ2VuZSkKTC45LjBfREVHMTAKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4wX0RFRzEwLiIsdG9wMTVERUdzX0wuOS4wWzEwLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4wX0RFRzEwLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4wX0RFRzExIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMFsxMSwgXSRnZW5lKQpMLjkuMF9ERUcxMQpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjBfREVHMTEuIix0b3AxNURFR3NfTC45LjBbMTEsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjBfREVHMTEsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjBfREVHMTIgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4wWzEyLCBdJGdlbmUpCkwuOS4wX0RFRzEyCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMF9ERUcxMi4iLHRvcDE1REVHc19MLjkuMFsxMiwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMF9ERUcxMiwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuMF9ERUcxMyA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjBbMTMsIF0kZ2VuZSkKTC45LjBfREVHMTMKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS4wX0RFRzEzLiIsdG9wMTVERUdzX0wuOS4wWzEzLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS4wX0RFRzEzLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS4wX0RFRzE0IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuMFsxNCwgXSRnZW5lKQpMLjkuMF9ERUcxNApnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjBfREVHMTQuIix0b3AxNURFR3NfTC45LjBbMTQsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjBfREVHMTQsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjBfREVHMTUgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS4wWzE1LCBdJGdlbmUpCkwuOS4wX0RFRzE1CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuMF9ERUcxNS4iLHRvcDE1REVHc19MLjkuMFsxNSwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuMF9ERUcxNSwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpgYGAKCgojIExpdmVyIHRpc3N1ZSwgOSpDIHYuIDUqQwoKVGhlIDlcKkMgdGVtcGVyYXR1cmUgdHJlYXRtZW50IGlzIGVmZmVjdGl2ZWx5IG91ciAiY29udHJvbCwiIGFzIGl0IHJlcHJlc2VudHMgdGhlIGFtYmllbnQgdGVtcGVyYXR1cmUgdGhhdCB3aWxkIGp1dmVuaWxlIFBhY2lmaWMgY29kIHdvdWxkIGV4cGVyaWVuY2UuCgpgYGB7ciwgY2FjaGU9VFJVRX0KIyBsaXZlciB0aXNzdWUsIHRlbXBlcmF0dXJlcyA5IHZzLiA1IAoKIyBGaWx0ZXIgZGF0YQppbmZvc3ViX0wuOS41IDwtIGNvZF9zYW1wbGVfaW5mbyAlPiUgZmlsdGVyKHRpc3N1ZV90eXBlID09ICJMaXZlciIgJiAodGVtcF90cmVhdG1lbnQgPT0gIjkiIHwgdGVtcF90cmVhdG1lbnQgPT0gIjUiKSkKY291bnRzdWJfTC45LjUgPC0gc3Vic2V0KGNvZF9jb3VudHNfZGF0YSwgc2VsZWN0PXJvdy5uYW1lcyhpbmZvc3ViX0wuOS41KSkKCiMgQ2FsY3VsYXRlIERFU2VxIG9iamVjdApkZHNfTC45LjUgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHN1Yl9MLjkuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGluZm9zdWJfTC45LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gdGVtcF90cmVhdG1lbnQpCgpkZHNfTC45LjUgPC0gREVTZXEoZGRzX0wuOS41KQpyZXN1bHRzTmFtZXMoZGRzX0wuOS41KSAjIGxpc3RzIHRoZSBjb2VmZmljaWVudHMKYGBgCgpgYGB7cn0KcGxvdERpc3BFc3RzKGRkc19MLjkuNSkKYGBgCgpgYGB7ciwgY2FjaGU9VFJVRX0KIyBGaWx0ZXJpbmc6IGtlZXAgZ2VuZXMgdGhhdCBoYXZlIGF0IGxlYXN0IDEwIGNvdW50cyBhY3Jvc3MgMS8zIG9mIHRoZSBzYW1wbGVzIC0gaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC8xMTAzMDcvCmtlZXAgPC0gcm93U3VtcyhERVNlcTI6OmNvdW50cyhkZHNfTC45LjUpID49IDEwKSA+PSBuY29sKGNvdW50c3ViX0wuOS41KS8zCmRkc19MLjkuNTwtIGRkc19MLjkuNVtrZWVwLF0KCiMgR2VuZXJhdGUgQ29udHJhc3RzCmNvbnRyYXN0X2xpc3RfTC45LjUgICAgICAgIDwtIGMoInRlbXBfdHJlYXRtZW50IiwgIjUiLCAiOSIpICMgb3JkZXIgaXMgaW1wb3J0YW50OiBmYWN0b3IsIHRyZWF0bWVudCBncm91cCwgY29udHJvbApyZXNfdGFibGVfTC45LjVfbm9zaHJpbmsgPC0gcmVzdWx0cyhkZHNfTC45LjUsIGNvbnRyYXN0PWNvbnRyYXN0X2xpc3RfTC45LjUsIGFscGhhID0gMC4wNSkKCnJlc190YWJsZV9MLjkuNV9ub3JtICAgICA8LSBsZmNTaHJpbmsoZGRzX0wuOS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9Im5vcm1hbCIpICMgbGZjVGhyZXNob2xkID0gMC41ODUpICAjIGEgbGZjIHRocmVzaG9sZCBvZiAxID0gMi1mb2xkIGNoYW5nZSwgMC41ODUgPSAxLjUtZm9sZCBjaGFuZ2UKcmVzX3RhYmxlX0wuOS41X2FwZWdsbSAgIDwtIGxmY1NocmluayhkZHNfTC45LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9ImFwZWdsbSIpICMgbGZjVGhyZXNob2xkID0gMC41ODUpICAjIGEgbGZjIHRocmVzaG9sZCBvZiAxID0gMi1mb2xkIGNoYW5nZSwgMC41ODUgPSAxLjUtZm9sZCBjaGFuZ2UKcmVzX3RhYmxlX0wuOS41X2FzaHIgICAgIDwtIGxmY1NocmluayhkZHNfTC45LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9ImFzaHIiKQpgYGAKCmBgYHtyfQojIEdlbmVyYXRlIE1BIHBsb3RzCnBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDQsNCwyLDEpKQp4bGltIDwtIGMoMSwxZTUpOyB5bGltIDwtIGMoLTQsNCkKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS41X25vc2hyaW5rLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0ibm8gc2hyaW5rIikKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS41X25vcm0sIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJub3JtYWwiKQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjVfYXBlZ2xtLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0iYXBlZ2xtIikKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS41X2FzaHIsIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJhc2hyIikKYGBgCgpgYGB7cn0KIyBFeGFtaW5lIHJlc3VsdHMgZm9ybWF0dGluZwpyZXNfdGFibGVfTC45LjVfbm9ybSAlPiUgZGF0YS5mcmFtZSgpICU+JSBoZWFkKCkKYGBgCgpOb3RlIHRoYXQgdGhlIG1ldHJpYyB3ZSB3YW50IHRvIHVzZSB0byBpZGVudGlmeSBzaWduaWZpY2FudGx5IGV4cHJlc3NlZCBnZW5lcyBpcyB0aGUgYHBhZGpgIHZhbHVlcywgKipOT1QqKiB0aGUgYHB2YWx1ZWAuIGBwYWRqYCBhcmUgcC12YWx1ZXMgY29ycmVjdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nIChkZWZhdWx0IG1ldGhvZCBpcyB0aGUgQmVuamFtaW5pIGFuZCBIb2NoYmVyZyBtZXRob2QpLgoKYGBge3J9CnN1bW1hcnkocmVzX3RhYmxlX0wuOS41X25vc2hyaW5rKQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuNV9ub3JtKQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuNV9hcGVnbG0pCnN1bW1hcnkocmVzX3RhYmxlX0wuOS41X2FzaHIpCmBgYAoKIyMgRXh0cmFjdGluZyBzaWduaWZpY2FudGx5IGV4cHJlc3NlZCBnZW5lcwoKYGBge3J9CnBhZGouY3V0b2ZmIDwtIDAuMDUKbGZjLmN1dG9mZiA8LSAwLjU4CgojIENvbnZlcnQgcmVzdWx0cyB0YWJsZSBpbnRvIHRpYmJsZQpyZXNfdGFibGVfTC45LjVfbm9ybV90YiA8LSByZXNfdGFibGVfTC45LjVfbm9ybSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhcj0iZ2VuZSIpICU+JQogIGFzX3RpYmJsZSgpCgojIHN1YnNldCB0aGF0IHRhYmxlIHRvIG9ubHkga2VlcCB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgdXNpbmcgb3VyIHByZS1kZWZpbmVkIHRocmVzaG9sZHM6CnNpZ19MLjkuNV9ub3JtX25vTEZDY3V0b2ZmIDwtIHJlc190YWJsZV9MLjkuNV9ub3JtX3RiICU+JQogIGZpbHRlcihwYWRqIDwgcGFkai5jdXRvZmYpCgpzaWdfTC45LjVfbm9ybSA8LSBzaWdfTC45LjVfbm9ybV9ub0xGQ2N1dG9mZiAlPiUgCiAgZmlsdGVyKGFicyhsb2cyRm9sZENoYW5nZSkgPiBsZmMuY3V0b2ZmKQoKaGVhZChzaWdfTC45LjVfbm9ybSkKcGFzdGUoIk51bWJlciBvZiBzaWduaWZpY2FudCBERUdzIGZvciA5QyB2IDVDOiIsIG5yb3coc2lnX0wuOS41X25vcm1fbm9MRkNjdXRvZmYpLCAiKHBhZGo8IiwgcGFkai5jdXRvZmYsICIpIikKCmhlYWQoc2lnX0wuOS41X25vcm0pCnBhc3RlKCJOdW1iZXIgb2Ygc2lnbmlmaWNhbnQgREVHcyBmb3IgOUMgdiA1QzoiLCBucm93KHNpZ19MLjkuNV9ub3JtKSwgIihwYWRqPCIsIHBhZGouY3V0b2ZmLCAiLCBsb2ctZm9sZCBjaGFuZ2UgPiIsIGxmYy5jdXRvZmYsICIpIikKCndyaXRlLnRhYmxlKHNpZ19MLjkuNV9ub3JtX25vTEZDY3V0b2ZmLCBmaWxlID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9HbWFjX0RFR3Nfc2lnX0wuOS41X25vcm1fbm9MRkNjdXRvZmYudGFiIiwgc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gTkEpCgp3cml0ZS50YWJsZShzaWdfTC45LjVfbm9ybSwgZmlsZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvR21hY19ERUdzX3NpZ19MLjkuNV9ub3JtLnRhYiIsIHNlcCA9ICJcdCIsCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IFRSVUUsIGNvbC5uYW1lcyA9IE5BKQpgYGAKCiMjIEhlYXRtYXAKCkZvciBERUdzIGJhc2VkIG9uIGFkanVzdGVkIHAtdmFsdWUgKmFuZCogTEZDIGN1dG9mZgpgYGB7cn0KIyBSZXRyaWV2ZSBub3JtYWxpemVkIGNvdW50cyBtYXRyaXgKZGRzX0wuOS41X25vcm1fY291bnRzIDwtIGNvdW50cyhkZHNfTC45LjUsIG5vcm1hbGl6ZWQ9VFJVRSkKCiMgRXh0cmFjdCBub3JtYWxpemVkIGV4cHJlc3Npb24gZm9yIHNpZ25pZmljYW50IGdlbmVzCm5vcm1fc2lnX0wuOS41IDwtIGRkc19MLjkuNV9ub3JtX2NvdW50cyAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JQogIGZpbHRlcihyb3cubmFtZXMoZGRzX0wuOS41X25vcm1fY291bnRzKSAlaW4lIHNpZ19MLjkuNV9ub3JtJGdlbmUpCgpoZWFkKG5vcm1fc2lnX0wuOS41KQoKIyBBbm5vdGF0ZSBoZWF0bWFwCmFubm90YXRpb24gPC0gaW5mb3N1Yl9MLjkuNSAlPiUgCglkcGx5cjo6c2VsZWN0KHRlbXBfdHJlYXRtZW50KQoKIyBTZXQgYSBjb2xvciBwYWxldHRlCmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCgojIFJ1biBwaGVhdG1hcApoLkwuOS41IDwtIHBoZWF0bWFwKG5vcm1fc2lnX0wuOS41LCAKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgCiAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsIAogICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbiA9IGFubm90YXRpb24sIAogICAgICAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsIAogICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDMwLAogICAgICAgICAgICAgICAgICAgICBtYWluID0gIk5vcm1hbGl6ZWQgU2lnbmlmaWNhbnQgRXhwcmVzc2lvbiwgTGl2ZXIsIDkqQyBhbmQgNSpDIikKCiMgU2F2ZSBwbG90CmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9oZWF0bWFwX0wuOS41X25vcm1fc2lnLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGguTC45LjUsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgpOb3RlIHRoZSBhcmd1bWVudCBgc2NhbGU9InJvdyJgIHdhcyBpbmNsdWRlZCwgc28gdGhlIHZhbHVlcyBwbG90dGVkIGluIHRoZSBoZWF0IG1hcCBhcmUgKlotc2NvcmVzKiwgcmF0aGVyIHRobiB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZS4gVGhpcyB2YXN0bHkgaW1wcm92ZXMgdGhlIGNvbG9yIHZpc3VhbGl6YXRpb24uCgpGb3IgREVHcyBiYXNlZCBvbiBhZGp1c3RlZCBwLXZhbHVlICpvbmx5KgpgYGB7cn0KIyBFeHRyYWN0IG5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBmb3Igc2lnbmlmaWNhbnQgZ2VuZXMKbm9ybV9zaWdfTC45LjVfbm9MRkNjdXRvZmYgPC0gZGRzX0wuOS41X25vcm1fY291bnRzICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lCiAgZmlsdGVyKHJvdy5uYW1lcyhkZHNfTC45LjVfbm9ybV9jb3VudHMpICVpbiUgc2lnX0wuOS41X25vcm1fbm9MRkNjdXRvZmYkZ2VuZSkKCmhlYWQobm9ybV9zaWdfTC45LjVfbm9MRkNjdXRvZmYpCgojIEFubm90YXRlIGhlYXRtYXAKYW5ub3RhdGlvbiA8LSBpbmZvc3ViX0wuOS41ICU+JSAKCWRwbHlyOjpzZWxlY3QodGVtcF90cmVhdG1lbnQpCgojIFNldCBhIGNvbG9yIHBhbGV0dGUKaGVhdF9jb2xvcnMgPC0gcmV2KGJyZXdlci5wYWwoMTIsICJSZFlsQnUiKSkKCiMgUnVuIHBoZWF0bWFwCmguTC45LjUgPC0gcGhlYXRtYXAobm9ybV9zaWdfTC45LjVfbm9MRkNjdXRvZmYsIAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwgCiAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uID0gYW5ub3RhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgIGJvcmRlcl9jb2xvciA9IE5BLCAKICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSAicm93IiwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMzAsCiAgICAgICAgICAgICAgICAgICAgIG1haW4gPSAiTm9ybWFsaXplZCBTaWduaWZpY2FudCBFeHByZXNzaW9uIChubyBMRkMgY3V0b2ZmKSwgTGl2ZXIsIDkqQyBhbmQgNSpDIikKCiMgU2F2ZSBwbG90CmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9oZWF0bWFwX0wuOS41X25vcm1fc2lnX25vTEZDY3V0b2ZmLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGguTC45LjUsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgojIyBWb2xjYW5vIHBsb3QKCmBgYHtyfQojIEdlbmVyYXRlIHBsb3QKdi5MLjkuNSA8LSAKICBnZ3Bsb3QocmVzX3RhYmxlX0wuOS41X25vcm1fdGIpICsKICAjIFBsb3QgYWxsCiAgZ2VvbV9wb2ludChhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksY29sb3I9InVuY2hhbmdlZCIpLAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogICMgT3ZlcmxheSBhbGwgc2lnbmlmaWNhbnRseSB1cHJlZ3VsYXRlZCBpbiByZWQKICBnZW9tX3BvaW50KGRhdGEgPSBzaWdfTC45LjVfbm9ybVtzaWdfTC45LjVfbm9ybSRsb2cyRm9sZENoYW5nZSA+IDAsIF0sIAogICAgICAgICAgICAgYWVzKHg9bG9nMkZvbGRDaGFuZ2UsIHk9LWxvZzEwKHBhZGopLCBjb2xvcj0idXByZWd1bGF0ZWQiKSwgCiAgICAgICAgICAgICBzaXplPS41KSArCiAgIyBPdmVybGF5IGFsbCBzaWduaWZpY2FudGx5IGRvd25yZWd1bGF0ZWQgaW4gYmx1ZQogIGdlb21fcG9pbnQoZGF0YSA9IHNpZ19MLjkuNV9ub3JtW3NpZ19MLjkuNV9ub3JtJGxvZzJGb2xkQ2hhbmdlIDwgMCwgXSwgCiAgICAgICAgICAgICBhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksIGNvbG9yPSJkb3ducmVndWxhdGVkIiksIAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogIGdndGl0bGUoIkxpdmVyLCA5KkMgYW5kIDUqQyIpICsKICB4bGFiKCJsb2cyIGZvbGQgY2hhbmdlIikgKyAKICB5bGFiKCItbG9nMTAgYWRqdXN0ZWQgcC12YWx1ZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtNCw0KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMzApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInVuY2hhbmdlZCIgPSAiZGFya2dyZXkiLCAidXByZWd1bGF0ZWQiID0gInJlZCIsICJkb3ducmVndWxhdGVkIiA9ICJibHVlIiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInVuY2hhbmdlZCIgPSAiVW5jaGFuZ2VkIiwgInVwcmVndWxhdGVkIiA9ICJVcHJlZ3VsYXRlZCIsICJkb3ducmVndWxhdGVkIiA9ICJEb3ducmVndWxhdGVkIiksCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBOVUxMKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksIGhqdXN0ID0gMC41KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yNSkpKQoKdi5MLjkuNQoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL3ZvbGNhbm9fTC45LjUucG5nIiwKICAgICAgICAgcGxvdCAgID0gdi5MLjkuMCwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA2MDAwLAogICAgICAgICBoZWlnaHQgPSA0MDAwKQpgYGAKCiMjIFBsb3QgZXhwcmVzc2lvbiBvZiB0b3AgREVHcyBhY3Jvc3MgdHJlYXRtZW50cwoKYGBge3J9CnRvcDE1REVHc19MLjkuNSA8LSBzaWdfTC45LjVfbm9ybV9ub0xGQ2N1dG9mZiAlPiUKICBhcnJhbmdlKHBhZGopICU+JQogIHNsaWNlX2hlYWQobj0xNSkKCkwuOS41X0RFRzEgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS41WzEsIF0kZ2VuZSkKTC45LjVfREVHMQpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjVfREVHMS4iLHRvcDE1REVHc19MLjkuNVsxLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS41X0RFRzEsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjVfREVHMiA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjVbMiwgXSRnZW5lKQpMLjkuNV9ERUcyCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuNV9ERUcyLiIsdG9wMTVERUdzX0wuOS41WzIsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjVfREVHMiwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuNV9ERUczIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuNVszLCBdJGdlbmUpCkwuOS41X0RFRzMKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS41X0RFRzMuIix0b3AxNURFR3NfTC45LjVbMywgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuNV9ERUczLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS41X0RFRzQgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS41WzQsIF0kZ2VuZSkKTC45LjVfREVHNApnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjVfREVHNC4iLHRvcDE1REVHc19MLjkuNVs0LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS41X0RFRzQsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjVfREVHNSA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjVbNSwgXSRnZW5lKQpMLjkuNV9ERUc1CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuNV9ERUc1LiIsdG9wMTVERUdzX0wuOS41WzUsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjVfREVHNSwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuNV9ERUc2IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuNVs2LCBdJGdlbmUpCkwuOS41X0RFRzYKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS41X0RFRzYuIix0b3AxNURFR3NfTC45LjVbNiwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuNV9ERUc2LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS41X0RFRzcgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS41WzcsIF0kZ2VuZSkKTC45LjVfREVHNwpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjVfREVHNy4iLHRvcDE1REVHc19MLjkuNVs3LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS41X0RFRzcsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjVfREVHOCA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjVbOCwgXSRnZW5lKQpMLjkuNV9ERUc4CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuNV9ERUc4LiIsdG9wMTVERUdzX0wuOS41WzgsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjVfREVHOCwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuNV9ERUc5IDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuNVs5LCBdJGdlbmUpCkwuOS41X0RFRzkKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS41X0RFRzkuIix0b3AxNURFR3NfTC45LjVbOSwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuNV9ERUc5LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS41X0RFRzEwIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuNVsxMCwgXSRnZW5lKQpMLjkuNV9ERUcxMApnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjVfREVHMTAuIix0b3AxNURFR3NfTC45LjVbMTAsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjVfREVHMTAsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjVfREVHMTEgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS41WzExLCBdJGdlbmUpCkwuOS41X0RFRzExCmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuNV9ERUcxMS4iLHRvcDE1REVHc19MLjkuNVsxMSwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuNV9ERUcxMSwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuNV9ERUcxMiA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjVbMTIsIF0kZ2VuZSkKTC45LjVfREVHMTIKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS41X0RFRzEyLiIsdG9wMTVERUdzX0wuOS41WzEyLCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS41X0RFRzEyLCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCkwuOS41X0RFRzEzIDwtIHBsb3RfZ2VuZV9kYXRhKHRvcDE1REVHc19MLjkuNVsxMywgXSRnZW5lKQpMLjkuNV9ERUcxMwpnZ2V4cG9ydChmaWxlbmFtZSA9IHBhc3RlKCIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvTC45LjVfREVHMTMuIix0b3AxNURFR3NfTC45LjVbMTMsIF0kZ2VuZSwiLnBuZyIpLCBwbG90ID0gTC45LjVfREVHMTMsIHJlcyA9IDYwMCwgd2lkdGggPSA1MDAwLCBoZWlnaHQgPSA1MDAwKQoKTC45LjVfREVHMTQgPC0gcGxvdF9nZW5lX2RhdGEodG9wMTVERUdzX0wuOS41WzE0LCBdJGdlbmUpCkwuOS41X0RFRzE0CmdnZXhwb3J0KGZpbGVuYW1lID0gcGFzdGUoIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9MLjkuNV9ERUcxNC4iLHRvcDE1REVHc19MLjkuNVsxNCwgXSRnZW5lLCIucG5nIiksIHBsb3QgPSBMLjkuNV9ERUcxNCwgcmVzID0gNjAwLCB3aWR0aCA9IDUwMDAsIGhlaWdodCA9IDUwMDApCgpMLjkuNV9ERUcxNSA8LSBwbG90X2dlbmVfZGF0YSh0b3AxNURFR3NfTC45LjVbMTUsIF0kZ2VuZSkKTC45LjVfREVHMTUKZ2dleHBvcnQoZmlsZW5hbWUgPSBwYXN0ZSgiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0wuOS41X0RFRzE1LiIsdG9wMTVERUdzX0wuOS41WzE1LCBdJGdlbmUsIi5wbmciKSwgcGxvdCA9IEwuOS41X0RFRzE1LCByZXMgPSA2MDAsIHdpZHRoID0gNTAwMCwgaGVpZ2h0ID0gNTAwMCkKCmBgYAoK