library(tidyverse)
── Attaching packages ───────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.0.0     ✔ purrr   0.2.5
✔ tibble  1.4.2     ✔ dplyr   0.7.6
✔ tidyr   0.8.1     ✔ stringr 1.3.1
✔ readr   1.1.1     ✔ forcats 0.3.0
── Conflicts ──────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(here)
here() starts at /Users/scottericr/Documents/Tufts/Research Projects/BACE Tea/Data for drought by herbivory in tea
library(ggridges)

Attaching package: ‘ggridges’

The following object is masked from ‘package:ggplot2’:

    scale_discrete_manual
library(gglabeller)
library(ropls)
library(vegan)
Loading required package: permute
Loading required package: lattice
This is vegan 2.5-2
library(cowplot)

Attaching package: ‘cowplot’

The following object is masked from ‘package:ggplot2’:

    ggsave
library(chemhelper) #install with devtools::install_github("Aariq/chemhelper")
library(broom)
library(ggrepel)
library(HDoutliers)
Loading required package: FNN
Loading required package: FactoMineR
Loading required package: mclust
    __  ___________    __  _____________
   /  |/  / ____/ /   / / / / ___/_  __/
  / /|_/ / /   / /   / / / /\__ \ / /   
 / /  / / /___/ /___/ /_/ /___/ // /    
/_/  /_/\____/_____/\____//____//_/    version 5.4.1
Type 'citation("mclust")' for citing this R package in publications.

Attaching package: ‘mclust’

The following object is masked from ‘package:purrr’:

    map

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.
isnt_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 tidied data

lc <- read_rds(here("cleaned_data", "lcms.rds"))
lc <- lc %>% rename(conc = `mean_leaf_conc(µg/mg)`)
lc

Deal with non-detects

Non-detects are represented in this dataset as NA. I’ll set them to 0 for multivariate analysis.

lc2 <- lc %>% mutate_if(is.double, funs(ifelse(is.na(.), 0 , .)))

Deal with

to_remove <- lc2 %>% 
  filter(`Under LOQ` == TRUE) %>%
  arrange(Compound) %>% 
  group_by(Compound) %>% 
  summarise(count = n()) %>% 
  filter(count == 53) %>% 
  .$Compound
lc3 <- lc2 %>% 
  filter(!Compound %in% to_remove)

Visualize

Scatter plots

horiz_scatter <- function(){
  list(
    geom_point(alpha = 0.5),
    coord_flip(),
    labs(x = "Compound Name"),
    scale_color_brewer(type = "qual", palette = 6)
  )
}
p <- ggplot(lc3, aes(x = Compound, y = conc, label = unique.id)) + horiz_scatter() + ylab("Concentration (µg/mg)") + theme_bw()

Interactive, not run by default.

Created using chunk above interactively and copying code from p.lab$code:

gglabeller_data <- p$data
gglabeller_data[c(1:95, 97:100, 102:121, 123, 125:143, 147:154, 156:333, 335:371),'unique.id'] <- ''
p + geom_text_repel(data = gglabeller_data,mapping = aes(x = Compound, y = conc, label = unique.id), min.segment.length = unit(0.5, 'lines'),box.padding = unit(0.25, 'lines'),point.padding = unit(1e-06, 'lines'))

c9 and d3 appear to be possible outliers.

Make wide data and scale

lc_wide <- lc3 %>% 
  select(unique.id, Spray, Treatment, Compound, conc) %>% 
  spread(key = Compound, value = conc) %>% 
  ungroup()
lc_wide

PCA

lc_pca <- opls(select_if(lc_wide, is.double), plotL = FALSE, scaleC = "standard")
PCA
53 samples x 7 variables
standard scaling of predictors
plot(lc_pca, parAsColFcVn = lc_wide$Treatment, parLabVc = lc_wide$unique.id)

outliers <- HDoutliers(select_if(lc_wide, is.double), transform = FALSE)
lc_wide[outliers, ]

