library(tidyverse)
library(here)
library(ropls)
library(cowplot)
library(vegan)
library(broom)
library(readxl)
library(chemhelper) #install with devtools::install_github("Aariq/chemhelper")
library(latex2exp)
options(scipen = 999)

Create some helper functions

#create a "not in" function
#useful for filtering out outliers
`%!in%` <- Negate(`%in%`)
#detect if a column has at least one non-zero value.  Probably other ways to do this.
not_empty <- function(x) !is.double(x) || is.double(x) && sum(x) != 0
#function to select columns that are NOT double, i.e. integer, factor, and character
not_double <- function(x) !is.double(x)

Read in Data

# After fixing some mistakes in the Ion Analytics methods file, the FINAL output.
gc_zeroes_long.1 <- read_rds(here("cleaned_data", "GCMS_tidy_zeroes.rds"))
gc_log.1 <- read_rds(here("cleaned_data", "GCMS_wide_loged.rds"))

PCA

PCA shows the best separation by herbivory treatment in the 100%, ambient rainfall treatment. There is no obvious separation other than that. This indicates that plants responded to MeJA spray, but only in the 100% rainfall treatment.

gc_pca <- opls(select_if(gc_log.1, is.double), plotL = FALSE, scaleC = "standard")
PCA
45 samples x 128 variables
standard scaling of predictors
plot(gc_pca, parLabVc = gc_log.1$sample, parAsColFcVn = paste0(gc_log.1$Treatment, gc_log.1$Spray))
Character 'parAsColFcVn' set to a factor

Prettier plot

Extract scores

gc_pca_scores <- gc_pca %>% getScoreMN() %>% as.data.frame()
gc_pca_scores <- bind_cols(select_if(gc_log.1, not_double), gc_pca_scores)
gc_pca_scores <- gc_pca_scores %>% mutate(treatcombo = paste(Treatment, Spray))

Build Plot

build the base plot

# calculate data for convex hulls
hulldata<- hullfn(gc_pca_scores, "p1", "p2", "treatcombo") #in chemhelper
# set shapes and colors
trtcols <- c("100%" = "blue", "75%" = "darkgreen", "50%" = "darkorange3")
sprayshapes <- c("MeJA" = 17, "Control" = 20)
gc_pca.plot <- ggplot(gc_pca_scores, aes(x = p1, y = p2,shape = Spray, color = Treatment)) +
  geom_point(size = 2) +
  stat_ellipse(aes(group = Treatment:Spray, linetype = Spray), type = "t") + # Hotelling T^2 distribution
  # Uncomment to see convex hulls.  Pattern is less obvious because the outlines all overlap.
  #geom_polygon(data = hulldata, aes(linetype = Spray, fill = Treatment), alpha = 0.3) +
  scale_linetype_manual(values = c(1, 2), name = NULL) +
  scale_shape_manual(values = sprayshapes, name = "Simulated Herbivory") +
  scale_color_manual(values = trtcols, name = "% Ambient Rainfall") +
  guides(color = guide_legend(override.aes = list(shape = 15, size = 4, linetype = 0))) +
  xlab(paste0("PC1 (", signif(gc_pca@modelDF$R2X[1]*100, digits = 2), "%)")) +
  ylab(paste0("PC2 (", signif(gc_pca@modelDF$R2X[2]*100, digits = 2), "%)")) +
  theme(axis.title = element_text(size = 10),
        axis.text = element_text(size = 9)) +
  theme_bw()
# gc_pca.plot

Add custom legend

base <- gc_pca.plot + theme(legend.position = "none") #suppress legend
# Create some dummy data for legend
legend.df <- data.frame(x = c(10, 10), y = c(85, 80), label = c("MeJA", "Control"))
legend.df2 <- data.frame(x = c(10, 10, 10), y = c(65, 60, 55), label = c("100%", "75%", "50%"))
legend <- ggplot(legend.df) +
  xlim(0,100) +
  ylim(0,100) +
  theme_nothing() + #comment this line out to get a better idea of what is happening
  # Simulated herbivory legend
  geom_text(aes(x = 10, y = 90, label = "Simulated Herbivory"), #title
            hjust = "left",
            size = 3.5,
            data = data.frame(), inherit.aes = FALSE) +
  geom_text(aes(x = x, y = y, label = label), #labels
            hjust = "inward", nudge_x = 11,
            size = 3.0,
            data = legend.df, inherit.aes = FALSE) + 
  geom_point(aes(x = x, y = y, shape = label), #shapes
             position = position_nudge(x = 8),
             data = legend.df, inherit.aes = FALSE) +
  geom_segment(aes(x = x, y = y, xend = x + 5, yend = y, linetype = label), #ellipse lines
               position = position_nudge(x = 1),
            data = legend.df, inherit.aes = FALSE) +
  scale_shape_manual(values = sprayshapes) +
  scale_linetype_manual(values = c(2, 1)) +
  
  # Drought treatment legend
  geom_text(aes(x = 10, y = 70, label = "% Ambient Rainfall"), #title
            hjust = "left",
            size = 3.5,
            data = data.frame(),
            inherit.aes = FALSE) +
  geom_text(aes(x = x, y = y, label = label), #labels
            hjust = "inward",
            nudge_x = 5,
            size = 3,
            data = legend.df2, inherit.aes = FALSE) +
  geom_point(aes(x = x, y = y, color = label), #color swatches
             position = position_nudge(x = 2.3),
             shape = 15,
             size = 3.5,
             data = legend.df2, inherit.aes = FALSE) +
  scale_color_manual(values = trtcols)
legend

gc_pca.plot2 <- base + draw_plot(legend, -8, 5.8, width = 1, height = 1, scale = 28)
gc_pca.plot2
save_plot(here("figs", "GCMS PCA.png"), gc_pca.plot2, base_aspect_ratio = 1.3, base_height = 5)

PERMANOVA

PERMANOVA confirms what is seen in the PCA. There is a significant main effect of MeJA treatment on volatile profile and a significant interaction between drought treatment and MeJA treatment.

Scale Data

None of the vegan functions support scaling with and argument. I need to scale the data ahead of time.

gc_log_scale <- gc_log.1 %>% mutate_if(is.double, ~chem_scale(.,center = TRUE, scale = "auto"))

Test Assumptions

PERMANOVA assumes homogneity of variances in multivariate space.

#multivariate analog of Levene's Test for homogeneity of variances--an assumption of PERMANOVA
PERMDIST <- betadisper(vegdist(select_if(gc_log_scale, is.double), method = "eu"), group = paste(gc_log_scale$Treatment, gc_log_scale$Spray), type = "centroid")
#plot(PERMDIST)
#PERMDIST
anova(PERMDIST)
Analysis of Variance Table

Response: Distances
          Df Sum Sq Mean Sq F value Pr(>F)
Groups     5  15.96  3.1921  0.4863 0.7843
Residuals 39 255.97  6.5635               
#meets the assumption of homogeneity of dispersion if p > 0.05

Run Test

adonis(select_if(gc_log_scale, is.double) ~ Treatment*Spray,
        method = "euclidean",
        by = "terms",
        data = gc_log_scale)

Call:
adonis(formula = select_if(gc_log_scale, is.double) ~ Treatment *      Spray, data = gc_log_scale, method = "euclidean", by = "terms") 

