Objective

  1. Compare default ED with UMBS SLA and Vcmax
  2. Update ED SLA to UMBS values

Markdown set up

1. Ed vs UMBS

Compare the default ED SLA and Vcmax values with observations from UMBS.

A. Import Data

Import the data sets.

# The results from  a ED run 
ed_data <- readRDS(file.path(OUTPUT_DIR, "full-length.rds"))
# Read UMBS data from the fortedata  pacakge. 
umbs_sla <- as.data.table(read.csv(system.file('extdata/fd_sla.csv', package = 'fortedata'), 
                                   stringsAsFactors = FALSE))

Create mapping data frame that will be used to map ed pfts to the umbs species.

# The ED pfts 
PFTs    <- c(6, 8, 9, 10, 11, 7) # The PFTS to keep, some of the ED outputs report all of the PFTs.
pft_names <- data.table(pft = PFTs, 
                        pft_name = c('Northern North American pines', 
                                     'Late-successional North American conifers', 
                                     'Temperate broadleaf, early successional',  
                                     'Temperate broadleaf, mid-successional', 
                                     'Temperate broadleaf, late successional', 
                                     'Southern North American pines'), stringsAsFactors = FALSE)
pft_names <- pft_names[! pft %in% c(7, 8)]
# UMBS to ED pfts
mid_success       <- data.table(pft = 10, UMBS = c('ACRU','ACPE',  'FAGR', 'ACSA'), stringsAsFactors = FALSE)
temp_broadl_late  <- data.table(pft = 11, UMBS = c('QURU', 'TCSA'), stringsAsFactors = FALSE)
nor_pines         <- data.table(pft = 6, UMBS = c('PIST', 'PIRE'), stringsAsFactors = FALSE)
temp_broadl_early <- data.table(pft = 9, UMBS = c("AMEL", "POGR", "BEPA", "BEAL", "POTR"), stringsAsFactors = FALSE)
umbs_ed <- rbind(mid_success, temp_broadl_late, nor_pines, temp_broadl_early)

Let’s take a look at the maping betwee the UMBS species and the ED pfts.

umbs_ed[pft_names, on = 'pft', nomatch = 0][ , list(pft_name, pft, UMBS)] %>% 
  knitr::kable(format = 'markdown')
pft_name pft UMBS
Northern North American pines 6 PIST
Northern North American pines 6 PIRE
Temperate broadleaf, early successional 9 AMEL
Temperate broadleaf, early successional 9 POGR
Temperate broadleaf, early successional 9 BEPA
Temperate broadleaf, early successional 9 BEAL
Temperate broadleaf, early successional 9 POTR
Temperate broadleaf, mid-successional 10 ACRU
Temperate broadleaf, mid-successional 10 ACPE
Temperate broadleaf, mid-successional 10 FAGR
Temperate broadleaf, mid-successional 10 ACSA
Temperate broadleaf, late successional 11 QURU
Temperate broadleaf, late successional 11 TCSA

B. Format UMBS SLA

# Add the ED PFT information to the UMBS SLA measurements. 
umbs_sla <- umbs_sla[umbs_ed, on = c('species' = 'UMBS'), nomatch  = 0]

As Alexey noted, convert the SLA units.

umbs_sla$sla <- umbs_sla$sla * (1/0.48)
# Now determine the average value for each PFT, this is more analagous to what ED  does. 
umbs_sla <- umbs_sla[ , list(sla = mean(sla), min = min(sla), max = max(sla)), by = list(pft)]
umbs_sla <- pft_names[umbs_sla, on = "pft", nomatch = 0][, list(pft_name, pft, sla, min, max)] 

Let’s take a look at what UMBS SLA values look like

knitr::kable(umbs_sla)
pft_name pft sla min max
Temperate broadleaf, mid-successional 10 47.91667 39.58333 72.91667
Temperate broadleaf, late successional 11 20.87500 12.16667 29.58333
Northern North American pines 6 18.63542 11.22917 26.04167
Temperate broadleaf, early successional 9 37.46667 33.10417 43.37500

C. Format ED SLA

Import ED results and select the SLA values from our baseline run. Note that we will only be able to extract SLA values from the output, the Vcmax will have to come in put parameters.

ed_data$df_cohort[[1]] %>%
  dplyr::select(SLA, datetime, DBH, PFT) %>%  
  dplyr::left_join(pft_names, by = c('PFT' = "pft")) %>%  
  dplyr::select(pft_name, pft = PFT, SLA)  %>% 
  dplyr::distinct() %>%  
    as.data.table() -> 
    ed_sla
  knitr::kable(ed_sla)
pft_name pft SLA
Northern North American pines 6 6.0
Temperate broadleaf, mid-successional 10 24.2
Temperate broadleaf, late successional 11 60.0
Temperate broadleaf, early successional 9 30.0

D. Compare ED and UMBS SLA

ggplot() + 
    geom_point(data = umbs_sla, aes(pft_name, min, color = 'umbs', shape = 'min sla'),  size = 4) + 
    geom_point(data = umbs_sla, aes(pft_name, max, color = 'umbs', shape = 'max sla'),  size = 4) + 
    geom_point(data = umbs_sla, aes(pft_name, sla, color = 'umbs', shape = 'mean sla'),  size = 4) + 
  geom_point(data = ed_sla, aes(pft_name, SLA, color = 'ed', shape = 'mean sla'),  size = 4) + 
  THEME + 
  theme( axis.text.x = element_text(angle = 25, hjust = 1), 
         legend.position = 'bottom', 
         legend.text = element_text(size = 16)) + 
  labs(title = 'Comparison of UMBS and ED SLA', 
       y = 'SLA', 
       x = 'ED PFTs')

Recall from baseline ed run that the stand is dominated by the temperate broadlead early succesional.

E. ED Vcmax

Taking a look at ED code we can pull out the \({V}_{m0}\) values which is \({V}_{cmax}\) at 15 C instead of 25 C see Alexey’s notes.

ed_Vm0 <- cbind(pft_names, Vm0 = c(11.350000, 20.387075, 17.454687, 6.981875))

Now need to convert from the 15C to 25C, we can use the arrhenius scaling function from the fortebaseline.

ed_Vcmax_values <- arrhenius.scaling(observed.value = ed_Vm0$Vm0, 
                                     old.temp = 15,
                                     new.temp = 25)
ed_Vcmax <- cbind(pft_names, Vcmax = ed_Vcmax_values)

F. UMBS Vcmax

Lisa sent me some data for UMBS to provide a ball park estimate of the Vcmax values.

UMBS data table

UMBS  <- c('ACRU', 'BEPA', 'QURU', 'POGR')
Vcmax <- c(47.3, 58.5, 62.6, 71.4)
umbs_vcmax <- data.table(UMBS = UMBS, Vcmax = Vcmax)
umbs_vcmax <- umbs_vcmax[umbs_ed, on = 'UMBS', nomatch = 0]
umbs_vcmax <- umbs_vcmax[pft_names, on = 'pft', nomatch = 0]

G. Vcmax Comparison

Compare the UMBS and the ED Vcmax values.

