Science/Health Science/Data Science Module
Topic 8B: Big Data III (Gene Expression Analysis)
Welcome to the eighth computer lab for the Science, Health Science and Data Science modules.
In this computer lab we will conduct a simplified gene expression analysis.
This computer lab is designed to run alongside the content in the Introduction to Bioinformatics in R supplement. You are not required to have a background in biology or genomics in order to complete this lab. However, some terms from these disciplines are unavoidable when conducting bioinformatics analyses - the material in this supplement provides all the background information you will need.
By the end of this lab, you should be able to conduct some of the main statistical steps in a gene expression analysis. Let’s get started!
Preparations
Before we proceed, please make sure you have read the content in the Introduction to Bioinformatics in R supplement - if you haven’t, these lab questions may not make sense. It may also be helpful to keep this content open in a separate tab while you work through the lab material.
Thale Cress Gene Count Data
In this lab, we will assess gene count data from the thale cress plant (Arabidopsis thaliana).
The analysis steps we cover will be equally applicable to gene expression data for other organisms, e.g. humans.
An overview of the thale cress data is provided in Section 3 of the Introduction to Bioinformatics in R supplement.
In summary, we have some RNA-Seq gene expression data, which has been recorded at different times over the germination and post-germination period of thale cress seeds.
This data contains recordings for two time points, denoted X24hSL
and X48hSL
.
These are, respectively, the time points for thale cress seeds 24 hours and 48 hours after exposure to sunlight, following a stratification process (whereby the seeds are encouraged to germinate).
For each time point, we have recordings for three replicates - hence the _1
’s, _2
’s and _3
’s appended to the X24hSL
and X48hSL
column names.
We have actually carried out some filtering and pre-processing on the original thale cress gene count data set, to save you time (and possibly a headache), and to ensure that our focus in this lab can be on the final gene expression analysis and \(p\)-value assessments.
The pre-prepared thale cress data is stored in two files on LMS:
thale_cress_gene_count_data.RDS
contains filtered data on the gene counts for our different replicates
thale_cress_gene_exp_data.RDS
contains pre-processed gene count data, ready for our gene expression analysis
Pleased download these files now, and store them in your working directory.
These files have the extension .RDS
, which you might not have previously encountered. To read .RDS
files into R, we need to use the readRDS()
function. The code below shows how one would read in a .RDS
file called example.RDS
.
Note: The file must be stored in your current working directory in order for this code to work.
example_data <- readRDS("example.RDS")
Using this code as a guide:
- Store the
thale_cress_gene_count_data.RDS
data in an object called thale_cress_gene_counts
- Store the
thale_cress_gene_exp_data.RDS
data in an object called thale_cress_data
Gene Data Overview
Before we proceed with our gene expression analysis, let’s spend a couple of minutes familiarising ourselves with our two data sets.
Run the following R code to obtain an overview of the gene count data stored in the thale_cress_gene_counts
object:
head(thale_cress_gene_counts$counts)
This should produce the table of gene counts for the first few genes, identical to the table provided in Section 3 of the Introduction to Bioinformatics in R supplement
The thale_cress_gene_counts
object is actually a type of list
, and various information can be extracted from the object using the $
symbol - e.g. thale_cress_gene_counts$counts
. However, the counts data is the most relevant for us - the other information relates to pre-processing steps, which we don’t have to worry about.
Run the following R code to obtain a summary of the gene samples stored in the thale_cress_data
object:
thale_cress_data$samples
Here, the lib.size
column tells us the library sizes for each replicate (i.e. the total number of read counts for all genes in each replicate).
The norm.factors
column tells us the normalisation values for each replicate.
Originally, all the values in this column were 1
’s, meaning that each library was treated as equal, despite the library sizes being different.
As part of our pre-processing, we carried out a normalisation process, like the standardisation process covered in section 4.2 of Topic 3. As a result, the norm.factors
are now all different to 1, with some replicates having smaller weights (norm.factors < 1
) and some replicates having larger weights (norm.factors > 1
).
Does any one replicate have very different qualities to the others?
Identifying differentially expressed genes
Using our pre-processed data, we can try to identify the specific genes that are differentially expressed (DE), between the time points X24hSL
and X48hSL
.
As part of our pre-processing, we computed some \(p\)-values for each gene, using a test known as a Likelihood Ratio Test
(which is a little bit like a \(t\)-test).
If a gene has a small \(p\)-value, then this means it is likely to be differentially expressed between the time points X24hSL
and X48hSL
.
Run the R code below to see a table of some results for the first few genes:
head(thale_cress_data$table)
Don’t worry about the first few columns - just focus on the PValue
column, which contains the computed \(p\)-values.
Based on their \(p\)-values, what can you conclude about:
- Gene 1 (
AT1G01010
),
- Gene 3 (
AT1G01030
), and
- Gene 5 (
AT1G01050
)?
Since there are so many genes, and a \(p\)-value has been computed for each gene, we need to adjust our \(p\)-values to take into account the fact that multiple simultaneous tests have been performed. In other words, we need to use the p.adjust
function that we introduced in Computer Lab 7B!
The p.adjust
function has actually been built in to the topTags
function from the edgeR
package, via the argument adjust.method
.
Take a look at the partially completed R code below:
topTags(thale_cress_data, adjust.method = "...", n = ...)$table
Here, the ...
in adjust.method = "..."
can take the same variety of method specifications used in the p.adjust
function.
The n = ...
argument allows us to specify the maximum number of genes to include in our output (genes with the smallest \(p\)-values are selected first). The default setting is 10, which is a little low for us.
Let’s try a few options now.
Using the code in 3.2 as a base, specify that Bonferroni correction should be performed on the \(p\)-values in the thale_cress_data
object, and that results for the top 20,000 genes should be included.
Store your results in the object thale_cress_bonferroni
.
Hint: You might like to run the command ?p.adjust
and check the help file, if you can’t remember the argument options for the p.adjust
function.
As an alternative, specify that false discovery rate correction should be performed on the \(p\)-values in the thale_cress_data
object, and that results for the top 20,000 genes should be included.
Store your results in the object thale_cress_fdr
.
Since we are assessing so many genes (the top 20,000), it might be helpful to filter out genes with higher \(p\)-values.
The argument p.value
in the topTags
function can be used to specify a \(p\)-value cut-off - any genes with \(p\)-values above the specified value are removed from the data set.
Try updating your thale_cress_bonferroni
and thale_cress_fdr
objects, by re-running your topTags
code with a cut-off value of 0.01 specified via the p.value
argument.
Call your new objects thale_cress_bonferroni_filtered
and thale_cress_fdr_filtered
respectively.
Use the dim()
function to determine the overall number of genes remaining in your updated thale_cress_bonferroni_filtered
and thale_cress_fdr_filtered
objects.
Compare the results - which p.adjust
method do you prefer?
Volcano Plots
To visualise the gene information stored in our objects, we can use a new type of plot called a Volcano Plot
.
A volcano plot is a bit like a scatter plot, but with a few key differences.
For our data:
- The plot is centred at 0 on the x-axis.
- Each point represents a gene.
- A point close to
x=0
represents a gene that is probably not differentially expressed.
- Points far from
x=0
represent genes that are probably differentially expressed.
- Points far from
y=0
represent genes with small p-values.
Therefore, points that are far from both x=0
and y=0
most likely represent statistically significantly differentially expressed genes.
To create a volcano plot in R, we can just use the plot
function - the key is in the data we provide to this function. Run the R code below and take a look at the output.
plot(thale_cress_data$table$logFC,
-log10(thale_cress_data$table$PValue),
pch = 20, cex = 0.5, col = "blue",
main = "Volcano Plot for all Thale Cress Genes
for the timepoints X24hSL and X48hSL",
ylab="-log10(p-value)", xlab="logFC")
Note: Here the logFC
x-axis label refers to the log of the ratio of the gene count measurements at the two time points (the log-fold-change). A value close to 0 means that the measurement hasn’t changed much in the 24 hour period, while a larger value means there has been a larger change (either positive or negative).
Using the code shown above in 4.1 as a base, create volcano plots for your thale_cress_bonferroni_filtered
and thale_cress_fdr_filtered
objects.
Compare your volcano plots with each other, and with the volcano plot shown in 4.1.
Do you think that the \(p\)-value adjustments you performed were beneficial in identifying the genes which were most likely to be differentially expressed between the time points X24hSL
and X48hSL
?
Looking at your two volcano plots, has your preference between the two p.adjust
methods you used changed? Why/why not?
Great work, that’s everything for today!
That was a lot to cover in conjunction with the supplement material, but hopefully this lab has given you a taste of the world of Bioinformatics, and the integral role of statistics within this world.
By conducting this gene expression analysis, we have been able to identify genes that are statistically significantly differentially expressed between two seed germination time points for the thale cress plant.
While this might not seem immediately ground-breaking, it’s important to note that we could use the same procedure to identify, for example, genes that are statistically significantly differentially expressed between a healthy human genome, and the genome of a human with a certain illness or disease. This has immediate practical implications, and could for example lead to the development of drugs which target those genes in an effort to reduce the suffering of individuals with that condition (or possibly even cure the condition).
References
Bioconductor.org. 2021.
“Bioconductor: Open Source Software for Bioinformatics.” 2021.
https://bioconductor.org/.
Chen, Y., D. J. McCarthy, M. Ritchie, M. Robinson, and G. K. Smyth. 2018. edgeR: Differential Expression Analysis of Digital Gene Expression Data User’s Guide.
McCarthy, D. J., Y. Chen, and G. K. Smyth. 2012. “Differential Expression Analysis of Multifactor RNA-Seq Experiments with Respect to Biological Variation.” Nucleic Acids Research 40 (10): 4288–97.
Robinson, M. D., D. J. McCarthy, and G. K. Smyth. 2010. “edgeR: A Bioconductor Package for Differential Expression Analysis of Digital Gene Expression Data.” Bioinformatics 26 (1): 139–40.
These notes have been prepared by Rupert Kuveke. The copyright for the material in these notes resides with the author named above, with the Department of Mathematics and Statistics and with La Trobe University. Copyright in this work is vested in La Trobe University including all La Trobe University branding and naming. Unless otherwise stated, material within this work is licensed under a Creative Commons Attribution-Non Commercial-Non Derivatives License
BY-NC-ND.
LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiA4QiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIFNjaWVuY2UvSGVhbHRoIFNjaWVuY2UvRGF0YSBTY2llbmNlIE1vZHVsZSB7LX0NCg0KIyMjIFRvcGljIDhCOiBCaWcgRGF0YSBJSUkgKEdlbmUgRXhwcmVzc2lvbiBBbmFseXNpcykgey19DQoNCjxicj4NCg0KV2VsY29tZSB0byB0aGUgZWlnaHRoIGNvbXB1dGVyIGxhYiBmb3IgdGhlIFNjaWVuY2UsIEhlYWx0aCBTY2llbmNlIGFuZCBEYXRhIFNjaWVuY2UgbW9kdWxlcy4NCkluIHRoaXMgY29tcHV0ZXIgbGFiIHdlIHdpbGwgY29uZHVjdCBhIHNpbXBsaWZpZWQgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzLg0KDQpUaGlzIGNvbXB1dGVyIGxhYiBpcyBkZXNpZ25lZCB0byBydW4gYWxvbmdzaWRlIHRoZSBjb250ZW50IGluIHRoZSBbSW50cm9kdWN0aW9uIHRvIEJpb2luZm9ybWF0aWNzIGluIFIgc3VwcGxlbWVudF0oaHR0cHM6Ly9ib29rZG93bi5vcmcvcmVoay9zdG0xMDAxX2RzbV9pbnRyb2R1Y3Rpb25fdG9fYmlvaW5mb3JtYXRpY3NfaW5fci8pLiBZb3UgYXJlIG5vdCByZXF1aXJlZCB0byBoYXZlIGEgYmFja2dyb3VuZCBpbiBiaW9sb2d5IG9yIGdlbm9taWNzIGluIG9yZGVyIHRvIGNvbXBsZXRlIHRoaXMgbGFiLiBIb3dldmVyLCBzb21lIHRlcm1zIGZyb20gdGhlc2UgZGlzY2lwbGluZXMgYXJlIHVuYXZvaWRhYmxlIHdoZW4gY29uZHVjdGluZyBiaW9pbmZvcm1hdGljcyBhbmFseXNlcyAtIHRoZSBtYXRlcmlhbCBpbiB0aGlzIHN1cHBsZW1lbnQgcHJvdmlkZXMgYWxsIHRoZSBiYWNrZ3JvdW5kIGluZm9ybWF0aW9uIHlvdSB3aWxsIG5lZWQuIA0KDQpCeSB0aGUgZW5kIG9mIHRoaXMgbGFiLCB5b3Ugc2hvdWxkIGJlIGFibGUgdG8gY29uZHVjdCBzb21lIG9mIHRoZSBtYWluIHN0YXRpc3RpY2FsIHN0ZXBzIGluIGEgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzLiBMZXQncyBnZXQgc3RhcnRlZCENCg0KIyBQcmVwYXJhdGlvbnMgeyNwcmVwfQ0KDQpCZWZvcmUgd2UgcHJvY2VlZCwgcGxlYXNlIG1ha2Ugc3VyZSB5b3UgaGF2ZSByZWFkIHRoZSBjb250ZW50IGluIHRoZSBbSW50cm9kdWN0aW9uIHRvIEJpb2luZm9ybWF0aWNzIGluIFIgc3VwcGxlbWVudF0oaHR0cHM6Ly9ib29rZG93bi5vcmcvcmVoay9zdG0xMDAxX2RzbV9pbnRyb2R1Y3Rpb25fdG9fYmlvaW5mb3JtYXRpY3NfaW5fci8pIC0gaWYgeW91IGhhdmVuJ3QsIHRoZXNlIGxhYiBxdWVzdGlvbnMgbWF5IG5vdCBtYWtlIHNlbnNlLiBJdCBtYXkgYWxzbyBiZSBoZWxwZnVsIHRvIGtlZXAgdGhpcyBjb250ZW50IG9wZW4gaW4gYSBzZXBhcmF0ZSB0YWIgd2hpbGUgeW91IHdvcmsgdGhyb3VnaCB0aGUgbGFiIG1hdGVyaWFsLg0KIA0KIyMgQmlvaW5mb3JtYXRpY3MgUGFja2FnZXMgDQogDQpJbiBwcmV2aW91cyBjb21wdXRlciBsYWJzLCB3ZSBoYXZlIGRvd25sb2FkZWQgUiBwYWNrYWdlcyBmcm9tIENSQU4sIHVzaW5nIHRoZSBjb21tYW5kIGBpbnN0YWxsLnBhY2thZ2VzKC4uLilgLg0KSG93ZXZlciwgbW9zdCBCaW9pbmZvcm1hdGljcy1zcGVjaWZpYyBSIHBhY2thZ2VzIGFyZSBub3QgaG9zdGVkIG9uIENSQU4sIGJ1dCByYXRoZXIgYXJlIGhvc3RlZCBvbiB0aGUgQmlvY29uZHVjdG9yIHdlYnNpdGUgW0BCaW9jb25kdWN0b3JdLg0KDQpJbiB0aGlzIGNvbXB1dGVyIGxhYiwgd2Ugd2lsbCBuZWVkIHRvIHVzZSBvbmUgc3VjaCBwYWNrYWdlLCBgZWRnZVJgIF5bc2VlIEBlZGdlUmJhc2UsIEBlZGdlUiwgYW5kIEBlZGdlUnBhY2thZ2VdLiBUbyBpbnN0YWxsIHRoaXMgcGFja2FnZSwgd2Ugd2lsbCBuZWVkIHRvIGZvbGxvdyBhIHNsaWdodGx5IGRpZmZlcmVudCBhcHByb2FjaCB0byB1c3VhbC4NCg0KVG8gYmVnaW4sIHdlIHNoYWxsIGluc3RhbGwgdGhlIGBCaW9jTWFuYWdlcmAgcGFja2FnZSAodXNpbmcgdGhlIG5vcm1hbCBpbnN0YWxsYXRpb24gcHJvY2VzcyksIHdoaWNoIHdlIHdpbGwgdGhlbiB1c2UgdG8gaW5zdGFsbCB0aGUgQmlvY29uZHVjdG9yIGBlZGdlUmAgcGFja2FnZS4gUnVuIHRoZSBjb2RlIGJlbG93IHRvIGluc3RhbGwgdGhlc2UgcGFja2FnZXMsIGFuZCB0byBsb2FkIHRoZSBgZWRnZVJgIHBhY2thZ2UuDQoNCmBgYHtyIGV2YWwgPSBGLCBpbmNsdWRlID0gVH0NCmluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCkJpb2NNYW5hZ2VyOjppbnN0YWxsKHZlcnNpb24gPSAiMy4xNCIpDQpCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZWRnZVIiKQ0KDQpsaWJyYXJ5KGVkZ2VSKQ0KYGBgDQoNCmBgYHtyIGV2YWwgPSBULCBpbmNsdWRlID0gRn0NCmxpYnJhcnkoZWRnZVIpDQpgYGANCg0KKk5vdGU6IFNvbWUgYWRkaXRpb25hbCBkZXBlbmRlbmN5IHBhY2thZ2VzLCBuYW1lbHkgYGxpbW1hYCwgYGxvY2ZpdGAgYW5kIGBSY3BwYCBtYXkgYmUgaW5zdGFsbGVkIGFzIHBhcnQgb2YgdGhlIGBlZGdlUmAgaW5zdGFsbGF0aW9uIHByb2Nlc3MuIFRoZSBlbnRpcmUgaW5zdGFsbGF0aW9uIHNob3VsZCBvbmx5IHRha2UgYSBmZXcgbWludXRlcy4gSWYgeW91IGFyZSBhc2tlZCB0byB1cGRhdGUgZXhpc3RpbmcgcGFja2FnZXMsIHdpdGggdGhlIGxpbmUgYFVwZGF0ZSBhbGwvc29tZS9ub25lPyBbYS9zL25dOiBgIGluIHRoZSBjb21tYW5kIGNvbnNvbGUsIHR5cGUgYG5gIGFuZCBoaXQgZW50ZXIuKg0KDQojIyBUaGFsZSBDcmVzcyBHZW5lIENvdW50IERhdGENCg0KSW4gdGhpcyBsYWIsIHdlIHdpbGwgYXNzZXNzIGdlbmUgY291bnQgZGF0YSBmcm9tIHRoZSB0aGFsZSBjcmVzcyBwbGFudCAoKkFyYWJpZG9wc2lzIHRoYWxpYW5hKikuDQpUaGUgYW5hbHlzaXMgc3RlcHMgd2UgY292ZXIgd2lsbCBiZSBlcXVhbGx5IGFwcGxpY2FibGUgdG8gZ2VuZSBleHByZXNzaW9uIGRhdGEgZm9yIG90aGVyIG9yZ2FuaXNtcywgZS5nLiBodW1hbnMuIA0KDQpBbiBvdmVydmlldyBvZiB0aGUgdGhhbGUgY3Jlc3MgZGF0YSBpcyBwcm92aWRlZCBpbiBbU2VjdGlvbiAzIG9mIHRoZSBJbnRyb2R1Y3Rpb24gdG8gQmlvaW5mb3JtYXRpY3MgaW4gUiBzdXBwbGVtZW50XShodHRwczovL2Jvb2tkb3duLm9yZy9yZWhrL3N0bTEwMDFfZHNtX2ludHJvZHVjdGlvbl90b19iaW9pbmZvcm1hdGljc19pbl9yL3RoYWxlLWNyZXNzLWdlbmUtZXhwcmVzc2lvbi5odG1sKS4NCg0KSW4gc3VtbWFyeSwgd2UgaGF2ZSBzb21lIFJOQS1TZXEgZ2VuZSBleHByZXNzaW9uIGRhdGEsIHdoaWNoIGhhcyBiZWVuIHJlY29yZGVkIGF0IGRpZmZlcmVudCB0aW1lcyBvdmVyIHRoZSBnZXJtaW5hdGlvbiBhbmQgcG9zdC1nZXJtaW5hdGlvbiBwZXJpb2Qgb2YgdGhhbGUgY3Jlc3Mgc2VlZHMuDQoNClRoaXMgZGF0YSBjb250YWlucyByZWNvcmRpbmdzIGZvciB0d28gdGltZSBwb2ludHMsIGRlbm90ZWQgYFgyNGhTTGAgYW5kIGBYNDhoU0xgLiANCg0KVGhlc2UgYXJlLCByZXNwZWN0aXZlbHksIHRoZSB0aW1lIHBvaW50cyBmb3IgdGhhbGUgY3Jlc3Mgc2VlZHMgMjQgaG91cnMgYW5kIDQ4IGhvdXJzIGFmdGVyIGV4cG9zdXJlIHRvIHN1bmxpZ2h0LCBmb2xsb3dpbmcgYSBzdHJhdGlmaWNhdGlvbiBwcm9jZXNzICh3aGVyZWJ5IHRoZSBzZWVkcyBhcmUgZW5jb3VyYWdlZCB0byBnZXJtaW5hdGUpLg0KDQpGb3IgZWFjaCB0aW1lIHBvaW50LCB3ZSBoYXZlIHJlY29yZGluZ3MgZm9yIHRocmVlIHJlcGxpY2F0ZXMgLSBoZW5jZSB0aGUgYF8xYCdzLCBgXzJgJ3MgYW5kIGBfM2AncyBhcHBlbmRlZCB0byB0aGUgYFgyNGhTTGAgYW5kIGBYNDhoU0xgIGNvbHVtbiBuYW1lcy4NCg0KIyMjIA0KDQpXZSBoYXZlIGFjdHVhbGx5IGNhcnJpZWQgb3V0IHNvbWUgZmlsdGVyaW5nIGFuZCBwcmUtcHJvY2Vzc2luZyBvbiB0aGUgb3JpZ2luYWwgdGhhbGUgY3Jlc3MgZ2VuZSBjb3VudCBkYXRhIHNldCwgdG8gc2F2ZSB5b3UgdGltZSAoYW5kIHBvc3NpYmx5IGEgaGVhZGFjaGUpLCBhbmQgdG8gZW5zdXJlIHRoYXQgb3VyIGZvY3VzIGluIHRoaXMgbGFiIGNhbiBiZSBvbiB0aGUgZmluYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzIGFuZCAkcCQtdmFsdWUgYXNzZXNzbWVudHMuICANCg0KVGhlIHByZS1wcmVwYXJlZCB0aGFsZSBjcmVzcyBkYXRhIGlzIHN0b3JlZCBpbiB0d28gZmlsZXMgb24gTE1TOiANCg0KKiBgdGhhbGVfY3Jlc3NfZ2VuZV9jb3VudF9kYXRhLlJEU2AgY29udGFpbnMgZmlsdGVyZWQgZGF0YSBvbiB0aGUgZ2VuZSBjb3VudHMgZm9yIG91ciBkaWZmZXJlbnQgcmVwbGljYXRlcw0KKiBgdGhhbGVfY3Jlc3NfZ2VuZV9leHBfZGF0YS5SRFNgIGNvbnRhaW5zIHByZS1wcm9jZXNzZWQgZ2VuZSBjb3VudCBkYXRhLCByZWFkeSBmb3Igb3VyIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcyA8IS0tICRee1xkYWdnZXJ9JC0tPg0KDQpQbGVhc2VkIGRvd25sb2FkIHRoZXNlIGZpbGVzIG5vdywgYW5kIHN0b3JlIHRoZW0gaW4geW91ciB3b3JraW5nIGRpcmVjdG9yeS4NCg0KPCEtLSAkXntcZGFnZ2VyfSQgKklmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgcHJlLXByb2Nlc3Npbmcgc3RlcHMgd2UgaGF2ZSBjb25kdWN0ZWQsIHNvbWUgb3B0aW9uYWwgcmVhZGluZyBpcyBwcm92aWRlZCBpbiBbU2VjdGlvbiA0IG9mIHRoZSBJbnRyb2R1Y3Rpb24gdG8gQmlvaW5mb3JtYXRpY3MgaW4gUiBzdXBwbGVtZW50XShodHRwczovL2Jvb2tkb3duLm9yZy9yZWhrL3N0bTEwMDFfZHNtX2ludHJvZHVjdGlvbl90b19iaW9pbmZvcm1hdGljc19pbl9yL3RoYWxlLWNyZXNzLWdlbmUtZXhwcmVzc2lvbi5odG1sKSogLS0+DQoNCiMjIyANCg0KVGhlc2UgZmlsZXMgaGF2ZSB0aGUgZXh0ZW5zaW9uIGAuUkRTYCwgd2hpY2ggeW91IG1pZ2h0IG5vdCBoYXZlIHByZXZpb3VzbHkgZW5jb3VudGVyZWQuIFRvIHJlYWQgYC5SRFNgIGZpbGVzIGludG8gUiwgd2UgbmVlZCB0byB1c2UgdGhlIGByZWFkUkRTKClgIGZ1bmN0aW9uLiBUaGUgY29kZSBiZWxvdyBzaG93cyBob3cgb25lIHdvdWxkIHJlYWQgaW4gYSBgLlJEU2AgZmlsZSBjYWxsZWQgYGV4YW1wbGUuUkRTYC4NCg0KKk5vdGU6IFRoZSBmaWxlIG11c3QgYmUgc3RvcmVkIGluIHlvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSBpbiBvcmRlciBmb3IgdGhpcyBjb2RlIHRvIHdvcmsuKg0KDQpgYGAge3IsIGVjaG8gPSBULCBldmFsID0gRn0NCmV4YW1wbGVfZGF0YSA8LSByZWFkUkRTKCJleGFtcGxlLlJEUyIpDQpgYGANCg0KVXNpbmcgdGhpcyBjb2RlIGFzIGEgZ3VpZGU6DQoNCiogU3RvcmUgdGhlIGB0aGFsZV9jcmVzc19nZW5lX2NvdW50X2RhdGEuUkRTYCBkYXRhIGluIGFuIG9iamVjdCBjYWxsZWQgYHRoYWxlX2NyZXNzX2dlbmVfY291bnRzYA0KKiBTdG9yZSB0aGUgYHRoYWxlX2NyZXNzX2dlbmVfZXhwX2RhdGEuUkRTYCBkYXRhIGluIGFuIG9iamVjdCBjYWxsZWQgYHRoYWxlX2NyZXNzX2RhdGFgDQoNCmBgYCB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBGfQ0KdGhhbGVfY3Jlc3NfZ2VuZV9jb3VudHMgPC0gcmVhZFJEUygiZGF0YS90aGFsZV9jcmVzc19nZW5lX2NvdW50X2RhdGEuUkRTIikNCnRoYWxlX2NyZXNzX2RhdGEgPC0gcmVhZFJEUygiZGF0YS90aGFsZV9jcmVzc19nZW5lX2V4cF9kYXRhLlJEUyIpDQpgYGANCg0KDQojIEdlbmUgRGF0YSBPdmVydmlldyB7I3N1bW1hcnl9DQoNCkJlZm9yZSB3ZSBwcm9jZWVkIHdpdGggb3VyIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcywgbGV0J3Mgc3BlbmQgYSBjb3VwbGUgb2YgbWludXRlcyBmYW1pbGlhcmlzaW5nIG91cnNlbHZlcyB3aXRoIG91ciB0d28gZGF0YSBzZXRzLg0KDQojIw0KDQpSdW4gdGhlIGZvbGxvd2luZyBSIGNvZGUgdG8gb2J0YWluIGFuIG92ZXJ2aWV3IG9mIHRoZSBnZW5lIGNvdW50IGRhdGEgc3RvcmVkIGluIHRoZSBgdGhhbGVfY3Jlc3NfZ2VuZV9jb3VudHNgIG9iamVjdDoNCg0KYGBgIHtyLCBlY2hvID0gVCwgZXZhbCA9IEZ9DQpoZWFkKHRoYWxlX2NyZXNzX2dlbmVfY291bnRzJGNvdW50cykNCmBgYA0KDQpUaGlzIHNob3VsZCBwcm9kdWNlIHRoZSB0YWJsZSBvZiBnZW5lIGNvdW50cyBmb3IgdGhlIGZpcnN0IGZldyBnZW5lcywgaWRlbnRpY2FsIHRvIHRoZSB0YWJsZSBwcm92aWRlZCBpbiBbU2VjdGlvbiAzIG9mIHRoZSBJbnRyb2R1Y3Rpb24gdG8gQmlvaW5mb3JtYXRpY3MgaW4gUiBzdXBwbGVtZW50XShodHRwczovL2Jvb2tkb3duLm9yZy9yZWhrL3N0bTEwMDFfZHNtX2ludHJvZHVjdGlvbl90b19iaW9pbmZvcm1hdGljc19pbl9yL3RoYWxlLWNyZXNzLWdlbmUtZXhwcmVzc2lvbi5odG1sKQ0KDQojIyMNCg0KVGhlIGB0aGFsZV9jcmVzc19nZW5lX2NvdW50c2Agb2JqZWN0IGlzIGFjdHVhbGx5IGEgdHlwZSBvZiBgbGlzdGAsIGFuZCB2YXJpb3VzIGluZm9ybWF0aW9uIGNhbiBiZSBleHRyYWN0ZWQgZnJvbSB0aGUgb2JqZWN0IHVzaW5nIHRoZSBgJGAgc3ltYm9sIC0gZS5nLiBgdGhhbGVfY3Jlc3NfZ2VuZV9jb3VudHMkY291bnRzYC4gSG93ZXZlciwgdGhlIGNvdW50cyBkYXRhIGlzIHRoZSBtb3N0IHJlbGV2YW50IGZvciB1cyAtIHRoZSBvdGhlciBpbmZvcm1hdGlvbiByZWxhdGVzIHRvIHByZS1wcm9jZXNzaW5nIHN0ZXBzLCB3aGljaCB3ZSBkb24ndCBoYXZlIHRvIHdvcnJ5IGFib3V0Lg0KDQojIw0KDQpSdW4gdGhlIGZvbGxvd2luZyBSIGNvZGUgdG8gb2J0YWluIGEgc3VtbWFyeSBvZiB0aGUgZ2VuZSBzYW1wbGVzIHN0b3JlZCBpbiB0aGUgYHRoYWxlX2NyZXNzX2RhdGFgIG9iamVjdDoNCg0KYGBgIHtyLCBlY2hvID0gVCwgZXZhbCA9IEZ9DQp0aGFsZV9jcmVzc19kYXRhJHNhbXBsZXMNCmBgYA0KDQpIZXJlLCB0aGUgYGxpYi5zaXplYCBjb2x1bW4gdGVsbHMgdXMgdGhlIGxpYnJhcnkgc2l6ZXMgZm9yIGVhY2ggcmVwbGljYXRlIChpLmUuIHRoZSB0b3RhbCBudW1iZXIgb2YgcmVhZCBjb3VudHMgZm9yIGFsbCBnZW5lcyBpbiBlYWNoIHJlcGxpY2F0ZSkuIA0KVGhlIGBub3JtLmZhY3RvcnNgIGNvbHVtbiB0ZWxscyB1cyB0aGUgbm9ybWFsaXNhdGlvbiB2YWx1ZXMgZm9yIGVhY2ggcmVwbGljYXRlLiANCg0KT3JpZ2luYWxseSwgYWxsIHRoZSB2YWx1ZXMgaW4gdGhpcyBjb2x1bW4gd2VyZSBgMWAncywgbWVhbmluZyB0aGF0IGVhY2ggbGlicmFyeSB3YXMgdHJlYXRlZCBhcyBlcXVhbCwgZGVzcGl0ZSB0aGUgbGlicmFyeSBzaXplcyBiZWluZyBkaWZmZXJlbnQuDQoNCkFzIHBhcnQgb2Ygb3VyIHByZS1wcm9jZXNzaW5nLCB3ZSBjYXJyaWVkIG91dCBhIG5vcm1hbGlzYXRpb24gcHJvY2VzcywgbGlrZSB0aGUgc3RhbmRhcmRpc2F0aW9uIHByb2Nlc3MgY292ZXJlZCBpbiBbc2VjdGlvbiA0LjIgb2YgVG9waWMgM10oaHR0cHM6Ly9ib29rZG93bi5vcmcvYV9zaGFrZXIvU1RNMTAwMV9Ub3BpY18zLzQtMi1zdGFuZGFyZGlzYXRpb24uaHRtbCkuIEFzIGEgcmVzdWx0LCB0aGUgYG5vcm0uZmFjdG9yc2AgYXJlIG5vdyBhbGwgZGlmZmVyZW50IHRvIDEsIHdpdGggc29tZSByZXBsaWNhdGVzIGhhdmluZyBzbWFsbGVyIHdlaWdodHMgKGBub3JtLmZhY3RvcnMgPCAxYCkgYW5kIHNvbWUgcmVwbGljYXRlcyBoYXZpbmcgbGFyZ2VyIHdlaWdodHMgKGBub3JtLmZhY3RvcnMgPiAxYCkuDQoNCiMjIw0KDQpEb2VzIGFueSBvbmUgcmVwbGljYXRlIGhhdmUgdmVyeSBkaWZmZXJlbnQgcXVhbGl0aWVzIHRvIHRoZSBvdGhlcnM/IA0KDQojCUlkZW50aWZ5aW5nIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyB7I2RlZ2VuZXN9DQoNClVzaW5nIG91ciBwcmUtcHJvY2Vzc2VkIGRhdGEsIHdlIGNhbiB0cnkgdG8gaWRlbnRpZnkgdGhlIHNwZWNpZmljIGdlbmVzIHRoYXQgYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCAoREUpLCBiZXR3ZWVuIHRoZSB0aW1lIHBvaW50cyBgWDI0aFNMYCBhbmQgYFg0OGhTTGAuDQoNCiMjIA0KDQpBcyBwYXJ0IG9mIG91ciBwcmUtcHJvY2Vzc2luZywgd2UgY29tcHV0ZWQgc29tZSAkcCQtdmFsdWVzIGZvciBlYWNoIGdlbmUsIHVzaW5nIGEgdGVzdCBrbm93biBhcyBhIGBMaWtlbGlob29kIFJhdGlvIFRlc3RgICh3aGljaCBpcyBhIGxpdHRsZSBiaXQgbGlrZSBhICR0JC10ZXN0KS4NCg0KSWYgYSBnZW5lIGhhcyBhIHNtYWxsICRwJC12YWx1ZSwgdGhlbiB0aGlzIG1lYW5zIGl0IGlzIGxpa2VseSB0byBiZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiB0aGUgdGltZSBwb2ludHMgYFgyNGhTTGAgYW5kIGBYNDhoU0xgLg0KDQpSdW4gdGhlIFIgY29kZSBiZWxvdyB0byBzZWUgYSB0YWJsZSBvZiBzb21lIHJlc3VsdHMgZm9yIHRoZSBmaXJzdCBmZXcgZ2VuZXM6DQoNCmBgYCB7ciwgZWNobyA9IFQsIGV2YWwgPSBGfQ0KaGVhZCh0aGFsZV9jcmVzc19kYXRhJHRhYmxlKQ0KYGBgDQoNCkRvbid0IHdvcnJ5IGFib3V0IHRoZSBmaXJzdCBmZXcgY29sdW1ucyAtIGp1c3QgZm9jdXMgb24gdGhlIGBQVmFsdWVgIGNvbHVtbiwgd2hpY2ggY29udGFpbnMgdGhlIGNvbXB1dGVkICRwJC12YWx1ZXMuDQoNCkJhc2VkIG9uIHRoZWlyICRwJC12YWx1ZXMsIHdoYXQgY2FuIHlvdSBjb25jbHVkZSBhYm91dDogDQoNCiogR2VuZSAxIChgQVQxRzAxMDEwYCksIA0KKiBHZW5lIDMgKGBBVDFHMDEwMzBgKSwgYW5kDQoqIEdlbmUgNSAoYEFUMUcwMTA1MGApPw0KDQojIyB7I3BhZGp1c3R9DQoNClNpbmNlIHRoZXJlIGFyZSBzbyBtYW55IGdlbmVzLCBhbmQgYSAkcCQtdmFsdWUgaGFzIGJlZW4gY29tcHV0ZWQgZm9yIGVhY2ggZ2VuZSwgd2UgbmVlZCB0byBhZGp1c3Qgb3VyICRwJC12YWx1ZXMgdG8gdGFrZSBpbnRvIGFjY291bnQgdGhlIGZhY3QgdGhhdCBtdWx0aXBsZSBzaW11bHRhbmVvdXMgdGVzdHMgaGF2ZSBiZWVuIHBlcmZvcm1lZC4gSW4gb3RoZXIgd29yZHMsIHdlIG5lZWQgdG8gdXNlIHRoZSBgcC5hZGp1c3RgIGZ1bmN0aW9uIHRoYXQgd2UgaW50cm9kdWNlZCBpbiBbQ29tcHV0ZXIgTGFiIDdCXShodHRwczovL3JwdWJzLmNvbS9MVFVfU1RNMTAwMS9TTURTTUNMNykhDQoNClRoZSBgcC5hZGp1c3RgIGZ1bmN0aW9uIGhhcyBhY3R1YWxseSBiZWVuIGJ1aWx0IGluIHRvIHRoZSBgdG9wVGFnc2AgZnVuY3Rpb24gZnJvbSB0aGUgYGVkZ2VSYCBwYWNrYWdlLCB2aWEgdGhlIGFyZ3VtZW50IGBhZGp1c3QubWV0aG9kYC4NCg0KVGFrZSBhIGxvb2sgYXQgdGhlIHBhcnRpYWxseSBjb21wbGV0ZWQgUiBjb2RlIGJlbG93Og0KDQpgYGAge3IsIGVjaG8gPSBULCBldmFsID0gRn0NCnRvcFRhZ3ModGhhbGVfY3Jlc3NfZGF0YSwgYWRqdXN0Lm1ldGhvZCA9ICIuLi4iLCBuID0gLi4uKSR0YWJsZQ0KYGBgDQoNCkhlcmUsIHRoZSAgYC4uLmAgaW4gYGFkanVzdC5tZXRob2QgPSAiLi4uImAgY2FuIHRha2UgdGhlIHNhbWUgdmFyaWV0eSBvZiBtZXRob2Qgc3BlY2lmaWNhdGlvbnMgdXNlZCBpbiB0aGUgYHAuYWRqdXN0YCBmdW5jdGlvbi4NCg0KVGhlIGBuID0gLi4uYCBhcmd1bWVudCBhbGxvd3MgdXMgdG8gc3BlY2lmeSB0aGUgbWF4aW11bSBudW1iZXIgb2YgZ2VuZXMgdG8gaW5jbHVkZSBpbiBvdXIgb3V0cHV0IChnZW5lcyB3aXRoIHRoZSBzbWFsbGVzdCAkcCQtdmFsdWVzIGFyZSBzZWxlY3RlZCBmaXJzdCkuIFRoZSBkZWZhdWx0IHNldHRpbmcgaXMgMTAsIHdoaWNoIGlzIGEgbGl0dGxlIGxvdyBmb3IgdXMuDQoNCkxldCdzIHRyeSBhIGZldyBvcHRpb25zIG5vdy4NCg0KIyMjDQoNClVzaW5nIHRoZSBjb2RlIGluIFxAcmVmKHBhZGp1c3QpIGFzIGEgYmFzZSwgc3BlY2lmeSB0aGF0IEJvbmZlcnJvbmkgY29ycmVjdGlvbiBzaG91bGQgYmUgcGVyZm9ybWVkIG9uIHRoZSAkcCQtdmFsdWVzIGluIHRoZSBgdGhhbGVfY3Jlc3NfZGF0YWAgb2JqZWN0LCBhbmQgdGhhdCByZXN1bHRzIGZvciB0aGUgdG9wIDIwLDAwMCBnZW5lcyBzaG91bGQgYmUgaW5jbHVkZWQuDQoNClN0b3JlIHlvdXIgcmVzdWx0cyBpbiB0aGUgb2JqZWN0IGB0aGFsZV9jcmVzc19ib25mZXJyb25pYC4NCg0KKkhpbnQ6IFlvdSBtaWdodCBsaWtlIHRvIHJ1biB0aGUgY29tbWFuZCBgP3AuYWRqdXN0YCBhbmQgY2hlY2sgdGhlIGhlbHAgZmlsZSwgaWYgeW91IGNhbid0IHJlbWVtYmVyIHRoZSBhcmd1bWVudCBvcHRpb25zIGZvciB0aGUgYHAuYWRqdXN0YCBmdW5jdGlvbi4qDQoNCiMjIw0KDQpBcyBhbiBhbHRlcm5hdGl2ZSwgc3BlY2lmeSB0aGF0IGZhbHNlIGRpc2NvdmVyeSByYXRlIGNvcnJlY3Rpb24gc2hvdWxkIGJlIHBlcmZvcm1lZCBvbiB0aGUgJHAkLXZhbHVlcyBpbiB0aGUgYHRoYWxlX2NyZXNzX2RhdGFgIG9iamVjdCwgYW5kIHRoYXQgcmVzdWx0cyBmb3IgdGhlIHRvcCAyMCwwMDAgZ2VuZXMgc2hvdWxkIGJlIGluY2x1ZGVkLg0KDQpTdG9yZSB5b3VyIHJlc3VsdHMgaW4gdGhlIG9iamVjdCBgdGhhbGVfY3Jlc3NfZmRyYC4NCg0KIyMgeyNmaWx0ZXJ9DQoNClNpbmNlIHdlIGFyZSBhc3Nlc3Npbmcgc28gbWFueSBnZW5lcyAodGhlIHRvcCAyMCwwMDApLCBpdCBtaWdodCBiZSBoZWxwZnVsIHRvIGZpbHRlciBvdXQgZ2VuZXMgd2l0aCBoaWdoZXIgJHAkLXZhbHVlcy4gDQoNClRoZSBhcmd1bWVudCBgcC52YWx1ZWAgaW4gdGhlIGB0b3BUYWdzYCBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBzcGVjaWZ5IGEgJHAkLXZhbHVlIGN1dC1vZmYgLSBhbnkgZ2VuZXMgd2l0aCAkcCQtdmFsdWVzIGFib3ZlIHRoZSBzcGVjaWZpZWQgdmFsdWUgYXJlIHJlbW92ZWQgZnJvbSB0aGUgZGF0YSBzZXQuDQoNClRyeSB1cGRhdGluZyB5b3VyIGB0aGFsZV9jcmVzc19ib25mZXJyb25pYCBhbmQgYHRoYWxlX2NyZXNzX2ZkcmAgb2JqZWN0cywgYnkgcmUtcnVubmluZyB5b3VyIGB0b3BUYWdzYCBjb2RlIHdpdGggYSBjdXQtb2ZmIHZhbHVlIG9mIDAuMDEgc3BlY2lmaWVkIHZpYSB0aGUgYHAudmFsdWVgIGFyZ3VtZW50Lg0KDQpDYWxsIHlvdXIgbmV3IG9iamVjdHMgIGB0aGFsZV9jcmVzc19ib25mZXJyb25pX2ZpbHRlcmVkYCBhbmQgYHRoYWxlX2NyZXNzX2Zkcl9maWx0ZXJlZGAgcmVzcGVjdGl2ZWx5Lg0KDQojIyMNCg0KVXNlIHRoZSBgZGltKClgIGZ1bmN0aW9uIHRvIGRldGVybWluZSB0aGUgb3ZlcmFsbCBudW1iZXIgb2YgZ2VuZXMgcmVtYWluaW5nIGluIHlvdXIgdXBkYXRlZCBgdGhhbGVfY3Jlc3NfYm9uZmVycm9uaV9maWx0ZXJlZGAgYW5kIGB0aGFsZV9jcmVzc19mZHJfZmlsdGVyZWRgIG9iamVjdHMuDQoNCkNvbXBhcmUgdGhlIHJlc3VsdHMgLSB3aGljaCBgcC5hZGp1c3RgIG1ldGhvZCBkbyB5b3UgcHJlZmVyPw0KDQojIFZvbGNhbm8gUGxvdHMNCg0KVG8gdmlzdWFsaXNlIHRoZSBnZW5lIGluZm9ybWF0aW9uIHN0b3JlZCBpbiBvdXIgb2JqZWN0cywgd2UgY2FuIHVzZSBhIG5ldyB0eXBlIG9mIHBsb3QgY2FsbGVkIGEgYFZvbGNhbm8gUGxvdGAuDQpBIHZvbGNhbm8gcGxvdCBpcyBhIGJpdCBsaWtlIGEgc2NhdHRlciBwbG90LCBidXQgd2l0aCBhIGZldyBrZXkgZGlmZmVyZW5jZXMuIA0KDQpGb3Igb3VyIGRhdGE6DQoNCiogVGhlIHBsb3QgaXMgY2VudHJlZCBhdCAwIG9uIHRoZSB4LWF4aXMuDQoqIEVhY2ggcG9pbnQgcmVwcmVzZW50cyBhIGdlbmUuDQoqIEEgcG9pbnQgY2xvc2UgdG8gYHg9MGAgcmVwcmVzZW50cyBhIGdlbmUgdGhhdCBpcyBwcm9iYWJseSBub3QgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkLg0KKiBQb2ludHMgZmFyIGZyb20gYHg9MGAgcmVwcmVzZW50IGdlbmVzIHRoYXQgYXJlIHByb2JhYmx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZC4NCiogUG9pbnRzIGZhciBmcm9tIGB5PTBgIHJlcHJlc2VudCBnZW5lcyB3aXRoIHNtYWxsIHAtdmFsdWVzLg0KDQpUaGVyZWZvcmUsIHBvaW50cyB0aGF0IGFyZSBmYXIgZnJvbSBib3RoIGB4PTBgIGFuZCBgeT0wYCBtb3N0IGxpa2VseSByZXByZXNlbnQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcy4NCg0KIyMgeyN2b2xjYW5vcGxvdH0NCg0KVG8gY3JlYXRlIGEgdm9sY2FubyBwbG90IGluIFIsIHdlIGNhbiBqdXN0IHVzZSB0aGUgYHBsb3RgIGZ1bmN0aW9uIC0gdGhlIGtleSBpcyBpbiB0aGUgZGF0YSB3ZSBwcm92aWRlIHRvIHRoaXMgZnVuY3Rpb24uIFJ1biB0aGUgUiBjb2RlIGJlbG93IGFuZCB0YWtlIGEgbG9vayBhdCB0aGUgb3V0cHV0Lg0KDQpgYGAge3IsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBsb3QodGhhbGVfY3Jlc3NfZGF0YSR0YWJsZSRsb2dGQywgDQogICAgIC1sb2cxMCh0aGFsZV9jcmVzc19kYXRhJHRhYmxlJFBWYWx1ZSksIA0KICAgICBwY2ggPSAyMCwgY2V4ID0gMC41LCBjb2wgPSAiYmx1ZSIsDQogICAgIG1haW4gPSAiVm9sY2FubyBQbG90IGZvciBhbGwgVGhhbGUgQ3Jlc3MgR2VuZXMNCiAgICAgZm9yIHRoZSB0aW1lcG9pbnRzIFgyNGhTTCBhbmQgWDQ4aFNMIiwNCiAgICAgeWxhYj0iLWxvZzEwKHAtdmFsdWUpIiwgeGxhYj0ibG9nRkMiKQ0KYGBgDQoNCipOb3RlOiBIZXJlIHRoZSBgbG9nRkNgIHgtYXhpcyBsYWJlbCByZWZlcnMgdG8gdGhlIGxvZyBvZiB0aGUgcmF0aW8gb2YgdGhlIGdlbmUgY291bnQgbWVhc3VyZW1lbnRzIGF0IHRoZSB0d28gdGltZSBwb2ludHMgKHRoZSBsb2ctZm9sZC1jaGFuZ2UpLiBBIHZhbHVlIGNsb3NlIHRvIDAgbWVhbnMgdGhhdCB0aGUgbWVhc3VyZW1lbnQgaGFzbid0IGNoYW5nZWQgbXVjaCBpbiB0aGUgMjQgaG91ciBwZXJpb2QsIHdoaWxlIGEgbGFyZ2VyIHZhbHVlIG1lYW5zIHRoZXJlIGhhcyBiZWVuIGEgbGFyZ2VyIGNoYW5nZSAoZWl0aGVyIHBvc2l0aXZlIG9yIG5lZ2F0aXZlKS4qDQoNCiMjDQoNClVzaW5nIHRoZSBjb2RlIHNob3duIGFib3ZlIGluIFxAcmVmKHZvbGNhbm9wbG90KSBhcyBhIGJhc2UsIGNyZWF0ZSB2b2xjYW5vIHBsb3RzIGZvciB5b3VyIGB0aGFsZV9jcmVzc19ib25mZXJyb25pX2ZpbHRlcmVkYCBhbmQgYHRoYWxlX2NyZXNzX2Zkcl9maWx0ZXJlZGAgb2JqZWN0cy4NCg0KIyMNCg0KQ29tcGFyZSB5b3VyIHZvbGNhbm8gcGxvdHMgd2l0aCBlYWNoIG90aGVyLCBhbmQgd2l0aCB0aGUgdm9sY2FubyBwbG90IHNob3duIGluIFxAcmVmKHZvbGNhbm9wbG90KS4NCg0KRG8geW91IHRoaW5rIHRoYXQgdGhlICRwJC12YWx1ZSBhZGp1c3RtZW50cyB5b3UgcGVyZm9ybWVkIHdlcmUgYmVuZWZpY2lhbCBpbiBpZGVudGlmeWluZyB0aGUgZ2VuZXMgd2hpY2ggd2VyZSBtb3N0IGxpa2VseSB0byBiZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiB0aGUgdGltZSBwb2ludHMgYFgyNGhTTGAgYW5kIGBYNDhoU0xgPw0KDQpMb29raW5nIGF0IHlvdXIgdHdvIHZvbGNhbm8gcGxvdHMsIGhhcyB5b3VyIHByZWZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGBwLmFkanVzdGAgbWV0aG9kcyB5b3UgdXNlZCBjaGFuZ2VkPyBXaHkvd2h5IG5vdD8NCg0KPGJyPg0KDQojIyMjIEdyZWF0IHdvcmssIHRoYXQncyBldmVyeXRoaW5nIGZvciB0b2RheSEgIyMjIyB7LX0NCg0KVGhhdCB3YXMgYSBsb3QgdG8gY292ZXIgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgc3VwcGxlbWVudCBtYXRlcmlhbCwgYnV0IGhvcGVmdWxseSB0aGlzIGxhYiBoYXMgZ2l2ZW4geW91IGEgdGFzdGUgb2YgdGhlIHdvcmxkIG9mIEJpb2luZm9ybWF0aWNzLCBhbmQgdGhlIGludGVncmFsIHJvbGUgb2Ygc3RhdGlzdGljcyB3aXRoaW4gdGhpcyB3b3JsZC4NCg0KQnkgY29uZHVjdGluZyB0aGlzIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcywgd2UgaGF2ZSBiZWVuIGFibGUgdG8gaWRlbnRpZnkgZ2VuZXMgdGhhdCBhcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBiZXR3ZWVuIHR3byBzZWVkIGdlcm1pbmF0aW9uIHRpbWUgcG9pbnRzIGZvciB0aGUgdGhhbGUgY3Jlc3MgcGxhbnQuIA0KDQpXaGlsZSB0aGlzIG1pZ2h0IG5vdCBzZWVtIGltbWVkaWF0ZWx5IGdyb3VuZC1icmVha2luZywgaXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHdlIGNvdWxkIHVzZSB0aGUgc2FtZSBwcm9jZWR1cmUgdG8gaWRlbnRpZnksIGZvciBleGFtcGxlLCBnZW5lcyB0aGF0IGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGJldHdlZW4gYSBoZWFsdGh5IGh1bWFuIGdlbm9tZSwgYW5kIHRoZSBnZW5vbWUgb2YgYSBodW1hbiB3aXRoIGEgY2VydGFpbiBpbGxuZXNzIG9yIGRpc2Vhc2UuIFRoaXMgaGFzIGltbWVkaWF0ZSBwcmFjdGljYWwgaW1wbGljYXRpb25zLCBhbmQgY291bGQgZm9yIGV4YW1wbGUgbGVhZCB0byB0aGUgZGV2ZWxvcG1lbnQgb2YgZHJ1Z3Mgd2hpY2ggdGFyZ2V0IHRob3NlIGdlbmVzIGluIGFuIGVmZm9ydCB0byByZWR1Y2UgdGhlIHN1ZmZlcmluZyBvZiBpbmRpdmlkdWFscyB3aXRoIHRoYXQgY29uZGl0aW9uIChvciBwb3NzaWJseSBldmVuIGN1cmUgdGhlIGNvbmRpdGlvbikuDQoNCg0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZS4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9yIG5hbWVkIGFib3ZlLCB3aXRoIHRoZSBEZXBhcnRtZW50IG9mIE1hdGhlbWF0aWNzIGFuZCBTdGF0aXN0aWNzIGFuZCB3aXRoIExhIFRyb2JlIFVuaXZlcnNpdHkuIENvcHlyaWdodCBpbiB0aGlzIHdvcmsgaXMgdmVzdGVkIGluIExhIFRyb2JlIFVuaXZlcnNpdHkgaW5jbHVkaW5nIGFsbCBMYSBUcm9iZSBVbml2ZXJzaXR5IGJyYW5kaW5nIGFuZCBuYW1pbmcuIFVubGVzcyBvdGhlcndpc2Ugc3RhdGVkLCBtYXRlcmlhbCB3aXRoaW4gdGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob24gQ29tbWVyY2lhbC1Ob24gRGVyaXZhdGl2ZXMgTGljZW5zZSANCjxhIGhyZWYgPSAiaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLW5kLzQuMC9DQyIgdGFyZ2V0PSJfYmxhbmsiPiBCWS1OQy1ORC4gPC9hPg0KPC9mb250Pg==