Permutation: free
Number of permutations: 999

Terms added sequentially (first to last)

                Df SumsOfSqs MeanSqs F.Model      R2 Pr(>F)    
Treatment        2     241.1  120.54  1.0042 0.04280  0.440    
Spray            1     391.9  391.86  3.2648 0.06958  0.001 ***
Treatment:Spray  2     317.9  158.97  1.3245 0.05645  0.061 .  
Residuals       39    4681.1  120.03         0.83116           
Total           44    5632.0                 1.00000           
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Spray and interaction are significant, matching what is seen in the PCA

Try pairwise post-hoc PERMANOVAS

library(pairwiseAdonis)
Loading required package: cluster
pairwise.adonis(select_if(gc_log_scale, is.double), factors = gc_log_scale$Treatment:gc_log_scale$Spray,
                sim.method = "euclidean",
                p.adjust.m = "none") %>% 
  filter(pairs %in% c("50%:MeJA vs 50%:Control", "75%:Control vs 75%:MeJA", "100%:MeJA vs 100%:Control")) %>% 
  mutate(p.adjusted = p.adjust(p.value, "fdr"))

PLS-DA

I can also try to use PLS-DA to confirm that there is an effect of MeJA, no main effect of drought, and an interaction between MeJA and drought treatment.

PLS-DA on Effect of MeJA Spray

There is significant separation of volatile profiles by MeJA spray. Q2 and R2 are both high and similar to eachother, and p < 0.05.

gc_plsda_spray <- opls(select_if(gc_log.1, is.double), gc_log.1$Spray,
                       permI = 1000,
                       scaleC = "standard",
                       plotL = FALSE)
PLS-DA
45 samples x 128 variables and 1 response
standard scaling of predictors and response(s)
# plot(gc_plsda_spray)

Plot

gc_plsda_sprayPD <- get_plotdata(gc_plsda_spray)
Joining, by = "sample"
ggplot(gc_plsda_sprayPD$plot_data, aes(x = p1, y = p2, shape = y1, color = gc_log.1$Treatment)) +
  stat_ellipse(aes(x = p1, y = p2, linetype = y1), inherit.aes = FALSE) +
  geom_point(size = 2.5) +
  labs(x = paste0("P1 (", gc_plsda_sprayPD$axis_stats$R2X[1]*100, "%)"),
       y = paste0("P2 (", gc_plsda_sprayPD$axis_stats$R2X[2]*100, "%)")) +
  ggtitle("PLS-DA on full data set",
          subtitle = paste0("R^2 = ", gc_plsda_sprayPD$model_stats$`R2Y(cum)`,
                            "  Q^2 = ", gc_plsda_sprayPD$model_stats$`Q2(cum)`,
                            "  p(Q^2) = ", gc_plsda_sprayPD$model_stats$pQ2)) +
  scale_shape_manual("Simulated\nHerbivory", values = sprayshapes) +
  scale_linetype("Simulated\nHerbivory") +
  scale_color_manual("% Ambient\nRainfall", values = trtcols) +
  theme_bw()

get_VIP(gc_plsda_spray) %>% #from chemhelper
  rename(Compound = "Variable") %>% 
  arrange(desc(VIP)) %>% 
  filter(VIP > 1)

PLS-DA on Effect of Drought Treatment

There is no significant separation by drought treatment (no model is built because first component is not significant).

gc_plsda_drought <- try(
  opls(select_if(gc_log.1, is.double), gc_log.1$Treatment,
                       permI = 100,
                       scaleC = "standard",
                       plotL = FALSE)
)
Error : No model was built because the first predictive component was already not significant;
Select a number of predictive components of 1 if you want the algorithm to compute a model despite this.

PLS-DA on Combined Drought and MeJA

There is no significant separation when using all 6 groups (every drought x MeJA combination). A single-component model is built, but the R2 and Q2 are extremely low, so there is essentially no predictive or explanatory power of the model.

gc_plsda_combo <- try(
  opls(select_if(gc_log.1, is.double), paste(gc_log.1$Treatment, gc_log.1$Spray),
                       permI = 100,
                       scaleC = "standard",
                       plotL = FALSE)
)
PLS-DA
45 samples x 128 variables and 1 response
standard scaling of predictors and response(s)

Table of high VIP Metabolites

Table 1 will be only the metabolites with VIP > 1, arranged by VIP from gc_plsda_spray showing mean RPA * 1000 for each treatment combination.

Extract VIPs

VIP_spray <- get_VIP(gc_plsda_spray) %>% rename(Compound = "Variable")

Calculate RI and summarise

Load in alkane data

alkanes <- read_csv(here("data", "GC alkanes.csv"))
Parsed with column specification:
cols(
  Compound = col_character(),
  `Actual RT` = col_double(),
  `Expected RT` = col_double(),
  RT = col_double(),
  C_num = col_integer()
)

Calculate mean RI

gc_ri <- gc_zeroes_long.1 %>%
  mutate(RI = map_dbl(RT, ~calc_RI(., alkanes$RT, alkanes$C_num))) %>% #calculate RI based on alkane file
  group_by(Compound) %>% 
  summarise(mean_RI = mean(RI, na.rm = TRUE)) #calculate mean RI for each compound

Summarise and spread

Add in ± SE here.

gc_summary <- gc_zeroes_long.1 %>%
  mutate(Combo = paste0(Treatment," rain, ", Spray) %>% # set up column headers
           fct_relevel("100% rain, Control",
                       "75% rain, Control",
                       "50% rain, Control",
                       "100% rain, MeJA",
                       "75% rain, MeJA",
                       "50% rain, MeJA")) %>% 
  group_by(Combo, Compound) %>% 
  summarise(mean_RPAx1000 = mean(RPA * 1000), # calculate mean RPA x 1000 (just to make it more readable)
            se_RPAx1000 = sd(RPA * 1000)/n()) %>% # calculate SEM
  mutate(`RPA ± SE` = ifelse(mean_RPAx1000 == 0, NA, # paste RPA ± SEM
                             paste0(round(mean_RPAx1000, 3), " ± ", round(se_RPAx1000, 2)))) %>% 
  select(-mean_RPAx1000, -se_RPAx1000) %>% 
  spread(key = Combo, value = `RPA ± SE`)

Join with VIP and RI

gc_table <- left_join(gc_summary, VIP_spray)
Joining, by = "Compound"
gc_table <- left_join(gc_table, gc_ri)
Joining, by = "Compound"
gc_table

Read in pretty names and join

annotations <- read_excel(here("data", "Compound annotation.xlsx"))
gc_table.1 <- left_join(gc_table,
          annotations %>%
            select(Compound, `Pretty Name`, LaTeX)) #start simple
Joining, by = "Compound"

Find and re-name unknowns by RI

Unknowns in the method are numbered based on some order they were found. Rename based on RI for publication.

gc_table.2 <- gc_table.1 %>% 
  mutate(unknown = str_detect(Compound, "^\\d+($| \\(DCSE\\)$)")) # unknowns are either all numbers or "<num> (DCSE)"
unknowns <- gc_table.2 %>% # extract just the unknowns and arrange by RI
  filter(unknown) %>%
  arrange(mean_RI) %>%
  add_column(unk_name = 1:nrow(.)) #add a column to give them new numbers
