Background

This project occurred during the summer of 2023 at the USDA Agricultural Research Services Fort Keogh Livestock and Range Research Laboratory, located in Miles City, MT. The purpose of this study is to determine the effects of fire on herbivory in the US Great Northern Plains.


Aboveground Biomass


Graphs

# Diagram showing methods

DiagrammeR::grViz("digraph {
  graph [center = TRUE, layout = dot, rankdir = TB]
  node [shape = rectangle]        
  rec1 [label = '1. Obtain clipping samples']
  rec2 [label = '2. Dry in oven for 48 hours']
  rec3 [label =  '3. Weigh samples']
  rec4 [label = '4. Analyze data in R Markdown']
  rec1 -> rec2 -> rec3 -> rec4
  }",
  height = 300)


# Load plot ID data

PlotID <-
  read_excel("LemonadeFireMasterData.xlsx",
             sheet = 'PlotID')

ID <- data.table(PlotID)
# Load bag mass data

BagMass <- 
  read_excel("LemonadeFireMasterData.xlsx",
             sheet = 'BagTares') %>%
  group_by(BagSize) %>%
  summarize(
    bagmass = mean(Mass))

# Load clipping data

ClipWeight <-
  read_excel("LemonadeFireMasterData.xlsx",
             sheet = 'ClipWeight')%>%
  mutate('ID' = paste(Location, Type, sep= " ")) %>%
  select( - Location,
          - Type) %>%
  data.table()

# Subtract bag weight from mass and conversions

ClipWeight <- 
  ClipWeight[ID, on = .(ID = LemonadeFireID)] %>%
  select(- PlotNumberPBG) %>%
  separate(AFRIname, c('SiteType', 'Replicate')) %>%
  separate(ID, c('Location', 'Type')) %>%
  select( - Replicate) %>%
  select(Location, Type, Quadrant, Nonant, MassGrams, BagSize, SiteType, BurnStatus, Month) %>%
  mutate(mass = case_when(
    BagSize ==
      "b"~MassGrams - filter(BagMass, BagSize == "b") $bagmass,
    BagSize ==
      "l" ~ MassGrams - filter(BagMass, BagSize == "l") $bagmass,
     BagSize ==
      "p"~MassGrams - filter(BagMass, BagSize == "p") $bagmass,
  )) %>%
  select( - MassGrams, - BagSize) %>%
  mutate(g1m2 = (mass / 0.05),
         KgHa = (g1m2 * 10),
         tac = (KgHa * 0.000404686))

# Plot difference in aboveground biomass between paired plots

ClipWeight %>%
  group_by(Location, SiteType, BurnStatus, Type) %>%
  summarise(
    meantac = mean(tac)) %>%
  pivot_wider(values_from = meantac,
              names_from = Type) %>%
  mutate(dif = ((E - O) / E) * 100) %>%
  ggplot(aes(x = dif,
             y = Location,
             color = SiteType)) + 
  labs(y = "", 
       x = "((E - O) / E) * 100%)",
       fill = "Ecological site",
       caption = "Fig. 1. Difference in aboveground biomass between paired open areas and exclosures.") +
  geom_vline(xintercept = 0, size = .3) +
  geom_label(aes(label = Location,
                 fill = factor(SiteType)),
             colour = "white",
             fontface = "bold") +
  theme(legend.position = "bottom",
        legend.direction = 'horizontal',
        legend.box = "horizontal",
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_rect(fill = "white",
                                        colour = "black",
                                        size = 0.5, linetype = "solid"),
        panel.grid.major = element_line(size = 0.1,
                                        linetype = 'solid',
                                        color = 'black'),
        panel.grid.minor = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank(),
        axis.line = element_line(color="black", size = .5),
        plot.margin = unit(c(0.1, 0.5, 0.1, 0.2),
                                "inches"),
        plot.caption = element_text(hjust = .45, size = 12)) +
  guides(fill = guide_legend(byrow = TRUE, override.aes = aes(label = "")))+
  scale_x_continuous(limits=c(-91, 91))


# Graph of burned vs unburned facet_wrap eco site

ClipWeight %>%
  group_by(Type, SiteType, BurnStatus, Month) %>%
  filter(Type == 'O') %>%
  mutate(BurnStatus =
           recode(BurnStatus,
                   "burned"="Burned",
                   "unburned"="Unburned")) %>%
  mutate(SiteType =
           recode(SiteType,
                  "sandy"="Sandy",
                  "silty"="Silty",
                  "steep"="Steep",
                  "shallow"="Shallow")) %>%
  summarise(
     meantac = mean(tac), 
     semtac = sd(tac) / sqrt(length(tac))) %>%
 ggplot(aes(x = Month, fill = BurnStatus)) + theme_bw(14) + 
      geom_line(aes(y = meantac,
                    color = BurnStatus,
                    group = BurnStatus),
                position = position_dodge(width = 0.3)) +
      geom_errorbar(aes(ymin = meantac - semtac,
                        ymax = meantac + semtac,
                        group = BurnStatus,
                        color = BurnStatus),
                    width = 0.15,
                    position = position_dodge(width = 0.3)) +
      geom_point(aes(y = meantac,
                 bg = BurnStatus,
                 shape = BurnStatus),
                 colour="black",
                 size=2.5, stroke = 1.1,
                 position = position_dodge(width = 0.3)) +
      facet_wrap(~SiteType) +
      labs(x = "Time",
           y = "Aboveground biomass (t/ac)",
           caption = "Fig. 2. Aboveground biomass at burned and unburned plots open to grazing.") +
  scale_color_manual('Burn status', values = wes_palette("Zissou1")[c(3, 5)]) +
  scale_fill_manual('Burn status', values = wes_palette("Zissou1")[c(3, 5)]) +
  scale_shape_manual('Burn status', values = c(21, 24)) + 
  scale_alpha_manual('Burn status', values = c(0.6, 0.6)) +
      theme(legend.position = "bottom",
            legend.direction = 'horizontal',
            legend.box = "horizontal",
            panel.grid.minor.x = element_blank(),
            legend.spacing.y = unit(0, "mm"),
            panel.border = element_rect(colour = "black", fill=NA),
            legend.background = element_blank(),
            plot.caption = element_text(hjust = .2, size = 12)) +
  scale_x_discrete(limits = c("May", "June", "July"))

# Facet grid of burn status and graze status

ClipWeight %>%
  select(Location, Type, SiteType, BurnStatus, Month, Quadrant, Nonant, tac)%>%
  filter(Type == 'E') %>%
  group_by(Location, Quadrant, Nonant) %>%
  filter(n()== 1) %>%
  group_by(Type, SiteType, BurnStatus, Month) %>%
  mutate(BurnStatus =
           recode(BurnStatus,
                   "burned"="Burned",
                   "unburned"="Unburned")) %>%
  mutate(SiteType =
           recode(SiteType,
                  "sandy"="Sandy",
                  "silty"="Silty",
                  "steep"="Steep",
                  "shallow"="Shallow")) %>%
  summarise(
     meantac = mean(tac), 
     semtac = sd(tac) / sqrt(length(tac))) %>%
 ggplot(aes(x = Month, fill = BurnStatus)) + theme_bw(14) + 
      geom_line(aes(y = meantac,
                    color = BurnStatus,
                    group = BurnStatus),
                position = position_dodge(width = 0.3)) +
      geom_errorbar(aes(ymin = meantac - semtac,
                        ymax = meantac + semtac,
                        group = BurnStatus,
                        color = BurnStatus),
                    width = 0.15,
                    position = position_dodge(width = 0.3)) +
      geom_point(aes(y = meantac,
                 bg = BurnStatus,
                 shape = BurnStatus),
                 colour="black",
                 size=2.5, stroke = 1.1,
                 position = position_dodge(width = 0.3)) +
      facet_wrap(~SiteType) +
      labs(x = "Time",
           y = "Aboveground biomass (t/ac)",
           caption = "Fig. 3. biomass growth in burned and unburned exclosures.") +
  scale_color_manual('Burn status', values = wes_palette("Zissou1")[c(3, 5)]) +
  scale_fill_manual('Burn status', values = wes_palette("Zissou1")[c(3, 5)]) +
  scale_shape_manual('Burn status', values = c(21, 24)) + 
  scale_alpha_manual('Burn status', values = c(0.6, 0.6)) +
      theme(legend.position = "bottom",
            legend.direction = 'horizontal',
            legend.box = "horizontal",
            panel.grid.minor.x = element_blank(),
            legend.spacing.y = unit(0, "mm"),
            panel.border = element_rect(colour = "black", fill=NA),
            legend.background = element_blank(),
            plot.caption = element_text(hjust = .45, size = 12)) +
  scale_x_discrete(limits = c("May", "June", "July"))


Statistics


Descriptive Statistics

# Descriptive stats

