Exploring data patterns of sugar maple and red maple trees

To start off this project uses a data set that covers a reasearch study conducted on “Maple Reproduction and Sap Flow at Harvard Forest since 2011”. This project uses the data sets provides by the study and can be found here https://doi.org/10.6073/pasta/7c2ddd7b75680980d84478011c5fbba9 or below in the full citation. This project will try and answer the question “Does the non-masting red maple species exhibit muted dynamics compared to the masting sugar maple species?”

Due to the incomplete nature of this data set, there is far too little data to concretely say red maples exhibit muted dynamics when compared to the sugar maple trees. Therefore, I’m going to be looking to find the best key indicators so that if the data were more fleshed out it would be easier to see if the red maple species exhibit muted dynamics.

Rapp, J., E. Crone, and K. Stinson. 2023. Maple Reproduction and Sap Flow at Harvard Forest since 2011 ver 6. Environmental Data Initiative. https://doi.org/10.6073/pasta/7c2ddd7b75680980d84478011c5fbba9 (Accessed 2024-12-11)

This notebook uses tidyverse for graphing and general R commands as well as for graphing and data visualizations, dplyr for data manipulation, and modelr for creating statistical models and their summarys.

library(tidyverse)
library(dplyr)
library(ggplot2)
library(modelr)

Below we read in each data set

library(readr)
hf285_01_maple_tap <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-01-maple-tap.csv")


hf285_02_maple_sap <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-02-maple-sap.csv")

hf285_03_maple_flower_qual <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-03-maple-flower-qual.csv")

hf285_04_maple_flower <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-04-maple-flower.csv")

hf285_05_maple_spring_branch <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-05-maple-spring-branch.csv")


hf285_06_maple_fall_branch <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-06-maple-fall-branch.csv")

hf285_07_maple_seedfilling <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-07-maple-seedfilling.csv")


hf285_08_maple_pollen_excl <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-08-maple-pollen-excl.csv")


hf285_09_maple_seed_count <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-09-maple-seed-count.csv")

hf285_10_leaf_removal <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-10-leaf-removal.csv")

hf285_11_leaf_removal_branches <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-11-leaf-removal-branches.csv")


hf285_12_leaf_seed_removal <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-12-leaf-seed-removal.csv")


hf285_13_leaf_seed_removal_branches <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-13-leaf-seed-removal-branches.csv")

hf285_14_perm_branches <- read_csv("C:/Users/Admin/Desktop/R stats homework/Final Project/knb-lter-hfr.285.6/hf285-14-perm-branches.csv")

Masting and Non-Masting

First we need to better understand our problem and learn a few key defintions. A masting tree is a tree that produces seeds large quanities in irregular intervals. Our sugar maple trees are masting trees and we want to know if the red maples show muted dynamics when compared to the sugar maples. To better understand our sugar maples we first need to see what years were masting years for the trees. We do this by examening the seed collection data average for the sugar maples each year of the data.


tree_seed_data <- hf285_09_maple_seed_count %>%
  filter(!is.na(total.count)) %>%
  mutate(year = as.numeric(format(date, "%Y"))) %>%
  group_by(tree, year) %>%
  summarise(Total_Seeds = sum(total.count, na.rm = TRUE), .groups = "drop")

ggplot(tree_seed_data, aes(x = factor(year), y = tree, fill = Total_Seeds)) +
  geom_tile(color = "black", linewidth = 0.5) +
  scale_fill_viridis_c() +
  labs(
    title = "Yearly Seed Count by Tree",
    x = "Year",
    y = "Tree ID",
    fill = "Seed Count"
  )

Based on the heat map we can see a few years that stick out 2011, 2013, 2017, and 2019. These are the best indicators that show what years we can see the masting taking place in our sugar maples.

Next below we add our masting years we found to our sap collection and sugar content dataset for the approprate trees which we can use for later to attept to build a model to predict masting seasons.

hf285_02_maple_sap <- hf285_02_maple_sap %>%
  mutate(date = as.Date(date))

hf285_02_maple_sap <- hf285_02_maple_sap %>%
  mutate(year = year(date))

hf285_02_maple_sap_masting <- hf285_02_maple_sap %>%
  mutate(masting = ifelse(year %in% c(2011, 2013, 2017, 2019), "Yes", "No"))

head(hf285_02_maple_sap_masting)

Breaking down key indicators

Here if we want to look for key indicators in our sugar maples that could predict when a masting might occur. These keye predictors could help us better compare and undertand if our red maples are exhibiting signs of muted dynamics. Below we graph both the sugar and red maples average sap sugar content for years there was data collected. HF stands for sugar maple and AR for red maple.

grouped_data <- hf285_02_maple_sap %>%
  filter(!is.na(sugar)) %>%
  mutate(Tree_Group = substr(tree, 1, 2)) %>%
  group_by(date, Tree_Group) %>%
  summarise(Average_Sugar = mean(sugar, na.rm = TRUE), .groups = "drop")

ggplot(grouped_data, aes(x = date, y = Average_Sugar, color = Tree_Group, group = Tree_Group)) +
  geom_line() +
  geom_point() +
  labs(
    title = "Average Sugar Content Over Time",
    x = "Date",
    y = "Average Sugar Content",
    color = "Tree Group"
  )

While we can see the average sugar content is much lower for the red maple that doesn’t answer our question right away especially when the data collected for red maples is very small with only about 4-5 years of data collected the data simply isn’t conclusive enough to answer our question.

Here is where can start to dig in and see if overlaying our graphs between yealy average sugar content of the sugar maple trees (HF) and the averge seed count of sugar maples have simlar graphs.

###Average seed count per year compared to average sugar content of sugar maples

hf285_02_maple_sap_HF <- hf285_02_maple_sap %>% 
  filter(grepl("^HF", tree), !is.na(sugar))

hf285_09_maple_seed_count_HF <- hf285_09_maple_seed_count %>%
  filter(grepl("^HF", tree), !is.na(total.count))

hf285_02_maple_sap_HF <- hf285_02_maple_sap_HF %>% 
  mutate(year = year(date))

hf285_09_maple_seed_count_HF <- hf285_09_maple_seed_count_HF %>%
  mutate(year = year(date))

average_data <- hf285_02_maple_sap_HF %>%
  group_by(year) %>%
  summarise(average_sugar = mean(sugar, na.rm = TRUE))

average_seeds <- hf285_09_maple_seed_count_HF %>%
  group_by(year) %>%
  summarise(average_seeds = mean(total.count, na.rm = TRUE))

merged_avg_data <- left_join(average_data, average_seeds, by = "year")

merged_avg_data_clean <- merged_avg_data %>%
  filter(!is.na(average_sugar) & !is.na(average_seeds))

sugar_content_HF <- ggplot(merged_avg_data_clean, aes(x = year, y = average_sugar)) +
  geom_line(color = "blue", size = 1) +
  geom_point(color = "red", size = 3) +
  labs(
    title = "Average Sugar Content for HF Trees by Year",
    x = "Year",
    y = "Average Sugar Content"
  ) +
  theme_minimal()

seed_count_HF <- ggplot(merged_avg_data_clean, aes(x = year, y = average_seeds)) +
  geom_line(color = "green", size = 1) +
  geom_point(color = "orange", size = 3) +
  labs(
    title = "Average Seed Count for HF Trees by Year",
    x = "Year",
    y = "Average Seed Count"
  ) +
  theme_minimal()

print(sugar_content_HF)

print(seed_count_HF)

Here we can see that while the graphs do have a similar shape the overall patterns don’t match exactly so to better try and find our key predictors we can use our added masting column from earlier to create a linear model.

