This workflow should show the full strength of the RRatepol package for working with data types other than fossil pollen, specifically for geochemical data. It should serve as step-by-step guidance starting from downloading datasets from Neotoma and building age-depth models, to estimating rate-of-change using age uncertainty.

For a workflow using XRF data, see Part 2 - XRF data.

⚠️This workflow is only meant as an example: There may be several additional steps for data preparation, which should be done to properly implement RRatepol and assess the rate of change for your specific project.

For a step-by-spet workflow with fossil pollen data, please see other package materials, such as African Polled Database workshop.

Additionally, please see FOSSILPOL, an R-based modular workflow to process multiple fossil pollen records to create a comprehensive, standardized dataset compilation, ready for multi-record and multi-proxy analyses at various spatial and temporal scales.

Install packages

Please follow the pre-workshop instructions to make sure all packages are installed.

Attach packages

library(tidyverse) # general data wrangling and visualisation ✨
library(pander) # nice tables 😍
library(RRatepol) # rate-of-vegetation change ! v1.2.2 ! 📈
library(neotoma2) # access to the Neotoma database 🌿
library(Bchron) # age-depth modelingng 🕰️
library(janitor) # string cleaning 🧹
library(here) # for working directory 🗺️

Download a dataset from Neotoma

Here we have selected the Chickaree Lake record (ID = 47613) by Higuera, Philip E. and Dunnette, Paul V.

Reference paper: Dunnette, P.V., P.E. Higuera, K.K. McLauchlan, K.M. Derr, C.E. Briles, and M.H. Keefe. 2014. Biogeochemical impacts of wildfires over four millennia in a Rocky Mountain subalpine watershed. New Phytologist 203(3):900-912. DOI: 10.1111/nph.12828

sel_dataset_download <-
  neotoma2::get_downloads(47613)

Prepare the geochemical data

# get samples
data_samples <-
  neotoma2::samples(sel_dataset_download)  %>% 
  tibble::as_tibble()

# prepare taxa table
data_community <-
  data_samples %>%
  dplyr::mutate(sample_id = as.character(sampleid)) %>%
  dplyr::select("sample_id", "value", "variablename") %>%
  # turn into the wider format
  tidyr::pivot_wider(
    names_from = "variablename",
    values_from = "value",
    values_fill = 0
  ) %>%
  # clean names
  janitor::clean_names()  %>% 
  # remove the ratio as it is just calcualtion from other variables
  dplyr::select(-carbon_nitrogen)

# make table with units for later
data_units <-
  data_samples %>%
  dplyr::distinct(variablename, units)  %>% 
  dplyr::filter(
    variablename != "Carbon:Nitrogen"
  )

head(data_community)[, 1:5]
sample_id nitrogen carbon d15n d13c
439811 2 19.07 0.08 -27.33
439812 1.4 15.15 -0.13 -26.89
439813 1.43 16.67 -0.23 -25.73
439814 1.28 14.01 -0.3 -26.03
439815 1.19 12.72 -0.19 -25.91
439816 1.15 12.94 0.04 -26.78

Here, we strongly advocate that careful preparation of the datasets (with additional steps) may be needed before using R-Ratepol!

We can now try to visualize the taxa per sample_id

data_community %>%
  tibble::rowid_to_column("ID") %>%
  tidyr::pivot_longer(
    cols = -c(sample_id, ID),
    names_to = "element",
    values_to = "value"
  ) %>%
  ggplot2::ggplot(
    mapping = ggplot2::aes(
      x = ID,
      y = value,
      col = element
    ),
  ) +
  ggplot2::facet_wrap(
    ~ element,
    nrow = 1,
    scales = "free_x"
  ) +
  ggplot2::coord_flip() +
  ggplot2::theme(
    panel.grid.major.x = ggplot2::element_line(
      colour = "grey",
      linewidth = 0.1
    ),
    axis.text.y = ggplot2::element_blank(),
    axis.ticks.y = ggplot2::element_blank(), 
    legend.position = "none"
  ) +
  ggplot2::labs(
    x = "sample id",
    y = "value"
  )  +
  ggplot2::geom_line()  

Preparation of the levels

Sample depth

Extract depth for each level

data_levels <-
  neotoma2::samples(sel_dataset_download) %>%
  tibble::as_tibble() %>%
  dplyr::mutate(sample_id = as.character(sampleid)) %>%
  dplyr::distinct(sample_id, depth) %>%
  dplyr::relocate(sample_id)

head(data_levels)
sample_id depth
439811 0.8
439812 2.9
439813 5.1
439814 7.8
439815 10.5
439816 12.7

Age-depth modelling

We will recalculate the age-depth model ‘de novo’ using the Bchron package.

Prepare chron.control table and run Bchron

The chronology control table contains all the dates (mostly radiocarbon) to create the age-depth model.

Here we only present a few of the important steps of preparation of the chronology control table. There are many more potential issues, but solving those is not the focus of this workflow.

# First, get the chronologies and check which we want to use used
sel_chron_control_table_download <-
  neotoma2::chroncontrols(sel_dataset_download)

print(sel_chron_control_table_download)
Table continues below
siteid chronologyid depth thickness agelimitolder chroncontrolid
27028 33168 0.8 1.6 -59.62 103110
27028 33168 2.4 1.1 -55.24 103111
27028 33168 3.5 1.1 -51 103112
27028 33168 4.6 2.1 -45.22 103113
27028 33168 6.7 2.2 -39.53 103114
27028 33168 8.9 2.1 -33.58 103115
agelimityounger chroncontrolage chroncontroltype
-60.38 -60 Lead-210
-56.04 -55.64 Lead-210
-51.84 -51.42 Lead-210
-46.14 -45.68 Lead-210
-40.55 -40.04 Lead-210
-34.74 -34.16 Lead-210
# prepare the table
data_chron_control_table <-
  sel_chron_control_table_download %>%
  # Here select the ID of one of the chronology
  dplyr::filter(chronologyid == 33168) %>%
  tibble::as_tibble() %>%
  # Here we calculate the error as the average of the age `limitolder` and
  #   `agelimityounger`
  dplyr::mutate(
    error = round((agelimitolder - agelimityounger) / 2)
  ) %>%
  # As Bchron cannot accept a error of 0, we need to replace the value with 1
  dplyr::mutate(
    error = replace(error, error == 0, 1),
    error = ifelse(is.na(error), 1, error)
  ) %>%
  # We need to specify which calibration curve should be used for what point
  dplyr::mutate(
    curve = ifelse(as.data.frame(sel_dataset_download)["lat"] > 0, "intcal20", "shcal20"),
    curve = ifelse(chroncontroltype != "Radiocarbon", "normal", curve)
  ) %>%
  tibble::column_to_rownames("chroncontrolid") %>%
  dplyr::arrange(depth) %>%
  dplyr::select(
    chroncontrolage, error, depth, thickness, chroncontroltype, curve
  )

head(data_chron_control_table)
chroncontrolage error depth thickness chroncontroltype curve
-60 1 0.8 1.6 Lead-210 normal
-55.64 1 2.4 1.1 Lead-210 normal
-51.42 1 3.5 1.1 Lead-210 normal
-45.68 1 4.6 2.1 Lead-210 normal
-40.04 1 6.7 2.2 Lead-210 normal
-34.16 1 8.9 2.1 Lead-210 normal

As this is just a toy example, we will use only the iteration multiplier (i_multiplier) of 0.1 to reduce the computation time. However, we strongly recommend increasing it to 5 for any normal age-depth model construction.

i_multiplier <- 0.1 # increase to 5

# Those are default values suggested by the Bchron package
n_iteration_default <- 10e3
n_burn_default <- 2e3
n_thin_default <- 8

# Let's multiply them by our i_multiplier
n_iteration <- n_iteration_default * i_multiplier
n_burn <- n_burn_default * i_multiplier
n_thin <- max(c(1, n_thin_default * i_multiplier))

# run Bchron
sel_bchron <-
  Bchron::Bchronology(
    ages = data_chron_control_table$chroncontrolage,
    ageSds = data_chron_control_table$error,
    positions = data_chron_control_table$depth,
    calCurves = data_chron_control_table$curve,
    positionThicknesses = data_chron_control_table$thickness,
    iterations = n_iteration,
    burn = n_burn,
    thin = n_thin
  )

Visually check the age-depth models

Bchron:::plot.BchronologyRun(sel_bchron) + # or just simple plot(sel_bchron)
  ggplot2::theme_bw() +
  ggplot2::theme(
    axis.title = ggplot2::element_text(size = 25),
    axis.text = ggplot2::element_text(size = 15),
    strip.text = ggplot2::element_text(size = 15),
    panel.grid = ggplot2::element_blank()
  ) +
  ggplot2::labs(
    x = "age (cal yr BP)",
    y = "depth"
  )

Predict ages

Let’s first extract posterior ages (i.e. possible ages) from the age-depth model.

age_position <-
  Bchron:::predict.BchronologyRun( # or just simple predict(sel_bchron)
    object = sel_bchron,
    newPositions = data_levels$depth
  )

age_uncertainties <-
  age_position %>%
  as.data.frame() %>%
  dplyr::mutate_all(., as.integer) %>%
  as.matrix()

colnames(age_uncertainties) <- data_levels$sample_id

head(age_uncertainties, n = 8)[, 1:8]

Here we see samples (e.g., 439811, 439812, 439813,…) and their possible ages (age sequence) with each model iteration (posterior). Each age-sequence is similar but there are differences of tens or hundreds of years. We will call this the uncertainty matrix.

439811 439812 439813 439814 439815 439816 439817 439818
-61 -53 -44 -36 -28 -20 -12 -6
-61 -53 -45 -35 -27 -22 -15 -4
-61 -52 -48 -36 -27 -22 -15 -6
-60 -53 -42 -38 -30 -23 -14 -6
-60 -53 -45 -37 -27 -22 -15 -5
-60 -53 -45 -36 -27 -23 -11 -5
-60 -53 -45 -36 -26 -23 -15 -4
-60 -53 -45 -38 -30 -22 -13 -8

