Download a dataset from Neotoma
Here we have selected the Dářko peat record (ID =
48306) by Kletetschka, Günther.
Reference paper: Roleček, J., H. Svitavská Svobodová, E. Jamrichová,
L. Dudová, P. Hájková, G. Kletetschka, P. Kuneš, and V. Abraham. 2020.
Conservation targets from the perspective of a palaeoecological
reconstruction: the case study of Dářko peat bog in the Czech Republic.
Preslia 92(2):87-114. DOI: 10.23855/preslia.2020.087
sel_dataset_download <-
neotoma2::get_downloads(48306)
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()
# make table with units for later
data_units <-
data_samples %>%
dplyr::distinct(variablename, units)
head(data_community)[, 1:5]
445127 |
4e-04 |
9e-04 |
0.0013 |
0.0032 |
445128 |
7e-04 |
0.0015 |
0.0024 |
0.0035 |
445129 |
8e-04 |
0.0017 |
0.0021 |
0.0037 |
445130 |
7e-04 |
0.0015 |
0.0026 |
0.0037 |
445131 |
7e-04 |
0.0017 |
0.0023 |
0.0039 |
445132 |
8e-04 |
0.0016 |
0.0022 |
0.0041 |
Here, we strongly advocate that careful preparation of the datasets
(with additional steps) may be needed before using R-Ratepol!
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)
445127 |
0 |
445128 |
0.2 |
445129 |
0.4 |
445130 |
0.6 |
445131 |
0.8 |
445132 |
1 |
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
27171 |
33682 |
0 |
NA |
-60 |
104411 |
27171 |
33682 |
25 |
1 |
645 |
104412 |
27171 |
33682 |
50 |
1 |
1795 |
104413 |
27171 |
33682 |
100 |
1 |
2400 |
104414 |
27171 |
33682 |
155 |
1 |
2810 |
104415 |
27171 |
33682 |
200 |
1 |
3590 |
104416 |
-70 |
-65 |
Core top |
585 |
615 |
Radiocarbon |
1735 |
1765 |
Radiocarbon |
2340 |
2370 |
Radiocarbon |
2740 |
2775 |
Radiocarbon |
3530 |
3560 |
Radiocarbon |
# prepare the table
data_chron_control_table <-
sel_chron_control_table_download %>%
# Here select the ID of one of the chronology
dplyr::filter(chronologyid == 33682) %>%
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),
thickness = ifelse(is.na(thickness), 1, thickness)
) %>%
# 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)
-65 |
5 |
0 |
1 |
Core top |
normal |
615 |
30 |
25 |
1 |
Radiocarbon |
intcal20 |
1765 |
30 |
50 |
1 |
Radiocarbon |
intcal20 |
2370 |
30 |
100 |
1 |
Radiocarbon |
intcal20 |
2775 |
35 |
155 |
1 |
Radiocarbon |
intcal20 |
3560 |
30 |
200 |
1 |
Radiocarbon |
intcal20 |
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
data_levels_predicted <-
data_levels %>%
dplyr::mutate(
age = apply(
age_uncertainties, 2,
stats::quantile,
probs = 0.5
)
)
head(data_levels_predicted)
445127 |
0 |
-65 |
445128 |
0.2 |
-59 |
445129 |
0.4 |
-54 |
445130 |
0.6 |
-48 |
445131 |
0.8 |
-43 |
445132 |
1 |
-38 |
Visualisation of our data
Let’s now make a simple diagram with proportions of the
concentrations (x-axis) against our estimated ages along the 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::scale_y_continuous(breaks = c(0, 50, 100)) +
ggplot2::theme(
panel.grid.major.x = ggplot2::element_line(
colour = "grey",
linewidth = 0.1
),
legend.position = "none",
panel.border = ggplot2::element_blank(),
strip.background = ggplot2::element_blank(),
strip.text = ggplot2::element_blank(),
axis.ticks.x = ggplot2::element_blank(),
axis.text.x = ggplot2::element_blank()
) +
ggplot2::labs(
x = "age (cal yr BP)",
y = "Percentage"
) +
ggplot2::geom_line()
Estimation Rate-of-Change
Now we will use our prepared XRF 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 %>%
dplyr::pull("units") %>%
table()
As we can see, all measured values are in percentage units.
Therefore, for all scenarios, we will be using the chisq
dissimilarity coefficient (works with closed data), and
time_standardisation
== 500 (this means that all ROC values
are ‘change per 500 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 = "chisq",
time_standardisation = 500,
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
measurement. 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 = "chisq",
time_standardisation = 500,
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 = "chisq",
time_standardisation = 500,
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 RoC value in certain
regions, this is caused by the extremely small numbers of age
differences and the 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 500 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 = "chisq",
working_units = "bins", # change the "bins"
bin_size = 500, # size of a time bin
time_standardisation = 500,
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 = "chisq",
working_units = "MW", # change the "MW" to apply the "moving window"
bin_size = 500,
number_of_shifts = 5, # number of shifts
time_standardisation = 500,
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
)
LS0tDQp0aXRsZTogUGFydCAyIC0gWFJGIGRhdGENCmZvcm1hdDogDQogIGdmbToNCiAgICBmaWctd2lkdGg6IDcNCiAgICBmaWctaGVpZ2h0OiA2DQogICAgd3JhcDogbm9uZQ0KDQotLS0NCg0KYGBge3J9DQojfCBsYWJlbDogY2h1bmsgc2V0dXANCiN8IGluY2x1ZGU6IEZBTFNFIA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGNvbW1lbnQgPSAiIz4iLA0KICByZXN1bHRzID0gImhpZGUiLA0KICB3YXJuaW5nID0gRkFMU0UsDQogIG1lc3NhZ2UgPSBGQUxTRSwNCiAgZmlnLmFsaWduID0gImNlbnRlciINCikNCmBgYA0KDQpUaGlzIHdvcmtmbG93IHNob3VsZCBzaG93IHRoZSBmdWxsIHN0cmVuZ3RoIG9mIHRoZSBbKlJSYXRlcG9sIHBhY2thZ2UqXShodHRwczovL2hvcGUtdWliLWJpby5naXRodWIuaW8vUi1SYXRlcG9sLXBhY2thZ2UvKSBmb3Igd29ya2luZyB3aXRoIGRhdGEgdHlwZXMgKipvdGhlcioqIHRoYW4gZm9zc2lsIHBvbGxlbiwgc3BlY2lmaWNhbGx5IGZvciAqKlhSRiBkYXRhKiouIEl0IHNob3VsZCBzZXJ2ZSBhcyBzdGVwLWJ5LXN0ZXAgZ3VpZGFuY2Ugc3RhcnRpbmcgZnJvbSBkb3dubG9hZGluZyBkYXRhc2V0cyBmcm9tIHRoZSBOZW90b21hIGFuZCBidWlsZGluZyBhZ2UtZGVwdGggbW9kZWxzLCB0byBlc3RpbWF0aW5nIHJhdGUtb2YtY2hhbmdlIHVzaW5nIGFnZSB1bmNlcnRhaW50eS4gDQoNCkZvciBhIHdvcmtmbG93IHVzaW5nICoqR2VvY2hlbWljYWwgZGF0YSoqLCBzZWUgW1BhcnQgMSAtIEdlb2NoZW1pY2FsIGRhdGFdKGh0dHBzOi8vb25kcmVqbW90dGwuZ2l0aHViLmlvL09DQ1JfUi1SYXRlcG9sX3dvcmtzaG9wL3BhcnRfMl94cmZfZGF0YS5odG1sKS4NCg0K4pqg77iPKipUaGlzIHdvcmtmbG93IGlzIG9ubHkgbWVhbnQgYXMgYW4gZXhhbXBsZSoqOiBUaGVyZSBtYXkgYmUgc2V2ZXJhbCBhZGRpdGlvbmFsIHN0ZXBzIGZvciBkYXRhIHByZXBhcmF0aW9uLCB3aGljaCBzaG91bGQgYmUgZG9uZSB0byBwcm9wZXJseSBpbXBsZW1lbnQgUlJhdGVwb2wgYW5kIGFzc2VzcyB0aGUgcmF0ZSBvZiBjaGFuZ2UgZm9yIHlvdXIgc3BlY2lmaWMgcHJvamVjdC4gDQoNCiMjIFByZXJlcXVpc2l0ZXMNCg0KUGxlYXNlIGZvbGxvdyB0aGUgW3ByZS13b3Jrc2hvcCBpbnN0cnVjdGlvbnNdKGh0dHBzOi8vb25kcmVqbW90dGwuZ2l0aHViLmlvL09DQ1JfUi1SYXRlcG9sX3dvcmtzaG9wL3ByZV93b3Jrc2hvcC5odG1sKSB0byBtYWtlIHN1cmUgYWxsIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQuDQoNClRoaXMgaXMgdGhlIHNlY29uZCBwYXJ0IG9mIHRoZSB3b3Jrc2hvcC4gVGhlcmVmb3JlLCBzb21lIHN0ZXBzIHdpbGwgYmUgb21pdHRlZCBhbmQvb3Igbm90IGV4cGxhaW5lZC4gRm9yIGFsbCBkZXRhaWxzIGFib3V0IGluZGl2aWR1YWwgc3RlcHMsIHNlZSBbUGFydCAxIC0gR2VvY2hlbWljYWwgZGF0YV0oaHR0cHM6Ly9vbmRyZWptb3R0bC5naXRodWIuaW8vT0NDUl9SLVJhdGVwb2xfd29ya3Nob3AvcGFydF8yX3hyZl9kYXRhLmh0bWwpLg0KDQojIyBBdHRhY2ggcGFja2FnZXMNCg0KYGBge3J9DQojfCBsYWJlbDogYXR0YWNoIHBhY2thZ2VzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBnZW5lcmFsIGRhdGEgd3JhbmdsaW5nIGFuZCB2aXN1YWxpc2F0aW9uIOKcqA0KbGlicmFyeShwYW5kZXIpICMgbmljZSB0YWJsZXMg8J+YjQ0KbGlicmFyeShSUmF0ZXBvbCkgIyByYXRlLW9mLXZlZ2V0YXRpb24gY2hhbmdlICEgPiB2MS4yLjAgISDwn5OIDQpsaWJyYXJ5KG5lb3RvbWEyKSAjIGFjY2VzcyB0byB0aGUgTmVvdG9tYSBkYXRhYmFzZSDwn4y/DQpsaWJyYXJ5KEJjaHJvbikgIyBhZ2UtZGVwdGggbW9kZWxpbmduZyDwn5Ww77iPDQpsaWJyYXJ5KGphbml0b3IpICMgc3RyaW5nIGNsZWFuaW5nIPCfp7kNCmxpYnJhcnkoaGVyZSkgIyBmb3Igd29ya2luZyBkaXJlY3Rvcnkg8J+Xuu+4jw0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHRoZW1lIHNldA0KI3wgaW5jbHVkZTogRkFMU0UNCmdncGxvdDI6OnRoZW1lX3NldCgNCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogICAgZ2dwbG90Mjo6dGhlbWUoDQogICAgICBheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAyNSksDQogICAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgIHN0cmlwLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgIHBhbmVsLmdyaWQgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCkNCiAgICApDQopDQpgYGANCg0KDQojIyBEb3dubG9hZCBhIGRhdGFzZXQgZnJvbSBOZW90b21hDQoNCkhlcmUgd2UgaGF2ZSBzZWxlY3RlZCB0aGUgKipEw6HFmWtvIHBlYXQqKiByZWNvcmQgKElEID0gNDgzMDYpIGJ5IEtsZXRldHNjaGthLCBHw7xudGhlci4NCg0KUmVmZXJlbmNlIHBhcGVyOiBSb2xlxI1laywgSi4sIEguIFN2aXRhdnNrw6EgU3ZvYm9kb3bDoSwgRS4gSmFtcmljaG92w6EsIEwuIER1ZG92w6EsIFAuIEjDoWprb3bDoSwgRy4gS2xldGV0c2Noa2EsIFAuIEt1bmXFoSwgYW5kIFYuIEFicmFoYW0uIDIwMjAuIENvbnNlcnZhdGlvbiB0YXJnZXRzIGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIGEgcGFsYWVvZWNvbG9naWNhbCByZWNvbnN0cnVjdGlvbjogdGhlIGNhc2Ugc3R1ZHkgb2YgRMOhxZlrbyBwZWF0IGJvZyBpbiB0aGUgQ3plY2ggUmVwdWJsaWMuIFByZXNsaWEgOTIoMik6ODctMTE0LiBET0k6IDEwLjIzODU1L3ByZXNsaWEuMjAyMC4wODcNCg0KYGBge3J9DQojfCBsYWJlbDogZG93bmxvYWQgZGF0YXNldA0Kc2VsX2RhdGFzZXRfZG93bmxvYWQgPC0NCiAgbmVvdG9tYTI6OmdldF9kb3dubG9hZHMoNDgzMDYpDQpgYGANCg0KIyMgUHJlcGFyZSB0aGUgZ2VvY2hlbWljYWwgZGF0YQ0KDQpgYGB7cn0NCiN8IGxhYmVsOiBwcmVwYXJlIGdlb2NoZW1pY2FsIGRhdGENCiMgZ2V0IHNhbXBsZXMNCmRhdGFfc2FtcGxlcyA8LQ0KICBuZW90b21hMjo6c2FtcGxlcyhzZWxfZGF0YXNldF9kb3dubG9hZCkgICU+JSANCiAgdGliYmxlOjphc190aWJibGUoKQ0KDQojIHByZXBhcmUgdGF4YSB0YWJsZQ0KZGF0YV9jb21tdW5pdHkgPC0NCiAgZGF0YV9zYW1wbGVzICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNhbXBsZV9pZCA9IGFzLmNoYXJhY3RlcihzYW1wbGVpZCkpICU+JQ0KICBkcGx5cjo6c2VsZWN0KCJzYW1wbGVfaWQiLCAidmFsdWUiLCAidmFyaWFibGVuYW1lIikgJT4lDQogICMgdHVybiBpbnRvIHRoZSB3aWRlciBmb3JtYXQNCiAgdGlkeXI6OnBpdm90X3dpZGVyKA0KICAgIG5hbWVzX2Zyb20gPSAidmFyaWFibGVuYW1lIiwNCiAgICB2YWx1ZXNfZnJvbSA9ICJ2YWx1ZSIsDQogICAgdmFsdWVzX2ZpbGwgPSAwDQogICkgJT4lDQogICMgY2xlYW4gbmFtZXMNCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAgDQoNCiMgbWFrZSB0YWJsZSB3aXRoIHVuaXRzIGZvciBsYXRlcg0KZGF0YV91bml0cyA8LQ0KICBkYXRhX3NhbXBsZXMgJT4lDQogIGRwbHlyOjpkaXN0aW5jdCh2YXJpYWJsZW5hbWUsIHVuaXRzKSANCg0KaGVhZChkYXRhX2NvbW11bml0eSlbLCAxOjVdDQpgYGANCg0KYGBge3J9DQojfCBsYWJlbDogZGlzcGxheSBjb21tdW5pdHkgdGFibGUNCiN8IGVjaG86IEZBTFNFDQojfCByZXN1bHRzOiAnYXNpcycNCnBhbmRlcjo6cGFuZG9jLnRhYmxlKGhlYWQoZGF0YV9jb21tdW5pdHkpWywgMTo1XSkNCmBgYA0KDQpIZXJlLCB3ZSBzdHJvbmdseSBhZHZvY2F0ZSB0aGF0IGNhcmVmdWwgcHJlcGFyYXRpb24gb2YgdGhlIGRhdGFzZXRzICh3aXRoIGFkZGl0aW9uYWwgc3RlcHMpIG1heSBiZSBuZWVkZWQgYmVmb3JlIHVzaW5nIFItUmF0ZXBvbCENCg0KIyMgUHJlcGFyYXRpb24gb2YgdGhlIGxldmVscw0KDQojIyMgU2FtcGxlIGRlcHRoDQoNCkV4dHJhY3QgZGVwdGggZm9yIGVhY2ggbGV2ZWwNCg0KYGBge3J9DQojfCBsYWJlbDogbGV2ZWwgcHJlcGFyYXRpb24NCmRhdGFfbGV2ZWxzIDwtDQogIG5lb3RvbWEyOjpzYW1wbGVzKHNlbF9kYXRhc2V0X2Rvd25sb2FkKSAlPiUNCiAgdGliYmxlOjphc190aWJibGUoKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzYW1wbGVfaWQgPSBhcy5jaGFyYWN0ZXIoc2FtcGxlaWQpKSAlPiUNCiAgZHBseXI6OmRpc3RpbmN0KHNhbXBsZV9pZCwgZGVwdGgpICU+JQ0KICBkcGx5cjo6cmVsb2NhdGUoc2FtcGxlX2lkKQ0KDQpoZWFkKGRhdGFfbGV2ZWxzKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IGRpc3BsYXkgbGV2ZWwNCiN8IGVjaG86IEZBTFNFDQojfCByZXN1bHRzOiAnYXNpcycNCnBhbmRlcjo6cGFuZG9jLnRhYmxlKGhlYWQoZGF0YV9sZXZlbHMpKQ0KYGBgDQoNCiMjIyBBZ2UtZGVwdGggbW9kZWxsaW5nDQoNCldlIHdpbGwgcmVjYWxjdWxhdGUgdGhlIGFnZS1kZXB0aCBtb2RlbCAnZGUgbm92bycgdXNpbmcgdGhlIFsqQmNocm9uKiBwYWNrYWdlXShodHRwOi8vYW5kcmV3Y3Bhcm5lbGwuZ2l0aHViLmlvL0JjaHJvbi8pLiANCg0KIyMjIyBQcmVwYXJlIGNocm9uLmNvbnRyb2wgdGFibGUgYW5kIHJ1biBCY2hyb24NClRoZSBjaHJvbm9sb2d5IGNvbnRyb2wgdGFibGUgY29udGFpbnMgYWxsIHRoZSBkYXRlcyAobW9zdGx5IHJhZGlvY2FyYm9uKSB0byBjcmVhdGUgdGhlIGFnZS1kZXB0aCBtb2RlbC4NCg0KSGVyZSB3ZSBvbmx5IHByZXNlbnQgYSBmZXcgb2YgdGhlIGltcG9ydGFudCBzdGVwcyBvZiBwcmVwYXJhdGlvbiBvZiB0aGUgY2hyb25vbG9neSBjb250cm9sIHRhYmxlLiBUaGVyZSBhcmUgbWFueSBtb3JlIHBvdGVudGlhbCBpc3N1ZXMsIGJ1dCBzb2x2aW5nIHRob3NlIGlzIG5vdCB0aGUgZm9jdXMgb2YgdGhpcyB3b3JrZmxvdy4NCg0KYGBge3J9DQojfCBsYWJlbDogZ2V0IGNocm9ub2xvZ3kgdGFibGVzDQojIEZpcnN0LCBnZXQgdGhlIGNocm9ub2xvZ2llcyBhbmQgY2hlY2sgd2hpY2ggd2Ugd2FudCB0byB1c2UgdXNlZA0Kc2VsX2Nocm9uX2NvbnRyb2xfdGFibGVfZG93bmxvYWQgPC0NCiAgbmVvdG9tYTI6OmNocm9uY29udHJvbHMoc2VsX2RhdGFzZXRfZG93bmxvYWQpDQoNCnByaW50KHNlbF9jaHJvbl9jb250cm9sX3RhYmxlX2Rvd25sb2FkKQ0KYGBgDQpgYGB7cn0NCiN8IGxhYmVsOiBkaXNwbGF5IGNocm9uIGNvbnRyb2wgdGFibGVzDQojfCBlY2hvOiBGQUxTRQ0KI3wgcmVzdWx0czogJ2FzaXMnDQpwYW5kZXI6OnBhbmRvYy50YWJsZShoZWFkKHNlbF9jaHJvbl9jb250cm9sX3RhYmxlX2Rvd25sb2FkKSkNCmBgYA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBwcmVwYXJlY2hyb24gY29udHJvbCB0YWJsZQ0KIyBwcmVwYXJlIHRoZSB0YWJsZQ0KZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlIDwtDQogIHNlbF9jaHJvbl9jb250cm9sX3RhYmxlX2Rvd25sb2FkICU+JQ0KICAjIEhlcmUgc2VsZWN0IHRoZSBJRCBvZiBvbmUgb2YgdGhlIGNocm9ub2xvZ3kNCiAgZHBseXI6OmZpbHRlcihjaHJvbm9sb2d5aWQgPT0gMzM2ODIpICU+JQ0KICB0aWJibGU6OmFzX3RpYmJsZSgpICU+JQ0KICAjIEhlcmUgd2UgY2FsY3VsYXRlIHRoZSBlcnJvciBhcyB0aGUgYXZlcmFnZSBvZiB0aGUgYWdlIGBsaW1pdG9sZGVyYCBhbmQNCiAgIyAgIGBhZ2VsaW1pdHlvdW5nZXJgDQogIGRwbHlyOjptdXRhdGUoDQogICAgZXJyb3IgPSByb3VuZCgoYWdlbGltaXRvbGRlciAtIGFnZWxpbWl0eW91bmdlcikgLyAyKQ0KICApICU+JQ0KICAjIEFzIEJjaHJvbiBjYW5ub3QgYWNjZXB0IGEgZXJyb3Igb2YgMCwgd2UgbmVlZCB0byByZXBsYWNlIHRoZSB2YWx1ZSB3aXRoIDENCiAgZHBseXI6Om11dGF0ZSgNCiAgICBlcnJvciA9IHJlcGxhY2UoZXJyb3IsIGVycm9yID09IDAsIDEpLA0KICAgIGVycm9yID0gaWZlbHNlKGlzLm5hKGVycm9yKSwgMSwgZXJyb3IpLA0KICAgIHRoaWNrbmVzcyA9IGlmZWxzZShpcy5uYSh0aGlja25lc3MpLCAxLCB0aGlja25lc3MpDQogICkgJT4lDQogICMgV2UgbmVlZCB0byBzcGVjaWZ5IHdoaWNoIGNhbGlicmF0aW9uIGN1cnZlIHNob3VsZCBiZSB1c2VkIGZvciB3aGF0IHBvaW50DQogIGRwbHlyOjptdXRhdGUoDQogICAgY3VydmUgPSBpZmVsc2UoYXMuZGF0YS5mcmFtZShzZWxfZGF0YXNldF9kb3dubG9hZClbImxhdCJdID4gMCwgImludGNhbDIwIiwgInNoY2FsMjAiKSwNCiAgICBjdXJ2ZSA9IGlmZWxzZShjaHJvbmNvbnRyb2x0eXBlICE9ICJSYWRpb2NhcmJvbiIsICJub3JtYWwiLCBjdXJ2ZSkNCiAgKSAlPiUNCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoImNocm9uY29udHJvbGlkIikgJT4lDQogIGRwbHlyOjphcnJhbmdlKGRlcHRoKSAlPiUNCiAgZHBseXI6OnNlbGVjdCgNCiAgICBjaHJvbmNvbnRyb2xhZ2UsIGVycm9yLCBkZXB0aCwgdGhpY2tuZXNzLCBjaHJvbmNvbnRyb2x0eXBlLCBjdXJ2ZQ0KICApDQoNCmhlYWQoZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IGRpc3BsYXkgcHJlcGFyZWQgY2hyb24gY29udHJvbCB0YWJsZQ0KI3wgZWNobzogRkFMU0UNCiN8IHJlc3VsdHM6ICdhc2lzJw0KcGFuZGVyOjpwYW5kb2MudGFibGUoaGVhZChkYXRhX2Nocm9uX2NvbnRyb2xfdGFibGUpKQ0KYGBgDQoNCkFzIHRoaXMgaXMganVzdCBhIHRveSBleGFtcGxlLCB3ZSB3aWxsIHVzZSBvbmx5IHRoZSBpdGVyYXRpb24gbXVsdGlwbGllciAoYGlfbXVsdGlwbGllcmApIG9mIGAwLjFgIHRvIHJlZHVjZSB0aGUgY29tcHV0YXRpb24gdGltZS4gSG93ZXZlciwgd2Ugc3Ryb25nbHkgcmVjb21tZW5kIGluY3JlYXNpbmcgaXQgdG8gNSBmb3IgYW55IG5vcm1hbCBhZ2UtZGVwdGggbW9kZWwgY29uc3RydWN0aW9uLg0KYGBge3J9DQojfCBsYWJlbDogcnVuIEJjaHJvbg0KaV9tdWx0aXBsaWVyIDwtIDAuMSAjIGluY3JlYXNlIHRvIDUNCg0KIyBUaG9zZSBhcmUgZGVmYXVsdCB2YWx1ZXMgc3VnZ2VzdGVkIGJ5IHRoZSBCY2hyb24gcGFja2FnZQ0Kbl9pdGVyYXRpb25fZGVmYXVsdCA8LSAxMGUzDQpuX2J1cm5fZGVmYXVsdCA8LSAyZTMNCm5fdGhpbl9kZWZhdWx0IDwtIDgNCg0KIyBMZXQncyBtdWx0aXBseSB0aGVtIGJ5IG91ciBpX211bHRpcGxpZXINCm5faXRlcmF0aW9uIDwtIG5faXRlcmF0aW9uX2RlZmF1bHQgKiBpX211bHRpcGxpZXINCm5fYnVybiA8LSBuX2J1cm5fZGVmYXVsdCAqIGlfbXVsdGlwbGllcg0Kbl90aGluIDwtIG1heChjKDEsIG5fdGhpbl9kZWZhdWx0ICogaV9tdWx0aXBsaWVyKSkNCg0KIyBydW4gQmNocm9uDQpzZWxfYmNocm9uIDwtDQogIEJjaHJvbjo6QmNocm9ub2xvZ3koDQogICAgYWdlcyA9IGRhdGFfY2hyb25fY29udHJvbF90YWJsZSRjaHJvbmNvbnRyb2xhZ2UsDQogICAgYWdlU2RzID0gZGF0YV9jaHJvbl9jb250cm9sX3RhYmxlJGVycm9yLA0KICAgIHBvc2l0aW9ucyA9IGRhdGFfY2hyb25fY29udHJvbF90YWJsZSRkZXB0aCwNCiAgICBjYWxDdXJ2ZXMgPSBkYXRhX2Nocm9uX2NvbnRyb2xfdGFibGUkY3VydmUsDQogICAgcG9zaXRpb25UaGlja25lc3NlcyA9IGRhdGFfY2hyb25fY29udHJvbF90YWJsZSR0aGlja25lc3MsDQogICAgaXRlcmF0aW9ucyA9IG5faXRlcmF0aW9uLA0KICAgIGJ1cm4gPSBuX2J1cm4sDQogICAgdGhpbiA9IG5fdGhpbg0KICApDQpgYGANCg0KVmlzdWFsbHkgY2hlY2sgdGhlIGFnZS1kZXB0aCBtb2RlbHMNCg0KYGBge3J9DQojfCBsYWJlbDogcGxvdCBCY2hyb24NCkJjaHJvbjo6OnBsb3QuQmNocm9ub2xvZ3lSdW4oc2VsX2JjaHJvbikgKyAjIG9yIGp1c3Qgc2ltcGxlIHBsb3Qoc2VsX2JjaHJvbikNCiAgZ2dwbG90Mjo6dGhlbWVfYncoKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDI1KSwNCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICBzdHJpcC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgcGFuZWwuZ3JpZCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKQ0KICApICsNCiAgZ2dwbG90Mjo6bGFicygNCiAgICB4ID0gImFnZSAoY2FsIHlyIEJQKSIsDQogICAgeSA9ICJkZXB0aCINCiAgKQ0KYGBgDQoNCiMjIyMgUHJlZGljdCBhZ2VzDQoNCkxldCdzIGZpcnN0IGV4dHJhY3QgcG9zdGVyaW9yIGFnZXMgKGkuZS4gcG9zc2libGUgYWdlcykgZnJvbSB0aGUgYWdlLWRlcHRoIG1vZGVsLiAgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHByZWRpY3QgYWdlcw0KYWdlX3Bvc2l0aW9uIDwtDQogIEJjaHJvbjo6OnByZWRpY3QuQmNocm9ub2xvZ3lSdW4oICMgb3IganVzdCBzaW1wbGUgcHJlZGljdChzZWxfYmNocm9uKQ0KICAgIG9iamVjdCA9IHNlbF9iY2hyb24sDQogICAgbmV3UG9zaXRpb25zID0gZGF0YV9sZXZlbHMkZGVwdGgNCiAgKQ0KDQphZ2VfdW5jZXJ0YWludGllcyA8LQ0KICBhZ2VfcG9zaXRpb24gJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgZHBseXI6Om11dGF0ZV9hbGwoLiwgYXMuaW50ZWdlcikgJT4lDQogIGFzLm1hdHJpeCgpDQoNCmNvbG5hbWVzKGFnZV91bmNlcnRhaW50aWVzKSA8LSBkYXRhX2xldmVscyRzYW1wbGVfaWQNCmBgYA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBnZXQgbWVkaWFuIGFnZQ0KZGF0YV9sZXZlbHNfcHJlZGljdGVkIDwtDQogIGRhdGFfbGV2ZWxzICU+JQ0KICBkcGx5cjo6bXV0YXRlKA0KICAgIGFnZSA9IGFwcGx5KA0KICAgICAgYWdlX3VuY2VydGFpbnRpZXMsIDIsDQogICAgICBzdGF0czo6cXVhbnRpbGUsDQogICAgICBwcm9icyA9IDAuNQ0KICAgICkNCiAgKQ0KDQpoZWFkKGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCkNCmBgYA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBkaXNwbGF5IG1lZGlhbiBhZ2UNCiN8IGVjaG86IEZBTFNFDQojfCByZXN1bHRzOiAnYXNpcycNCnBhbmRlcjo6cGFuZG9jLnRhYmxlKGhlYWQoZGF0YV9sZXZlbHNfcHJlZGljdGVkKSkNCmBgYA0KDQojIyMgVmlzdWFsaXNhdGlvbiBvZiBvdXIgZGF0YQ0KDQpMZXQncyBub3cgbWFrZSBhIHNpbXBsZSBkaWFncmFtIHdpdGggcHJvcG9ydGlvbnMgb2YgdGhlIGNvbmNlbnRyYXRpb25zICh4LWF4aXMpIGFnYWluc3Qgb3VyIGVzdGltYXRlZCBhZ2VzIGFsb25nIHRoZSBkZXB0aCAoeS1heGlzKS4NCg0KYGBge3J9DQojfCBsYWJlbDogcGxvdCBkYXRhIHdpdGggYWdlcw0KZGF0YV9jb21tdW5pdHkgJT4lDQogIGRwbHlyOjppbm5lcl9qb2luKA0KICAgIGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBieSA9IGRwbHlyOjpqb2luX2J5KHNhbXBsZV9pZCkNCiAgKSAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gLWMoc2FtcGxlX2lkLCBkZXB0aCwgYWdlKSwNCiAgICBuYW1lc190byA9ICJlbGVtZW50IiwNCiAgICB2YWx1ZXNfdG8gPSAidmFsdWUiDQogICkgJT4lDQogIGdncGxvdDI6OmdncGxvdCgNCiAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKA0KICAgICAgeCA9IGFnZSwNCiAgICAgIHkgPSB2YWx1ZSwNCiAgICAgIGNvbCA9IGVsZW1lbnQNCiAgICApLA0KICApICsNCiAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCgNCiAgICB+ZWxlbWVudCwNCiAgICBucm93ID0gMSwNCiAgICBzY2FsZXMgPSAiZnJlZV94Ig0KICApICsNCiAgZ2dwbG90Mjo6Y29vcmRfZmxpcCgpICsNCiAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gInJldmVyc2UiKSArDQogIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIDUwLCAxMDApKSArDQogIGdncGxvdDI6OnRoZW1lKA0KICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBnZ3Bsb3QyOjplbGVtZW50X2xpbmUoDQogICAgICBjb2xvdXIgPSAiZ3JleSIsDQogICAgICBsaW5ld2lkdGggPSAwLjENCiAgICApLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBwYW5lbC5ib3JkZXIgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICBzdHJpcC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGlja3MueCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRleHQueCA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKQ0KICApICsNCiAgZ2dwbG90Mjo6bGFicygNCiAgICB4ID0gImFnZSAoY2FsIHlyIEJQKSIsDQogICAgeSA9ICJQZXJjZW50YWdlIg0KICApICsNCiAgZ2dwbG90Mjo6Z2VvbV9saW5lKCkNCmBgYA0KDQoNCiMjIEVzdGltYXRpb24gUmF0ZS1vZi1DaGFuZ2UNCg0KTm93IHdlIHdpbGwgdXNlIG91ciBwcmVwYXJlZCBYUkYgZGF0YSBhbmQgYWdlLWRlcHRoIG1vZGVsIHRvIGVzdGltYXRlIHRoZSByYXRlIG9mIGNoYW5nZS4NCldlIHdpbGwgcHJlc2VudCBzZXZlcmFsIHNjZW5hcmlvcyAoaS5lLiBhcHByb2FjaGVzKSB0byBjYWxjdWxhdGUgUm9DLiANCg0KIyMjIFNlbGVjdGlvbiBvZiBkaXNzaW1pbGFyaXR5IGNvZWZmaWNpZW50IA0KDQpXZSBjYW4gY2hlY2sgdGhlIHVuaXRzIG9mIGluZGl2aWR1YWwgbWVhc3VyZWQgdmFsdWVzOg0KYGBge3J9DQojfCBsYWJlbDogZGF0YSB1bml0cw0KZGF0YV91bml0cyAlPiUNCiAgZHBseXI6OnB1bGwoInVuaXRzIikgJT4lDQogIHRhYmxlKCkNCmBgYA0KDQpgYGB7cn0NCiN8IGxhYmVsOiBkaXNwbGF5IGRhdGEgdW5pdHMNCiN8IGVjaG86IEZBTFNFDQojfCByZXN1bHRzOiAnYXNpcycNCmRhdGFfdW5pdHMgJT4lDQogIGRwbHlyOjpwdWxsKCJ1bml0cyIpICU+JQ0KICB0YWJsZSgpICU+JQ0KICBwYW5kZXI6OnBhbmRvYy50YWJsZSgpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSwgYWxsIG1lYXN1cmVkIHZhbHVlcyBhcmUgaW4gcGVyY2VudGFnZSB1bml0cy4gVGhlcmVmb3JlLCBmb3IgYWxsIHNjZW5hcmlvcywgd2Ugd2lsbCBiZSB1c2luZyB0aGUgYGNoaXNxYCBkaXNzaW1pbGFyaXR5IGNvZWZmaWNpZW50ICh3b3JrcyB3aXRoIGNsb3NlZCBkYXRhKSwgYW5kIGB0aW1lX3N0YW5kYXJkaXNhdGlvbmAgPT0gNTAwICh0aGlzIG1lYW5zIHRoYXQgYWxsIFJPQyB2YWx1ZXMgYXJlICdjaGFuZ2UgcGVyIDUwMCB5cicpLg0KDQojIyMgU2NlbmFyaW8gMSAtIEVzdGltYXRpbmcgUm9DIGZvciBlYWNoIGxldmVsDQoNClRoaXMgaXMgdGhlICJDbGFzc2ljIiBhcHByb2FjaCB0aGF0IHVzZXMgZWFjaCBzYW1wbGVkIGRlcHRoIGluIGEgcmVjb3JkIChpLmUuIGluZGl2aWR1YWwgbGV2ZWwpIHRvIGVzdGltYXRlIFJvQy4NCg0KYGBge3J9DQojfCBsYWJlbDogc2NlbmFyaW8gMQ0Kc2NlbmFyaW9fMSA8LQ0KICBSUmF0ZXBvbDo6ZXN0aW1hdGVfcm9jKA0KICAgIGRhdGFfc291cmNlX2NvbW11bml0eSA9IGRhdGFfY29tbXVuaXR5LA0KICAgIGRhdGFfc291cmNlX2FnZSA9IGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBkaXNzaW1pbGFyaXR5X2NvZWZmaWNpZW50ID0gImNoaXNxIiwNCiAgICB0aW1lX3N0YW5kYXJkaXNhdGlvbiA9IDUwMCwNCiAgICB3b3JraW5nX3VuaXRzID0gImxldmVscyIgIyBoZXJlIGlzIHNldCB0byB1c2UgaW5kaXZpZHVhbCBsZXZlbHMNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gMQ0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fMSkNCmBgYA0KDQojIyMgU2NlbmFyaW8gMiAtIEVzdGltYXRpbmcgUm9DIGZvciBlYWNoIGxldmVsIHdpdGggc21vb3RoaW5nIG9mIGRhdGENCg0KV2UgZG8gdGhlIHNhbWUgYXMgaW4gU2NlbmFyaW8gMSBidXQgbm93IHdlIHNtb290aCB0aGUgY29tbXVuaXR5IGRhdGEgYmVmb3JlIGNhbGN1bGF0aW5nIFJvQy4gVGhpcyBtYXkgYmUgdXNlZnVsIHRvIG1pdGlnYXRlIHRoZSBlcnJvciBvZiBtZWFzdXJlbWVudC4gU3BlY2lmaWNhbGx5LCB3ZSB3aWxsIGFkZCBgc21vb3RoX21ldGhvZGAgPSAic2hlcCIgKGkuZS4gU2hlcGFyZCdzIDUtdGVybSBmaWx0ZXIpLg0KDQpgYGB7cn0NCiN8IGxhYmVsOiBzY2VuYXJpbyAyDQpzY2VuYXJpb18yIDwtDQogIFJSYXRlcG9sOjplc3RpbWF0ZV9yb2MoDQogICAgZGF0YV9zb3VyY2VfY29tbXVuaXR5ID0gZGF0YV9jb21tdW5pdHksDQogICAgZGF0YV9zb3VyY2VfYWdlID0gZGF0YV9sZXZlbHNfcHJlZGljdGVkLA0KICAgIGRpc3NpbWlsYXJpdHlfY29lZmZpY2llbnQgPSAiY2hpc3EiLA0KICAgIHRpbWVfc3RhbmRhcmRpc2F0aW9uID0gNTAwLA0KICAgIHdvcmtpbmdfdW5pdHMgPSAibGV2ZWxzIiwNCiAgICBzbW9vdGhfbWV0aG9kID0gInNoZXAiICMgU2hlcGFyZCdzIDUtdGVybSBmaWx0ZXINCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gMg0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fMikNCmBgYA0KDQpXZSBzZWUgdGhhdCB0aGUgYWJzb2x1dGUgUm9DIHNjb3JlcyBhcmUgZGVjcmVhc2VkIGFuZCB0aGUgcGF0dGVybiBjaGFuZ2VkIHNsaWdodGx5ICh4LWF4aXMpLiANCg0KIyMjIFNjZW5hcmlvIDMgLSBVc2luZyB1bmNlcnRhaW50eSBtYXRyaXgNCg0KRm9yIFJvQyBhbmFseXNpcywgaXQgaXMgaW1wb3J0YW50IHRvIGNvbnNpZGVyIGFnZSB1bmNlcnRhaW50aWVzLiBGb3IgZWFjaCBpdGVyYXRpb24sIFJSYXRlcG9sIHdpbGwgcmFuZG9tbHkgc2VsZWN0IG9uZSBhZ2Utc2VxdWVuY2UgZnJvbSB0aGUgdW5jZXJ0YWludHkgbWF0cml4IChzZWUgdGhlIGFnZS1kZXB0aCBtb2RlbGluZyBzZWN0aW9uIGZvciBtb3JlIGluZm8pLiANCg0KQmVjYXVzZSBvZiB0aGF0LCB3ZSBuZWVkIHRvIGluY3JlYXNlIHRoZSBudW1iZXIgb2YgcmFuZG9taXphdGlvbnMuIFRoaXMgaXMgYWdhaW4gYSB0b3kgZXhhbXBsZSBmb3IgYSBxdWljayBjb21wdXRhdGlvbiBhbmQgdGhlcmVmb3JlIHdlIG9ubHkgZG8gMTAwIHJhbmRvbWl6YXRpb25zLiBXZSB3b3VsZCByZWNvbW1lbmQgaW5jcmVhc2luZyB0aGUgKnNldF9yYW5kb21pc2F0aW9ucyogdG8gMTAuMDAwIGZvciBhbnkgcmVhbCBlc3RpbWF0aW9uLiANCg0KYGBge3J9DQojfCBsYWJlbDogc2V0IHJhbmRvbWlzYXRpb25zDQpzZXRfcmFuZG9taXNhdGlvbnMgPC0gMTAwDQpgYGANCg0KVG8gc3BlZWQgdGhlIHByb2Nlc3MgdXAsIHlvdSBjYW4gYWxzbyBzZXQgYHVzZV9wYXJhbGxlbGAgPT0gYFRSVUVgLCB3aGljaCB3aWxsIHVzZSBhbGwgY29yZXMgb2YgeW91ciBjb21wdXRlci4NCg0KYGBge3J9DQojfCBsYWJlbDogc2NlbmFyaW8gMw0Kc2NlbmFyaW9fMyA8LQ0KICBSUmF0ZXBvbDo6ZXN0aW1hdGVfcm9jKA0KICBkYXRhX3NvdXJjZV9jb21tdW5pdHkgPSBkYXRhX2NvbW11bml0eSwNCiAgICBkYXRhX3NvdXJjZV9hZ2UgPSBkYXRhX2xldmVsc19wcmVkaWN0ZWQsDQogICAgZGlzc2ltaWxhcml0eV9jb2VmZmljaWVudCA9ICJjaGlzcSIsDQogICAgdGltZV9zdGFuZGFyZGlzYXRpb24gPSA1MDAsDQogICAgc21vb3RoX21ldGhvZCA9ICJzaGVwIiwNCiAgICBhZ2VfdW5jZXJ0YWludHkgPSBhZ2VfdW5jZXJ0YWludGllcywgIyBBZGQgdGhlIHVuY2VydGFpbnR5IG1hdHJpeA0KICAgIHJhbmQgPSBzZXRfcmFuZG9taXNhdGlvbnMsICAjIHNldCBudW1iZXIgb2YgcmFuZG9taXNhdGlvbnMNCiAgICB1c2VfcGFyYWxsZWwgPSBUUlVFICMgZG8gdXNlIHBhcmFsbGVsIGNvbXB1dGluZw0KICApDQpgYGAgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gMw0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fMykNCmBgYA0KDQpXZSB3aWxsIG5vdyBhbHNvIHZpc3VhbGl6ZSB1bmNlcnRhaW50eSBhcm91bmQgdGhlIFJvQyBzY29yZXMgc2hvd24gYnkgYSBncmV5IHNoYWRvdy4gV2Ugc2VlIGEgc3Vic3RhbnRpYWwgaW5jcmVhc2UgaW4gUm9DIHZhbHVlIGluIGNlcnRhaW4gcmVnaW9ucywgdGhpcyBpcyBjYXVzZWQgYnkgdGhlIGV4dHJlbWVseSBzbWFsbCBudW1iZXJzIG9mIGFnZSBkaWZmZXJlbmNlcyBhbmQgdGhlIGxvdyBudW1iZXIgb2YgcmFuZG9taXphdGlvbnMuDQoNCiMjIyBTY2VuYXJpbyA0IC0gRXN0aW1hdGluZyBSb0MgcGVyIGJpbg0KDQpJbiBvcmRlciB0byBnZXQgcmlkIG9mIHRoZSBlZmZlY3Qgb2YgdW5ldmVuIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGVkIGRlcHRocyAoaS5lLiBsZXZlbHMpIGluIGEgcmVjb3JkLCB3ZSBjYW4gYmluIHRoZSBkYXRhLg0KDQpTcGVjaWZpY2FsbHksIHdlIHdpbGwgY2hhbmdlIHRoZSBgd29ya2luZ191bml0c2AgZnJvbSBzaW5nbGUgbGV2ZWxzIHRvIGAiYmlucyJgLiBIZXJlIHdlIHNlbGVjdCBiaW5zIG9mIDUwMCB5ZWFycyBlYWNoIGluc3RlYWQgb2YgdGhlIGluZGl2aWR1YWwgbGV2ZWxzLiANCg0KTm90ZSB0aGF0IG9uZSBsZXZlbCBpcyByYW5kb21seSBzZWxlY3RlZCBhcyBhIHJlcHJlc2VudGF0aW9uIG9mIHRoYXQgdGltZSBiaW4uIFRoZXJlZm9yZSwgaXQgaXMgaW1wb3J0YW50IHRvIGluY3JlYXNlIHRoZSBudW1iZXIgb2YgcmFuZG9taXphdGlvbnMuIA0KYGBge3J9DQojfCBsYWJlbDogc2NlbmFyaW8gNA0Kc2NlbmFyaW9fNCA8LQ0KICBSUmF0ZXBvbDo6ZXN0aW1hdGVfcm9jKA0KICAgIGRhdGFfc291cmNlX2NvbW11bml0eSA9IGRhdGFfY29tbXVuaXR5LA0KICAgIGRhdGFfc291cmNlX2FnZSA9IGRhdGFfbGV2ZWxzX3ByZWRpY3RlZCwNCiAgICBkaXNzaW1pbGFyaXR5X2NvZWZmaWNpZW50ID0gImNoaXNxIiwNCiAgICB3b3JraW5nX3VuaXRzID0gImJpbnMiLCAjIGNoYW5nZSB0aGUgImJpbnMiDQogICAgYmluX3NpemUgPSA1MDAsICMgc2l6ZSBvZiBhIHRpbWUgYmluDQogICAgdGltZV9zdGFuZGFyZGlzYXRpb24gPSA1MDAsDQogICAgc21vb3RoX21ldGhvZCA9ICJzaGVwIiwNCiAgICBhZ2VfdW5jZXJ0YWludHkgPSBhZ2VfdW5jZXJ0YWludGllcywNCiAgICByYW5kID0gc2V0X3JhbmRvbWlzYXRpb25zLCANCiAgICB1c2VfcGFyYWxsZWwgPSBUUlVFIA0KICApDQpgYGANCg0KYGBge3J9DQojfCBsYWJlbDogcGxvdCBzY2VuYXJpbyA0DQpSUmF0ZXBvbDo6cGxvdF9yb2MoZGF0YV9zb3VyY2UgPSBzY2VuYXJpb180KQ0KYGBgDQoNCkhlcmUgd2UgY2FuIHNlZSBhIGRyYXN0aWMgY2hhbmdlIGluIHRoZSBzaGFwZSBvZiBSb0MgYnV0IGEgbGFyZ2UgbG9zcyBvZiB0ZW1wb3JhbCBwcmVjaXNpb24uDQoNCiMjIyBTY2VuYXJpbyA1IC0gRXN0aW1hdGluZyBSb0Mgd2l0aCB0aGUgbmV3ICJNb3Zpbmctd2luZG93IiBhcHByb2FjaA0KDQpJbiBvcmRlciB0byByZWR1Y2UgdGhlIHRlbXBvcmFsIHVuY2VydGFpbnR5IGFuZCBpbXByb3ZlIHRlbXBvcmFsIHByZWNpc2lvbiwgd2UgY2FuIGFwcGx5IGEgbm92ZWwgYXBwcm9hY2ggaW4gUlJBVEVQT0wgY2FsbGVkICJtb3Zpbmcgd2luZG93Ii4gDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHNjZW5hcmlvIDUNCnNjZW5hcmlvXzUgPC0NCiAgUlJhdGVwb2w6OmVzdGltYXRlX3JvYygNCiAgICBkYXRhX3NvdXJjZV9jb21tdW5pdHkgPSBkYXRhX2NvbW11bml0eSwNCiAgICBkYXRhX3NvdXJjZV9hZ2UgPSBkYXRhX2xldmVsc19wcmVkaWN0ZWQsDQogICAgZGlzc2ltaWxhcml0eV9jb2VmZmljaWVudCA9ICJjaGlzcSIsDQogICAgd29ya2luZ191bml0cyA9ICJNVyIsICMgY2hhbmdlIHRoZSAiTVciIHRvIGFwcGx5IHRoZSAibW92aW5nIHdpbmRvdyINCiAgICBiaW5fc2l6ZSA9IDUwMCwNCiAgICBudW1iZXJfb2Zfc2hpZnRzID0gNSwgIyBudW1iZXIgb2Ygc2hpZnRzDQogICAgdGltZV9zdGFuZGFyZGlzYXRpb24gPSA1MDAsDQogICAgc21vb3RoX21ldGhvZCA9ICJzaGVwIiwNCiAgICByYW5kID0gc2V0X3JhbmRvbWlzYXRpb25zLA0KICAgIHVzZV9wYXJhbGxlbCA9IFRSVUUsDQogICAgYWdlX3VuY2VydGFpbnR5ID0gYWdlX3VuY2VydGFpbnRpZXMNCiAgKQ0KYGBgDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBsb3Qgc2NlbmFyaW8gNQ0KUlJhdGVwb2w6OnBsb3Rfcm9jKGRhdGFfc291cmNlID0gc2NlbmFyaW9fNSkNCmBgYA0KDQojIyMgU2NlbmFyaW8gNiAtIERldGVjdGluZyBwZWFrIHBvaW50cw0KDQpUaHJvdWdob3V0IHRoZSByZWNvcmQsIHRoZXJlIGNhbiBiZSBwZXJpb2RzIHdoZW4gdGhlIFJvQyB3aWxsIHN1YnN0YW50aWFsbHkgY2hhbmdlLiBXZSBjYW4gZGV0ZWN0IFJvQyBpbmNyZWFzZXMgdGhhdCBhcmUgc2lnbmlmaWNhbnQgYnkgaWRlbnRpZnlpbmcgc28tY2FsbGVkICpwZWFrLXBvaW50cyouIEhlcmUsIHdlIHdpbGwgdXNlIHRoZSAiTm9uLWxpbmVhciIgbWV0aG9kLCB3aGljaCB3aWxsIGRldGVjdCBhIHNpZ25pZmljYW50IGNoYW5nZSBmcm9tIGEgbm9uLWxpbmVhciB0cmVuZCBvZiBSb0MuDQoNCmBgYHtyfQ0KI3wgbGFiZWw6IHBlYWtfcG9pbnRzIA0Kc2NlbmFyaW9fNV9wZWFrIDwtDQogIFJSYXRlcG9sOjpkZXRlY3RfcGVha19wb2ludHMoDQogICAgZGF0YV9zb3VyY2UgPSBzY2VuYXJpb181LA0KICAgIHNlbF9tZXRob2QgPSAidHJlbmRfbm9uX2xpbmVhciINCiAgKQ0KYGBgDQoNCk5vdyB3ZSB3aWxsIHBsb3QgdGhlIFJvQyBlc3RpbWF0ZXMgc2hvd2luZyB0aGUgcGVhayBwb2ludHMuIFNvIGhlcmUgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIHdlcmUgcmF0ZXMgb2YgdmVnZXRhdGlvbiBjaGFuZ2UgdGhyb3VnaG91dCB0aGUgcmVjb3JkIGJ1dCBvbmx5IGF0IGNlcnRhaW4gbW9tZW50cyBpbiB0aW1lIChncmVlbiBkb3RzIC0gcGVhayBwb2ludHMpIHRoZXNlIGNoYW5nZXMgd2VyZSBzaWduaWZpY2FudC4gVGhlcmUgeW91IGdvIQ0KDQpgYGB7cn0NCiN8IGxhYmVsOiBwbG90IHBlYWsgcG9pbnRzDQpSUmF0ZXBvbDo6cGxvdF9yb2MoDQogIGRhdGFfc291cmNlID0gc2NlbmFyaW9fNV9wZWFrLA0KICBwZWFrcyA9IFRSVUUNCikNCmBgYA==