d3 and c9 come out as outliers. This confirms univariate plots. Remove them

Remove outliers

outliers <- c("d3", "c9")
lc_wide2 <- lc_wide %>% filter(unique.id %!in% outliers)
lc_pca2 <- opls(lc_wide2 %>% select_if(is.double), plotL = FALSE, scaleC = "standard")
PCA
51 samples x 7 variables
standard scaling of predictors
plot(lc_pca2, parAsColFcVn = lc_wide2$Treatment, parLabVc = lc_wide2$unique.id)

No clear separation

Prettier plot

I’d love to streamline this exact plot. Maybe I can write a function for it sometime.

#extract scores and make into data frame
lc_pca2_scores <- lc_pca2 %>% getScoreMN() %>% 
  as_data_frame()
#rejoin with sample info
lc_pca2_scores <- bind_cols(select_if(lc_wide2, not_double), lc_pca2_scores)
lc_pca2_scores <- lc_pca2_scores %>% 
  mutate(treatcombo = paste(Treatment, Spray))
# set up colors and shapes
sprayshapes <- c("MeJA" = 17, "Control" = 20)
trtcols <- c("100%" = "blue", "75%" = "darkgreen", "50%" = "darkorange3")
#make base plot
lc_pca2_plot <- ggplot(lc_pca2_scores, aes(x = p1, y = p2, shape = Spray, color = Treatment)) + 
  geom_point(size = 2) +
  stat_ellipse(aes(group = Treatment:Spray, linetype = Spray), type = "t") +
  scale_shape_manual(values = sprayshapes) +
  scale_color_manual(values = trtcols) +
  guides(color = guide_legend(override.aes = list(shape = 15, size = 4, linetype = 0))) +
  xlab(paste0("PC1 (", signif(lc_pca2@modelDF$R2X[1]*100, digits = 2), "%)")) +
  ylab(paste0("PC2 (", signif(lc_pca2@modelDF$R2X[2]*100, digits = 2), "%)")) +
  #xlim(-9, 8) + ylim(-5, 18) +
  theme_bw() +
  theme(axis.title = element_text(size = 10),
        axis.text = element_text(size = 9))

Make the legend manually and plot inside the main plot.

base <- lc_pca2_plot +
  theme(legend.position = "none") + #suppress legend
  ylim(-5, 7) #expand axes to make room for custom 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

#overlay legend on base plot
lc_pca_plot <- base + draw_plot(legend, -1.4, 2.4, width = 1, height = 1, scale = 11)
lc_pca_plot
save_plot(here("figs", "LCMS PCA.png"), lc_pca_plot, base_aspect_ratio = 1.3, base_height = 5)

PERMANOVA

Test assumptions

lc_wide2_scale <- lc_wide2 %>% mutate_if(is.double, scale)
#multivariate analog of Levene's Test for homogeneity of variances--an assumption of PERMANOVA
PERMDIST <- betadisper(vegdist(select_if(lc_wide2_scale, is.double), method = "eu"), group = lc_wide2_scale$Treatment, type = "centroid")
plot(PERMDIST)

PERMDIST

    Homogeneity of multivariate dispersions

Call: betadisper(d = vegdist(select_if(lc_wide2_scale, is.double), method = "eu"), group =
lc_wide2_scale$Treatment, type = "centroid")

No. of Positive Eigenvalues: 7
No. of Negative Eigenvalues: 0

Average distance to centroid:
 100%   75%   50% 
2.534 2.221 2.538 

Eigenvalues for PCoA axes:
   PCoA1    PCoA2    PCoA3    PCoA4    PCoA5    PCoA6    PCoA7     <NA> 
111.9964  91.0814  59.3914  39.3388  23.6779  20.6940   3.8200       NA 
anova(PERMDIST)
Analysis of Variance Table

Response: Distances
          Df  Sum Sq Mean Sq F value Pr(>F)
Groups     2  1.1277 0.56383  0.9509 0.3936
Residuals 48 28.4612 0.59294               
#if p < 0.05 then doesn't pass test.

