Differential gene expression analysis for Pacific cod RNAseq data.

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 × 80
  ...1           kallisto_quant_100 kallisto_quant_107 kallisto_quant_108
  <chr>                       <dbl>              <dbl>              <dbl>
1 XR_009524663.1              89.5                69.9            774.   
2 XR_009524878.1               0                   0                0    
3 XM_060052481.1             432.                159.              72.4  
4 XM_060060803.1              12.7                30.9            139.   
5 XM_060071658.1               2.72                0                0.967
6 XM_060070373.1              40.2                58.8             60.2  
# ℹ 76 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_009524663.1      115       188         89         70        774         45
XR_009524878.1        3         0          0          0          0          0
XM_060052481.1      218       110        432        159         72        170
XM_060060803.1        0         0         13         31        139         41
XM_060071658.1        1         0          3          0          1          5
XM_060070373.1        0       100         40         59         60         25
               sample_11 sample_110 sample_117 sample_118 sample_119 sample_12
XR_009524663.1       132         40        127         65         34       133
XR_009524878.1         0          0          3          2          0         3
XM_060052481.1       289        909        279        232        911       285
XM_060060803.1        21         10         59         29         57         0
XM_060071658.1         0          0          5          0          0         1
XM_060070373.1         0          1         67         44          0         0
               sample_120 sample_121 sample_127 sample_128 sample_129 sample_13
XR_009524663.1        105        221        132         38        335        81
XR_009524878.1          2          6          3          0          0         8
XM_060052481.1        223         31         50          3          7       279
XM_060060803.1         58         91          0          0          0         0
XM_060071658.1          0          0          2          1          0         2
XM_060070373.1         59        119          0         60         29         0
               sample_131 sample_137 sample_138 sample_139 sample_140
XR_009524663.1        106         21         23         60         49
XR_009524878.1          3          0          0          0          0
XM_060052481.1        101        157         48        105         66
XM_060060803.1          0          0          0         15         22
XM_060071658.1          0          1          1          0          0
XM_060070373.1         90         46         22          0         26
               sample_147 sample_148 sample_149 sample_150 sample_18 sample_19
XR_009524663.1         51        412        431        343        93       499
XR_009524878.1          0          0         55          0         4         2
XM_060052481.1         48        222        549        196       476        61
XM_060060803.1          0        221          0          0        37        24
XM_060071658.1          0          1         17          0         1         0
XM_060070373.1          0          0        145         40         0        71
               sample_19-G sample_19-S sample_2 sample_20 sample_20-G
XR_009524663.1         276         317       37       121         281
XR_009524878.1           0          16        0         0           0
XM_060052481.1          81          98      694        72          75
XM_060060803.1          37          45       56        28          45
XM_060071658.1           5           7        0         5           6
XM_060070373.1           0         174       52        80         104
               sample_20-S sample_21 sample_28 sample_29 sample_3 sample_30
XR_009524663.1         320        85       103       132      123       164
XR_009524878.1           0         9         0         8        0         3
XM_060052481.1          54       348       348        68      528       209
XM_060060803.1           9        45       142        67       33         0
XM_060071658.1          15         4         0         0        0         2
XM_060070373.1         158        13         0        30       50       111
               sample_31 sample_37 sample_38 sample_39 sample_4 sample_40
XR_009524663.1        83       121       173        76       70        67
XR_009524878.1         0         0        16         0        0        24
XM_060052481.1        16        20        38        76       66         0
XM_060060803.1        18        27       235         0       42         0
XM_060071658.1         0         0         0         0        8         4
XM_060070373.1        31         8       143        65        0        75
               sample_41 sample_47 sample_48 sample_49 sample_5 sample_50
XR_009524663.1       690       113       148       258       78       168
XR_009524878.1         0         0         0        10        3         3
XM_060052481.1        14       197        62        62      344       134
XM_060060803.1         7         0       103       162       16        85
XM_060071658.1         1         1         0         1        7         2
XM_060070373.1       125        96        86       173       38       108
               sample_57 sample_57-G sample_57-S sample_58 sample_58-G
XR_009524663.1        76         320         857       411         248
XR_009524878.1         0           8          55         0           8
XM_060052481.1       284         211          19        80          77
XM_060060803.1         0         131           0        92         209
XM_060071658.1         0           6           0         5           6
XM_060070373.1         0         562         271         0         536
               sample_58-S sample_59 sample_60 sample_67 sample_68 sample_69
XR_009524663.1         365        54       311       138       200       150
XR_009524878.1           0         3         0         3         0         0
XM_060052481.1          23       116        95       173       172        48
XM_060060803.1          51       101         0        23       138        36
XM_060071658.1           2         0         1         5         0         6
XM_060070373.1         384        46       130       145       117         0
               sample_70 sample_78 sample_79 sample_80 sample_83 sample_88
XR_009524663.1       280        65        80       143        40       189
XR_009524878.1         0         0         0         0         0         0
XM_060052481.1        40       175       460        75       125       126
XM_060060803.1        83        60        12         0         0         0
XM_060071658.1         0         0         1         7         3         1
XM_060070373.1         1        65         0        83        64        84
               sample_90 sample_91 sample_97 sample_98 sample_99
XR_009524663.1       101       123       165      1100       369
XR_009524878.1         0         0         0         0         0
XM_060052481.1       184        77         0       198        58
XM_060060803.1         0        48         0        58         0
XM_060071658.1         2         2         1         0         1
XM_060070373.1        92       150        61       180        17
               sample_RESUB-116 sample_RESUB-156 sample_RESUB-36
XR_009524663.1              131               85             116
XR_009524878.1                0                0               0
XM_060052481.1              384              431             156
XM_060060803.1               31               50               0
XM_060071658.1                0                6               0
XM_060070373.1                0               58               0
               sample_RESUB-76 sample_RESUB-94
XR_009524663.1              95             138
XR_009524878.1               4               4
XM_060052481.1              83              46
XM_060060803.1              65              30
XM_060071658.1               0               2
XM_060070373.1              54              13
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_97"       
[73] "sample_98"        "sample_99"        "sample_RESUB-116" "sample_RESUB-156"
[77] "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 maing 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 tank temp_treatment tissue_type Microchip.ID
sample_1               1    1             16       Liver         9443
sample_10             10    2             16       Liver         9518
sample_100           100   15              9       Liver         9483
sample_107           107   16              9       Liver         4236
sample_108           108   16              9       Liver         9416
sample_109           109   16              9       Liver         9481
           SL_11212022 WWT_11212022 SL_12272022 WWT_12272022 MortDate
sample_1            99        10.54         108        12.94         
sample_10           95         9.45         105        12.67         
sample_100          70         4.54          78         5.23         
sample_107          94         9.15         104        11.44         
sample_108          81         6.26          91         7.87         
sample_109          89         7.77          95         9.49         
           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/missing samples
# Missing data: 92
# MuliQC report: 149, 129
# PCA outliers: 31, 41 (per Laura)
cod_sample_info <- cod_sample_info[!(row.names(cod_sample_info) %in% c("sample_92", "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] 75
nrow(cod_sample_info)
[1] 75
all(colnames(cod_counts_data) %in% rownames(cod_sample_info))
[1] TRUE
all(colnames(cod_counts_data) == rownames(cod_sample_info))
[1] TRUE

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
XR_009524663.1 172.02100    -0.58930033 0.2976828 -1.9804155 0.04765686
XM_060052481.1 234.42310     0.14067865 0.3120795  0.4507903 0.65214072
XM_060060803.1  26.91392     0.07544055 0.3308824  0.2280426 0.81961316
XM_060070373.1  46.30310    -0.43318495 0.3352593 -1.3076029 0.19100802
XM_060063653.1  71.04920    -0.76554420 0.3284260 -2.4752846 0.01331300
XM_060065730.1  23.27700    -0.43625018 0.3174980 -1.3755736 0.16895368
                     padj
XR_009524663.1 0.15709623
XM_060052481.1 0.82984033
XM_060060803.1 0.91921578
XM_060070373.1 0.40722399
XM_060063653.1 0.06165138
XM_060065730.1 0.37614627

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 21631 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 1888, 8.7%
LFC < 0 (down)     : 2465, 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 21631 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2431, 11%
LFC < 0 (down)     : 3079, 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 21631 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2431, 11%
LFC < 0 (down)     : 3079, 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 21631 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 2432, 11%
LFC < 0 (down)     : 3078, 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

4 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 <- res_table_L.9.16_norm_tb %>%
        filter(padj < padj.cutoff & abs(log2FoldChange) > lfc.cutoff)

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 XR_009525437.1     98.7         -2.20  0.268 -8.21 2.28e-16 1.08e-13
2 XM_060060327.1     93.8          1.04  0.256  4.05 5.08e- 5 7.78e- 4
3 XR_009529546.1     76.0         -0.609 0.211 -2.89 3.79e- 3 2.38e- 2
4 XM_060061699.1    116.          -1.18  0.178 -6.67 2.63e-11 3.49e- 9
5 XM_060058899.1     22.0         -1.32  0.271 -4.85 1.23e- 6 3.75e- 5
6 XM_060066319.1     68.4         -1.69  0.270 -6.25 4.15e-10 4.08e- 8
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: 3006 (padj< 0.05 , log-fold change > 0.58 )"
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)

4.1 Heatmap

# 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
XR_009525437.1  13.691735  24.87658   79.79397  326.40029  113.09950   94.06337
XM_060060327.1 215.040776  69.50808   84.78110   34.20789   44.78051   46.09105
XR_009529546.1  70.069466  31.46155   59.84548  133.98091   75.78241  107.23224
XM_060061699.1  36.242827  76.09306  118.69354  106.89966  229.64365  130.74808
XM_060058899.1   7.248565  51.21648   48.87381   21.37993   60.28146   35.74408
XM_060066319.1   9.664754  50.48482   40.89441  138.25689   66.02255   81.83513
                sample_11 sample_110 sample_12  sample_13  sample_18 sample_19
XR_009525437.1   9.750244   32.03493  76.31215  25.492429  25.778748 28.305643
XM_060060327.1 117.002926   38.44191  82.31423 152.954576 292.489637 44.031000
XR_009529546.1  72.683636   88.78251  36.86992  91.279344  62.463889 48.224429
XM_060061699.1  67.365321  135.46198  47.15920  50.984859  54.531966 62.901429
XM_060058899.1   8.863858   32.95021  14.57648   4.934019   4.957451  9.435214
XM_060066319.1  27.477960   43.93361  24.86576  27.959439  21.812786 30.402357
               sample_2  sample_20 sample_21  sample_28  sample_29  sample_3
XR_009525437.1 25.37087  27.365803  12.13809  24.062796  28.741588 23.272004
XM_060060327.1 48.62750 175.141138 168.06588 173.067036 105.385824 40.278469
XR_009529546.1 49.68462  58.015502  43.88387  30.541242  31.615747 52.809548
XM_060061699.1 60.25582  77.718880  96.17103 113.835537  45.986541 77.871707
XM_060058899.1 10.57120   8.757057  10.27069   2.776477   6.706371  9.845848
XM_060066319.1 25.37087  32.838963  30.81208  22.211812  16.286900 17.901542
               sample_30    sample_4  sample_5 sample_78  sample_79 sample_80
XR_009525437.1 47.269823  20.7611952  15.50890 117.70584 122.149108 109.26173
XM_060060327.1 88.537128 318.0237634 113.73193  29.69156  51.323155  62.12922
XR_009529546.1 36.765418  76.4389461  98.22303  99.67882  58.508396  64.27160
XM_060061699.1 68.278633  78.3263275  49.11151 162.24319 168.339947 275.29670
XM_060058899.1  3.751573   0.9436907  16.37050  42.41652   9.238168  22.49506
XM_060066319.1 22.509439  16.0427418  53.41954 148.45782  75.958269  46.06132
               sample_83 sample_88 sample_90 sample_91  sample_97  sample_98
XR_009525437.1 116.57969 179.41822 616.69232  90.91269 307.749037 357.531059
XM_060060327.1  70.46025  20.60885  28.71007  97.23706  42.498677   7.150621
XR_009529546.1 103.76874 134.56367  98.76264  44.27053 183.183951 215.710406
XM_060061699.1 152.45037 264.27819 110.24667 121.74396 136.288859  52.437889
XM_060058899.1  37.15177  40.00541  34.45209  21.34472   4.396415  26.218944
XM_060066319.1  90.95778 257.00448 259.53904  32.41235 323.869225 194.258542
               sample_99 sample_RESUB.116 sample_RESUB.36 sample_RESUB.94
XR_009525437.1 143.25894         27.11219        17.20051        77.04507
XM_060060327.1 121.13808        108.44874        38.70116        58.70101
XR_009529546.1  56.88223         28.98199       100.33633        37.60533
XM_060061699.1 117.97795        360.87254        88.86932       137.58048
XM_060058899.1  40.02823         55.15927        11.46701        34.85372
XM_060066319.1  40.02823         18.69806        11.46701        25.68169
# Annotate heatmap
annotation <- infosub_L.9.16 %>% 
    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.

4.2 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)

5 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
XR_009524663.1 185.25366     0.58935063 0.3143465  1.8749836 0.060794976
XM_060052481.1 158.28015     1.14320569 0.3594376  3.1842398 0.001451347
XM_060060803.1  42.57745    -0.53400319 0.4173017 -1.2891419 0.197348754
XM_060070373.1  64.28824     0.08828602 0.4084669  0.2161718 0.828853804
XM_060063653.1 102.30124     0.37603724 0.4146658  0.9081482 0.363799908
XM_060065730.1  26.84459     0.24339271 0.3855410  0.6318955 0.527455171
                     padj
XR_009524663.1 0.16372657
XM_060052481.1 0.00778942
XM_060060803.1 0.38681134
XM_060070373.1 0.91626691
XM_060063653.1 0.58110519
XM_060065730.1 0.72533375

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 21876 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 2938, 13%
LFC < 0 (down)     : 2964, 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 21876 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3611, 17%
LFC < 0 (down)     : 3414, 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 21876 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3611, 17%
LFC < 0 (down)     : 3414, 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 21876 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3609, 16%
LFC < 0 (down)     : 3416, 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

6 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 <- res_table_L.9.0_norm_tb %>%
        filter(padj < padj.cutoff & abs(log2FoldChange) > lfc.cutoff)

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_060052481.1    158.           1.14  0.359  3.18 0.00145      0.00779    
2 XM_060036766.1     50.5         -0.944 0.273 -3.45 0.000563     0.00343    
3 XM_060060327.1     76.5         -0.600 0.222 -2.71 0.00674      0.0282     
4 XM_060071434.1     35.4          0.927 0.213  4.35 0.0000137    0.000130   
5 XM_060061699.1    243.          -0.799 0.179 -4.47 0.00000774   0.0000782  
6 XM_060058899.1     23.9          1.40  0.247  5.65 0.0000000160 0.000000281
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: 4673 (padj< 0.05 , log-fold change > 0.58 )"
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)