Building a model with our data

Below we use our added data from before to attept to predict the sugar tree mastings based on sugar content of trees sap.

hf285_02_maple_sap_HF <- hf285_02_maple_sap_masting %>%
  mutate(masting_binary = ifelse(masting == "Yes", 1, 0))

lm_model <- lm(masting_binary ~ sugar, data = hf285_02_maple_sap_HF)

summary(lm_model)

Call:
lm(formula = masting_binary ~ sugar, data = hf285_02_maple_sap_HF)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.1457 -0.3395 -0.3146  0.6480  0.7228 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 0.231458   0.020481  11.301  < 2e-16 ***
sugar       0.041555   0.008005   5.191 2.14e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.471 on 8011 degrees of freedom
  (1009 observations deleted due to missingness)
Multiple R-squared:  0.003352,  Adjusted R-squared:  0.003228 
F-statistic: 26.95 on 1 and 8011 DF,  p-value: 2.143e-07

Here we get to know break down our model and look at its key values. Right off the bat we can see the sugar coef of .041555 so for every increase in 1 unit of sugar we see a 4.15% increase in the chance of a masting year. Next we can see that our RSE is quite high, a lower value would be better but this does show that some variability remains unexplained. Our R squared value of just .003352 shows that sugar alone is not a strong predictor. Lastly we look at our p-value which shows an incredly small 2.143e-07. So while sugar isn’t a great solo predictor our new model is statistically significant.

With sugar content helping work towards a stronger model we can look at other possible predictors we might have over looked. Below I have taken thehf285_03_maple_flower_qual data set and edited the data to give values to the flowering.intensity based on the values provided by Harvads ranges which can be found here https://harvardforest1.fas.harvard.edu/exist/apps/datasets/showData.html?id=hf285. Which states that data set hf285_03_maple_flower_qual gives these ranges

“flowering.intensity: qualitative evaluation of whole-tree flowering low: generally <1,000 flowering buds medium: generally 1,000-10,000 flowering buds high: generally >10,000 flowering buds none: no flowering buds”


hf285_03_maple_flower_qual_edit <- hf285_03_maple_flower_qual %>%
  mutate(flowering_value = case_when(
    flowering.intensity == "none" ~ 0,
    flowering.intensity == "low" ~ 999,
    flowering.intensity == "medium" ~ 5000,
    flowering.intensity == "high" ~ 10000,
    TRUE ~ NA_real_
  ))

head(hf285_03_maple_flower_qual_edit)

While creating the numbers for each group is overreaching. The dataset itself gives us very little to work with so attepting to put numbers to values that Harvad offered is the best we can do to get a better idea of our predictors.

Now that we have values for out flower intensity we can put it to a graph and compare to our graph of mastings

average_flowering_data <- hf285_03_maple_flower_qual_edit %>%
  group_by(year) %>%
  summarise(average_flowering = mean(flowering_value, na.rm = TRUE))