gc_table.3 <- right_join(unknowns, gc_table.2) %>%  #join back with original table
  mutate(`Pretty Name` = ifelse(unknown == TRUE, unk_name, `Pretty Name`)) #use the new numbers only for unknowns
Joining, by = c("Compound", "100% rain, Control", "75% rain, Control", "50% rain, Control", "100% rain, MeJA", "75% rain, MeJA", "50% rain, MeJA", "VIP", "mean_RI", "Pretty Name", "LaTeX", "unknown")
gc_table.3

Create tables with pretty names

#use pretty names
gc_table.4 <- gc_table.3 %>%
  mutate(Compound = ifelse(is.na(`Pretty Name`), Compound, `Pretty Name`)) %>% 
  select(-`Pretty Name`, -unknown, -unk_name) %>% 
  rename(RI = mean_RI) %>% 
  arrange(desc(VIP)) %>% 
  filter(VIP>1) %>% 
  select(Compound, RI, everything())
write_excel_csv(gc_table.4 %>% select(-LaTeX), here("figs", "Table 1.csv"), na = "-")

Supplementary table of all metabolites

# Create table of RIs
tableS1 <- gc_table.3 %>%
  select(-unknown, -unk_name, -VIP) %>% 
  rename(RI = mean_RI) %>% 
  arrange(RI)
# Read in CAS numbers and join
CASnums <- annotations %>% select(Compound, CAS)
tableS1 <- left_join(tableS1, CASnums)
# Read in reference standard data and join
referencestds <- read_csv(here("data", "Reference Standards.csv")) %>% 
  select(`Compound Name`, CAS, Vendor, `RI DB5`) %>%
  filter(!is.na(CAS))
tableS1 <- left_join(tableS1, referencestds)
# Read in literature RIs and join
master <- read_csv(here("data", "method_master RIs.csv"))
litRIs <- master %>% 
  select(Compound, CAS, RI_lit)
tableS1 <- left_join(tableS1, litRIs)
# Remove CAS numbers from unknowns (they were put by Ion Analytics)
tableS1 %>% filter(str_detect(`Pretty Name`, "^\\d+$"))
tableS1 <- tableS1 %>% 
  mutate(CAS = ifelse(str_detect(`Pretty Name`, "^\\d+$"), NA, CAS))
# Rename and select columns and write to .csv
tableS1 <- tableS1 %>% 
  select(Compound = `Pretty Name`, CAS, experimental_RI = RI, reference_RI = `RI DB5`, Vendor, literature_RI = RI_lit )
write_excel_csv(tableS1, here("figs", "Table S1.csv"), na = "-")

Checking compound identification status

tableS1 %>% filter(is.na(CAS)) %>% summarize(unknowns = n())
tableS1 %>% filter(!is.na(CAS)) %>% summarize(identified = n())
tableS1 %>% filter(!is.na(CAS), is.na(reference_RI)) %>% summarize(putative = n())
tableS1 %>% filter(!is.na(CAS), !is.na(reference_RI)) %>% summarize(reference = n())

Investigating Methyl Salicylate Response

gc_log.1 %>% 
  gather(-sample, -Treatment, -Spray, -Plot, -Plant, key = Compound, value = RPA) %>% 
  filter(Compound == "Methyl salicylate") %>% 
  ggplot(aes(x = Treatment, color = Spray, y = RPA)) +
  geom_jitter(width = 0.2) +
  labs(x = "Precipitation treatment", y = "log(RPA)")

gc_zeroes_long.1 %>% 
  filter(Compound == "Methyl salicylate") %>% 
  group_by(Treatment, Spray) %>% 
  summarize(detected = sum(RPA!=0))

Checking sample sizes

gc_log.1 %>% group_by(Spray) %>% 
  summarize(count = n())
