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.
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]
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)
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
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 |
-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)
-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.
-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)
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
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==