stat.desc(ClipWeight$tac)
##      nbr.val     nbr.null       nbr.na          min          max        range 
## 5.940000e+02 0.000000e+00 0.000000e+00 9.064966e-03 3.231175e+00 3.222110e+00 
##          sum       median         mean      SE.mean CI.mean.0.95          var 
## 5.192136e+02 7.101430e-01 8.740970e-01 2.530921e-02 4.970660e-02 3.804905e-01 
##      std.dev     coef.var 
## 6.168391e-01 7.056873e-01


Histogram with Normal Curve

# Histogram showing data distribution and normality curve

ClipWeight %>%
  ggplot(aes(x = tac)) + theme_bw(16) + 
  geom_histogram(aes(y = after_stat(.data[["density"]])),
                 binwidth = .1,
                 colour = "black",
                 fill = "lightyellow")+
  geom_density(alpha = .5, fill = "lightblue") +
  stat_function(fun = dnorm,
                args = list(mean = 0.72625780,
                            sd = 0.50911132),
                colour = "red",
                linewidth = 1.1) +
  labs(y = "Density", 
       x = "Aboveground biomass (t/ac)")


Ratio between Mean and Median

# Ratio between mean and median

knitr::kable(tibble(Mean = mean(ClipWeight$tac),
                    Median = median(ClipWeight$tac),
                    Ratio = Mean/Median))
Mean Median Ratio
0.874097 0.710143 1.230875


Skewness

# Skewness

skewness(ClipWeight$tac)
## [1] 1.220551


Kurtosis

# Kurtosis

kurtosis(ClipWeight$tac)
## [1] 4.416548


Kolmogorov-Smirnov Test

# Kolmogorov-Smirnov test

KSClip <-
  ks.test(ClipWeight$tac, "pnorm")

pander(KSClip)
Asymptotic one-sample Kolmogorov-Smirnov test: ClipWeight$tac
Test statistic P value Alternative hypothesis
0.5381 0 * * * two-sided


QQ-Plot

# QQ-plot

car::qqPlot(ClipWeight$tac, xlab = "Theoretical Quantiles", ylab = "Sample Quantiles")


Logarithmic Transformation

# Logarithmic transformation

SqRtClip <-
ClipWeight %>%
  mutate(SqRttac =  sqrt(tac))


Descriptive Statistics

# Descriptive stats

stat.desc(SqRtClip$SqRttac)
##      nbr.val     nbr.null       nbr.na          min          max        range 
## 594.00000000   0.00000000   0.00000000   0.09521012   1.79754691   1.70233679 
##          sum       median         mean      SE.mean CI.mean.0.95          var 
## 522.21070183   0.84269980   0.87914260   0.01306394   0.02565722   0.10137592 
##      std.dev     coef.var 
##   0.31839586   0.36216635


Histogram with Normal Curve

# Histogram showing data distribution and normality curve

SqRtClip %>%
  ggplot(aes(x = SqRttac)) + theme_bw(16) + 
  geom_histogram(aes(y = after_stat(.data[["density"]])),      
                 binwidth = .1,
                 colour = "black",
                 fill = "lightyellow")+
  geom_density(alpha = .5, fill = "lightblue") +
  stat_function(fun = dnorm,
                args = list(mean = 0.87914260,
                          sd = 0.31839586),
                colour = "red",
                linewidth = 1.1) +
  labs(y = "Density", 
       x = "Log aboveground biomass (t/ac)")


Ratio between Mean and Median

# Ratio between mean and median

knitr::kable(tibble(MeanSqRt = mean(SqRtClip$SqRttac),
                    MedianSqRt = median(SqRtClip$SqRttac),
                    RatioSqRt = MeanSqRt/MedianSqRt))
MeanSqRt MedianSqRt RatioSqRt
0.8791426 0.8426998 1.043245


Skewness

# Skewness

skewness(SqRtClip$SqRttac)
## [1] 0.4340627


Kurtosis

# Kurtosis

kurtosis(SqRtClip$SqRttac)
## [1] 2.740046


Kolmogorov-Smirnov Test

# Kolmogorov-Smirnov test

KSLogClip <-
  ks.test(SqRtClip$SqRttac, "pnorm")

pander(KSLogClip)
Asymptotic one-sample Kolmogorov-Smirnov test: SqRtClip$SqRttac
Test statistic P value Alternative hypothesis
0.6289 0 * * * two-sided


QQ-Plot

# QQ-plot

car::qqPlot(SqRtClip$SqRttac, xlab = "Theoretical Quantiles", ylab = "Sample Quantiles")


Soil Moisture


Graphs

# Diagram showing methods

DiagrammeR::grViz("digraph {
  graph [center = TRUE, layout = dot, rankdir = TB]
  node [shape = rectangle]        
  rec1 [label = '1. Obtain soil moisture data']
  rec2 [label = '2. Enter data in Excel']
  rec3 [label =  '3. Analyze data in R Markdown']
  rec1 -> rec2 -> rec3
  }",
  height = 225)


# Load soil moisture data

SoilMoist <-
  read_excel("LemonadeFireMasterData.xlsx", sheet = "SoilMoist") %>%
  mutate('ID' = paste(Location, Type, sep= " ")) %>%
  select( - Location,
          - Type)%>%
  data.table()

# Cross reference moisture data with ID data

SoilMoist <- 
  SoilMoist[ID, on = .(ID = LemonadeFireID)] %>%
  select(- PlotNumberPBG) %>%
  separate(AFRIname, c('SiteType', 'Replicate')) %>%
  select( - Replicate)

# Plot difference in % soil moisture between paired plots

SoilMoist %>%
  group_by(Location, SiteType, BurnStatus, GrazeStatus) %>%
  summarise(
    meanmois = mean(Moist)) %>%
  pivot_wider(values_from = meanmois,
              names_from = GrazeStatus) %>%
  mutate(dif = ((grazed - ungrazed) / ungrazed) * 100) %>%
  ggplot(aes(x = dif,
             y = Location,
             color = SiteType)) + 
  labs(y = "", 
       x = "((E - O) / E) * 100%)",
       fill = "Ecological Site",
       caption = "Fig. 4. Difference in soil moisture between paired open areas and exclosures.") +
  geom_vline(xintercept = 0, size = .3) +
  geom_label(aes(label = Location,
                fill = factor(SiteType)),
             colour = "white",
             fontface = "bold") +
  theme(legend.position = "bottom",
        legend.direction = 'horizontal',
        legend.box = "horizontal",
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_rect(fill = "white",
                                        colour = "black",
                                        size = 0.5, linetype = "solid"),
        panel.grid.major = element_line(size = 0.1,
                                        linetype = 'solid',
                                        color = 'black'),
        panel.grid.minor = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank(),
        axis.line = element_line(color="black", size = .5),
        plot.margin = unit(c(0.1, 0.5, 0.1, 0.2),
                                "inches"),
        plot.caption = element_text(hjust = .45, size = 12)) +
  guides(fill = guide_legend(byrow = TRUE, override.aes = aes(label = "")))+
  scale_x_continuous(limits=c(-91, 91))


# Facet grid of burn status and graze status

SoilMoist %>%
  group_by(Type, SiteType, BurnStatus, Month) %>%
  filter(Type == 'O') %>%
  mutate(BurnStatus =
           recode(BurnStatus,
                   "burned"="Burned",
                   "unburned"="Unburned")) %>%
  mutate(SiteType =
           recode(SiteType,
                  "sandy"="Sandy",
                  "silty"="Silty",
                  "steep"="Steep",
                  "shallow"="Shallow")) %>%
  summarise(
    meanmoist = mean(Moist), 
    semmoist = sd(Moist) / sqrt(length(Moist))) %>%
 ggplot(aes(x = Month, fill = BurnStatus)) + theme_bw(14) + 
      geom_line(aes(y = meanmoist,
                    color = BurnStatus,
                    group = BurnStatus),
                position = position_dodge(width = 0.3)) +
      geom_errorbar(aes(ymin = meanmoist - semmoist,
                        ymax = meanmoist + semmoist,
                        group = BurnStatus,
                        color = BurnStatus),
                    width = 0.15,
                    position = position_dodge(width = 0.3)) +
      geom_point(aes(y = meanmoist,
                 bg = BurnStatus,
                 shape = BurnStatus),
                 colour="black",
                 size = 2.5, stroke = 1.1,
                 position = position_dodge(width = 0.3)) +
      facet_wrap(~SiteType) +
      labs(x = "Time",
           y = "% soil moisture",
           caption = "Fig. 5. Soil moisture in burned and unburned locations.") +
  scale_color_manual('Burn status', values = wes_palette("Zissou1")[c(3, 5)]) +
  scale_fill_manual('Burn status', values = wes_palette("Zissou1")[c(3, 5)]) +
  scale_shape_manual('Burn status', values = c(21, 24)) + 
  scale_alpha_manual('Burn status', values = c(0.6, 0.6)) +
      theme(legend.position = "bottom",
            legend.direction = 'horizontal',
            legend.box = "horizontal",
            panel.grid.minor.x = element_blank(),
            legend.spacing.y = unit(0, "mm"),
            panel.border = element_rect(colour = "black", fill=NA),
            legend.background = element_blank(),
            plot.caption = element_text(hjust = .45, size = 12)) +
  scale_x_discrete(limits = c("May", "June", "July"))