ggplot() + 
  geom_point(data = ed_Vcmax, aes(pft_name, Vcmax, color = 'ED'), size = 3) + 
    geom_point(data = umbs_vcmax, aes(pft_name, Vcmax, color = 'UMBS'), size = 3) + 
    THEME + 
  theme( axis.text.x = element_text(angle = 25, hjust = 1), 
         legend.position = 'bottom', 
         legend.text = element_text(size = 16)) + 
  labs(title = 'Comparison of UMBS and ED Vcmax', 
       y = 'Vcmax', 
       x = 'ED PFTs')

Vcmax seems to be fairly high.

H. Concluding Thoughts & Next Steps

  • This analysis only makes sense if the ED PFTs and UMBS species are categorized properly
  • The ED temprate borad leaf late sucessional SLA is really far off! Could this be throwing the ED forest off?
  1. Ed run with “realistic” SLA
  2. Ed run with “realistic” Vcmax
  3. Ed run with “realistic” SLA and Vcmax

2. Adjust ED SLA

What happens when the ED SLA values are updated to better reflect the UMBS SLA values?

A. Import and format the results from the SLA adjusted run.

Start by importing and formating results from the FoRTE baseline run.

# Read the input file 
baseline <- readRDS(file.path(OUTPUT_DIR, 'test', 'baseline.rds'))
# Extract the SLA values, these will be compared with the old sla ED values and the UMBS observations. 
baseline$df_cohort[[1]] %>%
  dplyr::select(SLA, datetime, DBH, PFT) %>%  
  dplyr::left_join(pft_names, by = c('PFT' = "pft")) %>%  
  dplyr::select(pft_name, pft = PFT, SLA)  %>% 
  dplyr::distinct() %>%  
  as.data.table() ->
 ED_default_sla
ED_default_sla$scn <- 'default SLA'
ED_default_LAI <- as.data.table(baseline$df_pft[[1]])[  ,list(datetime, MMEAN_LAI_PY, pft)]
ED_default_LAI$datetime <- ymd(ED_default_LAI$datetime)
ED_default_LAI$year     <- year(ED_default_LAI$datetime)
ED_default_LAI$month    <- month(ED_default_LAI$datetime)
ED_default_LAI$variable <- 'MMEAN_LAI_CO'
ED_default_LAI <- ED_default_LAI[as.data.table(ed2_variable_info())[, list(variable, description, unit)], 
           on = 'variable',  nomatch=0]
ED_default_LAI     <- ED_default_LAI[pft_names, on = c('pft')]
ED_default_LAI$scn <- 'default SLA'
ED_default_NPP <- as.data.table(baseline$df_scalar[[1]])[  ,list(datetime, MMEAN_NEP_PY)]
ED_default_NPP$datetime <- ymd(ED_default_NPP$datetime)
ED_default_NPP$year <- year(ED_default_NPP$datetime)
ED_default_NPP$month <- month(ED_default_NPP$datetime)
ED_default_NPP$variable <- 'MMEAN_NEP_PY'
ED_default_NPP <- ED_default_NPP[as.data.table(ed2_variable_info())[, list(variable, description, unit)], 
                                 on = 'variable',  nomatch=0]
ED_default_NPP <- ED_default_NPP[, list(value = mean(MMEAN_NEP_PY, na.rm = TRUE)), 
                                 by = list(year, variable, unit, description)]
ED_default_NPP$scn <- 'ED default'

B. Import and format the results from the SLA adjusted run.

# Read in the input 
umbs_sla_adjusted <- readRDS(file.path(OUTPUT_DIR, 'test', 'UMBS_SLA-1.rds'))
# Extract the SLA values, these will be compared with the old sla ED values and the UMBS observations. 
umbs_sla_adjusted$df_cohort[[1]] %>%
  dplyr::select(SLA, datetime, DBH, PFT) %>%  
  dplyr::left_join(pft_names, by = c('PFT' = "pft")) %>%  
  dplyr::select(pft_name, pft = PFT, SLA)  %>% 
  dplyr::distinct() %>%  
  as.data.table() ->
  ED_adjusted_sla
ED_adjusted_sla$scn <- 'adjusted SLA'
umbs_sla_adjusted_LAI <- as.data.table(umbs_sla_adjusted$df_pft[[1]])[  ,list(datetime, MMEAN_LAI_PY, pft)]
umbs_sla_adjusted_LAI$datetime <- ymd(umbs_sla_adjusted_LAI$datetime)
umbs_sla_adjusted_LAI$year     <- year(umbs_sla_adjusted_LAI$datetime)
umbs_sla_adjusted_LAI$month    <- month(umbs_sla_adjusted_LAI$datetime)
umbs_sla_adjusted_LAI$variable <- 'MMEAN_LAI_CO'
umbs_sla_adjusted_LAI <- umbs_sla_adjusted_LAI[as.data.table(ed2_variable_info())[, list(variable, description, unit)], 
                                               on = 'variable',  nomatch=0]
umbs_sla_adjusted_LAI <- umbs_sla_adjusted_LAI[pft_names, on = c('pft')]
umbs_sla_adjusted_LAI$scn <- 'adjusted SLA'
umbs_ed_NPP <- as.data.table(umbs_sla_adjusted$df_scalar[[1]])[  ,list(datetime, MMEAN_NEP_PY)]
umbs_ed_NPP$datetime <- ymd(umbs_ed_NPP$datetime)
umbs_ed_NPP$year <- year(umbs_ed_NPP$datetime)
umbs_ed_NPP$month <- month(umbs_ed_NPP$datetime)
umbs_ed_NPP$variable <- 'MMEAN_NEP_PY'
umbs_ed_NPP <- umbs_ed_NPP[as.data.table(ed2_variable_info())[, list(variable, description, unit)], 
                           on = 'variable',  nomatch=0]
umbs_ed_NPP <- umbs_ed_NPP[, list(value = mean(MMEAN_NEP_PY, na.rm = TRUE)), 
                           by = list(year, variable, unit, description)]
umbs_ed_NPP$scn <- 'UMBS ed'
ED_umbs_AGB <- as.data.table(umbs_sla_adjusted$df_cohort[[1]])[  ,list(datetime, AGB_CO, PFT, DBH, NPLANT)]
# Add a unique identifier for each of the cohorts (reminder that cohorts = unique species at DBH)
split(ED_umbs_AGB, ED_umbs_AGB$datetime) %>%  
  lapply(function(x){
    
    x$CO <- LETTERS[1:nrow(x)]
    return(x)
    
  }) %>% 
  rbindlist() -> 
  ED_umbs_AGB
ED_umbs_AGB <- ED_umbs_AGB[pft_names, on = c('PFT' = 'pft')]
ED_umbs_AGB$year <- year(ED_umbs_AGB$datetime)
ED_umbs_AGB$month <- month(ED_umbs_AGB$datetime)
ED_umbs_AGB$variable <- "AGB_CO"
ED_umbs_AGB <- ED_umbs_AGB[as.data.table(ed2_variable_info())[, list(variable, description, unit)], on = 'variable',  nomatch=0]
ED_umbs_AGB$value <- ED_umbs_AGB$NPLANT * ED_umbs_AGB$AGB_CO
ED_umbs_AGB$unit <- gsub(pattern = '/plant', replacement = '/m2', ED_umbs_AGB$unit)
ED_umbs_AGB$scn <- 'umbs sla ed'