6.1 Heatmap

# 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 sample_37
XM_060052481.1  466.95239  239.91880   42.92562  170.61493  908.35452  20.38467
XM_060036766.1   44.31724   19.61600   52.46465   20.07235   57.95881  38.73087
XM_060060327.1   91.87721   36.21416   46.50276   49.17725   41.97018 131.48110
XM_060071434.1   82.14903   37.72308   36.96373   25.09043   36.97373  19.36543
XM_060061699.1  128.62809  113.16925  238.47568  139.50280  147.89491 281.30840
XM_060058899.1   52.96451   22.63385   62.59987   38.13746   35.97444  14.26927
               sample_38  sample_39  sample_40  sample_47 sample_48 sample_49
XM_060052481.1  32.81323  76.866605   0.000000 176.880035  73.10333  41.10154
XM_060036766.1  19.86064  44.501719  50.659380  52.974224  11.79086 168.38374
XM_060060327.1  54.40089  93.049048  79.443119 105.948448 116.72951  75.57380
XM_060071434.1  20.72415  16.182443  31.086438  17.059496  24.76081  11.26978
XM_060061699.1 360.94558 426.811938 417.939888 460.606386 124.98311 391.12758
XM_060058899.1  12.95259   5.057013   4.605398   7.182946  24.76081  17.23613
               sample_50  sample_57  sample_58 sample_59 sample_60 sample_67
XM_060052481.1 101.92734 221.998294  63.812977 122.17211  63.17434 113.54817
XM_060036766.1 103.44864  49.246100 106.089074  43.18152 105.06889  80.73078
XM_060060327.1  76.06518  58.626310  94.921803  92.68229  49.87448  95.82678
XM_060071434.1  36.51129  15.633683  33.501813  26.33020  27.92971  36.75548
XM_060061699.1 280.68050 221.998294 363.733968 252.76989 327.84155 330.79929
XM_060058899.1  19.77695   3.908421   3.988311  23.17057  11.96987  11.15791
               sample_68 sample_69 sample_70 sample_78  sample_79 sample_80
XM_060052481.1 114.74950  38.15700  41.05618 197.12316 509.572586  85.06323
XM_060036766.1  68.04912  77.90388  70.82191  36.04538  28.801929  55.57464
XM_060060327.1  78.05635  82.67351 123.16854  31.53971  55.388325  65.78223
XM_060071434.1  29.35452  13.51394  16.42247  58.57374  69.789289  22.68353
XM_060061699.1 296.21383 278.22814 257.62753 172.34196 181.673705 291.48333
XM_060058899.1  15.34441  12.71900  15.39607  45.05672   9.969898  23.81770
               sample_83 sample_88 sample_90 sample_91  sample_97  sample_98
XM_060052481.1 170.58097 161.91497 224.38893  65.53461   0.000000 248.945664
XM_060036766.1  13.64648  19.27559  26.82911  41.70384   4.612232   1.257301
XM_060060327.1  75.05563  21.84567  30.48763 104.68515  44.584911   7.543808
XM_060071434.1  98.25464  39.83622  23.17060  55.32142  66.108661   7.543808
XM_060061699.1 162.39308 280.13860 117.07249 131.06922 142.979197  55.321259
XM_060058899.1  39.57478  42.40630  36.58515  22.97967   4.612232  27.660629
               sample_99 sample_RESUB.116 sample_RESUB.76 sample_RESUB.94
XM_060052481.1  63.77450        385.75443       92.339857        46.02059
XM_060036766.1  46.18154         51.23301       74.539403        32.01432
XM_060060327.1 126.44944        116.52998      182.454658        64.02864
XM_060071434.1  52.77890         38.17362       24.475625        51.02282
XM_060061699.1 123.15076        387.76357      231.405907       150.06713
XM_060058899.1  41.78329         59.26956        4.450114        38.01701
# Annotate heatmap
annotation <- infosub_L.9.0 %>% 
    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.

6.2 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)

7 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
XR_009524663.1 149.50714     0.72434201 0.2700008  2.6892254 0.007161805
XM_060052481.1 188.17138     0.10301109 0.2844947  0.3622300 0.717180167
XM_060060803.1  24.73187    -0.05792871 0.2504703 -0.2307970 0.817472493
XM_060070373.1  51.30331     0.15532402 0.2767318  0.5637806 0.572903488
XM_060063653.1  88.75582     0.26037639 0.2794167  0.9385391 0.347967443
XM_060065730.1  22.46835     0.17581033 0.2806714  0.6292792 0.529166315
                     padj
XR_009524663.1 0.07800147
XM_060052481.1 0.93116389
XM_060060803.1 0.95859008
XM_060070373.1 0.87318671
XM_060063653.1 0.72448063
XM_060065730.1 0.84894573

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 21853 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 769, 3.5%
LFC < 0 (down)     : 772, 3.5%
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_norm)

out of 21853 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1127, 5.2%
LFC < 0 (down)     : 1045, 4.8%
outliers [1]       : 0, 0%
low counts [2]     : 848, 3.9%
(mean count < 9)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.5_apeglm)

out of 21853 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1127, 5.2%
LFC < 0 (down)     : 1045, 4.8%
outliers [1]       : 0, 0%
low counts [2]     : 848, 3.9%
(mean count < 9)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
summary(res_table_L.9.5_ashr)

out of 21853 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1129, 5.2%
LFC < 0 (down)     : 1043, 4.8%
outliers [1]       : 0, 0%
low counts [2]     : 848, 3.9%
(mean count < 9)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

8 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 <- res_table_L.9.5_norm_tb %>%
        filter(padj < padj.cutoff & 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_060071806.1   1361.          -0.647 0.221 -2.92 0.00345  0.0478 
2 XM_060038630.1    194.           0.600 0.196  3.06 0.00221  0.0352 
3 XM_060041934.1     17.6         -0.988 0.277 -3.56 0.000372 0.0101 
4 XR_009526506.1    116.          -0.796 0.216 -3.67 0.000239 0.00716
5 XR_009524073.1    679.           0.756 0.261  3.34 0.000828 0.0180 
6 XM_060067879.1    401.           0.717 0.197  3.63 0.000281 0.00812
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: 1091 (padj< 0.05 , log-fold change > 0.58 )"
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)

8.1 Heatmap

# 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_060071806.1 2276.06625 1253.481300  613.18869 919.302281 1568.066560
XM_060038630.1  158.58214  216.206220  194.36127 170.776117  120.428841
XM_060041934.1   18.33320    3.860825   11.61942   9.345957    8.305437
XR_009526506.1   45.83299   46.329904  190.13603  23.789708   33.221749
XR_009524073.1    0.00000 1494.139414   11.09127 913.354854   17.441418
XM_060067879.1  422.58016  553.384968  439.95364 484.290481  794.830348
               sample_117 sample_118 sample_119 sample_120  sample_121
XM_060071806.1 1549.63205 2523.28891  800.93631 1873.64032 2407.613714
XM_060038630.1  134.45428   97.56623   82.00441  111.44558  136.518840
XM_060041934.1   10.53328   42.42010   55.73115   30.17035    4.520491
XR_009526506.1  139.41112  123.72529   88.37369  213.03962   92.218024
XR_009524073.1    6.19605   12.72603    0.00000   37.55901    6.328688
XM_060067879.1  395.30798  244.62257  373.39874  339.26251  460.186024
               sample_127 sample_128 sample_131 sample_137 sample_138
XM_060071806.1 853.838874  699.22576 1896.61067 2735.72101 1553.41006
XM_060038630.1 104.573700  167.57044  113.84839  170.57253  265.35118
XM_060041934.1   9.163675   50.27113   23.28717    0.00000    0.00000
XR_009526506.1 229.091870  169.09381  186.29736   83.09944   96.74262
XR_009524073.1   3.234238  191.94433   10.34985   52.48386 1000.59509
XM_060067879.1 254.965775  179.75739  151.36661  430.80499  160.31634
               sample_139 sample_140 sample_147  sample_148 sample_150
XM_060071806.1 1004.31735 3606.44024  605.89400 1563.853701 1509.50485
XM_060038630.1  107.22249  164.35600  157.98382  214.545989  225.08722
XM_060041934.1   21.44450   54.78533   19.09695    1.865617   41.52094
XR_009526506.1  117.94474   97.04831  232.63552  220.142841  282.45169
XR_009524073.1   62.54645   15.65295  345.48110    3.264830  592.21978
XM_060067879.1  343.11198  353.75673  296.87070  229.470928  121.28486
                 sample_78  sample_79  sample_80 sample_83   sample_88
XM_060071806.1 1215.843957  792.48856 271.892978 1013.4707 1195.490676
XM_060038630.1  212.627719  188.01627 197.294182  178.5749  394.400195
XM_060041934.1    5.798938   12.22106   3.926252    0.0000    8.938248
XR_009526506.1   45.425013   33.84293 188.460115   46.3831   74.857827
XR_009524073.1   56.056399  724.80271 516.302189  979.8429 2233.444730
XM_060067879.1  316.042110 1164.76077 577.159101  599.5015  549.702255
                 sample_90   sample_91   sample_97   sample_98   sample_99
XM_060071806.1  706.321427 1282.226705  260.654353  394.443786 1734.246765
XM_060038630.1  322.889795  139.404036  470.252698  669.663038  186.988618
XM_060041934.1    7.434962    7.986690    9.405054    6.685488    5.813118
XR_009526506.1   92.405961   99.470588   90.019802   73.540367  139.514824
XR_009524073.1 3148.175502    9.438815 5242.645799 4682.070030    3.875412
XM_060067879.1  232.608109  486.462000  155.855180  151.537726  805.116794
               sample_RESUB.116 sample_RESUB.156 sample_RESUB.94
XM_060071806.1       843.907663       2628.16534       755.89520
XM_060038630.1       108.781652        108.86898       123.72276
XM_060041934.1        16.997133         62.93988        16.94832
XR_009526506.1        56.090540         94.40982        69.48812
XR_009524073.1         5.948997         18.71186        11.01641
XM_060067879.1       420.679046        249.20791       507.60227
# Annotate heatmap
annotation <- infosub_L.9.5 %>% 
    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.