Statistics

Descriptive Statistics

# Descriptive stats

stat.desc(SoilMoist$Moist)
##      nbr.val     nbr.null       nbr.na          min          max        range 
## 9.000000e+02 6.100000e+01 0.000000e+00 0.000000e+00 6.000000e+01 6.000000e+01 
##          sum       median         mean      SE.mean CI.mean.0.95          var 
## 1.141510e+04 1.040000e+01 1.268344e+01 3.420047e-01 6.712206e-01 1.052705e+02 
##      std.dev     coef.var 
## 1.026014e+01 8.089397e-01


Histogram with Normal Curve

# Histogram showing data distribution and normality curve

SoilMoist %>%
  ggplot(aes(x = Moist)) + theme_bw(16) +
  geom_histogram(aes(y = after_stat(.data[["density"]])),
                 binwidth = 3,
                 colour = "black",
                 fill = "lightyellow")+
  geom_density(alpha = .5, fill = "lightblue") +
  stat_function(fun = dnorm,
                args = list(mean = 17.5430556,
                          sd = 10.9276183),
                colour = "red",
                linewidth = 1.1) +
  labs(y = "Density", 
       x = "% soil moisture")


QQ-Plot

# QQ-plot

car::qqPlot(SoilMoist$Moist, xlab = "Theoretical Quantiles", ylab = "Sample Quantiles")


Ratio between Mean and Median

knitr::kable(tibble(Mean = mean(SoilMoist$Moist),
                    Median = median(SoilMoist$Moist),
                    Ratio = Mean/Median))
Mean Median Ratio
12.68344 10.4 1.219562


Skewness

# Skewness

skewness(SoilMoist$Moist)
## [1] 1.463398


Kurtosis

# Kurtosis

kurtosis(SoilMoist$Moist)
## [1] 5.687223


Kolmogorov-Smirnov Test

# Kolmogorov-Smirnov test

KSMoist <-
  ks.test(SoilMoist$Moist, "pnorm")

pander(KSMoist)
Asymptotic one-sample Kolmogorov-Smirnov test: SoilMoist$Moist
Test statistic P value Alternative hypothesis
0.8893 0 * * * two-sided


Square Root Transformation

# Square root transformation

SRMoist <-
SoilMoist %>%
  mutate(SqRtMoist =  sqrt(Moist))


Descriptive Statistics

# Descriptive stats

stat.desc(SRMoist$SqRtMoist)
##      nbr.val     nbr.null       nbr.na          min          max        range 
## 9.000000e+02 6.100000e+01 0.000000e+00 0.000000e+00 7.745967e+00 7.745967e+00 
##          sum       median         mean      SE.mean CI.mean.0.95          var 
## 2.905259e+03 3.224903e+00 3.228065e+00 5.017256e-02 9.846899e-02 2.265558e+00 
##      std.dev     coef.var 
## 1.505177e+00 4.662784e-01


Histogram with Normal Curve

# Histogram showing data distribution and normality curve

SRMoist %>%
  ggplot(aes(x = SqRtMoist)) + 
  theme_bw(16) + 
  geom_histogram(aes(y = after_stat(.data[["density"]])),
                 binwidth = .4,
                 colour = "black",
                 fill = "lightyellow")+
  geom_density(alpha = .5, fill = "lightblue")+
  stat_function(fun = dnorm,
                args = list(mean = 3.55608073,
                          sd = 1.33445545),
                colour = "red",
                linewidth = 1.1) +
  labs(y = "Density", 
       x = "Log % soil moisture")


Ratio between Mean and Median

# Ratio between mean and median

knitr::kable(tibble(Mean = mean(SRMoist$SqRtMoist),
                    Median = median(SRMoist$SqRtMoist),
                    Ratio = Mean/Median))
Mean Median Ratio
3.228065 3.224903 1.000981


Skewness

# Skewness

skewness(SRMoist$SqRtMoist)
## [1] -0.01944163


Kurtosis

# Kurtosis

kurtosis(SRMoist$SqRtMoist)
## [1] 3.28084


Kolmogorov-Smirnov Test

# Kolmogorov-Smirnov test

KSSqRtMoist <-
  ks.test(SRMoist$SqRtMoist, "pnorm")

pander(KSSqRtMoist)
Asymptotic one-sample Kolmogorov-Smirnov test: SRMoist$SqRtMoist
Test statistic P value Alternative hypothesis
0.8353 0 * * * two-sided


QQ-Plot

# QQ-plot

car::qqPlot(SRMoist$SqRtMoist, xlab = "Theoretical Quantiles", ylab = "Sample Quantiles")