C. Compare Ed

The SLA values

ggplot() + 
  geom_point(data = umbs_sla, aes(pft_name, min, color = 'umbs', shape = 'min sla'),  size = 4) + 
    geom_point(data = umbs_sla, aes(pft_name, max, color = 'umbs', shape = 'max sla'),  size = 4) + 
    geom_point(data = umbs_sla, aes(pft_name, sla, color = 'umbs', shape = 'mean sla'),  size = 4) +
  geom_jitter(data = ED_adjusted_sla, aes(pft_name, SLA, color = 'umbs ED'), height = NULL,
              size = 4) + 
  geom_point(data = ED_default_sla, aes(pft_name, SLA, color = 'default ED'), size = 4) + 
  THEME + 
  theme( axis.text.x = element_text(angle = 25, hjust = 1), 
         legend.position = 'bottom', 
         legend.text = element_text(size = 16)) + 
  labs(title = 'Comparison of UMBS and ED SLA', 
       y = 'SLA', 
       x = 'ED PFTs')

Alright so the umbs ED SLA values are what we would expect! Which is awesome.

Biomass (above ground)

So it looks like by increasing the the SLA increased the biomass, expect for with the late sucessional temperate broadleaf which makes sense because we decreased the default SLA. The pines increased a lot…

NPP values

Hmmm it is intersting that the long term NPP is similar in the two scenarios, I guess that makes sense.

LAI values

Interesting the default LAI is larger in the long term, for the temprate broad leaf. While the LAI for the pines is substaintally larger.

D. Concluding Thoughts

So it surprises me that the adjusted SLA does not have a larger LAI long term for broadlead PFTs.