8.2 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 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.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)
LS0tCnRpdGxlOiAiMDctY29kLVJOQXNlcS1ERVNlcTIiCmF1dGhvcjogIkthdGhsZWVuIER1cmtpbiIKZGF0ZTogIjIwMjQtMDMtMTkiCmFsd2F5c19hbGxvd19odG1sOiB0cnVlCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBodG1sX3ByZXZpZXc6IHRydWUgCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICAjIERpc3BsYXkgY29kZSBjaHVua3MKICBldmFsID0gVFJVRSwgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKRGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcyBmb3IgW1BhY2lmaWMgY29kIFJOQXNlcSBkYXRhXShodHRwczovL3NoZWR1cmtpbi5naXRodWIuaW8vUm9iZXJ0cy1MYWJOb3RlYm9vay9wb3N0cy9wcm9qZWN0cy9wYWNpZmljX2NvZC8yMDIzXzEyXzEzX3BhY2lmaWNfY29kLmh0bWwpLgoKLSAgIFJhdyByZWFkcyBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9vd2wuZmlzaC53YXNoaW5ndG9uLmVkdS9uaWdodGluZ2FsZXMvR19tYWNyb2NlcGhhbHVzLzMwLTk0MzEzMzgwNi8pCi0gICBSZWFkcyBhbGlnbmVkIHRvIHRyYW5zY3JpcHRvbWUgZG93bmxvYWRlZCBmcm9tIFtOQ0JJXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L2RhdGFzZXRzL2dlbm9tZS9HQ0ZfMDMxMTY4OTU1LjEvKSwgc3RvcmVkIFtoZXJlXShodHRwczovL293bC5maXNoLndhc2hpbmd0b24uZWR1L2hhbGZzaGVsbC9nZW5vbWljLWRhdGFiYW5rL0dDRl8wMzExNjg5NTUuMV9BU00zMTE2ODk1djFfcm5hLmZuYSkgYXMgYSBwYXJ0IG9mIGxhYiBbZ2Vub21pYyByZXNvdXJjZXNdKGh0dHBzOi8vcm9iZXJ0c2xhYi5naXRodWIuaW8vcmVzb3VyY2VzL0dlbm9taWMtUmVzb3VyY2VzLyNnYWR1cy1tYWNyb2NlcGhhbHVzLXBhY2lmaWMtY29kKS4KCiMjIyBJbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgaW5sY3VkZSA9IFRSVUV9CgojIyBjbGVhcgpybShsaXN0PWxzKCkpCgojIyBJbnN0YWxsIFJ0b29scyBkaXJlY3RseSBmcm9tIChodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9iaW4vd2luZG93cy9SdG9vbHMvKSwgdGhlbiBpbnN0YWxsIHRoZXNlIG9uIGZpcnN0IHJ1bjoKIyBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoInZzbiIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoInRpZHlidWxrIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZ29zZXEiKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJhZmZ5Y29yZXRvb2xzIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiRW5oYW5jZWRWb2xjYW5vIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgicGNhRXhwbG9yZXIiKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJhcGVnbG0iKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJQQ0F0b29scyIpCgoKIyBMaXN0IG9mIHBhY2thZ2VzIHdlIHdhbnQgdG8gaW5zdGFsbCAocnVuIGV2ZXJ5IHRpbWUpCmxvYWQubGliPC1jKCJERVNlcTIiLCJlZGdlUiIsImdvc2VxIiwiZHBseXIiLCJHZW5vbWljRmVhdHVyZXMiLCJkYXRhLnRhYmxlIiwiY2FsaWJyYXRlIiwiYWZmeWNvcmV0b29scyIsImRhdGEudGFibGUiLCJ2c24iLCJ0aWR5YnVsayIsImdncGxvdDIiLCJjb3dwbG90IiwicGhlYXRtYXAiLCJncGxvdHMiLCJSQ29sb3JCcmV3ZXIiLCJFbmhhbmNlZFZvbGNhbm8iLCJwY2FFeHBsb3JlciIsInJlYWR4bCIsImFwZWdsbSIsImFzaHIiLCJ0aWJibGUiLCJwbG90bHkiLCJzcWxkZiIsIlBDQXRvb2xzIiwiZ2dwdWJyIiwiYmVlcHIiLCJnZW5lZmlsdGVyIiwiQ29tcGxleEhlYXRtYXAiLCJjaXJjbGl6ZSIsInNjYWxlcyIsICJ0aWR5dmVyc2UiLCAiZ3JpZGV4dHJhJyIpCgojIFNlbGVjdCBvbmx5IHRoZSBwYWNrYWdlcyB0aGF0IGFyZW4ndCBjdXJyZW50bHkgaW5zdGFsbGVkIChydW4gZXZlcnkgdGltZSkKIyBpbnN0YWxsLmxpYiA8LSBsb2FkLmxpYlshbG9hZC5saWIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKV0KCiMgQW5kIGZpbmFsbHkgd2UgaW5zdGFsbCB0aGUgbWlzc2luZyBwYWNrYWdlcywgaW5jbHVkaW5nIHRoZWlyIGRlcGVuZGVuY3kuCiMgZm9yKGxpYiBpbiBpbnN0YWxsLmxpYikgaW5zdGFsbC5wYWNrYWdlcyhsaWIsZGVwZW5kZW5jaWVzPVRSVUUpCiMgQWZ0ZXIgdGhlIGluc3RhbGxhdGlvbiBwcm9jZXNzIGNvbXBsZXRlcywgd2UgbG9hZCBhbGwgcGFja2FnZXMuCnNhcHBseShsb2FkLmxpYixyZXF1aXJlLGNoYXJhY3Rlcj1UUlVFKQogICAgICAgICAgICAgICAgICAgICAgICAKYGBgCgpJIGZvdW5kIHRoZSBbREVTZXEyIHZpZ25ldHRlXShodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvREVTZXEyL2luc3QvZG9jL0RFU2VxMi5odG1sKSBhbmQgdGhlIFtIQkMgREdFIHRyYWluaW5nIHdvcmtzaG9wXShodHRwczovL2dpdGh1Yi5jb20vaGJjdHJhaW5pbmcvREdFX3dvcmtzaG9wKSBzdXBlciBoZWxwZnVsIGluIGZpZ3VyaW5nIG91dCBob3cgdG8gdXNlIHRoZSBERVNlcTIgcGFja2FnZSEKCiMgTG9hZCBkYXRhCgojIyBMb2FkIGNvdW50IGRhdGEKCkxvYWQgaW4gdGhlIGNvdW50IG1hdHJpeCB3ZSBnZW5lcmF0ZWQgYWZ0ZXIga2FsbGlzdG8gcHNldWRvYWxpZ25tZW50IHVzaW5nIHRoZSBUcmluaXR5IGFidW5kYW5jZV9lc3RpbWF0ZXNfdG9fbWF0cml4LnBsIHNjcmlwdC4gV2UgYWxzbyBuZWVkIHRvIHNsaWdodGx5IHJlZm9ybWF0IHRoZSBjb3VudCBtYXRyaXggdG8gbWFrZSBhbGwgb2YgdGhlIGVzdGltYXRlZCBjb3VudHMgaW50ZWdlcnMsIGFzIHJlcXVpcmVkIGZvciBERVNlcTIuCgpgYGB7cn0KIyBSZWFkIGluIGNvdW50cyBkYXRhLiBUaGlzIGlzIGEgZ2VuZS1sZXZlbCBjb3VudHMgbWF0cml4IGdlbmVyYXRlZCBmcm9tIGthbGxpc3RvIHRyYW5zY3JpcHQgYWJ1bmRhbmNlcyB1c2luZyBUcmluaXR5CmNvZF9jb3VudHNfZGF0YV9PRyA8LSByZWFkX2RlbGltKCIuLi9vdXRwdXQvMDYtY29kLVJOQXNlcS1hbGlnbm1lbnQva2FsbGlzdG8va2FsbGlzdG8uaXNvZm9ybS5jb3VudHMubWF0cml4IikgCmhlYWQoY29kX2NvdW50c19kYXRhX09HKQpgYGAKCiMjIENvdW50IGRhdGEgbXVuZ2luZwoKYGBge3J9CiMgIyBXZSBuZWVkIHRvIG1vZGlmeSB0aGlzIGRhdGEgZnJhbWUgc28gdGhhdCB0aGUgcm93IG5hbWVzIGFyZSBhY3R1YWxseSByb3cgbmFtZXMsIGluc3RlYWQgb2YgY29tcHJpc2luZyB0aGUgZmlyc3QgY29sdW1uCmNvZF9jb3VudHNfZGF0YSA8LSBjb2RfY291bnRzX2RhdGFfT0cgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiLi4uMSIpCgojIEFkZGl0aW9uYWwgZm9ybWF0dGluZwojIFJvdW5kIGFsbCBlc3RpbWF0ZWQgY291bnRzIHRvIGludGVnZXJzCmNvZF9jb3VudHNfZGF0YSA8LSByb3VuZChjb2RfY291bnRzX2RhdGEsIGRpZ2l0cyA9IDApCgojIFJlbW92ZSB0aGUgImthbGxpc3RvX3F1YW50XyIgcG9ydGlvbiBvZiB0aGUgY29sdW1uIG5hbWVzLCB0byBsZWF2ZSBqdXN0IHRoZSBzYW1wbGUgbmFtZXMKY29sbmFtZXMoY29kX2NvdW50c19kYXRhKSA8LSBzdWIoImthbGxpc3RvX3F1YW50XyIsICJzYW1wbGVfIiwgY29sbmFtZXMoY29kX2NvdW50c19kYXRhKSkKCiMgUmVvcmRlciB0aGUgY291bW5zIGludG8gYWxwaGFiZXRpY2FsIG9yZGVyICh0byBtYWtlIGl0IGVhc2llciB0byBjcmVhdGUgYW4gYXNzb2NpYXRlZCBtZXRhZGF0YSBzcHJlYWRzaGVldCkKY29kX2NvdW50c19kYXRhIDwtIGNvZF9jb3VudHNfZGF0YVssIG9yZGVyKGNvbG5hbWVzKGNvZF9jb3VudHNfZGF0YSkpXQoKY29kX3NhbXBsZV9uYW1lcyA8LSBuYW1lcyhjb2RfY291bnRzX2RhdGEpCgpoZWFkKGNvZF9jb3VudHNfZGF0YSkKY29kX3NhbXBsZV9uYW1lcwpgYGAKCiMjIEltcG9ydCBzYW1wbGUgbWV0YWRhdGEgc2hlZXRzCgpgYGB7cn0KIyBSZWFkIGluIHRoZSBjc3YgZmlsZSBhcyBhIGRhdGEgZnJhbWUKY29kX3NhbXBsZV9pbmZvX09HIDwtIHJlYWQuY3N2KCJ+L3Byb2plY3QtY29kLXRlbXBlcmF0dXJlL2RhdGEvREVTZXEyX1NhbXBsZV9JbmZvcm1hdGlvbi5jc3YiKQpjb2RfZXhwZXJpbWVudF9hbGxkYXRhX09HIDwtIHJlYWQuY3N2KCJ+L3Byb2plY3QtY29kLXRlbXBlcmF0dXJlL2RhdGEvdGVtcC1leHBlcmltZW50LmNzdiIpCmhlYWQoY29kX3NhbXBsZV9pbmZvX09HKQpoZWFkKGNvZF9leHBlcmltZW50X2FsbGRhdGFfT0cpCgojIFJlbmFtZSB0aGUgIkdlbmV0aWNTYW1wbGluZ0NvdW50IiBjb2x1bW4gb2YgdGhlIGV4cGVyaW1lbnRhbCBkYXRhIHRvICJzYW1wbGVfbnVtYmVyIgpjb2RfZXhwZXJpbWVudF9hbGxkYXRhIDwtIGNvZF9leHBlcmltZW50X2FsbGRhdGFfT0cKbmFtZXMoY29kX2V4cGVyaW1lbnRfYWxsZGF0YSlbbmFtZXMoY29kX2V4cGVyaW1lbnRfYWxsZGF0YSkgPT0gIkdlbmV0aWNTYW1wbGluZ0NvdW50Il0gPC0gInNhbXBsZV9udW1iZXIiCgojIENhbGN1bGF0ZSBsZW5ndGggZGlmZmVyZW5jZSBhbmQgd2VpZ2h0IGRpZmZlcmVuY2UgKGVuZC1iZWdpbm5pbmcpCmNvZF9leHBlcmltZW50X2FsbGRhdGEkU0xfZGlmZl9tbSA8LSBjb2RfZXhwZXJpbWVudF9hbGxkYXRhJFNMX21tIC0gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSRTTF8xMTIxMjAyMgpjb2RfZXhwZXJpbWVudF9hbGxkYXRhJFdXVF9kaWZmX2cgPC0gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSRXaG9sZUJvZHlXV19nIC0gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSRXV1RfMTEyMTIwMjIKCiMgTWVyZ2UgdGhlIHR3byBkYXRhIGZyYW1lcyB0byBnZXQgZXhwZXJpbWVudGFsIGRhdGEgZm9yIGFsbCBvZiBvdXIgUk5Bc2VxJ2Qgc2FtcGxlcy4KIyBUaGlzIHNob3VsZCBpbmNsdWRlIGFsbCByb3dzIGZyb20gY29kX3NhbXBsZV9pbmZvX09HIGFuZCBtYXRjaGluZyByb3dzIGZyb20gY29kX2V4cGVyaW1lbnRfYWxsZGF0YSBiYXNlZCBvbiB0aGUgc2hhcmVkIHNhbXBsZV9udW1iZXIgY29sdW1uLiBTYW1wbGUgbnVtYmVyIGR1cGxpY2F0ZXMgKGUuZy4gZnJvbSBkaWZmZXJlbnQgdGlzc3VlIHR5cGVzKSBzaG91bGQgYmUgcmV0YWluZWQuCmNvZF9zYW1wbGVfaW5mbyA8LSBtZXJnZShjb2Rfc2FtcGxlX2luZm9fT0csIGNvZF9leHBlcmltZW50X2FsbGRhdGEsIGJ5ID0gInNhbXBsZV9udW1iZXIiLCBhbGwueCA9IFRSVUUpCgojIFJlb3JkZXIgdGhlIGRhdGEgZnJhbWUgaW50byBhbHBoYWJldGljYWwgb3JkZXIgYnkgdGhlIHNhbXBsZSBuYW1lcywgc28gdGhhdCB0aGUgcm93cyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgb3VyIGNvdW50IG1hdHJpeCBjb2x1bW5zCmNvZF9zYW1wbGVfaW5mbyA8LSBjb2Rfc2FtcGxlX2luZm9bb3JkZXIoY29kX3NhbXBsZV9pbmZvJHNhbXBsZV9uYW1lKSwgXQoKIyBBZ2Fpbiwgd2UgbmVlZCB0byByZWZvcm1hdCBzbyB0aGF0IHRoZSBkYXRhIGluIHRoZSBmaXJzdCBjb2x1bW4gYmVjb21lcyB0aGUgcm93IG5hbWVzCnJvd25hbWVzKGNvZF9zYW1wbGVfaW5mbykgPC0gY29kX3NhbXBsZV9pbmZvJHNhbXBsZV9uYW1lCgojIFJlbW92ZSBkdXBsaWNhdGUgY29sdW1ucyAoYXJ0aWZhY3Qgb2YgbWVyZ2luZyBkYXRhIGZyYW1lcyB3aXRoIG11bHRpcGxlIHNoYXJlZCBjb2x1bW5zIGFuZCBvZiBtYWluZyBzYW1wbGVfbmFtZSB0aGUgcm93bmFtZXMgaW5zdGVhZCBvZiBhIHZhcmlhYmxlKQpjb2Rfc2FtcGxlX2luZm8gPC0gc3Vic2V0KGNvZF9zYW1wbGVfaW5mbywgc2VsZWN0PS1UZW1wZXJhdHVyZSkKY29kX3NhbXBsZV9pbmZvIDwtIHN1YnNldChjb2Rfc2FtcGxlX2luZm8sIHNlbGVjdD0tVGFuaykKY29kX3NhbXBsZV9pbmZvIDwtIHN1YnNldChjb2Rfc2FtcGxlX2luZm8sIHNlbGVjdD0tc2FtcGxlX25hbWUpCgoKaGVhZChjb2Rfc2FtcGxlX2luZm8pCmBgYAoKIyMgU2FtcGxlIG1ldGFkYXRhIG11bmdpbmcKCmBgYHtyfQojIEZhY3RvciB2YXJpYWJsZXMKY29kX3NhbXBsZV9pbmZvJHRlbXBfdHJlYXRtZW50IDwtIGZhY3Rvcihjb2Rfc2FtcGxlX2luZm8kdGVtcF90cmVhdG1lbnQpCmNvZF9zYW1wbGVfaW5mbyR0YW5rIDwtIGZhY3Rvcihjb2Rfc2FtcGxlX2luZm8kdGFuaykKY29kX3NhbXBsZV9pbmZvJHRpc3N1ZV90eXBlIDwtIGZhY3Rvcihjb2Rfc2FtcGxlX2luZm8kdGlzc3VlX3R5cGUpCgojIFJlbW92ZSBiYWQvbWlzc2luZyBzYW1wbGVzCiMgTWlzc2luZyBkYXRhOiA5MgojIE11bGlRQyByZXBvcnQ6IDE0OSwgMTI5CiMgUENBIG91dGxpZXJzOiAzMSwgNDEgKHBlciBMYXVyYSkKY29kX3NhbXBsZV9pbmZvIDwtIGNvZF9zYW1wbGVfaW5mb1shKHJvdy5uYW1lcyhjb2Rfc2FtcGxlX2luZm8pICVpbiUgYygic2FtcGxlXzkyIiwgInNhbXBsZV8xNDkiLCAic2FtcGxlXzEyOSIsICJzYW1wbGVfMzEiLCAic2FtcGxlXzQxIikpLF0KY29kX2NvdW50c19kYXRhIDwtIGFzLm1hdHJpeChzdWJzZXQoY29kX2NvdW50c19kYXRhLCBzZWxlY3Q9LWMoc2FtcGxlXzE0OSwgc2FtcGxlXzEyOSwgc2FtcGxlXzMxLCBzYW1wbGVfNDEpKSkKCiMgQ2hlY2sgdGhhdCB0aGUgY29sdW1uIG5hbWVzIG9mIG91ciBjb3VudCBkYXRhIG1hdGNoIHRoZSByb3cgbmFtZXMgb2Ygb3VyIHNhbXBsZSBpbmZvIHNoZWV0Cm5jb2woY29kX2NvdW50c19kYXRhKQpucm93KGNvZF9zYW1wbGVfaW5mbykKCmFsbChjb2xuYW1lcyhjb2RfY291bnRzX2RhdGEpICVpbiUgcm93bmFtZXMoY29kX3NhbXBsZV9pbmZvKSkKYWxsKGNvbG5hbWVzKGNvZF9jb3VudHNfZGF0YSkgPT0gcm93bmFtZXMoY29kX3NhbXBsZV9pbmZvKSkKYGBgCgojIFByZWxpbWluYXJ5IFBDQSB2aXN1YWxpemF0aW9uIChsaXZlciB0aXNzdWUpCgojIyBERVNlcSBvYmplY3QKCmBgYHtyfQojIEZpbHRlciBkYXRhCmluZm9zdWJfTCA8LSBjb2Rfc2FtcGxlX2luZm8gJT4lIGZpbHRlcih0aXNzdWVfdHlwZSA9PSAiTGl2ZXIiKQpjb3VudHN1Yl9MIDwtIHN1YnNldChjb2RfY291bnRzX2RhdGEsIHNlbGVjdD1yb3cubmFtZXMoaW5mb3N1Yl9MKSkKCiMgQ2FsY3VsYXRlIERFU2VxIG9iamVjdApkZHNfTCA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGNvdW50c3ViX0wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBpbmZvc3ViX0wsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gdGVtcF90cmVhdG1lbnQpIAoKIyBSdW4gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgCiMgKE5vdGUgdGhhdCB0aGlzIERFU2VxKCkgZnVuY3Rpb24gcnVucyBhbGwgbmVjZXNzYXJ5IHN0ZXBzLCBpbmNsdWRpbmcgZGF0YSBub3JtYWxpemF0aW9uLCAKIyBlc3RpbWF0aW5nIHNpemUgZmFjdG9ycywgZXN0aW1hdGluZyBkaXNwZXJzaW9ucywgZ2VuZS13aXNlIGRpc3BlcnNpb24gZXN0aW1hdGVzLCBtZWFuLWRpc3BlcnNpb24gCiMgcmVsYXRpb25zaGlwLCBmaW5hbCBkaXNwZXJzaW9uIGVzdGltYXRlcywgZml0dGluZyBtb2RlbCwgYW5kIHRlc3RpbmcpCmRkc19MIDwtIERFU2VxKGRkc19MKQpyZXN1bHRzTmFtZXMoZGRzX0wpICMgbGlzdHMgdGhlIGNvZWZmaWNpZW50cwpgYGAKCmBgYHtyfQpwbG90RGlzcEVzdHMoZGRzX0wpCmBgYAoKIyMgUENBIHZpc3VhbGl6YXRpb24KCmBgYHtyfQojIEdlbmVyYXRlIFBDQXMKIyB0b3AgNTAwIG1vc3QgdmFyaWFibGUgZ2VuZXMKcGNhX0xfNTAwPC0gcGxvdFBDQSh2c3QoZGRzX0wpLCBpbnRncm91cCA9IGMoInRlbXBfdHJlYXRtZW50IiksIHJldHVybkRhdGE9VFJVRSkKcGVyY2VudFZhcl9MXzUwMCA8LSByb3VuZCgxMDAqYXR0cihwY2FfTF81MDAsICJwZXJjZW50VmFyIikpCiMgbWVyZ2Ugd2l0aCBtZXRhZGF0YSBzaGVldCBzbyB3ZSBjYW4gcGxvdCB1c2luZyBvdGhlciBmZWF0dXJlcwpwY2FfTF81MDAgPC0gc3Vic2V0KHBjYV9MXzUwMCwgc2VsZWN0PS10ZW1wX3RyZWF0bWVudCkgI3JlbW92ZSB0aGUgdGVtcF90cmVhdG1lbnQgY29sdW1uLCB3aGljaCB3aWxsIGJlIGEgZHVwbGljYXRlIHBvc3QtbWVyZ2UKcGNhX0xfNTAwIDwtIG1lcmdlKHBjYV9MXzUwMCwgY29kX3NhbXBsZV9pbmZvLCBieS54ID0gIm5hbWUiLCBieS55ID0gInJvdy5uYW1lcyIpCgojIHRvcCAxMDAwIG1vc3QgdmFyaWFibGUgZ2VuZXMKcGNhX0xfMTAwMCA8LSBwbG90UENBKHZzdChkZHNfTCksIGludGdyb3VwID0gYygidGVtcF90cmVhdG1lbnQiKSwgcmV0dXJuRGF0YT1UUlVFLCBudG9wPTEwMDApCnBlcmNlbnRWYXJfTF8xMDAwIDwtIHJvdW5kKDEwMCphdHRyKHBjYV9MXzEwMDAsICJwZXJjZW50VmFyIikpCiMgbWVyZ2Ugd2l0aCBtZXRhZGF0YSBzaGVldCBzbyB3ZSBjYW4gcGxvdCB1c2luZyBvdGhlciBmZWF0dXJlcwpwY2FfTF8xMDAwIDwtIHN1YnNldChwY2FfTF8xMDAwLCBzZWxlY3Q9LXRlbXBfdHJlYXRtZW50KSAjcmVtb3ZlIHRoZSB0ZW1wX3RyZWF0bWVudCBjb2x1bW4sIHdoaWNoIHdpbGwgYmUgYSBkdXBsaWNhdGUgcG9zdC1tZXJnZQpwY2FfTF8xMDAwIDwtIG1lcmdlKHBjYV9MXzEwMDAsIGNvZF9zYW1wbGVfaW5mbywgYnkueCA9ICJuYW1lIiwgYnkueSA9ICJyb3cubmFtZXMiKQoKIyBhbGwgZ2VuZXMKcGNhX0xfYWxsIDwtIHBsb3RQQ0EodnN0KGRkc19MKSwgaW50Z3JvdXAgPSBjKCJ0ZW1wX3RyZWF0bWVudCIpLCByZXR1cm5EYXRhPVRSVUUsIG50b3A9bnJvdyhhc3NheSh2c3QoZGRzX0wpKSkpCnBlcmNlbnRWYXJfTF9hbGwgPC0gcm91bmQoMTAwKmF0dHIocGNhX0xfYWxsLCAicGVyY2VudFZhciIpKQojIG1lcmdlIHdpdGggbWV0YWRhdGEgc2hlZXQgc28gd2UgY2FuIHBsb3QgdXNpbmcgb3RoZXIgZmVhdHVyZXMKcGNhX0xfYWxsIDwtIHN1YnNldChwY2FfTF9hbGwsIHNlbGVjdD0tdGVtcF90cmVhdG1lbnQpICNyZW1vdmUgdGhlIHRlbXBfdHJlYXRtZW50IGNvbHVtbiwgd2hpY2ggd2lsbCBiZSBhIGR1cGxpY2F0ZSBwb3N0LW1lcmdlCnBjYV9MX2FsbCA8LSBtZXJnZShwY2FfTF9hbGwsIGNvZF9zYW1wbGVfaW5mbywgYnkueCA9ICJuYW1lIiwgYnkueSA9ICJyb3cubmFtZXMiKQoKIyBBc3NpZ24gc3BlY2lmaWMgY29sb3JzIHRvIGVhY2ggdGVtcGVyYXR1cmUgdHJlYXRtZW50IGxldmVsCnRlbXBfY29sb3JzIDwtIGMoCiAgIjAiID0gImRhcmtibHVlIiwKICAiNSIgPSAicm95YWxibHVlMSIsCiAgIjkiID0gImdyZWVuIiwKICAiMTYiID0gIm9yYW5nZXJlZCIpIAoKIyBQbG90IFBDQXMKcC5MLjUwMCA8LSBnZ3Bsb3QocGNhX0xfNTAwLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50KSkgKyAKICBnZW9tX3BvaW50KHNpemU9NCwgYWxwaGEgPSA1LzEwKSArCiAgZ2d0aXRsZSgiTGl2ZXIsIHRvcCA1MDAgbW9zdCB2YXJpYWJsZSBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLHBlcmNlbnRWYXJfTF81MDBbMV0sIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIscGVyY2VudFZhcl9MXzUwMFsyXSwiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9dGVtcF9jb2xvcnMpKwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuNTAwLlNMZGlmZiA8LSBnZ3Bsb3QocGNhX0xfNTAwLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50LCBzaXplPVNMX2RpZmZfbW0pKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBnZ3RpdGxlKCJMaXZlciwgdG9wIDUwMCBtb3N0IHZhcmlhYmxlIGdlbmVzIikgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJfTF81MDBbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyX0xfNTAwWzJdLCAiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ZW1wX2NvbG9ycykgKwogIHNjYWxlX3NpemVfY29udGludW91cygpICsgICMgQWRkIHRoaXMgbGluZSB0byBjb250cm9sIHRoZSBzaXplIG9mIHBvaW50cwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuNTAwLldXVGRpZmYgPC0gZ2dwbG90KHBjYV9MXzUwMCwgYWVzKFBDMSwgUEMyLCBjb2xvcj10ZW1wX3RyZWF0bWVudCwgc2l6ZT1XV1RfZGlmZl9nKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgZ2d0aXRsZSgiTGl2ZXIsIHRvcCA1MDAgbW9zdCB2YXJpYWJsZSBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyX0xfNTAwWzFdLCAiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhcl9MXzUwMFsyXSwgIiUgdmFyaWFuY2UiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdGVtcF9jb2xvcnMpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoKSArICAjIEFkZCB0aGlzIGxpbmUgdG8gY29udHJvbCB0aGUgc2l6ZSBvZiBwb2ludHMKICBzdGF0X2VsbGlwc2UoKQoKcC5MLjEwMDAgPC0gZ2dwbG90KHBjYV9MXzEwMDAsIGFlcyhQQzEsIFBDMiwgY29sb3I9dGVtcF90cmVhdG1lbnQpKSArIAogIGdlb21fcG9pbnQoc2l6ZT00LCBhbHBoYSA9IDUvMTApICsKICBnZ3RpdGxlKCJMaXZlciwgdG9wIDEwMDAgbW9zdCB2YXJpYWJsZSBnZW5lcyIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLHBlcmNlbnRWYXJfTF8xMDAwWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRWYXJfTF8xMDAwWzJdLCIlIHZhcmlhbmNlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz10ZW1wX2NvbG9ycykrCiAgc3RhdF9lbGxpcHNlKCkKCnAuTC4xMDAwLlNMZGlmZiA8LSBnZ3Bsb3QocGNhX0xfMTAwMCwgYWVzKFBDMSwgUEMyLCBjb2xvcj10ZW1wX3RyZWF0bWVudCwgc2l6ZT1TTF9kaWZmX21tKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgZ2d0aXRsZSgiTGl2ZXIsIHRvcCAxMDAwIG1vc3QgdmFyaWFibGUgZ2VuZXMiKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhcl9MXzUwMFsxXSwgIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRWYXJfTF81MDBbMl0sICIlIHZhcmlhbmNlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHRlbXBfY29sb3JzKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKCkgKyAgIyBBZGQgdGhpcyBsaW5lIHRvIGNvbnRyb2wgdGhlIHNpemUgb2YgcG9pbnRzCiAgc3RhdF9lbGxpcHNlKCkKCnAuTC4xMDAwLldXVGRpZmYgPC0gZ2dwbG90KHBjYV9MXzEwMDAsIGFlcyhQQzEsIFBDMiwgY29sb3I9dGVtcF90cmVhdG1lbnQsIHNpemU9V1dUX2RpZmZfZykpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKwogIGdndGl0bGUoIkxpdmVyLCB0b3AgMTAwMCBtb3N0IHZhcmlhYmxlIGdlbmVzIikgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJfTF81MDBbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyX0xfNTAwWzJdLCAiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ZW1wX2NvbG9ycykgKwogIHNjYWxlX3NpemVfY29udGludW91cygpICsgICMgQWRkIHRoaXMgbGluZSB0byBjb250cm9sIHRoZSBzaXplIG9mIHBvaW50cwogIHN0YXRfZWxsaXBzZSgpCgpwLkwuYWxsIDwtIGdncGxvdChwY2FfTF9hbGwsIGFlcyhQQzEsIFBDMiwgY29sb3I9dGVtcF90cmVhdG1lbnQpKSArIAogIGdlb21fcG9pbnQoc2l6ZT00LCBhbHBoYSA9IDUvMTApICsKICBnZ3RpdGxlKCJMaXZlciwgYWxsIGdlbmVzIikgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIscGVyY2VudFZhcl9MX2FsbFsxXSwiJSB2YXJpYW5jZSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIixwZXJjZW50VmFyX0xfYWxsWzJdLCIlIHZhcmlhbmNlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz10ZW1wX2NvbG9ycykrCiAgc3RhdF9lbGxpcHNlKCkKCnAuTC5hbGwuU0xkaWZmIDwtIGdncGxvdChwY2FfTF9hbGwsIGFlcyhQQzEsIFBDMiwgY29sb3I9dGVtcF90cmVhdG1lbnQsIHNpemU9U0xfZGlmZl9tbSkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKwogIGdndGl0bGUoIkxpdmVyLCBhbGwgZ2VuZXMiKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhcl9MXzUwMFsxXSwgIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRWYXJfTF81MDBbMl0sICIlIHZhcmlhbmNlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHRlbXBfY29sb3JzKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKCkgKyAgIyBBZGQgdGhpcyBsaW5lIHRvIGNvbnRyb2wgdGhlIHNpemUgb2YgcG9pbnRzCiAgc3RhdF9lbGxpcHNlKCkKCnAuTC5hbGwuV1dUZGlmZiA8LSBnZ3Bsb3QocGNhX0xfYWxsLCBhZXMoUEMxLCBQQzIsIGNvbG9yPXRlbXBfdHJlYXRtZW50LCBzaXplPVdXVF9kaWZmX2cpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsKICBnZ3RpdGxlKCJMaXZlciwgYWxsIGdlbmVzIikgKwogIHhsYWIocGFzdGUwKCJQQzE6ICIsIHBlcmNlbnRWYXJfTF81MDBbMV0sICIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLCBwZXJjZW50VmFyX0xfNTAwWzJdLCAiJSB2YXJpYW5jZSIpKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ZW1wX2NvbG9ycykgKwogIHNjYWxlX3NpemVfY29udGludW91cygpICsgICMgQWRkIHRoaXMgbGluZSB0byBjb250cm9sIHRoZSBzaXplIG9mIHBvaW50cwogIHN0YXRfZWxsaXBzZSgpCgojIFZpZXcgUENBcwpwLkwuNTAwCnAuTC41MDAuU0xkaWZmCnAuTC41MDAuV1dUZGlmZgpwLkwuMTAwMApwLkwuMTAwMC5TTGRpZmYKcC5MLjEwMDAuV1dUZGlmZgpwLkwuYWxsCnAuTC5hbGwuU0xkaWZmCnAuTC5hbGwuV1dUZGlmZgoKIyBFeHBvcnQgUENBcyBhcyBwbmdzCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9QQ0FfTF81MDAucG5nIiwKICAgICAgICAgcGxvdCAgID0gcC5MLjUwMCwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA2MDAwLAogICAgICAgICBoZWlnaHQgPSA0MDAwKQoKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL1BDQV9MXzEwMDAucG5nIiwKICAgICAgICAgcGxvdCAgID0gcC5MLjEwMDAsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNjAwMCwKICAgICAgICAgaGVpZ2h0ID0gNDAwMCkKCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9QQ0FfTF9hbGwucG5nIiwKICAgICAgICAgcGxvdCAgID0gcC5MLmFsbCwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA2MDAwLAogICAgICAgICBoZWlnaHQgPSA0MDAwKQpgYGAKCiMgTGl2ZXIgdGlzc3VlLCA5KkMgdi4gMTYqQwoKVGhlIDlcKkMgdGVtcGVyYXR1cmUgdHJlYXRtZW50IGlzIGVmZmVjdGl2ZWx5IG91ciAiY29udHJvbCwiIGFzIGl0IHJlcHJlc2VudHMgdGhlIGFtYmllbnQgdGVtcGVyYXR1cmUgdGhhdCB3aWxkIGp1dmVuaWxlIFBhY2lmaWMgY29kIHdvdWxkIGV4cGVyaWVuY2UuCgpgYGB7cn0KIyBsaXZlciB0aXNzdWUsIHRlbXBlcmF0dXJlcyA5IHZzLiAxNiAKCiMgRmlsdGVyIGRhdGEKaW5mb3N1Yl9MLjkuMTYgPC0gY29kX3NhbXBsZV9pbmZvICU+JSBmaWx0ZXIodGlzc3VlX3R5cGUgPT0gIkxpdmVyIiAmICh0ZW1wX3RyZWF0bWVudCA9PSAiOSIgfCB0ZW1wX3RyZWF0bWVudCA9PSAiMTYiKSkKY291bnRzdWJfTC45LjE2IDwtIHN1YnNldChjb2RfY291bnRzX2RhdGEsIHNlbGVjdD1yb3cubmFtZXMoaW5mb3N1Yl9MLjkuMTYpKQoKIyBDYWxjdWxhdGUgREVTZXEgb2JqZWN0CmRkc19MLjkuMTYgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHN1Yl9MLjkuMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBpbmZvc3ViX0wuOS4xNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzaWduID0gfiB0ZW1wX3RyZWF0bWVudCkKCmRkc19MLjkuMTYgPC0gREVTZXEoZGRzX0wuOS4xNikKcmVzdWx0c05hbWVzKGRkc19MLjkuMTYpICMgbGlzdHMgdGhlIGNvZWZmaWNpZW50cwpgYGAKCmBgYHtyfQpwbG90RGlzcEVzdHMoZGRzX0wuOS4xNikKYGBgCgpgYGB7cn0KIyBGaWx0ZXJpbmc6IGtlZXAgZ2VuZXMgdGhhdCBoYXZlIGF0IGxlYXN0IDEwIGNvdW50cyBhY3Jvc3MgMS8zIG9mIHRoZSBzYW1wbGVzIC0gaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC8xMTAzMDcvCmtlZXAgPC0gcm93U3VtcyhERVNlcTI6OmNvdW50cyhkZHNfTC45LjE2KSA+PSAxMCkgPj0gbmNvbChjb3VudHN1Yl9MLjkuMTYpLzMKZGRzX0wuOS4xNjwtIGRkc19MLjkuMTZba2VlcCxdCgojIEdlbmVyYXRlIENvbnRyYXN0cwpjb250cmFzdF9saXN0X0wuOS4xNiAgICAgICAgPC0gYygidGVtcF90cmVhdG1lbnQiLCAiMTYiLCAiOSIpICMgb3JkZXIgaXMgaW1wb3J0YW50OiBmYWN0b3IsIHRyZWF0bWVudCBncm91cCwgY29udHJvbApyZXNfdGFibGVfTC45LjE2X25vc2hyaW5rIDwtIHJlc3VsdHMoZGRzX0wuOS4xNiwgY29udHJhc3Q9Y29udHJhc3RfbGlzdF9MLjkuMTYsIGFscGhhID0gMC4wNSkKCnJlc190YWJsZV9MLjkuMTZfbm9ybSAgICAgPC0gbGZjU2hyaW5rKGRkc19MLjkuMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0ibm9ybWFsIikgIyBsZmNUaHJlc2hvbGQgPSAwLjU4NSkgICMgYSBsZmMgdGhyZXNob2xkIG9mIDEgPSAyLWZvbGQgY2hhbmdlLCAwLjU4NSA9IDEuNS1mb2xkIGNoYW5nZQpyZXNfdGFibGVfTC45LjE2X2FwZWdsbSAgIDwtIGxmY1NocmluayhkZHNfTC45LjE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPSJhcGVnbG0iKSAjIGxmY1RocmVzaG9sZCA9IDAuNTg1KSAgIyBhIGxmYyB0aHJlc2hvbGQgb2YgMSA9IDItZm9sZCBjaGFuZ2UsIDAuNTg1ID0gMS41LWZvbGQgY2hhbmdlCnJlc190YWJsZV9MLjkuMTZfYXNociAgICAgPC0gbGZjU2hyaW5rKGRkc19MLjkuMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9ImFzaHIiKQpgYGAKCmBgYHtyfQojIEdlbmVyYXRlIE1BIHBsb3RzCnBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDQsNCwyLDEpKQp4bGltIDwtIGMoMSwxZTUpOyB5bGltIDwtIGMoLTQsNCkKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS4xNl9ub3NocmluaywgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49Im5vIHNocmluayIpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMTZfbm9ybSwgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49Im5vcm1hbCIpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMTZfYXBlZ2xtLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0iYXBlZ2xtIikKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS4xNl9hc2hyLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0iYXNociIpCmBgYAoKYGBge3J9CiMgRXhhbWluZSByZXN1bHRzIGZvcm1hdHRpbmcKcmVzX3RhYmxlX0wuOS4xNl9ub3JtICU+JSBkYXRhLmZyYW1lKCkgJT4lIGhlYWQoKQpgYGAKCk5vdGUgdGhhdCB0aGUgbWV0cmljIHdlIHdhbnQgdG8gdXNlIHRvIGlkZW50aWZ5IHNpZ25pZmljYW50bHkgZXhwcmVzc2VkIGdlbmVzIGlzIHRoZSBgcGFkamAgdmFsdWVzLCAqKk5PVCoqIHRoZSBgcHZhbHVlYC4gYHBhZGpgIGFyZSBwLXZhbHVlcyBjb3JyZWN0ZWQgZm9yIG11bHRpcGxlIHRlc3RpbmcgKGRlZmF1bHQgbWV0aG9kIGlzIHRoZSBCZW5qYW1pbmkgYW5kIEhvY2hiZXJnIG1ldGhvZCkuCgpgYGB7cn0Kc3VtbWFyeShyZXNfdGFibGVfTC45LjE2X25vc2hyaW5rKQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuMTZfbm9ybSkKc3VtbWFyeShyZXNfdGFibGVfTC45LjE2X2FwZWdsbSkKc3VtbWFyeShyZXNfdGFibGVfTC45LjE2X2FzaHIpCmBgYAoKIyBFeHRyYWN0aW5nIHNpZ25pZmljYW50bHkgZXhwcmVzc2VkIGdlbmVzCgpgYGB7cn0KcGFkai5jdXRvZmYgPC0gMC4wNQpsZmMuY3V0b2ZmIDwtIDAuNTgKCiMgQ29udmVydCByZXN1bHRzIHRhYmxlIGludG8gdGliYmxlCnJlc190YWJsZV9MLjkuMTZfbm9ybV90YiA8LSByZXNfdGFibGVfTC45LjE2X25vcm0gJT4lCiAgZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXI9ImdlbmUiKSAlPiUKICBhc190aWJibGUoKQoKIyBzdWJzZXQgdGhhdCB0YWJsZSB0byBvbmx5IGtlZXAgdGhlIHNpZ25pZmljYW50IGdlbmVzIHVzaW5nIG91ciBwcmUtZGVmaW5lZCB0aHJlc2hvbGRzOgpzaWdfTC45LjE2X25vcm0gPC0gcmVzX3RhYmxlX0wuOS4xNl9ub3JtX3RiICU+JQogICAgICAgIGZpbHRlcihwYWRqIDwgcGFkai5jdXRvZmYgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID4gbGZjLmN1dG9mZikKCmhlYWQoc2lnX0wuOS4xNl9ub3JtKQpwYXN0ZSgiTnVtYmVyIG9mIHNpZ25pZmljYW50IERFR3MgZm9yIDlDIHYgMTZDOiIsIG5yb3coc2lnX0wuOS4xNl9ub3JtKSwgIihwYWRqPCIsIHBhZGouY3V0b2ZmLCAiLCBsb2ctZm9sZCBjaGFuZ2UgPiIsIGxmYy5jdXRvZmYsICIpIikKCndyaXRlLnRhYmxlKHNpZ19MLjkuMTZfbm9ybSwgZmlsZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvR21hY19ERUdzX3NpZ19MLjkuMTZfbm9ybS50YWIiLCBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBOQSkKYGBgCgojIyBIZWF0bWFwCgpgYGB7cn0KIyBSZXRyaWV2ZSBub3JtYWxpemVkIGNvdW50cyBtYXRyaXgKZGRzX0wuOS4xNl9ub3JtX2NvdW50cyA8LSBjb3VudHMoZGRzX0wuOS4xNiwgbm9ybWFsaXplZD1UUlVFKQoKIyBFeHRyYWN0IG5vcm1hbGl6ZWQgZXhwcmVzc2lvbiBmb3Igc2lnbmlmaWNhbnQgZ2VuZXMKbm9ybV9zaWdfTC45LjE2IDwtIGRkc19MLjkuMTZfbm9ybV9jb3VudHMgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUKICBmaWx0ZXIocm93Lm5hbWVzKGRkc19MLjkuMTZfbm9ybV9jb3VudHMpICVpbiUgc2lnX0wuOS4xNl9ub3JtJGdlbmUpCgpoZWFkKG5vcm1fc2lnX0wuOS4xNikKCiMgQW5ub3RhdGUgaGVhdG1hcAphbm5vdGF0aW9uIDwtIGluZm9zdWJfTC45LjE2ICU+JSAKCXNlbGVjdCh0ZW1wX3RyZWF0bWVudCkKCiMgU2V0IGEgY29sb3IgcGFsZXR0ZQpoZWF0X2NvbG9ycyA8LSByZXYoYnJld2VyLnBhbCgxMiwgIlJkWWxCdSIpKQoKIyBSdW4gcGhlYXRtYXAKaC5MLjkuMTYgPC0gcGhlYXRtYXAobm9ybV9zaWdfTC45LjE2LCAKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgCiAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsIAogICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbiA9IGFubm90YXRpb24sIAogICAgICAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsIAogICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDMwLAogICAgICAgICAgICAgICAgICAgICBtYWluID0gIk5vcm1hbGl6ZWQgU2lnbmlmaWNhbnQgRXhwcmVzc2lvbiwgTGl2ZXIsIDkqQyBhbmQgMTYqQyIpCgojIFNhdmUgcGxvdApnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvaGVhdG1hcF9MLjkuMTZfbm9ybV9zaWcucG5nIiwKICAgICAgICAgcGxvdCAgID0gaC5MLjkuMTYsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgpOb3RlIHRoZSBhcmd1bWVudCBgc2NhbGU9InJvdyJgIHdhcyBpbmNsdWRlZCwgc28gdGhlIHZhbHVlcyBwbG90dGVkIGluIHRoZSBoZWF0IG1hcCBhcmUgKlotc2NvcmVzKiwgcmF0aGVyIHRobiB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZS4gVGhpcyB2YXN0bHkgaW1wcm92ZXMgdGhlIGNvbG9yIHZpc3VhbGl6YXRpb24uCgojIyBWb2xjYW5vIHBsb3QKCmBgYHtyfQojIEdlbmVyYXRlIHBsb3QKdi5MLjkuMTYgPC0gCiAgZ2dwbG90KHJlc190YWJsZV9MLjkuMTZfbm9ybV90YikgKwogICMgUGxvdCBhbGwKICBnZW9tX3BvaW50KGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwYWRqKSxjb2xvcj0idW5jaGFuZ2VkIiksCiAgICAgICAgICAgICBzaXplPS41KSArCiAgIyBPdmVybGF5IGFsbCBzaWduaWZpY2FudGx5IHVwcmVndWxhdGVkIGluIHJlZAogIGdlb21fcG9pbnQoZGF0YSA9IHNpZ19MLjkuMTZfbm9ybVtzaWdfTC45LjE2X25vcm0kbG9nMkZvbGRDaGFuZ2UgPiAwLCBdLCAKICAgICAgICAgICAgIGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwYWRqKSwgY29sb3I9InVwcmVndWxhdGVkIiksIAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogICMgT3ZlcmxheSBhbGwgc2lnbmlmaWNhbnRseSBkb3ducmVndWxhdGVkIGluIGJsdWUKICBnZW9tX3BvaW50KGRhdGEgPSBzaWdfTC45LjE2X25vcm1bc2lnX0wuOS4xNl9ub3JtJGxvZzJGb2xkQ2hhbmdlIDwgMCwgXSwgCiAgICAgICAgICAgICBhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksIGNvbG9yPSJkb3ducmVndWxhdGVkIiksIAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogIGdndGl0bGUoIkxpdmVyLCA5KkMgYW5kIDE2KkMiKSArCiAgeGxhYigibG9nMiBmb2xkIGNoYW5nZSIpICsgCiAgeWxhYigiLWxvZzEwIGFkanVzdGVkIHAtdmFsdWUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTQsNCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDMwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJ1bmNoYW5nZWQiID0gImRhcmtncmV5IiwgInVwcmVndWxhdGVkIiA9ICJyZWQiLCAiZG93bnJlZ3VsYXRlZCIgPSAiYmx1ZSIpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJ1bmNoYW5nZWQiID0gIlVuY2hhbmdlZCIsICJ1cHJlZ3VsYXRlZCIgPSAiVXByZWd1bGF0ZWQiLCAiZG93bnJlZ3VsYXRlZCIgPSAiRG93bnJlZ3VsYXRlZCIpLAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gTlVMTCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjUpLCBoanVzdCA9IDAuNSksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMjUpKSkKCnYuTC45LjE2CgojIFNhdmUgcGxvdApnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvdm9sY2Fub19MLjkuMTYucG5nIiwKICAgICAgICAgcGxvdCAgID0gdi5MLjkuMTYsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNjAwMCwKICAgICAgICAgaGVpZ2h0ID0gNDAwMCkKYGBgCgoKIyBMaXZlciB0aXNzdWUsIDkqQyB2LiAwKkMKClRoZSA5XCpDIHRlbXBlcmF0dXJlIHRyZWF0bWVudCBpcyBlZmZlY3RpdmVseSBvdXIgImNvbnRyb2wsIiBhcyBpdCByZXByZXNlbnRzIHRoZSBhbWJpZW50IHRlbXBlcmF0dXJlIHRoYXQgd2lsZCBqdXZlbmlsZSBQYWNpZmljIGNvZCB3b3VsZCBleHBlcmllbmNlLgoKYGBge3J9CiMgbGl2ZXIgdGlzc3VlLCB0ZW1wZXJhdHVyZXMgOSB2cy4gMCAKCiMgRmlsdGVyIGRhdGEKaW5mb3N1Yl9MLjkuMCA8LSBjb2Rfc2FtcGxlX2luZm8gJT4lIGZpbHRlcih0aXNzdWVfdHlwZSA9PSAiTGl2ZXIiICYgKHRlbXBfdHJlYXRtZW50ID09ICI5IiB8IHRlbXBfdHJlYXRtZW50ID09ICIwIikpCmNvdW50c3ViX0wuOS4wIDwtIHN1YnNldChjb2RfY291bnRzX2RhdGEsIHNlbGVjdD1yb3cubmFtZXMoaW5mb3N1Yl9MLjkuMCkpCgojIENhbGN1bGF0ZSBERVNlcSBvYmplY3QKZGRzX0wuOS4wIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzdWJfTC45LjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBpbmZvc3ViX0wuOS4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IHRlbXBfdHJlYXRtZW50KQoKZGRzX0wuOS4wIDwtIERFU2VxKGRkc19MLjkuMCkKcmVzdWx0c05hbWVzKGRkc19MLjkuMCkgIyBsaXN0cyB0aGUgY29lZmZpY2llbnRzCmBgYAoKYGBge3J9CnBsb3REaXNwRXN0cyhkZHNfTC45LjApCmBgYAoKYGBge3J9CiMgRmlsdGVyaW5nOiBrZWVwIGdlbmVzIHRoYXQgaGF2ZSBhdCBsZWFzdCAxMCBjb3VudHMgYWNyb3NzIDEvMyBvZiB0aGUgc2FtcGxlcyAtIGh0dHBzOi8vc3VwcG9ydC5iaW9jb25kdWN0b3Iub3JnL3AvMTEwMzA3LwprZWVwIDwtIHJvd1N1bXMoREVTZXEyOjpjb3VudHMoZGRzX0wuOS4wKSA+PSAxMCkgPj0gbmNvbChjb3VudHN1Yl9MLjkuMCkvMwpkZHNfTC45LjA8LSBkZHNfTC45LjBba2VlcCxdCgojIEdlbmVyYXRlIENvbnRyYXN0cwpjb250cmFzdF9saXN0X0wuOS4wICAgICAgICA8LSBjKCJ0ZW1wX3RyZWF0bWVudCIsICIwIiwgIjkiKSAjIG9yZGVyIGlzIGltcG9ydGFudDogZmFjdG9yLCB0cmVhdG1lbnQgZ3JvdXAsIGNvbnRyb2wKcmVzX3RhYmxlX0wuOS4wX25vc2hyaW5rIDwtIHJlc3VsdHMoZGRzX0wuOS4wLCBjb250cmFzdD1jb250cmFzdF9saXN0X0wuOS4wLCBhbHBoYSA9IDAuMDUpCgpyZXNfdGFibGVfTC45LjBfbm9ybSAgICAgPC0gbGZjU2hyaW5rKGRkc19MLjkuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZj0yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPSJub3JtYWwiKSAjIGxmY1RocmVzaG9sZCA9IDAuNTg1KSAgIyBhIGxmYyB0aHJlc2hvbGQgb2YgMSA9IDItZm9sZCBjaGFuZ2UsIDAuNTg1ID0gMS41LWZvbGQgY2hhbmdlCnJlc190YWJsZV9MLjkuMF9hcGVnbG0gICA8LSBsZmNTaHJpbmsoZGRzX0wuOS4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPSJhcGVnbG0iKSAjIGxmY1RocmVzaG9sZCA9IDAuNTg1KSAgIyBhIGxmYyB0aHJlc2hvbGQgb2YgMSA9IDItZm9sZCBjaGFuZ2UsIDAuNTg1ID0gMS41LWZvbGQgY2hhbmdlCnJlc190YWJsZV9MLjkuMF9hc2hyICAgICA8LSBsZmNTaHJpbmsoZGRzX0wuOS4wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPSJhc2hyIikKYGBgCgpgYGB7cn0KIyBHZW5lcmF0ZSBNQSBwbG90cwpwYXIobWZyb3c9YygyLDIpLCBtYXI9Yyg0LDQsMiwxKSkKeGxpbSA8LSBjKDEsMWU1KTsgeWxpbSA8LSBjKC00LDQpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMF9ub3NocmluaywgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49Im5vIHNocmluayIpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMF9ub3JtLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0ibm9ybWFsIikKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS4wX2FwZWdsbSwgeGxpbT14bGltLCB5bGltPXlsaW0sIG1haW49ImFwZWdsbSIpCkRFU2VxMjo6cGxvdE1BKHJlc190YWJsZV9MLjkuMF9hc2hyLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0iYXNociIpCmBgYAoKYGBge3J9CiMgRXhhbWluZSByZXN1bHRzIGZvcm1hdHRpbmcKcmVzX3RhYmxlX0wuOS4wX25vcm0gJT4lIGRhdGEuZnJhbWUoKSAlPiUgaGVhZCgpCmBgYAoKTm90ZSB0aGF0IHRoZSBtZXRyaWMgd2Ugd2FudCB0byB1c2UgdG8gaWRlbnRpZnkgc2lnbmlmaWNhbnRseSBleHByZXNzZWQgZ2VuZXMgaXMgdGhlIGBwYWRqYCB2YWx1ZXMsICoqTk9UKiogdGhlIGBwdmFsdWVgLiBgcGFkamAgYXJlIHAtdmFsdWVzIGNvcnJlY3RlZCBmb3IgbXVsdGlwbGUgdGVzdGluZyAoZGVmYXVsdCBtZXRob2QgaXMgdGhlIEJlbmphbWluaSBhbmQgSG9jaGJlcmcgbWV0aG9kKS4KCmBgYHtyfQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuMF9ub3NocmluaykKc3VtbWFyeShyZXNfdGFibGVfTC45LjBfbm9ybSkKc3VtbWFyeShyZXNfdGFibGVfTC45LjBfYXBlZ2xtKQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuMF9hc2hyKQpgYGAKCiMgRXh0cmFjdGluZyBzaWduaWZpY2FudGx5IGV4cHJlc3NlZCBnZW5lcwoKYGBge3J9CnBhZGouY3V0b2ZmIDwtIDAuMDUKbGZjLmN1dG9mZiA8LSAwLjU4CgojIENvbnZlcnQgcmVzdWx0cyB0YWJsZSBpbnRvIHRpYmJsZQpyZXNfdGFibGVfTC45LjBfbm9ybV90YiA8LSByZXNfdGFibGVfTC45LjBfbm9ybSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhcj0iZ2VuZSIpICU+JQogIGFzX3RpYmJsZSgpCgojIHN1YnNldCB0aGF0IHRhYmxlIHRvIG9ubHkga2VlcCB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgdXNpbmcgb3VyIHByZS1kZWZpbmVkIHRocmVzaG9sZHM6CnNpZ19MLjkuMF9ub3JtIDwtIHJlc190YWJsZV9MLjkuMF9ub3JtX3RiICU+JQogICAgICAgIGZpbHRlcihwYWRqIDwgcGFkai5jdXRvZmYgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID4gbGZjLmN1dG9mZikKCmhlYWQoc2lnX0wuOS4wX25vcm0pCnBhc3RlKCJOdW1iZXIgb2Ygc2lnbmlmaWNhbnQgREVHcyBmb3IgOUMgdiAwQzoiLCBucm93KHNpZ19MLjkuMF9ub3JtKSwgIihwYWRqPCIsIHBhZGouY3V0b2ZmLCAiLCBsb2ctZm9sZCBjaGFuZ2UgPiIsIGxmYy5jdXRvZmYsICIpIikKCndyaXRlLnRhYmxlKHNpZ19MLjkuMF9ub3JtLCBmaWxlID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9HbWFjX0RFR3Nfc2lnX0wuOS4wX25vcm0udGFiIiwgc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSwgY29sLm5hbWVzID0gTkEpCmBgYAoKIyMgSGVhdG1hcAoKYGBge3J9CiMgUmV0cmlldmUgbm9ybWFsaXplZCBjb3VudHMgbWF0cml4CmRkc19MLjkuMF9ub3JtX2NvdW50cyA8LSBjb3VudHMoZGRzX0wuOS4wLCBub3JtYWxpemVkPVRSVUUpCgojIEV4dHJhY3Qgbm9ybWFsaXplZCBleHByZXNzaW9uIGZvciBzaWduaWZpY2FudCBnZW5lcwpub3JtX3NpZ19MLjkuMCA8LSBkZHNfTC45LjBfbm9ybV9jb3VudHMgJT4lIAogIGRhdGEuZnJhbWUoKSAlPiUKICBmaWx0ZXIocm93Lm5hbWVzKGRkc19MLjkuMF9ub3JtX2NvdW50cykgJWluJSBzaWdfTC45LjBfbm9ybSRnZW5lKQoKaGVhZChub3JtX3NpZ19MLjkuMCkKCiMgQW5ub3RhdGUgaGVhdG1hcAphbm5vdGF0aW9uIDwtIGluZm9zdWJfTC45LjAgJT4lIAoJc2VsZWN0KHRlbXBfdHJlYXRtZW50KQoKIyBTZXQgYSBjb2xvciBwYWxldHRlCmhlYXRfY29sb3JzIDwtIHJldihicmV3ZXIucGFsKDEyLCAiUmRZbEJ1IikpCgojIFJ1biBwaGVhdG1hcApoLkwuOS4wIDwtIHBoZWF0bWFwKG5vcm1fc2lnX0wuOS4wLCAKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgCiAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsIAogICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbiA9IGFubm90YXRpb24sIAogICAgICAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsIAogICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDMwLAogICAgICAgICAgICAgICAgICAgICBtYWluID0gIk5vcm1hbGl6ZWQgU2lnbmlmaWNhbnQgRXhwcmVzc2lvbiwgTGl2ZXIsIDkqQyBhbmQgMCpDIikKCiMgU2F2ZSBwbG90CmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8wNy1jb2QtUk5Bc2VxLURFU2VxMi9oZWF0bWFwX0wuOS4wX25vcm1fc2lnLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGguTC45LjAsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgpOb3RlIHRoZSBhcmd1bWVudCBgc2NhbGU9InJvdyJgIHdhcyBpbmNsdWRlZCwgc28gdGhlIHZhbHVlcyBwbG90dGVkIGluIHRoZSBoZWF0IG1hcCBhcmUgKlotc2NvcmVzKiwgcmF0aGVyIHRobiB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZS4gVGhpcyB2YXN0bHkgaW1wcm92ZXMgdGhlIGNvbG9yIHZpc3VhbGl6YXRpb24uCgojIyBWb2xjYW5vIHBsb3QKCmBgYHtyfQojIEdlbmVyYXRlIHBsb3QKdi5MLjkuMCA8LSAKICBnZ3Bsb3QocmVzX3RhYmxlX0wuOS4wX25vcm1fdGIpICsKICAjIFBsb3QgYWxsCiAgZ2VvbV9wb2ludChhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksY29sb3I9InVuY2hhbmdlZCIpLAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogICMgT3ZlcmxheSBhbGwgc2lnbmlmaWNhbnRseSB1cHJlZ3VsYXRlZCBpbiByZWQKICBnZW9tX3BvaW50KGRhdGEgPSBzaWdfTC45LjBfbm9ybVtzaWdfTC45LjBfbm9ybSRsb2cyRm9sZENoYW5nZSA+IDAsIF0sIAogICAgICAgICAgICAgYWVzKHg9bG9nMkZvbGRDaGFuZ2UsIHk9LWxvZzEwKHBhZGopLCBjb2xvcj0idXByZWd1bGF0ZWQiKSwgCiAgICAgICAgICAgICBzaXplPS41KSArCiAgIyBPdmVybGF5IGFsbCBzaWduaWZpY2FudGx5IGRvd25yZWd1bGF0ZWQgaW4gYmx1ZQogIGdlb21fcG9pbnQoZGF0YSA9IHNpZ19MLjkuMF9ub3JtW3NpZ19MLjkuMF9ub3JtJGxvZzJGb2xkQ2hhbmdlIDwgMCwgXSwgCiAgICAgICAgICAgICBhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksIGNvbG9yPSJkb3ducmVndWxhdGVkIiksIAogICAgICAgICAgICAgc2l6ZT0uNSkgKwogIGdndGl0bGUoIkxpdmVyLCA5KkMgYW5kIDAqQyIpICsKICB4bGFiKCJsb2cyIGZvbGQgY2hhbmdlIikgKyAKICB5bGFiKCItbG9nMTAgYWRqdXN0ZWQgcC12YWx1ZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtNCw0KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMzApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInVuY2hhbmdlZCIgPSAiZGFya2dyZXkiLCAidXByZWd1bGF0ZWQiID0gInJlZCIsICJkb3ducmVndWxhdGVkIiA9ICJibHVlIiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInVuY2hhbmdlZCIgPSAiVW5jaGFuZ2VkIiwgInVwcmVndWxhdGVkIiA9ICJVcHJlZ3VsYXRlZCIsICJkb3ducmVndWxhdGVkIiA9ICJEb3ducmVndWxhdGVkIiksCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBOVUxMKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuNSksIGhqdXN0ID0gMC41KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yNSkpKQoKdi5MLjkuMAoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL3ZvbGNhbm9fTC45LjAucG5nIiwKICAgICAgICAgcGxvdCAgID0gdi5MLjkuMCwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA2MDAwLAogICAgICAgICBoZWlnaHQgPSA0MDAwKQpgYGAKCgojIExpdmVyIHRpc3N1ZSwgOSpDIHYuIDUqQwoKVGhlIDlcKkMgdGVtcGVyYXR1cmUgdHJlYXRtZW50IGlzIGVmZmVjdGl2ZWx5IG91ciAiY29udHJvbCwiIGFzIGl0IHJlcHJlc2VudHMgdGhlIGFtYmllbnQgdGVtcGVyYXR1cmUgdGhhdCB3aWxkIGp1dmVuaWxlIFBhY2lmaWMgY29kIHdvdWxkIGV4cGVyaWVuY2UuCgpgYGB7cn0KIyBsaXZlciB0aXNzdWUsIHRlbXBlcmF0dXJlcyA5IHZzLiA1IAoKIyBGaWx0ZXIgZGF0YQppbmZvc3ViX0wuOS41IDwtIGNvZF9zYW1wbGVfaW5mbyAlPiUgZmlsdGVyKHRpc3N1ZV90eXBlID09ICJMaXZlciIgJiAodGVtcF90cmVhdG1lbnQgPT0gIjkiIHwgdGVtcF90cmVhdG1lbnQgPT0gIjUiKSkKY291bnRzdWJfTC45LjUgPC0gc3Vic2V0KGNvZF9jb3VudHNfZGF0YSwgc2VsZWN0PXJvdy5uYW1lcyhpbmZvc3ViX0wuOS41KSkKCiMgQ2FsY3VsYXRlIERFU2VxIG9iamVjdApkZHNfTC45LjUgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHN1Yl9MLjkuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGluZm9zdWJfTC45LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gdGVtcF90cmVhdG1lbnQpCgpkZHNfTC45LjUgPC0gREVTZXEoZGRzX0wuOS41KQpyZXN1bHRzTmFtZXMoZGRzX0wuOS41KSAjIGxpc3RzIHRoZSBjb2VmZmljaWVudHMKYGBgCgpgYGB7cn0KcGxvdERpc3BFc3RzKGRkc19MLjkuNSkKYGBgCgpgYGB7cn0KIyBGaWx0ZXJpbmc6IGtlZXAgZ2VuZXMgdGhhdCBoYXZlIGF0IGxlYXN0IDEwIGNvdW50cyBhY3Jvc3MgMS8zIG9mIHRoZSBzYW1wbGVzIC0gaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC8xMTAzMDcvCmtlZXAgPC0gcm93U3VtcyhERVNlcTI6OmNvdW50cyhkZHNfTC45LjUpID49IDEwKSA+PSBuY29sKGNvdW50c3ViX0wuOS41KS8zCmRkc19MLjkuNTwtIGRkc19MLjkuNVtrZWVwLF0KCiMgR2VuZXJhdGUgQ29udHJhc3RzCmNvbnRyYXN0X2xpc3RfTC45LjUgICAgICAgIDwtIGMoInRlbXBfdHJlYXRtZW50IiwgIjUiLCAiOSIpICMgb3JkZXIgaXMgaW1wb3J0YW50OiBmYWN0b3IsIHRyZWF0bWVudCBncm91cCwgY29udHJvbApyZXNfdGFibGVfTC45LjVfbm9zaHJpbmsgPC0gcmVzdWx0cyhkZHNfTC45LjUsIGNvbnRyYXN0PWNvbnRyYXN0X2xpc3RfTC45LjUsIGFscGhhID0gMC4wNSkKCnJlc190YWJsZV9MLjkuNV9ub3JtICAgICA8LSBsZmNTaHJpbmsoZGRzX0wuOS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9Im5vcm1hbCIpICMgbGZjVGhyZXNob2xkID0gMC41ODUpICAjIGEgbGZjIHRocmVzaG9sZCBvZiAxID0gMi1mb2xkIGNoYW5nZSwgMC41ODUgPSAxLjUtZm9sZCBjaGFuZ2UKcmVzX3RhYmxlX0wuOS41X2FwZWdsbSAgIDwtIGxmY1NocmluayhkZHNfTC45LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9ImFwZWdsbSIpICMgbGZjVGhyZXNob2xkID0gMC41ODUpICAjIGEgbGZjIHRocmVzaG9sZCBvZiAxID0gMi1mb2xkIGNoYW5nZSwgMC41ODUgPSAxLjUtZm9sZCBjaGFuZ2UKcmVzX3RhYmxlX0wuOS41X2FzaHIgICAgIDwtIGxmY1NocmluayhkZHNfTC45LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWY9MiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9ImFzaHIiKQpgYGAKCmBgYHtyfQojIEdlbmVyYXRlIE1BIHBsb3RzCnBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDQsNCwyLDEpKQp4bGltIDwtIGMoMSwxZTUpOyB5bGltIDwtIGMoLTQsNCkKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS41X25vc2hyaW5rLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0ibm8gc2hyaW5rIikKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS41X25vcm0sIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJub3JtYWwiKQpERVNlcTI6OnBsb3RNQShyZXNfdGFibGVfTC45LjVfYXBlZ2xtLCB4bGltPXhsaW0sIHlsaW09eWxpbSwgbWFpbj0iYXBlZ2xtIikKREVTZXEyOjpwbG90TUEocmVzX3RhYmxlX0wuOS41X2FzaHIsIHhsaW09eGxpbSwgeWxpbT15bGltLCBtYWluPSJhc2hyIikKYGBgCgpgYGB7cn0KIyBFeGFtaW5lIHJlc3VsdHMgZm9ybWF0dGluZwpyZXNfdGFibGVfTC45LjVfbm9ybSAlPiUgZGF0YS5mcmFtZSgpICU+JSBoZWFkKCkKYGBgCgpOb3RlIHRoYXQgdGhlIG1ldHJpYyB3ZSB3YW50IHRvIHVzZSB0byBpZGVudGlmeSBzaWduaWZpY2FudGx5IGV4cHJlc3NlZCBnZW5lcyBpcyB0aGUgYHBhZGpgIHZhbHVlcywgKipOT1QqKiB0aGUgYHB2YWx1ZWAuIGBwYWRqYCBhcmUgcC12YWx1ZXMgY29ycmVjdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nIChkZWZhdWx0IG1ldGhvZCBpcyB0aGUgQmVuamFtaW5pIGFuZCBIb2NoYmVyZyBtZXRob2QpLgoKYGBge3J9CnN1bW1hcnkocmVzX3RhYmxlX0wuOS41X25vc2hyaW5rKQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuNV9ub3JtKQpzdW1tYXJ5KHJlc190YWJsZV9MLjkuNV9hcGVnbG0pCnN1bW1hcnkocmVzX3RhYmxlX0wuOS41X2FzaHIpCmBgYAoKIyBFeHRyYWN0aW5nIHNpZ25pZmljYW50bHkgZXhwcmVzc2VkIGdlbmVzCgpgYGB7cn0KcGFkai5jdXRvZmYgPC0gMC4wNQpsZmMuY3V0b2ZmIDwtIDAuNTgKCiMgQ29udmVydCByZXN1bHRzIHRhYmxlIGludG8gdGliYmxlCnJlc190YWJsZV9MLjkuNV9ub3JtX3RiIDwtIHJlc190YWJsZV9MLjkuNV9ub3JtICU+JQogIGRhdGEuZnJhbWUoKSAlPiUKICByb3duYW1lc190b19jb2x1bW4odmFyPSJnZW5lIikgJT4lCiAgYXNfdGliYmxlKCkKCiMgc3Vic2V0IHRoYXQgdGFibGUgdG8gb25seSBrZWVwIHRoZSBzaWduaWZpY2FudCBnZW5lcyB1c2luZyBvdXIgcHJlLWRlZmluZWQgdGhyZXNob2xkczoKc2lnX0wuOS41X25vcm0gPC0gcmVzX3RhYmxlX0wuOS41X25vcm1fdGIgJT4lCiAgICAgICAgZmlsdGVyKHBhZGogPCBwYWRqLmN1dG9mZiAmIGFicyhsb2cyRm9sZENoYW5nZSkgPiBsZmMuY3V0b2ZmKQoKaGVhZChzaWdfTC45LjVfbm9ybSkKcGFzdGUoIk51bWJlciBvZiBzaWduaWZpY2FudCBERUdzIGZvciA5QyB2IDVDOiIsIG5yb3coc2lnX0wuOS41X25vcm0pLCAiKHBhZGo8IiwgcGFkai5jdXRvZmYsICIsIGxvZy1mb2xkIGNoYW5nZSA+IiwgbGZjLmN1dG9mZiwgIikiKQoKd3JpdGUudGFibGUoc2lnX0wuOS41X25vcm0sIGZpbGUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL0dtYWNfREVHc19zaWdfTC45LjVfbm9ybS50YWIiLCBzZXAgPSAiXHQiLAogICAgICAgICAgICByb3cubmFtZXMgPSBUUlVFLCBjb2wubmFtZXMgPSBOQSkKYGBgCgojIyBIZWF0bWFwCgpgYGB7cn0KIyBSZXRyaWV2ZSBub3JtYWxpemVkIGNvdW50cyBtYXRyaXgKZGRzX0wuOS41X25vcm1fY291bnRzIDwtIGNvdW50cyhkZHNfTC45LjUsIG5vcm1hbGl6ZWQ9VFJVRSkKCiMgRXh0cmFjdCBub3JtYWxpemVkIGV4cHJlc3Npb24gZm9yIHNpZ25pZmljYW50IGdlbmVzCm5vcm1fc2lnX0wuOS41IDwtIGRkc19MLjkuNV9ub3JtX2NvdW50cyAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JQogIGZpbHRlcihyb3cubmFtZXMoZGRzX0wuOS41X25vcm1fY291bnRzKSAlaW4lIHNpZ19MLjkuNV9ub3JtJGdlbmUpCgpoZWFkKG5vcm1fc2lnX0wuOS41KQoKIyBBbm5vdGF0ZSBoZWF0bWFwCmFubm90YXRpb24gPC0gaW5mb3N1Yl9MLjkuNSAlPiUgCglzZWxlY3QodGVtcF90cmVhdG1lbnQpCgojIFNldCBhIGNvbG9yIHBhbGV0dGUKaGVhdF9jb2xvcnMgPC0gcmV2KGJyZXdlci5wYWwoMTIsICJSZFlsQnUiKSkKCiMgUnVuIHBoZWF0bWFwCmguTC45LjUgPC0gcGhlYXRtYXAobm9ybV9zaWdfTC45LjUsIAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGhlYXRfY29sb3JzLCAKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwgCiAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uID0gYW5ub3RhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgIGJvcmRlcl9jb2xvciA9IE5BLCAKICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSAicm93IiwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDEwLCAKICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMzAsCiAgICAgICAgICAgICAgICAgICAgIG1haW4gPSAiTm9ybWFsaXplZCBTaWduaWZpY2FudCBFeHByZXNzaW9uLCBMaXZlciwgOSpDIGFuZCA1KkMiKQoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzA3LWNvZC1STkFzZXEtREVTZXEyL2hlYXRtYXBfTC45LjVfbm9ybV9zaWcucG5nIiwKICAgICAgICAgcGxvdCAgID0gaC5MLjkuNSwKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA1MDAwLAogICAgICAgICBoZWlnaHQgPSA1MDAwKQpgYGAKCk5vdGUgdGhlIGFyZ3VtZW50IGBzY2FsZT0icm93ImAgd2FzIGluY2x1ZGVkLCBzbyB0aGUgdmFsdWVzIHBsb3R0ZWQgaW4gdGhlIGhlYXQgbWFwIGFyZSAqWi1zY29yZXMqLCByYXRoZXIgdGhuIHRoZSBub3JtYWxpemVkIGNvdW50IHZhbHVlLiBUaGlzIHZhc3RseSBpbXByb3ZlcyB0aGUgY29sb3IgdmlzdWFsaXphdGlvbi4KCiMjIFZvbGNhbm8gcGxvdAoKYGBge3J9CiMgR2VuZXJhdGUgcGxvdAp2LkwuOS41IDwtIAogIGdncGxvdChyZXNfdGFibGVfTC45LjVfbm9ybV90YikgKwogICMgUGxvdCBhbGwKICBnZW9tX3BvaW50KGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwYWRqKSxjb2xvcj0idW5jaGFuZ2VkIiksCiAgICAgICAgICAgICBzaXplPS41KSArCiAgIyBPdmVybGF5IGFsbCBzaWduaWZpY2FudGx5IHVwcmVndWxhdGVkIGluIHJlZAogIGdlb21fcG9pbnQoZGF0YSA9IHNpZ19MLjkuNV9ub3JtW3NpZ19MLjkuNV9ub3JtJGxvZzJGb2xkQ2hhbmdlID4gMCwgXSwgCiAgICAgICAgICAgICBhZXMoeD1sb2cyRm9sZENoYW5nZSwgeT0tbG9nMTAocGFkaiksIGNvbG9yPSJ1cHJlZ3VsYXRlZCIpLCAKICAgICAgICAgICAgIHNpemU9LjUpICsKICAjIE92ZXJsYXkgYWxsIHNpZ25pZmljYW50bHkgZG93bnJlZ3VsYXRlZCBpbiBibHVlCiAgZ2VvbV9wb2ludChkYXRhID0gc2lnX0wuOS41X25vcm1bc2lnX0wuOS41X25vcm0kbG9nMkZvbGRDaGFuZ2UgPCAwLCBdLCAKICAgICAgICAgICAgIGFlcyh4PWxvZzJGb2xkQ2hhbmdlLCB5PS1sb2cxMChwYWRqKSwgY29sb3I9ImRvd25yZWd1bGF0ZWQiKSwgCiAgICAgICAgICAgICBzaXplPS41KSArCiAgZ2d0aXRsZSgiTGl2ZXIsIDkqQyBhbmQgMCpDIikgKwogIHhsYWIoImxvZzIgZm9sZCBjaGFuZ2UiKSArIAogIHlsYWIoIi1sb2cxMCBhZGp1c3RlZCBwLXZhbHVlIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC00LDQpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwzMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygidW5jaGFuZ2VkIiA9ICJkYXJrZ3JleSIsICJ1cHJlZ3VsYXRlZCIgPSAicmVkIiwgImRvd25yZWd1bGF0ZWQiID0gImJsdWUiKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygidW5jaGFuZ2VkIiA9ICJVbmNoYW5nZWQiLCAidXByZWd1bGF0ZWQiID0gIlVwcmVndWxhdGVkIiwgImRvd25yZWd1bGF0ZWQiID0gIkRvd25yZWd1bGF0ZWQiKSwKICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IE5VTEwpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS41KSwgaGp1c3QgPSAwLjUpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjI1KSkpCgp2LkwuOS41CgojIFNhdmUgcGxvdApnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMDctY29kLVJOQXNlcS1ERVNlcTIvdm9sY2Fub19MLjkuNS5wbmciLAogICAgICAgICBwbG90ICAgPSB2LkwuOS4wLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDYwMDAsCiAgICAgICAgIGhlaWdodCA9IDQwMDApCmBgYAo=