LS0tDQp0aXRsZTogIlJhbmdlbGFuZCByZXNwb25zZSB0byBmaXJlIGFuZCBoZXJiaXZvcnkiDQphdXRob3I6ICJbTm9haCBDLiBXZWlkaWddKGh0dHBzOi8vbm9haHdlaWRpZy5jb20vKSB8IFtVU0RBLCBBZ3JpY3VsdHVyYWwgUmVzZWFyY2ggU2VydmljZXMsIE1pbGVzIENpdHksIE1UIFVTQV0oaHR0cHM6Ly93d3cuYXJzLnVzZGEuZ292L3BsYWlucy1hcmVhL21pbGVzLWNpdHktbXQvbGFycmwvKSINCmRhdGU6ICJMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIGF0IGByIGZvcm1hdChTeXMudGltZSgpLCAnJUk6JU0gJXAnKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBGQUxTRQ0KICAgIHRvY19mbG9hdDogRkFMU0UNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0aGVtZTogZGVmYXVsdA0KICAgIGhpZ2hsaWdodDogZGVmYXVsdA0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogRkFMU0UNCiAgICBpbmNsdWRlOg0KICAgICAgYWZ0ZXJfYm9keTogZm9vdGVyLmh0bWwNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGUgdHlwZSA9ICJ0ZXh0L2NzcyI+DQoNCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiAzOHB4Ow0KICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmF1dGhvciB7DQogICAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IEJsYWNrOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsNCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IEJsYWNrOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoubmF2LXBpbGxzPmxpPmEgew0KICAgICBjb2xvcjogRGFya1JlZDsNCiAgICAgfQ0KLm5hdi1waWxscz5saT5hOmhvdmVyLCAubmF2LXBpbGxzPmxpPmE6Zm9jdXMsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmEsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmE6aG92ZXIsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmE6Zm9jdXN7DQogICAgIGNvbG9yOiBXaGl0ZTsNCiAgICAgYmFja2dyb3VuZC1jb2xvcjogRGFya1JlZDsNCiAgICAgfQ0KLm5hdi1waWxscyA+IGxpOm50aC1vZi10eXBlKDIpPmEgew0KICAgICBjb2xvcjogRGFya1JlZDsNCiAgICAgfQ0KLm5hdi1waWxscyA+IGxpOm50aC1vZi10eXBlKDIpPmE6aG92ZXIsIC5uYXYtcGlsbHMgPiBsaTpudGgtb2YtdHlwZSgyKT5hOmZvY3VzLCAubmF2LXBpbGxzID4gbGk6bnRoLW9mLXR5cGUoMikuYWN0aXZlPmEgew0KICAgICBjb2xvcjogV2hpdGU7DQogICAgIGJhY2tncm91bmQtY29sb3I6IERhcmtSZWQ7fQ0KLm5hdi1waWxscyA+IGxpOm5vdCguYWN0aXZlKSBhIHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjRUNFQ0VDOw0KICAgIGNvbG9yOiBEYXJrUmVkOw0KfQ0KLm5hdi1waWxscz5saTpub3QoLmFjdGl2ZSkgYTpob3ZlciB7DQogICAgYmFja2dyb3VuZC1jb2xvcjogI0RBREFEQTsNCiAgICBjb2xvcjogRGFya1JlZDsNCn0NCi5uYXYtcGlsbHMgew0KICAgIGRpc3BsYXk6IGZsZXg7DQogICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7DQp9DQouaHRtbC13aWRnZXQgew0KICAgIG1hcmdpbjogYXV0bzsNCn0NCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCg0KIyBHZW5lcmFsIHNjcmlwdCBzZXR1cA0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQoJZWNobyA9IFRSVUUsDQoJbWVzc2FnZSA9IEZBTFNFLA0KCXdhcm5pbmcgPSBUUlVFDQopDQpgYGANCg0KYGBge2NzcywgZWNobz1GQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInfQ0KDQpoMSwgaDIsIGgzLCBoNCwgaDQsIGg1IHsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KYGBgDQoNCjxicj4NCg0KYGBge3IgUGFja2FnZXMsIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPVRSVUV9DQoNCiMgTG9hZCBhIGhlYWRlciBpbWFnZQ0KIyBJbnN0YWxsIGFuZCBsb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcw0KDQpwYWNtYW46OnBfbG9hZCh0aWR5dmVyc2UsIHJlYWR4bCwga25pdHIsIGRwbHlyLCBkYXRhLnRhYmxlLCBzY2FsZXMsIERpYWdyYW1tZVIsIG1vbWVudHMsIHBhc3RlY3MsIHBuZywgZ3JpZCwgcGFuZGVyLCByc3RhdGl4LCBnZ3B1YnIpDQoNCnBhY21hbjo6cF9sb2FkX2doKCJkZXZhbm1jZy93ZXNhbmRlcnNvbiIpDQoNCmltZyA8LSByZWFkUE5HKCJSYW5nbGFuZC5wbmciKQ0KDQpncmlkLnJhc3RlcihpbWcpDQoNCiMgaGlkZSBkcGx5ciBzdW1tYXJ5IGluZm8NCg0Kb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpDQpgYGANCg0KPGJyPg0KDQojIyBCYWNrZ3JvdW5kDQoNClRoaXMgcHJvamVjdCBvY2N1cnJlZCBkdXJpbmcgdGhlIHN1bW1lciBvZiAyMDIzIGF0IHRoZSBVU0RBIEFncmljdWx0dXJhbCBSZXNlYXJjaCBTZXJ2aWNlcyBGb3J0IEtlb2doIExpdmVzdG9jayBhbmQgUmFuZ2UgUmVzZWFyY2ggTGFib3JhdG9yeSwgbG9jYXRlZCBpbiBNaWxlcyBDaXR5LCBNVC4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBzdHVkeSBpcyB0byBkZXRlcm1pbmUgdGhlIGVmZmVjdHMgb2YgZmlyZSBvbiBoZXJiaXZvcnkgaW4gdGhlIFVTIEdyZWF0IE5vcnRoZXJuIFBsYWlucy4NCg0KPGJyPg0KDQojIyBBYm92ZWdyb3VuZCBCaW9tYXNzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQo8YnI+DQoNCiMjIyBHcmFwaHMNCg0KYGBge3IgQ2xpcHBpbmdEaWFncmFtLCBlY2hvPVRSVUUsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInfQ0KDQojIERpYWdyYW0gc2hvd2luZyBtZXRob2RzDQoNCkRpYWdyYW1tZVI6OmdyVml6KCJkaWdyYXBoIHsNCiAgZ3JhcGggW2NlbnRlciA9IFRSVUUsIGxheW91dCA9IGRvdCwgcmFua2RpciA9IFRCXQ0KICBub2RlIFtzaGFwZSA9IHJlY3RhbmdsZV0gICAgICAgIA0KICByZWMxIFtsYWJlbCA9ICcxLiBPYnRhaW4gY2xpcHBpbmcgc2FtcGxlcyddDQogIHJlYzIgW2xhYmVsID0gJzIuIERyeSBpbiBvdmVuIGZvciA0OCBob3VycyddDQogIHJlYzMgW2xhYmVsID0gICczLiBXZWlnaCBzYW1wbGVzJ10NCiAgcmVjNCBbbGFiZWwgPSAnNC4gQW5hbHl6ZSBkYXRhIGluIFIgTWFya2Rvd24nXQ0KICByZWMxIC0+IHJlYzIgLT4gcmVjMyAtPiByZWM0DQogIH0iLA0KICBoZWlnaHQgPSAzMDApDQpgYGANCg0KPGJyPg0KDQpgYGB7ciBDbGlwRGlmZiwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGZpZy53aWR0aD03LGZpZy5oZWlnaHQ9NS41fQ0KDQojIExvYWQgcGxvdCBJRCBkYXRhDQoNClBsb3RJRCA8LQ0KICByZWFkX2V4Y2VsKCJMZW1vbmFkZUZpcmVNYXN0ZXJEYXRhLnhsc3giLA0KICAgICAgICAgICAgIHNoZWV0ID0gJ1Bsb3RJRCcpDQoNCklEIDwtIGRhdGEudGFibGUoUGxvdElEKQ0KIyBMb2FkIGJhZyBtYXNzIGRhdGENCg0KQmFnTWFzcyA8LSANCiAgcmVhZF9leGNlbCgiTGVtb25hZGVGaXJlTWFzdGVyRGF0YS54bHN4IiwNCiAgICAgICAgICAgICBzaGVldCA9ICdCYWdUYXJlcycpICU+JQ0KICBncm91cF9ieShCYWdTaXplKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGJhZ21hc3MgPSBtZWFuKE1hc3MpKQ0KDQojIExvYWQgY2xpcHBpbmcgZGF0YQ0KDQpDbGlwV2VpZ2h0IDwtDQogIHJlYWRfZXhjZWwoIkxlbW9uYWRlRmlyZU1hc3RlckRhdGEueGxzeCIsDQogICAgICAgICAgICAgc2hlZXQgPSAnQ2xpcFdlaWdodCcpJT4lDQogIG11dGF0ZSgnSUQnID0gcGFzdGUoTG9jYXRpb24sIFR5cGUsIHNlcD0gIiAiKSkgJT4lDQogIHNlbGVjdCggLSBMb2NhdGlvbiwNCiAgICAgICAgICAtIFR5cGUpICU+JQ0KICBkYXRhLnRhYmxlKCkNCg0KIyBTdWJ0cmFjdCBiYWcgd2VpZ2h0IGZyb20gbWFzcyBhbmQgY29udmVyc2lvbnMNCg0KQ2xpcFdlaWdodCA8LSANCiAgQ2xpcFdlaWdodFtJRCwgb24gPSAuKElEID0gTGVtb25hZGVGaXJlSUQpXSAlPiUNCiAgc2VsZWN0KC0gUGxvdE51bWJlclBCRykgJT4lDQogIHNlcGFyYXRlKEFGUkluYW1lLCBjKCdTaXRlVHlwZScsICdSZXBsaWNhdGUnKSkgJT4lDQogIHNlcGFyYXRlKElELCBjKCdMb2NhdGlvbicsICdUeXBlJykpICU+JQ0KICBzZWxlY3QoIC0gUmVwbGljYXRlKSAlPiUNCiAgc2VsZWN0KExvY2F0aW9uLCBUeXBlLCBRdWFkcmFudCwgTm9uYW50LCBNYXNzR3JhbXMsIEJhZ1NpemUsIFNpdGVUeXBlLCBCdXJuU3RhdHVzLCBNb250aCkgJT4lDQogIG11dGF0ZShtYXNzID0gY2FzZV93aGVuKA0KICAgIEJhZ1NpemUgPT0NCiAgICAgICJiIn5NYXNzR3JhbXMgLSBmaWx0ZXIoQmFnTWFzcywgQmFnU2l6ZSA9PSAiYiIpICRiYWdtYXNzLA0KICAgIEJhZ1NpemUgPT0NCiAgICAgICJsIiB+IE1hc3NHcmFtcyAtIGZpbHRlcihCYWdNYXNzLCBCYWdTaXplID09ICJsIikgJGJhZ21hc3MsDQogICAgIEJhZ1NpemUgPT0NCiAgICAgICJwIn5NYXNzR3JhbXMgLSBmaWx0ZXIoQmFnTWFzcywgQmFnU2l6ZSA9PSAicCIpICRiYWdtYXNzLA0KICApKSAlPiUNCiAgc2VsZWN0KCAtIE1hc3NHcmFtcywgLSBCYWdTaXplKSAlPiUNCiAgbXV0YXRlKGcxbTIgPSAobWFzcyAvIDAuMDUpLA0KICAgICAgICAgS2dIYSA9IChnMW0yICogMTApLA0KICAgICAgICAgdGFjID0gKEtnSGEgKiAwLjAwMDQwNDY4NikpDQoNCiMgUGxvdCBkaWZmZXJlbmNlIGluIGFib3ZlZ3JvdW5kIGJpb21hc3MgYmV0d2VlbiBwYWlyZWQgcGxvdHMNCg0KQ2xpcFdlaWdodCAlPiUNCiAgZ3JvdXBfYnkoTG9jYXRpb24sIFNpdGVUeXBlLCBCdXJuU3RhdHVzLCBUeXBlKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW50YWMgPSBtZWFuKHRhYykpICU+JQ0KICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IG1lYW50YWMsDQogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBUeXBlKSAlPiUNCiAgbXV0YXRlKGRpZiA9ICgoRSAtIE8pIC8gRSkgKiAxMDApICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBkaWYsDQogICAgICAgICAgICAgeSA9IExvY2F0aW9uLA0KICAgICAgICAgICAgIGNvbG9yID0gU2l0ZVR5cGUpKSArIA0KICBsYWJzKHkgPSAiIiwgDQogICAgICAgeCA9ICIoKEUgLSBPKSAvIEUpICogMTAwJSkiLA0KICAgICAgIGZpbGwgPSAiRWNvbG9naWNhbCBzaXRlIiwNCiAgICAgICBjYXB0aW9uID0gIkZpZy4gMS4gRGlmZmVyZW5jZSBpbiBhYm92ZWdyb3VuZCBiaW9tYXNzIGJldHdlZW4gcGFpcmVkIG9wZW4gYXJlYXMgYW5kIGV4Y2xvc3VyZXMuIikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBzaXplID0gLjMpICsNCiAgZ2VvbV9sYWJlbChhZXMobGFiZWwgPSBMb2NhdGlvbiwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihTaXRlVHlwZSkpLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAnaG9yaXpvbnRhbCcsDQogICAgICAgIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41LCBsaW5ldHlwZSA9ICJzb2xpZCIpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAnc29saWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ2JsYWNrJyksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3I9ImJsYWNrIiwgc2l6ZSA9IC41KSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMC4xLCAwLjUsIDAuMSwgMC4yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImluY2hlcyIpLA0KICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAuNDUsIHNpemUgPSAxMikpICsNCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQoYnlyb3cgPSBUUlVFLCBvdmVycmlkZS5hZXMgPSBhZXMobGFiZWwgPSAiIikpKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKC05MSwgOTEpKQ0KYGBgDQoNCjxicj4NCg0KYGBge3IgQ2xpcEZhY2V0LCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZmlnLndpZHRoPTcsZmlnLmhlaWdodD02LjV9DQoNCiMgR3JhcGggb2YgYnVybmVkIHZzIHVuYnVybmVkIGZhY2V0X3dyYXAgZWNvIHNpdGUNCg0KQ2xpcFdlaWdodCAlPiUNCiAgZ3JvdXBfYnkoVHlwZSwgU2l0ZVR5cGUsIEJ1cm5TdGF0dXMsIE1vbnRoKSAlPiUNCiAgZmlsdGVyKFR5cGUgPT0gJ08nKSAlPiUNCiAgbXV0YXRlKEJ1cm5TdGF0dXMgPQ0KICAgICAgICAgICByZWNvZGUoQnVyblN0YXR1cywNCiAgICAgICAgICAgICAgICAgICAiYnVybmVkIj0iQnVybmVkIiwNCiAgICAgICAgICAgICAgICAgICAidW5idXJuZWQiPSJVbmJ1cm5lZCIpKSAlPiUNCiAgbXV0YXRlKFNpdGVUeXBlID0NCiAgICAgICAgICAgcmVjb2RlKFNpdGVUeXBlLA0KICAgICAgICAgICAgICAgICAgInNhbmR5Ij0iU2FuZHkiLA0KICAgICAgICAgICAgICAgICAgInNpbHR5Ij0iU2lsdHkiLA0KICAgICAgICAgICAgICAgICAgInN0ZWVwIj0iU3RlZXAiLA0KICAgICAgICAgICAgICAgICAgInNoYWxsb3ciPSJTaGFsbG93IikpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgIG1lYW50YWMgPSBtZWFuKHRhYyksIA0KICAgICBzZW10YWMgPSBzZCh0YWMpIC8gc3FydChsZW5ndGgodGFjKSkpICU+JQ0KIGdncGxvdChhZXMoeCA9IE1vbnRoLCBmaWxsID0gQnVyblN0YXR1cykpICsgdGhlbWVfYncoMTQpICsgDQogICAgICBnZW9tX2xpbmUoYWVzKHkgPSBtZWFudGFjLA0KICAgICAgICAgICAgICAgICAgICBjb2xvciA9IEJ1cm5TdGF0dXMsDQogICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQnVyblN0YXR1cyksDQogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsNCiAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFudGFjIC0gc2VtdGFjLA0KICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9IG1lYW50YWMgKyBzZW10YWMsDQogICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IEJ1cm5TdGF0dXMsDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IEJ1cm5TdGF0dXMpLA0KICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMTUsDQogICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjMpKSArDQogICAgICBnZW9tX3BvaW50KGFlcyh5ID0gbWVhbnRhYywNCiAgICAgICAgICAgICAgICAgYmcgPSBCdXJuU3RhdHVzLA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IEJ1cm5TdGF0dXMpLA0KICAgICAgICAgICAgICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgc2l6ZT0yLjUsIHN0cm9rZSA9IDEuMSwNCiAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsNCiAgICAgIGZhY2V0X3dyYXAoflNpdGVUeXBlKSArDQogICAgICBsYWJzKHggPSAiVGltZSIsDQogICAgICAgICAgIHkgPSAiQWJvdmVncm91bmQgYmlvbWFzcyAodC9hYykiLA0KICAgICAgICAgICBjYXB0aW9uID0gIkZpZy4gMi4gQWJvdmVncm91bmQgYmlvbWFzcyBhdCBidXJuZWQgYW5kIHVuYnVybmVkIHBsb3RzIG9wZW4gdG8gZ3JhemluZy4iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgnQnVybiBzdGF0dXMnLCB2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIpW2MoMywgNSldKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IHdlc19wYWxldHRlKCJaaXNzb3UxIilbYygzLCA1KV0pICsNCiAgc2NhbGVfc2hhcGVfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IGMoMjEsIDI0KSkgKyANCiAgc2NhbGVfYWxwaGFfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IGMoMC42LCAwLjYpKSArDQogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAnaG9yaXpvbnRhbCcsDQogICAgICAgICAgICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLA0KICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMCwgIm1tIiksDQogICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSksDQogICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IC4yLCBzaXplID0gMTIpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiTWF5IiwgIkp1bmUiLCAiSnVseSIpKQ0KYGBgDQoNCmBgYHtyIEZvcmFnZUdyb3csIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSxmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTYuNX0NCg0KIyBGYWNldCBncmlkIG9mIGJ1cm4gc3RhdHVzIGFuZCBncmF6ZSBzdGF0dXMNCg0KQ2xpcFdlaWdodCAlPiUNCiAgc2VsZWN0KExvY2F0aW9uLCBUeXBlLCBTaXRlVHlwZSwgQnVyblN0YXR1cywgTW9udGgsIFF1YWRyYW50LCBOb25hbnQsIHRhYyklPiUNCiAgZmlsdGVyKFR5cGUgPT0gJ0UnKSAlPiUNCiAgZ3JvdXBfYnkoTG9jYXRpb24sIFF1YWRyYW50LCBOb25hbnQpICU+JQ0KICBmaWx0ZXIobigpPT0gMSkgJT4lDQogIGdyb3VwX2J5KFR5cGUsIFNpdGVUeXBlLCBCdXJuU3RhdHVzLCBNb250aCkgJT4lDQogIG11dGF0ZShCdXJuU3RhdHVzID0NCiAgICAgICAgICAgcmVjb2RlKEJ1cm5TdGF0dXMsDQogICAgICAgICAgICAgICAgICAgImJ1cm5lZCI9IkJ1cm5lZCIsDQogICAgICAgICAgICAgICAgICAgInVuYnVybmVkIj0iVW5idXJuZWQiKSkgJT4lDQogIG11dGF0ZShTaXRlVHlwZSA9DQogICAgICAgICAgIHJlY29kZShTaXRlVHlwZSwNCiAgICAgICAgICAgICAgICAgICJzYW5keSI9IlNhbmR5IiwNCiAgICAgICAgICAgICAgICAgICJzaWx0eSI9IlNpbHR5IiwNCiAgICAgICAgICAgICAgICAgICJzdGVlcCI9IlN0ZWVwIiwNCiAgICAgICAgICAgICAgICAgICJzaGFsbG93Ij0iU2hhbGxvdyIpKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgICBtZWFudGFjID0gbWVhbih0YWMpLCANCiAgICAgc2VtdGFjID0gc2QodGFjKSAvIHNxcnQobGVuZ3RoKHRhYykpKSAlPiUNCiBnZ3Bsb3QoYWVzKHggPSBNb250aCwgZmlsbCA9IEJ1cm5TdGF0dXMpKSArIHRoZW1lX2J3KDE0KSArIA0KICAgICAgZ2VvbV9saW5lKGFlcyh5ID0gbWVhbnRhYywNCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCdXJuU3RhdHVzLA0KICAgICAgICAgICAgICAgICAgICBncm91cCA9IEJ1cm5TdGF0dXMpLA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjMpKSArDQogICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbnRhYyAtIHNlbXRhYywNCiAgICAgICAgICAgICAgICAgICAgICAgIHltYXggPSBtZWFudGFjICsgc2VtdGFjLA0KICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBCdXJuU3RhdHVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCdXJuU3RhdHVzKSwNCiAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAwLjE1LA0KICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSkgKw0KICAgICAgZ2VvbV9wb2ludChhZXMoeSA9IG1lYW50YWMsDQogICAgICAgICAgICAgICAgIGJnID0gQnVyblN0YXR1cywNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSBCdXJuU3RhdHVzKSwNCiAgICAgICAgICAgICAgICAgY29sb3VyPSJibGFjayIsDQogICAgICAgICAgICAgICAgIHNpemU9Mi41LCBzdHJva2UgPSAxLjEsDQogICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjMpKSArDQogICAgICBmYWNldF93cmFwKH5TaXRlVHlwZSkgKw0KICAgICAgbGFicyh4ID0gIlRpbWUiLA0KICAgICAgICAgICB5ID0gIkFib3ZlZ3JvdW5kIGJpb21hc3MgKHQvYWMpIiwNCiAgICAgICAgICAgY2FwdGlvbiA9ICJGaWcuIDMuIGJpb21hc3MgZ3Jvd3RoIGluIGJ1cm5lZCBhbmQgdW5idXJuZWQgZXhjbG9zdXJlcy4iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgnQnVybiBzdGF0dXMnLCB2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIpW2MoMywgNSldKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IHdlc19wYWxldHRlKCJaaXNzb3UxIilbYygzLCA1KV0pICsNCiAgc2NhbGVfc2hhcGVfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IGMoMjEsIDI0KSkgKyANCiAgc2NhbGVfYWxwaGFfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IGMoMC42LCAwLjYpKSArDQogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAnaG9yaXpvbnRhbCcsDQogICAgICAgICAgICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLA0KICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMCwgIm1tIiksDQogICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSksDQogICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IC40NSwgc2l6ZSA9IDEyKSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIk1heSIsICJKdW5lIiwgIkp1bHkiKSkNCmBgYA0KDQo8YnI+DQoNCiMjIyBTdGF0aXN0aWNzDQoNCjxicj4NCg0KIyMjIyBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzDQoNCmBgYHtyIENsaXBEZXNjcmlwdGl2ZXMsIGVjaG89VFJVRSwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuc2hvdz0nc2hvdycsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgRGVzY3JpcHRpdmUgc3RhdHMNCg0Kc3RhdC5kZXNjKENsaXBXZWlnaHQkdGFjKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBIaXN0b2dyYW0gd2l0aCBOb3JtYWwgQ3VydmUNCg0KYGBge3IgQ2xpcEhpc3RvZ3JhbSwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEhpc3RvZ3JhbSBzaG93aW5nIGRhdGEgZGlzdHJpYnV0aW9uIGFuZCBub3JtYWxpdHkgY3VydmUNCg0KQ2xpcFdlaWdodCAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gdGFjKSkgKyB0aGVtZV9idygxNikgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KC5kYXRhW1siZGVuc2l0eSJdXSkpLA0KICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IC4xLA0KICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0eWVsbG93IikrDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IC41LCBmaWxsID0gImxpZ2h0Ymx1ZSIpICsNCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwNCiAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChtZWFuID0gMC43MjYyNTc4MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZCA9IDAuNTA5MTExMzIpLA0KICAgICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiLA0KICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuMSkgKw0KICBsYWJzKHkgPSAiRGVuc2l0eSIsIA0KICAgICAgIHggPSAiQWJvdmVncm91bmQgYmlvbWFzcyAodC9hYykiKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBSYXRpbyBiZXR3ZWVuIE1lYW4gYW5kIE1lZGlhbg0KDQpgYGB7ciBDbGlwUmF0aW8sIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyBSYXRpbyBiZXR3ZWVuIG1lYW4gYW5kIG1lZGlhbg0KDQprbml0cjo6a2FibGUodGliYmxlKE1lYW4gPSBtZWFuKENsaXBXZWlnaHQkdGFjKSwNCiAgICAgICAgICAgICAgICAgICAgTWVkaWFuID0gbWVkaWFuKENsaXBXZWlnaHQkdGFjKSwNCiAgICAgICAgICAgICAgICAgICAgUmF0aW8gPSBNZWFuL01lZGlhbikpDQpgYGANCg0KPGJyPg0KDQojIyMjIFNrZXduZXNzDQoNCmBgYHtyIENsaXBTa2V3bmVzcywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIFNrZXduZXNzDQoNCnNrZXduZXNzKENsaXBXZWlnaHQkdGFjKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBLdXJ0b3Npcw0KDQpgYGB7ciBDbGlwS3VydG9zaXMsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyBLdXJ0b3Npcw0KDQprdXJ0b3NpcyhDbGlwV2VpZ2h0JHRhYykNCmBgYA0KDQo8YnI+DQoNCiMjIyMgS29sbW9nb3Jvdi1TbWlybm92IFRlc3QNCg0KYGBge3IgQ2xpcEtTLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgS29sbW9nb3Jvdi1TbWlybm92IHRlc3QNCg0KS1NDbGlwIDwtDQogIGtzLnRlc3QoQ2xpcFdlaWdodCR0YWMsICJwbm9ybSIpDQoNCnBhbmRlcihLU0NsaXApDQpgYGANCg0KPGJyPg0KDQojIyMjIFFRLVBsb3QNCg0KYGBge3IgQ2xpcFFRLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KDQojIFFRLXBsb3QNCg0KY2FyOjpxcVBsb3QoQ2xpcFdlaWdodCR0YWMsIHhsYWIgPSAiVGhlb3JldGljYWwgUXVhbnRpbGVzIiwgeWxhYiA9ICJTYW1wbGUgUXVhbnRpbGVzIikNCmBgYA0KDQo8YnI+DQoNCiMjIyMgTG9nYXJpdGhtaWMgVHJhbnNmb3JtYXRpb24NCg0KYGBge3IgU3FSdENsaXAsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyBMb2dhcml0aG1pYyB0cmFuc2Zvcm1hdGlvbg0KDQpTcVJ0Q2xpcCA8LQ0KQ2xpcFdlaWdodCAlPiUNCiAgbXV0YXRlKFNxUnR0YWMgPSAgc3FydCh0YWMpKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzDQoNCmBgYHtyIFNxUnRDbGlwRGVzY3JpcHRpdmVzLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgRGVzY3JpcHRpdmUgc3RhdHMNCg0Kc3RhdC5kZXNjKFNxUnRDbGlwJFNxUnR0YWMpDQpgYGANCg0KPGJyPg0KDQojIyMjIEhpc3RvZ3JhbSB3aXRoIE5vcm1hbCBDdXJ2ZQ0KDQpgYGB7ciBTcVJ0Q2xpcEhpc3RvZ3JhbSwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEhpc3RvZ3JhbSBzaG93aW5nIGRhdGEgZGlzdHJpYnV0aW9uIGFuZCBub3JtYWxpdHkgY3VydmUNCg0KU3FSdENsaXAgJT4lDQogIGdncGxvdChhZXMoeCA9IFNxUnR0YWMpKSArIHRoZW1lX2J3KDE2KSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoLmRhdGFbWyJkZW5zaXR5Il1dKSksICAgICAgDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gLjEsDQogICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgIGZpbGwgPSAibGlnaHR5ZWxsb3ciKSsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gLjUsIGZpbGwgPSAibGlnaHRibHVlIikgKw0KICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLA0KICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1lYW4gPSAwLjg3OTE0MjYwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZCA9IDAuMzE4Mzk1ODYpLA0KICAgICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiLA0KICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuMSkgKw0KICBsYWJzKHkgPSAiRGVuc2l0eSIsIA0KICAgICAgIHggPSAiTG9nIGFib3ZlZ3JvdW5kIGJpb21hc3MgKHQvYWMpIikNCmBgYA0KDQo8YnI+DQoNCiMjIyMgUmF0aW8gYmV0d2VlbiBNZWFuIGFuZCBNZWRpYW4NCg0KYGBge3IgU3FSdENsaXBSYXRpbywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIFJhdGlvIGJldHdlZW4gbWVhbiBhbmQgbWVkaWFuDQoNCmtuaXRyOjprYWJsZSh0aWJibGUoTWVhblNxUnQgPSBtZWFuKFNxUnRDbGlwJFNxUnR0YWMpLA0KICAgICAgICAgICAgICAgICAgICBNZWRpYW5TcVJ0ID0gbWVkaWFuKFNxUnRDbGlwJFNxUnR0YWMpLA0KICAgICAgICAgICAgICAgICAgICBSYXRpb1NxUnQgPSBNZWFuU3FSdC9NZWRpYW5TcVJ0KSkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgU2tld25lc3MNCg0KYGBge3IgTG9nQ2xpcFNrZXduZXNzLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgU2tld25lc3MNCg0Kc2tld25lc3MoU3FSdENsaXAkU3FSdHRhYykNCmBgYA0KDQo8YnI+DQoNCiMjIyMgS3VydG9zaXMNCg0KYGBge3IgTG9nQ2xpcEt1cnRvc2lzLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgS3VydG9zaXMNCg0Ka3VydG9zaXMoU3FSdENsaXAkU3FSdHRhYykNCmBgYA0KDQo8YnI+DQoNCiMjIyMgS29sbW9nb3Jvdi1TbWlybm92IFRlc3QNCg0KYGBge3IgTG9nQ2xpcEtTLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgS29sbW9nb3Jvdi1TbWlybm92IHRlc3QNCg0KS1NMb2dDbGlwIDwtDQogIGtzLnRlc3QoU3FSdENsaXAkU3FSdHRhYywgInBub3JtIikNCg0KcGFuZGVyKEtTTG9nQ2xpcCkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgUVEtUGxvdA0KDQpgYGB7ciBMb2dDbGlwUVEsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQoNCiMgUVEtcGxvdA0KDQpjYXI6OnFxUGxvdChTcVJ0Q2xpcCRTcVJ0dGFjLCB4bGFiID0gIlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsIHlsYWIgPSAiU2FtcGxlIFF1YW50aWxlcyIpDQpgYGANCg0KPGJyPg0KDQojIyBTb2lsIE1vaXN0dXJlIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQo8YnI+DQoNCiMjIyBHcmFwaHMNCg0KYGBge3IgTW9pc3REaWFncmFtLCBlY2hvPVRSVUUsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIERpYWdyYW0gc2hvd2luZyBtZXRob2RzDQoNCkRpYWdyYW1tZVI6OmdyVml6KCJkaWdyYXBoIHsNCiAgZ3JhcGggW2NlbnRlciA9IFRSVUUsIGxheW91dCA9IGRvdCwgcmFua2RpciA9IFRCXQ0KICBub2RlIFtzaGFwZSA9IHJlY3RhbmdsZV0gICAgICAgIA0KICByZWMxIFtsYWJlbCA9ICcxLiBPYnRhaW4gc29pbCBtb2lzdHVyZSBkYXRhJ10NCiAgcmVjMiBbbGFiZWwgPSAnMi4gRW50ZXIgZGF0YSBpbiBFeGNlbCddDQogIHJlYzMgW2xhYmVsID0gICczLiBBbmFseXplIGRhdGEgaW4gUiBNYXJrZG93biddDQogIHJlYzEgLT4gcmVjMiAtPiByZWMzDQogIH0iLA0KICBoZWlnaHQgPSAyMjUpDQpgYGANCg0KPGJyPg0KDQpgYGB7ciBNb2lzdERpZmYsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSxmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTUuNX0NCg0KIyBMb2FkIHNvaWwgbW9pc3R1cmUgZGF0YQ0KDQpTb2lsTW9pc3QgPC0NCiAgcmVhZF9leGNlbCgiTGVtb25hZGVGaXJlTWFzdGVyRGF0YS54bHN4Iiwgc2hlZXQgPSAiU29pbE1vaXN0IikgJT4lDQogIG11dGF0ZSgnSUQnID0gcGFzdGUoTG9jYXRpb24sIFR5cGUsIHNlcD0gIiAiKSkgJT4lDQogIHNlbGVjdCggLSBMb2NhdGlvbiwNCiAgICAgICAgICAtIFR5cGUpJT4lDQogIGRhdGEudGFibGUoKQ0KDQojIENyb3NzIHJlZmVyZW5jZSBtb2lzdHVyZSBkYXRhIHdpdGggSUQgZGF0YQ0KDQpTb2lsTW9pc3QgPC0gDQogIFNvaWxNb2lzdFtJRCwgb24gPSAuKElEID0gTGVtb25hZGVGaXJlSUQpXSAlPiUNCiAgc2VsZWN0KC0gUGxvdE51bWJlclBCRykgJT4lDQogIHNlcGFyYXRlKEFGUkluYW1lLCBjKCdTaXRlVHlwZScsICdSZXBsaWNhdGUnKSkgJT4lDQogIHNlbGVjdCggLSBSZXBsaWNhdGUpDQoNCiMgUGxvdCBkaWZmZXJlbmNlIGluICUgc29pbCBtb2lzdHVyZSBiZXR3ZWVuIHBhaXJlZCBwbG90cw0KDQpTb2lsTW9pc3QgJT4lDQogIGdyb3VwX2J5KExvY2F0aW9uLCBTaXRlVHlwZSwgQnVyblN0YXR1cywgR3JhemVTdGF0dXMpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgbWVhbm1vaXMgPSBtZWFuKE1vaXN0KSkgJT4lDQogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gbWVhbm1vaXMsDQogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBHcmF6ZVN0YXR1cykgJT4lDQogIG11dGF0ZShkaWYgPSAoKGdyYXplZCAtIHVuZ3JhemVkKSAvIHVuZ3JhemVkKSAqIDEwMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IGRpZiwNCiAgICAgICAgICAgICB5ID0gTG9jYXRpb24sDQogICAgICAgICAgICAgY29sb3IgPSBTaXRlVHlwZSkpICsgDQogIGxhYnMoeSA9ICIiLCANCiAgICAgICB4ID0gIigoRSAtIE8pIC8gRSkgKiAxMDAlKSIsDQogICAgICAgZmlsbCA9ICJFY29sb2dpY2FsIFNpdGUiLA0KICAgICAgIGNhcHRpb24gPSAiRmlnLiA0LiBEaWZmZXJlbmNlIGluIHNvaWwgbW9pc3R1cmUgYmV0d2VlbiBwYWlyZWQgb3BlbiBhcmVhcyBhbmQgZXhjbG9zdXJlcy4iKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIHNpemUgPSAuMykgKw0KICBnZW9tX2xhYmVsKGFlcyhsYWJlbCA9IExvY2F0aW9uLA0KICAgICAgICAgICAgICAgIGZpbGwgPSBmYWN0b3IoU2l0ZVR5cGUpKSwNCiAgICAgICAgICAgICBjb2xvdXIgPSAid2hpdGUiLA0KICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gJ2hvcml6b250YWwnLA0KICAgICAgICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAic29saWQiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShzaXplID0gMC4xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gJ3NvbGlkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yPSJibGFjayIsIHNpemUgPSAuNSksDQogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAuMSwgMC41LCAwLjEsIDAuMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbmNoZXMiKSwNCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gLjQ1LCBzaXplID0gMTIpKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKGJ5cm93ID0gVFJVRSwgb3ZlcnJpZGUuYWVzID0gYWVzKGxhYmVsID0gIiIpKSkrDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygtOTEsIDkxKSkNCmBgYA0KDQo8YnI+DQoNCmBgYHtyIE1vaXN0RmFjZXQsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1UUlVFLGZpZy53aWR0aD03LGZpZy5oZWlnaHQ9Ni41fQ0KDQojIEZhY2V0IGdyaWQgb2YgYnVybiBzdGF0dXMgYW5kIGdyYXplIHN0YXR1cw0KDQpTb2lsTW9pc3QgJT4lDQogIGdyb3VwX2J5KFR5cGUsIFNpdGVUeXBlLCBCdXJuU3RhdHVzLCBNb250aCkgJT4lDQogIGZpbHRlcihUeXBlID09ICdPJykgJT4lDQogIG11dGF0ZShCdXJuU3RhdHVzID0NCiAgICAgICAgICAgcmVjb2RlKEJ1cm5TdGF0dXMsDQogICAgICAgICAgICAgICAgICAgImJ1cm5lZCI9IkJ1cm5lZCIsDQogICAgICAgICAgICAgICAgICAgInVuYnVybmVkIj0iVW5idXJuZWQiKSkgJT4lDQogIG11dGF0ZShTaXRlVHlwZSA9DQogICAgICAgICAgIHJlY29kZShTaXRlVHlwZSwNCiAgICAgICAgICAgICAgICAgICJzYW5keSI9IlNhbmR5IiwNCiAgICAgICAgICAgICAgICAgICJzaWx0eSI9IlNpbHR5IiwNCiAgICAgICAgICAgICAgICAgICJzdGVlcCI9IlN0ZWVwIiwNCiAgICAgICAgICAgICAgICAgICJzaGFsbG93Ij0iU2hhbGxvdyIpKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lYW5tb2lzdCA9IG1lYW4oTW9pc3QpLCANCiAgICBzZW1tb2lzdCA9IHNkKE1vaXN0KSAvIHNxcnQobGVuZ3RoKE1vaXN0KSkpICU+JQ0KIGdncGxvdChhZXMoeCA9IE1vbnRoLCBmaWxsID0gQnVyblN0YXR1cykpICsgdGhlbWVfYncoMTQpICsgDQogICAgICBnZW9tX2xpbmUoYWVzKHkgPSBtZWFubW9pc3QsDQogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gQnVyblN0YXR1cywNCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBCdXJuU3RhdHVzKSwNCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSkgKw0KICAgICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IG1lYW5tb2lzdCAtIHNlbW1vaXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9IG1lYW5tb2lzdCArIHNlbW1vaXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBCdXJuU3RhdHVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCdXJuU3RhdHVzKSwNCiAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAwLjE1LA0KICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSkgKw0KICAgICAgZ2VvbV9wb2ludChhZXMoeSA9IG1lYW5tb2lzdCwNCiAgICAgICAgICAgICAgICAgYmcgPSBCdXJuU3RhdHVzLA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IEJ1cm5TdGF0dXMpLA0KICAgICAgICAgICAgICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNSwgc3Ryb2tlID0gMS4xLA0KICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSkgKw0KICAgICAgZmFjZXRfd3JhcCh+U2l0ZVR5cGUpICsNCiAgICAgIGxhYnMoeCA9ICJUaW1lIiwNCiAgICAgICAgICAgeSA9ICIlIHNvaWwgbW9pc3R1cmUiLA0KICAgICAgICAgICBjYXB0aW9uID0gIkZpZy4gNS4gU29pbCBtb2lzdHVyZSBpbiBidXJuZWQgYW5kIHVuYnVybmVkIGxvY2F0aW9ucy4iKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCgnQnVybiBzdGF0dXMnLCB2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIpW2MoMywgNSldKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IHdlc19wYWxldHRlKCJaaXNzb3UxIilbYygzLCA1KV0pICsNCiAgc2NhbGVfc2hhcGVfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IGMoMjEsIDI0KSkgKyANCiAgc2NhbGVfYWxwaGFfbWFudWFsKCdCdXJuIHN0YXR1cycsIHZhbHVlcyA9IGMoMC42LCAwLjYpKSArDQogICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAnaG9yaXpvbnRhbCcsDQogICAgICAgICAgICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLA0KICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMCwgIm1tIiksDQogICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiwgZmlsbD1OQSksDQogICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IC40NSwgc2l6ZSA9IDEyKSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIk1heSIsICJKdW5lIiwgIkp1bHkiKSkNCmBgYA0KDQojIyMgU3RhdGlzdGljcw0KDQojIyMjIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MNCg0KYGBge3IgTW9pc3REZXNjcmlwdGl2ZXMsIGZpZy5hbGlnbj0gJ2NlbnRlcicsIGZpZy5zaG93PSdzaG93JywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQ0KDQoNCiMgRGVzY3JpcHRpdmUgc3RhdHMNCg0Kc3RhdC5kZXNjKFNvaWxNb2lzdCRNb2lzdCkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgSGlzdG9ncmFtIHdpdGggTm9ybWFsIEN1cnZlDQoNCmBgYHtyIE1vaXN0SGlzdG9ncmFtLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgSGlzdG9ncmFtIHNob3dpbmcgZGF0YSBkaXN0cmlidXRpb24gYW5kIG5vcm1hbGl0eSBjdXJ2ZQ0KDQpTb2lsTW9pc3QgJT4lDQogIGdncGxvdChhZXMoeCA9IE1vaXN0KSkgKyB0aGVtZV9idygxNikgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoLmRhdGFbWyJkZW5zaXR5Il1dKSksDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMywNCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgZmlsbCA9ICJsaWdodHllbGxvdyIpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAuNSwgZmlsbCA9ICJsaWdodGJsdWUiKSArDQogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sDQogICAgICAgICAgICAgICAgYXJncyA9IGxpc3QobWVhbiA9IDE3LjU0MzA1NTYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNkID0gMTAuOTI3NjE4MyksDQogICAgICAgICAgICAgICAgY29sb3VyID0gInJlZCIsDQogICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMS4xKSArDQogIGxhYnMoeSA9ICJEZW5zaXR5IiwgDQogICAgICAgeCA9ICIlIHNvaWwgbW9pc3R1cmUiKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBRUS1QbG90DQoNCmBgYHtyIE1vaXN0UVEsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQoNCiMgUVEtcGxvdA0KDQpjYXI6OnFxUGxvdChTb2lsTW9pc3QkTW9pc3QsIHhsYWIgPSAiVGhlb3JldGljYWwgUXVhbnRpbGVzIiwgeWxhYiA9ICJTYW1wbGUgUXVhbnRpbGVzIikNCmBgYA0KDQo8YnI+DQoNCiMjIyMgUmF0aW8gYmV0d2VlbiBNZWFuIGFuZCBNZWRpYW4NCg0KYGBge3IgTW9pc3RSYXRpbywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQprbml0cjo6a2FibGUodGliYmxlKE1lYW4gPSBtZWFuKFNvaWxNb2lzdCRNb2lzdCksDQogICAgICAgICAgICAgICAgICAgIE1lZGlhbiA9IG1lZGlhbihTb2lsTW9pc3QkTW9pc3QpLA0KICAgICAgICAgICAgICAgICAgICBSYXRpbyA9IE1lYW4vTWVkaWFuKSkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgU2tld25lc3MNCg0KYGBge3IgTW9pc3RTa2V3bmVzcywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIFNrZXduZXNzDQoNCnNrZXduZXNzKFNvaWxNb2lzdCRNb2lzdCkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgS3VydG9zaXMNCg0KYGBge3IgTW9pc3RLdXJ0b3NpcywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEt1cnRvc2lzDQoNCmt1cnRvc2lzKFNvaWxNb2lzdCRNb2lzdCkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgS29sbW9nb3Jvdi1TbWlybm92IFRlc3QNCg0KYGBge3IgTW9pc3RLUywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEtvbG1vZ29yb3YtU21pcm5vdiB0ZXN0DQoNCktTTW9pc3QgPC0NCiAga3MudGVzdChTb2lsTW9pc3QkTW9pc3QsICJwbm9ybSIpDQoNCnBhbmRlcihLU01vaXN0KQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBTcXVhcmUgUm9vdCBUcmFuc2Zvcm1hdGlvbg0KDQpgYGB7ciBTcVJ0TW9pc3QsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyBTcXVhcmUgcm9vdCB0cmFuc2Zvcm1hdGlvbg0KDQpTUk1vaXN0IDwtDQpTb2lsTW9pc3QgJT4lDQogIG11dGF0ZShTcVJ0TW9pc3QgPSAgc3FydChNb2lzdCkpDQpgYGANCg0KPGJyPg0KDQojIyMjIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MNCg0KYGBge3IgU3FSdE1vaXN0RGVzY3JpcHRpdmVzLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgRGVzY3JpcHRpdmUgc3RhdHMNCg0Kc3RhdC5kZXNjKFNSTW9pc3QkU3FSdE1vaXN0KQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBIaXN0b2dyYW0gd2l0aCBOb3JtYWwgQ3VydmUNCg0KYGBge3IgU3FSdE1vaXN0SGlzdG9ncmFtLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgSGlzdG9ncmFtIHNob3dpbmcgZGF0YSBkaXN0cmlidXRpb24gYW5kIG5vcm1hbGl0eSBjdXJ2ZQ0KDQpTUk1vaXN0ICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBTcVJ0TW9pc3QpKSArIA0KICB0aGVtZV9idygxNikgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KC5kYXRhW1siZGVuc2l0eSJdXSkpLA0KICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IC40LA0KICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0eWVsbG93IikrDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IC41LCBmaWxsID0gImxpZ2h0Ymx1ZSIpKw0KICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLA0KICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1lYW4gPSAzLjU1NjA4MDczLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZCA9IDEuMzM0NDU1NDUpLA0KICAgICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiLA0KICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuMSkgKw0KICBsYWJzKHkgPSAiRGVuc2l0eSIsIA0KICAgICAgIHggPSAiTG9nICUgc29pbCBtb2lzdHVyZSIpDQpgYGANCg0KPGJyPg0KDQojIyMjIFJhdGlvIGJldHdlZW4gTWVhbiBhbmQgTWVkaWFuDQoNCmBgYHtyIFNxUnRNb2lzdFJhdGlvLCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgUmF0aW8gYmV0d2VlbiBtZWFuIGFuZCBtZWRpYW4NCg0Ka25pdHI6OmthYmxlKHRpYmJsZShNZWFuID0gbWVhbihTUk1vaXN0JFNxUnRNb2lzdCksDQogICAgICAgICAgICAgICAgICAgIE1lZGlhbiA9IG1lZGlhbihTUk1vaXN0JFNxUnRNb2lzdCksDQogICAgICAgICAgICAgICAgICAgIFJhdGlvID0gTWVhbi9NZWRpYW4pKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBTa2V3bmVzcw0KDQpgYGB7ciBTcVJ0TW9pc3RTa2V3bmVzcywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIFNrZXduZXNzDQoNCnNrZXduZXNzKFNSTW9pc3QkU3FSdE1vaXN0KQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBLdXJ0b3Npcw0KDQpgYGB7ciBTcVJ0TW9pc3RLdXJ0b3NpcywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEt1cnRvc2lzDQoNCmt1cnRvc2lzKFNSTW9pc3QkU3FSdE1vaXN0KQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBLb2xtb2dvcm92LVNtaXJub3YgVGVzdA0KDQpgYGB7ciBTcVJ0TW9pc3RLUywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEtvbG1vZ29yb3YtU21pcm5vdiB0ZXN0DQoNCktTU3FSdE1vaXN0IDwtDQogIGtzLnRlc3QoU1JNb2lzdCRTcVJ0TW9pc3QsICJwbm9ybSIpDQoNCnBhbmRlcihLU1NxUnRNb2lzdCkNCmBgYA0KDQo8YnI+DQoNCiMjIyMgUVEtUGxvdA0KDQpgYGB7ciBTcVJ0TW9pc3RRUSwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCg0KIyBRUS1wbG90DQoNCmNhcjo6cXFQbG90KFNSTW9pc3QkU3FSdE1vaXN0LCB4bGFiID0gIlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsIHlsYWIgPSAiU2FtcGxlIFF1YW50aWxlcyIpDQpgYGANCg==