Passes

adonis2(select_if(lc_wide2_scale, is.double) ~ Treatment*Spray, method = "euclidean", by = "terms", data = lc_wide2_scale)
Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = select_if(lc_wide2_scale, is.double) ~ Treatment * Spray, data = lc_wide2_scale, method = "euclidean", by = "terms")
                Df SumOfSqs      R2      F Pr(>F)
Treatment        2    19.04 0.05440 1.3374  0.196
Spray            1     2.24 0.00641 0.3151  0.914
Treatment:Spray  2     8.37 0.02392 0.5880  0.807
Residual        45   320.34 0.91527              
Total           50   350.00 1.00000              

Treatment has biggest effect, but not significant unless no data censoring. Indicating its low concentration compounds that are effected.

Table S2 for non-volatiles

LS0tCnRpdGxlOiAiTENNUyBhbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoZ2dyaWRnZXMpCmxpYnJhcnkoZ2dsYWJlbGxlcikKbGlicmFyeShyb3BscykKbGlicmFyeSh2ZWdhbikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGNoZW1oZWxwZXIpICNpbnN0YWxsIHdpdGggZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJBYXJpcS9jaGVtaGVscGVyIikKbGlicmFyeShicm9vbSkKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KEhEb3V0bGllcnMpCmBgYAoKIyBDcmVhdGUgc29tZSBoZWxwZXIgZnVuY3Rpb25zCmBgYHtyIGhlbHBlci1mdW5jdGlvbnN9CiNjcmVhdGUgYSAibm90IGluIiBmdW5jdGlvbgojdXNlZnVsIGZvciBmaWx0ZXJpbmcgb3V0IG91dGxpZXJzCmAlIWluJWAgPC0gTmVnYXRlKGAlaW4lYCkKCiNkZXRlY3QgaWYgYSBjb2x1bW4gaGFzIGF0IGxlYXN0IG9uZSBub24temVybyB2YWx1ZS4gIFByb2JhYmx5IG90aGVyIHdheXMgdG8gZG8gdGhpcy4KaXNudF9lbXB0eSA8LSBmdW5jdGlvbih4KSAhaXMuZG91YmxlKHgpIHx8IGlzLmRvdWJsZSh4KSAmJiBzdW0oeCkgIT0gMCAKCiNmdW5jdGlvbiB0byBzZWxlY3QgY29sdW1ucyB0aGF0IGFyZSBOT1QgZG91YmxlLCBpLmUuIGludGVnZXIsIGZhY3RvciwgYW5kIGNoYXJhY3Rlcgpub3RfZG91YmxlIDwtIGZ1bmN0aW9uKHgpICFpcy5kb3VibGUoeCkgCmBgYAoKIyBSZWFkIGluIHRpZGllZCBkYXRhCmBgYHtyfQpsYyA8LSByZWFkX3JkcyhoZXJlKCJjbGVhbmVkX2RhdGEiLCAibGNtcy5yZHMiKSkKbGMgPC0gbGMgJT4lIHJlbmFtZShjb25jID0gYG1lYW5fbGVhZl9jb25jKMK1Zy9tZylgKQpsYwpgYGAKCiMgRGVhbCB3aXRoIG5vbi1kZXRlY3RzCk5vbi1kZXRlY3RzIGFyZSByZXByZXNlbnRlZCBpbiB0aGlzIGRhdGFzZXQgYXMgYE5BYC4gIEknbGwgc2V0IHRoZW0gdG8gMCBmb3IgbXVsdGl2YXJpYXRlIGFuYWx5c2lzLgpgYGB7cn0KbGMyIDwtIGxjICU+JSBtdXRhdGVfaWYoaXMuZG91YmxlLCBmdW5zKGlmZWxzZShpcy5uYSguKSwgMCAsIC4pKSkKYGBgCgojIERlYWwgd2l0aCA8TE9RIHZhbHVlcy4KSSdsbCByZW1vdmUgY29tcG91bmRzIHRoYXQgYXJlIGJlbG93IHRoZSBMT1EgZm9yIGFsbCBzYW1wbGVzLgpgYGB7cn0KdG9fcmVtb3ZlIDwtIGxjMiAlPiUgCiAgZmlsdGVyKGBVbmRlciBMT1FgID09IFRSVUUpICU+JQogIGFycmFuZ2UoQ29tcG91bmQpICU+JSAKICBncm91cF9ieShDb21wb3VuZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIGZpbHRlcihjb3VudCA9PSA1MykgJT4lIAogIC4kQ29tcG91bmQKCmxjMyA8LSBsYzIgJT4lIAogIGZpbHRlcighQ29tcG91bmQgJWluJSB0b19yZW1vdmUpCmBgYAoKIyBWaXN1YWxpemUKIyMgU2NhdHRlciBwbG90cwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpob3Jpel9zY2F0dGVyIDwtIGZ1bmN0aW9uKCl7CiAgbGlzdCgKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpLAogICAgY29vcmRfZmxpcCgpLAogICAgbGFicyh4ID0gIkNvbXBvdW5kIE5hbWUiKSwKICAgIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBwYWxldHRlID0gNikKICApCn0KCnAgPC0gZ2dwbG90KGxjMywgYWVzKHggPSBDb21wb3VuZCwgeSA9IGNvbmMsIGxhYmVsID0gdW5pcXVlLmlkKSkgKyBob3Jpel9zY2F0dGVyKCkgKyB5bGFiKCJDb25jZW50cmF0aW9uICjCtWcvbWcpIikgKyB0aGVtZV9idygpCgpgYGAKSW50ZXJhY3RpdmUsIG5vdCBydW4gYnkgZGVmYXVsdC4KYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KcC5sYWIgPC0gZ2dsYWJlbGxlcihwKQpwLmxhYiRwbG90CmBgYAoKQ3JlYXRlZCB1c2luZyBjaHVuayBhYm92ZSBpbnRlcmFjdGl2ZWx5IGFuZCBjb3B5aW5nIGNvZGUgZnJvbSBgcC5sYWIkY29kZWA6CmBgYHtyfQpnZ2xhYmVsbGVyX2RhdGEgPC0gcCRkYXRhCmdnbGFiZWxsZXJfZGF0YVtjKDE6OTUsIDk3OjEwMCwgMTAyOjEyMSwgMTIzLCAxMjU6MTQzLCAxNDc6MTU0LCAxNTY6MzMzLCAzMzU6MzcxKSwndW5pcXVlLmlkJ10gPC0gJycKcCArIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZ2dsYWJlbGxlcl9kYXRhLG1hcHBpbmcgPSBhZXMoeCA9IENvbXBvdW5kLCB5ID0gY29uYywgbGFiZWwgPSB1bmlxdWUuaWQpLCBtaW4uc2VnbWVudC5sZW5ndGggPSB1bml0KDAuNSwgJ2xpbmVzJyksYm94LnBhZGRpbmcgPSB1bml0KDAuMjUsICdsaW5lcycpLHBvaW50LnBhZGRpbmcgPSB1bml0KDFlLTA2LCAnbGluZXMnKSkKYGBgCmM5IGFuZCBkMyBhcHBlYXIgdG8gYmUgcG9zc2libGUgb3V0bGllcnMuCgoKIyBNYWtlIHdpZGUgZGF0YSBhbmQgc2NhbGUKYGBge3J9CmxjX3dpZGUgPC0gbGMzICU+JSAKICBzZWxlY3QodW5pcXVlLmlkLCBTcHJheSwgVHJlYXRtZW50LCBDb21wb3VuZCwgY29uYykgJT4lIAogIHNwcmVhZChrZXkgPSBDb21wb3VuZCwgdmFsdWUgPSBjb25jKSAlPiUgCiAgdW5ncm91cCgpCgpsY193aWRlCmBgYAoKIyBQQ0EKYGBge3J9CmxjX3BjYSA8LSBvcGxzKHNlbGVjdF9pZihsY193aWRlLCBpcy5kb3VibGUpLCBwbG90TCA9IEZBTFNFLCBzY2FsZUMgPSAic3RhbmRhcmQiKQpwbG90KGxjX3BjYSwgcGFyQXNDb2xGY1ZuID0gbGNfd2lkZSRUcmVhdG1lbnQsIHBhckxhYlZjID0gbGNfd2lkZSR1bmlxdWUuaWQpCmBgYApgYGB7cn0Kb3V0bGllcnMgPC0gSERvdXRsaWVycyhzZWxlY3RfaWYobGNfd2lkZSwgaXMuZG91YmxlKSwgdHJhbnNmb3JtID0gRkFMU0UpCmxjX3dpZGVbb3V0bGllcnMsIF0KYGBgCgpkMyBhbmQgYzkgY29tZSBvdXQgYXMgb3V0bGllcnMuIFRoaXMgY29uZmlybXMgdW5pdmFyaWF0ZSBwbG90cy4gIFJlbW92ZSB0aGVtCgojIFJlbW92ZSBvdXRsaWVycwpgYGB7cn0Kb3V0bGllcnMgPC0gYygiZDMiLCAiYzkiKQpsY193aWRlMiA8LSBsY193aWRlICU+JSBmaWx0ZXIodW5pcXVlLmlkICUhaW4lIG91dGxpZXJzKQpsY19wY2EyIDwtIG9wbHMobGNfd2lkZTIgJT4lIHNlbGVjdF9pZihpcy5kb3VibGUpLCBwbG90TCA9IEZBTFNFLCBzY2FsZUMgPSAic3RhbmRhcmQiKQpwbG90KGxjX3BjYTIsIHBhckFzQ29sRmNWbiA9IGxjX3dpZGUyJFRyZWF0bWVudCwgcGFyTGFiVmMgPSBsY193aWRlMiR1bmlxdWUuaWQpCmBgYApObyBjbGVhciBzZXBhcmF0aW9uCgojIyBQcmV0dGllciBwbG90CgpJJ2QgbG92ZSB0byBzdHJlYW1saW5lIHRoaXMgZXhhY3QgcGxvdC4gIE1heWJlIEkgY2FuIHdyaXRlIGEgZnVuY3Rpb24gZm9yIGl0IHNvbWV0aW1lLgoKYGBge3J9CiNleHRyYWN0IHNjb3JlcyBhbmQgbWFrZSBpbnRvIGRhdGEgZnJhbWUKbGNfcGNhMl9zY29yZXMgPC0gbGNfcGNhMiAlPiUgZ2V0U2NvcmVNTigpICU+JSAKICBhc19kYXRhX2ZyYW1lKCkKI3Jlam9pbiB3aXRoIHNhbXBsZSBpbmZvCmxjX3BjYTJfc2NvcmVzIDwtIGJpbmRfY29scyhzZWxlY3RfaWYobGNfd2lkZTIsIG5vdF9kb3VibGUpLCBsY19wY2EyX3Njb3JlcykKbGNfcGNhMl9zY29yZXMgPC0gbGNfcGNhMl9zY29yZXMgJT4lIAogIG11dGF0ZSh0cmVhdGNvbWJvID0gcGFzdGUoVHJlYXRtZW50LCBTcHJheSkpCgojIHNldCB1cCBjb2xvcnMgYW5kIHNoYXBlcwpzcHJheXNoYXBlcyA8LSBjKCJNZUpBIiA9IDE3LCAiQ29udHJvbCIgPSAyMCkKdHJ0Y29scyA8LSBjKCIxMDAlIiA9ICJibHVlIiwgIjc1JSIgPSAiZGFya2dyZWVuIiwgIjUwJSIgPSAiZGFya29yYW5nZTMiKQojbWFrZSBiYXNlIHBsb3QKbGNfcGNhMl9wbG90IDwtIGdncGxvdChsY19wY2EyX3Njb3JlcywgYWVzKHggPSBwMSwgeSA9IHAyLCBzaGFwZSA9IFNwcmF5LCBjb2xvciA9IFRyZWF0bWVudCkpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIHN0YXRfZWxsaXBzZShhZXMoZ3JvdXAgPSBUcmVhdG1lbnQ6U3ByYXksIGxpbmV0eXBlID0gU3ByYXkpLCB0eXBlID0gInQiKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IHNwcmF5c2hhcGVzKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHRydGNvbHMpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaGFwZSA9IDE1LCBzaXplID0gNCwgbGluZXR5cGUgPSAwKSkpICsKICB4bGFiKHBhc3RlMCgiUEMxICgiLCBzaWduaWYobGNfcGNhMkBtb2RlbERGJFIyWFsxXSoxMDAsIGRpZ2l0cyA9IDIpLCAiJSkiKSkgKwogIHlsYWIocGFzdGUwKCJQQzIgKCIsIHNpZ25pZihsY19wY2EyQG1vZGVsREYkUjJYWzJdKjEwMCwgZGlnaXRzID0gMiksICIlKSIpKSArCiAgI3hsaW0oLTksIDgpICsgeWxpbSgtNSwgMTgpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkKYGBgCk1ha2UgdGhlIGxlZ2VuZCBtYW51YWxseSBhbmQgcGxvdCBpbnNpZGUgdGhlIG1haW4gcGxvdC4KYGBge3J9CmJhc2UgPC0gbGNfcGNhMl9wbG90ICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgI3N1cHByZXNzIGxlZ2VuZAogIHlsaW0oLTUsIDcpICNleHBhbmQgYXhlcyB0byBtYWtlIHJvb20gZm9yIGN1c3RvbSBsZWdlbmQKCiMgQ3JlYXRlIHNvbWUgZHVtbXkgZGF0YSBmb3IgbGVnZW5kCmxlZ2VuZC5kZiA8LSBkYXRhLmZyYW1lKHggPSBjKDEwLCAxMCksIHkgPSBjKDg1LCA4MCksIGxhYmVsID0gYygiTWVKQSIsICJDb250cm9sIikpCmxlZ2VuZC5kZjIgPC0gZGF0YS5mcmFtZSh4ID0gYygxMCwgMTAsIDEwKSwgeSA9IGMoNjUsIDYwLCA1NSksIGxhYmVsID0gYygiMTAwJSIsICI3NSUiLCAiNTAlIikpCgpsZWdlbmQgPC0gZ2dwbG90KGxlZ2VuZC5kZikgKwogIHhsaW0oMCwxMDApICsKICB5bGltKDAsMTAwKSArCiAgdGhlbWVfbm90aGluZygpICsgI2NvbW1lbnQgdGhpcyBsaW5lIG91dCB0byBnZXQgYSBiZXR0ZXIgaWRlYSBvZiB3aGF0IGlzIGhhcHBlbmluZwogICMgU2ltdWxhdGVkIGhlcmJpdm9yeSBsZWdlbmQKICBnZW9tX3RleHQoYWVzKHggPSAxMCwgeSA9IDkwLCBsYWJlbCA9ICJTaW11bGF0ZWQgSGVyYml2b3J5IiksICN0aXRsZQogICAgICAgICAgICBoanVzdCA9ICJsZWZ0IiwKICAgICAgICAgICAgc2l6ZSA9IDMuNSwKICAgICAgICAgICAgZGF0YSA9IGRhdGEuZnJhbWUoKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIGdlb21fdGV4dChhZXMoeCA9IHgsIHkgPSB5LCBsYWJlbCA9IGxhYmVsKSwgI2xhYmVscwogICAgICAgICAgICBoanVzdCA9ICJpbndhcmQiLCBudWRnZV94ID0gMTEsCiAgICAgICAgICAgIHNpemUgPSAzLjAsCiAgICAgICAgICAgIGRhdGEgPSBsZWdlbmQuZGYsIGluaGVyaXQuYWVzID0gRkFMU0UpICsgCiAgZ2VvbV9wb2ludChhZXMoeCA9IHgsIHkgPSB5LCBzaGFwZSA9IGxhYmVsKSwgI3NoYXBlcwogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gOCksCiAgICAgICAgICAgICBkYXRhID0gbGVnZW5kLmRmLCBpbmhlcml0LmFlcyA9IEZBTFNFKSArCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0geCwgeSA9IHksIHhlbmQgPSB4ICsgNSwgeWVuZCA9IHksIGxpbmV0eXBlID0gbGFiZWwpLCAjZWxsaXBzZSBsaW5lcwogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAxKSwKICAgICAgICAgICAgZGF0YSA9IGxlZ2VuZC5kZiwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBzcHJheXNoYXBlcykgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIsIDEpKSArCiAgCiAgIyBEcm91Z2h0IHRyZWF0bWVudCBsZWdlbmQKICBnZW9tX3RleHQoYWVzKHggPSAxMCwgeSA9IDcwLCBsYWJlbCA9ICIlIEFtYmllbnQgUmFpbmZhbGwiKSwgI3RpdGxlCiAgICAgICAgICAgIGhqdXN0ID0gImxlZnQiLAogICAgICAgICAgICBzaXplID0gMy41LAogICAgICAgICAgICBkYXRhID0gZGF0YS5mcmFtZSgpLAogICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0geCwgeSA9IHksIGxhYmVsID0gbGFiZWwpLCAjbGFiZWxzCiAgICAgICAgICAgIGhqdXN0ID0gImlud2FyZCIsCiAgICAgICAgICAgIG51ZGdlX3ggPSA1LAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgZGF0YSA9IGxlZ2VuZC5kZjIsIGluaGVyaXQuYWVzID0gRkFMU0UpICsKICBnZW9tX3BvaW50KGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gbGFiZWwpLCAjY29sb3Igc3dhdGNoZXMKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IDIuMyksCiAgICAgICAgICAgICBzaGFwZSA9IDE1LAogICAgICAgICAgICAgc2l6ZSA9IDMuNSwKICAgICAgICAgICAgIGRhdGEgPSBsZWdlbmQuZGYyLCBpbmhlcml0LmFlcyA9IEZBTFNFKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHRydGNvbHMpCgoKbGVnZW5kCgojb3ZlcmxheSBsZWdlbmQgb24gYmFzZSBwbG90CmxjX3BjYV9wbG90IDwtIGJhc2UgKyBkcmF3X3Bsb3QobGVnZW5kLCAtMS40LCAyLjQsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgc2NhbGUgPSAxMSkKbGNfcGNhX3Bsb3QKc2F2ZV9wbG90KGhlcmUoImZpZ3MiLCAiTENNUyBQQ0EucG5nIiksIGxjX3BjYV9wbG90LCBiYXNlX2FzcGVjdF9yYXRpbyA9IDEuMywgYmFzZV9oZWlnaHQgPSA1KQpgYGAKCgojIFBFUk1BTk9WQQojIyBUZXN0IGFzc3VtcHRpb25zCmBgYHtyfQpsY193aWRlMl9zY2FsZSA8LSBsY193aWRlMiAlPiUgbXV0YXRlX2lmKGlzLmRvdWJsZSwgc2NhbGUpCgojbXVsdGl2YXJpYXRlIGFuYWxvZyBvZiBMZXZlbmUncyBUZXN0IGZvciBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMtLWFuIGFzc3VtcHRpb24gb2YgUEVSTUFOT1ZBClBFUk1ESVNUIDwtIGJldGFkaXNwZXIodmVnZGlzdChzZWxlY3RfaWYobGNfd2lkZTJfc2NhbGUsIGlzLmRvdWJsZSksIG1ldGhvZCA9ICJldSIpLCBncm91cCA9IGxjX3dpZGUyX3NjYWxlJFRyZWF0bWVudCwgdHlwZSA9ICJjZW50cm9pZCIpCnBsb3QoUEVSTURJU1QpClBFUk1ESVNUCmFub3ZhKFBFUk1ESVNUKQojaWYgcCA8IDAuMDUgdGhlbiBkb2Vzbid0IHBhc3MgdGVzdC4KYGBgClBhc3NlcwoKYGBge3J9CmFkb25pczIoc2VsZWN0X2lmKGxjX3dpZGUyX3NjYWxlLCBpcy5kb3VibGUpIH4gVHJlYXRtZW50KlNwcmF5LCBtZXRob2QgPSAiZXVjbGlkZWFuIiwgYnkgPSAidGVybXMiLCBkYXRhID0gbGNfd2lkZTJfc2NhbGUpCmBgYApUcmVhdG1lbnQgaGFzIGJpZ2dlc3QgZWZmZWN0LCBidXQgbm90IHNpZ25pZmljYW50IHVubGVzcyBubyBkYXRhIGNlbnNvcmluZy4gIEluZGljYXRpbmcgaXRzIGxvdyBjb25jZW50cmF0aW9uIGNvbXBvdW5kcyB0aGF0IGFyZSBlZmZlY3RlZC4KCgojIFRhYmxlIFMyIGZvciBub24tdm9sYXRpbGVzCmBgYHtyfQpsY19maW5hbCA8LSBsYyAlPiUgZmlsdGVyKHVuaXF1ZS5pZCAlIWluJSBvdXRsaWVycykKCmxjX3N1bW1hcnkgPC0gbGNfZmluYWwgJT4lCiAgcmVwbGFjZV9uYShsaXN0KGNvbmMgPSAwLCBSU0QgPSAwKSkgJT4lIAogIGdyb3VwX2J5KENvbXBvdW5kLCBUcmVhdG1lbnQsIFNwcmF5KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fY29uYyA9IG1lYW4oY29uYywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgU0VNX2NvbmMgPSBzZChjb25jLCBuYS5ybSA9IFRSVUUpL3NxcnQobigpKSkKCnRhYmxlUzIgPC0gbGNfc3VtbWFyeSAlPiUKICBtdXRhdGUoYE1lYW4gQ29uY2VudHJhdGlvbiDCsSBTRU0gKMK1Zy9tZylgID0gcGFzdGUwKHJvdW5kKG1lYW5fY29uYywgMiksICIgwrEgIiwgcm91bmQoU0VNX2NvbmMsIDMpKSwKICAgICAgICAgdHJ0Y29tYm8gPSBwYXN0ZTAoVHJlYXRtZW50LCAiIHJhaW5mYWxsICsgIiwgU3ByYXkpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QoQ29tcG91bmQsIHRydGNvbWJvLCBgTWVhbiBDb25jZW50cmF0aW9uIMKxIFNFTSAowrVnL21nKWApICU+JSAKICBzcHJlYWQoa2V5ID0gdHJ0Y29tYm8sIHZhbHVlID0gYE1lYW4gQ29uY2VudHJhdGlvbiDCsSBTRU0gKMK1Zy9tZylgKQp0YWJsZVMyCndyaXRlX2V4Y2VsX2Nzdih0YWJsZVMyLCBoZXJlKCJmaWdzIiwgIlRhYmxlIDItTENNUyBjb21wb3VuZHMuY3N2IikpCmBgYAoKYGBge3J9CmxjX2ZpbmFsICU+JQogIGdyb3VwX2J5KENvbXBvdW5kKSAlPiUgCiAgc3VtbWFyaXplKG4gPSBzdW0oIWlzLm5hKGNvbmMpKSwKICAgICAgICAgICAgb3ZlckxPUSA9IHN1bSghYFVuZGVyIExPUWApKQpgYGAKCg==