We can visualize these “possible ages” (age-sequence) of each iteration.

# create a data.frame for plotting
data_age_uncertainties <-
  age_uncertainties %>%
  as.data.frame() %>%
  tibble::rowid_to_column("ID") %>%
  tidyr::pivot_longer(
    cols = -ID,
    names_to = "sample_id",
    values_to = "age"
  ) %>%
  dplyr::left_join(
    data_levels,
    by = dplyr::join_by(sample_id)
  )

Each line is a single potential age-depth model iteration (age-sequence). Green points represent the radiocarbon dates. Horizontal lines are the depths of our samples.

(
  fig_age_uncertainties <-
    data_age_uncertainties %>%
    ggplot2::ggplot(
      mapping = ggplot2::aes(
        x = age,
        y = depth
      )
    ) +
    ggplot2::geom_line(
      mapping = ggplot2::aes(
        group = ID
      ),
      alpha = 0.05,
      linewidth = 0.1
    ) +
    ggplot2::geom_hline(
      yintercept = data_levels$depth,
      lty = 2,
      color = "gray50",
      alpha = 0.1,
      linewidth = 0.1
    ) +
    ggplot2::geom_point(
      data = data_chron_control_table,
      mapping = ggplot2::aes(
        x = chroncontrolage
      ),
      color = "green",
      shape = 15,
      size = 3
    ) +
    ggplot2::scale_y_continuous(trans = "reverse") +
    ggplot2::scale_x_continuous(trans = "reverse") +
    ggplot2::labs(
      x = "age (cal yr BP)"
    )
)

We can visualize all age-depth “possible ages” together as the range of values. Here, each line represents one sampled depth in our record.

data_age_uncertainties %>%
  ggplot2::ggplot(
    mapping = ggplot2::aes(
      x = age,
      y = depth,
      group = depth
    )
  ) +
  ggplot2::geom_hline(
    yintercept = data_levels$depth,
    lty = 2,
    color = "gray50",
    alpha = 0.1,
    linewidth = 0.1
  ) +
  ggplot2::geom_boxplot(
    outlier.shape = NA
  ) +
  ggplot2::scale_y_continuous(trans = "reverse") +
  ggplot2::scale_x_continuous(trans = "reverse") +
  ggplot2::labs(
    x = "age (cal yr BP)"
  )

Let’s take the median age of all possible ages (i.e. the estimated age from each age-depth model run) as our default.

data_levels_predicted <-
  data_levels %>%
  dplyr::mutate(
    age = apply(
      age_uncertainties, 2,
      stats::quantile,
      probs = 0.5
    )
  )

head(data_levels_predicted)
sample_id depth age
439811 0.8 -60
439812 2.9 -54
439813 5.1 -44
439814 7.8 -37
439815 10.5 -28
439816 12.7 -21

We can visualize the median age by drawing a red line. This age is the age that is often reported in publications but in essence, it represents multiple age-depth model runs with smaller or larger age uncertainties throughout the record.

fig_age_uncertainties +
  ggplot2::geom_point(
    data = data_levels_predicted,
    color = "red",
    size = 1
  ) +
  ggplot2::geom_line(
    data = data_levels_predicted,
    color = "red",
    linewidth = 0.5
  )

Visualisation of our data

Let’s now make a simple pollen diagram with proportions of the main pollen taxa (x-axis) against our estimated ages along depth (y-axis).

data_community %>%
  dplyr::inner_join(
    data_levels_predicted,
    by = dplyr::join_by(sample_id)
  ) %>%
  tidyr::pivot_longer(
    cols = -c(sample_id, depth, age),
    names_to = "element",
    values_to = "value"
  ) %>%
  ggplot2::ggplot(
    mapping = ggplot2::aes(
      x = age,
      y = value,
      col = element
    ),
  ) +
  ggplot2::facet_wrap(
    ~element,
    nrow = 1,
    scales = "free_x"
  ) +
  ggplot2::coord_flip() +
  ggplot2::scale_x_continuous(trans = "reverse") +
  ggplot2::theme(
    panel.grid.major.x = ggplot2::element_line(
      colour = "grey",
      linewidth = 0.1
    ),
    legend.position = "none"
  ) +
  ggplot2::labs(
    x = "age (cal yr BP)",
    y = "value"
  ) +
  ggplot2::geom_line()

Estimation Rate-of-Change

Now we will use our prepared geochemistry data and age-depth model to estimate the rate of change. We will present several scenarios (i.e. approaches) to calculate RoC.

Selection of dissimilarity coefficient

We can check the units of individual measured values:

data_units
variablename units
Nitrogen percent
Carbon percent
d15N per mille air N
d13C per mille VPDB/17O

As we can see, all measured values are in different units. Therefore, for all scenarios, we will be using the gower dissimilarity coefficient (works with data in various units), prevent turning them into proportions (as it does not make sense) with tranform_to_proportions == FALSE, and set time_standardisation == 250 (this means that all ROC values are ‘change per 250 yr’).

Scenario 1 - Estimating RoC for each level

This is the “Classic” approach that uses each sampled depth in a record (i.e. individual level) to estimate RoC.

scenario_1 <-
  RRatepol::estimate_roc(
    data_source_community = data_community,
    data_source_age = data_levels_predicted,
    dissimilarity_coefficient = "gower",
    tranform_to_proportions = FALSE,
    time_standardisation = 250,
    working_units = "levels" # here is set to use individual levels
  )
RRatepol::plot_roc(data_source = scenario_1)

Scenario 2 - Estimating RoC for each level with smoothing of data

We do the same as in Scenario 1 but now we smooth the community data before calculating RoC. This may be useful to mitigate the error of measurements. Specifically, we will add smooth_method = “shep” (i.e. Shepard’s 5-term filter).

scenario_2 <-
  RRatepol::estimate_roc(
    data_source_community = data_community,
    data_source_age = data_levels_predicted,
    dissimilarity_coefficient = "gower",
    tranform_to_proportions = FALSE,
    time_standardisation = 250,
    working_units = "levels",
    smooth_method = "shep" # Shepard's 5-term filter
  )
RRatepol::plot_roc(data_source = scenario_2)

We see that the absolute RoC scores are decreased and the pattern changed slightly (x-axis).

Scenario 3 - Using uncertainty matrix

For RoC analysis, it is important to consider age uncertainties. For each iteration, RRatepol will randomly select one age sequence from the uncertainty matrix (see the age-depth modeling section for more info).

Because of that, we need to increase the number of randomizations. This is again a toy example for a quick computation and therefore we only do 100 randomizations. We would recommend increasing the set_randomisations to 10.000 for any real estimation.

set_randomisations <- 100

To speed the process up, you can also set use_parallel == TRUE, which will use all cores of your computer.

scenario_3 <-
  RRatepol::estimate_roc(
  data_source_community = data_community,
    data_source_age = data_levels_predicted,
    dissimilarity_coefficient = "gower",
    tranform_to_proportions = FALSE,
    time_standardisation = 250,
    smooth_method = "shep",
    age_uncertainty = age_uncertainties, # Add the uncertainty matrix
    rand = set_randomisations,  # set number of randomisations
    use_parallel = TRUE # do use parallel computing
  )
RRatepol::plot_roc(data_source = scenario_3)

We will now also visualize uncertainty around the RoC scores shown by a grey shadow. We see a substantial increase in the RoC value in certain regions, this is caused by the extremely small numbers of age differences and low number of randomizations.

Scenario 4 - Estimating RoC per bin

In order to get rid of the effect of uneven distribution of sampled depths (i.e. levels) in a record, we can bin the data.

Specifically, we will change the working_units from single levels to "bins". Here we select bins of 250 years each instead of the individual levels.

Note that one level is randomly selected as a representation of that time bin. Therefore, it is important to increase the number of randomizations.

scenario_4 <-
  RRatepol::estimate_roc(
    data_source_community = data_community,
    data_source_age = data_levels_predicted,
    dissimilarity_coefficient = "gower",
    tranform_to_proportions = FALSE,
    working_units = "bins", # change the "bins"
    bin_size = 250, # size of a time bin
    time_standardisation = 250,
    smooth_method = "shep",
    age_uncertainty = age_uncertainties,
    rand = set_randomisations, 
    use_parallel = TRUE 
  )
RRatepol::plot_roc(data_source = scenario_4)

Here we can see a drastic change in the shape of RoC but a large loss of temporal precision.

Scenario 5 - Estimating RoC with the new “Moving-window” approach

In order to reduce the temporal uncertainty and improve temporal precision, we can apply a novel approach in RRATEPOL called “moving window”.

scenario_5 <-
  RRatepol::estimate_roc(
    data_source_community = data_community,
    data_source_age = data_levels_predicted,
    dissimilarity_coefficient = "gower",
    tranform_to_proportions = FALSE,
    working_units = "MW", # change the "MW" to apply the "moving window"
    bin_size = 250,
    number_of_shifts = 5, # number of shifts
    time_standardisation = 250,
    smooth_method = "shep",
    rand = set_randomisations,
    use_parallel = TRUE,
    age_uncertainty = age_uncertainties
  )
RRatepol::plot_roc(data_source = scenario_5)

Scenario 6 - Detecting peak points

Throughout the record, there can be periods when the RoC will substantially change. We can detect RoC increases that are significant by identifying so-called peak-points. Here, we will use the “Non-linear” method, which will detect a significant change from a non-linear trend of RoC.

scenario_5_peak <-
  RRatepol::detect_peak_points(
    data_source = scenario_5,
    sel_method = "trend_non_linear"
  )

Now we will plot the RoC estimates showing the peak points. So here we can see that there were rates of vegetation change throughout the record but only at certain moments in time (green dots - peak points) these changes were significant. There you go!

RRatepol::plot_roc(
  data_source = scenario_5_peak,
  peaks = TRUE
)