LS0tCnRpdGxlOiAiR0MvTVMgQW5hbHlzaXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCgoKYGBge3IgcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocm9wbHMpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeSh2ZWdhbikKbGlicmFyeShicm9vbSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoY2hlbWhlbHBlcikgI2luc3RhbGwgd2l0aCBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIkFhcmlxL2NoZW1oZWxwZXIiKQpsaWJyYXJ5KGxhdGV4MmV4cCkKb3B0aW9ucyhzY2lwZW4gPSA5OTkpCmBgYAoKIyBDcmVhdGUgc29tZSBoZWxwZXIgZnVuY3Rpb25zCmBgYHtyIGhlbHBlci1mdW5jdGlvbnN9CiNjcmVhdGUgYSAibm90IGluIiBmdW5jdGlvbgojdXNlZnVsIGZvciBmaWx0ZXJpbmcgb3V0IG91dGxpZXJzCmAlIWluJWAgPC0gTmVnYXRlKGAlaW4lYCkKCiNkZXRlY3QgaWYgYSBjb2x1bW4gaGFzIGF0IGxlYXN0IG9uZSBub24temVybyB2YWx1ZS4gIFByb2JhYmx5IG90aGVyIHdheXMgdG8gZG8gdGhpcy4Kbm90X2VtcHR5IDwtIGZ1bmN0aW9uKHgpICFpcy5kb3VibGUoeCkgfHwgaXMuZG91YmxlKHgpICYmIHN1bSh4KSAhPSAwCgojZnVuY3Rpb24gdG8gc2VsZWN0IGNvbHVtbnMgdGhhdCBhcmUgTk9UIGRvdWJsZSwgaS5lLiBpbnRlZ2VyLCBmYWN0b3IsIGFuZCBjaGFyYWN0ZXIKbm90X2RvdWJsZSA8LSBmdW5jdGlvbih4KSAhaXMuZG91YmxlKHgpCmBgYAoKIyBSZWFkIGluIERhdGEKYGBge3J9CiMgQWZ0ZXIgZml4aW5nIHNvbWUgbWlzdGFrZXMgaW4gdGhlIElvbiBBbmFseXRpY3MgbWV0aG9kcyBmaWxlLCB0aGUgRklOQUwgb3V0cHV0LgpnY196ZXJvZXNfbG9uZy4xIDwtIHJlYWRfcmRzKGhlcmUoImNsZWFuZWRfZGF0YSIsICJHQ01TX3RpZHlfemVyb2VzLnJkcyIpKQpnY19sb2cuMSA8LSByZWFkX3JkcyhoZXJlKCJjbGVhbmVkX2RhdGEiLCAiR0NNU193aWRlX2xvZ2VkLnJkcyIpKQpgYGAKCiMgUENBClBDQSBzaG93cyB0aGUgYmVzdCBzZXBhcmF0aW9uIGJ5IGhlcmJpdm9yeSB0cmVhdG1lbnQgaW4gdGhlIDEwMCUsIGFtYmllbnQgcmFpbmZhbGwgdHJlYXRtZW50LiAgVGhlcmUgaXMgbm8gb2J2aW91cyBzZXBhcmF0aW9uIG90aGVyIHRoYW4gdGhhdC4gIFRoaXMgaW5kaWNhdGVzIHRoYXQgcGxhbnRzIHJlc3BvbmRlZCB0byBNZUpBIHNwcmF5LCBidXQgb25seSBpbiB0aGUgMTAwJSByYWluZmFsbCB0cmVhdG1lbnQuCmBgYHtyfQpnY19wY2EgPC0gb3BscyhzZWxlY3RfaWYoZ2NfbG9nLjEsIGlzLmRvdWJsZSksIHBsb3RMID0gRkFMU0UsIHNjYWxlQyA9ICJzdGFuZGFyZCIpCnBsb3QoZ2NfcGNhLCBwYXJMYWJWYyA9IGdjX2xvZy4xJHNhbXBsZSwgcGFyQXNDb2xGY1ZuID0gcGFzdGUwKGdjX2xvZy4xJFRyZWF0bWVudCwgZ2NfbG9nLjEkU3ByYXkpKQpgYGAKCiMjIFByZXR0aWVyIHBsb3QKIyMjIEV4dHJhY3Qgc2NvcmVzCmBgYHtyfQpnY19wY2Ffc2NvcmVzIDwtIGdjX3BjYSAlPiUgZ2V0U2NvcmVNTigpICU+JSBhcy5kYXRhLmZyYW1lKCkKZ2NfcGNhX3Njb3JlcyA8LSBiaW5kX2NvbHMoc2VsZWN0X2lmKGdjX2xvZy4xLCBub3RfZG91YmxlKSwgZ2NfcGNhX3Njb3JlcykKZ2NfcGNhX3Njb3JlcyA8LSBnY19wY2Ffc2NvcmVzICU+JSBtdXRhdGUodHJlYXRjb21ibyA9IHBhc3RlKFRyZWF0bWVudCwgU3ByYXkpKQpgYGAKIyMjIEJ1aWxkIFBsb3QKYnVpbGQgdGhlIGJhc2UgcGxvdApgYGB7cn0KIyBjYWxjdWxhdGUgZGF0YSBmb3IgY29udmV4IGh1bGxzCmh1bGxkYXRhPC0gaHVsbGZuKGdjX3BjYV9zY29yZXMsICJwMSIsICJwMiIsICJ0cmVhdGNvbWJvIikgI2luIGNoZW1oZWxwZXIKCiMgc2V0IHNoYXBlcyBhbmQgY29sb3JzCnRydGNvbHMgPC0gYygiMTAwJSIgPSAiYmx1ZSIsICI3NSUiID0gImRhcmtncmVlbiIsICI1MCUiID0gImRhcmtvcmFuZ2UzIikKc3ByYXlzaGFwZXMgPC0gYygiTWVKQSIgPSAxNywgIkNvbnRyb2wiID0gMjApCgpnY19wY2EucGxvdCA8LSBnZ3Bsb3QoZ2NfcGNhX3Njb3JlcywgYWVzKHggPSBwMSwgeSA9IHAyLHNoYXBlID0gU3ByYXksIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBzdGF0X2VsbGlwc2UoYWVzKGdyb3VwID0gVHJlYXRtZW50OlNwcmF5LCBsaW5ldHlwZSA9IFNwcmF5KSwgdHlwZSA9ICJ0IikgKyAjIEhvdGVsbGluZyBUXjIgZGlzdHJpYnV0aW9uCiAgIyBVbmNvbW1lbnQgdG8gc2VlIGNvbnZleCBodWxscy4gIFBhdHRlcm4gaXMgbGVzcyBvYnZpb3VzIGJlY2F1c2UgdGhlIG91dGxpbmVzIGFsbCBvdmVybGFwLgogICNnZW9tX3BvbHlnb24oZGF0YSA9IGh1bGxkYXRhLCBhZXMobGluZXR5cGUgPSBTcHJheSwgZmlsbCA9IFRyZWF0bWVudCksIGFscGhhID0gMC4zKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgMiksIG5hbWUgPSBOVUxMKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IHNwcmF5c2hhcGVzLCBuYW1lID0gIlNpbXVsYXRlZCBIZXJiaXZvcnkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHRydGNvbHMsIG5hbWUgPSAiJSBBbWJpZW50IFJhaW5mYWxsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNoYXBlID0gMTUsIHNpemUgPSA0LCBsaW5ldHlwZSA9IDApKSkgKwogIHhsYWIocGFzdGUwKCJQQzEgKCIsIHNpZ25pZihnY19wY2FAbW9kZWxERiRSMlhbMV0qMTAwLCBkaWdpdHMgPSAyKSwgIiUpIikpICsKICB5bGFiKHBhc3RlMCgiUEMyICgiLCBzaWduaWYoZ2NfcGNhQG1vZGVsREYkUjJYWzJdKjEwMCwgZGlnaXRzID0gMiksICIlKSIpKSArCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpICsKICB0aGVtZV9idygpCiMgZ2NfcGNhLnBsb3QKYGBgCkFkZCBjdXN0b20gbGVnZW5kCmBgYHtyfQpiYXNlIDwtIGdjX3BjYS5wbG90ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAjc3VwcHJlc3MgbGVnZW5kCgojIENyZWF0ZSBzb21lIGR1bW15IGRhdGEgZm9yIGxlZ2VuZApsZWdlbmQuZGYgPC0gZGF0YS5mcmFtZSh4ID0gYygxMCwgMTApLCB5ID0gYyg4NSwgODApLCBsYWJlbCA9IGMoIk1lSkEiLCAiQ29udHJvbCIpKQpsZWdlbmQuZGYyIDwtIGRhdGEuZnJhbWUoeCA9IGMoMTAsIDEwLCAxMCksIHkgPSBjKDY1LCA2MCwgNTUpLCBsYWJlbCA9IGMoIjEwMCUiLCAiNzUlIiwgIjUwJSIpKQoKbGVnZW5kIDwtIGdncGxvdChsZWdlbmQuZGYpICsKICB4bGltKDAsMTAwKSArCiAgeWxpbSgwLDEwMCkgKwogIHRoZW1lX25vdGhpbmcoKSArICNjb21tZW50IHRoaXMgbGluZSBvdXQgdG8gZ2V0IGEgYmV0dGVyIGlkZWEgb2Ygd2hhdCBpcyBoYXBwZW5pbmcKICAjIFNpbXVsYXRlZCBoZXJiaXZvcnkgbGVnZW5kCiAgZ2VvbV90ZXh0KGFlcyh4ID0gMTAsIHkgPSA5MCwgbGFiZWwgPSAiU2ltdWxhdGVkIEhlcmJpdm9yeSIpLCAjdGl0bGUKICAgICAgICAgICAgaGp1c3QgPSAibGVmdCIsCiAgICAgICAgICAgIHNpemUgPSAzLjUsCiAgICAgICAgICAgIGRhdGEgPSBkYXRhLmZyYW1lKCksIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBnZW9tX3RleHQoYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBsYWJlbCksICNsYWJlbHMKICAgICAgICAgICAgaGp1c3QgPSAiaW53YXJkIiwgbnVkZ2VfeCA9IDExLAogICAgICAgICAgICBzaXplID0gMy4wLAogICAgICAgICAgICBkYXRhID0gbGVnZW5kLmRmLCBpbmhlcml0LmFlcyA9IEZBTFNFKSArIAogIGdlb21fcG9pbnQoYWVzKHggPSB4LCB5ID0geSwgc2hhcGUgPSBsYWJlbCksICNzaGFwZXMKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IDgpLAogICAgICAgICAgICAgZGF0YSA9IGxlZ2VuZC5kZiwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IHgsIHkgPSB5LCB4ZW5kID0geCArIDUsIHllbmQgPSB5LCBsaW5ldHlwZSA9IGxhYmVsKSwgI2VsbGlwc2UgbGluZXMKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMSksCiAgICAgICAgICAgIGRhdGEgPSBsZWdlbmQuZGYsIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc3ByYXlzaGFwZXMpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLCAxKSkgKwoKICAKICAjIERyb3VnaHQgdHJlYXRtZW50IGxlZ2VuZAogIGdlb21fdGV4dChhZXMoeCA9IDEwLCB5ID0gNzAsIGxhYmVsID0gIiUgQW1iaWVudCBSYWluZmFsbCIpLCAjdGl0bGUKICAgICAgICAgICAgaGp1c3QgPSAibGVmdCIsCiAgICAgICAgICAgIHNpemUgPSAzLjUsCiAgICAgICAgICAgIGRhdGEgPSBkYXRhLmZyYW1lKCksCiAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBnZW9tX3RleHQoYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBsYWJlbCksICNsYWJlbHMKICAgICAgICAgICAgaGp1c3QgPSAiaW53YXJkIiwKICAgICAgICAgICAgbnVkZ2VfeCA9IDUsCiAgICAgICAgICAgIHNpemUgPSAzLAogICAgICAgICAgICBkYXRhID0gbGVnZW5kLmRmMiwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSB4LCB5ID0geSwgY29sb3IgPSBsYWJlbCksICNjb2xvciBzd2F0Y2hlcwogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMi4zKSwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gMy41LAogICAgICAgICAgICAgZGF0YSA9IGxlZ2VuZC5kZjIsIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdHJ0Y29scykKbGVnZW5kCgpnY19wY2EucGxvdDIgPC0gYmFzZSArIGRyYXdfcGxvdChsZWdlbmQsIC04LCA1LjgsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgc2NhbGUgPSAyOCkKZ2NfcGNhLnBsb3QyCnNhdmVfcGxvdChoZXJlKCJmaWdzIiwgIkdDTVMgUENBLnBuZyIpLCBnY19wY2EucGxvdDIsIGJhc2VfYXNwZWN0X3JhdGlvID0gMS4zLCBiYXNlX2hlaWdodCA9IDUpCmBgYAoKCiMgUEVSTUFOT1ZBClBFUk1BTk9WQSBjb25maXJtcyB3aGF0IGlzIHNlZW4gaW4gdGhlIFBDQS4gIFRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgbWFpbiBlZmZlY3Qgb2YgTWVKQSB0cmVhdG1lbnQgb24gdm9sYXRpbGUgcHJvZmlsZSBhbmQgYSBzaWduaWZpY2FudCBpbnRlcmFjdGlvbiBiZXR3ZWVuIGRyb3VnaHQgdHJlYXRtZW50IGFuZCBNZUpBIHRyZWF0bWVudC4KCiMjIFNjYWxlIERhdGEKTm9uZSBvZiB0aGUgYHZlZ2FuYCBmdW5jdGlvbnMgc3VwcG9ydCBzY2FsaW5nIHdpdGggYW5kIGFyZ3VtZW50LiAgSSBuZWVkIHRvIHNjYWxlIHRoZSBkYXRhIGFoZWFkIG9mIHRpbWUuCmBgYHtyfQpnY19sb2dfc2NhbGUgPC0gZ2NfbG9nLjEgJT4lIG11dGF0ZV9pZihpcy5kb3VibGUsIH5jaGVtX3NjYWxlKC4sY2VudGVyID0gVFJVRSwgc2NhbGUgPSAiYXV0byIpKQpgYGAKCiMjIFRlc3QgQXNzdW1wdGlvbnMKUEVSTUFOT1ZBIGFzc3VtZXMgaG9tb2duZWl0eSBvZiB2YXJpYW5jZXMgaW4gbXVsdGl2YXJpYXRlIHNwYWNlLgpgYGB7cn0KI211bHRpdmFyaWF0ZSBhbmFsb2cgb2YgTGV2ZW5lJ3MgVGVzdCBmb3IgaG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VzLS1hbiBhc3N1bXB0aW9uIG9mIFBFUk1BTk9WQQpQRVJNRElTVCA8LSBiZXRhZGlzcGVyKHZlZ2Rpc3Qoc2VsZWN0X2lmKGdjX2xvZ19zY2FsZSwgaXMuZG91YmxlKSwgbWV0aG9kID0gImV1IiksIGdyb3VwID0gcGFzdGUoZ2NfbG9nX3NjYWxlJFRyZWF0bWVudCwgZ2NfbG9nX3NjYWxlJFNwcmF5KSwgdHlwZSA9ICJjZW50cm9pZCIpCiNwbG90KFBFUk1ESVNUKQojUEVSTURJU1QKYW5vdmEoUEVSTURJU1QpCiNtZWV0cyB0aGUgYXNzdW1wdGlvbiBvZiBob21vZ2VuZWl0eSBvZiBkaXNwZXJzaW9uIGlmIHAgPiAwLjA1CmBgYAojIyBSdW4gVGVzdApgYGB7cn0KYWRvbmlzKHNlbGVjdF9pZihnY19sb2dfc2NhbGUsIGlzLmRvdWJsZSkgfiBUcmVhdG1lbnQqU3ByYXksCiAgICAgICAgbWV0aG9kID0gImV1Y2xpZGVhbiIsCiAgICAgICAgYnkgPSAidGVybXMiLAogICAgICAgIGRhdGEgPSBnY19sb2dfc2NhbGUpCmBgYApTcHJheSBhbmQgaW50ZXJhY3Rpb24gYXJlIHNpZ25pZmljYW50LCBtYXRjaGluZyB3aGF0IGlzIHNlZW4gaW4gdGhlIFBDQQoKIyMgVHJ5IHBhaXJ3aXNlIHBvc3QtaG9jIFBFUk1BTk9WQVMKYGBge3J9CmxpYnJhcnkocGFpcndpc2VBZG9uaXMpCnBhaXJ3aXNlLmFkb25pcyhzZWxlY3RfaWYoZ2NfbG9nX3NjYWxlLCBpcy5kb3VibGUpLCBmYWN0b3JzID0gZ2NfbG9nX3NjYWxlJFRyZWF0bWVudDpnY19sb2dfc2NhbGUkU3ByYXksCiAgICAgICAgICAgICAgICBzaW0ubWV0aG9kID0gImV1Y2xpZGVhbiIsCiAgICAgICAgICAgICAgICBwLmFkanVzdC5tID0gIm5vbmUiKSAlPiUgCiAgZmlsdGVyKHBhaXJzICVpbiUgYygiNTAlOk1lSkEgdnMgNTAlOkNvbnRyb2wiLCAiNzUlOkNvbnRyb2wgdnMgNzUlOk1lSkEiLCAiMTAwJTpNZUpBIHZzIDEwMCU6Q29udHJvbCIpKSAlPiUgCiAgbXV0YXRlKHAuYWRqdXN0ZWQgPSBwLmFkanVzdChwLnZhbHVlLCAiZmRyIikpCmBgYAoKIyBQTFMtREEKSSBjYW4gYWxzbyB0cnkgdG8gdXNlIFBMUy1EQSB0byBjb25maXJtIHRoYXQgdGhlcmUgaXMgYW4gZWZmZWN0IG9mIE1lSkEsIG5vIG1haW4gZWZmZWN0IG9mIGRyb3VnaHQsIGFuZCBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuIE1lSkEgYW5kIGRyb3VnaHQgdHJlYXRtZW50LgoKIyMgUExTLURBIG9uIEVmZmVjdCBvZiBNZUpBIFNwcmF5ClRoZXJlIGlzIHNpZ25pZmljYW50IHNlcGFyYXRpb24gb2Ygdm9sYXRpbGUgcHJvZmlsZXMgYnkgTWVKQSBzcHJheS4gUTIgYW5kIFIyIGFyZSBib3RoIGhpZ2ggYW5kIHNpbWlsYXIgdG8gZWFjaG90aGVyLCBhbmQgcCA8IDAuMDUuCmBgYHtyfQpnY19wbHNkYV9zcHJheSA8LSBvcGxzKHNlbGVjdF9pZihnY19sb2cuMSwgaXMuZG91YmxlKSwgZ2NfbG9nLjEkU3ByYXksCiAgICAgICAgICAgICAgICAgICAgICAgcGVybUkgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQyA9ICJzdGFuZGFyZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdEwgPSBGQUxTRSkKIyBwbG90KGdjX3Bsc2RhX3NwcmF5KQpgYGAKUGxvdApgYGB7cn0KZ2NfcGxzZGFfc3ByYXlQRCA8LSBnZXRfcGxvdGRhdGEoZ2NfcGxzZGFfc3ByYXkpCmdncGxvdChnY19wbHNkYV9zcHJheVBEJHBsb3RfZGF0YSwgYWVzKHggPSBwMSwgeSA9IHAyLCBzaGFwZSA9IHkxLCBjb2xvciA9IGdjX2xvZy4xJFRyZWF0bWVudCkpICsKICBzdGF0X2VsbGlwc2UoYWVzKHggPSBwMSwgeSA9IHAyLCBsaW5ldHlwZSA9IHkxKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIuNSkgKwogIGxhYnMoeCA9IHBhc3RlMCgiUDEgKCIsIGdjX3Bsc2RhX3NwcmF5UEQkYXhpc19zdGF0cyRSMlhbMV0qMTAwLCAiJSkiKSwKICAgICAgIHkgPSBwYXN0ZTAoIlAyICgiLCBnY19wbHNkYV9zcHJheVBEJGF4aXNfc3RhdHMkUjJYWzJdKjEwMCwgIiUpIikpICsKICBnZ3RpdGxlKCJQTFMtREEgb24gZnVsbCBkYXRhIHNldCIsCiAgICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiUl4yID0gIiwgZ2NfcGxzZGFfc3ByYXlQRCRtb2RlbF9zdGF0cyRgUjJZKGN1bSlgLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAgUV4yID0gIiwgZ2NfcGxzZGFfc3ByYXlQRCRtb2RlbF9zdGF0cyRgUTIoY3VtKWAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiICBwKFFeMikgPSAiLCBnY19wbHNkYV9zcHJheVBEJG1vZGVsX3N0YXRzJHBRMikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwoIlNpbXVsYXRlZFxuSGVyYml2b3J5IiwgdmFsdWVzID0gc3ByYXlzaGFwZXMpICsKICBzY2FsZV9saW5ldHlwZSgiU2ltdWxhdGVkXG5IZXJiaXZvcnkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCIlIEFtYmllbnRcblJhaW5mYWxsIiwgdmFsdWVzID0gdHJ0Y29scykgKwogIHRoZW1lX2J3KCkKYGBgCgpgYGB7cn0KZ2V0X1ZJUChnY19wbHNkYV9zcHJheSkgJT4lICNmcm9tIGNoZW1oZWxwZXIKICByZW5hbWUoQ29tcG91bmQgPSAiVmFyaWFibGUiKSAlPiUgCiAgYXJyYW5nZShkZXNjKFZJUCkpICU+JSAKICBmaWx0ZXIoVklQID4gMSkKYGBgCgojIyBQTFMtREEgb24gRWZmZWN0IG9mIERyb3VnaHQgVHJlYXRtZW50ClRoZXJlIGlzIG5vIHNpZ25pZmljYW50IHNlcGFyYXRpb24gYnkgZHJvdWdodCB0cmVhdG1lbnQgKG5vIG1vZGVsIGlzIGJ1aWx0IGJlY2F1c2UgZmlyc3QgY29tcG9uZW50IGlzIG5vdCBzaWduaWZpY2FudCkuCmBgYHtyfQpnY19wbHNkYV9kcm91Z2h0IDwtIHRyeSgKICBvcGxzKHNlbGVjdF9pZihnY19sb2cuMSwgaXMuZG91YmxlKSwgZ2NfbG9nLjEkVHJlYXRtZW50LAogICAgICAgICAgICAgICAgICAgICAgIHBlcm1JID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQyA9ICJzdGFuZGFyZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdEwgPSBGQUxTRSkKKQpgYGAKCgoKIyMgUExTLURBIG9uIENvbWJpbmVkIERyb3VnaHQgYW5kIE1lSkEKVGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgc2VwYXJhdGlvbiB3aGVuIHVzaW5nIGFsbCA2IGdyb3VwcyAoZXZlcnkgZHJvdWdodCB4IE1lSkEgY29tYmluYXRpb24pLiAgQSBzaW5nbGUtY29tcG9uZW50IG1vZGVsIGlzIGJ1aWx0LCBidXQgdGhlIFIyIGFuZCBRMiBhcmUgZXh0cmVtZWx5IGxvdywgc28gdGhlcmUgaXMgZXNzZW50aWFsbHkgbm8gcHJlZGljdGl2ZSBvciBleHBsYW5hdG9yeSBwb3dlciBvZiB0aGUgbW9kZWwuCmBgYHtyfQpnY19wbHNkYV9jb21ibyA8LSB0cnkoCiAgb3BscyhzZWxlY3RfaWYoZ2NfbG9nLjEsIGlzLmRvdWJsZSksIHBhc3RlKGdjX2xvZy4xJFRyZWF0bWVudCwgZ2NfbG9nLjEkU3ByYXkpLAogICAgICAgICAgICAgICAgICAgICAgIHBlcm1JID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgIHNjYWxlQyA9ICJzdGFuZGFyZCIsCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdEwgPSBGQUxTRSkKKQpgYGAKCgojIFRhYmxlIG9mIGhpZ2ggVklQIE1ldGFib2xpdGVzClRhYmxlIDEgd2lsbCBiZSBvbmx5IHRoZSBtZXRhYm9saXRlcyB3aXRoIFZJUCA+IDEsIGFycmFuZ2VkIGJ5IFZJUCBmcm9tIGBnY19wbHNkYV9zcHJheWAgc2hvd2luZyBtZWFuIFJQQSAqIDEwMDAgZm9yIGVhY2ggdHJlYXRtZW50IGNvbWJpbmF0aW9uLgoKIyMgRXh0cmFjdCBWSVBzCmBgYHtyfQpWSVBfc3ByYXkgPC0gZ2V0X1ZJUChnY19wbHNkYV9zcHJheSkgJT4lIHJlbmFtZShDb21wb3VuZCA9ICJWYXJpYWJsZSIpCmBgYAojIyBDYWxjdWxhdGUgUkkgYW5kIHN1bW1hcmlzZQojIyMgTG9hZCBpbiBhbGthbmUgZGF0YQpgYGB7cn0KYWxrYW5lcyA8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwgIkdDIGFsa2FuZXMuY3N2IikpCmBgYAoKIyMjIENhbGN1bGF0ZSBtZWFuIFJJCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmdjX3JpIDwtIGdjX3plcm9lc19sb25nLjEgJT4lCiAgbXV0YXRlKFJJID0gbWFwX2RibChSVCwgfmNhbGNfUkkoLiwgYWxrYW5lcyRSVCwgYWxrYW5lcyRDX251bSkpKSAlPiUgI2NhbGN1bGF0ZSBSSSBiYXNlZCBvbiBhbGthbmUgZmlsZQogIGdyb3VwX2J5KENvbXBvdW5kKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fUkkgPSBtZWFuKFJJLCBuYS5ybSA9IFRSVUUpKSAjY2FsY3VsYXRlIG1lYW4gUkkgZm9yIGVhY2ggY29tcG91bmQKYGBgCgojIyBTdW1tYXJpc2UgYW5kIHNwcmVhZApBZGQgaW4gwrEgU0UgaGVyZS4KYGBge3J9CmdjX3N1bW1hcnkgPC0gZ2NfemVyb2VzX2xvbmcuMSAlPiUKICBtdXRhdGUoQ29tYm8gPSBwYXN0ZTAoVHJlYXRtZW50LCIgcmFpbiwgIiwgU3ByYXkpICU+JSAjIHNldCB1cCBjb2x1bW4gaGVhZGVycwogICAgICAgICAgIGZjdF9yZWxldmVsKCIxMDAlIHJhaW4sIENvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICI3NSUgcmFpbiwgQ29udHJvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgIjUwJSByYWluLCBDb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAiMTAwJSByYWluLCBNZUpBIiwKICAgICAgICAgICAgICAgICAgICAgICAiNzUlIHJhaW4sIE1lSkEiLAogICAgICAgICAgICAgICAgICAgICAgICI1MCUgcmFpbiwgTWVKQSIpKSAlPiUgCiAgZ3JvdXBfYnkoQ29tYm8sIENvbXBvdW5kKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fUlBBeDEwMDAgPSBtZWFuKFJQQSAqIDEwMDApLCAjIGNhbGN1bGF0ZSBtZWFuIFJQQSB4IDEwMDAgKGp1c3QgdG8gbWFrZSBpdCBtb3JlIHJlYWRhYmxlKQogICAgICAgICAgICBzZV9SUEF4MTAwMCA9IHNkKFJQQSAqIDEwMDApL24oKSkgJT4lICMgY2FsY3VsYXRlIFNFTQogIG11dGF0ZShgUlBBIMKxIFNFYCA9IGlmZWxzZShtZWFuX1JQQXgxMDAwID09IDAsIE5BLCAjIHBhc3RlIFJQQSDCsSBTRU0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAocm91bmQobWVhbl9SUEF4MTAwMCwgMyksICIgwrEgIiwgcm91bmQoc2VfUlBBeDEwMDAsIDIpKSkpICU+JSAKICBzZWxlY3QoLW1lYW5fUlBBeDEwMDAsIC1zZV9SUEF4MTAwMCkgJT4lIAogIHNwcmVhZChrZXkgPSBDb21ibywgdmFsdWUgPSBgUlBBIMKxIFNFYCkKYGBgCiMjIEpvaW4gd2l0aCBWSVAgYW5kIFJJCmBgYHtyfQpnY190YWJsZSA8LSBsZWZ0X2pvaW4oZ2Nfc3VtbWFyeSwgVklQX3NwcmF5KQpnY190YWJsZSA8LSBsZWZ0X2pvaW4oZ2NfdGFibGUsIGdjX3JpKQpnY190YWJsZQpgYGAKCiMjIFJlYWQgaW4gcHJldHR5IG5hbWVzIGFuZCBqb2luCmBgYHtyfQphbm5vdGF0aW9ucyA8LSByZWFkX2V4Y2VsKGhlcmUoImRhdGEiLCAiQ29tcG91bmQgYW5ub3RhdGlvbi54bHN4IikpCgpnY190YWJsZS4xIDwtIGxlZnRfam9pbihnY190YWJsZSwKICAgICAgICAgIGFubm90YXRpb25zICU+JQogICAgICAgICAgICBzZWxlY3QoQ29tcG91bmQsIGBQcmV0dHkgTmFtZWAsIExhVGVYKSkgI3N0YXJ0IHNpbXBsZQpgYGAKIyMgRmluZCBhbmQgcmUtbmFtZSB1bmtub3ducyBieSBSSQpVbmtub3ducyBpbiB0aGUgbWV0aG9kIGFyZSBudW1iZXJlZCBiYXNlZCBvbiBzb21lIG9yZGVyIHRoZXkgd2VyZSBmb3VuZC4gIFJlbmFtZSBiYXNlZCBvbiBSSSBmb3IgcHVibGljYXRpb24uCmBgYHtyfQpnY190YWJsZS4yIDwtIGdjX3RhYmxlLjEgJT4lIAogIG11dGF0ZSh1bmtub3duID0gc3RyX2RldGVjdChDb21wb3VuZCwgIl5cXGQrKCR8IFxcKERDU0VcXCkkKSIpKSAjIHVua25vd25zIGFyZSBlaXRoZXIgYWxsIG51bWJlcnMgb3IgIjxudW0+IChEQ1NFKSIKCnVua25vd25zIDwtIGdjX3RhYmxlLjIgJT4lICMgZXh0cmFjdCBqdXN0IHRoZSB1bmtub3ducyBhbmQgYXJyYW5nZSBieSBSSQogIGZpbHRlcih1bmtub3duKSAlPiUKICBhcnJhbmdlKG1lYW5fUkkpICU+JQogIGFkZF9jb2x1bW4odW5rX25hbWUgPSAxOm5yb3coLikpICNhZGQgYSBjb2x1bW4gdG8gZ2l2ZSB0aGVtIG5ldyBudW1iZXJzCgpnY190YWJsZS4zIDwtIHJpZ2h0X2pvaW4odW5rbm93bnMsIGdjX3RhYmxlLjIpICU+JSAgI2pvaW4gYmFjayB3aXRoIG9yaWdpbmFsIHRhYmxlCiAgbXV0YXRlKGBQcmV0dHkgTmFtZWAgPSBpZmVsc2UodW5rbm93biA9PSBUUlVFLCB1bmtfbmFtZSwgYFByZXR0eSBOYW1lYCkpICN1c2UgdGhlIG5ldyBudW1iZXJzIG9ubHkgZm9yIHVua25vd25zCmdjX3RhYmxlLjMKYGBgCgojIyBDcmVhdGUgdGFibGVzIHdpdGggcHJldHR5IG5hbWVzCmBgYHtyfQojdXNlIHByZXR0eSBuYW1lcwpnY190YWJsZS40IDwtIGdjX3RhYmxlLjMgJT4lCiAgbXV0YXRlKENvbXBvdW5kID0gaWZlbHNlKGlzLm5hKGBQcmV0dHkgTmFtZWApLCBDb21wb3VuZCwgYFByZXR0eSBOYW1lYCkpICU+JSAKICBzZWxlY3QoLWBQcmV0dHkgTmFtZWAsIC11bmtub3duLCAtdW5rX25hbWUpICU+JSAKICByZW5hbWUoUkkgPSBtZWFuX1JJKSAlPiUgCiAgYXJyYW5nZShkZXNjKFZJUCkpICU+JSAKICBmaWx0ZXIoVklQPjEpICU+JSAKICBzZWxlY3QoQ29tcG91bmQsIFJJLCBldmVyeXRoaW5nKCkpCgp3cml0ZV9leGNlbF9jc3YoZ2NfdGFibGUuNCAlPiUgc2VsZWN0KC1MYVRlWCksIGhlcmUoImZpZ3MiLCAiVGFibGUgMS5jc3YiKSwgbmEgPSAiLSIpCmBgYAoKIyBTdXBwbGVtZW50YXJ5IHRhYmxlIG9mIGFsbCBtZXRhYm9saXRlcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBDcmVhdGUgdGFibGUgb2YgUklzCnRhYmxlUzEgPC0gZ2NfdGFibGUuMyAlPiUKICBzZWxlY3QoLXVua25vd24sIC11bmtfbmFtZSwgLVZJUCkgJT4lIAogIHJlbmFtZShSSSA9IG1lYW5fUkkpICU+JSAKICBhcnJhbmdlKFJJKQoKIyBSZWFkIGluIENBUyBudW1iZXJzIGFuZCBqb2luCkNBU251bXMgPC0gYW5ub3RhdGlvbnMgJT4lIHNlbGVjdChDb21wb3VuZCwgQ0FTKQp0YWJsZVMxIDwtIGxlZnRfam9pbih0YWJsZVMxLCBDQVNudW1zKQoKIyBSZWFkIGluIHJlZmVyZW5jZSBzdGFuZGFyZCBkYXRhIGFuZCBqb2luCnJlZmVyZW5jZXN0ZHMgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJSZWZlcmVuY2UgU3RhbmRhcmRzLmNzdiIpKSAlPiUgCiAgc2VsZWN0KGBDb21wb3VuZCBOYW1lYCwgQ0FTLCBWZW5kb3IsIGBSSSBEQjVgKSAlPiUKICBmaWx0ZXIoIWlzLm5hKENBUykpCnRhYmxlUzEgPC0gbGVmdF9qb2luKHRhYmxlUzEsIHJlZmVyZW5jZXN0ZHMpCgojIFJlYWQgaW4gbGl0ZXJhdHVyZSBSSXMgYW5kIGpvaW4KbWFzdGVyIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAibWV0aG9kX21hc3RlciBSSXMuY3N2IikpCmxpdFJJcyA8LSBtYXN0ZXIgJT4lIAogIHNlbGVjdChDb21wb3VuZCwgQ0FTLCBSSV9saXQpCnRhYmxlUzEgPC0gbGVmdF9qb2luKHRhYmxlUzEsIGxpdFJJcykKCiMgUmVtb3ZlIENBUyBudW1iZXJzIGZyb20gdW5rbm93bnMgKHRoZXkgd2VyZSBwdXQgYnkgSW9uIEFuYWx5dGljcykKdGFibGVTMSAlPiUgZmlsdGVyKHN0cl9kZXRlY3QoYFByZXR0eSBOYW1lYCwgIl5cXGQrJCIpKQp0YWJsZVMxIDwtIHRhYmxlUzEgJT4lIAogIG11dGF0ZShDQVMgPSBpZmVsc2Uoc3RyX2RldGVjdChgUHJldHR5IE5hbWVgLCAiXlxcZCskIiksIE5BLCBDQVMpKQoKIyBSZW5hbWUgYW5kIHNlbGVjdCBjb2x1bW5zIGFuZCB3cml0ZSB0byAuY3N2CnRhYmxlUzEgPC0gdGFibGVTMSAlPiUgCiAgc2VsZWN0KENvbXBvdW5kID0gYFByZXR0eSBOYW1lYCwgQ0FTLCBleHBlcmltZW50YWxfUkkgPSBSSSwgcmVmZXJlbmNlX1JJID0gYFJJIERCNWAsIFZlbmRvciwgbGl0ZXJhdHVyZV9SSSA9IFJJX2xpdCApCndyaXRlX2V4Y2VsX2Nzdih0YWJsZVMxLCBoZXJlKCJmaWdzIiwgIlRhYmxlIFMxLmNzdiIpLCBuYSA9ICItIikKYGBgCgojIyBDaGVja2luZyBjb21wb3VuZCBpZGVudGlmaWNhdGlvbiBzdGF0dXMKCmBgYHtyfQp0YWJsZVMxICU+JSBmaWx0ZXIoaXMubmEoQ0FTKSkgJT4lIHN1bW1hcml6ZSh1bmtub3ducyA9IG4oKSkKdGFibGVTMSAlPiUgZmlsdGVyKCFpcy5uYShDQVMpKSAlPiUgc3VtbWFyaXplKGlkZW50aWZpZWQgPSBuKCkpCnRhYmxlUzEgJT4lIGZpbHRlcighaXMubmEoQ0FTKSwgaXMubmEocmVmZXJlbmNlX1JJKSkgJT4lIHN1bW1hcml6ZShwdXRhdGl2ZSA9IG4oKSkKdGFibGVTMSAlPiUgZmlsdGVyKCFpcy5uYShDQVMpLCAhaXMubmEocmVmZXJlbmNlX1JJKSkgJT4lIHN1bW1hcml6ZShyZWZlcmVuY2UgPSBuKCkpCmBgYAoKIyMgSW52ZXN0aWdhdGluZyBNZXRoeWwgU2FsaWN5bGF0ZSBSZXNwb25zZQoKYGBge3J9CmdjX2xvZy4xICU+JSAKICBnYXRoZXIoLXNhbXBsZSwgLVRyZWF0bWVudCwgLVNwcmF5LCAtUGxvdCwgLVBsYW50LCBrZXkgPSBDb21wb3VuZCwgdmFsdWUgPSBSUEEpICU+JSAKICBmaWx0ZXIoQ29tcG91bmQgPT0gIk1ldGh5bCBzYWxpY3lsYXRlIikgJT4lIAogIGdncGxvdChhZXMoeCA9IFRyZWF0bWVudCwgY29sb3IgPSBTcHJheSwgeSA9IFJQQSkpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMikgKwogIGxhYnMoeCA9ICJQcmVjaXBpdGF0aW9uIHRyZWF0bWVudCIsIHkgPSAibG9nKFJQQSkiKQoKZ2NfemVyb2VzX2xvbmcuMSAlPiUgCiAgZmlsdGVyKENvbXBvdW5kID09ICJNZXRoeWwgc2FsaWN5bGF0ZSIpICU+JSAKICBncm91cF9ieShUcmVhdG1lbnQsIFNwcmF5KSAlPiUgCiAgc3VtbWFyaXplKGRldGVjdGVkID0gc3VtKFJQQSE9MCkpCmBgYAoKIyMgQ2hlY2tpbmcgc2FtcGxlIHNpemVzCmBgYHtyfQpnY19sb2cuMSAlPiUgZ3JvdXBfYnkoU3ByYXkpICU+JSAKICBzdW1tYXJpemUoY291bnQgPSBuKCkpCmBgYAoK