Here are answers regarding all the questions asked in the
tutorial.
Loading the data (Q1-Q6)
Summarizing the data
- Q1: How many plots were sampled?
nrow(plot_data)
Answer: There are 180 sampled plots.
- Q2: How many species are there in the dataset?
nrow(species_traits)
Answer: There are 691 species in the dataset.
- Q3: How many traits are available?
head(species_traits, 2)
Answer: There are 13 traits in the dataset.
- Q4: How many of them are continuous? How many of
them are discrete?
Answer: Looking at the trait table there 3
continuous traits (height
, sla
, and
wood.dens
) and 10 that are discrete. (Referring to the
README file we see that the seed
column contains indeed a
categorical trait).
- Q5: What is the most numerous family among all
observed species?
summary(species_traits)
Answer: The summary()
function displays
the number of observations in each categories ordered by the most
abundant category. The family
column shows that the
“Leguminosae” (a.k.a, Fabaceae) is the most numerous in the dataset.
- Q6: What is the most numerous genus?
Answer: Similarly the most numerous genus is
“Unknown”, which corresponds to individual that weren’t identified at
the genus level.
Functional diversity (Q7-Q19)
Computing Biomass-weighted mean traits per plot
(Q7-Q10)
- Q7: How would you describe the relationship between
the different CWMs and forest loss?
Answer: We’re eye-balling the relationships but it
seems that:
The CWM-Height seems to decrease with forest loss.
The CWM-SLA seems to increase with forest loss.
There seem to be no relationship between the CWM-wood density and
forest loss.
Q8: Can you test the correlation using the
function cor.test()
and does it support your previous
statements?
cor.test(cwm_env$forestloss17, cwm_env$height)
cor.test(cwm_env$forestloss17, cwm_env$sla)
cor.test(cwm_env$forestloss17, cwm_env$wood.dens)
Answer:
We observe a negative correlation (-0.48) between CWM-Height and
forest loss.
We observe a positive correlation (0.48) between CWM-SLA and
forest loss.
We observe a slight negative correlation (-0.24) between CWM-wood
density and forest loss.
Q9: How would you describe the understorey
vegetation changes with increasing forest loss?
Answer: The CWM values reflect the dominant trait of
the community. This means that with forest loss we observe smaller
species, species with higher SLA, and species with lower wood density.
Linking back to ecology, this is probably due to a change in understorey
vegetation type from woody species in unlogged area to more herbaceous
species in heavily logged area.
- Q10: How does this observation compare to above
description of the change of understorey vegetation along the forest
loss gradient?
cor.test(non_quanti_cwm$forestloss17, non_quanti_cwm$woody_no)
Answer: The woody_no
CWM represents the
proportion of non-woody species in the community. We observe a positive
medium correlation between this CWM and forest loss which tells us that
non-woody species are more frequent in understorey vegetation with
increasing forest loss.
Building the functional space
(Q11-Q12)
- Q11: Using the metadata available in the
README.txt
file, what is the meaning of the
pgf
column?
Answer: The README.txt
file (in the
data/doi_10.5061_dryad.f77p7__v1/
folders) describes the
full dataset with the meaning of all columns. It says:
pgf: Plant growth form: A = fern, B = graminoid, C = forb, D =
herbaceous climber, E = herbaceous shrub, F = tree sapling, G = woody
climber, H = woody shrub, na = indeterminate
So the pgf
column describes the plant growth form.
- Q12: How do you interpret the PCoA results given
your answer to the previous question?
Answer: The PCoA shows groups of species according
to their plant growth form. Especially the category “F” (tree saplings)
seem to differentiate from all other growth forms. This means that tree
saplings have distinct traits from all other growth form groups.
Computing functional diversity indices
(Q13-Q15)
- Q13: How would you describe the relationships
between functional diversity and forest loss and road density?
Answer: None of the relationships seem to be very
straightforward, they rather show no clear relationship.
- Q14: Using the plot generated by the code beneath
how could you describe the relationships between the three different
functional diversity indices we computed?
Answer: This plot is a pairs plot it
represents the relationship between each pair of variables and display
the corresponding correlation coefficient on the upper diagonal. We
observe no correlation between Rao’s Quadratic Entropy and Functional
Evenness. We observe a slight correlation between Functional Evenness
and Functional Richness. And we observe a strong correlation between
Functional Richness and Rao’s Quadratic Entropy. This correlation can
highlight that both co-vary even though they are supposed to assess
independent dimensions of functional diversity. This may be due to a
hidden relationship with species richness.
- Q15: How does the relationship between indices with
species richness compare with the one observed with total biomass
values? (You can use the function
cor.test()
if you want to
test the association)
pairs(ntaxa ~ FRic + FEve + Q, data = site_rich_fd, upper.panel = panel.cor)
pairs(tot_biomass ~ FRic + FEve + Q, data = site_rich_fd,
upper.panel = panel.cor)
cor.test(site_rich_fd$ntaxa, site_rich_fd$FRic)
cor.test(site_rich_fd$tot_biomass, site_rich_fd$FRic)
cor.test(site_rich_fd$ntaxa, site_rich_fd$Q)
cor.test(site_rich_fd$tot_biomass, site_rich_fd$Q)
Answer: We observe a strong correlation between
species richness and functional richness, as well as a medium
correlation between species richness and Rao’s quadratic entropy. This
correlations become respectively small and absent when using total
biomass.
Null modeling (Q16-Q19)
- Q16: How would describe verbally the position of
the observed value of FRic for site “a100f177r” compared to the null
distribution?
Answer: The observe value is on the right tail of
the distribution which means that the observed value is slightly higher
than the null expectation.
- Q17: What’s the quantile of the observed FRic value
in the end?
# The observed value of FRic for the site
subset(site_fd, plot.code == "a100f177r")$FRic
# The null distribution of FRic for the same site
summary(subset(null_fd_999, site == "a100f177r")$FRic)
Answer: The observe FRic is close to the third
quartile (75th percentile).
- Q18: Using the
subset()
function with
the greater (or equal) than >=
and the lower (or equal)
than <=
, can you determine how many sites show a
significant deviation from the null observation? (absolute SES >=
2)
# First way of answering the question two separate subset() calls
nrow(subset(ses_fd, ses_FRic >= 2))
nrow(subset(ses_fd, ses_FRic <= -2))
# Or with a single call selecting the rows by absolute SES values
nrow(subset(ses_fd, abs(ses_FRic) >= 2))
Answer: We observe 16 sites with significant
deviation from the null observation.
- Q19: Using similar code as used for observed
values, what are the relationships between SES values and forest
loss?
par(mfrow = c(1, 1))
site_env_ses_fd = merge(ses_fd, plot_data[, c("plot.code", "forestloss17")],
by = "plot.code")
plot(site_env_ses_fd$forestloss17, site_env_ses_fd$ses_FRic,
xlab = "Forest loss (%)", ylab = "SES of Functional Richness (FRic)",
main = "SES Functional Richness vs. forest loss")
cor.test(site_env_ses_fd$forestloss17, site_env_ses_fd$ses_FRic)
cor.test(site_env_ses_fd$forestloss17, site_env_ses_fd$ses_Q)
cor.test(site_env_ses_fd$forestloss17, site_env_ses_fd$ses_FEve)
Anwser: The relationship is not clear when looking
at it but we observe a medium negative correlation between the SES
values and forest loss. This means that logging activity may decrease
the functional richness of understorey vegetation. We observe a similar
trend with the SES of Rao’s quadratic entropy. There are no trend with
the SES of functional evenness.
Phylogenetic diversity
(Q20-Q27)
Getting the phylogenetic tree
(Q20-Q21)
- Q20: How many taxa are in the phylogenetic
tree?
phylo_tree
Answer: There are 611 tips in the phylogenetic tree
so 611.
- Q21: How does this number compare to the number of
taxa found in the dataset?
Answer: There are 691 taxa in the dataset so 80 taxa
are missing from the phylogenetic tree.
Computing phylogenetic diversity indices
(Q22-Q24)
- Q22: What do you notice with the species names?
Especially compared to the ones available in
species_traits
.
Answer: The tip labels in the phylogenetic tree only
contain the species epithet (second part of the binomial
name) which corresponds to the species
column in the
species_traits
data.frame. That may be the source of
confusion in the phylogenetic tree that reduces the number of taxa.
- Q23: What is the relationship between the weighted
and the unweighted version of the MPD?
cor.test(obs_mpd$mpd_unweighted, obs_mpd$mpd_weighted)
Answer: There is a positive relationship between
both.
- Q24: What is the relationship between MPD and taxa
richness? And with forest loss? Plot these relationships to visualize
them and use the
cor.test()
function to validate your
observations.
par(mfrow = c(1, 2))
plot(obs_mpd$ntaxa, obs_mpd$mpd_weighted)
plot(obs_mpd$forestloss17, obs_mpd$mpd_weighted)
cor.test(obs_mpd$ntaxa, obs_mpd$mpd_weighted)
cor.test(obs_mpd$forestloss17, obs_mpd$mpd_weighted)
Answer: We seem to observe a positive relationship
between species richness and MPD and it is shown by a medium positive
correlation. We observe no relationship between forest loss and MPD.
Null modeling (Q25-Q27)
- Q25: Explain what does the column
mpd.obs.z
means? How does this compare with the SES values
we computed for functional diversity indices?
Answer: From the help page of
picante::ses.mpd
accessed with
?picante::ses.mpd
mpd.obs.z
Standardized effect size of mpd vs. null
communities (= (mpd.obs - mpd.rand.mean) / mpd.rand.sd, equivalent to
-NRI)
These are exactly SES values but for phylogenetic diversity. The name
comes from Z-scoring
variables?
- Q26: How does the standardized value relates to
taxa richness?
cor.test(ses_mpd_999$ntaxa, ses_mpd_999$mpd.obs.z)
Answer: They show no relationship. Which clearly
shows that the null models corrected for the richness
effect compared to the observed values.
- Q27: What are the relationships between MPD values
considering null models and forest loss? Visualize the relationships
with the
plot()
function, validate your observations with
the cor.test()
function.
par(mfrow = c(1, 1))
ses_mpd_999_env = merge(ses_mpd_999, plot_data[, c("plot.code", "forestloss17")],
by = "plot.code")
plot(ses_mpd_999_env$forestloss17, ses_mpd_999_env$mpd.obs.z)
cor.test(ses_mpd_999_env$forestloss17, ses_mpd_999_env$mpd.obs.z)
Anwser: There is still no clear relationship.
Modelling the effect of logging
(Q29-Q31)
Single-predictor models
(Q29-Q30)
- Q29: How would you qualify the effect of forest
loss on the taxa richness?
Answer: Forest loss do not seem to affect taxa
richnes.
- Q30: With the same formula build similar models
with the other predictors
roaddensprim
and
roaddistprim
. How do they compare with forest loss?
mod_taxa_dens = lm(ntaxa ~ roaddensprim, data = plot_div_env)
mod_taxa_dist = lm(ntaxa ~ roaddistprim, data = plot_div_env)
par(mfrow = c(1, 2))
plot(mod_taxa_dens$model$roaddensprim, mod_taxa_dens$model$ntaxa,
xlab = "Primary Road Density", ylab = "Species Richness")
abline(coef = coef(mod_taxa_dens), col = "darkred", lwd = 1)
plot(mod_taxa_dist$model$roaddistprim, mod_taxa_dist$model$ntaxa,
xlab = "Distance to nearest primary road", ylab = "Species Richness")
abline(coef = coef(mod_taxa_dist), col = "darkred", lwd = 1)
Answer: Similarly we observe no clear relationships
between species richness and other disturbance variables.
Multi-predictors models (Q31)
- Q31: What can you say about the effect of the
disturbances on the different diversity metrics? What are the
explanatory power of our models?
summary(mod_taxa_all)
summary(mod_fd_all)
summary(mod_pd_all)
Answer: We do not observe any variables with a
strong effect. Most of our models show a poor R-squared (< 20%) which
means they have poor explanatory powers. We should probably think better
about the determinants of our explanatory variables and account for the
non-independence of our dataset (block design in sampling).
LS0tCnRpdGxlOiAiQW5zd2VycyB0byBxdWVzdGlvbnMgYXNrZWQgaW4gdGhlIHR1dG9yaWFsIgphdXRob3I6ICJNYXR0aGlhcyBHcmVuacOpICYgTWFydGVuIFdpbnRlciIKZGF0ZTogIk1vbmRheSBKdWx5IDV0aCAyMDIxIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKSGVyZSBhcmUgYW5zd2VycyByZWdhcmRpbmcgYWxsIHRoZSBxdWVzdGlvbnMgYXNrZWQgaW4gdGhlIHR1dG9yaWFsLgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXZhbCA9IEZBTFNFKQpgYGAKCiMgTG9hZGluZyB0aGUgZGF0YSAoKipRMSoqLSoqUTYqKikKCiMjIFN1bW1hcml6aW5nIHRoZSBkYXRhCgoqICoqUTEqKjogSG93IG1hbnkgcGxvdHMgd2VyZSBzYW1wbGVkPwoKYGBge3IgcTF9Cm5yb3cocGxvdF9kYXRhKQpgYGAKCioqQW5zd2VyKio6IFRoZXJlIGFyZSAxODAgc2FtcGxlZCBwbG90cy4gCgoKKiAqKlEyKio6IEhvdyBtYW55IHNwZWNpZXMgYXJlIHRoZXJlIGluIHRoZSBkYXRhc2V0PwoKYGBge3IgcTJ9Cm5yb3coc3BlY2llc190cmFpdHMpCmBgYAoKKipBbnN3ZXIqKjogVGhlcmUgYXJlIDY5MSBzcGVjaWVzIGluIHRoZSBkYXRhc2V0LgoKCiogKipRMyoqOiBIb3cgbWFueSB0cmFpdHMgYXJlIGF2YWlsYWJsZT8KCmBgYHtyIHEzfQpoZWFkKHNwZWNpZXNfdHJhaXRzLCAyKQpgYGAKCioqQW5zd2VyKio6IFRoZXJlIGFyZSAxMyB0cmFpdHMgaW4gdGhlIGRhdGFzZXQuCgoKKiAqKlE0Kio6IEhvdyBtYW55IG9mIHRoZW0gYXJlIGNvbnRpbnVvdXM/IEhvdyBtYW55IG9mIHRoZW0gYXJlIGRpc2NyZXRlPwoKKipBbnN3ZXIqKjogTG9va2luZyBhdCB0aGUgdHJhaXQgdGFibGUgdGhlcmUgMyBjb250aW51b3VzIHRyYWl0cyAoYGhlaWdodGAsIGBzbGFgLCBhbmQgYHdvb2QuZGVuc2ApIGFuZCAxMCB0aGF0IGFyZSBkaXNjcmV0ZS4gKFJlZmVycmluZyB0byB0aGUgUkVBRE1FIGZpbGUgd2Ugc2VlIHRoYXQgdGhlIGBzZWVkYCBjb2x1bW4gY29udGFpbnMgaW5kZWVkIGEgY2F0ZWdvcmljYWwgdHJhaXQpLiAKCiogKipRNSoqOiBXaGF0IGlzIHRoZSBtb3N0IG51bWVyb3VzIGZhbWlseSBhbW9uZyBhbGwgb2JzZXJ2ZWQgc3BlY2llcz8KCmBgYHtyIHE1fQpzdW1tYXJ5KHNwZWNpZXNfdHJhaXRzKQpgYGAKCioqQW5zd2VyKio6IFRoZSBgc3VtbWFyeSgpYCBmdW5jdGlvbiBkaXNwbGF5cyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBlYWNoIGNhdGVnb3JpZXMgb3JkZXJlZCBieSB0aGUgbW9zdCBhYnVuZGFudCBjYXRlZ29yeS4gVGhlIGBmYW1pbHlgIGNvbHVtbiBzaG93cyB0aGF0IHRoZSAiTGVndW1pbm9zYWUiIChhLmsuYSwgRmFiYWNlYWUpIGlzIHRoZSBtb3N0IG51bWVyb3VzIGluIHRoZSBkYXRhc2V0LgoKKiAqKlE2Kio6IFdoYXQgaXMgdGhlIG1vc3QgbnVtZXJvdXMgZ2VudXM/CgoqKkFuc3dlcioqOiBTaW1pbGFybHkgdGhlIG1vc3QgbnVtZXJvdXMgZ2VudXMgaXMgIlVua25vd24iLCB3aGljaCBjb3JyZXNwb25kcyB0byBpbmRpdmlkdWFsIHRoYXQgd2VyZW4ndCBpZGVudGlmaWVkIGF0IHRoZSBnZW51cyBsZXZlbC4KCiMgRnVuY3Rpb25hbCBkaXZlcnNpdHkgKCoqUTcqKi0qKlExOSoqKQoKIyMgQ29tcHV0aW5nIEJpb21hc3Mtd2VpZ2h0ZWQgbWVhbiB0cmFpdHMgcGVyIHBsb3QgKCoqUTcqKi0qKlExMCoqKQoKKiAqKlE3Kio6IEhvdyB3b3VsZCB5b3UgZGVzY3JpYmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgQ1dNcyBhbmQgZm9yZXN0IGxvc3M/CgoqKkFuc3dlcioqOiBXZSdyZSBleWUtYmFsbGluZyB0aGUgcmVsYXRpb25zaGlwcyBidXQgaXQgc2VlbXMgdGhhdDoKCiogVGhlIENXTS1IZWlnaHQgc2VlbXMgdG8gZGVjcmVhc2Ugd2l0aCBmb3Jlc3QgbG9zcy4KKiBUaGUgQ1dNLVNMQSBzZWVtcyB0byBpbmNyZWFzZSB3aXRoIGZvcmVzdCBsb3NzLgoqIFRoZXJlIHNlZW0gdG8gYmUgbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIENXTS13b29kIGRlbnNpdHkgYW5kIGZvcmVzdCBsb3NzLiAKCiogKipROCoqOiBDYW4geW91IHRlc3QgdGhlIGNvcnJlbGF0aW9uIHVzaW5nIHRoZSBmdW5jdGlvbiBgY29yLnRlc3QoKWAgYW5kIGRvZXMgaXQgc3VwcG9ydCB5b3VyIHByZXZpb3VzIHN0YXRlbWVudHM/CgpgYGB7ciBxOH0KY29yLnRlc3QoY3dtX2VudiRmb3Jlc3Rsb3NzMTcsIGN3bV9lbnYkaGVpZ2h0KQpjb3IudGVzdChjd21fZW52JGZvcmVzdGxvc3MxNywgY3dtX2VudiRzbGEpCmNvci50ZXN0KGN3bV9lbnYkZm9yZXN0bG9zczE3LCBjd21fZW52JHdvb2QuZGVucykKYGBgCgoqKkFuc3dlcioqOgoKKiBXZSBvYnNlcnZlIGEgbmVnYXRpdmUgY29ycmVsYXRpb24gKC0wLjQ4KSBiZXR3ZWVuIENXTS1IZWlnaHQgYW5kIGZvcmVzdCBsb3NzLgoqIFdlIG9ic2VydmUgYSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiAoMC40OCkgYmV0d2VlbiBDV00tU0xBIGFuZCBmb3Jlc3QgbG9zcy4KKiBXZSBvYnNlcnZlIGEgc2xpZ2h0IG5lZ2F0aXZlIGNvcnJlbGF0aW9uICgtMC4yNCkgYmV0d2VlbiBDV00td29vZCBkZW5zaXR5IGFuZCBmb3Jlc3QgbG9zcy4gCgoqICoqUTkqKjogSG93IHdvdWxkIHlvdSBkZXNjcmliZSB0aGUgdW5kZXJzdG9yZXkgdmVnZXRhdGlvbiBjaGFuZ2VzIHdpdGggaW5jcmVhc2luZyBmb3Jlc3QgbG9zcz8KCioqQW5zd2VyKio6IFRoZSBDV00gdmFsdWVzIHJlZmxlY3QgdGhlIGRvbWluYW50IHRyYWl0IG9mIHRoZSBjb21tdW5pdHkuIFRoaXMgbWVhbnMgdGhhdCB3aXRoIGZvcmVzdCBsb3NzIHdlIG9ic2VydmUgc21hbGxlciBzcGVjaWVzLCBzcGVjaWVzIHdpdGggaGlnaGVyIFNMQSwgYW5kIHNwZWNpZXMgd2l0aCBsb3dlciB3b29kIGRlbnNpdHkuIExpbmtpbmcgYmFjayB0byBlY29sb2d5LCB0aGlzIGlzIHByb2JhYmx5IGR1ZSB0byBhIGNoYW5nZSBpbiB1bmRlcnN0b3JleSB2ZWdldGF0aW9uIHR5cGUgZnJvbSB3b29keSBzcGVjaWVzIGluIHVubG9nZ2VkIGFyZWEgdG8gbW9yZSBoZXJiYWNlb3VzIHNwZWNpZXMgaW4gaGVhdmlseSBsb2dnZWQgYXJlYS4KCiogKipRMTAqKjogSG93IGRvZXMgdGhpcyBvYnNlcnZhdGlvbiBjb21wYXJlIHRvIGFib3ZlIGRlc2NyaXB0aW9uIG9mIHRoZSBjaGFuZ2Ugb2YgdW5kZXJzdG9yZXkgdmVnZXRhdGlvbiBhbG9uZyB0aGUgZm9yZXN0IGxvc3MgZ3JhZGllbnQ/CgpgYGB7ciBxMTB9CmNvci50ZXN0KG5vbl9xdWFudGlfY3dtJGZvcmVzdGxvc3MxNywgbm9uX3F1YW50aV9jd20kd29vZHlfbm8pCmBgYAoKKipBbnN3ZXIqKjogVGhlIGB3b29keV9ub2AgQ1dNIHJlcHJlc2VudHMgdGhlIHByb3BvcnRpb24gb2Ygbm9uLXdvb2R5IHNwZWNpZXMgaW4gdGhlIGNvbW11bml0eS4gV2Ugb2JzZXJ2ZSBhIHBvc2l0aXZlIG1lZGl1bSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoaXMgQ1dNIGFuZCBmb3Jlc3QgbG9zcyB3aGljaCB0ZWxscyB1cyB0aGF0IG5vbi13b29keSBzcGVjaWVzIGFyZSBtb3JlIGZyZXF1ZW50IGluIHVuZGVyc3RvcmV5IHZlZ2V0YXRpb24gd2l0aCBpbmNyZWFzaW5nIGZvcmVzdCBsb3NzLgoKIyMgQnVpbGRpbmcgdGhlIGZ1bmN0aW9uYWwgc3BhY2UgKCoqUTExKiotKipRMTIqKikKCiogKipRMTEqKjogVXNpbmcgdGhlIG1ldGFkYXRhIGF2YWlsYWJsZSBpbiB0aGUgYFJFQURNRS50eHRgIGZpbGUsIHdoYXQgaXMgdGhlIG1lYW5pbmcgb2YgdGhlIGBwZ2ZgIGNvbHVtbj8KCioqQW5zd2VyKio6IFRoZSBgUkVBRE1FLnR4dGAgZmlsZSAoaW4gdGhlIGBkYXRhL2RvaV8xMC41MDYxX2RyeWFkLmY3N3A3X192MS9gIGZvbGRlcnMpIGRlc2NyaWJlcyB0aGUgZnVsbCBkYXRhc2V0IHdpdGggdGhlIG1lYW5pbmcgb2YgYWxsIGNvbHVtbnMuIEl0IHNheXM6Cgo+IHBnZjogUGxhbnQgZ3Jvd3RoIGZvcm06IEEgPSBmZXJuLCBCID0gZ3JhbWlub2lkLCBDID0gZm9yYiwgRCA9IGhlcmJhY2VvdXMgY2xpbWJlciwgRSA9IGhlcmJhY2VvdXMgc2hydWIsIEYgPSB0cmVlIHNhcGxpbmcsIEcgPSB3b29keSBjbGltYmVyLCBIID0gd29vZHkgc2hydWIsIG5hID0gaW5kZXRlcm1pbmF0ZQoKU28gdGhlIGBwZ2ZgIGNvbHVtbiBkZXNjcmliZXMgdGhlIHBsYW50IGdyb3d0aCBmb3JtLgoKKiAqKlExMioqOiBIb3cgZG8geW91IGludGVycHJldCB0aGUgUENvQSByZXN1bHRzIGdpdmVuIHlvdXIgYW5zd2VyIHRvIHRoZSBwcmV2aW91cyBxdWVzdGlvbj8KCioqQW5zd2VyKio6IFRoZSBQQ29BIHNob3dzIGdyb3VwcyBvZiBzcGVjaWVzIGFjY29yZGluZyB0byB0aGVpciBwbGFudCBncm93dGggZm9ybS4gRXNwZWNpYWxseSB0aGUgY2F0ZWdvcnkgIkYiICh0cmVlIHNhcGxpbmdzKSBzZWVtIHRvIGRpZmZlcmVudGlhdGUgZnJvbSBhbGwgb3RoZXIgZ3Jvd3RoIGZvcm1zLiBUaGlzIG1lYW5zIHRoYXQgdHJlZSBzYXBsaW5ncyBoYXZlIGRpc3RpbmN0IHRyYWl0cyBmcm9tIGFsbCBvdGhlciBncm93dGggZm9ybSBncm91cHMuCgoKIyMgQ29tcHV0aW5nIGZ1bmN0aW9uYWwgZGl2ZXJzaXR5IGluZGljZXMgKCoqUTEzKiotKipRMTUqKikKCiogKipRMTMqKjogSG93IHdvdWxkIHlvdSBkZXNjcmliZSB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGZ1bmN0aW9uYWwgZGl2ZXJzaXR5IGFuZCBmb3Jlc3QgbG9zcyBhbmQgcm9hZCBkZW5zaXR5PwoKKipBbnN3ZXIqKjogTm9uZSBvZiB0aGUgcmVsYXRpb25zaGlwcyBzZWVtIHRvIGJlIHZlcnkgc3RyYWlnaHRmb3J3YXJkLCB0aGV5IHJhdGhlciBzaG93IG5vIGNsZWFyIHJlbGF0aW9uc2hpcC4KCiogKipRMTQqKjogVXNpbmcgdGhlIHBsb3QgZ2VuZXJhdGVkIGJ5IHRoZSBjb2RlIGJlbmVhdGggaG93IGNvdWxkIHlvdSBkZXNjcmliZSB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSB0aHJlZSBkaWZmZXJlbnQgZnVuY3Rpb25hbCBkaXZlcnNpdHkgaW5kaWNlcyB3ZSBjb21wdXRlZD8KCioqQW5zd2VyKio6IFRoaXMgcGxvdCBpcyBhIFtwYWlycyBwbG90XShodHRwczovL3d3dy5zdGF0b2xvZ3kub3JnL3BhaXJzLXBsb3RzLXIvKSBpdCByZXByZXNlbnRzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlYWNoIHBhaXIgb2YgdmFyaWFibGVzIGFuZCBkaXNwbGF5IHRoZSBjb3JyZXNwb25kaW5nIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9uIHRoZSB1cHBlciBkaWFnb25hbC4gV2Ugb2JzZXJ2ZSBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIFJhbydzIFF1YWRyYXRpYyBFbnRyb3B5IGFuZCBGdW5jdGlvbmFsIEV2ZW5uZXNzLiBXZSBvYnNlcnZlIGEgc2xpZ2h0IGNvcnJlbGF0aW9uIGJldHdlZW4gRnVuY3Rpb25hbCBFdmVubmVzcyBhbmQgRnVuY3Rpb25hbCBSaWNobmVzcy4gQW5kIHdlIG9ic2VydmUgYSBzdHJvbmcgY29ycmVsYXRpb24gYmV0d2VlbiBGdW5jdGlvbmFsIFJpY2huZXNzIGFuZCBSYW8ncyBRdWFkcmF0aWMgRW50cm9weS4gVGhpcyBjb3JyZWxhdGlvbiBjYW4gaGlnaGxpZ2h0IHRoYXQgYm90aCBjby12YXJ5IGV2ZW4gdGhvdWdoIHRoZXkgYXJlIHN1cHBvc2VkIHRvIGFzc2VzcyBpbmRlcGVuZGVudCBkaW1lbnNpb25zIG9mIGZ1bmN0aW9uYWwgZGl2ZXJzaXR5LiBUaGlzIG1heSBiZSBkdWUgdG8gYSBoaWRkZW4gcmVsYXRpb25zaGlwIHdpdGggc3BlY2llcyByaWNobmVzcy4KCiogKipRMTUqKjogSG93IGRvZXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGluZGljZXMgd2l0aCBzcGVjaWVzIHJpY2huZXNzIGNvbXBhcmUgd2l0aCB0aGUgb25lIG9ic2VydmVkIHdpdGggdG90YWwgYmlvbWFzcyB2YWx1ZXM/IChZb3UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gYGNvci50ZXN0KClgIGlmIHlvdSB3YW50IHRvIHRlc3QgdGhlIGFzc29jaWF0aW9uKQoKYGBge3IgcTE1fQpwYWlycyhudGF4YSB+IEZSaWMgKyBGRXZlICsgUSwgZGF0YSA9IHNpdGVfcmljaF9mZCwgdXBwZXIucGFuZWwgPSBwYW5lbC5jb3IpCnBhaXJzKHRvdF9iaW9tYXNzIH4gRlJpYyArIEZFdmUgKyBRLCBkYXRhID0gc2l0ZV9yaWNoX2ZkLAogICAgICB1cHBlci5wYW5lbCA9IHBhbmVsLmNvcikKY29yLnRlc3Qoc2l0ZV9yaWNoX2ZkJG50YXhhLCBzaXRlX3JpY2hfZmQkRlJpYykKY29yLnRlc3Qoc2l0ZV9yaWNoX2ZkJHRvdF9iaW9tYXNzLCBzaXRlX3JpY2hfZmQkRlJpYykKCmNvci50ZXN0KHNpdGVfcmljaF9mZCRudGF4YSwgc2l0ZV9yaWNoX2ZkJFEpCmNvci50ZXN0KHNpdGVfcmljaF9mZCR0b3RfYmlvbWFzcywgc2l0ZV9yaWNoX2ZkJFEpCmBgYAoKKipBbnN3ZXIqKjogV2Ugb2JzZXJ2ZSBhIHN0cm9uZyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNwZWNpZXMgcmljaG5lc3MgYW5kIGZ1bmN0aW9uYWwgcmljaG5lc3MsIGFzIHdlbGwgYXMgYSBtZWRpdW0gY29ycmVsYXRpb24gYmV0d2VlbiBzcGVjaWVzIHJpY2huZXNzIGFuZCBSYW8ncyBxdWFkcmF0aWMgZW50cm9weS4gVGhpcyBjb3JyZWxhdGlvbnMgYmVjb21lIHJlc3BlY3RpdmVseSBzbWFsbCBhbmQgYWJzZW50IHdoZW4gdXNpbmcgdG90YWwgYmlvbWFzcy4KCiMjIE51bGwgbW9kZWxpbmcgKCoqUTE2KiotKipRMTkqKikKCiogKipRMTYqKjogSG93IHdvdWxkIGRlc2NyaWJlIHZlcmJhbGx5IHRoZSBwb3NpdGlvbiBvZiB0aGUgb2JzZXJ2ZWQgdmFsdWUgb2YgRlJpYyBmb3Igc2l0ZSAiYTEwMGYxNzdyIiBjb21wYXJlZCB0byB0aGUgbnVsbCBkaXN0cmlidXRpb24/CgoqKkFuc3dlcioqOiBUaGUgb2JzZXJ2ZSB2YWx1ZSBpcyBvbiB0aGUgcmlnaHQgdGFpbCBvZiB0aGUgZGlzdHJpYnV0aW9uIHdoaWNoIG1lYW5zIHRoYXQgdGhlIG9ic2VydmVkIHZhbHVlIGlzIHNsaWdodGx5IGhpZ2hlciB0aGFuIHRoZSBudWxsIGV4cGVjdGF0aW9uLgoKKiAqKlExNyoqOiBXaGF0J3MgdGhlIHF1YW50aWxlIG9mIHRoZSBvYnNlcnZlZCBGUmljIHZhbHVlIGluIHRoZSBlbmQ/CgpgYGB7ciBxMTd9CiMgVGhlIG9ic2VydmVkIHZhbHVlIG9mIEZSaWMgZm9yIHRoZSBzaXRlCnN1YnNldChzaXRlX2ZkLCBwbG90LmNvZGUgPT0gImExMDBmMTc3ciIpJEZSaWMKCiMgVGhlIG51bGwgZGlzdHJpYnV0aW9uIG9mIEZSaWMgZm9yIHRoZSBzYW1lIHNpdGUKc3VtbWFyeShzdWJzZXQobnVsbF9mZF85OTksIHNpdGUgPT0gImExMDBmMTc3ciIpJEZSaWMpCmBgYAoKKipBbnN3ZXIqKjogVGhlIG9ic2VydmUgRlJpYyBpcyBjbG9zZSB0byB0aGUgdGhpcmQgcXVhcnRpbGUgKDc1dGggcGVyY2VudGlsZSkuCgoqICoqUTE4Kio6IFVzaW5nIHRoZSBgc3Vic2V0KClgIGZ1bmN0aW9uIHdpdGggdGhlIGdyZWF0ZXIgKG9yIGVxdWFsKSB0aGFuIGA+PWAgYW5kIHRoZSBsb3dlciAob3IgZXF1YWwpIHRoYW4gYDw9YCwgY2FuIHlvdSBkZXRlcm1pbmUgaG93IG1hbnkgc2l0ZXMgc2hvdyBhIHNpZ25pZmljYW50IGRldmlhdGlvbiBmcm9tIHRoZSBudWxsIG9ic2VydmF0aW9uPyAoYWJzb2x1dGUgU0VTID49IDIpCgpgYGB7ciBxMTh9CiMgRmlyc3Qgd2F5IG9mIGFuc3dlcmluZyB0aGUgcXVlc3Rpb24gdHdvIHNlcGFyYXRlIHN1YnNldCgpIGNhbGxzCm5yb3coc3Vic2V0KHNlc19mZCwgc2VzX0ZSaWMgPj0gMikpCm5yb3coc3Vic2V0KHNlc19mZCwgc2VzX0ZSaWMgPD0gLTIpKQoKIyBPciB3aXRoIGEgc2luZ2xlIGNhbGwgc2VsZWN0aW5nIHRoZSByb3dzIGJ5IGFic29sdXRlIFNFUyB2YWx1ZXMKbnJvdyhzdWJzZXQoc2VzX2ZkLCBhYnMoc2VzX0ZSaWMpID49IDIpKQpgYGAKCioqQW5zd2VyKio6IFdlIG9ic2VydmUgMTYgc2l0ZXMgd2l0aCBzaWduaWZpY2FudCBkZXZpYXRpb24gZnJvbSB0aGUgbnVsbCBvYnNlcnZhdGlvbi4KCiogKipRMTkqKjogVXNpbmcgc2ltaWxhciBjb2RlIGFzIHVzZWQgZm9yIG9ic2VydmVkIHZhbHVlcywgd2hhdCBhcmUgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBTRVMgdmFsdWVzIGFuZCBmb3Jlc3QgbG9zcz8KCmBgYHtyIHExOX0KcGFyKG1mcm93ID0gYygxLCAxKSkKCnNpdGVfZW52X3Nlc19mZCA9IG1lcmdlKHNlc19mZCwgcGxvdF9kYXRhWywgYygicGxvdC5jb2RlIiwgImZvcmVzdGxvc3MxNyIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAicGxvdC5jb2RlIikKCnBsb3Qoc2l0ZV9lbnZfc2VzX2ZkJGZvcmVzdGxvc3MxNywgc2l0ZV9lbnZfc2VzX2ZkJHNlc19GUmljLAogICAgIHhsYWIgPSAiRm9yZXN0IGxvc3MgKCUpIiwgeWxhYiA9ICJTRVMgb2YgRnVuY3Rpb25hbCBSaWNobmVzcyAoRlJpYykiLAogICAgIG1haW4gPSAiU0VTIEZ1bmN0aW9uYWwgUmljaG5lc3MgdnMuIGZvcmVzdCBsb3NzIikKY29yLnRlc3Qoc2l0ZV9lbnZfc2VzX2ZkJGZvcmVzdGxvc3MxNywgc2l0ZV9lbnZfc2VzX2ZkJHNlc19GUmljKQpjb3IudGVzdChzaXRlX2Vudl9zZXNfZmQkZm9yZXN0bG9zczE3LCBzaXRlX2Vudl9zZXNfZmQkc2VzX1EpCmNvci50ZXN0KHNpdGVfZW52X3Nlc19mZCRmb3Jlc3Rsb3NzMTcsIHNpdGVfZW52X3Nlc19mZCRzZXNfRkV2ZSkKYGBgCgoqKkFud3NlcioqOiBUaGUgcmVsYXRpb25zaGlwIGlzIG5vdCBjbGVhciB3aGVuIGxvb2tpbmcgYXQgaXQgYnV0IHdlIG9ic2VydmUgYSBtZWRpdW0gbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgU0VTIHZhbHVlcyBhbmQgZm9yZXN0IGxvc3MuIFRoaXMgbWVhbnMgdGhhdCBsb2dnaW5nIGFjdGl2aXR5IG1heSBkZWNyZWFzZSB0aGUgZnVuY3Rpb25hbCByaWNobmVzcyBvZiB1bmRlcnN0b3JleSB2ZWdldGF0aW9uLiBXZSBvYnNlcnZlIGEgc2ltaWxhciB0cmVuZCB3aXRoIHRoZSBTRVMgb2YgUmFvJ3MgcXVhZHJhdGljIGVudHJvcHkuIFRoZXJlIGFyZSBubyB0cmVuZCB3aXRoIHRoZSBTRVMgb2YgZnVuY3Rpb25hbCBldmVubmVzcy4KCiMgUGh5bG9nZW5ldGljIGRpdmVyc2l0eSAoKipRMjAqKi0qKlEyNyoqKQoKIyMgR2V0dGluZyB0aGUgcGh5bG9nZW5ldGljIHRyZWUgKCoqUTIwKiotKipRMjEqKikKCiogKipRMjAqKjogSG93IG1hbnkgdGF4YSBhcmUgaW4gdGhlIHBoeWxvZ2VuZXRpYyB0cmVlPwoKYGBge3IgcTIwfQpwaHlsb190cmVlCmBgYAoKKipBbnN3ZXIqKjogVGhlcmUgYXJlIDYxMSB0aXBzIGluIHRoZSBwaHlsb2dlbmV0aWMgdHJlZSBzbyA2MTEuCgoqICoqUTIxKio6IEhvdyBkb2VzIHRoaXMgbnVtYmVyIGNvbXBhcmUgdG8gdGhlIG51bWJlciBvZiB0YXhhIGZvdW5kIGluIHRoZSBkYXRhc2V0PwoKKipBbnN3ZXIqKjogVGhlcmUgYXJlIDY5MSB0YXhhIGluIHRoZSBkYXRhc2V0IHNvIDgwIHRheGEgYXJlIG1pc3NpbmcgZnJvbSB0aGUgcGh5bG9nZW5ldGljIHRyZWUuCgojIyBDb21wdXRpbmcgcGh5bG9nZW5ldGljIGRpdmVyc2l0eSBpbmRpY2VzICgqKlEyMioqLSoqUTI0KiopCgoqICoqUTIyKio6IFdoYXQgZG8geW91IG5vdGljZSB3aXRoIHRoZSBzcGVjaWVzIG5hbWVzPyBFc3BlY2lhbGx5IGNvbXBhcmVkIHRvIHRoZSBvbmVzIGF2YWlsYWJsZSBpbiBgc3BlY2llc190cmFpdHNgLgoKKipBbnN3ZXIqKjogVGhlIHRpcCBsYWJlbHMgaW4gdGhlIHBoeWxvZ2VuZXRpYyB0cmVlIG9ubHkgY29udGFpbiB0aGUgc3BlY2llcyBlcGl0aGV0IChzZWNvbmQgcGFydCBvZiB0aGUgW2Jpbm9taWFsIG5hbWVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Jpbm9taWFsX25vbWVuY2xhdHVyZSkpIHdoaWNoIGNvcnJlc3BvbmRzIHRvIHRoZSBgc3BlY2llc2AgY29sdW1uIGluIHRoZSBgc3BlY2llc190cmFpdHNgIGRhdGEuZnJhbWUuIFRoYXQgbWF5IGJlIHRoZSBzb3VyY2Ugb2YgY29uZnVzaW9uIGluIHRoZSBwaHlsb2dlbmV0aWMgdHJlZSB0aGF0IHJlZHVjZXMgdGhlIG51bWJlciBvZiB0YXhhLgoKKiAqKlEyMyoqOiBXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgd2VpZ2h0ZWQgYW5kIHRoZSB1bndlaWdodGVkIHZlcnNpb24gb2YgdGhlIE1QRD8KCmBgYHtyIHEyM30KY29yLnRlc3Qob2JzX21wZCRtcGRfdW53ZWlnaHRlZCwgb2JzX21wZCRtcGRfd2VpZ2h0ZWQpCmBgYAoKKipBbnN3ZXIqKjogVGhlcmUgaXMgYSBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBib3RoLgoKKiAqKlEyNCoqOiBXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBNUEQgYW5kIHRheGEgcmljaG5lc3M/IEFuZCB3aXRoIGZvcmVzdCBsb3NzPyBQbG90IHRoZXNlIHJlbGF0aW9uc2hpcHMgdG8gdmlzdWFsaXplIHRoZW0gYW5kIHVzZSB0aGUgYGNvci50ZXN0KClgIGZ1bmN0aW9uIHRvIHZhbGlkYXRlIHlvdXIgb2JzZXJ2YXRpb25zLgoKYGBge3IgcTI0fQpwYXIobWZyb3cgPSBjKDEsIDIpKQpwbG90KG9ic19tcGQkbnRheGEsIG9ic19tcGQkbXBkX3dlaWdodGVkKQpwbG90KG9ic19tcGQkZm9yZXN0bG9zczE3LCBvYnNfbXBkJG1wZF93ZWlnaHRlZCkKCmNvci50ZXN0KG9ic19tcGQkbnRheGEsIG9ic19tcGQkbXBkX3dlaWdodGVkKQpjb3IudGVzdChvYnNfbXBkJGZvcmVzdGxvc3MxNywgb2JzX21wZCRtcGRfd2VpZ2h0ZWQpCmBgYAoKKipBbnN3ZXIqKjogV2Ugc2VlbSB0byBvYnNlcnZlIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gc3BlY2llcyByaWNobmVzcyBhbmQgTVBEIGFuZCBpdCBpcyBzaG93biBieSBhIG1lZGl1bSBwb3NpdGl2ZSBjb3JyZWxhdGlvbi4gV2Ugb2JzZXJ2ZSBubyByZWxhdGlvbnNoaXAgYmV0d2VlbiBmb3Jlc3QgbG9zcyBhbmQgTVBELgoKIyMgTnVsbCBtb2RlbGluZyAoKipRMjUqKi0qKlEyNyoqKQoKKiAqKlEyNSoqOiBFeHBsYWluIHdoYXQgZG9lcyB0aGUgY29sdW1uIGBtcGQub2JzLnpgIG1lYW5zPyBIb3cgZG9lcyB0aGlzIGNvbXBhcmUgd2l0aCB0aGUgU0VTIHZhbHVlcyB3ZSBjb21wdXRlZCBmb3IgZnVuY3Rpb25hbCBkaXZlcnNpdHkgaW5kaWNlcz8KCioqQW5zd2VyKio6IEZyb20gdGhlIGhlbHAgcGFnZSBvZiBgcGljYW50ZTo6c2VzLm1wZGAgYWNjZXNzZWQgd2l0aCBgP3BpY2FudGU6OnNlcy5tcGRgCgo+IGBtcGQub2JzLnpgIFN0YW5kYXJkaXplZCBlZmZlY3Qgc2l6ZSBvZiBtcGQgdnMuIG51bGwgY29tbXVuaXRpZXMgKD0gKG1wZC5vYnMgLSBtcGQucmFuZC5tZWFuKSAvIG1wZC5yYW5kLnNkLCBlcXVpdmFsZW50IHRvIC1OUkkpCgpUaGVzZSBhcmUgZXhhY3RseSBTRVMgdmFsdWVzIGJ1dCBmb3IgcGh5bG9nZW5ldGljIGRpdmVyc2l0eS4gVGhlIG5hbWUgY29tZXMgZnJvbSBbWi1zY29yaW5nIHZhcmlhYmxlc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU3RhbmRhcmRfc2NvcmUpPwoKKiAqKlEyNioqOiBIb3cgZG9lcyB0aGUgc3RhbmRhcmRpemVkIHZhbHVlIHJlbGF0ZXMgdG8gdGF4YSByaWNobmVzcz8KCmBgYHtyIHEyNn0KY29yLnRlc3Qoc2VzX21wZF85OTkkbnRheGEsIHNlc19tcGRfOTk5JG1wZC5vYnMueikKYGBgCgoqKkFuc3dlcioqOiBUaGV5IHNob3cgbm8gcmVsYXRpb25zaGlwLiBXaGljaCBjbGVhcmx5IHNob3dzIHRoYXQgdGhlIG51bGwgbW9kZWxzICoqY29ycmVjdGVkKiogZm9yIHRoZSByaWNobmVzcyBlZmZlY3QgY29tcGFyZWQgdG8gdGhlIG9ic2VydmVkIHZhbHVlcy4KCiogKipRMjcqKjogV2hhdCBhcmUgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBNUEQgdmFsdWVzIGNvbnNpZGVyaW5nIG51bGwgbW9kZWxzIGFuZCBmb3Jlc3QgbG9zcz8gVmlzdWFsaXplIHRoZSByZWxhdGlvbnNoaXBzIHdpdGggdGhlIGBwbG90KClgIGZ1bmN0aW9uLCB2YWxpZGF0ZSB5b3VyIG9ic2VydmF0aW9ucyB3aXRoIHRoZSBgY29yLnRlc3QoKWAgZnVuY3Rpb24uCgpgYGB7ciBxMjcsIG9wdGlvbnN9CnBhcihtZnJvdyA9IGMoMSwgMSkpCgpzZXNfbXBkXzk5OV9lbnYgPSBtZXJnZShzZXNfbXBkXzk5OSwgcGxvdF9kYXRhWywgYygicGxvdC5jb2RlIiwgImZvcmVzdGxvc3MxNyIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAicGxvdC5jb2RlIikKCnBsb3Qoc2VzX21wZF85OTlfZW52JGZvcmVzdGxvc3MxNywgc2VzX21wZF85OTlfZW52JG1wZC5vYnMueikKCmNvci50ZXN0KHNlc19tcGRfOTk5X2VudiRmb3Jlc3Rsb3NzMTcsIHNlc19tcGRfOTk5X2VudiRtcGQub2JzLnopCmBgYAoKKipBbndzZXIqKjogVGhlcmUgaXMgc3RpbGwgbm8gY2xlYXIgcmVsYXRpb25zaGlwLgoKIyBDb21wYXJpbmcgZmFjZXRzICgqKlEyOCoqKQoKKiAqKlEyOCoqOiBIb3cgYXJlIHJlbGF0ZWQgYXJlIG9ic2VydmVkIHZhbHVlcyBvZiBmdW5jdGlvbmFsIGRpdmVyc2l0eSBhbmQgcGh5bG9nZW5ldGljIGRpdmVyc2l0eT8gV2hhdCBhYm91dCB0aGUgU0VTcz8KCioqQW5zd2VyKio6IE9ic2VydmVkIE1QRCBpcyBjb3JyZWxhdGVkIHdpdGggb2JzZXJ2ZWQgUSBhbmQgb2JzZXJ2ZWQgRlJpYywgYW5kIHdpdGggcmljaG5lc3MuIEFsbCB0aGVzZSBjb3JyZWxhdGlvbnMgZGlzYXBwZWFyIHdpdGggdGhlIFNFUyB2YWx1ZXMuIChUaGlzIHRoZSBlZmZlY3Qgb2YgbnVsbCBtb2RlbGluZyB0byBhY2NvdW50IGZvciB0aGUgcmVsYXRpb25zaGlwcyB3aXRoIHNwZWNpZXMgcmljaG5lc3MpLgoKIyBNb2RlbGxpbmcgdGhlIGVmZmVjdCBvZiBsb2dnaW5nICgqKlEyOSoqLSoqUTMxKiopCgojIyBTaW5nbGUtcHJlZGljdG9yIG1vZGVscyAoKipRMjkqKi0qKlEzMCoqKQoKKiAqKlEyOSoqOiBIb3cgd291bGQgeW91IHF1YWxpZnkgdGhlIGVmZmVjdCBvZiBmb3Jlc3QgbG9zcyBvbiB0aGUgdGF4YSByaWNobmVzcz8KCioqQW5zd2VyKio6IEZvcmVzdCBsb3NzIGRvIG5vdCBzZWVtIHRvIGFmZmVjdCB0YXhhIHJpY2huZXMuCgoqICoqUTMwKio6IFdpdGggdGhlIHNhbWUgZm9ybXVsYSBidWlsZCBzaW1pbGFyIG1vZGVscyB3aXRoIHRoZSBvdGhlciBwcmVkaWN0b3JzIGByb2FkZGVuc3ByaW1gIGFuZCBgcm9hZGRpc3RwcmltYC4gSG93IGRvIHRoZXkgY29tcGFyZSB3aXRoIGZvcmVzdCBsb3NzPwoKYGBge3IgcTMwfQoKbW9kX3RheGFfZGVucyA9IGxtKG50YXhhIH4gcm9hZGRlbnNwcmltLCBkYXRhID0gcGxvdF9kaXZfZW52KQptb2RfdGF4YV9kaXN0ID0gbG0obnRheGEgfiByb2FkZGlzdHByaW0sIGRhdGEgPSBwbG90X2Rpdl9lbnYpCgpwYXIobWZyb3cgPSBjKDEsIDIpKQpwbG90KG1vZF90YXhhX2RlbnMkbW9kZWwkcm9hZGRlbnNwcmltLCBtb2RfdGF4YV9kZW5zJG1vZGVsJG50YXhhLAogICAgIHhsYWIgPSAiUHJpbWFyeSBSb2FkIERlbnNpdHkiLCB5bGFiID0gIlNwZWNpZXMgUmljaG5lc3MiKQphYmxpbmUoY29lZiA9IGNvZWYobW9kX3RheGFfZGVucyksIGNvbCA9ICJkYXJrcmVkIiwgbHdkID0gMSkKCnBsb3QobW9kX3RheGFfZGlzdCRtb2RlbCRyb2FkZGlzdHByaW0sIG1vZF90YXhhX2Rpc3QkbW9kZWwkbnRheGEsCiAgICAgeGxhYiA9ICJEaXN0YW5jZSB0byBuZWFyZXN0IHByaW1hcnkgcm9hZCIsIHlsYWIgPSAiU3BlY2llcyBSaWNobmVzcyIpCmFibGluZShjb2VmID0gY29lZihtb2RfdGF4YV9kaXN0KSwgY29sID0gImRhcmtyZWQiLCBsd2QgPSAxKQpgYGAKCioqQW5zd2VyKio6IFNpbWlsYXJseSB3ZSBvYnNlcnZlIG5vIGNsZWFyIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzcGVjaWVzIHJpY2huZXNzIGFuZCBvdGhlciBkaXN0dXJiYW5jZSB2YXJpYWJsZXMuCgojIyBNdWx0aS1wcmVkaWN0b3JzIG1vZGVscyAoKipRMzEqKikKCiogKipRMzEqKjogV2hhdCBjYW4geW91IHNheSBhYm91dCB0aGUgZWZmZWN0IG9mIHRoZSBkaXN0dXJiYW5jZXMgb24gdGhlIGRpZmZlcmVudCBkaXZlcnNpdHkgbWV0cmljcz8gV2hhdCBhcmUgdGhlIGV4cGxhbmF0b3J5IHBvd2VyIG9mIG91ciBtb2RlbHM/CgpgYGB7ciBxMzF9CnN1bW1hcnkobW9kX3RheGFfYWxsKQpzdW1tYXJ5KG1vZF9mZF9hbGwpCnN1bW1hcnkobW9kX3BkX2FsbCkKYGBgCgoqKkFuc3dlcioqOiBXZSBkbyBub3Qgb2JzZXJ2ZSBhbnkgdmFyaWFibGVzIHdpdGggYSBzdHJvbmcgZWZmZWN0LiBNb3N0IG9mIG91ciBtb2RlbHMgc2hvdyBhIHBvb3IgUi1zcXVhcmVkICg8IDIwJSkgd2hpY2ggbWVhbnMgdGhleSBoYXZlIHBvb3IgZXhwbGFuYXRvcnkgcG93ZXJzLiBXZSBzaG91bGQgcHJvYmFibHkgdGhpbmsgYmV0dGVyIGFib3V0IHRoZSBkZXRlcm1pbmFudHMgb2Ygb3VyIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBhbmQgYWNjb3VudCBmb3IgdGhlIG5vbi1pbmRlcGVuZGVuY2Ugb2Ygb3VyIGRhdGFzZXQgKGJsb2NrIGRlc2lnbiBpbiBzYW1wbGluZykuCg==