LS0tCnRpdGxlOiAiQ2hlY2tpbmcgb3V0IFNMQSBhbmQgVmNtYXgiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKPCEtLSBJIHJlYWxseSB3b3VsZCBsaWtlIHRvIGZpZ3VyZSBvdXQgaG93IHRvIGFkZCBhIGZsb2F0aW5nIHRvYyB0byB0aGUgaHRtbCBub3RlYm9va3MtLS0+IAoKIyMgT2JqZWN0aXZlIAoKMS4gQ29tcGFyZSBkZWZhdWx0IEVEIHdpdGggVU1CUyBTTEEgYW5kIFZjbWF4IAoyLiBVcGRhdGUgRUQgU0xBIHRvIFVNQlMgdmFsdWVzIAoKTWFya2Rvd24gc2V0IHVwCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgVGhlIGRlZmF1bHRzIGZvciB0aGUgY2h1bmtzCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDUpCgojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShlZDRmb3J0ZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGZvcnRlZGF0YSkKbGlicmFyeShmb3J0ZWRhdGEpCmxpYnJhcnkoZm9ydGViYXNlbGluZSkKCiMgU2V0IHVwIHRoZSBkaXJzIApCQVNFX0RJUiA8LSBoZXJlOjpoZXJlKCkKSU5QVVQgPC0gZmlsZS5wYXRoKEJBU0VfRElSLCAiQS5pbnB1dHMiKQpPVVRQVVRfRElSIDwtIGZpbGUucGF0aChCQVNFX0RJUiwgIkVELW91dHB1dHMiKQpUSEVNRSA8LSB0aGVtZV9idyhiYXNlX3NpemUgPSAyMCkKYGBgCgoKIyMgIHsudGFic2V0fQoKIyMjIDEuIEVkIHZzIFVNQlMKCkNvbXBhcmUgdGhlIGRlZmF1bHQgRUQgU0xBIGFuZCBWY21heCB2YWx1ZXMgd2l0aCBvYnNlcnZhdGlvbnMgZnJvbSBVTUJTLiAKCgojIyMjIEEuIEltcG9ydCBEYXRhIAoKSW1wb3J0IHRoZSBkYXRhIHNldHMuIApgYGB7cn0KIyBUaGUgcmVzdWx0cyBmcm9tICBhIEVEIHJ1biAKZWRfZGF0YSA8LSByZWFkUkRTKGZpbGUucGF0aChPVVRQVVRfRElSLCAiZnVsbC1sZW5ndGgucmRzIikpCgojIFJlYWQgVU1CUyBkYXRhIGZyb20gdGhlIGZvcnRlZGF0YSAgcGFjYWtnZS4gCnVtYnNfc2xhIDwtIGFzLmRhdGEudGFibGUocmVhZC5jc3Yoc3lzdGVtLmZpbGUoJ2V4dGRhdGEvZmRfc2xhLmNzdicsIHBhY2thZ2UgPSAnZm9ydGVkYXRhJyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkpCmBgYAoKQ3JlYXRlIG1hcHBpbmcgZGF0YSBmcmFtZSB0aGF0IHdpbGwgYmUgdXNlZCB0byBtYXAgZWQgcGZ0cyB0byB0aGUgdW1icyBzcGVjaWVzLiAKCmBgYHtyfQojIFRoZSBFRCBwZnRzIApQRlRzICAgIDwtIGMoNiwgOCwgOSwgMTAsIDExLCA3KSAjIFRoZSBQRlRTIHRvIGtlZXAsIHNvbWUgb2YgdGhlIEVEIG91dHB1dHMgcmVwb3J0IGFsbCBvZiB0aGUgUEZUcy4KcGZ0X25hbWVzIDwtIGRhdGEudGFibGUocGZ0ID0gUEZUcywgCiAgICAgICAgICAgICAgICAgICAgICAgIHBmdF9uYW1lID0gYygnTm9ydGhlcm4gTm9ydGggQW1lcmljYW4gcGluZXMnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMYXRlLXN1Y2Nlc3Npb25hbCBOb3J0aCBBbWVyaWNhbiBjb25pZmVycycsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RlbXBlcmF0ZSBicm9hZGxlYWYsIGVhcmx5IHN1Y2Nlc3Npb25hbCcsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUZW1wZXJhdGUgYnJvYWRsZWFmLCBtaWQtc3VjY2Vzc2lvbmFsJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVGVtcGVyYXRlIGJyb2FkbGVhZiwgbGF0ZSBzdWNjZXNzaW9uYWwnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTb3V0aGVybiBOb3J0aCBBbWVyaWNhbiBwaW5lcycpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCnBmdF9uYW1lcyA8LSBwZnRfbmFtZXNbISBwZnQgJWluJSBjKDcsIDgpXQoKIyBVTUJTIHRvIEVEIHBmdHMKbWlkX3N1Y2Nlc3MgICAgICAgPC0gZGF0YS50YWJsZShwZnQgPSAxMCwgVU1CUyA9IGMoJ0FDUlUnLCdBQ1BFJywgICdGQUdSJywgJ0FDU0EnKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQp0ZW1wX2Jyb2FkbF9sYXRlICA8LSBkYXRhLnRhYmxlKHBmdCA9IDExLCBVTUJTID0gYygnUVVSVScsICdUQ1NBJyksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKbm9yX3BpbmVzICAgICAgICAgPC0gZGF0YS50YWJsZShwZnQgPSA2LCBVTUJTID0gYygnUElTVCcsICdQSVJFJyksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKdGVtcF9icm9hZGxfZWFybHkgPC0gZGF0YS50YWJsZShwZnQgPSA5LCBVTUJTID0gYygiQU1FTCIsICJQT0dSIiwgIkJFUEEiLCAiQkVBTCIsICJQT1RSIiksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCnVtYnNfZWQgPC0gcmJpbmQobWlkX3N1Y2Nlc3MsIHRlbXBfYnJvYWRsX2xhdGUsIG5vcl9waW5lcywgdGVtcF9icm9hZGxfZWFybHkpCgpgYGAKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBtYXBpbmcgYmV0d2VlIHRoZSBVTUJTIHNwZWNpZXMgYW5kIHRoZSBFRCBwZnRzLiAKCmBgYHtyfQoKdW1ic19lZFtwZnRfbmFtZXMsIG9uID0gJ3BmdCcsIG5vbWF0Y2ggPSAwXVsgLCBsaXN0KHBmdF9uYW1lLCBwZnQsIFVNQlMpXSAlPiUgCiAga25pdHI6OmthYmxlKGZvcm1hdCA9ICdtYXJrZG93bicpCgpgYGAKCgoKIyMjIyBCLiBGb3JtYXQgVU1CUyBTTEEKCmBgYHtyfQojIEFkZCB0aGUgRUQgUEZUIGluZm9ybWF0aW9uIHRvIHRoZSBVTUJTIFNMQSBtZWFzdXJlbWVudHMuIAp1bWJzX3NsYSA8LSB1bWJzX3NsYVt1bWJzX2VkLCBvbiA9IGMoJ3NwZWNpZXMnID0gJ1VNQlMnKSwgbm9tYXRjaCAgPSAwXQoKYGBgCgpBcyBbQWxleGV5IG5vdGVkXShodHRwczovL2dpdGh1Yi5jb20vRm9SVEV4cGVyaW1lbnQvRm9SVEUtbWdtdC9pc3N1ZXMvNzcjaXNzdWVjb21tZW50LTcxMjExNjUyNSksIGNvbnZlcnQgdGhlIFNMQSB1bml0cy4gIAoKYGBge3J9CnVtYnNfc2xhJHNsYSA8LSB1bWJzX3NsYSRzbGEgKiAoMS8wLjQ4KQpgYGAKCmBgYHtyfQojIE5vdyBkZXRlcm1pbmUgdGhlIGF2ZXJhZ2UgdmFsdWUgZm9yIGVhY2ggUEZULCB0aGlzIGlzIG1vcmUgYW5hbGFnb3VzIHRvIHdoYXQgRUQgIGRvZXMuIAp1bWJzX3NsYSA8LSB1bWJzX3NsYVsgLCBsaXN0KHNsYSA9IG1lYW4oc2xhKSwgbWluID0gbWluKHNsYSksIG1heCA9IG1heChzbGEpKSwgYnkgPSBsaXN0KHBmdCldCnVtYnNfc2xhIDwtIHBmdF9uYW1lc1t1bWJzX3NsYSwgb24gPSAicGZ0Iiwgbm9tYXRjaCA9IDBdWywgbGlzdChwZnRfbmFtZSwgcGZ0LCBzbGEsIG1pbiwgbWF4KV0gCmBgYAoKCkxldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgVU1CUyBTTEEgdmFsdWVzIGxvb2sgbGlrZQoKYGBge3J9CmtuaXRyOjprYWJsZSh1bWJzX3NsYSkKYGBgCgoKCiMjIyMgQy4gRm9ybWF0IEVEIFNMQQoKCkltcG9ydCBFRCByZXN1bHRzIGFuZCBzZWxlY3QgdGhlICBTTEEgdmFsdWVzIGZyb20gb3VyIGJhc2VsaW5lIHJ1bi4gTm90ZSB0aGF0IHdlIHdpbGwgb25seSBiZSBhYmxlIHRvIGV4dHJhY3QgU0xBIHZhbHVlcyBmcm9tIHRoZSBvdXRwdXQsIHRoZSBWY21heCB3aWxsIGhhdmUgdG8gY29tZSBpbiBwdXQgcGFyYW1ldGVycy4gCgoKYGBge3J9CmVkX2RhdGEkZGZfY29ob3J0W1sxXV0gJT4lCiAgZHBseXI6OnNlbGVjdChTTEEsIGRhdGV0aW1lLCBEQkgsIFBGVCkgJT4lICAKICBkcGx5cjo6bGVmdF9qb2luKHBmdF9uYW1lcywgYnkgPSBjKCdQRlQnID0gInBmdCIpKSAlPiUgIAogIGRwbHlyOjpzZWxlY3QocGZ0X25hbWUsIHBmdCA9IFBGVCwgU0xBKSAgJT4lIAogIGRwbHlyOjpkaXN0aW5jdCgpICU+JSAgCiAgYXMuZGF0YS50YWJsZSgpIC0+IAogIGVkX3NsYQprbml0cjo6a2FibGUoZWRfc2xhKQpgYGAKCgojIyMjIEQuIENvbXBhcmUgRUQgYW5kIFVNQlMgU0xBIAoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic19zbGEsIGFlcyhwZnRfbmFtZSwgbWluLCBjb2xvciA9ICd1bWJzJywgc2hhcGUgPSAnbWluIHNsYScpLCAgc2l6ZSA9IDQpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic19zbGEsIGFlcyhwZnRfbmFtZSwgbWF4LCBjb2xvciA9ICd1bWJzJywgc2hhcGUgPSAnbWF4IHNsYScpLCAgc2l6ZSA9IDQpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic19zbGEsIGFlcyhwZnRfbmFtZSwgc2xhLCBjb2xvciA9ICd1bWJzJywgc2hhcGUgPSAnbWVhbiBzbGEnKSwgIHNpemUgPSA0KSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGVkX3NsYSwgYWVzKHBmdF9uYW1lLCBTTEEsIGNvbG9yID0gJ2VkJywgc2hhcGUgPSAnbWVhbiBzbGEnKSwgIHNpemUgPSA0KSArIAogIFRIRU1FICsgCiAgdGhlbWUoIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjUsIGhqdXN0ID0gMSksIAogICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJywgCiAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpICsgCiAgbGFicyh0aXRsZSA9ICdDb21wYXJpc29uIG9mIFVNQlMgYW5kIEVEIFNMQScsIAogICAgICAgeSA9ICdTTEEnLCAKICAgICAgIHggPSAnRUQgUEZUcycpCmBgYAoKUmVjYWxsIGZyb20gW2Jhc2VsaW5lIGVkIHJ1bl0oaHR0cHM6Ly9ycHVicy5jb20va2RvcmhlaW0vNjY4MDk1KSB0aGF0IHRoZSBzdGFuZCBpcyBkb21pbmF0ZWQgYnkgdGhlIHRlbXBlcmF0ZSBicm9hZGxlYWQgZWFybHkgc3VjY2VzaW9uYWwuIAoKIyMjIyBFLiBFRCBWY21heCAKClRha2luZyBhIGxvb2sgYXQgW0VEIGNvZGVdKGh0dHBzOi8vZ2l0aHViLmNvbS9FRG1vZGVsL0VEMi9ibG9iLzQzZDNkZjIwM2Q2NGRmNzZlMTNjMjQxMWM5MGYwN2JjY2UzYmI3ZTUvRUQvc3JjL2luaXQvZWRfcGFyYW1zLmY5MCNMNDgwMCkgd2UgY2FuIHB1bGwgb3V0IHRoZSAke1Z9X3ttMH0kIHZhbHVlcyB3aGljaCBpcyAke1Z9X3tjbWF4fSQgYXQgMTUgQyBpbnN0ZWFkIG9mIDI1IEMgc2VlIFtBbGV4ZXkncyBub3Rlc10oaHR0cHM6Ly9naXRodWIuY29tL0ZvUlRFeHBlcmltZW50L0ZvUlRFLW1nbXQvaXNzdWVzLzc3I2lzc3VlY29tbWVudC03MDkzMzE3ODcpLiAKCmBgYHtyfQplZF9WbTAgPC0gY2JpbmQocGZ0X25hbWVzLCBWbTAgPSBjKDExLjM1MDAwMCwgMjAuMzg3MDc1LCAxNy40NTQ2ODcsIDYuOTgxODc1KSkKYGBgCgpOb3cgbmVlZCB0byBjb252ZXJ0IGZyb20gdGhlIDE1QyB0byAyNUMsIHdlIGNhbiB1c2UgdGhlIGFycmhlbml1cyBzY2FsaW5nIGZ1bmN0aW9uIGZyb20gdGhlIGZvcnRlYmFzZWxpbmUuIAoKYGBge3J9CmVkX1ZjbWF4X3ZhbHVlcyA8LSBhcnJoZW5pdXMuc2NhbGluZyhvYnNlcnZlZC52YWx1ZSA9IGVkX1ZtMCRWbTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkLnRlbXAgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy50ZW1wID0gMjUpCmVkX1ZjbWF4IDwtIGNiaW5kKHBmdF9uYW1lcywgVmNtYXggPSBlZF9WY21heF92YWx1ZXMpCmBgYAoKCiMjIyMgRi4gVU1CUyBWY21heCAKCkxpc2Egc2VudCBtZSBzb21lIGRhdGEgZm9yIFVNQlMgdG8gcHJvdmlkZSBhIGJhbGwgcGFyayBlc3RpbWF0ZSBvZiB0aGUgVmNtYXggdmFsdWVzLiAKCiFbVU1CUyBkYXRhIHRhYmxlXSgvVXNlcnMvZG9yaDAxMi9Eb2N1bWVudHMvMjAyMC9Gb1JURS9mb3J0ZS1kaXN0dXJiYW5jZS9DLmFuYWx5c2lzL2ZpZ3MvdW1ic192Y21heC5wbmcpCgoKYGBge3J9ClVNQlMgIDwtIGMoJ0FDUlUnLCAnQkVQQScsICdRVVJVJywgJ1BPR1InKQpWY21heCA8LSBjKDQ3LjMsIDU4LjUsIDYyLjYsIDcxLjQpCnVtYnNfdmNtYXggPC0gZGF0YS50YWJsZShVTUJTID0gVU1CUywgVmNtYXggPSBWY21heCkKdW1ic192Y21heCA8LSB1bWJzX3ZjbWF4W3VtYnNfZWQsIG9uID0gJ1VNQlMnLCBub21hdGNoID0gMF0KdW1ic192Y21heCA8LSB1bWJzX3ZjbWF4W3BmdF9uYW1lcywgb24gPSAncGZ0Jywgbm9tYXRjaCA9IDBdCmBgYAoKCiMjIyMgRy4gVmNtYXggQ29tcGFyaXNvbiAKCkNvbXBhcmUgdGhlIFVNQlMgYW5kIHRoZSBFRCBWY21heCB2YWx1ZXMuCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBlZF9WY21heCwgYWVzKHBmdF9uYW1lLCBWY21heCwgY29sb3IgPSAnRUQnKSwgc2l6ZSA9IDMpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic192Y21heCwgYWVzKHBmdF9uYW1lLCBWY21heCwgY29sb3IgPSAnVU1CUycpLCBzaXplID0gMykgKyAKICBUSEVNRSArIAogIHRoZW1lKCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI1LCBoanVzdCA9IDEpLCAKICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsIAogICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKSArIAogIGxhYnModGl0bGUgPSAnQ29tcGFyaXNvbiBvZiBVTUJTIGFuZCBFRCBWY21heCcsIAogICAgICAgeSA9ICdWY21heCcsIAogICAgICAgeCA9ICdFRCBQRlRzJykKYGBgCgpWY21heCBzZWVtcyB0byBiZSBmYWlybHkgaGlnaC4gCgoKIyMjIyBILiBDb25jbHVkaW5nIFRob3VnaHRzICYgTmV4dCBTdGVwcwoKKiBUaGlzIGFuYWx5c2lzIG9ubHkgbWFrZXMgc2Vuc2UgaWYgdGhlIEVEIFBGVHMgYW5kIFVNQlMgc3BlY2llcyBhcmUgY2F0ZWdvcml6ZWQgcHJvcGVybHkKKiBUaGUgRUQgdGVtcHJhdGUgYm9yYWQgbGVhZiBsYXRlIHN1Y2Vzc2lvbmFsIFNMQSBpcyByZWFsbHkgZmFyIG9mZiEgQ291bGQgdGhpcyBiZSB0aHJvd2luZyB0aGUgRUQgZm9yZXN0IG9mZj8gCgoxLiBFZCBydW4gd2l0aCAicmVhbGlzdGljIiBTTEEKMi4gRWQgcnVuIHdpdGggInJlYWxpc3RpYyIgVmNtYXggCjMuIEVkIHJ1biB3aXRoICJyZWFsaXN0aWMiIFNMQSBhbmQgVmNtYXgKCiMjIyAyLiBBZGp1c3QgRUQgU0xBIAoKCldoYXQgaGFwcGVucyB3aGVuIHRoZSBFRCBTTEEgdmFsdWVzIGFyZSB1cGRhdGVkIHRvIGJldHRlciByZWZsZWN0IHRoZSBVTUJTIFNMQSB2YWx1ZXM/IAoKIyMjIyBBLiBJbXBvcnQgYW5kIGZvcm1hdCB0aGUgcmVzdWx0cyBmcm9tIHRoZSBTTEEgYWRqdXN0ZWQgcnVuLiAKClN0YXJ0IGJ5IGltcG9ydGluZyBhbmQgZm9ybWF0aW5nIHJlc3VsdHMgZnJvbSB0aGUgRm9SVEUgYmFzZWxpbmUgcnVuLiAKCmBgYHtyfQojIFJlYWQgdGhlIGlucHV0IGZpbGUgCmJhc2VsaW5lIDwtIHJlYWRSRFMoZmlsZS5wYXRoKE9VVFBVVF9ESVIsICd0ZXN0JywgJ2Jhc2VsaW5lLnJkcycpKQoKIyBFeHRyYWN0IHRoZSBTTEEgdmFsdWVzLCB0aGVzZSB3aWxsIGJlIGNvbXBhcmVkIHdpdGggdGhlIG9sZCBzbGEgRUQgdmFsdWVzIGFuZCB0aGUgVU1CUyBvYnNlcnZhdGlvbnMuIApiYXNlbGluZSRkZl9jb2hvcnRbWzFdXSAlPiUKICBkcGx5cjo6c2VsZWN0KFNMQSwgZGF0ZXRpbWUsIERCSCwgUEZUKSAlPiUgIAogIGRwbHlyOjpsZWZ0X2pvaW4ocGZ0X25hbWVzLCBieSA9IGMoJ1BGVCcgPSAicGZ0IikpICU+JSAgCiAgZHBseXI6OnNlbGVjdChwZnRfbmFtZSwgcGZ0ID0gUEZULCBTTEEpICAlPiUgCiAgZHBseXI6OmRpc3RpbmN0KCkgJT4lICAKICBhcy5kYXRhLnRhYmxlKCkgLT4KICBFRF9kZWZhdWx0X3NsYQoKRURfZGVmYXVsdF9zbGEkc2NuIDwtICdkZWZhdWx0IFNMQScKCkVEX2RlZmF1bHRfTEFJIDwtIGFzLmRhdGEudGFibGUoYmFzZWxpbmUkZGZfcGZ0W1sxXV0pWyAgLGxpc3QoZGF0ZXRpbWUsIE1NRUFOX0xBSV9QWSwgcGZ0KV0KRURfZGVmYXVsdF9MQUkkZGF0ZXRpbWUgPC0geW1kKEVEX2RlZmF1bHRfTEFJJGRhdGV0aW1lKQpFRF9kZWZhdWx0X0xBSSR5ZWFyICAgICA8LSB5ZWFyKEVEX2RlZmF1bHRfTEFJJGRhdGV0aW1lKQpFRF9kZWZhdWx0X0xBSSRtb250aCAgICA8LSBtb250aChFRF9kZWZhdWx0X0xBSSRkYXRldGltZSkKRURfZGVmYXVsdF9MQUkkdmFyaWFibGUgPC0gJ01NRUFOX0xBSV9DTycKRURfZGVmYXVsdF9MQUkgPC0gRURfZGVmYXVsdF9MQUlbYXMuZGF0YS50YWJsZShlZDJfdmFyaWFibGVfaW5mbygpKVssIGxpc3QodmFyaWFibGUsIGRlc2NyaXB0aW9uLCB1bml0KV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbiA9ICd2YXJpYWJsZScsICBub21hdGNoPTBdCkVEX2RlZmF1bHRfTEFJICAgICA8LSBFRF9kZWZhdWx0X0xBSVtwZnRfbmFtZXMsIG9uID0gYygncGZ0JyldCkVEX2RlZmF1bHRfTEFJJHNjbiA8LSAnZGVmYXVsdCBTTEEnCgpFRF9kZWZhdWx0X05QUCA8LSBhcy5kYXRhLnRhYmxlKGJhc2VsaW5lJGRmX3NjYWxhcltbMV1dKVsgICxsaXN0KGRhdGV0aW1lLCBNTUVBTl9ORVBfUFkpXQpFRF9kZWZhdWx0X05QUCRkYXRldGltZSA8LSB5bWQoRURfZGVmYXVsdF9OUFAkZGF0ZXRpbWUpCkVEX2RlZmF1bHRfTlBQJHllYXIgPC0geWVhcihFRF9kZWZhdWx0X05QUCRkYXRldGltZSkKRURfZGVmYXVsdF9OUFAkbW9udGggPC0gbW9udGgoRURfZGVmYXVsdF9OUFAkZGF0ZXRpbWUpCkVEX2RlZmF1bHRfTlBQJHZhcmlhYmxlIDwtICdNTUVBTl9ORVBfUFknCkVEX2RlZmF1bHRfTlBQIDwtIEVEX2RlZmF1bHRfTlBQW2FzLmRhdGEudGFibGUoZWQyX3ZhcmlhYmxlX2luZm8oKSlbLCBsaXN0KHZhcmlhYmxlLCBkZXNjcmlwdGlvbiwgdW5pdCldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb24gPSAndmFyaWFibGUnLCAgbm9tYXRjaD0wXQpFRF9kZWZhdWx0X05QUCA8LSBFRF9kZWZhdWx0X05QUFssIGxpc3QodmFsdWUgPSBtZWFuKE1NRUFOX05FUF9QWSwgbmEucm0gPSBUUlVFKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoeWVhciwgdmFyaWFibGUsIHVuaXQsIGRlc2NyaXB0aW9uKV0KCkVEX2RlZmF1bHRfTlBQJHNjbiA8LSAnRUQgZGVmYXVsdCcKCgoKRURfZGVmYXVsdF9BR0IgPC0gYXMuZGF0YS50YWJsZShiYXNlbGluZSRkZl9jb2hvcnRbWzFdXSlbICAsbGlzdChkYXRldGltZSwgQUdCX0NPLCBQRlQsIERCSCwgTlBMQU5UKV0KCiMgQWRkIGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggb2YgdGhlIGNvaG9ydHMgKHJlbWluZGVyIHRoYXQgY29ob3J0cyA9IHVuaXF1ZSBzcGVjaWVzIGF0IERCSCkKc3BsaXQoRURfZGVmYXVsdF9BR0IsIEVEX2RlZmF1bHRfQUdCJGRhdGV0aW1lKSAlPiUgIAogIGxhcHBseShmdW5jdGlvbih4KXsKICAgIAogICAgeCRDTyA8LSBMRVRURVJTWzE6bnJvdyh4KV0KICAgIHJldHVybih4KQogICAgCiAgfSkgJT4lIAogIHJiaW5kbGlzdCgpIC0+IAogIEVEX2RlZmF1bHRfQUdCCgpFRF9kZWZhdWx0X0FHQiA8LSBFRF9kZWZhdWx0X0FHQltwZnRfbmFtZXMsIG9uID0gYygnUEZUJyA9ICdwZnQnKV0KRURfZGVmYXVsdF9BR0IkeWVhciA8LSB5ZWFyKEVEX2RlZmF1bHRfQUdCJGRhdGV0aW1lKQpFRF9kZWZhdWx0X0FHQiRtb250aCA8LSBtb250aChFRF9kZWZhdWx0X0FHQiRkYXRldGltZSkKRURfZGVmYXVsdF9BR0IkdmFyaWFibGUgPC0gIkFHQl9DTyIKRURfZGVmYXVsdF9BR0IgPC0gRURfZGVmYXVsdF9BR0JbYXMuZGF0YS50YWJsZShlZDJfdmFyaWFibGVfaW5mbygpKVssIGxpc3QodmFyaWFibGUsIGRlc2NyaXB0aW9uLCB1bml0KV0sIG9uID0gJ3ZhcmlhYmxlJywgIG5vbWF0Y2g9MF0KRURfZGVmYXVsdF9BR0IkdmFsdWUgPC0gRURfZGVmYXVsdF9BR0IkTlBMQU5UICogRURfZGVmYXVsdF9BR0IkQUdCX0NPCkVEX2RlZmF1bHRfQUdCJHVuaXQgPC0gZ3N1YihwYXR0ZXJuID0gJy9wbGFudCcsIHJlcGxhY2VtZW50ID0gJy9tMicsIEVEX2RlZmF1bHRfQUdCJHVuaXQpCkVEX2RlZmF1bHRfQUdCJHNjbiA8LSAnZGVmYXVsdCBFRCcKYGBgCgojIyMjIEIuIEltcG9ydCBhbmQgZm9ybWF0IHRoZSByZXN1bHRzIGZyb20gdGhlIFNMQSBhZGp1c3RlZCBydW4uIAoKYGBge3J9CiMgUmVhZCBpbiB0aGUgaW5wdXQgCnVtYnNfc2xhX2FkanVzdGVkIDwtIHJlYWRSRFMoZmlsZS5wYXRoKE9VVFBVVF9ESVIsICd0ZXN0JywgJ1VNQlNfU0xBLTEucmRzJykpCgojIEV4dHJhY3QgdGhlIFNMQSB2YWx1ZXMsIHRoZXNlIHdpbGwgYmUgY29tcGFyZWQgd2l0aCB0aGUgb2xkIHNsYSBFRCB2YWx1ZXMgYW5kIHRoZSBVTUJTIG9ic2VydmF0aW9ucy4gCnVtYnNfc2xhX2FkanVzdGVkJGRmX2NvaG9ydFtbMV1dICU+JQogIGRwbHlyOjpzZWxlY3QoU0xBLCBkYXRldGltZSwgREJILCBQRlQpICU+JSAgCiAgZHBseXI6OmxlZnRfam9pbihwZnRfbmFtZXMsIGJ5ID0gYygnUEZUJyA9ICJwZnQiKSkgJT4lICAKICBkcGx5cjo6c2VsZWN0KHBmdF9uYW1lLCBwZnQgPSBQRlQsIFNMQSkgICU+JSAKICBkcGx5cjo6ZGlzdGluY3QoKSAlPiUgIAogIGFzLmRhdGEudGFibGUoKSAtPgogIEVEX2FkanVzdGVkX3NsYQoKRURfYWRqdXN0ZWRfc2xhJHNjbiA8LSAnYWRqdXN0ZWQgU0xBJwoKdW1ic19zbGFfYWRqdXN0ZWRfTEFJIDwtIGFzLmRhdGEudGFibGUodW1ic19zbGFfYWRqdXN0ZWQkZGZfcGZ0W1sxXV0pWyAgLGxpc3QoZGF0ZXRpbWUsIE1NRUFOX0xBSV9QWSwgcGZ0KV0KdW1ic19zbGFfYWRqdXN0ZWRfTEFJJGRhdGV0aW1lIDwtIHltZCh1bWJzX3NsYV9hZGp1c3RlZF9MQUkkZGF0ZXRpbWUpCnVtYnNfc2xhX2FkanVzdGVkX0xBSSR5ZWFyICAgICA8LSB5ZWFyKHVtYnNfc2xhX2FkanVzdGVkX0xBSSRkYXRldGltZSkKdW1ic19zbGFfYWRqdXN0ZWRfTEFJJG1vbnRoICAgIDwtIG1vbnRoKHVtYnNfc2xhX2FkanVzdGVkX0xBSSRkYXRldGltZSkKdW1ic19zbGFfYWRqdXN0ZWRfTEFJJHZhcmlhYmxlIDwtICdNTUVBTl9MQUlfQ08nCnVtYnNfc2xhX2FkanVzdGVkX0xBSSA8LSB1bWJzX3NsYV9hZGp1c3RlZF9MQUlbYXMuZGF0YS50YWJsZShlZDJfdmFyaWFibGVfaW5mbygpKVssIGxpc3QodmFyaWFibGUsIGRlc2NyaXB0aW9uLCB1bml0KV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uID0gJ3ZhcmlhYmxlJywgIG5vbWF0Y2g9MF0KdW1ic19zbGFfYWRqdXN0ZWRfTEFJIDwtIHVtYnNfc2xhX2FkanVzdGVkX0xBSVtwZnRfbmFtZXMsIG9uID0gYygncGZ0JyldCnVtYnNfc2xhX2FkanVzdGVkX0xBSSRzY24gPC0gJ2FkanVzdGVkIFNMQScKCnVtYnNfZWRfTlBQIDwtIGFzLmRhdGEudGFibGUodW1ic19zbGFfYWRqdXN0ZWQkZGZfc2NhbGFyW1sxXV0pWyAgLGxpc3QoZGF0ZXRpbWUsIE1NRUFOX05FUF9QWSldCnVtYnNfZWRfTlBQJGRhdGV0aW1lIDwtIHltZCh1bWJzX2VkX05QUCRkYXRldGltZSkKdW1ic19lZF9OUFAkeWVhciA8LSB5ZWFyKHVtYnNfZWRfTlBQJGRhdGV0aW1lKQp1bWJzX2VkX05QUCRtb250aCA8LSBtb250aCh1bWJzX2VkX05QUCRkYXRldGltZSkKdW1ic19lZF9OUFAkdmFyaWFibGUgPC0gJ01NRUFOX05FUF9QWScKdW1ic19lZF9OUFAgPC0gdW1ic19lZF9OUFBbYXMuZGF0YS50YWJsZShlZDJfdmFyaWFibGVfaW5mbygpKVssIGxpc3QodmFyaWFibGUsIGRlc2NyaXB0aW9uLCB1bml0KV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBvbiA9ICd2YXJpYWJsZScsICBub21hdGNoPTBdCnVtYnNfZWRfTlBQIDwtIHVtYnNfZWRfTlBQWywgbGlzdCh2YWx1ZSA9IG1lYW4oTU1FQU5fTkVQX1BZLCBuYS5ybSA9IFRSVUUpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdCh5ZWFyLCB2YXJpYWJsZSwgdW5pdCwgZGVzY3JpcHRpb24pXQoKdW1ic19lZF9OUFAkc2NuIDwtICdVTUJTIGVkJwoKCkVEX3VtYnNfQUdCIDwtIGFzLmRhdGEudGFibGUodW1ic19zbGFfYWRqdXN0ZWQkZGZfY29ob3J0W1sxXV0pWyAgLGxpc3QoZGF0ZXRpbWUsIEFHQl9DTywgUEZULCBEQkgsIE5QTEFOVCldCgojIEFkZCBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBlYWNoIG9mIHRoZSBjb2hvcnRzIChyZW1pbmRlciB0aGF0IGNvaG9ydHMgPSB1bmlxdWUgc3BlY2llcyBhdCBEQkgpCnNwbGl0KEVEX3VtYnNfQUdCLCBFRF91bWJzX0FHQiRkYXRldGltZSkgJT4lICAKICBsYXBwbHkoZnVuY3Rpb24oeCl7CiAgICAKICAgIHgkQ08gPC0gTEVUVEVSU1sxOm5yb3coeCldCiAgICByZXR1cm4oeCkKICAgIAogIH0pICU+JSAKICByYmluZGxpc3QoKSAtPiAKICBFRF91bWJzX0FHQgoKRURfdW1ic19BR0IgPC0gRURfdW1ic19BR0JbcGZ0X25hbWVzLCBvbiA9IGMoJ1BGVCcgPSAncGZ0JyldCkVEX3VtYnNfQUdCJHllYXIgPC0geWVhcihFRF91bWJzX0FHQiRkYXRldGltZSkKRURfdW1ic19BR0IkbW9udGggPC0gbW9udGgoRURfdW1ic19BR0IkZGF0ZXRpbWUpCkVEX3VtYnNfQUdCJHZhcmlhYmxlIDwtICJBR0JfQ08iCkVEX3VtYnNfQUdCIDwtIEVEX3VtYnNfQUdCW2FzLmRhdGEudGFibGUoZWQyX3ZhcmlhYmxlX2luZm8oKSlbLCBsaXN0KHZhcmlhYmxlLCBkZXNjcmlwdGlvbiwgdW5pdCldLCBvbiA9ICd2YXJpYWJsZScsICBub21hdGNoPTBdCkVEX3VtYnNfQUdCJHZhbHVlIDwtIEVEX3VtYnNfQUdCJE5QTEFOVCAqIEVEX3VtYnNfQUdCJEFHQl9DTwpFRF91bWJzX0FHQiR1bml0IDwtIGdzdWIocGF0dGVybiA9ICcvcGxhbnQnLCByZXBsYWNlbWVudCA9ICcvbTInLCBFRF91bWJzX0FHQiR1bml0KQpFRF91bWJzX0FHQiRzY24gPC0gJ3VtYnMgc2xhIGVkJwpgYGAKCgojIyMjIEMuIENvbXBhcmUgRWQgCgpUaGUgU0xBIHZhbHVlcwoKYGBge3J9CmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic19zbGEsIGFlcyhwZnRfbmFtZSwgbWluLCBjb2xvciA9ICd1bWJzJywgc2hhcGUgPSAnbWluIHNsYScpLCAgc2l6ZSA9IDQpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic19zbGEsIGFlcyhwZnRfbmFtZSwgbWF4LCBjb2xvciA9ICd1bWJzJywgc2hhcGUgPSAnbWF4IHNsYScpLCAgc2l6ZSA9IDQpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gdW1ic19zbGEsIGFlcyhwZnRfbmFtZSwgc2xhLCBjb2xvciA9ICd1bWJzJywgc2hhcGUgPSAnbWVhbiBzbGEnKSwgIHNpemUgPSA0KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IEVEX2FkanVzdGVkX3NsYSwgYWVzKHBmdF9uYW1lLCBTTEEsIGNvbG9yID0gJ3VtYnMgRUQnKSwgaGVpZ2h0ID0gTlVMTCwKICAgICAgICAgICAgICBzaXplID0gNCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBFRF9kZWZhdWx0X3NsYSwgYWVzKHBmdF9uYW1lLCBTTEEsIGNvbG9yID0gJ2RlZmF1bHQgRUQnKSwgc2l6ZSA9IDQpICsgCiAgVEhFTUUgKyAKICB0aGVtZSggYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNSwgaGp1c3QgPSAxKSwgCiAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLCAKICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkgKyAKICBsYWJzKHRpdGxlID0gJ0NvbXBhcmlzb24gb2YgVU1CUyBhbmQgRUQgU0xBJywgCiAgICAgICB5ID0gJ1NMQScsIAogICAgICAgeCA9ICdFRCBQRlRzJykKYGBgCgpBbHJpZ2h0IHNvIHRoZSB1bWJzIEVEIFNMQSB2YWx1ZXMgYXJlIHdoYXQgd2Ugd291bGQgZXhwZWN0ISBXaGljaCBpcyBhd2Vzb21lLiAKCgoKQmlvbWFzcyAoYWJvdmUgZ3JvdW5kKQoKYGBge3J9CgpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IEVEX3VtYnNfQUdCLCBhZXMoZGF0ZXRpbWUsIEFHQl9DTywgY29sb3IgPSBzY24pKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IEVEX2RlZmF1bHRfQUdCLCBhZXMoZGF0ZXRpbWUsIEFHQl9DTywgY29sb3IgPSBzY24pKSArIAogIFRIRU1FICsgCiAgbGFicyh5ID0gJ2tnQy9tMicpICsgCiAgZmFjZXRfd3JhcCgncGZ0X25hbWUnLCBzY2FsZXMgPSAnZnJlZV95JykKYGBgCgoKU28gaXQgbG9va3MgbGlrZSBieSBpbmNyZWFzaW5nIHRoZSB0aGUgU0xBIGluY3JlYXNlZCB0aGUgYmlvbWFzcywgZXhwZWN0IGZvciB3aXRoIHRoZSBsYXRlIHN1Y2Vzc2lvbmFsIHRlbXBlcmF0ZSBicm9hZGxlYWYgd2hpY2ggbWFrZXMgc2Vuc2UgYmVjYXVzZSB3ZSBkZWNyZWFzZWQgdGhlIGRlZmF1bHQgU0xBLiBUaGUgcGluZXMgaW5jcmVhc2VkIGEgbG90Li4uIAoKCk5QUCB2YWx1ZXMgCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG5hLm9taXQodW1ic19lZF9OUFApLCBhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gc2NuKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG5hLm9taXQoRURfZGVmYXVsdF9OUFApLCBhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gc2NuKSkgKyAKICBUSEVNRSArIAogIGxhYnMoeSA9ICJrZy9tMi95ciIsIHRpdGxlID0gJ05QUCcpCgpgYGAKCkhtbW0gaXQgaXMgaW50ZXJzdGluZyB0aGF0IHRoZSBsb25nIHRlcm0gTlBQIGlzIHNpbWlsYXIgaW4gdGhlIHR3byBzY2VuYXJpb3MsIEkgZ3Vlc3MgdGhhdCBtYWtlcyBzZW5zZS4gCgoKCgoKCkxBSSB2YWx1ZXMgCgpgYGB7cn0KZ2dwbG90KCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IG5hLm9taXQodW1ic19zbGFfYWRqdXN0ZWRfTEFJKSwgYWVzKGRhdGV0aW1lLE1NRUFOX0xBSV9QWSwgY29sb3IgPSBzY24pKSArIAogIGdlb21fbGluZShkYXRhID0gbmEub21pdChFRF9kZWZhdWx0X0xBSSksIGFlcyhkYXRldGltZSwgTU1FQU5fTEFJX1BZLCBjb2xvciA9IHNjbikpICsgCiAgVEhFTUUgKyAKICBmYWNldF93cmFwKCJwZnRfbmFtZSIsIHNjYWxlcyA9ICdmcmVlJywgbmNvbCA9IDEpICsgCiAgbGFicyh5ID0gJ20ybGVhZi9tMicpCmBgYAoKSW50ZXJlc3RpbmcgdGhlIGRlZmF1bHQgTEFJIGlzIGxhcmdlciBpbiB0aGUgbG9uZyB0ZXJtLCBmb3IgdGhlIHRlbXByYXRlIGJyb2FkIGxlYWYuIFdoaWxlIHRoZSBMQUkgZm9yIHRoZSBwaW5lcyAgaXMgIHN1YnN0YWludGFsbHkgbGFyZ2VyLiAKCgojIyMjIEQuIENvbmNsdWRpbmcgVGhvdWdodHMgCgpTbyBpdCBzdXJwcmlzZXMgbWUgdGhhdCB0aGUgYWRqdXN0ZWQgU0xBIGRvZXMgbm90IGhhdmUgYSBsYXJnZXIgTEFJIGxvbmcgdGVybSBmb3IgYnJvYWRsZWFkIFBGVHMuICAgCgo=