ggplot(average_flowering_data, aes(x = factor(year), y = average_flowering)) +
  geom_point(color = "blue", size = 3) +
  labs(
    title = "Average Flowering Intensity for the Forest Over Time",
    x = "Year",
    y = "Average Flowering Intensity"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Here we can see a strong pattern though we see large spikes on our masting years with 2011, 2013, 2017, and 2019! This is very big becuase it matches very close to our heat map of our masting years. But just looking similar isn’t enough, we can test this by adding on to our linear model to see if the number of flowers is a good predictor.

Below we look to test if the number of flower is a accurate predictor on if sugar maple trees will have a masting year. By combining it with our sugar model from earlier.

average_flowering_data_masting <- hf285_03_maple_flower_qual_edit %>%
  mutate(
    masting = ifelse(year %in% c(2011, 2013, 2017, 2019), "Yes", "No"),
    masting_binary = ifelse(masting == "Yes", 1, 0)
  )
lm_model_flowering <- lm(masting_binary ~ flowering_value, data = average_flowering_data_masting)

summary(lm_model_flowering)

Call:
lm(formula = masting_binary ~ flowering_value, data = average_flowering_data_masting)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.62634 -0.10057 -0.04222  0.37366  0.95778 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     4.222e-02  3.625e-02   1.165    0.245    
flowering_value 5.841e-05  5.669e-06  10.304   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3843 on 230 degrees of freedom
Multiple R-squared:  0.3158,    Adjusted R-squared:  0.3129 
F-statistic: 106.2 on 1 and 230 DF,  p-value: < 2.2e-16

First off we can see by our average_flowering coef showing .004 average flowering is statistically significant. Second we can see our intercept shows that for every increase by 1 flower increases the chance of a masting year by .0001. Which on the surface doesn’t seem like much when dealing with trees these blossoms can range from a few hundred to well over ten thousand this can add up. Now when we look at RSE there are improvements over the sugar model with ours being .334 which shows us the model is a better fit. Our R squared shows .579 showing us that about 58% of the variance in the masting binary outcome is explained by average_flowering. Lastly our p-value shows that over all this model is statistically significant.


view(hf285_02_maple_sap_masting)

combined_data <- left_join(
  average_flowering_data_masting, 
  hf285_02_maple_sap_masting %>% 
    group_by(year) %>% 
    summarise(average_sugar = mean(sugar, na.rm = TRUE)), 
  by = "year"
)

view(average_flowering_data_masting)

combined_lm <- lm(masting_binary ~ flowering_value + average_sugar, data = combined_data)

summary(combined_lm)

Call:
lm(formula = masting_binary ~ flowering_value + average_sugar, 
    data = combined_data)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.66676 -0.22594 -0.03772  0.34683  0.83780 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -9.725e-01  3.400e-01  -2.860  0.00465 ** 
flowering_value  4.897e-05  5.899e-06   8.302 1.09e-14 ***
average_sugar    4.202e-01  1.393e-01   3.017  0.00285 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3765 on 217 degrees of freedom
  (12 observations deleted due to missingness)
Multiple R-squared:  0.2951,    Adjusted R-squared:  0.2886 
F-statistic: 45.42 on 2 and 217 DF,  p-value: < 2.2e-16

First off we can see by our average_flowering coef is incredibly small so average flowering is highly statistically significant. Second we can see our intercept shows that for every increase by 1 flower increases the chance of a masting year but only by 4.897e-05. Which on the surface doesn’t seem like much when dealing with trees these blossoms can range from a few hundred to well over ten thousand this can add up. Our average sugar has changed some too we now see the coef at .002 making it a statistically significant predictor of masting. Now when we look at RSE there are improvements over the sugar model with ours being .376 which shows us the model is a better fit then before. Our R squared shows .295 showing us that about 30% of the variance in the masting binary outcome is explained by average_flowering and average_sugar. Lastly our p-value shows that over all this model is highly statistically significant. While our data shows that this model is statistically significant our R squared only explains about 30% of the variance in the model showing the model needs more data to better predict masting seasons.

In concluion

Overall, while there is not enough data to accurately state whether red maple species exhibit muted dynamics or not I believe that the two best key predictor in this limited data set are sap sugar content and the number of flowers in bloom. If the data were more complete I believe that these two predictors could be used to better see if the red maple trees exhibit muted dynamics when compared to the sugar maple trees but with the current data set limitations the data is inconclusive

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCkF1dGhvcjogTm9haCBTemFyZWprbw0KLS0tDQoNCiMjIyBFeHBsb3JpbmcgZGF0YSBwYXR0ZXJucyBvZiBzdWdhciBtYXBsZSBhbmQgcmVkIG1hcGxlIHRyZWVzDQoNCiBUbyBzdGFydCBvZmYgdGhpcyBwcm9qZWN0IHVzZXMgYSBkYXRhIHNldCB0aGF0IGNvdmVycyBhIHJlYXNlYXJjaCBzdHVkeSBjb25kdWN0ZWQgb24gIk1hcGxlIFJlcHJvZHVjdGlvbiBhbmQgU2FwIEZsb3cgYXQgSGFydmFyZCBGb3Jlc3Qgc2luY2UgMjAxMSIuIFRoaXMgcHJvamVjdCB1c2VzIHRoZSBkYXRhIHNldHMgcHJvdmlkZXMgYnkgdGhlIHN0dWR5IGFuZCBjYW4gYmUgZm91bmQgaGVyZSBodHRwczovL2RvaS5vcmcvMTAuNjA3My9wYXN0YS83YzJkZGQ3Yjc1NjgwOTgwZDg0NDc4MDExYzVmYmJhOSBvciBiZWxvdyBpbiB0aGUgZnVsbCBjaXRhdGlvbi4gVGhpcyBwcm9qZWN0IHdpbGwgdHJ5IGFuZCBhbnN3ZXIgdGhlIHF1ZXN0aW9uICJEb2VzIHRoZSBub24tbWFzdGluZyByZWQgbWFwbGUgc3BlY2llcyBleGhpYml0IG11dGVkIGR5bmFtaWNzIGNvbXBhcmVkIHRvIHRoZSBtYXN0aW5nIHN1Z2FyIG1hcGxlIHNwZWNpZXM/Ig0KIA0KRHVlIHRvIHRoZSBpbmNvbXBsZXRlIG5hdHVyZSBvZiB0aGlzIGRhdGEgc2V0LCB0aGVyZSBpcyBmYXIgdG9vIGxpdHRsZSBkYXRhIHRvIGNvbmNyZXRlbHkgc2F5IHJlZCBtYXBsZXMgZXhoaWJpdCBtdXRlZCBkeW5hbWljcyB3aGVuIGNvbXBhcmVkIHRvIHRoZSBzdWdhciBtYXBsZSB0cmVlcy4gVGhlcmVmb3JlLCBJJ20gZ29pbmcgdG8gYmUgbG9va2luZyB0byBmaW5kIHRoZSBiZXN0IGtleSBpbmRpY2F0b3JzIHNvIHRoYXQgaWYgdGhlIGRhdGEgd2VyZSBtb3JlIGZsZXNoZWQgb3V0IGl0IHdvdWxkIGJlIGVhc2llciB0byBzZWUgaWYgdGhlIHJlZCBtYXBsZSBzcGVjaWVzIGV4aGliaXQgbXV0ZWQgZHluYW1pY3MuIA0KDQpSYXBwLCBKLiwgRS4gQ3JvbmUsIGFuZCBLLiBTdGluc29uLiAyMDIzLiBNYXBsZSBSZXByb2R1Y3Rpb24gYW5kIFNhcCBGbG93IGF0IEhhcnZhcmQgRm9yZXN0IHNpbmNlIDIwMTEgdmVyIDYuIEVudmlyb25tZW50YWwgRGF0YSBJbml0aWF0aXZlLiBodHRwczovL2RvaS5vcmcvMTAuNjA3My9wYXN0YS83YzJkZGQ3Yjc1NjgwOTgwZDg0NDc4MDExYzVmYmJhOSAoQWNjZXNzZWQgMjAyNC0xMi0xMSkNCg0KVGhpcyBub3RlYm9vayB1c2VzIHRpZHl2ZXJzZSBmb3IgZ3JhcGhpbmcgYW5kIGdlbmVyYWwgUiBjb21tYW5kcyBhcyB3ZWxsIGFzIGZvciBncmFwaGluZyBhbmQgZGF0YSB2aXN1YWxpemF0aW9ucywgZHBseXIgZm9yIGRhdGEgbWFuaXB1bGF0aW9uLCBhbmQgbW9kZWxyIGZvciBjcmVhdGluZyBzdGF0aXN0aWNhbCBtb2RlbHMgYW5kIHRoZWlyIHN1bW1hcnlzLg0KDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShtb2RlbHIpDQpgYGANCg0KQmVsb3cgd2UgcmVhZCBpbiBlYWNoIGRhdGEgc2V0DQpgYGB7cn0NCmxpYnJhcnkocmVhZHIpDQpoZjI4NV8wMV9tYXBsZV90YXAgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL0FkbWluL0Rlc2t0b3AvUiBzdGF0cyBob21ld29yay9GaW5hbCBQcm9qZWN0L2tuYi1sdGVyLWhmci4yODUuNi9oZjI4NS0wMS1tYXBsZS10YXAuY3N2IikNCg0KDQpoZjI4NV8wMl9tYXBsZV9zYXAgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL0FkbWluL0Rlc2t0b3AvUiBzdGF0cyBob21ld29yay9GaW5hbCBQcm9qZWN0L2tuYi1sdGVyLWhmci4yODUuNi9oZjI4NS0wMi1tYXBsZS1zYXAuY3N2IikNCg0KaGYyODVfMDNfbWFwbGVfZmxvd2VyX3F1YWwgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL0FkbWluL0Rlc2t0b3AvUiBzdGF0cyBob21ld29yay9GaW5hbCBQcm9qZWN0L2tuYi1sdGVyLWhmci4yODUuNi9oZjI4NS0wMy1tYXBsZS1mbG93ZXItcXVhbC5jc3YiKQ0KDQpoZjI4NV8wNF9tYXBsZV9mbG93ZXIgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL0FkbWluL0Rlc2t0b3AvUiBzdGF0cyBob21ld29yay9GaW5hbCBQcm9qZWN0L2tuYi1sdGVyLWhmci4yODUuNi9oZjI4NS0wNC1tYXBsZS1mbG93ZXIuY3N2IikNCg0KaGYyODVfMDVfbWFwbGVfc3ByaW5nX2JyYW5jaCA8LSByZWFkX2NzdigiQzovVXNlcnMvQWRtaW4vRGVza3RvcC9SIHN0YXRzIGhvbWV3b3JrL0ZpbmFsIFByb2plY3Qva25iLWx0ZXItaGZyLjI4NS42L2hmMjg1LTA1LW1hcGxlLXNwcmluZy1icmFuY2guY3N2IikNCg0KDQpoZjI4NV8wNl9tYXBsZV9mYWxsX2JyYW5jaCA8LSByZWFkX2NzdigiQzovVXNlcnMvQWRtaW4vRGVza3RvcC9SIHN0YXRzIGhvbWV3b3JrL0ZpbmFsIFByb2plY3Qva25iLWx0ZXItaGZyLjI4NS42L2hmMjg1LTA2LW1hcGxlLWZhbGwtYnJhbmNoLmNzdiIpDQoNCmhmMjg1XzA3X21hcGxlX3NlZWRmaWxsaW5nIDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9BZG1pbi9EZXNrdG9wL1Igc3RhdHMgaG9tZXdvcmsvRmluYWwgUHJvamVjdC9rbmItbHRlci1oZnIuMjg1LjYvaGYyODUtMDctbWFwbGUtc2VlZGZpbGxpbmcuY3N2IikNCg0KDQpoZjI4NV8wOF9tYXBsZV9wb2xsZW5fZXhjbCA8LSByZWFkX2NzdigiQzovVXNlcnMvQWRtaW4vRGVza3RvcC9SIHN0YXRzIGhvbWV3b3JrL0ZpbmFsIFByb2plY3Qva25iLWx0ZXItaGZyLjI4NS42L2hmMjg1LTA4LW1hcGxlLXBvbGxlbi1leGNsLmNzdiIpDQoNCg0KaGYyODVfMDlfbWFwbGVfc2VlZF9jb3VudCA8LSByZWFkX2NzdigiQzovVXNlcnMvQWRtaW4vRGVza3RvcC9SIHN0YXRzIGhvbWV3b3JrL0ZpbmFsIFByb2plY3Qva25iLWx0ZXItaGZyLjI4NS42L2hmMjg1LTA5LW1hcGxlLXNlZWQtY291bnQuY3N2IikNCg0KaGYyODVfMTBfbGVhZl9yZW1vdmFsIDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9BZG1pbi9EZXNrdG9wL1Igc3RhdHMgaG9tZXdvcmsvRmluYWwgUHJvamVjdC9rbmItbHRlci1oZnIuMjg1LjYvaGYyODUtMTAtbGVhZi1yZW1vdmFsLmNzdiIpDQoNCmhmMjg1XzExX2xlYWZfcmVtb3ZhbF9icmFuY2hlcyA8LSByZWFkX2NzdigiQzovVXNlcnMvQWRtaW4vRGVza3RvcC9SIHN0YXRzIGhvbWV3b3JrL0ZpbmFsIFByb2plY3Qva25iLWx0ZXItaGZyLjI4NS42L2hmMjg1LTExLWxlYWYtcmVtb3ZhbC1icmFuY2hlcy5jc3YiKQ0KDQoNCmhmMjg1XzEyX2xlYWZfc2VlZF9yZW1vdmFsIDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9BZG1pbi9EZXNrdG9wL1Igc3RhdHMgaG9tZXdvcmsvRmluYWwgUHJvamVjdC9rbmItbHRlci1oZnIuMjg1LjYvaGYyODUtMTItbGVhZi1zZWVkLXJlbW92YWwuY3N2IikNCg0KDQpoZjI4NV8xM19sZWFmX3NlZWRfcmVtb3ZhbF9icmFuY2hlcyA8LSByZWFkX2NzdigiQzovVXNlcnMvQWRtaW4vRGVza3RvcC9SIHN0YXRzIGhvbWV3b3JrL0ZpbmFsIFByb2plY3Qva25iLWx0ZXItaGZyLjI4NS42L2hmMjg1LTEzLWxlYWYtc2VlZC1yZW1vdmFsLWJyYW5jaGVzLmNzdiIpDQoNCmhmMjg1XzE0X3Blcm1fYnJhbmNoZXMgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL0FkbWluL0Rlc2t0b3AvUiBzdGF0cyBob21ld29yay9GaW5hbCBQcm9qZWN0L2tuYi1sdGVyLWhmci4yODUuNi9oZjI4NS0xNC1wZXJtLWJyYW5jaGVzLmNzdiIpDQpgYGANCg0KIyMjIE1hc3RpbmcgYW5kIE5vbi1NYXN0aW5nIA0KDQpGaXJzdCB3ZSBuZWVkIHRvIGJldHRlciB1bmRlcnN0YW5kIG91ciBwcm9ibGVtIGFuZCBsZWFybiBhIGZldyBrZXkgZGVmaW50aW9ucy4gQSBtYXN0aW5nIHRyZWUgaXMgYSB0cmVlIHRoYXQgcHJvZHVjZXMgc2VlZHMgbGFyZ2UgcXVhbml0aWVzIGluIGlycmVndWxhciBpbnRlcnZhbHMuIE91ciBzdWdhciBtYXBsZSB0cmVlcyBhcmUgbWFzdGluZyB0cmVlcyBhbmQgd2Ugd2FudCB0byBrbm93IGlmIHRoZSByZWQgbWFwbGVzIHNob3cgbXV0ZWQgZHluYW1pY3Mgd2hlbiBjb21wYXJlZCB0byB0aGUgc3VnYXIgbWFwbGVzLiBUbyBiZXR0ZXIgdW5kZXJzdGFuZCBvdXIgc3VnYXIgbWFwbGVzIHdlIGZpcnN0IG5lZWQgdG8gc2VlIHdoYXQgeWVhcnMgd2VyZSBtYXN0aW5nIHllYXJzIGZvciB0aGUgdHJlZXMuIFdlIGRvIHRoaXMgYnkgZXhhbWVuaW5nIHRoZSBzZWVkIGNvbGxlY3Rpb24gZGF0YSBhdmVyYWdlIGZvciB0aGUgc3VnYXIgbWFwbGVzIGVhY2ggeWVhciBvZiB0aGUgZGF0YS4gDQoNCmBgYHtyfQ0KDQp0cmVlX3NlZWRfZGF0YSA8LSBoZjI4NV8wOV9tYXBsZV9zZWVkX2NvdW50ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHRvdGFsLmNvdW50KSkgJT4lDQogIG11dGF0ZSh5ZWFyID0gYXMubnVtZXJpYyhmb3JtYXQoZGF0ZSwgIiVZIikpKSAlPiUNCiAgZ3JvdXBfYnkodHJlZSwgeWVhcikgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9TZWVkcyA9IHN1bSh0b3RhbC5jb3VudCwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0KZ2dwbG90KHRyZWVfc2VlZF9kYXRhLCBhZXMoeCA9IGZhY3Rvcih5ZWFyKSwgeSA9IHRyZWUsIGZpbGwgPSBUb3RhbF9TZWVkcykpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gImJsYWNrIiwgbGluZXdpZHRoID0gMC41KSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlllYXJseSBTZWVkIENvdW50IGJ5IFRyZWUiLA0KICAgIHggPSAiWWVhciIsDQogICAgeSA9ICJUcmVlIElEIiwNCiAgICBmaWxsID0gIlNlZWQgQ291bnQiDQogICkNCmBgYA0KQmFzZWQgb24gdGhlIGhlYXQgbWFwIHdlIGNhbiBzZWUgYSBmZXcgeWVhcnMgdGhhdCBzdGljayBvdXQgMjAxMSwgMjAxMywgMjAxNywgYW5kIDIwMTkuIFRoZXNlIGFyZSB0aGUgYmVzdCBpbmRpY2F0b3JzIHRoYXQgc2hvdyB3aGF0IHllYXJzIHdlIGNhbiBzZWUgdGhlIG1hc3RpbmcgdGFraW5nIHBsYWNlIGluIG91ciBzdWdhciBtYXBsZXMuDQoNCg0KTmV4dCBiZWxvdyB3ZSBhZGQgb3VyIG1hc3RpbmcgeWVhcnMgd2UgZm91bmQgdG8gb3VyIHNhcCBjb2xsZWN0aW9uIGFuZCBzdWdhciBjb250ZW50IGRhdGFzZXQgZm9yIHRoZSBhcHByb3ByYXRlIHRyZWVzIHdoaWNoIHdlIGNhbiB1c2UgZm9yIGxhdGVyIHRvIGF0dGVwdCB0byBidWlsZCBhIG1vZGVsIHRvIHByZWRpY3QgbWFzdGluZyBzZWFzb25zLiANCmBgYHtyfQ0KaGYyODVfMDJfbWFwbGVfc2FwIDwtIGhmMjg1XzAyX21hcGxlX3NhcCAlPiUNCiAgbXV0YXRlKGRhdGUgPSBhcy5EYXRlKGRhdGUpKQ0KDQpoZjI4NV8wMl9tYXBsZV9zYXAgPC0gaGYyODVfMDJfbWFwbGVfc2FwICU+JQ0KICBtdXRhdGUoeWVhciA9IHllYXIoZGF0ZSkpDQoNCmhmMjg1XzAyX21hcGxlX3NhcF9tYXN0aW5nIDwtIGhmMjg1XzAyX21hcGxlX3NhcCAlPiUNCiAgbXV0YXRlKG1hc3RpbmcgPSBpZmVsc2UoeWVhciAlaW4lIGMoMjAxMSwgMjAxMywgMjAxNywgMjAxOSksICJZZXMiLCAiTm8iKSkNCg0KaGVhZChoZjI4NV8wMl9tYXBsZV9zYXBfbWFzdGluZykNCmBgYA0KIyMjIEJyZWFraW5nIGRvd24ga2V5IGluZGljYXRvcnMgDQoNCkhlcmUgaWYgd2Ugd2FudCB0byBsb29rIGZvciBrZXkgaW5kaWNhdG9ycyBpbiBvdXIgc3VnYXIgbWFwbGVzIHRoYXQgY291bGQgcHJlZGljdCB3aGVuIGEgbWFzdGluZyBtaWdodCBvY2N1ci4gVGhlc2Uga2V5ZSBwcmVkaWN0b3JzIGNvdWxkIGhlbHAgdXMgYmV0dGVyIGNvbXBhcmUgYW5kIHVuZGVydGFuZCBpZiBvdXIgcmVkIG1hcGxlcyBhcmUgZXhoaWJpdGluZyBzaWducyBvZiANCm11dGVkIGR5bmFtaWNzLiBCZWxvdyB3ZSBncmFwaCBib3RoIHRoZSBzdWdhciBhbmQgcmVkIG1hcGxlcyBhdmVyYWdlIHNhcCBzdWdhciBjb250ZW50IGZvciB5ZWFycyB0aGVyZSB3YXMgZGF0YSBjb2xsZWN0ZWQuIEhGIHN0YW5kcyBmb3Igc3VnYXIgbWFwbGUgYW5kIEFSIGZvciByZWQgbWFwbGUuDQpgYGB7cn0NCmdyb3VwZWRfZGF0YSA8LSBoZjI4NV8wMl9tYXBsZV9zYXAgJT4lDQogIGZpbHRlcighaXMubmEoc3VnYXIpKSAlPiUNCiAgbXV0YXRlKFRyZWVfR3JvdXAgPSBzdWJzdHIodHJlZSwgMSwgMikpICU+JQ0KICBncm91cF9ieShkYXRlLCBUcmVlX0dyb3VwKSAlPiUNCiAgc3VtbWFyaXNlKEF2ZXJhZ2VfU3VnYXIgPSBtZWFuKHN1Z2FyLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQ0KDQpnZ3Bsb3QoZ3JvdXBlZF9kYXRhLCBhZXMoeCA9IGRhdGUsIHkgPSBBdmVyYWdlX1N1Z2FyLCBjb2xvciA9IFRyZWVfR3JvdXAsIGdyb3VwID0gVHJlZV9Hcm91cCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkF2ZXJhZ2UgU3VnYXIgQ29udGVudCBPdmVyIFRpbWUiLA0KICAgIHggPSAiRGF0ZSIsDQogICAgeSA9ICJBdmVyYWdlIFN1Z2FyIENvbnRlbnQiLA0KICAgIGNvbG9yID0gIlRyZWUgR3JvdXAiDQogICkNCmBgYA0KIFdoaWxlIHdlIGNhbiBzZWUgdGhlIGF2ZXJhZ2Ugc3VnYXIgY29udGVudCBpcyBtdWNoIGxvd2VyIGZvciB0aGUgcmVkIG1hcGxlIHRoYXQgZG9lc24ndCBhbnN3ZXIgb3VyIHF1ZXN0aW9uIHJpZ2h0IGF3YXkgZXNwZWNpYWxseSB3aGVuIHRoZSBkYXRhIGNvbGxlY3RlZCBmb3IgcmVkIG1hcGxlcyBpcyB2ZXJ5IHNtYWxsIHdpdGggb25seSBhYm91dCA0LTUgeWVhcnMgb2YgZGF0YSBjb2xsZWN0ZWQgdGhlIGRhdGEgc2ltcGx5IGlzbid0IGNvbmNsdXNpdmUgZW5vdWdoIHRvIGFuc3dlciBvdXIgcXVlc3Rpb24uIA0KDQpIZXJlIGlzIHdoZXJlIGNhbiBzdGFydCB0byBkaWcgaW4gYW5kIHNlZSBpZiBvdmVybGF5aW5nIG91ciBncmFwaHMgYmV0d2VlbiB5ZWFseSBhdmVyYWdlIHN1Z2FyIGNvbnRlbnQgb2YgdGhlIHN1Z2FyIG1hcGxlIHRyZWVzIChIRikgYW5kIHRoZSBhdmVyZ2Ugc2VlZCBjb3VudCBvZiBzdWdhciBtYXBsZXMgaGF2ZSBzaW1sYXIgZ3JhcGhzLiANCg0KIyMjQXZlcmFnZSBzZWVkIGNvdW50IHBlciB5ZWFyIGNvbXBhcmVkIHRvIGF2ZXJhZ2Ugc3VnYXIgY29udGVudCBvZiBzdWdhciBtYXBsZXMgIA0KYGBge3J9DQpoZjI4NV8wMl9tYXBsZV9zYXBfSEYgPC0gaGYyODVfMDJfbWFwbGVfc2FwICU+JSANCiAgZmlsdGVyKGdyZXBsKCJeSEYiLCB0cmVlKSwgIWlzLm5hKHN1Z2FyKSkNCg0KaGYyODVfMDlfbWFwbGVfc2VlZF9jb3VudF9IRiA8LSBoZjI4NV8wOV9tYXBsZV9zZWVkX2NvdW50ICU+JQ0KICBmaWx0ZXIoZ3JlcGwoIl5IRiIsIHRyZWUpLCAhaXMubmEodG90YWwuY291bnQpKQ0KDQpoZjI4NV8wMl9tYXBsZV9zYXBfSEYgPC0gaGYyODVfMDJfbWFwbGVfc2FwX0hGICU+JSANCiAgbXV0YXRlKHllYXIgPSB5ZWFyKGRhdGUpKQ0KDQpoZjI4NV8wOV9tYXBsZV9zZWVkX2NvdW50X0hGIDwtIGhmMjg1XzA5X21hcGxlX3NlZWRfY291bnRfSEYgJT4lDQogIG11dGF0ZSh5ZWFyID0geWVhcihkYXRlKSkNCg0KYXZlcmFnZV9kYXRhIDwtIGhmMjg1XzAyX21hcGxlX3NhcF9IRiAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcmlzZShhdmVyYWdlX3N1Z2FyID0gbWVhbihzdWdhciwgbmEucm0gPSBUUlVFKSkNCg0KYXZlcmFnZV9zZWVkcyA8LSBoZjI4NV8wOV9tYXBsZV9zZWVkX2NvdW50X0hGICU+JQ0KICBncm91cF9ieSh5ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKGF2ZXJhZ2Vfc2VlZHMgPSBtZWFuKHRvdGFsLmNvdW50LCBuYS5ybSA9IFRSVUUpKQ0KDQptZXJnZWRfYXZnX2RhdGEgPC0gbGVmdF9qb2luKGF2ZXJhZ2VfZGF0YSwgYXZlcmFnZV9zZWVkcywgYnkgPSAieWVhciIpDQoNCm1lcmdlZF9hdmdfZGF0YV9jbGVhbiA8LSBtZXJnZWRfYXZnX2RhdGEgJT4lDQogIGZpbHRlcighaXMubmEoYXZlcmFnZV9zdWdhcikgJiAhaXMubmEoYXZlcmFnZV9zZWVkcykpDQoNCnN1Z2FyX2NvbnRlbnRfSEYgPC0gZ2dwbG90KG1lcmdlZF9hdmdfZGF0YV9jbGVhbiwgYWVzKHggPSB5ZWFyLCB5ID0gYXZlcmFnZV9zdWdhcikpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gInJlZCIsIHNpemUgPSAzKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQXZlcmFnZSBTdWdhciBDb250ZW50IGZvciBIRiBUcmVlcyBieSBZZWFyIiwNCiAgICB4ID0gIlllYXIiLA0KICAgIHkgPSAiQXZlcmFnZSBTdWdhciBDb250ZW50Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnNlZWRfY291bnRfSEYgPC0gZ2dwbG90KG1lcmdlZF9hdmdfZGF0YV9jbGVhbiwgYWVzKHggPSB5ZWFyLCB5ID0gYXZlcmFnZV9zZWVkcykpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImdyZWVuIiwgc2l6ZSA9IDEpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJvcmFuZ2UiLCBzaXplID0gMykgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkF2ZXJhZ2UgU2VlZCBDb3VudCBmb3IgSEYgVHJlZXMgYnkgWWVhciIsDQogICAgeCA9ICJZZWFyIiwNCiAgICB5ID0gIkF2ZXJhZ2UgU2VlZCBDb3VudCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpwcmludChzdWdhcl9jb250ZW50X0hGKQ0KcHJpbnQoc2VlZF9jb3VudF9IRikNCmBgYA0KSGVyZSB3ZSBjYW4gc2VlIHRoYXQgd2hpbGUgdGhlIGdyYXBocyBkbyBoYXZlIGEgc2ltaWxhciBzaGFwZSB0aGUgb3ZlcmFsbCBwYXR0ZXJucyBkb24ndCBtYXRjaCBleGFjdGx5IHNvIHRvIGJldHRlciB0cnkgYW5kIGZpbmQgb3VyIGtleSBwcmVkaWN0b3JzIHdlIGNhbiB1c2Ugb3VyIGFkZGVkIG1hc3RpbmcgY29sdW1uIGZyb20gZWFybGllciB0byBjcmVhdGUgYSBsaW5lYXIgbW9kZWwuIA0KDQojIyMgQnVpbGRpbmcgYSBtb2RlbCB3aXRoIG91ciBkYXRhDQoNCkJlbG93IHdlIHVzZSBvdXIgYWRkZWQgZGF0YSBmcm9tIGJlZm9yZSB0byBhdHRlcHQgdG8gcHJlZGljdCB0aGUgc3VnYXIgdHJlZSBtYXN0aW5ncyBiYXNlZCBvbiBzdWdhciBjb250ZW50IG9mIHRyZWVzIHNhcC4gDQpgYGB7cn0NCmhmMjg1XzAyX21hcGxlX3NhcF9IRiA8LSBoZjI4NV8wMl9tYXBsZV9zYXBfbWFzdGluZyAlPiUNCiAgbXV0YXRlKG1hc3RpbmdfYmluYXJ5ID0gaWZlbHNlKG1hc3RpbmcgPT0gIlllcyIsIDEsIDApKQ0KDQpsbV9tb2RlbCA8LSBsbShtYXN0aW5nX2JpbmFyeSB+IHN1Z2FyLCBkYXRhID0gaGYyODVfMDJfbWFwbGVfc2FwX0hGKQ0KDQpzdW1tYXJ5KGxtX21vZGVsKQ0KYGBgDQpIZXJlIHdlIGdldCB0byBrbm93IGJyZWFrIGRvd24gb3VyIG1vZGVsIGFuZCBsb29rIGF0IGl0cyBrZXkgdmFsdWVzLiBSaWdodCBvZmYgdGhlIGJhdCB3ZSBjYW4gc2VlIHRoZSBzdWdhciBjb2VmIG9mIC4wNDE1NTUgc28gZm9yIGV2ZXJ5IGluY3JlYXNlIGluIDEgdW5pdCBvZiBzdWdhciB3ZSBzZWUgYSA0LjE1JSBpbmNyZWFzZSBpbiB0aGUgY2hhbmNlIG9mIGEgbWFzdGluZyB5ZWFyLiBOZXh0IHdlIGNhbiBzZWUgdGhhdCBvdXIgUlNFIGlzIHF1aXRlIGhpZ2gsIGEgbG93ZXIgdmFsdWUgd291bGQgYmUgYmV0dGVyIGJ1dCB0aGlzIGRvZXMgc2hvdyB0aGF0IHNvbWUgdmFyaWFiaWxpdHkgcmVtYWlucyB1bmV4cGxhaW5lZC4gT3VyIFIgc3F1YXJlZCB2YWx1ZSBvZiBqdXN0IC4wMDMzNTIgc2hvd3MgdGhhdCBzdWdhciBhbG9uZSBpcyBub3QgYSBzdHJvbmcgcHJlZGljdG9yLiBMYXN0bHkgd2UgbG9vayBhdCBvdXIgcC12YWx1ZSB3aGljaCBzaG93cyBhbiBpbmNyZWRseSBzbWFsbCAyLjE0M2UtMDcuIFNvIHdoaWxlIHN1Z2FyIGlzbid0IGEgZ3JlYXQgc29sbyBwcmVkaWN0b3Igb3VyIG5ldyBtb2RlbCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiANCg0KDQpXaXRoIHN1Z2FyIGNvbnRlbnQgaGVscGluZyB3b3JrIHRvd2FyZHMgYSBzdHJvbmdlciBtb2RlbCB3ZSBjYW4gbG9vayBhdCBvdGhlciBwb3NzaWJsZSBwcmVkaWN0b3JzIHdlIG1pZ2h0IGhhdmUgb3ZlciBsb29rZWQuIEJlbG93IEkgaGF2ZSB0YWtlbiB0aGVoZjI4NV8wM19tYXBsZV9mbG93ZXJfcXVhbCBkYXRhIHNldCBhbmQgZWRpdGVkIHRoZSBkYXRhIHRvIGdpdmUgdmFsdWVzIHRvIHRoZSBmbG93ZXJpbmcuaW50ZW5zaXR5IGJhc2VkIG9uIHRoZSB2YWx1ZXMgcHJvdmlkZWQgYnkgSGFydmFkcyByYW5nZXMgd2hpY2ggY2FuIGJlIGZvdW5kIGhlcmUgaHR0cHM6Ly9oYXJ2YXJkZm9yZXN0MS5mYXMuaGFydmFyZC5lZHUvZXhpc3QvYXBwcy9kYXRhc2V0cy9zaG93RGF0YS5odG1sP2lkPWhmMjg1LiBXaGljaCBzdGF0ZXMgdGhhdCBkYXRhIHNldCBoZjI4NV8wM19tYXBsZV9mbG93ZXJfcXVhbCBnaXZlcyB0aGVzZSByYW5nZXMNCg0KImZsb3dlcmluZy5pbnRlbnNpdHk6IHF1YWxpdGF0aXZlIGV2YWx1YXRpb24gb2Ygd2hvbGUtdHJlZSBmbG93ZXJpbmcNCiAgICBsb3c6IGdlbmVyYWxseSA8MSwwMDAgZmxvd2VyaW5nIGJ1ZHMNCiAgICBtZWRpdW06IGdlbmVyYWxseSAxLDAwMC0xMCwwMDAgZmxvd2VyaW5nIGJ1ZHMNCiAgICBoaWdoOiBnZW5lcmFsbHkgPjEwLDAwMCBmbG93ZXJpbmcgYnVkcw0KICAgIG5vbmU6IG5vIGZsb3dlcmluZyBidWRzIg0KDQpgYGB7cn0NCg0KaGYyODVfMDNfbWFwbGVfZmxvd2VyX3F1YWxfZWRpdCA8LSBoZjI4NV8wM19tYXBsZV9mbG93ZXJfcXVhbCAlPiUNCiAgbXV0YXRlKGZsb3dlcmluZ192YWx1ZSA9IGNhc2Vfd2hlbigNCiAgICBmbG93ZXJpbmcuaW50ZW5zaXR5ID09ICJub25lIiB+IDAsDQogICAgZmxvd2VyaW5nLmludGVuc2l0eSA9PSAibG93IiB+IDk5OSwNCiAgICBmbG93ZXJpbmcuaW50ZW5zaXR5ID09ICJtZWRpdW0iIH4gNTAwMCwNCiAgICBmbG93ZXJpbmcuaW50ZW5zaXR5ID09ICJoaWdoIiB+IDEwMDAwLA0KICAgIFRSVUUgfiBOQV9yZWFsXw0KICApKQ0KDQpoZWFkKGhmMjg1XzAzX21hcGxlX2Zsb3dlcl9xdWFsX2VkaXQpDQpgYGANCldoaWxlIGNyZWF0aW5nIHRoZSBudW1iZXJzIGZvciBlYWNoIGdyb3VwIGlzIG92ZXJyZWFjaGluZy4gVGhlIGRhdGFzZXQgaXRzZWxmIGdpdmVzIHVzIHZlcnkgbGl0dGxlIHRvIHdvcmsgd2l0aCBzbyBhdHRlcHRpbmcgdG8gcHV0IG51bWJlcnMgdG8gdmFsdWVzIHRoYXQgSGFydmFkIG9mZmVyZWQgaXMgdGhlIGJlc3Qgd2UgY2FuIGRvIHRvIGdldCBhIGJldHRlciBpZGVhIG9mIG91ciBwcmVkaWN0b3JzLg0KDQoNCk5vdyB0aGF0IHdlIGhhdmUgdmFsdWVzIGZvciBvdXQgZmxvd2VyIGludGVuc2l0eSB3ZSBjYW4gcHV0IGl0IHRvIGEgZ3JhcGggYW5kIGNvbXBhcmUgdG8gb3VyIGdyYXBoIG9mIG1hc3RpbmdzDQoNCmBgYHtyfQ0KYXZlcmFnZV9mbG93ZXJpbmdfZGF0YSA8LSBoZjI4NV8wM19tYXBsZV9mbG93ZXJfcXVhbF9lZGl0ICU+JQ0KICBncm91cF9ieSh5ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKGF2ZXJhZ2VfZmxvd2VyaW5nID0gbWVhbihmbG93ZXJpbmdfdmFsdWUsIG5hLnJtID0gVFJVRSkpDQoNCg0KDQpnZ3Bsb3QoYXZlcmFnZV9mbG93ZXJpbmdfZGF0YSwgYWVzKHggPSBmYWN0b3IoeWVhciksIHkgPSBhdmVyYWdlX2Zsb3dlcmluZykpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDMpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJBdmVyYWdlIEZsb3dlcmluZyBJbnRlbnNpdHkgZm9yIHRoZSBGb3Jlc3QgT3ZlciBUaW1lIiwNCiAgICB4ID0gIlllYXIiLA0KICAgIHkgPSAiQXZlcmFnZSBGbG93ZXJpbmcgSW50ZW5zaXR5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KSGVyZSB3ZSBjYW4gc2VlIGEgc3Ryb25nIHBhdHRlcm4gdGhvdWdoIHdlIHNlZSBsYXJnZSBzcGlrZXMgb24gb3VyIG1hc3RpbmcgeWVhcnMgd2l0aCAyMDExLCAyMDEzLCAyMDE3LCBhbmQgMjAxOSEgVGhpcyBpcyB2ZXJ5IGJpZyBiZWN1YXNlIGl0IG1hdGNoZXMgdmVyeSBjbG9zZSB0byBvdXIgaGVhdCBtYXAgb2Ygb3VyIG1hc3RpbmcgeWVhcnMuIEJ1dCBqdXN0IGxvb2tpbmcgc2ltaWxhciBpc24ndCBlbm91Z2gsIHdlIGNhbiB0ZXN0IHRoaXMgYnkgYWRkaW5nIG9uIHRvIG91ciBsaW5lYXIgbW9kZWwgdG8gc2VlIGlmIHRoZSBudW1iZXIgb2YgZmxvd2VycyBpcyBhIGdvb2QgcHJlZGljdG9yLg0KDQpCZWxvdyB3ZSBsb29rIHRvIHRlc3QgaWYgdGhlIG51bWJlciBvZiBmbG93ZXIgaXMgYSBhY2N1cmF0ZSBwcmVkaWN0b3Igb24gaWYgc3VnYXIgbWFwbGUgdHJlZXMgd2lsbCBoYXZlIGEgbWFzdGluZyB5ZWFyLiBCeSBjb21iaW5pbmcgaXQgd2l0aCBvdXIgc3VnYXIgbW9kZWwgZnJvbSBlYXJsaWVyLiANCmBgYHtyfQ0KYXZlcmFnZV9mbG93ZXJpbmdfZGF0YV9tYXN0aW5nIDwtIGhmMjg1XzAzX21hcGxlX2Zsb3dlcl9xdWFsX2VkaXQgJT4lDQogIG11dGF0ZSgNCiAgICBtYXN0aW5nID0gaWZlbHNlKHllYXIgJWluJSBjKDIwMTEsIDIwMTMsIDIwMTcsIDIwMTkpLCAiWWVzIiwgIk5vIiksDQogICAgbWFzdGluZ19iaW5hcnkgPSBpZmVsc2UobWFzdGluZyA9PSAiWWVzIiwgMSwgMCkNCiAgKQ0KbG1fbW9kZWxfZmxvd2VyaW5nIDwtIGxtKG1hc3RpbmdfYmluYXJ5IH4gZmxvd2VyaW5nX3ZhbHVlLCBkYXRhID0gYXZlcmFnZV9mbG93ZXJpbmdfZGF0YV9tYXN0aW5nKQ0KDQpzdW1tYXJ5KGxtX21vZGVsX2Zsb3dlcmluZykNCmBgYA0KRmlyc3Qgb2ZmIHdlIGNhbiBzZWUgYnkgb3VyIGF2ZXJhZ2VfZmxvd2VyaW5nIGNvZWYgc2hvd2luZyAuMDA0IGF2ZXJhZ2UgZmxvd2VyaW5nIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIFNlY29uZCB3ZSBjYW4gc2VlIG91ciBpbnRlcmNlcHQgc2hvd3MgdGhhdCBmb3IgZXZlcnkgaW5jcmVhc2UgYnkgMSBmbG93ZXIgaW5jcmVhc2VzIHRoZSBjaGFuY2Ugb2YgYSBtYXN0aW5nIHllYXIgYnkgLjAwMDEuIFdoaWNoIG9uIHRoZSBzdXJmYWNlIGRvZXNuJ3Qgc2VlbSBsaWtlIG11Y2ggd2hlbiBkZWFsaW5nIHdpdGggdHJlZXMgdGhlc2UgYmxvc3NvbXMgY2FuIHJhbmdlIGZyb20gYSBmZXcgaHVuZHJlZCB0byB3ZWxsIG92ZXIgdGVuIHRob3VzYW5kIHRoaXMgY2FuIGFkZCB1cC4gTm93IHdoZW4gd2UgbG9vayBhdCBSU0UgdGhlcmUgYXJlIGltcHJvdmVtZW50cyBvdmVyIHRoZSBzdWdhciBtb2RlbCB3aXRoIG91cnMgYmVpbmcgLjMzNCB3aGljaCBzaG93cyB1cyB0aGUgbW9kZWwgaXMgYSBiZXR0ZXIgZml0LiBPdXIgUiBzcXVhcmVkIHNob3dzIC41Nzkgc2hvd2luZyB1cyB0aGF0IGFib3V0IDU4JSBvZiB0aGUgdmFyaWFuY2UgaW4gdGhlIG1hc3RpbmcgYmluYXJ5IG91dGNvbWUgaXMgZXhwbGFpbmVkIGJ5IGF2ZXJhZ2VfZmxvd2VyaW5nLiBMYXN0bHkgb3VyIHAtdmFsdWUgc2hvd3MgdGhhdCBvdmVyIGFsbCB0aGlzIG1vZGVsIGlzICBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiANCg0KDQpgYGB7cn0NCg0KdmlldyhoZjI4NV8wMl9tYXBsZV9zYXBfbWFzdGluZykNCg0KY29tYmluZWRfZGF0YSA8LSBsZWZ0X2pvaW4oDQogIGF2ZXJhZ2VfZmxvd2VyaW5nX2RhdGFfbWFzdGluZywgDQogIGhmMjg1XzAyX21hcGxlX3NhcF9tYXN0aW5nICU+JSANCiAgICBncm91cF9ieSh5ZWFyKSAlPiUgDQogICAgc3VtbWFyaXNlKGF2ZXJhZ2Vfc3VnYXIgPSBtZWFuKHN1Z2FyLCBuYS5ybSA9IFRSVUUpKSwgDQogIGJ5ID0gInllYXIiDQopDQoNCg0KY29tYmluZWRfbG0gPC0gbG0obWFzdGluZ19iaW5hcnkgfiBmbG93ZXJpbmdfdmFsdWUgKyBhdmVyYWdlX3N1Z2FyLCBkYXRhID0gY29tYmluZWRfZGF0YSkNCg0Kc3VtbWFyeShjb21iaW5lZF9sbSkNCg0KYGBgDQpGaXJzdCBvZmYgd2UgY2FuIHNlZSBieSBvdXIgYXZlcmFnZV9mbG93ZXJpbmcgY29lZiBpcyBpbmNyZWRpYmx5IHNtYWxsIHNvIGF2ZXJhZ2UgZmxvd2VyaW5nIGlzIGhpZ2hseSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiBTZWNvbmQgd2UgY2FuIHNlZSBvdXIgaW50ZXJjZXB0IHNob3dzIHRoYXQgZm9yIGV2ZXJ5IGluY3JlYXNlIGJ5IDEgZmxvd2VyIGluY3JlYXNlcyB0aGUgY2hhbmNlIG9mIGEgbWFzdGluZyB5ZWFyIGJ1dCBvbmx5IGJ5IDQuODk3ZS0wNS4gV2hpY2ggb24gdGhlIHN1cmZhY2UgZG9lc24ndCBzZWVtIGxpa2UgbXVjaCB3aGVuIGRlYWxpbmcgd2l0aCB0cmVlcyB0aGVzZSBibG9zc29tcyBjYW4gcmFuZ2UgZnJvbSBhIGZldyBodW5kcmVkIHRvIHdlbGwgb3ZlciB0ZW4gdGhvdXNhbmQgdGhpcyBjYW4gYWRkIHVwLiBPdXIgYXZlcmFnZSBzdWdhciBoYXMgY2hhbmdlZCBzb21lIHRvbyB3ZSBub3cgc2VlIHRoZSBjb2VmIGF0IC4wMDIgbWFraW5nIGl0IGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBwcmVkaWN0b3Igb2YgbWFzdGluZy4gTm93IHdoZW4gd2UgbG9vayBhdCBSU0UgdGhlcmUgYXJlIGltcHJvdmVtZW50cyBvdmVyIHRoZSBzdWdhciBtb2RlbCB3aXRoIG91cnMgYmVpbmcgLjM3NiB3aGljaCBzaG93cyB1cyB0aGUgbW9kZWwgaXMgYSBiZXR0ZXIgZml0IHRoZW4gYmVmb3JlLiBPdXIgUiBzcXVhcmVkIHNob3dzIC4yOTUgc2hvd2luZyB1cyB0aGF0IGFib3V0IDMwJSBvZiB0aGUgdmFyaWFuY2UgaW4gdGhlIG1hc3RpbmcgYmluYXJ5IG91dGNvbWUgaXMgZXhwbGFpbmVkIGJ5IGF2ZXJhZ2VfZmxvd2VyaW5nIGFuZCBhdmVyYWdlX3N1Z2FyLiBMYXN0bHkgb3VyIHAtdmFsdWUgc2hvd3MgdGhhdCBvdmVyIGFsbCB0aGlzIG1vZGVsIGlzIGhpZ2hseSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiBXaGlsZSBvdXIgZGF0YSBzaG93cyB0aGF0IHRoaXMgbW9kZWwgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBvdXIgUiBzcXVhcmVkIG9ubHkgZXhwbGFpbnMgYWJvdXQgMzAlIG9mIHRoZSB2YXJpYW5jZSBpbiB0aGUgbW9kZWwgc2hvd2luZyB0aGUgbW9kZWwgbmVlZHMgbW9yZSBkYXRhIHRvIGJldHRlciBwcmVkaWN0IG1hc3Rpbmcgc2Vhc29ucy4gDQoNCg0KIyMjIEluIGNvbmNsdWlvbiANCk92ZXJhbGwsIHdoaWxlIHRoZXJlIGlzIG5vdCBlbm91Z2ggZGF0YSB0byBhY2N1cmF0ZWx5IHN0YXRlIHdoZXRoZXIgcmVkIG1hcGxlIHNwZWNpZXMgZXhoaWJpdCBtdXRlZCBkeW5hbWljcw0Kb3Igbm90IEkgYmVsaWV2ZSB0aGF0IHRoZSB0d28gYmVzdCBrZXkgcHJlZGljdG9yIGluIHRoaXMgbGltaXRlZCBkYXRhIHNldCBhcmUgc2FwIHN1Z2FyIGNvbnRlbnQgYW5kIHRoZSBudW1iZXIgb2YgZmxvd2VycyBpbiBibG9vbS4gSWYgdGhlIGRhdGEgd2VyZSBtb3JlIGNvbXBsZXRlIEkgYmVsaWV2ZSB0aGF0IHRoZXNlIHR3byBwcmVkaWN0b3JzIGNvdWxkIGJlIHVzZWQgdG8gYmV0dGVyIHNlZSBpZiB0aGUgcmVkIG1hcGxlIHRyZWVzIGV4aGliaXQgbXV0ZWQgZHluYW1pY3Mgd2hlbiBjb21wYXJlZCB0byB0aGUgc3VnYXIgbWFwbGUgdHJlZXMgYnV0IHdpdGggdGhlIGN1cnJlbnQgZGF0YSBzZXQgbGltaXRhdGlvbnMgdGhlIGRhdGEgaXMgaW5jb25jbHVzaXZlIA==