LS0tDQp0aXRsZTogUGFydCAxIC0gR2VvY2hlbWljYWwgZGF0YQ0KZm9ybWF0OiANCiAgZ2ZtOg0KICAgIGZpZy13aWR0aDogNw0KICAgIGZpZy1oZWlnaHQ6IDYNCiAgICB3cmFwOiBub25lDQoNCi0tLQ0KDQpgYGB7cn0NCiN8IGxhYmVsOiBjaHVuayBzZXR1cA0KI3wgaW5jbHVkZTogRkFMU0UgDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbGxhcHNlID0gVFJVRSwNCiAgY29tbWVudCA9ICIjPiIsDQogIHJlc3VsdHMgPSAiaGlkZSIsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICBmaWcuYWxpZ24gPSAiY2VudGVyIg0KKQ0KYGBgDQoNClRoaXMgd29ya2Zsb3cgc2hvdWxkIHNob3cgdGhlIGZ1bGwgc3RyZW5ndGggb2YgdGhlIFsqUlJhdGVwb2wgcGFja2FnZSpdKGh0dHBzOi8vaG9wZS11aWItYmlvLmdpdGh1Yi5pby9SLVJhdGVwb2wtcGFja2FnZS8pIGZvciB3b3JraW5nIHdpdGggZGF0YSB0eXBlcyAqKm90aGVyKiogdGhhbiBmb3NzaWwgcG9sbGVuLCBzcGVjaWZpY2FsbHkgZm9yICoqZ2VvY2hlbWljYWwgZGF0YSoqLiBJdCBzaG91bGQgc2VydmUgYXMgc3RlcC1ieS1zdGVwIGd1aWRhbmNlIHN0YXJ0aW5nIGZyb20gZG93bmxvYWRpbmcgZGF0YXNldHMgZnJvbSBOZW90b21hIGFuZCBidWlsZGluZyBhZ2UtZGVwdGggbW9kZWxzLCB0byBlc3RpbWF0aW5nIHJhdGUtb2YtY2hhbmdlIHVzaW5nIGFnZSB1bmNlcnRhaW50eS4NCg0KRm9yIGEgd29ya2Zsb3cgdXNpbmcgKipYUkYgZGF0YSoqLCBzZWUgW1BhcnQgMiAtIFhSRiBkYXRhXShodHRwczovL29uZHJlam1vdHRsLmdpdGh1Yi5pby9PQ0NSX1ItUmF0ZXBvbF93b3Jrc2hvcC9wYXJ0XzJfeHJmX2RhdGEuaHRtbCkuDQoNCuKaoO+4jyoqVGhpcyB3b3JrZmxvdyBpcyBvbmx5IG1lYW50IGFzIGFuIGV4YW1wbGUqKjogVGhlcmUgbWF5IGJlIHNldmVyYWwgYWRkaXRpb25hbCBzdGVwcyBmb3IgZGF0YSBwcmVwYXJhdGlvbiwgd2hpY2ggc2hvdWxkIGJlIGRvbmUgdG8gcHJvcGVybHkgaW1wbGVtZW50IFJSYXRlcG9sIGFuZCBhc3Nlc3MgdGhlIHJhdGUgb2YgY2hhbmdlIGZvciB5b3VyIHNwZWNpZmljIHByb2plY3QuIA0KDQpGb3IgYSBzdGVwLWJ5LXNwZXQgd29ya2Zsb3cgd2l0aCBmb3NzaWwgcG9sbGVuIGRhdGEsIHBsZWFzZSBzZWUgb3RoZXIgcGFja2FnZSBtYXRlcmlhbHMsIHN1Y2ggYXMgW0FmcmljYW4gUG9sbGVkIERhdGFiYXNlIHdvcmtzaG9wXShodHRwczovL29uZHJlam1vdHRsLmdpdGh1Yi5pby9BUERfUi1SYXRlcG9sX3dvcmtzaG9wL2luZGV4Lmh0bWwpLg0KDQpBZGRpdGlvbmFsbHksIHBsZWFzZSBzZWUgWyoqRk9TU0lMUE9MKipdKGh0dHBzOi8vaG9wZS11aWItYmlvLmdpdGh1Yi5pby9GT1NTSUxQT0wtd2Vic2l0ZS8pLCBhbiBSLWJhc2VkIG1vZHVsYXIgd29ya2Zsb3cgdG8gcHJvY2VzcyBtdWx0aXBsZSBmb3NzaWwgcG9sbGVuIHJlY29yZHMgdG8gY3JlYXRlIGEgY29tcHJlaGVuc2l2ZSwgc3RhbmRhcmRpemVkIGRhdGFzZXQgY29tcGlsYXRpb24sIHJlYWR5IGZvciBtdWx0aS1yZWNvcmQgYW5kIG11bHRpLXByb3h5IGFuYWx5c2VzIGF0IHZhcmlvdXMgc3BhdGlhbCBhbmQgdGVtcG9yYWwgc2NhbGVzLg0KDQojIyBJbnN0YWxsIHBhY2thZ2VzDQoNClBsZWFzZSBmb2xsb3cgdGhlIFtwcmUtd29ya3Nob3AgaW5zdHJ1Y3Rpb25zXShodHRwczovL29uZHJlam1vdHRsLmdpdGh1Yi5pby9PQ0NSX1ItUmF0ZXBvbF93b3Jrc2hvcC9wcmVfd29ya3Nob3AuaHRtbCkgdG8gbWFrZSBzdXJlIGFsbCBwYWNrYWdlcyBhcmUgaW5zdGFsbGVkLg0KDQojIyBBdHRhY2ggcGFja2FnZXMNCg0KYGBge3J9DQojfCBsYWJlbDogYXR0YWNoIHBhY2thZ2VzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBnZW5lcmFsIGRhdGEgd3JhbmdsaW5nIGFuZCB2aXN1YWxpc2F0aW9uIOKcqA0KbGlicmFyeShwYW5kZXIpICMgbmljZSB0YWJsZXMg8J+YjQ0KbGlicmFyeShSUmF0ZXBvbCkgIyByYXRlLW9mLXZlZ2V0YXRpb24gY2hhbmdlICEgdjEuMi4yICEg8J+TiA0KbGlicmFyeShuZW90b21hMikgIyBhY2Nlc3MgdG8gdGhlIE5lb3RvbWEgZGF0YWJhc2Ug8J+Mvw0KbGlicmFyeShCY2hyb24pICMgYWdlLWRlcHRoIG1vZGVsaW5nbmcg8J+VsO+4jw0KbGlicmFyeShqYW5pdG9yKSAjIHN0cmluZyBjbGVhbmluZyDwn6e5DQpsaWJyYXJ5KGhlcmUpICMgZm9yIHdvcmtpbmcgZGlyZWN0b3J5IPCfl7rvuI8NCmBgYA0KDQpgYGB7cn0NCiN8IGxhYmVsOiB0aGVtZSBzZXQNCiN8IGluY2x1ZGU6IEZBTFNFDQpnZ3Bsb3QyOjp0aGVtZV9zZXQoDQogIGdncGxvdDI6OnRoZW1lX2J3KCkgKw0KICAgIGdncGxvdDI6OnRoZW1lKA0KICAgICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMjUpLA0KICAgICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICBzdHJpcC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICBwYW5lbC5ncmlkID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpDQogICAgKQ0KKQ0KYGBgDQoNCiMjIERvd25sb2FkIGEgZGF0YXNldCBmcm9tIE5lb3RvbWENCg0KSGVyZSB3ZSBoYXZlIHNlbGVjdGVkIHRoZSAqKkNoaWNrYXJlZSBMYWtlKiogcmVjb3JkIChJRCA9IDQ3NjEzKSBieSBIaWd1ZXJhLCBQaGlsaXAgRS4gYW5kIER1bm5ldHRlLCBQYXVsIFYuDQoNClJlZmVyZW5jZSBwYXBlcjogRHVubmV0dGUsIFAuVi4sIFAuRS4gSGlndWVyYSwgSy5LLiBNY0xhdWNobGFuLCBLLk0uIERlcnIsIEMuRS4gQnJpbGVzLCBhbmQgTS5ILiBLZWVmZS4gMjAxNC4gQmlvZ2VvY2hlbWljYWwgaW1wYWN0cyBvZiB3aWxkZmlyZXMgb3ZlciBmb3VyIG1pbGxlbm5pYSBpbiBhIFJvY2t5IE1vdW50YWluIHN1YmFscGluZSB3YXRlcnNoZWQuIE5ldyBQaHl0b2xvZ2lzdCAyMDMoMyk6OTAwLTkxMi4gRE9JOiAxMC4xMTExL25waC4xMjgyOA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBEb3dubG9hZCBkYXRhc2V0DQpzZWxfZGF0YXNldF9kb3dubG9hZCA8LQ0KICBuZW90b21hMjo6Z2V0X2Rvd25sb2Fkcyg0NzYxMykNCmBgYA0KDQojIyBQcmVwYXJlIHRoZSBnZW9jaGVtaWNhbCBkYXRhDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHByZXBhcmUgZ2VvY2hlbWljYWwgZGF0YQ0KIyBnZXQgc2FtcGxlcw0KZGF0YV9zYW1wbGVzIDwtDQogIG5lb3RvbWEyOjpzYW1wbGVzKHNlbF9kYXRhc2V0X2Rvd25sb2FkKSAgJT4lIA0KICB0aWJibGU6OmFzX3RpYmJsZSgpDQoNCiMgcHJlcGFyZSB0YXhhIHRhYmxlDQpkYXRhX2NvbW11bml0eSA8LQ0KICBkYXRhX3NhbXBsZXMgJT4lDQogIGRwbHlyOjptdXRhdGUoc2FtcGxlX2lkID0gYXMuY2hhcmFjdGVyKHNhbXBsZWlkKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoInNhbXBsZV9pZCIsICJ2YWx1ZSIsICJ2YXJpYWJsZW5hbWUiKSAlPiUNCiAgIyB0dXJuIGludG8gdGhlIHdpZGVyIGZvcm1hdA0KICB0aWR5cjo6cGl2b3Rfd2lkZXIoDQogICAgbmFtZXNfZnJvbSA9ICJ2YXJpYWJsZW5hbWUiLA0KICAgIHZhbHVlc19mcm9tID0gInZhbHVlIiwNCiAgICB2YWx1ZXNfZmlsbCA9IDANCiAgKSAlPiUNCiAgIyBjbGVhbiBuYW1lcw0KICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICAlPiUgDQogICMgcmVtb3ZlIHRoZSByYXRpbyBhcyBpdCBpcyBqdXN0IGNhbGN1YWx0aW9uIGZyb20gb3RoZXIgdmFyaWFibGVzDQogIGRwbHlyOjpzZWxlY3QoLWNhcmJvbl9uaXRyb2dlbikNCg0KIyBtYWtlIHRhYmxlIHdpdGggdW5pdHMgZm9yIGxhdGVyDQpkYXRhX3VuaXRzIDwtDQogIGRhdGFfc2FtcGxlcyAlPiUNCiAgZHBseXI6OmRpc3RpbmN0KHZhcmlhYmxlbmFtZSwgdW5pdHMpICAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoDQogICAgdmFyaWFibGVuYW1lICE9ICJDYXJib246Tml0cm9nZW4iDQogICkNCg0KaGVhZChkYXRhX2NvbW11bml0eSlbLCAxOjVdDQpgYGANCg0KYGBge3J9DQojfCBsYWJlbDogZGlzcGxheSBnZW9jaGVtaXN0cnkgdGFibGUNCiN8IGVjaG86IEZBTFNFDQojfCByZXN1bHRzOiAnYXNpcycNCnBhbmRlcjo6cGFuZG9jLnRhYmxlKGhlYWQoZGF0YV9jb21tdW5pdHkpWywgMTo1XSkNCmBgYA0KDQpIZXJlLCB3ZSBzdHJvbmdseSBhZHZvY2F0ZSB0aGF0IGNhcmVmdWwgcHJlcGFyYXRpb24gb2YgdGhlIGRhdGFzZXRzICh3aXRoIGFkZGl0aW9uYWwgc3RlcHMpIG1heSBiZSBuZWVkZWQgYmVmb3JlIHVzaW5nIFItUmF0ZXBvbCENCg0KV2UgY2FuIG5vdyB0cnkgdG8gdmlzdWFsaXplIHRoZSB0YXhhIHBlciBzYW1wbGVfaWQNCg0KYGBge3J9DQojfCBsYWJlbDogZ2VvY2hlbWlzdHJ5IHZpc3VhbGlzZQ0KZGF0YV9jb21tdW5pdHkgJT4lDQogIHRpYmJsZTo6cm93aWRfdG9fY29sdW1uKCJJRCIpICU+JQ0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSAtYyhzYW1wbGVfaWQsIElEKSwNCiAgICBuYW1lc190byA9ICJlbGVtZW50IiwNCiAgICB2YWx1ZXNfdG8gPSAidmFsdWUiDQogICkgJT4lDQogIGdncGxvdDI6OmdncGxvdCgNCiAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKA0KICAgICAgeCA9IElELA0KICAgICAgeSA9IHZhbHVlLA0KICAgICAgY29sID0gZWxlbWVudA0KICAgICksDQogICkgKw0KICBnZ3Bsb3QyOjpmYWNldF93cmFwKA0KICAgIH4gZWxlbWVudCwNCiAgICBucm93ID0gMSwNCiAgICBzY2FsZXMgPSAiZnJlZV94Ig0KICApICsNCiAgZ2dwbG90Mjo6Y29vcmRfZmxpcCgpICsNCiAgZ2dwbG90Mjo6dGhlbWUoDQogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZ2dwbG90Mjo6ZWxlbWVudF9saW5lKA0KICAgICAgY29sb3VyID0gImdyZXkiLA0KICAgICAgbGluZXdpZHRoID0gMC4xDQogICAgKSwNCiAgICBheGlzLnRleHQueSA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzLnkgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApICsNCiAgZ2dwbG90Mjo6bGFicygNCiAgICB4ID0gInNhbXBsZSBpZCIsDQogICAgeSA9ICJ2YWx1ZSINCiAgKSAgKw0KICBnZ3Bsb3QyOjpnZW9tX2xpbmUoKSAgDQpgYGANCg0KIyMgUHJlcGFyYXRpb24gb2YgdGhlIGxldmVscw0KDQojIyMgU2FtcGxlIGRlcHRoDQoNCkV4dHJhY3QgZGVwdGggZm9yIGVhY2ggbGV2ZWwNCg0KYGBge3J9DQojfCBsYWJlbDogbGV2ZWwgcHJlcGFyYXRpb24NCmRhdGFfbGV2ZWxzIDwtDQogIG5lb3RvbWEyOjpzYW1wbGVzKHNlbF9kYXRhc2V0X2Rvd25sb2FkKSAlPiUNCiAgdGliYmxlOjphc190aWJibGUoKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzYW1wbGVfaWQgPSBhcy5jaGFyYWN0ZXIoc2FtcGxlaWQpKSAlPiUNCiAgZHBseXI6OmRpc3RpbmN0KHNhbXBsZV9pZCwgZGVwdGgpICU+JQ0KICBkcGx5cjo6cmVsb2NhdGUoc2FtcGxlX2lkKQ0KDQpoZWFkKGRhdGFfbGV2ZWxzKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IGRpc3BsYXkgbGV2ZWwNCiN8IGVjaG86IEZBTFNFDQojfCByZXN1bHRzOiAnYXNpcycNCnBhbmRlcjo6cGFuZG9jLnRhYmxlKGhlYWQoZGF0YV9sZXZlbHMpKQ0KYGBgDQoNCiMjIyBBZ2UtZGVwdGggbW9kZWxsaW5nDQoNCldlIHdpbGwgcmVjYWxjdWxhdGUgdGhlIGFnZS1kZXB0aCBtb2RlbCAnZGUgbm92bycgdXNpbmcgdGhlIFsqQmNocm9uKiBwYWNrYWdlXShodHRwOi8vYW5kcmV3Y3Bhcm5lbGwuZ2l0aHViLmlvL0JjaHJvbi8pLiANCg0KIyMjIyBQcmVwYXJlIGNocm9uLmNvbnRyb2wgdGFibGUgYW5kIHJ1biBCY2hyb24NClRoZSBjaHJvbm9sb2d5IGNvbnRyb2wgdGFibGUgY29udGFpbnMgYWxsIHRoZSBkYXRlcyAobW9zdGx5IHJhZGlvY2FyYm9uKSB0byBjcmVhdGUgdGhlIGFnZS1kZXB0aCBtb2RlbC4NCg0KSGVyZSB3ZSBvbmx5IHByZXNlbnQgYSBmZXcgb2YgdGhlIGltcG9ydGFudCBzdGVwcyBvZiBwcmVwYXJhdGlvbiBvZiB0aGUgY2hyb25vbG9neSBjb250cm9sIHRhYmxlLiBUaGVyZSBhcmUgbWFueSBtb3JlIHBvdGVudGlhbCBpc3N1ZXMsIGJ1dCBzb2x2aW5nIHRob3NlIGlzIG5vdCB0aGUgZm9jdXMgb2YgdGhpcyB3b3JrZmxvdy4NCg0KYGBge3J9DQojfCBsYWJlbDogZ2V0IGNocm9ub2xvZ3kgdGFibGVzDQojIEZpcnN0LCBnZXQgdGhlIGNocm9ub2xvZ2llcyBhbmQgY2hlY2sgd2hpY2ggd2Ugd2FudCB0byB1c2UgdXNlZA0Kc2VsX2Nocm9uX2NvbnRyb2xfdGFibGVfZG93bmxvYWQgPC0NCiAgbmVvdG9tYTI6OmNocm9uY29udHJvbHMoc2VsX2RhdGFzZXRfZG93bmxvYWQpDQoNCnByaW50KHNlbF9jaHJvbl9jb250cm9sX3RhYmxlX2Rvd25sb2FkKQ0KYGBgDQpgYGB7cn0NCiN8IGxhYmVsOiBkaXNwbGF5IGNocm9uIGNvbnRyb2wgdGFibGVzDQojfCBlY2hvOiBGQUxTRQ0KI3wgcmVzdWx0czogJ2FzaXMnDQpwYW5kZXI6OnBhbmRvYy50YWJsZShoZWFkKHNlbF9jaHJvbl9jb250cm9sX3RhYmxlX2Rvd25sb2FkKSkNCmBgYA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBwcmVwYXJlY2hyb24gY29udHJvbCB0YWJsZQ0KIyBwcmVwYXJlIHRoZSB0YWJsZQ0KZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlIDwtDQogIHNlbF9jaHJvbl9jb250cm9sX3RhYmxlX2Rvd25sb2FkICU+JQ0KICAjIEhlcmUgc2VsZWN0IHRoZSBJRCBvZiBvbmUgb2YgdGhlIGNocm9ub2xvZ3kNCiAgZHBseXI6OmZpbHRlcihjaHJvbm9sb2d5aWQgPT0gMzMxNjgpICU+JQ0KICB0aWJibGU6OmFzX3RpYmJsZSgpICU+JQ0KICAjIEhlcmUgd2UgY2FsY3VsYXRlIHRoZSBlcnJvciBhcyB0aGUgYXZlcmFnZSBvZiB0aGUgYWdlIGBsaW1pdG9sZGVyYCBhbmQNCiAgIyAgIGBhZ2VsaW1pdHlvdW5nZXJgDQogIGRwbHlyOjptdXRhdGUoDQogICAgZXJyb3IgPSByb3VuZCgoYWdlbGltaXRvbGRlciAtIGFnZWxpbWl0eW91bmdlcikgLyAyKQ0KICApICU+JQ0KICAjIEFzIEJjaHJvbiBjYW5ub3QgYWNjZXB0IGEgZXJyb3Igb2YgMCwgd2UgbmVlZCB0byByZXBsYWNlIHRoZSB2YWx1ZSB3aXRoIDENCiAgZHBseXI6Om11dGF0ZSgNCiAgICBlcnJvciA9IHJlcGxhY2UoZXJyb3IsIGVycm9yID09IDAsIDEpLA0KICAgIGVycm9yID0gaWZlbHNlKGlzLm5hKGVycm9yKSwgMSwgZXJyb3IpDQogICkgJT4lDQogICMgV2UgbmVlZCB0byBzcGVjaWZ5IHdoaWNoIGNhbGlicmF0aW9uIGN1cnZlIHNob3VsZCBiZSB1c2VkIGZvciB3aGF0IHBvaW50DQogIGRwbHlyOjptdXRhdGUoDQogICAgY3VydmUgPSBpZmVsc2UoYXMuZGF0YS5mcmFtZShzZWxfZGF0YXNldF9kb3dubG9hZClbImxhdCJdID4gMCwgImludGNhbDIwIiwgInNoY2FsMjAiKSwNCiAgICBjdXJ2ZSA9IGlmZWxzZShjaHJvbmNvbnRyb2x0eXBlICE9ICJSYWRpb2NhcmJvbiIsICJub3JtYWwiLCBjdXJ2ZSkNCiAgKSAlPiUNCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoImNocm9uY29udHJvbGlkIikgJT4lDQogIGRwbHlyOjphcnJhbmdlKGRlcHRoKSAlPiUNCiAgZHBseXI6OnNlbGVjdCgNCiAgICBjaHJvbmNvbnRyb2xhZ2UsIGVycm9yLCBkZXB0aCwgdGhpY2tuZXNzLCBjaHJvbmNvbnRyb2x0eXBlLCBjdXJ2ZQ0KICApDQoNCmhlYWQoZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IGRpc3BsYXkgcHJlcGFyZWQgY2hyb24gY29udHJvbCB0YWJsZQ0KI3wgZWNobzogRkFMU0UNCiN8IHJlc3VsdHM6ICdhc2lzJw0KcGFuZGVyOjpwYW5kb2MudGFibGUoaGVhZChkYXRhX2Nocm9uX2NvbnRyb2xfdGFibGUpKQ0KYGBgDQoNCkFzIHRoaXMgaXMganVzdCBhIHRveSBleGFtcGxlLCB3ZSB3aWxsIHVzZSBvbmx5IHRoZSBpdGVyYXRpb24gbXVsdGlwbGllciAoYGlfbXVsdGlwbGllcmApIG9mIGAwLjFgIHRvIHJlZHVjZSB0aGUgY29tcHV0YXRpb24gdGltZS4gSG93ZXZlciwgd2Ugc3Ryb25nbHkgcmVjb21tZW5kIGluY3JlYXNpbmcgaXQgdG8gNSBmb3IgYW55IG5vcm1hbCBhZ2UtZGVwdGggbW9kZWwgY29uc3RydWN0aW9uLg0KYGBge3J9DQojfCBsYWJlbDogcnVuIEJjaHJvbg0KaV9tdWx0aXBsaWVyIDwtIDAuMSAjIGluY3JlYXNlIHRvIDUNCg0KIyBUaG9zZSBhcmUgZGVmYXVsdCB2YWx1ZXMgc3VnZ2VzdGVkIGJ5IHRoZSBCY2hyb24gcGFja2FnZQ0Kbl9pdGVyYXRpb25fZGVmYXVsdCA8LSAxMGUzDQpuX2J1cm5fZGVmYXVsdCA8LSAyZTMNCm5fdGhpbl9kZWZhdWx0IDwtIDgNCg0KIyBMZXQncyBtdWx0aXBseSB0aGVtIGJ5IG91ciBpX211bHRpcGxpZXINCm5faXRlcmF0aW9uIDwtIG5faXRlcmF0aW9uX2RlZmF1bHQgKiBpX211bHRpcGxpZXINCm5fYnVybiA8LSBuX2J1cm5fZGVmYXVsdCAqIGlfbXVsdGlwbGllcg0Kbl90aGluIDwtIG1heChjKDEsIG5fdGhpbl9kZWZhdWx0ICogaV9tdWx0aXBsaWVyKSkNCg0KIyBydW4gQmNocm9uDQpzZWxfYmNocm9uIDwtDQogIEJjaHJvbjo6QmNocm9ub2xvZ3koDQogICAgYWdlcyA9IGRhdGFfY2hyb25fY29udHJvbF90YWJsZSRjaHJvbmNvbnRyb2xhZ2UsDQogICAgYWdlU2RzID0gZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlJGVycm9yLA0KICAgIHBvc2l0aW9ucyA9IGRhdGFfY2hyb25fY29udHJvbF90YWJsZSRkZXB0aCwNCiAgICBjYWxDdXJ2ZXMgPSBkYXRhX2Nocm9uX2NvbnRyb2xfdGFibGUkY3VydmUsDQogICAgcG9zaXRpb25UaGlja25lc3NlcyA9IGRhdGFfY2hyb25fY29udHJvbF90YWJsZSR0aGlja25lc3MsDQogICAgaXRlcmF0aW9ucyA9IG5faXRlcmF0aW9uLA0KICAgIGJ1cm4gPSBuX2J1cm4sDQogICAgdGhpbiA9IG5fdGhpbg0KICApDQpgYGANCg0KVmlzdWFsbHkgY2hlY2sgdGhlIGFnZS1kZXB0aCBtb2RlbHMNCg0KYGBge3J9DQojfCBsYWJlbDogcGxvdCBCY2hyb24NCkJjaHJvbjo6OnBsb3QuQmNocm9ub2xvZ3lSdW4oc2VsX2JjaHJvbikgKyAjIG9yIGp1c3Qgc2ltcGxlIHBsb3Qoc2VsX2JjaHJvbikNCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwNCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICBzdHJpcC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgcGFuZWwuZ3JpZCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKQ0KICApICsNCiAgZ2dwbG90Mjo6bGFicygNCiAgICB4ID0gImFnZSAoY2FsIHlyIEJQKSIsDQogICAgeSA9ICJkZXB0aCINCiAgKQ0KYGBgDQoNCiMjIyMgUHJlZGljdCBhZ2VzDQoNCkxldCdzIGZpcnN0IGV4dHJhY3QgcG9zdGVyaW9yIGFnZXMgKGkuZS4gcG9zc2libGUgYWdlcykgZnJvbSB0aGUgYWdlLWRlcHRoIG1vZGVsLiAgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHByZWRpY3QgYWdlcw0KYWdlX3Bvc2l0aW9uIDwtDQogIEJjaHJvbjo6OnByZWRpY3QuQmNocm9ub2xvZ3lSdW4oICMgb3IganVzdCBzaW1wbGUgcHJlZGljdChzZWxfYmNocm9uKQ0KICAgIG9iamVjdCA9IHNlbF9iY2hyb24sDQogICAgbmV3UG9zaXRpb25zID0gZGF0YV9sZXZlbHMkZGVwdGgNCiAgKQ0KDQphZ2VfdW5jZXJ0YWludGllcyA8LQ0KICBhZ2VfcG9zaXRpb24gJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgZHBseXI6Om11dGF0ZV9hbGwoLiwgYXMuaW50ZWdlcikgJT4lDQogIGFzLm1hdHJpeCgpDQoNCmNvbG5hbWVzKGFnZV91bmNlcnRhaW50aWVzKSA8LSBkYXRhX2xldmVscyRzYW1wbGVfaWQNCg0KaGVhZChhZ2VfdW5jZXJ0YWludGllcywgbiA9IDgpWywgMTo4XQ0KYGBgDQoNCkhlcmUgd2Ugc2VlIHNhbXBsZXMgKGUuZy4sIDQzOTgxMSwgNDM5ODEyLCA0Mzk4MTMsLi4uKSBhbmQgdGhlaXIgcG9zc2libGUgYWdlcyAoYWdlIHNlcXVlbmNlKSB3aXRoIGVhY2ggbW9kZWwgaXRlcmF0aW9uIChwb3N0ZXJpb3IpLiBFYWNoIGFnZS1zZXF1ZW5jZSBpcyBzaW1pbGFyIGJ1dCB0aGVyZSBhcmUgZGlmZmVyZW5jZXMgb2YgdGVucyBvciBodW5kcmVkcyBvZiB5ZWFycy4gV2Ugd2lsbCBjYWxsIHRoaXMgKnRoZSB1bmNlcnRhaW50eSBtYXRyaXgqLg0KDQpgYGB7cn0NCiN8IGxhYmVsOiBkaXNwbGF5IHVuY2VydGFpbnR5IG1hdHJpeA0KI3wgZWNobzogRkFMU0UNCiN8IHJlc3VsdHM6ICdhc2lzJw0KcGFuZGVyOjpwYW5kb2MudGFibGUoaGVhZChhZ2VfdW5jZXJ0YWludGllcywgbiA9IDgpWywgMTo4XSkNCmBgYA0KDQpXZSBjYW4gdmlzdWFsaXplIHRoZXNlICJwb3NzaWJsZSBhZ2VzIiAoYWdlLXNlcXVlbmNlKSBvZiBlYWNoIGl0ZXJhdGlvbi4NCg0KYGBge3J9DQojfCBsYWJlbDogZGF0YSB0byBwbG90IHVuY2VydGFpbnR5IG1hdHJpeA0KIyBjcmVhdGUgYSBkYXRhLmZyYW1lIGZvciBwbG90dGluZw0KZGF0YV9hZ2VfdW5jZXJ0YWludGllcyA8LQ0KICBhZ2VfdW5jZXJ0YWludGllcyAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICB0aWJibGU6OnJvd2lkX3RvX2NvbHVtbigiSUQiKSAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLUlELA0KICAgIG5hbWVzX3RvID0gInNhbXBsZV9pZCIsDQogICAgdmFsdWVzX3RvID0gImFnZSINCiAgKSAlPiUNCiAgZHBseXI6OmxlZnRfam9pbigNCiAgICBkYXRhX2xldmVscywNCiAgICBieSA9IGRwbHlyOjpqb2luX2J5KHNhbXBsZV9pZCkNCiAgKQ0KYGBgDQoNCkVhY2ggbGluZSBpcyBhIHNpbmdsZSBwb3RlbnRpYWwgYWdlLWRlcHRoIG1vZGVsIGl0ZXJhdGlvbiAoYWdlLXNlcXVlbmNlKS4gR3JlZW4gcG9pbnRzIHJlcHJlc2VudCB0aGUgcmFkaW9jYXJib24gZGF0ZXMuIEhvcml6b250YWwgbGluZXMgYXJlIHRoZSBkZXB0aHMgb2Ygb3VyIHNhbXBsZXMuDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3QgdW5jZXJ0YWludHkgbWF0cml4DQojfCBmaWcuaGVpZ2h0OiAxMA0KKA0KICBmaWdfYWdlX3VuY2VydGFpbnRpZXMgPC0NCiAgICBkYXRhX2FnZV91bmNlcnRhaW50aWVzICU+JQ0KICAgIGdncGxvdDI6OmdncGxvdCgNCiAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMoDQogICAgICAgIHggPSBhZ2UsDQogICAgICAgIHkgPSBkZXB0aA0KICAgICAgKQ0KICAgICkgKw0KICAgIGdncGxvdDI6Omdlb21fbGluZSgNCiAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMoDQogICAgICAgIGdyb3VwID0gSUQNCiAgICAgICksDQogICAgICBhbHBoYSA9IDAuMDUsDQogICAgICBsaW5ld2lkdGggPSAwLjENCiAgICApICsNCiAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKA0KICAgICAgeWludGVyY2VwdCA9IGRhdGFfbGV2ZWxzJGRlcHRoLA0KICAgICAgbHR5ID0gMiwNCiAgICAgIGNvbG9yID0gImdyYXk1MCIsDQogICAgICBhbHBoYSA9IDAuMSwNCiAgICAgIGxpbmV3aWR0aCA9IDAuMQ0KICAgICkgKw0KICAgIGdncGxvdDI6Omdlb21fcG9pbnQoDQogICAgICBkYXRhID0gZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlLA0KICAgICAgbWFwcGluZyA9IGdncGxvdDI6OmFlcygNCiAgICAgICAgeCA9IGNocm9uY29udHJvbGFnZQ0KICAgICAgKSwNCiAgICAgIGNvbG9yID0gImdyZWVuIiwNCiAgICAgIHNoYXBlID0gMTUsDQogICAgICBzaXplID0gMw0KICAgICkgKw0KICAgIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJyZXZlcnNlIikgKw0KICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJyZXZlcnNlIikgKw0KICAgIGdncGxvdDI6OmxhYnMoDQogICAgICB4ID0gImFnZSAoY2FsIHlyIEJQKSINCiAgICApDQopDQpgYGANCg0KV2UgY2FuIHZpc3VhbGl6ZSBhbGwgYWdlLWRlcHRoICJwb3NzaWJsZSBhZ2VzIiB0b2dldGhlciBhcyB0aGUgcmFuZ2Ugb2YgdmFsdWVzLiBIZXJlLCBlYWNoIGxpbmUgcmVwcmVzZW50cyBvbmUgc2FtcGxlZCBkZXB0aCBpbiBvdXIgcmVjb3JkLg0KDQpgYGB7cn0NCiN8IGxhYmVsOiBwbG90IHVuY2VydGFpbnR5IG1hdHJpeCBib3hwbG90cw0KI3wgZmlnLmhlaWdodDogMTANCmRhdGFfYWdlX3VuY2VydGFpbnRpZXMgJT4lDQogIGdncGxvdDI6OmdncGxvdCgNCiAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKA0KICAgICAgeCA9IGFnZSwNCiAgICAgIHkgPSBkZXB0aCwNCiAgICAgIGdyb3VwID0gZGVwdGgNCiAgICApDQogICkgKw0KICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKA0KICAgIHlpbnRlcmNlcHQgPSBkYXRhX2xldmVscyRkZXB0aCwNCiAgICBsdHkgPSAyLA0KICAgIGNvbG9yID0gImdyYXk1MCIsDQogICAgYWxwaGEgPSAwLjEsDQogICAgbGluZXdpZHRoID0gMC4xDQogICkgKw0KICBnZ3Bsb3QyOjpnZW9tX2JveHBsb3QoDQogICAgb3V0bGllci5zaGFwZSA9IE5BDQogICkgKw0KICBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAicmV2ZXJzZSIpICsNCiAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gInJldmVyc2UiKSArDQogIGdncGxvdDI6OmxhYnMoDQogICAgeCA9ICJhZ2UgKGNhbCB5ciBCUCkiDQogICkNCmBgYA0KDQpMZXQncyB0YWtlIHRoZSBtZWRpYW4gYWdlIG9mIGFsbCBwb3NzaWJsZSBhZ2VzIChpLmUuIHRoZSBlc3RpbWF0ZWQgYWdlIGZyb20gZWFjaCBhZ2UtZGVwdGggbW9kZWwgcnVuKSBhcyBvdXIgZGVmYXVsdC4NCg0KYGBge3J9DQojfCBsYWJlbDogZ2V0IG1lZGlhbiBhZ2UNCmRhdGFfbGV2ZWxzX3ByZWRpY3RlZCA8LQ0KICBkYXRhX2xldmVscyAlPiUNCiAgZHBseXI6Om11dGF0ZSgNCiAgICBhZ2UgPSBhcHBseSgNCiAgICAgIGFnZV91bmNlcnRhaW50aWVzLCAyLA0KICAgICAgc3RhdHM6OnF1YW50aWxlLA0KICAgICAgcHJvYnMgPSAwLjUNCiAgICApDQogICkNCg0KaGVhZChkYXRhX2xldmVsc19wcmVkaWN0ZWQpDQpgYGANCg0KYGBge3J9DQojfCBsYWJlbDogZGlzcGxheSBtZWRpYW4gYWdlDQojfCBlY2hvOiBGQUxTRQ0KI3wgcmVzdWx0czogJ2FzaXMnDQpwYW5kZXI6OnBhbmRvYy50YWJsZShoZWFkKGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCkpDQpgYGANCg0KV2UgY2FuIHZpc3VhbGl6ZSB0aGUgbWVkaWFuIGFnZSBieSBkcmF3aW5nIGEgcmVkIGxpbmUuIFRoaXMgYWdlIGlzIHRoZSBhZ2UgdGhhdCBpcyBvZnRlbiByZXBvcnRlZCBpbiBwdWJsaWNhdGlvbnMgYnV0IGluIGVzc2VuY2UsIGl0IHJlcHJlc2VudHMgbXVsdGlwbGUgYWdlLWRlcHRoIG1vZGVsIHJ1bnMgd2l0aCBzbWFsbGVyIG9yIGxhcmdlciBhZ2UgdW5jZXJ0YWludGllcyB0aHJvdWdob3V0IHRoZSByZWNvcmQuDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3QgbWVkaWFuIGFnZQ0KI3wgZmlnLmhlaWdodDogMTANCmZpZ19hZ2VfdW5jZXJ0YWludGllcyArDQogIGdncGxvdDI6Omdlb21fcG9pbnQoDQogICAgZGF0YSA9IGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBjb2xvciA9ICJyZWQiLA0KICAgIHNpemUgPSAxDQogICkgKw0KICBnZ3Bsb3QyOjpnZW9tX2xpbmUoDQogICAgZGF0YSA9IGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBjb2xvciA9ICJyZWQiLA0KICAgIGxpbmV3aWR0aCA9IDAuNQ0KICApDQpgYGANCg0KIyMjIFZpc3VhbGlzYXRpb24gb2Ygb3VyIGRhdGENCg0KTGV0J3Mgbm93IG1ha2UgYSBzaW1wbGUgcG9sbGVuIGRpYWdyYW0gd2l0aCBwcm9wb3J0aW9ucyBvZiB0aGUgbWFpbiBwb2xsZW4gdGF4YSAoeC1heGlzKSBhZ2FpbnN0IG91ciBlc3RpbWF0ZWQgYWdlcyBhbG9uZyBkZXB0aCAoeS1heGlzKS4NCg0KYGBge3J9DQojfCBsYWJlbDogcGxvdCBkYXRhIHdpdGggYWdlcw0KZGF0YV9jb21tdW5pdHkgJT4lDQogIGRwbHlyOjppbm5lcl9qb2luKA0KICAgIGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBieSA9IGRwbHlyOjpqb2luX2J5KHNhbXBsZV9pZCkNCiAgKSAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWMoc2FtcGxlX2lkLCBkZXB0aCwgYWdlKSwNCiAgICBuYW1lc190byA9ICJlbGVtZW50IiwNCiAgICB2YWx1ZXNfdG8gPSAidmFsdWUiDQogICkgJT4lDQogIGdncGxvdDI6OmdncGxvdCgNCiAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKA0KICAgICAgeCA9IGFnZSwNCiAgICAgIHkgPSB2YWx1ZSwNCiAgICAgIGNvbCA9IGVsZW1lbnQNCiAgICApLA0KICApICsNCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCgNCiAgICB+ZWxlbWVudCwNCiAgICBucm93ID0gMSwNCiAgICBzY2FsZXMgPSAiZnJlZV94Ig0KICApICsNCiAgZ2dwbG90Mjo6Y29vcmRfZmxpcCgpICsNCiAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gInJldmVyc2UiKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGdncGxvdDI6OmVsZW1lbnRfbGluZSgNCiAgICAgIGNvbG91ciA9ICJncmV5IiwNCiAgICAgIGxpbmV3aWR0aCA9IDAuMQ0KICAgICksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkgKw0KICBnZ3Bsb3QyOjpsYWJzKA0KICAgIHggPSAiYWdlIChjYWwgeXIgQlApIiwNCiAgICB5ID0gInZhbHVlIg0KICApICsNCiAgZ2dwbG90Mjo6Z2VvbV9saW5lKCkNCmBgYA0KDQoNCiMjIEVzdGltYXRpb24gUmF0ZS1vZi1DaGFuZ2UNCg0KTm93IHdlIHdpbGwgdXNlIG91ciBwcmVwYXJlZCBnZW9jaGVtaXN0cnkgZGF0YSBhbmQgYWdlLWRlcHRoIG1vZGVsIHRvIGVzdGltYXRlIHRoZSByYXRlIG9mIGNoYW5nZS4NCldlIHdpbGwgcHJlc2VudCBzZXZlcmFsIHNjZW5hcmlvcyAoaS5lLiBhcHByb2FjaGVzKSB0byBjYWxjdWxhdGUgUm9DLiANCg0KIyMjIFNlbGVjdGlvbiBvZiBkaXNzaW1pbGFyaXR5IGNvZWZmaWNpZW50IA0KDQpXZSBjYW4gY2hlY2sgdGhlIHVuaXRzIG9mIGluZGl2aWR1YWwgbWVhc3VyZWQgdmFsdWVzOg0KYGBge3J9DQojfCBsYWJlbDogZGF0YSB1bml0cw0KZGF0YV91bml0cw0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IGRpc3BsYXkgZGF0YSB1bml0cw0KI3wgZWNobzogRkFMU0UNCiN8IHJlc3VsdHM6ICdhc2lzJw0KcGFuZGVyOjpwYW5kb2MudGFibGUoZGF0YV91bml0cykNCmBgYA0KDQpBcyB3ZSBjYW4gc2VlLCBhbGwgbWVhc3VyZWQgdmFsdWVzIGFyZSBpbiBkaWZmZXJlbnQgdW5pdHMuIFRoZXJlZm9yZSwgZm9yIGFsbCBzY2VuYXJpb3MsIHdlIHdpbGwgYmUgdXNpbmcgdGhlIGBnb3dlcmAgZGlzc2ltaWxhcml0eSBjb2VmZmljaWVudCAod29ya3Mgd2l0aCBkYXRhIGluIHZhcmlvdXMgdW5pdHMpLCBwcmV2ZW50IHR1cm5pbmcgdGhlbSBpbnRvIHByb3BvcnRpb25zIChhcyBpdCBkb2VzIG5vdCBtYWtlIHNlbnNlKSB3aXRoIGB0cmFuZm9ybV90b19wcm9wb3J0aW9uc2AgPT0gYEZBTFNFYCwgYW5kIHNldCBgdGltZV9zdGFuZGFyZGlzYXRpb25gID09IDI1MCAodGhpcyBtZWFucyB0aGF0IGFsbCBST0MgdmFsdWVzIGFyZSAnY2hhbmdlIHBlciAyNTAgeXInKS4NCg0KIyMjIFNjZW5hcmlvIDEgLSBFc3RpbWF0aW5nIFJvQyBmb3IgZWFjaCBsZXZlbA0KDQpUaGlzIGlzIHRoZSAiQ2xhc3NpYyIgYXBwcm9hY2ggdGhhdCB1c2VzIGVhY2ggc2FtcGxlZCBkZXB0aCBpbiBhIHJlY29yZCAoaS5lLiBpbmRpdmlkdWFsIGxldmVsKSB0byBlc3RpbWF0ZSBSb0MuDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHNjZW5hcmlvIDENCnNjZW5hcmlvXzEgPC0NCiAgUlJhdGVwb2w6OmVzdGltYXRlX3JvYygNCiAgICBkYXRhX3NvdXJjZV9jb21tdW5pdHkgPSBkYXRhX2NvbW11bml0eSwNCiAgICBkYXRhX3NvdXJjZV9hZ2UgPSBkYXRhX2xldmVsc19wcmVkaWN0ZWQsDQogICAgZGlzc2ltaWxhcml0eV9jb2VmZmljaWVudCA9ICJnb3dlciIsDQogICAgdHJhbmZvcm1fdG9fcHJvcG9ydGlvbnMgPSBGQUxTRSwNCiAgICB0aW1lX3N0YW5kYXJkaXNhdGlvbiA9IDI1MCwNCiAgICB3b3JraW5nX3VuaXRzID0gImxldmVscyIgIyBoZXJlIGlzIHNldCB0byB1c2UgaW5kaXZpZHVhbCBsZXZlbHMNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gMQ0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fMSkNCmBgYA0KDQojIyMgU2NlbmFyaW8gMiAtIEVzdGltYXRpbmcgUm9DIGZvciBlYWNoIGxldmVsIHdpdGggc21vb3RoaW5nIG9mIGRhdGENCg0KV2UgZG8gdGhlIHNhbWUgYXMgaW4gU2NlbmFyaW8gMSBidXQgbm93IHdlIHNtb290aCB0aGUgY29tbXVuaXR5IGRhdGEgYmVmb3JlIGNhbGN1bGF0aW5nIFJvQy4gVGhpcyBtYXkgYmUgdXNlZnVsIHRvIG1pdGlnYXRlIHRoZSBlcnJvciBvZiBtZWFzdXJlbWVudHMuIFNwZWNpZmljYWxseSwgd2Ugd2lsbCBhZGQgYHNtb290aF9tZXRob2RgID0gInNoZXAiIChpLmUuIFNoZXBhcmQncyA1LXRlcm0gZmlsdGVyKS4NCg0KYGBge3J9DQojfCBsYWJlbDogc2NlbmFyaW8gMg0Kc2NlbmFyaW9fMiA8LQ0KICBSUmF0ZXBvbDo6ZXN0aW1hdGVfcm9jKA0KICAgIGRhdGFfc291cmNlX2NvbW11bml0eSA9IGRhdGFfY29tbXVuaXR5LA0KICAgIGRhdGFfc291cmNlX2FnZSA9IGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBkaXNzaW1pbGFyaXR5X2NvZWZmaWNpZW50ID0gImdvd2VyIiwNCiAgICB0cmFuZm9ybV90b19wcm9wb3J0aW9ucyA9IEZBTFNFLA0KICAgIHRpbWVfc3RhbmRhcmRpc2F0aW9uID0gMjUwLA0KICAgIHdvcmtpbmdfdW5pdHMgPSAibGV2ZWxzIiwNCiAgICBzbW9vdGhfbWV0aG9kID0gInNoZXAiICMgU2hlcGFyZCdzIDUtdGVybSBmaWx0ZXINCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gMg0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fMikNCmBgYA0KDQpXZSBzZWUgdGhhdCB0aGUgYWJzb2x1dGUgUm9DIHNjb3JlcyBhcmUgZGVjcmVhc2VkIGFuZCB0aGUgcGF0dGVybiBjaGFuZ2VkIHNsaWdodGx5ICh4LWF4aXMpLiANCg0KIyMjIFNjZW5hcmlvIDMgLSBVc2luZyB1bmNlcnRhaW50eSBtYXRyaXgNCg0KRm9yIFJvQyBhbmFseXNpcywgaXQgaXMgaW1wb3J0YW50IHRvIGNvbnNpZGVyIGFnZSB1bmNlcnRhaW50aWVzLiBGb3IgZWFjaCBpdGVyYXRpb24sIFJSYXRlcG9sIHdpbGwgcmFuZG9tbHkgc2VsZWN0IG9uZSBhZ2Ugc2VxdWVuY2UgZnJvbSB0aGUgdW5jZXJ0YWludHkgbWF0cml4IChzZWUgdGhlIGFnZS1kZXB0aCBtb2RlbGluZyBzZWN0aW9uIGZvciBtb3JlIGluZm8pLiANCg0KQmVjYXVzZSBvZiB0aGF0LCB3ZSBuZWVkIHRvIGluY3JlYXNlIHRoZSBudW1iZXIgb2YgcmFuZG9taXphdGlvbnMuIFRoaXMgaXMgYWdhaW4gYSB0b3kgZXhhbXBsZSBmb3IgYSBxdWljayBjb21wdXRhdGlvbiBhbmQgdGhlcmVmb3JlIHdlIG9ubHkgZG8gMTAwIHJhbmRvbWl6YXRpb25zLiBXZSB3b3VsZCByZWNvbW1lbmQgaW5jcmVhc2luZyB0aGUgKnNldF9yYW5kb21pc2F0aW9ucyogdG8gMTAuMDAwIGZvciBhbnkgcmVhbCBlc3RpbWF0aW9uLiANCg0KYGBge3J9DQojfCBsYWJlbDogc2V0IHJhbmRvbWlzYXRpb25zDQpzZXRfcmFuZG9taXNhdGlvbnMgPC0gMTAwDQpgYGANCg0KVG8gc3BlZWQgdGhlIHByb2Nlc3MgdXAsIHlvdSBjYW4gYWxzbyBzZXQgYHVzZV9wYXJhbGxlbGAgPT0gYFRSVUVgLCB3aGljaCB3aWxsIHVzZSBhbGwgY29yZXMgb2YgeW91ciBjb21wdXRlci4NCg0KYGBge3J9DQojfCBsYWJlbDogc2NlbmFyaW8gMw0Kc2NlbmFyaW9fMyA8LQ0KICBSUmF0ZXBvbDo6ZXN0aW1hdGVfcm9jKA0KICBkYXRhX3NvdXJjZV9jb21tdW5pdHkgPSBkYXRhX2NvbW11bml0eSwNCiAgICBkYXRhX3NvdXJjZV9hZ2UgPSBkYXRhX2xldmVsc19wcmVkaWN0ZWQsDQogICAgZGlzc2ltaWxhcml0eV9jb2VmZmljaWVudCA9ICJnb3dlciIsDQogICAgdHJhbmZvcm1fdG9fcHJvcG9ydGlvbnMgPSBGQUxTRSwNCiAgICB0aW1lX3N0YW5kYXJkaXNhdGlvbiA9IDI1MCwNCiAgICBzbW9vdGhfbWV0aG9kID0gInNoZXAiLA0KICAgIGFnZV91bmNlcnRhaW50eSA9IGFnZV91bmNlcnRhaW50aWVzLCAjIEFkZCB0aGUgdW5jZXJ0YWludHkgbWF0cml4DQogICAgcmFuZCA9IHNldF9yYW5kb21pc2F0aW9ucywgICMgc2V0IG51bWJlciBvZiByYW5kb21pc2F0aW9ucw0KICAgIHVzZV9wYXJhbGxlbCA9IFRSVUUgIyBkbyB1c2UgcGFyYWxsZWwgY29tcHV0aW5nDQogICkNCmBgYCANCg0KYGBge3J9DQojfCBsYWJlbDogcGxvdCBzY2VuYXJpbyAzDQpSUmF0ZXBvbDo6cGxvdF9yb2MoZGF0YV9zb3VyY2UgPSBzY2VuYXJpb18zKQ0KYGBgDQoNCldlIHdpbGwgbm93IGFsc28gdmlzdWFsaXplIHVuY2VydGFpbnR5IGFyb3VuZCB0aGUgUm9DIHNjb3JlcyBzaG93biBieSBhIGdyZXkgc2hhZG93LiBXZSBzZWUgYSBzdWJzdGFudGlhbCBpbmNyZWFzZSBpbiB0aGUgUm9DIHZhbHVlIGluIGNlcnRhaW4gcmVnaW9ucywgdGhpcyBpcyBjYXVzZWQgYnkgdGhlIGV4dHJlbWVseSBzbWFsbCBudW1iZXJzIG9mIGFnZSBkaWZmZXJlbmNlcyBhbmQgbG93IG51bWJlciBvZiByYW5kb21pemF0aW9ucy4NCg0KIyMjIFNjZW5hcmlvIDQgLSBFc3RpbWF0aW5nIFJvQyBwZXIgYmluDQoNCkluIG9yZGVyIHRvIGdldCByaWQgb2YgdGhlIGVmZmVjdCBvZiB1bmV2ZW4gZGlzdHJpYnV0aW9uIG9mIHNhbXBsZWQgZGVwdGhzIChpLmUuIGxldmVscykgaW4gYSByZWNvcmQsIHdlIGNhbiBiaW4gdGhlIGRhdGEuDQoNClNwZWNpZmljYWxseSwgd2Ugd2lsbCBjaGFuZ2UgdGhlIGB3b3JraW5nX3VuaXRzYCBmcm9tIHNpbmdsZSBsZXZlbHMgdG8gYCJiaW5zImAuIEhlcmUgd2Ugc2VsZWN0IGJpbnMgb2YgMjUwIHllYXJzIGVhY2ggaW5zdGVhZCBvZiB0aGUgaW5kaXZpZHVhbCBsZXZlbHMuIA0KDQpOb3RlIHRoYXQgb25lIGxldmVsIGlzIHJhbmRvbWx5IHNlbGVjdGVkIGFzIGEgcmVwcmVzZW50YXRpb24gb2YgdGhhdCB0aW1lIGJpbi4gVGhlcmVmb3JlLCBpdCBpcyBpbXBvcnRhbnQgdG8gaW5jcmVhc2UgdGhlIG51bWJlciBvZiByYW5kb21pemF0aW9ucy4gDQpgYGB7cn0NCiN8IGxhYmVsOiBzY2VuYXJpbyA0DQpzY2VuYXJpb180IDwtDQogIFJSYXRlcG9sOjplc3RpbWF0ZV9yb2MoDQogICAgZGF0YV9zb3VyY2VfY29tbXVuaXR5ID0gZGF0YV9jb21tdW5pdHksDQogICAgZGF0YV9zb3VyY2VfYWdlID0gZGF0YV9sZXZlbHNfcHJlZGljdGVkLA0KICAgIGRpc3NpbWlsYXJpdHlfY29lZmZpY2llbnQgPSAiZ293ZXIiLA0KICAgIHRyYW5mb3JtX3RvX3Byb3BvcnRpb25zID0gRkFMU0UsDQogICAgd29ya2luZ191bml0cyA9ICJiaW5zIiwgIyBjaGFuZ2UgdGhlICJiaW5zIg0KICAgIGJpbl9zaXplID0gMjUwLCAjIHNpemUgb2YgYSB0aW1lIGJpbg0KICAgIHRpbWVfc3RhbmRhcmRpc2F0aW9uID0gMjUwLA0KICAgIHNtb290aF9tZXRob2QgPSAic2hlcCIsDQogICAgYWdlX3VuY2VydGFpbnR5ID0gYWdlX3VuY2VydGFpbnRpZXMsDQogICAgcmFuZCA9IHNldF9yYW5kb21pc2F0aW9ucywgDQogICAgdXNlX3BhcmFsbGVsID0gVFJVRSANCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gNA0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fNCkNCmBgYA0KDQpIZXJlIHdlIGNhbiBzZWUgYSBkcmFzdGljIGNoYW5nZSBpbiB0aGUgc2hhcGUgb2YgUm9DIGJ1dCBhIGxhcmdlIGxvc3Mgb2YgdGVtcG9yYWwgcHJlY2lzaW9uLg0KDQojIyMgU2NlbmFyaW8gNSAtIEVzdGltYXRpbmcgUm9DIHdpdGggdGhlIG5ldyAiTW92aW5nLXdpbmRvdyIgYXBwcm9hY2gNCg0KSW4gb3JkZXIgdG8gcmVkdWNlIHRoZSB0ZW1wb3JhbCB1bmNlcnRhaW50eSBhbmQgaW1wcm92ZSB0ZW1wb3JhbCBwcmVjaXNpb24sIHdlIGNhbiBhcHBseSBhIG5vdmVsIGFwcHJvYWNoIGluIFJSQVRFUE9MIGNhbGxlZCAibW92aW5nIHdpbmRvdyIuIA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBzY2VuYXJpbyA1DQpzY2VuYXJpb181IDwtDQogIFJSYXRlcG9sOjplc3RpbWF0ZV9yb2MoDQogICAgZGF0YV9zb3VyY2VfY29tbXVuaXR5ID0gZGF0YV9jb21tdW5pdHksDQogICAgZGF0YV9zb3VyY2VfYWdlID0gZGF0YV9sZXZlbHNfcHJlZGljdGVkLA0KICAgIGRpc3NpbWlsYXJpdHlfY29lZmZpY2llbnQgPSAiZ293ZXIiLA0KICAgIHRyYW5mb3JtX3RvX3Byb3BvcnRpb25zID0gRkFMU0UsDQogICAgd29ya2luZ191bml0cyA9ICJNVyIsICMgY2hhbmdlIHRoZSAiTVciIHRvIGFwcGx5IHRoZSAibW92aW5nIHdpbmRvdyINCiAgICBiaW5fc2l6ZSA9IDI1MCwNCiAgICBudW1iZXJfb2Zfc2hpZnRzID0gNSwgIyBudW1iZXIgb2Ygc2hpZnRzDQogICAgdGltZV9zdGFuZGFyZGlzYXRpb24gPSAyNTAsDQogICAgc21vb3RoX21ldGhvZCA9ICJzaGVwIiwNCiAgICByYW5kID0gc2V0X3JhbmRvbWlzYXRpb25zLA0KICAgIHVzZV9wYXJhbGxlbCA9IFRSVUUsDQogICAgYWdlX3VuY2VydGFpbnR5ID0gYWdlX3VuY2VydGFpbnRpZXMNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gNQ0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fNSkNCmBgYA0KDQojIyMgU2NlbmFyaW8gNiAtIERldGVjdGluZyBwZWFrIHBvaW50cw0KDQpUaHJvdWdob3V0IHRoZSByZWNvcmQsIHRoZXJlIGNhbiBiZSBwZXJpb2RzIHdoZW4gdGhlIFJvQyB3aWxsIHN1YnN0YW50aWFsbHkgY2hhbmdlLiBXZSBjYW4gZGV0ZWN0IFJvQyBpbmNyZWFzZXMgdGhhdCBhcmUgc2lnbmlmaWNhbnQgYnkgaWRlbnRpZnlpbmcgc28tY2FsbGVkICpwZWFrLXBvaW50cyouIEhlcmUsIHdlIHdpbGwgdXNlIHRoZSAiTm9uLWxpbmVhciIgbWV0aG9kLCB3aGljaCB3aWxsIGRldGVjdCBhIHNpZ25pZmljYW50IGNoYW5nZSBmcm9tIGEgbm9uLWxpbmVhciB0cmVuZCBvZiBSb0MuDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBlYWtfcG9pbnRzIA0Kc2NlbmFyaW9fNV9wZWFrIDwtDQogIFJSYXRlcG9sOjpkZXRlY3RfcGVha19wb2ludHMoDQogICAgZGF0YV9zb3VyY2UgPSBzY2VuYXJpb181LA0KICAgIHNlbF9tZXRob2QgPSAidHJlbmRfbm9uX2xpbmVhciINCiAgKQ0KYGBgDQoNCk5vdyB3ZSB3aWxsIHBsb3QgdGhlIFJvQyBlc3RpbWF0ZXMgc2hvd2luZyB0aGUgcGVhayBwb2ludHMuIFNvIGhlcmUgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIHdlcmUgcmF0ZXMgb2YgdmVnZXRhdGlvbiBjaGFuZ2UgdGhyb3VnaG91dCB0aGUgcmVjb3JkIGJ1dCBvbmx5IGF0IGNlcnRhaW4gbW9tZW50cyBpbiB0aW1lIChncmVlbiBkb3RzIC0gcGVhayBwb2ludHMpIHRoZXNlIGNoYW5nZXMgd2VyZSBzaWduaWZpY2FudC4gVGhlcmUgeW91IGdvIQ0KDQpgYGB7cn0NCiN8IGxhYmVsOiBwbG90IHBlYWsgcG9pbnRzDQpSUmF0ZXBvbDo6cGxvdF9yb2MoDQogIGRhdGFfc291cmNlID0gc2NlbmFyaW9fNV9wZWFrLA0KICBwZWFrcyA9IFRSVUUNCikNCmBgYA==