By Angus Ball
Had enough of me by now? you can also read the devs tutorial here: https://www.bioconductor.org/packages/release/bioc/vignettes/ANCOMBC/inst/doc/ANCOMBC.html
Welcome to the fray! ANCOM-BC-2 is great and has alot of cool
features, read about em (and understand them >:[! (These are the same
as the ones on the git):
So what’s ANCOM-BC-2’s deal?
-Multiple pairwise comparisons!! This may not sound like a big deal
but this is the first program I’ve encountered that promises it’ll do
all the comparisons you care about in groups of 3+ rather than just
having a reference taxon and you have to fiddle around with it. (it’ll
also do binary comparisons)
-Pattern analysis over ordered study groups (effectively pairwise
comparisons but with a fuzzer image)
-ANCOM-BC-2 will also account for taxon-specific bias. Remember how
choosing your PCR primers was so important? because they will
preferentially bias certain taxons? ANCOMBC2 promises to account for
this in your data.
-(This one is really cool) ANCOMBC2 will perform sensitivity analysis
based on choice of pseudo-count. See pseudo-count can change your
results (specifically regarding rare taxa as they are more biased by the
psuedo-count), leading to an inflated FDR. ANCOMBC2 will run the
analysis with multiple pseudo-counts and see how they effect the results
and filter out taxa that are significantly affected by pseudo-count.
-ANCOMBC2 knows about compositionality and how scary it is. See we
use relative abundance because microbiome data is compositional, but a
change in the absolute abundance of a single taxon can alter the
relative abundances of all taxa (This is shockingly not great).
Therefore, when we hypothesis test comparing relative abundances is not
equivalent to absolute abundances. Relative abundance/ sampling fraction
can be affected by the microbial load in the system and library size.
Library size is simple too small a library size you don’t hit the
important parts of your rarefaction curve and you miss out on species.
Microbial load is a bit more complex (and explained well in the ANCOMBC
paper). But in short two ecosystems/samples can have the same relative
abundance and library sizes of a taxon, but their absolute population
size, or microbial load, is different. If you don’t account for this
then you’d say the two ecosystems are the same (wrong). ANCOMBC accounts
for microbial load by introducing a sample-specific offset term to bias
correct for the microbial load and constitutionality of microbiome
data.
-Preforms worse when sample size is small (n = 5), and runs perfectly
when n >= 10
-Accounts for structural zeros. Structural zeros are defined as
taxons present in one sample type and not present in another
(i.e. imagine comparing samples from a jungle to a forest, there’ll just
be some species that straight up don’t exist in one environment or the
other and this is expect). You can’t really do stats on these structural
zeros because its just not there in one sample. So we’ll have to examine
this differently (and subjectively). Please give Naught all zeros in
sequence count data are the same a skim it has some stuff to say about
zeros (if you couldn’t guess by the title). Structural zeros are called
biological zeros in this paper. Now this being said the way these
structural zeros are defined is a bit suspect. See if your library size
in some samples is too small it won’t pick up rare taxa at all! so these
rare taxa might be erroneously picked up as structural zeros (where they
should be called sampling zeros). However, in my humble opinion using
the same sequencing tech and primers should mitigate the issues with
sampling zeros (and technical zeros) as you’d expect equal various among
samples. ANCOMBC skirts some of these issues by first filter taxa to
have to exist in a certain amount of samples (10% by default) to get
around rare taxa getting picked up just because they are rare.
Cool, so how do we get ANCOMBC running?, well This package is new as
hell, and the biocmanaer version isn’t up to date, so we’ll be
downloading straight off of the github
#Heres how to install it
devtools::install_github("FrederickHuangLin/ANCOMBC", branch = "bugfix")
it uhh takes a second
You’ll also need these packages (Which you probably don’t have)
#Also download these bad boys
devtools::install_github("vmikk/metagMisc")
devtools::install_github("zdk123/SpiecEasi")
devtools::install_github("GraceYoon/SPRING")
devtools::install_github("stefpeschel/NetCoMi",
dependencies = c("Depends", "Imports", "LinkingTo"),
repos = c("https://cloud.r-project.org/",
BiocManager::repositories()))
#if NetCoMi doesn't work, you may need to install git on your computer https://git-scm.com/downloads
In the end this is the libraries you’ll need (You probably have most
of em already + there aren’t special download instructions, use
biocmanager for phyloseq, and speedyseq)
Load your phylosq object!
physeq_Key <- readRDS("C:\\Users\\angus\\OneDrive - UNBC\\Angus Ball\\Lab work\\Bioinformatics\\Lisas data\\R objects\\physeq_Key.rds")
Now I’m going to run ANCOMBC2 on a binary comparison (i.e. two
options), if you have 3+ comparisons please see the other tutorial!
This data has samples from a treated area and control area, we only
need year 1 samples for this analysis so lets subset them now
physeq_yr1 <- subset_samples(physeq_Key, Years == "1")
We are also going to run this analysis on a Family level. I recommend
running this analysis at a family and genus level (Especially if you are
working with fungi, since then you can still use Fungaltraits to look at
species comparisons). But you’re welcome to use any taxon level you
like!
physeq_glom <- speedyseq::tax_glom(physeq_yr1, #physeq object
taxrank = "Family", #taxa you want to conglomerate to
NArm = FALSE) #dont remove NA taxa
Then we have some data management to do!
#First remove any taxa with a sum of sequence counts equal to zero (You might have this if you have removed specific samples from your analysis)
physeq_glompruned <- prune_taxa(taxa_sums(physeq_glom) >0, physeq_glom)
#Then we are going to rename the taxa, this is why we downloaded netcomi, so especially in fungal taxonomy there are taxa with the same name even at a family level! its all very confusing and annoying. This next function efffectively just renames all the duplicates to taxa_1 taxa_2 ect so we can determine what species actually are differentially abundant
physeq_Key_renamed <- renameTaxa(physeq_glompruned,
pat = "<name>",
substPat = "<name>_<subst_name>(<subst_R>)",
numDupli = "Family") #Change family to taxon of interest
Columns 6 contain NAs only and are ignored.Columns 7 contain NAs only and are ignored.
ANCOM will remove taxa that arent present (or prevalent) in enough
samples so theres some statistical trust in the difference (i.e. there
could be a massive difference between the relative abundance of a taxa
in treated compared to control, but if its only because of one sample
does it really mean anything?)
However this seems to only work for the actual statistical test not
the pretest structural zero measurement! so we’ll just help ancombc by
running the prevelance filter first with yet another package
physeq_prev <- metagMisc::phyloseq_filter_prevalence(physeq_Key_renamed, prev.trh = 0.1) #this makes sure to only include samples with a prevelance over 10% (0.1) (i.e taxa must be present in 10% of samples).
PS. do you NEED to rename your physeq object after each command? of
course not! hell you can run all these things under one command with
enough %>% pipes, but since I usually make these code decks first
troubleshooting comes up ALOT, so having seperate names lets me easily
know where things go wrong.
We’ll also extract the taxa table from the phyloseq object, this
becomes important later on
family_taxa <- as(phyloseq::tax_table(physeq_prev), "matrix")
family_taxa <- as.data.frame(family_taxa)
For whatever reason you cant feed ancombc a phyloseq object so uhh
make this dumb rando object with mia
year1 = mia::makeTreeSummarizedExperimentFromPhyloseq(physeq_prev)
Most of my names will be year1_something, thats just because of how I
did my analysis and what this data says! feel free to change it at your
hearts content
Now… run ancombc
output_year1 = ancombc2(data = year1, #data
assay_name = "counts", #arbitrary name
tax_level = "Family", #level of comparison, like "Family", NULL is base level (ASV)
fix_formula = "Treat", #covariate that controls similar samples
rand_formula = NULL, #do microbial abundances have reandom effects in data? lets hope not...
p_adj_method = "holm", # p value adjust method
pseudo_sens = TRUE, #ANCOM-BC2 doesn't use a zero count, but it measures the effect a pseudocount will have on your data, how nice!
prv_cut = 0.1, #means taxa need to have non-zero counts in over 10% of samples, BUT doesn't work for structural zeros, therefore we have the change above too
lib_cut = 0, #removes samples with less reads than this number
s0_perc = 0.05,#this protets you from rare taxa being signifigantly different just because of small standard errors and not differential abundance
group = "Treat", #comparison group, must be in covariate list
struc_zero = TRUE, #structural zeros mean the sample is fully absent in one sample type compared to the other
#i.e. if you were comparing a rainforest and a desert there would be a bunch of structural zeros clouding the analysis
#by saying yes here the program checks for structural zeros and if it finds any it automatically decides they are differentially abundant (bc they are)
neg_lb = FALSE,#makes the definition of struct_zero a bit wider, recommended if sample size is over 30 per group
alpha = 0.05, #hopefully you know what this one is ;)
n_cl = 1, #how many nodes/clusters to be used, if youre on a windows or mac just say 1
verbose = TRUE,#talkative >:]
global = FALSE, #perform global test y/n
pairwise = FALSE, #hey want to do pairwise tests for multiple group comparisons make this true!
dunnet = FALSE, #dunnets test involves the use of a control group so weird dont use?
trend = FALSE, #another random test
)
Checking the input data type ...
The input data is of type: TreeSummarizedExperiment
PASS
Checking the sample metadata ...
The specified variables in the formula: Treat
The available variables in the sample metadata: LW., block.site.ID..true.replicates., Treated.or.Control, Plot....repeated.measures.within.each.replicate., Years.post.treatment..controls.are.not.treated.but.coordinate.with.blocks.of.those.treatment.years., Total.Mass.g., Course.Fragment.Mass.g., percent.coarse.fragment, Colour, Texturing, BlockTreat, Years, YearsTreat, Block, Treat, TreatBlock
PASS
Checking other arguments ...
The number of groups of interest is: 2
Warning: The group variable has < 3 categories
The multi-group comparisons (global/pairwise/dunnet/trend) will be deactivatedThe sample size per group is: control = 22, treated = 23
PASS
Obtaining initial estimates ...
Estimating sample-specific biases ...
Loading required package: foreach
Attaching package: ‘foreach’
The following objects are masked from ‘package:purrr’:
accumulate, when
Loading required package: rngtools
Sensitivity analysis for pseudo-count addition to 0s: ...
ANCOM-BC2 primary results ...
Extract the structural zero data… (go read the ancombc paper if you
don’t know what it is)
#which families are structural zeros?
tab_zero_year1 = output_year1$zero_ind #extract the structural zero data
tab_zero_year1 %>%
datatable(caption = "The detection of structural zeros") #display it nice
#this only has the family label on it, lets add some more information from the family taxa dataframe we extracted early
tab_zero_year1_bound <- cbind(tab_zero_year1, family_taxa) #this just matches columns with the same information in them
#remove random columns
tab_zero_year1_clean <- select(tab_zero_year1_bound, -"taxon", -"Genus", -"Species")
#now lets make a table of taxons that are only structural zeros
#structural zeros in mineral layer
tab_zero_year1_Sig_control <- dplyr::filter(tab_zero_year1_clean, `structural_zero (Treat = control)` == TRUE ) #im filtering them based on if they were from the control or treated fractions
#Structural zeros in organic layer
tab_zero_year1_Sig_treated <- dplyr::filter(tab_zero_year1_clean, `structural_zero (Treat = treated)` == TRUE )
# you can now use these tables and maybe make some kind of graphic to display which of these taxa are structural zeros?
Now lets extract the meat and potatoes of our data
res_prim_year1 = output_year1$res
Now lets make a nice graph/readable tables from it, because if you
look at res_prim_year1 oh boy is there alot of random stuff.
df_sig_y1 = res_prim_year1 %>%
dplyr::select(taxon, contains("Treat")) %>% #First we want to select samples that are for the treat comparison (this is only important if you have multiple comparisons at play)
dplyr::filter(diff_Treattreated == "TRUE") %>% #then select taxa that passed the differential abundance test diff_
dplyr::filter(passed_ss_Treattreated == "TRUE") #then select taxa that passed the sensitivity analysis (again go read the ancombc paper)
#a reminder for a taxa to be included in your results it must pass BOTH the sensitivity analysis and differential abundnace tests
#then we can add some useful information from our family taxa table to this datatable
df_sig_y1 <- merge(family_taxa, df_sig_y1, by.y = "taxon", by.x = "Family")
df_sig_y1 <- df_sig_y1 %>%
dplyr::arrange(desc(lfc_Treattreated)) %>%
dplyr::mutate(direct = ifelse(lfc_Treattreated > 0, "Positive LFC", "Negative LFC"))
df_sig_y1
So theres alot going on here… lfc_ represents the lofc fold change
from the alternate comparison group lfc_(intercept) can be ignored, its
a stats thing that has no bearing on your conclusions
se_ is standard error
W_ and p_ are our test statistics and p value, but only worry about
q_ which is our family-wise error rate adjusted p value.
Now lets make a pretty graph!
fig_y1 = df_sig_y1 %>%
dplyr::mutate(Family = fct_reorder(Family, dplyr::desc(lfc_Treattreated))) %>% #reorders taxa log fold change in a descending pattern
ggplot(aes(x = Family, y = lfc_Treattreated, fill = direct)) +
geom_bar(stat = "identity", width = 0.7, color = "black",
position = position_dodge(width = 0.4)) + #adds the lfc change itself
geom_errorbar(aes(ymin = lfc_Treattreated - se_Treattreated, ymax = lfc_Treattreated + se_Treattreated),
width = 0.2, position = position_dodge(0.05), color = "black") + #adds our error bars
labs(x = NULL, y = "Log fold change",
title = "Log fold changes of fungi families after treatment in one year old plots") + #er title...
scale_fill_discrete(name = NULL) +
scale_color_discrete(name = NULL) +
theme_bw() + #ggplot fun theme stuff, feel free to play around
theme(plot.title = element_text(hjust = 0.5),
panel.grid.minor.y = element_blank(),
axis.text.x = element_text(angle = 60, hjust = 1
)) # This makes the names at the bottom of the graph all cool and sideways looking
fig_y1

And you’re done! In the next tutorial I will show the difference
between multiple group comparisons
LS0tDQp0aXRsZTogIkFOQ09NQkMyX3R3byINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQpCeSBBbmd1cyBCYWxsIA0KDQpIYWQgZW5vdWdoIG9mIG1lIGJ5IG5vdz8geW91IGNhbiBhbHNvIHJlYWQgdGhlIGRldnMgdHV0b3JpYWwgaGVyZTogaHR0cHM6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvdmlnbmV0dGVzL0FOQ09NQkMvaW5zdC9kb2MvQU5DT01CQy5odG1sDQoNCg0KV2VsY29tZSB0byB0aGUgZnJheSEgQU5DT00tQkMtMiBpcyBncmVhdCBhbmQgaGFzIGFsb3Qgb2YgY29vbCBmZWF0dXJlcywgcmVhZCBhYm91dCBlbSAoYW5kIHVuZGVyc3RhbmQgdGhlbSA+OlshIChUaGVzZSBhcmUgdGhlIHNhbWUgYXMgdGhlIG9uZXMgb24gdGhlIGdpdCk6DQoNClNvIHdoYXQncyBBTkNPTS1CQy0yJ3MgZGVhbD8NCg0KICAtTXVsdGlwbGUgcGFpcndpc2UgY29tcGFyaXNvbnMhISBUaGlzIG1heSBub3Qgc291bmQgbGlrZSBhIGJpZyBkZWFsIGJ1dCB0aGlzIGlzIHRoZSBmaXJzdCBwcm9ncmFtIEkndmUgZW5jb3VudGVyZWQgdGhhdCBwcm9taXNlcyBpdCdsbCBkbyBhbGwgdGhlIGNvbXBhcmlzb25zIHlvdSBjYXJlIGFib3V0IGluIGdyb3VwcyBvZiAzKyByYXRoZXIgdGhhbiBqdXN0IGhhdmluZyBhIHJlZmVyZW5jZSB0YXhvbiBhbmQgeW91IGhhdmUgdG8gZmlkZGxlIGFyb3VuZCB3aXRoIGl0LiAoaXQnbGwgYWxzbyBkbyBiaW5hcnkgY29tcGFyaXNvbnMpDQoNCiAgLVBhdHRlcm4gYW5hbHlzaXMgb3ZlciBvcmRlcmVkIHN0dWR5IGdyb3VwcyAoZWZmZWN0aXZlbHkgcGFpcndpc2UgY29tcGFyaXNvbnMgYnV0IHdpdGggYSBmdXp6ZXIgaW1hZ2UpDQoNCiAgLUFOQ09NLUJDLTIgd2lsbCBhbHNvIGFjY291bnQgZm9yIHRheG9uLXNwZWNpZmljIGJpYXMuIFJlbWVtYmVyIGhvdyBjaG9vc2luZyB5b3VyIFBDUiBwcmltZXJzIHdhcyBzbyBpbXBvcnRhbnQ/IGJlY2F1c2UgdGhleSB3aWxsIHByZWZlcmVudGlhbGx5IGJpYXMgY2VydGFpbiB0YXhvbnM/IEFOQ09NQkMyIHByb21pc2VzIHRvIGFjY291bnQgZm9yIHRoaXMgaW4geW91ciBkYXRhLg0KDQogIC0oVGhpcyBvbmUgaXMgcmVhbGx5IGNvb2wpIEFOQ09NQkMyIHdpbGwgcGVyZm9ybSBzZW5zaXRpdml0eSBhbmFseXNpcyBiYXNlZCBvbiBjaG9pY2Ugb2YgcHNldWRvLWNvdW50LiBTZWUgcHNldWRvLWNvdW50IGNhbiBjaGFuZ2UgeW91ciByZXN1bHRzIChzcGVjaWZpY2FsbHkgcmVnYXJkaW5nIHJhcmUgdGF4YSBhcyB0aGV5IGFyZSBtb3JlIGJpYXNlZCBieSB0aGUgcHN1ZWRvLWNvdW50KSwgbGVhZGluZyB0byBhbiBpbmZsYXRlZCBGRFIuIEFOQ09NQkMyIHdpbGwgcnVuIHRoZSBhbmFseXNpcyB3aXRoIG11bHRpcGxlIHBzZXVkby1jb3VudHMgYW5kIHNlZSBob3cgdGhleSBlZmZlY3QgdGhlIHJlc3VsdHMgYW5kIGZpbHRlciBvdXQgdGF4YSB0aGF0IGFyZSBzaWduaWZpY2FudGx5IGFmZmVjdGVkIGJ5IHBzZXVkby1jb3VudC4NCg0KICAtQU5DT01CQzIga25vd3MgYWJvdXQgY29tcG9zaXRpb25hbGl0eSBhbmQgaG93IHNjYXJ5IGl0IGlzLiBTZWUgd2UgdXNlIHJlbGF0aXZlIGFidW5kYW5jZSBiZWNhdXNlIG1pY3JvYmlvbWUgZGF0YSBpcyBjb21wb3NpdGlvbmFsLCBidXQgYSBjaGFuZ2UgaW4gdGhlIGFic29sdXRlIGFidW5kYW5jZSBvZiBhIHNpbmdsZSB0YXhvbiBjYW4gYWx0ZXIgdGhlIHJlbGF0aXZlIGFidW5kYW5jZXMgb2YgYWxsIHRheGEgKFRoaXMgaXMgc2hvY2tpbmdseSBub3QgZ3JlYXQpLiBUaGVyZWZvcmUsIHdoZW4gd2UgaHlwb3RoZXNpcyB0ZXN0IGNvbXBhcmluZyByZWxhdGl2ZSBhYnVuZGFuY2VzIGlzIG5vdCBlcXVpdmFsZW50IHRvIGFic29sdXRlIGFidW5kYW5jZXMuIFJlbGF0aXZlIGFidW5kYW5jZS8gc2FtcGxpbmcgZnJhY3Rpb24gY2FuIGJlIGFmZmVjdGVkIGJ5IHRoZSBtaWNyb2JpYWwgbG9hZCBpbiB0aGUgc3lzdGVtIGFuZCBsaWJyYXJ5IHNpemUuIExpYnJhcnkgc2l6ZSBpcyBzaW1wbGUgdG9vIHNtYWxsIGEgbGlicmFyeSBzaXplIHlvdSBkb24ndCBoaXQgdGhlIGltcG9ydGFudCBwYXJ0cyBvZiB5b3VyIHJhcmVmYWN0aW9uIGN1cnZlIGFuZCB5b3UgbWlzcyBvdXQgb24gc3BlY2llcy4gTWljcm9iaWFsIGxvYWQgaXMgYSBiaXQgbW9yZSBjb21wbGV4IChhbmQgZXhwbGFpbmVkIHdlbGwgaW4gdGhlIEFOQ09NQkMgcGFwZXIpLiBCdXQgaW4gc2hvcnQgdHdvIGVjb3N5c3RlbXMvc2FtcGxlcyBjYW4gaGF2ZSB0aGUgc2FtZSByZWxhdGl2ZSBhYnVuZGFuY2UgYW5kIGxpYnJhcnkgc2l6ZXMgb2YgYSB0YXhvbiwgYnV0IHRoZWlyIGFic29sdXRlIHBvcHVsYXRpb24gc2l6ZSwgb3IgbWljcm9iaWFsIGxvYWQsIGlzIGRpZmZlcmVudC4gSWYgeW91IGRvbid0IGFjY291bnQgZm9yIHRoaXMgdGhlbiB5b3UnZCBzYXkgdGhlIHR3byBlY29zeXN0ZW1zIGFyZSB0aGUgc2FtZSAod3JvbmcpLiBBTkNPTUJDIGFjY291bnRzIGZvciBtaWNyb2JpYWwgbG9hZCBieSBpbnRyb2R1Y2luZyBhIHNhbXBsZS1zcGVjaWZpYyBvZmZzZXQgdGVybSB0byBiaWFzIGNvcnJlY3QgZm9yIHRoZSBtaWNyb2JpYWwgbG9hZCBhbmQgY29uc3RpdHV0aW9uYWxpdHkgb2YgbWljcm9iaW9tZSBkYXRhLg0KDQogIC1QcmVmb3JtcyB3b3JzZSB3aGVuIHNhbXBsZSBzaXplIGlzIHNtYWxsIChuID0gNSksIGFuZCBydW5zIHBlcmZlY3RseSB3aGVuIG4gPj0gMTANCg0KICAtQWNjb3VudHMgZm9yIHN0cnVjdHVyYWwgemVyb3MuIFN0cnVjdHVyYWwgemVyb3MgYXJlIGRlZmluZWQgYXMgdGF4b25zIHByZXNlbnQgaW4gb25lIHNhbXBsZSB0eXBlIGFuZCBub3QgcHJlc2VudCBpbiBhbm90aGVyIChpLmUuIGltYWdpbmUgY29tcGFyaW5nIHNhbXBsZXMgZnJvbSBhIGp1bmdsZSB0byBhIGZvcmVzdCwgdGhlcmUnbGwganVzdCBiZSBzb21lIHNwZWNpZXMgdGhhdCBzdHJhaWdodCB1cCBkb24ndCBleGlzdCBpbiBvbmUgZW52aXJvbm1lbnQgb3IgdGhlIG90aGVyIGFuZCB0aGlzIGlzIGV4cGVjdCkuIFlvdSBjYW4ndCByZWFsbHkgZG8gc3RhdHMgb24gdGhlc2Ugc3RydWN0dXJhbCB6ZXJvcyBiZWNhdXNlIGl0cyBqdXN0IG5vdCB0aGVyZSBpbiBvbmUgc2FtcGxlLiBTbyB3ZSdsbCBoYXZlIHRvIGV4YW1pbmUgdGhpcyBkaWZmZXJlbnRseSAoYW5kIHN1YmplY3RpdmVseSkuIFBsZWFzZSBnaXZlIE5hdWdodCBhbGwgemVyb3MgaW4gc2VxdWVuY2UgY291bnQgZGF0YSBhcmUgdGhlIHNhbWUgYSBza2ltIGl0IGhhcyBzb21lIHN0dWZmIHRvIHNheSBhYm91dCB6ZXJvcyAoaWYgeW91IGNvdWxkbid0IGd1ZXNzIGJ5IHRoZSB0aXRsZSkuIFN0cnVjdHVyYWwgemVyb3MgYXJlIGNhbGxlZCBiaW9sb2dpY2FsIHplcm9zIGluIHRoaXMgcGFwZXIuIE5vdyB0aGlzIGJlaW5nIHNhaWQgdGhlIHdheSB0aGVzZSBzdHJ1Y3R1cmFsIHplcm9zIGFyZSBkZWZpbmVkIGlzIGEgYml0IHN1c3BlY3QuIFNlZSBpZiB5b3VyIGxpYnJhcnkgc2l6ZSBpbiBzb21lIHNhbXBsZXMgaXMgdG9vIHNtYWxsIGl0IHdvbid0IHBpY2sgdXAgcmFyZSB0YXhhIGF0IGFsbCEgc28gdGhlc2UgcmFyZSB0YXhhIG1pZ2h0IGJlIGVycm9uZW91c2x5IHBpY2tlZCB1cCBhcyBzdHJ1Y3R1cmFsIHplcm9zICh3aGVyZSB0aGV5IHNob3VsZCBiZSBjYWxsZWQgc2FtcGxpbmcgemVyb3MpLiBIb3dldmVyLCBpbiBteSBodW1ibGUgb3BpbmlvbiB1c2luZyB0aGUgc2FtZSBzZXF1ZW5jaW5nIHRlY2ggYW5kIHByaW1lcnMgc2hvdWxkIG1pdGlnYXRlIHRoZSBpc3N1ZXMgd2l0aCBzYW1wbGluZyB6ZXJvcyAoYW5kIHRlY2huaWNhbCB6ZXJvcykgYXMgeW91J2QgZXhwZWN0IGVxdWFsIHZhcmlvdXMgYW1vbmcgc2FtcGxlcy4gQU5DT01CQyBza2lydHMgc29tZSBvZiB0aGVzZSBpc3N1ZXMgYnkgZmlyc3QgZmlsdGVyIHRheGEgdG8gaGF2ZSB0byBleGlzdCBpbiBhIGNlcnRhaW4gYW1vdW50IG9mIHNhbXBsZXMgKDEwJSBieSBkZWZhdWx0KSB0byBnZXQgYXJvdW5kIHJhcmUgdGF4YSBnZXR0aW5nIHBpY2tlZCB1cCBqdXN0IGJlY2F1c2UgdGhleSBhcmUgcmFyZS4NCg0KDQoNCkNvb2wsIHNvIGhvdyBkbyB3ZSBnZXQgQU5DT01CQyBydW5uaW5nPywgd2VsbCBUaGlzIHBhY2thZ2UgaXMgbmV3IGFzIGhlbGwsIGFuZCB0aGUgYmlvY21hbmFlciB2ZXJzaW9uIGlzbid0IHVwIHRvIGRhdGUsIHNvIHdlJ2xsIGJlIGRvd25sb2FkaW5nIHN0cmFpZ2h0IG9mZiBvZiB0aGUgZ2l0aHViDQpgYGB7cn0NCiNIZXJlcyBob3cgdG8gaW5zdGFsbCBpdA0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJGcmVkZXJpY2tIdWFuZ0xpbi9BTkNPTUJDIiwgYnJhbmNoID0gImJ1Z2ZpeCIpDQpgYGANCml0IHVoaCB0YWtlcyBhIHNlY29uZA0KDQoNCllvdSdsbCBhbHNvIG5lZWQgdGhlc2UgcGFja2FnZXMgKFdoaWNoIHlvdSBwcm9iYWJseSBkb24ndCBoYXZlKQ0KYGBge3J9DQojQWxzbyBkb3dubG9hZCB0aGVzZSBiYWQgYm95cw0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ2bWlray9tZXRhZ01pc2MiKQ0KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ6ZGsxMjMvU3BpZWNFYXNpIikNCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiR3JhY2VZb29uL1NQUklORyIpDQoNCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigic3RlZnBlc2NoZWwvTmV0Q29NaSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRlcGVuZGVuY2llcyA9IGMoIkRlcGVuZHMiLCAiSW1wb3J0cyIsICJMaW5raW5nVG8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICByZXBvcyA9IGMoImh0dHBzOi8vY2xvdWQuci1wcm9qZWN0Lm9yZy8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCaW9jTWFuYWdlcjo6cmVwb3NpdG9yaWVzKCkpKQ0KDQojaWYgTmV0Q29NaSBkb2Vzbid0IHdvcmssIHlvdSBtYXkgbmVlZCB0byBpbnN0YWxsIGdpdCBvbiB5b3VyIGNvbXB1dGVyIGh0dHBzOi8vZ2l0LXNjbS5jb20vZG93bmxvYWRzDQpgYGANCg0KDQpJbiB0aGUgZW5kIHRoaXMgaXMgdGhlIGxpYnJhcmllcyB5b3UnbGwgbmVlZCAoWW91IHByb2JhYmx5IGhhdmUgbW9zdCBvZiBlbSBhbHJlYWR5ICsgdGhlcmUgYXJlbid0IHNwZWNpYWwgZG93bmxvYWQgaW5zdHJ1Y3Rpb25zLCB1c2UgYmlvY21hbmFnZXIgZm9yIHBoeWxvc2VxLCBhbmQgc3BlZWR5c2VxKQ0KDQpgYGB7cn0NCiNsaWJyYXJpZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShBTkNPTUJDKQ0KbGlicmFyeShOZXRDb01pKQ0KbGlicmFyeShzcGVlZHlzZXEpDQpsaWJyYXJ5KG1pYSkNCmxpYnJhcnkocGh5bG9zZXEpDQpsaWJyYXJ5KG1ldGFnTWlzYykNCmxpYnJhcnkoRFQpDQpgYGANCg0KTG9hZCB5b3VyIHBoeWxvc3Egb2JqZWN0IQ0KYGBge3J9DQpwaHlzZXFfS2V5IDwtIHJlYWRSRFMoIkM6XFxVc2Vyc1xcYW5ndXNcXE9uZURyaXZlIC0gVU5CQ1xcQW5ndXMgQmFsbFxcTGFiIHdvcmtcXEJpb2luZm9ybWF0aWNzXFxMaXNhcyBkYXRhXFxSIG9iamVjdHNcXHBoeXNlcV9LZXkucmRzIikNCmBgYA0KDQoNCg0KTm93IEknbSBnb2luZyB0byBydW4gQU5DT01CQzIgb24gYSBiaW5hcnkgY29tcGFyaXNvbiAoaS5lLiB0d28gb3B0aW9ucyksIGlmIHlvdSBoYXZlIDMrIGNvbXBhcmlzb25zIHBsZWFzZSBzZWUgdGhlIG90aGVyIHR1dG9yaWFsIQ0KDQpUaGlzIGRhdGEgaGFzIHNhbXBsZXMgZnJvbSBhIHRyZWF0ZWQgYXJlYSBhbmQgY29udHJvbCBhcmVhLCB3ZSBvbmx5IG5lZWQgeWVhciAxIHNhbXBsZXMgZm9yIHRoaXMgYW5hbHlzaXMgc28gbGV0cyBzdWJzZXQgdGhlbSBub3cNCmBgYHtyfQ0KcGh5c2VxX3lyMSA8LSBzdWJzZXRfc2FtcGxlcyhwaHlzZXFfS2V5LCBZZWFycyA9PSAiMSIpDQpgYGANCg0KDQpXZSBhcmUgYWxzbyBnb2luZyB0byBydW4gdGhpcyBhbmFseXNpcyBvbiBhIEZhbWlseSBsZXZlbC4gSSByZWNvbW1lbmQgcnVubmluZyB0aGlzIGFuYWx5c2lzIGF0IGEgZmFtaWx5IGFuZCBnZW51cyBsZXZlbCAoRXNwZWNpYWxseSBpZiB5b3UgYXJlIHdvcmtpbmcgd2l0aCBmdW5naSwgc2luY2UgdGhlbiB5b3UgY2FuIHN0aWxsIHVzZSBGdW5nYWx0cmFpdHMgdG8gbG9vayBhdCBzcGVjaWVzIGNvbXBhcmlzb25zKS4gQnV0IHlvdSdyZSB3ZWxjb21lIHRvIHVzZSBhbnkgdGF4b24gbGV2ZWwgeW91IGxpa2UhDQoNCmBgYHtyfQ0KcGh5c2VxX2dsb20gPC0gc3BlZWR5c2VxOjp0YXhfZ2xvbShwaHlzZXFfeXIxLCAjcGh5c2VxIG9iamVjdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheHJhbmsgPSAiRmFtaWx5IiwgI3RheGEgeW91IHdhbnQgdG8gY29uZ2xvbWVyYXRlIHRvDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFybSA9IEZBTFNFKSAjZG9udCByZW1vdmUgTkEgdGF4YQ0KYGBgDQoNClRoZW4gd2UgaGF2ZSBzb21lIGRhdGEgbWFuYWdlbWVudCB0byBkbyENCg0KYGBge3J9DQojRmlyc3QgcmVtb3ZlIGFueSB0YXhhIHdpdGggYSBzdW0gb2Ygc2VxdWVuY2UgY291bnRzIGVxdWFsIHRvIHplcm8gKFlvdSBtaWdodCBoYXZlIHRoaXMgaWYgeW91IGhhdmUgcmVtb3ZlZCBzcGVjaWZpYyBzYW1wbGVzIGZyb20geW91ciBhbmFseXNpcykNCnBoeXNlcV9nbG9tcHJ1bmVkIDwtIHBydW5lX3RheGEodGF4YV9zdW1zKHBoeXNlcV9nbG9tKSA+MCwgcGh5c2VxX2dsb20pDQoNCiNUaGVuIHdlIGFyZSBnb2luZyB0byByZW5hbWUgdGhlIHRheGEsIHRoaXMgaXMgd2h5IHdlIGRvd25sb2FkZWQgbmV0Y29taSwgc28gZXNwZWNpYWxseSBpbiBmdW5nYWwgdGF4b25vbXkgdGhlcmUgYXJlIHRheGEgd2l0aCB0aGUgc2FtZSBuYW1lIGV2ZW4gYXQgYSBmYW1pbHkgbGV2ZWwhIGl0cyBhbGwgdmVyeSBjb25mdXNpbmcgYW5kIGFubm95aW5nLiBUaGlzIG5leHQgZnVuY3Rpb24gZWZmZmVjdGl2ZWx5IGp1c3QgcmVuYW1lcyBhbGwgdGhlIGR1cGxpY2F0ZXMgdG8gdGF4YV8xIHRheGFfMiBlY3Qgc28gd2UgY2FuIGRldGVybWluZSB3aGF0IHNwZWNpZXMgYWN0dWFsbHkgYXJlIGRpZmZlcmVudGlhbGx5IGFidW5kYW50IA0KDQpwaHlzZXFfS2V5X3JlbmFtZWQgPC0gcmVuYW1lVGF4YShwaHlzZXFfZ2xvbXBydW5lZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXQgPSAiPG5hbWU+IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzdFBhdCA9ICI8bmFtZT5fPHN1YnN0X25hbWU+KDxzdWJzdF9SPikiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtRHVwbGkgPSAiRmFtaWx5IikgI0NoYW5nZSBmYW1pbHkgdG8gdGF4b24gb2YgaW50ZXJlc3QNCg0KYGBgDQoNCkFOQ09NIHdpbGwgcmVtb3ZlIHRheGEgdGhhdCBhcmVudCBwcmVzZW50IChvciBwcmV2YWxlbnQpIGluIGVub3VnaCBzYW1wbGVzIHNvIHRoZXJlcyBzb21lIHN0YXRpc3RpY2FsIHRydXN0IGluIHRoZSBkaWZmZXJlbmNlIChpLmUuIHRoZXJlIGNvdWxkIGJlIGEgbWFzc2l2ZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBhIHRheGEgaW4gdHJlYXRlZCBjb21wYXJlZCB0byBjb250cm9sLCBidXQgaWYgaXRzIG9ubHkgYmVjYXVzZSBvZiBvbmUgc2FtcGxlIGRvZXMgaXQgcmVhbGx5IG1lYW4gYW55dGhpbmc/KQ0KDQpIb3dldmVyIHRoaXMgc2VlbXMgdG8gb25seSB3b3JrIGZvciB0aGUgYWN0dWFsIHN0YXRpc3RpY2FsIHRlc3Qgbm90IHRoZSBwcmV0ZXN0IHN0cnVjdHVyYWwgemVybyBtZWFzdXJlbWVudCEgc28gd2UnbGwganVzdCBoZWxwIGFuY29tYmMgYnkgcnVubmluZyB0aGUgcHJldmVsYW5jZSBmaWx0ZXIgZmlyc3Qgd2l0aCB5ZXQgYW5vdGhlciBwYWNrYWdlDQoNCmBgYHtyfQ0KcGh5c2VxX3ByZXYgPC0gbWV0YWdNaXNjOjpwaHlsb3NlcV9maWx0ZXJfcHJldmFsZW5jZShwaHlzZXFfS2V5X3JlbmFtZWQsIHByZXYudHJoID0gMC4xKSAjdGhpcyBtYWtlcyBzdXJlIHRvIG9ubHkgaW5jbHVkZSBzYW1wbGVzIHdpdGggYSBwcmV2ZWxhbmNlIG92ZXIgMTAlICgwLjEpIChpLmUgdGF4YSBtdXN0IGJlIHByZXNlbnQgaW4gMTAlIG9mIHNhbXBsZXMpLiANCg0KYGBgDQoNClBTLiBkbyB5b3UgTkVFRCB0byByZW5hbWUgeW91ciBwaHlzZXEgb2JqZWN0IGFmdGVyIGVhY2ggY29tbWFuZD8gb2YgY291cnNlIG5vdCEgaGVsbCB5b3UgY2FuIHJ1biBhbGwgdGhlc2UgdGhpbmdzIHVuZGVyIG9uZSBjb21tYW5kIHdpdGggZW5vdWdoICU+JSBwaXBlcywgYnV0IHNpbmNlIEkgdXN1YWxseSBtYWtlIHRoZXNlIGNvZGUgZGVja3MgZmlyc3QgdHJvdWJsZXNob290aW5nIGNvbWVzIHVwIEFMT1QsIHNvIGhhdmluZyBzZXBlcmF0ZSBuYW1lcyBsZXRzIG1lIGVhc2lseSBrbm93IHdoZXJlIHRoaW5ncyBnbyB3cm9uZy4NCg0KV2UnbGwgYWxzbyBleHRyYWN0IHRoZSB0YXhhIHRhYmxlIGZyb20gdGhlIHBoeWxvc2VxIG9iamVjdCwgdGhpcyBiZWNvbWVzIGltcG9ydGFudCBsYXRlciBvbg0KDQpgYGB7cn0NCmZhbWlseV90YXhhIDwtIGFzKHBoeWxvc2VxOjp0YXhfdGFibGUocGh5c2VxX3ByZXYpLCAibWF0cml4IikNCmZhbWlseV90YXhhIDwtIGFzLmRhdGEuZnJhbWUoZmFtaWx5X3RheGEpDQpgYGANCg0KDQpGb3Igd2hhdGV2ZXIgcmVhc29uIHlvdSBjYW50IGZlZWQgYW5jb21iYyBhIHBoeWxvc2VxIG9iamVjdCBzbyB1aGggbWFrZSB0aGlzIGR1bWIgcmFuZG8gb2JqZWN0IHdpdGggbWlhDQoNCmBgYHtyfQ0KeWVhcjEgPSBtaWE6Om1ha2VUcmVlU3VtbWFyaXplZEV4cGVyaW1lbnRGcm9tUGh5bG9zZXEocGh5c2VxX3ByZXYpDQoNCmBgYA0KDQpNb3N0IG9mIG15IG5hbWVzIHdpbGwgYmUgeWVhcjFfc29tZXRoaW5nLCB0aGF0cyBqdXN0IGJlY2F1c2Ugb2YgaG93IEkgZGlkIG15IGFuYWx5c2lzIGFuZCB3aGF0IHRoaXMgZGF0YSBzYXlzISBmZWVsIGZyZWUgdG8gY2hhbmdlIGl0IGF0IHlvdXIgaGVhcnRzIGNvbnRlbnQNCg0KTm93Li4uIHJ1biBhbmNvbWJjDQoNCmBgYHtyfQ0Kb3V0cHV0X3llYXIxID0gYW5jb21iYzIoZGF0YSA9IHllYXIxLCAjZGF0YQ0KICAgICAgICAgICAgICAgICAgYXNzYXlfbmFtZSA9ICJjb3VudHMiLCAjYXJiaXRyYXJ5IG5hbWUNCiAgICAgICAgICAgICAgICAgIHRheF9sZXZlbCA9ICJGYW1pbHkiLCAjbGV2ZWwgb2YgY29tcGFyaXNvbiwgbGlrZSAiRmFtaWx5IiwgTlVMTCBpcyBiYXNlIGxldmVsIChBU1YpDQogICAgICAgICAgICAgICAgICBmaXhfZm9ybXVsYSA9ICJUcmVhdCIsICNjb3ZhcmlhdGUgdGhhdCBjb250cm9scyBzaW1pbGFyIHNhbXBsZXMNCiAgICAgICAgICAgICAgICAgIHJhbmRfZm9ybXVsYSA9IE5VTEwsICNkbyBtaWNyb2JpYWwgYWJ1bmRhbmNlcyBoYXZlIHJlYW5kb20gZWZmZWN0cyBpbiBkYXRhPyBsZXRzIGhvcGUgbm90Li4uDQogICAgICAgICAgICAgICAgICBwX2Fkal9tZXRob2QgPSAiaG9sbSIsICMgcCB2YWx1ZSBhZGp1c3QgbWV0aG9kDQogICAgICAgICAgICAgICAgICBwc2V1ZG9fc2VucyA9IFRSVUUsICNBTkNPTS1CQzIgZG9lc24ndCB1c2UgYSB6ZXJvIGNvdW50LCBidXQgaXQgbWVhc3VyZXMgdGhlIGVmZmVjdCBhIHBzZXVkb2NvdW50IHdpbGwgaGF2ZSBvbiB5b3VyIGRhdGEsIGhvdyBuaWNlIQ0KICAgICAgICAgICAgICAgICAgcHJ2X2N1dCA9IDAuMSwgI21lYW5zIHRheGEgbmVlZCB0byBoYXZlIG5vbi16ZXJvIGNvdW50cyBpbiBvdmVyIDEwJSBvZiBzYW1wbGVzLCBCVVQgZG9lc24ndCB3b3JrIGZvciBzdHJ1Y3R1cmFsIHplcm9zLCB0aGVyZWZvcmUgd2UgaGF2ZSB0aGUgY2hhbmdlIGFib3ZlIHRvbw0KICAgICAgICAgICAgICAgICAgbGliX2N1dCA9IDAsICNyZW1vdmVzIHNhbXBsZXMgd2l0aCBsZXNzIHJlYWRzIHRoYW4gdGhpcyBudW1iZXINCiAgICAgICAgICAgICAgICAgIHMwX3BlcmMgPSAwLjA1LCN0aGlzIHByb3RldHMgeW91IGZyb20gcmFyZSB0YXhhIGJlaW5nIHNpZ25pZmlnYW50bHkgZGlmZmVyZW50IGp1c3QgYmVjYXVzZSBvZiBzbWFsbCBzdGFuZGFyZCBlcnJvcnMgYW5kIG5vdCBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJUcmVhdCIsICNjb21wYXJpc29uIGdyb3VwLCBtdXN0IGJlIGluIGNvdmFyaWF0ZSBsaXN0DQogICAgICAgICAgICAgICAgICBzdHJ1Y196ZXJvID0gVFJVRSwgI3N0cnVjdHVyYWwgemVyb3MgbWVhbiB0aGUgc2FtcGxlIGlzIGZ1bGx5IGFic2VudCBpbiBvbmUgc2FtcGxlIHR5cGUgY29tcGFyZWQgdG8gdGhlIG90aGVyIA0KICAgICAgICAgICAgICAgICAgI2kuZS4gaWYgeW91IHdlcmUgY29tcGFyaW5nIGEgcmFpbmZvcmVzdCBhbmQgYSBkZXNlcnQgdGhlcmUgd291bGQgYmUgYSBidW5jaCBvZiBzdHJ1Y3R1cmFsIHplcm9zIGNsb3VkaW5nIHRoZSBhbmFseXNpcw0KICAgICAgICAgICAgICAgICAgI2J5IHNheWluZyB5ZXMgaGVyZSB0aGUgcHJvZ3JhbSBjaGVja3MgZm9yIHN0cnVjdHVyYWwgemVyb3MgYW5kIGlmIGl0IGZpbmRzIGFueSBpdCBhdXRvbWF0aWNhbGx5IGRlY2lkZXMgdGhleSBhcmUgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgKGJjIHRoZXkgYXJlKQ0KICAgICAgICAgICAgICAgICAgbmVnX2xiID0gRkFMU0UsI21ha2VzIHRoZSBkZWZpbml0aW9uIG9mIHN0cnVjdF96ZXJvIGEgYml0IHdpZGVyLCByZWNvbW1lbmRlZCBpZiBzYW1wbGUgc2l6ZSBpcyBvdmVyIDMwIHBlciBncm91cCANCiAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwgI2hvcGVmdWxseSB5b3Uga25vdyB3aGF0IHRoaXMgb25lIGlzIDspDQogICAgICAgICAgICAgICAgICBuX2NsID0gMSwgI2hvdyBtYW55IG5vZGVzL2NsdXN0ZXJzIHRvIGJlIHVzZWQsIGlmIHlvdXJlIG9uIGEgd2luZG93cyBvciBtYWMganVzdCBzYXkgMQ0KICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUsI3RhbGthdGl2ZSA+Ol0NCiAgICAgICAgICAgICAgICAgIGdsb2JhbCA9IEZBTFNFLCAjcGVyZm9ybSBnbG9iYWwgdGVzdCB5L24NCiAgICAgICAgICAgICAgICAgIHBhaXJ3aXNlID0gRkFMU0UsICNoZXkgd2FudCB0byBkbyBwYWlyd2lzZSB0ZXN0cyBmb3IgbXVsdGlwbGUgZ3JvdXAgY29tcGFyaXNvbnMgbWFrZSB0aGlzIHRydWUhIA0KICAgICAgICAgICAgICAgICAgZHVubmV0ID0gRkFMU0UsICNkdW5uZXRzIHRlc3QgaW52b2x2ZXMgdGhlIHVzZSBvZiBhIGNvbnRyb2wgZ3JvdXAgc28gd2VpcmQgZG9udCB1c2U/DQogICAgICAgICAgICAgICAgICB0cmVuZCA9IEZBTFNFLCAjYW5vdGhlciByYW5kb20gdGVzdA0KICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCg0KDQpFeHRyYWN0IHRoZSBzdHJ1Y3R1cmFsIHplcm8gZGF0YS4uLiAoZ28gcmVhZCB0aGUgYW5jb21iYyBwYXBlciBpZiB5b3UgZG9uJ3Qga25vdyB3aGF0IGl0IGlzKQ0KDQpgYGB7cn0NCg0KI3doaWNoIGZhbWlsaWVzIGFyZSBzdHJ1Y3R1cmFsIHplcm9zPw0KdGFiX3plcm9feWVhcjEgPSBvdXRwdXRfeWVhcjEkemVyb19pbmQgI2V4dHJhY3QgdGhlIHN0cnVjdHVyYWwgemVybyBkYXRhDQoNCnRhYl96ZXJvX3llYXIxICU+JQ0KICBkYXRhdGFibGUoY2FwdGlvbiA9ICJUaGUgZGV0ZWN0aW9uIG9mIHN0cnVjdHVyYWwgemVyb3MiKSAjZGlzcGxheSBpdCBuaWNlDQoNCg0KI3RoaXMgb25seSBoYXMgdGhlIGZhbWlseSBsYWJlbCBvbiBpdCwgbGV0cyBhZGQgc29tZSBtb3JlIGluZm9ybWF0aW9uIGZyb20gdGhlIGZhbWlseSB0YXhhIGRhdGFmcmFtZSB3ZSBleHRyYWN0ZWQgZWFybHkNCg0KdGFiX3plcm9feWVhcjFfYm91bmQgPC0gY2JpbmQodGFiX3plcm9feWVhcjEsIGZhbWlseV90YXhhKSAjdGhpcyBqdXN0IG1hdGNoZXMgY29sdW1ucyB3aXRoIHRoZSBzYW1lIGluZm9ybWF0aW9uIGluIHRoZW0NCg0KI3JlbW92ZSByYW5kb20gY29sdW1ucw0KdGFiX3plcm9feWVhcjFfY2xlYW4gPC0gc2VsZWN0KHRhYl96ZXJvX3llYXIxX2JvdW5kLCAtInRheG9uIiwgLSJHZW51cyIsIC0iU3BlY2llcyIpDQoNCg0KI25vdyBsZXRzIG1ha2UgYSB0YWJsZSBvZiB0YXhvbnMgdGhhdCBhcmUgb25seSBzdHJ1Y3R1cmFsIHplcm9zDQoNCiNzdHJ1Y3R1cmFsIHplcm9zIGluIG1pbmVyYWwgbGF5ZXINCnRhYl96ZXJvX3llYXIxX1NpZ19jb250cm9sIDwtIGRwbHlyOjpmaWx0ZXIodGFiX3plcm9feWVhcjFfY2xlYW4sIGBzdHJ1Y3R1cmFsX3plcm8gKFRyZWF0ID0gY29udHJvbClgID09IFRSVUUgKSAgI2ltIGZpbHRlcmluZyB0aGVtIGJhc2VkIG9uIGlmIHRoZXkgd2VyZSBmcm9tIHRoZSBjb250cm9sIG9yIHRyZWF0ZWQgZnJhY3Rpb25zLCB5b3UnbGwgbmVlZCB0byBjaGFuZ2UgdGhlIG5hbWVzIGluIHRoZSBicmFja2V0cyB0byB5b3VyIGRhdGEgdHlwZSENCg0KI1N0cnVjdHVyYWwgemVyb3MgaW4gb3JnYW5pYyBsYXllcg0KdGFiX3plcm9feWVhcjFfU2lnX3RyZWF0ZWQgPC0gZHBseXI6OmZpbHRlcih0YWJfemVyb195ZWFyMV9jbGVhbiwgYHN0cnVjdHVyYWxfemVybyAoVHJlYXQgPSB0cmVhdGVkKWAgPT0gVFJVRSApIA0KDQojIHlvdSBjYW4gbm93IHVzZSB0aGVzZSB0YWJsZXMgYW5kIG1heWJlIG1ha2Ugc29tZSBraW5kIG9mIGdyYXBoaWMgdG8gZGlzcGxheSB3aGljaCBvZiB0aGVzZSB0YXhhIGFyZSBzdHJ1Y3R1cmFsIHplcm9zIGlmIHlvdSB3YW50IG9yIGp1c3QgbGlzdCBlbSwgd2Ugb25seSBoYXZlIG9uZSBzdHJ1Y3R1cmFsIHplcm8gZm9yIHRoZSB0cmVhdGVkIHNhbXBsZXMhDQoNCiMgUFMgaXRzIGNhbGxlZCBUcmVhdCA9IGNvbnRyb2wgb3IgVHJlYXQgPSBUcmVhdGVkIGJlY2F1c2UgSSd2ZSBjYWxsZWQgbXkgY29sdW1uIGhlYWRlciBmb3IgdGhpcyBpbmZvcm1hdGlvbiBUcmVhdA0KDQpgYGANCg0KTm93IGxldHMgZXh0cmFjdCB0aGUgbWVhdCBhbmQgcG90YXRvZXMgb2Ygb3VyIGRhdGENCg0KDQpgYGB7cn0NCnJlc19wcmltX3llYXIxID0gb3V0cHV0X3llYXIxJHJlcw0KYGBgDQoNCg0KTm93IGxldHMgbWFrZSBhIG5pY2UgZ3JhcGgvcmVhZGFibGUgdGFibGVzIGZyb20gaXQsIGJlY2F1c2UgaWYgeW91IGxvb2sgYXQgcmVzX3ByaW1feWVhcjEgb2ggYm95IGlzIHRoZXJlIGFsb3Qgb2YgcmFuZG9tIHN0dWZmLg0KYGBge3J9DQoNCg0KZGZfc2lnX3kxID0gcmVzX3ByaW1feWVhcjEgJT4lDQogIGRwbHlyOjpzZWxlY3QodGF4b24sIGNvbnRhaW5zKCJUcmVhdCIpKSAlPiUgI0ZpcnN0IHdlIHdhbnQgdG8gc2VsZWN0IHNhbXBsZXMgdGhhdCBhcmUgZm9yIHRoZSB0cmVhdCBjb21wYXJpc29uICh0aGlzIGlzIG9ubHkgaW1wb3J0YW50IGlmIHlvdSBoYXZlIG11bHRpcGxlIGNvbXBhcmlzb25zIGF0IHBsYXkpDQogIGRwbHlyOjpmaWx0ZXIoZGlmZl9UcmVhdHRyZWF0ZWQgPT0gIlRSVUUiKSAlPiUgI3RoZW4gc2VsZWN0IHRheGEgdGhhdCBwYXNzZWQgdGhlIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgdGVzdCBkaWZmXw0KICBkcGx5cjo6ZmlsdGVyKHBhc3NlZF9zc19UcmVhdHRyZWF0ZWQgPT0gIlRSVUUiKSAjdGhlbiBzZWxlY3QgdGF4YSB0aGF0IHBhc3NlZCB0aGUgc2Vuc2l0aXZpdHkgYW5hbHlzaXMgKGFnYWluIGdvIHJlYWQgdGhlIGFuY29tYmMgcGFwZXIpDQoNCiNhIHJlbWluZGVyIGZvciBhIHRheGEgdG8gYmUgaW5jbHVkZWQgaW4geW91ciByZXN1bHRzIGl0IG11c3QgcGFzcyBCT1RIIHRoZSBzZW5zaXRpdml0eSBhbmFseXNpcyBhbmQgZGlmZmVyZW50aWFsIGFidW5kbmFjZSB0ZXN0cw0KDQoNCiN0aGVuIHdlIGNhbiBhZGQgc29tZSB1c2VmdWwgaW5mb3JtYXRpb24gZnJvbSBvdXIgZmFtaWx5IHRheGEgdGFibGUgdG8gdGhpcyBkYXRhdGFibGUNCmRmX3NpZ195MSA8LSBtZXJnZShmYW1pbHlfdGF4YSwgZGZfc2lnX3kxLCBieS55ID0gInRheG9uIiwgYnkueCA9ICJGYW1pbHkiKQ0KDQojZmluYWxseSB3ZSBhcmUgZ29pbmcgdG8gYXJyYW5nZSB0aGUgdGF4YSBiYXNlZCBvbiB0aGVpciBsb2cgZm9sZCBjaGFuZ2UgZm9yIHJlYWRhYmlsaXR5LCBhbmQgbWFrZSB0aGlzIGRpcmVjdCBvYmplY3QgdGhhdCBsYWJlbHMgdGhlIHRheGEgYXMgcG9zaXRpdmUgb3IgbmVnYXRpdmUgbG9nIGZvbGQgY2hhbmdlLCBpdGxsIGJlIHVzZWZ1bCBpbiB0aGUgZ3JhcGggd2UncmUgYWJvdXQgdG8gbWFrZQ0KZGZfc2lnX3kxIDwtIGRmX3NpZ195MSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhsZmNfVHJlYXR0cmVhdGVkKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoZGlyZWN0ID0gaWZlbHNlKGxmY19UcmVhdHRyZWF0ZWQgPiAwLCAiUG9zaXRpdmUgTEZDIiwgIk5lZ2F0aXZlIExGQyIpKQ0KZGZfc2lnX3kxDQoNCg0KYGBgDQoNClNvIHRoZXJlcyBhbG90IGdvaW5nIG9uIGhlcmUuLi4gDQpsZmNfIHJlcHJlc2VudHMgdGhlIGxvZmMgZm9sZCBjaGFuZ2UgZnJvbSB0aGUgYWx0ZXJuYXRlIGNvbXBhcmlzb24gZ3JvdXANCmxmY18oaW50ZXJjZXB0KSBjYW4gYmUgaWdub3JlZCwgaXRzIGEgc3RhdHMgdGhpbmcgdGhhdCBoYXMgbm8gYmVhcmluZyBvbiB5b3VyIGNvbmNsdXNpb25zDQoNCnNlXyBpcyBzdGFuZGFyZCBlcnJvcg0KDQpXXyBhbmQgcF8gYXJlIG91ciB0ZXN0IHN0YXRpc3RpY3MgYW5kIHAgdmFsdWUsIGJ1dCBvbmx5IHdvcnJ5IGFib3V0IHFfIHdoaWNoIGlzIG91ciBmYW1pbHktd2lzZSBlcnJvciByYXRlIGFkanVzdGVkIHAgdmFsdWUuDQoNCk5vdyBsZXRzIG1ha2UgYSBwcmV0dHkgZ3JhcGghDQoNCmBgYHtyfQ0KDQpmaWdfeTEgPSBkZl9zaWdfeTEgJT4lDQogIGRwbHlyOjptdXRhdGUoRmFtaWx5ID0gZmN0X3Jlb3JkZXIoRmFtaWx5LCBkcGx5cjo6ZGVzYyhsZmNfVHJlYXR0cmVhdGVkKSkpICU+JSAjcmVvcmRlcnMgdGF4YSBsb2cgZm9sZCBjaGFuZ2UgaW4gYSBkZXNjZW5kaW5nIHBhdHRlcm4gDQogIGdncGxvdChhZXMoeCA9IEZhbWlseSwgeSA9IGxmY19UcmVhdHRyZWF0ZWQsIGZpbGwgPSBkaXJlY3QpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIGNvbG9yID0gImJsYWNrIiwgDQogICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjQpKSArICNhZGRzIHRoZSBsZmMgY2hhbmdlIGl0c2VsZg0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbGZjX1RyZWF0dHJlYXRlZCAtIHNlX1RyZWF0dHJlYXRlZCwgeW1heCA9IGxmY19UcmVhdHRyZWF0ZWQgKyBzZV9UcmVhdHRyZWF0ZWQpLA0KICAgICAgICAgICAgICAgIHdpZHRoID0gMC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMDUpLCBjb2xvciA9ICJibGFjayIpICsgI2FkZHMgb3VyIGVycm9yIGJhcnMNCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJMb2cgZm9sZCBjaGFuZ2UiLCANCiAgICAgICB0aXRsZSA9ICJMb2cgZm9sZCBjaGFuZ2VzIG9mIGZ1bmdpIGZhbWlsaWVzIGFmdGVyIHRyZWF0bWVudCBpbiBvbmUgeWVhciBvbGQgcGxvdHMiKSArICNlciB0aXRsZS4uLg0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSBOVUxMKSArDQogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSBOVUxMKSArDQogIHRoZW1lX2J3KCkgKyAjZ2dwbG90IGZ1biB0aGVtZSBzdHVmZiwgZmVlbCBmcmVlIHRvIHBsYXkgYXJvdW5kDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIGhqdXN0ID0gMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAjIFRoaXMgbWFrZXMgdGhlIG5hbWVzIGF0IHRoZSBib3R0b20gb2YgdGhlIGdyYXBoIGFsbCBjb29sIGFuZCBzaWRld2F5cyBsb29raW5nDQpmaWdfeTENCmBgYA0KDQoNCg0KQW5kIHlvdSdyZSBkb25lISBJbiB0aGUgbmV4dCB0dXRvcmlhbCBJIHdpbGwgc2hvdyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG11bHRpcGxlIGdyb3VwIGNvbXBhcmlzb25zDQoNCg0K