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