1. Basic Unix
UNIX is an operating system that was developed in the 1960s and it has been the base of widely used operating systems such as Linux and Mac OS. As the data coming out from biological outputs growing exponentially through time, Knowing the UNIX basics have become essential to do bioinformatics. Here there is a list of the most used commands:
cd |
Tove between directories |
cd FASTQ (to enter a folder) |
cd .. |
To change to the parent of the current directory |
|
cd - |
To go to previous directory |
|
pwd |
Where am I? |
|
ls |
List files |
ls (on this directory); ls FASTQ (list files inside FASTQ) |
mkdir |
make new directory |
mkdir my_folder |
mv |
move a file or directory |
mv file my_folder/ (move file to a folder) |
cp |
copy file |
cp my_folder/* new_folder/ (copy all files of al folder) |
rm |
Remove a file or folder |
rm file ; rm -rf folder |
less |
Displays the contents of a file |
less file.txt (press q to quit) |
head |
Displays the first ten lines of a file |
|
tail |
Displays the last ten lines of a file |
|
cat |
Print file content |
cat file1 file2 > file.total (merge files) |
zcat |
Print file content of compresed files |
zcat SRR7889597.fastq.gz |
gzcat |
mac OSx version of zcat |
gzcat SRR7889597.fastq.gz |
wc |
word count |
wc -l file (count lines inside of a file) |
grep |
Pattern matching |
grep patern file (get lines that match the patern) |
cut |
extract columns from files |
cut -f 2 file (extract second column) |
sort |
sort file by column |
sort -nr -k 2 file (sort file by second column) |
Exercise 1.0.1
On the course directory, create a folder named test_folder
and copy the smallest file inside FASTQ/
folder. Then change the name of the folder that you just create to to_delete
and finally remove this folder.
1.2 Efficient use of the terminal
To accelerate our interaction with the terminal, we can use the TAB key:
For instance, if you are at course folder and you write ls Gene_
and then press TAB key once, it will complete the command to ls Gene_annotation
. But if you just write ls G
and press TAB two times, it will show you the two options (Gene_annotation and Genome).
Another powerful thing is to pipe (|
) the output of one command into and another command. For example you can do:
ls FASTQ/*.fastq.gz | wc -l
To count all the FASTQ files that are stored inside of FASTQ/
folder.
Finally, if you want to know more, every command has its own options, you can see the entire description of a command using man
. For instance, use man to know more about head
typing on the command line:
man head
Exercise 1.2.1
Read the manual of head
command. Then use it to extract the first 100 lines of Gene_annotation/dm6.Ensembl.genes.gtf
and count all the lines that have CDS
in the third column.
3. Quality control before alingment
3.1 FASTQC
To perform a QC of the Fastq files we can use FastQC. We can access to a basic manual of this tool by typing on fastqc --help
on terminal.
Exercise 3.1.1
Create a directory named QC
. Read fastqc
help manual to run it for FASTQ/SRR7889585.fastq.gz
and store the results at the newly created folder (QC
). To speed it up, use 7 threads (which it will allow our machines to use 7 processors). You will get an html file as output; Open it with an internet browser (Chrome, Firefox, etc) and answer the following questions:
- What is the read length?
- Does the quality score very through the read length?
- How is the data’s quality?
3.2 Metadata analysis on R-studio
The fastq.gz files that we have at /FASTQ
correspond to RNA-seq data extracted from D. melanogaster brain samples. The data corresponding to a full study published last year on Cell Reports and the full study was published in SRA archive.
Exercise 3.2.1
Check the study runs and compare with the file names from FASTQ/
folder. Which tissues the samples were extracted from? Select the Runs that correspond to the files that we have and download the RunInfo Table
corresponding to these tables and save it as SraRunTable.txt
on the course folder.
Exercise 3.2.2
Open R-studio and open the Day1.Rmd
file that is located at the course folder. This is an R-notebook file, that has all the code used to generate this document. But, now when you open this file you will be able to run chunks
of code interactively inside R-studio. Run the following chunk by clicking at the green play button.
library(data.table)
metadata <- fread("./SraRunTable.txt") #Please be sure to place the file under ./Course_Materials/00_Reproducible_RNA-Seq_Processing/
metadata
By running this code, we imported the metadata as a data.table object, which corresponds to a very convenient structure to manipulate data in R. For more information visit this link. We can now easily manipulate the data! For example, we can filter the metadata rows, so we only see the ones corresponding to “central neurons”
metadata[source_name=="central neurons" , ]
We can also get explore if we have a lowly sequenced sample filtering by the MBases
values
metadata[MBases < 100 , ]
Or get the average Mega bases across this sample
metadata[ , mean(MBases) ]
To explore this visually, we can plot with ggplot2. This is one of the most popular packages to visualize data. A basic code to visualize the Mbases distribution can be run as:
library(ggplot2)
ggplot(data = metadata) + # Frist layer - Data input
geom_bar(aes(x=Run, y=MBases), stat = "identity") # second layer - type of plot and axis
We can rotate the text to make it more visible
ggplot(data=metadata) +
geom_bar(aes(x=Run, y=MBases, ), stat = "identity") +
theme(axis.text.x = element_text(angle = 45)) # Third layer - visual configuration
inside aes( )
are the variables and we can also define a variable as the colour:
ggplot(data=metadata) +
geom_bar(aes(x=Run, y=MBases, colour=source_name), stat = "identity") +
theme(axis.text.x = element_text(angle = 45))
But for this particular type of graph, filling the bar with one colour is more suitable
ggplot(data=metadata) +
geom_bar(aes(x=Run, y=MBases, fill=source_name), stat = "identity") +
theme(axis.text.x = element_text(angle = 45))
From this plot, we can clearly see that one of the samples that were taken from central neurons is much smaller than the rest. This factor needs to be considered at the time we analyze the samples, as this poorly sequenced sample might have lead to less accurate mRNA quantification and it might need to be removed for quantitative analyses.
4. Mapping reads to the genome and getting raw counts
After we have a diagnosis of the data quality, we can start to analyse the data. Usually, the first step into the analysis requires mapping the RNA-seq reads to the genome. There are numerous tools to do perform short read alignment and the choice of it should be carefully made according to the analysis goals and requirements. Hisat2 is a very fastq tool that has been shown to have a good performance on published benchmarks.
4.1 Indexing the genome for Hisat2
To start mapping RNA-seq reads to the genome, we need to index the genome. The command to do this is hisat2-build
.
hisat2-build --help
Exercise 4.1.1.
Go to Course_Materials/00_Reproducible_RNA-Seq_Processing
directory using cd
(This is going to be our base directory to solve all the following exercises). Do ls
to list the directories and create a new folder called Index
inside Genome
folder. Then run the following command:
hisat2-build -p 7 Genome/dm6.fa Genome/Index/dm6
This command will use the genome (located at Genome/dm6.fa
) and it will generate the index files on Genome/Index/
. All the files will start with dm6
prefix. Take a look at hisat2-build
help,
- Why do we use
-p 7
and what is the maximun=m value we should use on these machines?
- How many files are created on this process?
4.2 Hisat2
To map the reads to the genome we need to run hisat2. Take a quick look to hisat2’s description
hisat2 --help
Exercise 4.2.1
Run hisat2 for the smallest file, located at FASTQ folder using 7 proccesors. Save the results inside a folder named hisat2
(create it before using mkdir
) and save the results using the right extension (.sam
). hint: use hisat --help
and look for -p -U -x flags and tt the end of the command use >
to save the resuls to a file.
4.4 Visualise BAM files
BAMs can be used for different downstream analyses. But most of them require the BAM files to be sorted
. When a BAM file is sorted, the alignments are ordered by the position they map to. BAM files can be sorted using samtools sort
and following this formula:
samtools sort sample.bam -o sample.sorted.bam
To visualise a BAM’s alignment, we need to index it first. Which can be made with samtools index
:
samtools index sample.sorted.bam
Exercise 4.4.1
- Sort and Index your BAM file.
- Open IGV, load D. melanogaster’s genome (dm6) and load the sorted bamfile.
IGV help
Load the reference genome. On the top menu bar find the genomes dropdown (top-left) and then find D. melanogaster
assembly dm6. You might need to click on ‘More…’ to see a list of available genomes.
Load the BAM file. On the top menu bar go to ‘File –> Load from File…’ and select the sorted BAM file you have created on the previous step.
Zoom in into a particular gene to see the read alignments.
4.5 FeatureCounts
To count the number of reads we will use FeatureCounts, which uses a gene annotation file (GTF) to process the genomic intervals of every gene and count all the reads that map to the exonic regions.
Exercise 4.2.2
Run featureCounts providing the transcript annotation and the same file you produced with hisat2. To do this, read the featureCount help manual and find the rights flags run featureCounts (hint: read the Required arguments
section).
Exercise 4.2.2
Find the gene with the highest number of counts. Can we say this gene is the one with higher expression levels on this sample?
5. Introduction to reporducible bioinformatics
Until this point, we have introduced every command mannually in the terminal. Please check how many files do we have at FASTQ/
. Do you think you can get the raw counts from all the samples without having errors? what about processing hundred of samples, is it reasonable to do it manually?
The answer is clearly no. We need systematic ways to process data to avoid errors and enable reproducibility in our analyses. This is why we are going to use a workflow manager to execute the remaining steps to get the raw counts from our samples.
Snakemake is currently one most popular workflow managers to work with bioinformatic software. To install snakemake please the following command:
conda create -n snakemake_env snakemake
By doing this we created a virtual environment, called snakemake_env
that has latest version of snakemake and our it dependencies installed. Now to activate this environment, write:
conda activate snakemake_env
As we already wrote a snakemake
pipeline for you, we are going to demonstrate you some of its properties and how to use it. To see the code from the this pipeline, Use Atom
(or any text editor) to open the Snakefile
. Can you recognize some of the steps that we have done already?. Every rule
represent a step of the analysis. For example:
rule hisat2_Genome_index:
input:
"Genome/dm6.fa"
output:
"Genome/Index/dm6.1.ht2"
threads: 7
conda:
"envs/core.yaml"
log:
"logs/hisat2_Genome_index.log"
shell:
"hisat2-build -p {threads} {input} Genome/Index/dm6 2> {log}"
This code correspond to the indexing step, in which it takes Genome/dm6.fa
as input and Genome/Index/dm6.1.ht2
as output. The rules have several key
words by which different parts of the command are declared: * input: set of intput files, in this case just “Genome/dm6.fa” * output: set of output files. In this case, more output files are created, but they do not have to be pointed by the commands, we can just refer to one of the files that is created. Snakemake will check if this file is successfully created after the process is finished. * threads: number of processors * conda: the virtual environment in which the process will be run. * log : file that store anything that hisat2 outputs while is creating the index. * shell : This is the formula to create the shell command given all the parameters described above.
The indexing rule is directly connected to the following mapping rule:
rule hisat2_to_Genome:
input:
fastq = "FASTQ/{sample}.fastq.gz",
genome = "Genome/Index/dm6.1.ht2"
output:
temp("hisat2/{sample}.sam") # Temporary output
threads: 3
conda:
"envs/core.yaml"
log:
"logs/hisat2_to_Genome.{sample}.log"
shell:
"hisat2 -p 3 -U {input.fastq} -x Genome/Index/dm6 > {output} 2> {log}"
This rule takes fastq files as input and also the genome index files. All the sample names were obtained fromNCBI_accession_list.txt
file, which contains the SRA accession codes corresponding to all the samples that we are analysing. Inside the rule {sample}
takes the value of every accession code, and allow snakemake to generate all the mapping commands for every sample. As we here set threads
as 3, every mapping process will use 3 processors, which means that 2 mapping processes can be run in parallel when 7 cores are provided.
The next rule bamstats
take every SAM file and transform it to BAM, but also the BAM file is sorted and indexed at the same time:
rule samTobam:
input:
"hisat2/{sample}.sam"
output:
"hisat2/{sample}.sorted.bam"
conda:
"envs/core.yaml"
shell:
"samtools view -b {input} | samtools sort - -o {output} && samtools index {output} "
Because SAM files were produced as temporary files (temp("hisat2/{sample}.sam")
), as soon as samTobam
finishes, SAM files are deleted. This optimizes the disk space, which is important when a large number of samples are processed.
Finally, all these steps converge at:
rule featureCounts:
input:
gtf = "Gene_annotation/dm6.Ensembl.genes.gtf",
bam = expand("hisat2/{sample}.sorted.bam", sample=SAMPLES)
output:
"featureCounts/total_samples.gene_count.txt"
threads: 1
conda:
"envs/core.yaml"
log:
"logs/featureCounts.total.log"
shell:
"featureCounts -a {input.gtf} -o {output} {input.bam} 2> {log}"
Where {input.gtf}
list all the sorted bam that we generated. Notice that this Snakefile starts with include: "rules/00_download_data.skm"
, which is a statement that connects this Snakefile with rules/00_download_data.skm
. This is a script that read all accession codes from NCBI_accession_list.txt
and stores those at SAMPLES
, which is then used by expand("hisat2/{sample}.sorted.bam", sample=SAMPLES)
to generate the list of all sorted BAM files.
5.1 Quantifying all the samples at once
We have only qualified one sample so far, but now executing the Snakefie, we can process all the other samples in parallel. For this, we first are going to do a dry-run
to check the list of commands that snakemake will run for us. On the command line (in our base folder, 00_Reproducible_RNA-Seq_Processing
), please write:
snakemake -np featureCounts
This command shows us all the steps that snakemake will until executing a rule named featureCounts (see Snakefile’s code) which run featureCounts
over all the samples. Where -n
prevent snakemake from running the pipeline and -p
prints the commands for each step.
To visualise these steps run:
snakemake featureCounts --dag | dot -Tpng > featureCounts.png
This will produce the following image:
Which help us to understand the planned job execution.
Finally, to run these steps we need to enable snakemake to use the environment files are needed for each rule by including --use-conda
and also we should limit the number of processors to 7 with --cores 7
.
Exercise 5.1.1
Execute snakemake
to quantify all the samples using featureCounts. Look inside Snakefile
code to see where the final output of featureCount will be stored and compare it with the output we previously had using featureCounts.
Exercise 5.1.2
Snakemake can have individual files as a target. The following rule:
rule bamstats:
input:
"hisat2/{sample}.sorted.bam"
output:
stats_txt = "QC/{sample}/{sample}.stats",
stats_html = "QC/{sample}/{sample}.plots.html"
params:
"QC/{sample}/{sample}.plots"
conda:
"envs/core.yaml"
shell:
"samtools stats {input} > {output.stats_txt} && plot-bamstats -p {params} {output.stats_txt}"
Was not included as part of our workflow, as it was not required to run featureCounts. To run this rule for a particular file, you have target one of the output that is generated by this rule for a particular file using the following formula:
snakemake --use-conda QC/SAMPLE/SAMPLE.plots.html
Where SAMPLE can be any of the accession codes from NCBI_accession_list.txt
. Can you run this rule? What useful information can be found on the output html file>
LS0tCnRpdGxlOiAiIFJlcHJvZHVjaWJsZSBSTkEtc2VxIFByb2NlZXNzaW5nIC0gRGF5MSAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgojIDEuIEJhc2ljIFVuaXgKCgpVTklYIGlzIGFuIG9wZXJhdGluZyBzeXN0ZW0gdGhhdCB3YXMgZGV2ZWxvcGVkIGluIHRoZSAxOTYwcyBhbmQgaXQgaGFzIGJlZW4gdGhlIGJhc2Ugb2Ygd2lkZWx5IHVzZWQgb3BlcmF0aW5nIHN5c3RlbXMgc3VjaCBhcyBMaW51eCBhbmQgTWFjIE9TLiBBcyB0aGUgZGF0YSBjb21pbmcgb3V0IGZyb20gYmlvbG9naWNhbCBvdXRwdXRzIGdyb3dpbmcgZXhwb25lbnRpYWxseSB0aHJvdWdoIHRpbWUsIEtub3dpbmcgdGhlIFVOSVggYmFzaWNzIGhhdmUgYmVjb21lIGVzc2VudGlhbCB0byBkbyBiaW9pbmZvcm1hdGljcy4gSGVyZSB0aGVyZSBpcyBhIGxpc3Qgb2YgdGhlIG1vc3QgdXNlZCBjb21tYW5kczoKCgp8Q29tbWFkfCBVc2V8IEV4YW1wbGVzfCAgCnwtLTp8LS06fC0tLS0tOnwKfGBjZGAgfCBUb3ZlIGJldHdlZW4gZGlyZWN0b3JpZXN8IGBjZCBGQVNUUWAgKHRvIGVudGVyIGEgZm9sZGVyKXwKfGBjZCAuLmAgfCBUbyBjaGFuZ2UgdG8gdGhlIHBhcmVudCBvZiB0aGUgY3VycmVudCBkaXJlY3Rvcnl8IHwKfGBjZCAtYCB8IFRvIGdvIHRvIHByZXZpb3VzIGRpcmVjdG9yeXwgfAp8YHB3ZGAgfCBXaGVyZSBhbSBJP3wgfAp8YGxzYCB8IExpc3QgZmlsZXMgfCBgbHNgIChvbiB0aGlzIGRpcmVjdG9yeSk7IGBscyBGQVNUUWAgKGxpc3QgZmlsZXMgaW5zaWRlIEZBU1RRKSB8CnxgbWtkaXJgIHwgbWFrZSBuZXcgZGlyZWN0b3J5fCBgbWtkaXIgbXlfZm9sZGVyYCB8CnxgbXZgIHwgbW92ZSBhIGZpbGUgb3IgZGlyZWN0b3J5fCBgbXYgZmlsZSBteV9mb2xkZXIvYCAobW92ZSBmaWxlIHRvIGEgZm9sZGVyKSB8CnxgY3BgIHwgY29weSBmaWxlfCBgY3AgbXlfZm9sZGVyLyogbmV3X2ZvbGRlci9gIChjb3B5IGFsbCBmaWxlcyBvZiBhbCBmb2xkZXIpIHwKfGBybWAgfFJlbW92ZSBhIGZpbGUgb3IgZm9sZGVyfCBgcm0gZmlsZWA7IGBybSAtcmYgZm9sZGVyYCB8CnxgbGVzc2AgfERpc3BsYXlzIHRoZSBjb250ZW50cyBvZiBhIGZpbGV8IGBsZXNzIGZpbGUudHh0YCAocHJlc3MgYHFgIHRvIHF1aXQpIHwKfGBoZWFkYHwgRGlzcGxheXMgdGhlIGZpcnN0IHRlbiBsaW5lcyBvZiBhIGZpbGUgfCB8CnxgdGFpbGB8IERpc3BsYXlzIHRoZSBsYXN0IHRlbiBsaW5lcyBvZiBhIGZpbGUgfCB8CnxgY2F0YCB8UHJpbnQgZmlsZSBjb250ZW50fGBjYXQgZmlsZTEgZmlsZTIgPiBmaWxlLnRvdGFsYCAobWVyZ2UgZmlsZXMpfAp8YHpjYXRgIHxQcmludCBmaWxlIGNvbnRlbnQgb2YgY29tcHJlc2VkIGZpbGVzfGB6Y2F0IFNSUjc4ODk1OTcuZmFzdHEuZ3pgIHwKfGBnemNhdGAgfG1hYyBPU3ggdmVyc2lvbiBvZiB6Y2F0ICAgfGBnemNhdCBTUlI3ODg5NTk3LmZhc3RxLmd6YCB8Cnxgd2NgIHwgd29yZCBjb3VudCB8IGB3YyAtbCBmaWxlIGAgKGNvdW50IGxpbmVzIGluc2lkZSBvZiBhIGZpbGUpfAp8YGdyZXBgIHwgUGF0dGVybiBtYXRjaGluZyB8IGBncmVwIHBhdGVybiBmaWxlYCAoZ2V0IGxpbmVzIHRoYXQgbWF0Y2ggdGhlIHBhdGVybil8CnwgYGN1dGAgfCBleHRyYWN0IGNvbHVtbnMgZnJvbSBmaWxlcyB8IGBjdXQgLWYgMiBmaWxlYCAoZXh0cmFjdCBzZWNvbmQgY29sdW1uKQp8YHNvcnRgIHwgc29ydCBmaWxlIGJ5IGNvbHVtbiB8YHNvcnQgLW5yIC1rIDIgZmlsZWAgKHNvcnQgZmlsZSBieSBzZWNvbmQgY29sdW1uKSB8IAoKCioqRXhlcmNpc2UgMS4wLjEqKgoKT24gdGhlIGNvdXJzZSBkaXJlY3RvcnksIGNyZWF0ZSBhIGZvbGRlciBuYW1lZCBgdGVzdF9mb2xkZXJgIGFuZCBjb3B5IHRoZSBzbWFsbGVzdCBmaWxlIGluc2lkZSBgRkFTVFEvYCBmb2xkZXIuIFRoZW4gY2hhbmdlIHRoZSBuYW1lIG9mIHRoZSBmb2xkZXIgdGhhdCB5b3UganVzdCBjcmVhdGUgdG8gYHRvX2RlbGV0ZWAgYW5kIGZpbmFsbHkgcmVtb3ZlIHRoaXMgZm9sZGVyLiAKCgojIyAxLjIgRWZmaWNpZW50IHVzZSBvZiB0aGUgdGVybWluYWwgCgoKVG8gYWNjZWxlcmF0ZSBvdXIgaW50ZXJhY3Rpb24gd2l0aCB0aGUgdGVybWluYWwsIHdlIGNhbiB1c2UgdGhlIFRBQiBrZXk6ICAKCiFbXShJbWFnZXMvVEFCLnBuZykgCgpGb3IgaW5zdGFuY2UsIGlmIHlvdSBhcmUgYXQgY291cnNlIGZvbGRlciBhbmQgeW91IHdyaXRlIGBscyBHZW5lX2AgYW5kIHRoZW4gcHJlc3MgVEFCIGtleSBvbmNlLCBpdCB3aWxsIGNvbXBsZXRlIHRoZSBjb21tYW5kIHRvIGBscyBHZW5lX2Fubm90YXRpb25gLiBCdXQgaWYgeW91IGp1c3Qgd3JpdGUgYGxzIEdgIGFuZCBwcmVzcyBUQUIgdHdvIHRpbWVzLCBpdCB3aWxsIHNob3cgeW91IHRoZSB0d28gb3B0aW9ucyAoR2VuZV9hbm5vdGF0aW9uIGFuZCBHZW5vbWUpLgoKQW5vdGhlciBwb3dlcmZ1bCB0aGluZyBpcyB0byBwaXBlIChgfGApIHRoZSBvdXRwdXQgb2Ygb25lIGNvbW1hbmQgaW50byBhbmQgYW5vdGhlciBjb21tYW5kLiBGb3IgZXhhbXBsZSB5b3UgY2FuIGRvOgoKYGxzIEZBU1RRLyouZmFzdHEuZ3ogfCB3YyAtbGAKClRvIGNvdW50IGFsbCB0aGUgRkFTVFEgZmlsZXMgdGhhdCBhcmUgc3RvcmVkIGluc2lkZSBvZiBgRkFTVFEvYCBmb2xkZXIuCgpGaW5hbGx5LCBpZiB5b3Ugd2FudCB0byBrbm93IG1vcmUsIGV2ZXJ5IGNvbW1hbmQgaGFzIGl0cyBvd24gb3B0aW9ucywgeW91IGNhbiBzZWUgdGhlIGVudGlyZSBkZXNjcmlwdGlvbiBvZiBhIGNvbW1hbmQgdXNpbmcgYG1hbmAuIEZvciBpbnN0YW5jZSwgdXNlIG1hbiB0byBrbm93IG1vcmUgYWJvdXQgYGhlYWRgIHR5cGluZyBvbiB0aGUgY29tbWFuZCBsaW5lOgoKYG1hbiBoZWFkYAoKKipFeGVyY2lzZSAxLjIuMSoqCgpSZWFkIHRoZSBtYW51YWwgb2YgYGhlYWRgIGNvbW1hbmQuIFRoZW4gdXNlIGl0IHRvIGV4dHJhY3QgdGhlIGZpcnN0IDEwMCBsaW5lcyBvZiBgR2VuZV9hbm5vdGF0aW9uL2RtNi5FbnNlbWJsLmdlbmVzLmd0ZmAgYW5kIGNvdW50IGFsbCB0aGUgbGluZXMgdGhhdCBoYXZlIGBDRFNgIGluIHRoZSB0aGlyZCBjb2x1bW4uIAoKIyAyLiBJbnB1dCBkYXRhIGZvcm1hdAoKCkluIG9yZGVyIHRvIHF1YW50aWZ5IG1STkEgYnkgUk5BLXNlcSBhbmFseXNpcywgZGlmZmVyZW50IGZpbGVzIGFyZSByZXF1aXJlZCB3aGljaCBhcyBhIGRpZmZlcmVudCBmb3JtYXQuIFJOQS1TZXEgcmVhZHMgYXJlIG5vcm1hbGx5IGZvcm1hdHRlZCBhcyBbRkFTVFFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0ZBU1RRX2Zvcm1hdCksIFNSQSBvciBDUkFNLiBUbyBwcm9jZXNzIHRoaXMgZGF0YSwgdGhlIG1vc3QgY29tbW9uIGluaXRpYWwgc3RlcCBpcyB0byBtYXAgdGhlIHJlYWRzIHRvIHRoZSBnZW5vbWUsIHdoaWNoIGlzIG9mdGVuIGZvcm1hdHRlZCBhcyBbRkFTVEFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0ZBU1RBX2Zvcm1hdCkuIEZpbmFsbHksIHRvIHF1YW50aWZ5IGdlbmUgZXhwcmVzc2lvbiwgd2UgbmVlZCB0byBrbm93IHdoaWNoIHBhcnQgb2YgdGhlIGdlbm9tZSBlbmNvZGVzIGZvciBnZW5lcy4gVGhpcyBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgYXQgZ2VuZSBhbm5vdGF0aW9uIGZpbGVzLCB3aGljaCBjYW4gYmUgZm9ybWF0dGVkIGFzIFtHVEZdKGh0dHA6Ly9tYmxhYi53dXN0bC5lZHUvR1RGMjIuaHRtbCNmaWVsZHMpIG9yIFtCRURdKGh0dHBzOi8vZ2Vub21lLnVjc2MuZWR1L0ZBUS9GQVFmb3JtYXQuaHRtbCNmb3JtYXQxKSBmaWxlcy4gRXhwbG9yZSB0aGUgZGlmZmVyZW50IGh5cGVybGlua3MgcHJvdmlkZWQgZm9yIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IHRoZSBkaWZmZXJlbnQgZmlsZSBmb3JtYXRzLgoKCiMjIDIuMSBGQVNUQSBmb3JtYXQKCkZBU1RBIGZpbGVzIGNvbnRhaW4gbnVjbGVvdGlkZSBvciBhbWlubyBhY2lkIHNlcXVlbmNlIGluZm9ybWF0aW9uLiBUaGUgZGF0YSBpcyBjb21wb3NlZCBvZiBpZGVudGlmaWVycywgd2hpY2ggc3RhcnRzIHdpdGggYD5gIGFuZCBudWNsZW90aWRlIG8gYW1pbm8gYWNpZCBzZXF1ZW5jZXMuIEh1bmRyZWQgb2YgdGhvdXNhbmRzIG9mIGdlbm9tZXMgY29taW5nIGZyb20gZGlmZmVyZW50IHNwZWNpZXMgYXJlIGF2YWlsYWJsZSBpbiBwdWJsaWMgcmVwb3NpdG9yaWVzIGFzIEZBU1RBIGZpbGVzLiBJdCBpcyBpbXBvcnRhbnQgdG8gbm90aWNlIHRoYXQgYSBnaXZlbiBzcGVjaWVzIGNhbiBoYXZlIGRpZmZlcmVudCBnZW5vbWljIGFzc2VtYmxpZXMuIEZvciBpbnN0YW5jZSwgYSBwb3B1bGFyIGFzc2VtYmx5IGh1bWFuIGdlbm9tZSBhc3NlbWJseSBpcyBgaGcxOWAgdGhhdCB3YXMgcHVibGlzaGVkIGluIEZlYnJ1YXJ5IDIwMDksIGFuZCBhcyBhIGh1Z2UgYW1vdW50IG9mIGRhdGEgaXMgYXZhaWxhYmxlIGZvciB0aGF0IGFzc2VtYmx5IHNvbWUgcmVzZWFyY2hlcnMga2VlcCBkb2luZyB0aGVpciBhbmFseXNlcyB3aXRoIHRoYXQgdmVyc2lvbi4gQnV0IG90aGVyIHJlY2VudCBhbmFseXNlcyBoYXZlIHN0YXJ0ZWQgdG8gdXNlIGBoZzM4YCBpbnN0ZWFkLCB3aGljaCB3YXMgcHVibGlzaGVkIGluIERlY2VtYmVyIDIwMTMgYW5kIHJlcHJlc2VudCBhIG1vcmUgY3VyYXRlZCB2ZXJzaW9uIG9mIHRoZSBodW1hbiBnZW5vbWUuCgpGb3IgdG9kYXkncyBwcmFjdGljZSwgd2UgYXJlIGdvaW5nIHRvIHdvcmsgd2l0aCBhIHNtYWxsZXIgZ2Vub21lLiBXZSBhbHJlYWR5IGhhdmUgZG93bmxvYWRlZCBmb3IgeW91IHRoZSBgZG02YCBhc3NlbWJseSBvZiBELiBtZWxhbm9nYXN0ZXIncyBnZW5vbWUsIGFuIGludmVydGVicmF0ZSBvcmdhbmlzbSB3aWRlbHkgdXNlZCBhcyBhIG1vZGVsIG9yZ2FuaXNtIGZvciBnZW5ldGljIGFuZCBiZWhhdmlvcmFsIHN0dWRpZXMuIFRoZSBnZW5vbWUgZmlsZSBpcyBhdCBjb3Vyc2UgbWF0ZXJpYWwgZm9sZGVyIGF0IGBHZW5vbWUvZG02LmZhYC4gCgoqKkV4ZXJjaXNlIDIuMS4xKioKCkNvdW50IHRoZSBudW1iZXIgb2Ygc2VxdWVuY2VzIHByZXNlbnQgYXQgYGRtNi5mYWAgKGhpbnQ6IGNvdW50IGxpbmVzIHRoYXQgc3RhcnQgd2l0aCBgPmAsIGJ1dCBhcyB0aGlzIGlzIGEgc3BlY2lhbCBVTklYIGNoYXJhY3RlciwgcmVmZXIgdG8gaXQgYXMgYFw+YC4gV2hpY2ggY29tbWFuZCBjYW4gYmUgdXNlZCBmb3IgcGF0dGVybiBtYXRjaGluZyBhbmQgY291bnQgbGluZXM/KS4gCgpJZiBlYWNoIHNlcXVlbmNlIGlzIHJlbGF0ZWQgdG8gYSBjaHJvbW9zb21lLCB3aHkgZG8gd2UgZmluZCBzbyBtYW55IHNlcXVlbmNlcz8gSG93IG1hbnkgbWFpbiBzY2FmZm9sZHMgY2FuIHlvdSBzZWU/CgoqKkV4ZXJjaXNlIDIuMS4yKioKCkNhbiB5b3UgY2FsY3VsYXRlIHRoZSBleGFjdCBudW1iZXIgb2YgbnVjbGVvdGlkZXMgdGhhdCB0aGlzIEQuIG1lbGFub2dhc3RlciBhc3NlbWJseSBpcyBtYWRlIG9mPyAoaGludDogZXhwbG9yZSBhZGRpdGlvbmFsIG9wdGlvbnMgb2YgYGdyZXBgIGFuZCBgd2NgKQoKCiMjIDIuMiBGQVNUUSBmb3JtYXQKClJOQS1zZXEgcmVhZHMgb2Z0ZW4gY29tZSBhcyBGQVNUUSwgd2hpY2ggaXMgYW4gZXh0ZW5zaW9uIG9mIEZBU1RBIGZpbGUgZm9ybWF0LiBFdmVyeSByZWFkIGlzIHJlcHJlc2VudGVkIGJ5IGZvdXIgbGluZXM6CgoqIEZpcnN0IGxpbmU6IHN0YXJ0IHdpdGggYEBgIGFuZCBjb3JyZXNwb25kIHRvIGEgcmVhZCBpZGVudGlmaWVyLiAKKiBTZWNvbmQgbGluZTogcmVhZCBudWNsZW90aWRlIHNlcXVlbmNlLgoqIFRoaXJkIGxpbmU6IFN0YXJ0IHdpdGggYCtgIGFuZCBpdCBjYW4gYmUgZm9sbG93ZWQgYnkgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiwgYnV0IG9mdGVuIGl0IGlzIGp1c3QgYCtgLgoqIEZvdXJ0aCBsaW5lOiAgUGhyZWQgcXVhbGl0eSBzY29yZSByZXByZXNlbnQgdGhlIHJlbGlhYmlsaXR5IG9mIGEgYmFzZSBjYWxsIChhcyBoaWdoZXIgdGhlIGJldHRlcikuIEl0IGlzIGVuY29kZWQgYXMgQVNDSUkgY2hhcmFjdGVycy4gSXQgY2FuIGhhdmUgZGlmZmVyZW50IGVuY29kaW5ncywgc3VjaCBhcyBTYW5nZXIsIFNvbGV4YSwgSWxsdW1pbmEgMS4zKyBvciBJbGx1bWluYSAxLjgrLiBQbGVhc2UgY2hlY2sgW0ZBU1RRIGZvcm1hdCBkZXNjcmlwdGlvbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRkFTVFFfZm9ybWF0KSBmb3IgbW9yZSBkZXRhaWxzLgoKKipFeGVyY2lzZSAyLjIuMSoqCgpXaGljaCBvZiB0aGUgZmFzdHEgZmlsZXMgZm91bmQgYXQgYEZBU1RRL2AgaGFzIHRoZSBoaWdoZXN0IGFuZCB0aGUgbG93ZXN0IGFtb3VudCBvZiByZWFkcz8gSG93IG1hbnkgcmVhZHMgZG8gdGhleSBoYXZlPyBXaGF0IGlzIHRoZSByZWFkIGxlbmd0aD8KCgojIyAyLjMgR2VuZSBhbm5vdGF0aW9uCgpFZmZvcnRzIGhhdmUgYmVlbiBtYWRlIHRvIGlkZW50aWZ5IHRoZSBnZW5vbWljIHJlZ2lvbnMgdGhhdCBlbmNvZGUgZm9yIGdlbmVzLiBUaGlzIGluZm9ybWF0aW9uIGNhbiBiZSBzdG9yZWQgYXMgQkVEIG9yIEdURiBmaWxlcyAoYW1vbmcgb3RoZXIgZm9ybWF0cykuIEJFRCBmaWxlcyBzdG9yZSBpbmZvcm1hdGlvbiBhYm91dCBnZW5vbWljIGNvb3JkaW5hdGVzLiBFYWNoIHJvdyBvZiBhIEJFRCBmaWxlIHJlcHJlc2VudHMgYSBnZW5vbWljIGludGVydmFsLCBpbiB0aGUgY2FzZSBvZiBnZW5lIGFubm90YXRpb24gZmlsZSwgaXQgcmVwcmVzZW50cyB0aGUgc3RhcnQgYW5kIGVuZCBvZiBhIHRyYW5zY3JpcHQuIEV4b25zIGNvb3JkaW5hdGVzIGFyZSBlbmNvZGVkIGFzIGBibG9ja3NgLCB3aGVyZSB0aGUgYGJsb2NrU3RhcnRzYCBjb2x1bW4gaXMgYSBsaXN0IG9mIGFsbCBleG9uIHN0YXJ0cyByZWxhdGl2ZSB0byB0aGUgdHJhbnNjcmlwdCBzdGFydHMgYW5kIGBibG9ja1NpemVzYCBjb2x1bW4gY29udGFpbiBhbGwgdGhlIGV4b24gc2l6ZXMuIFBsZWFzZSByZWFkIFtCRUQgZGVzY3JpcHRpb24gZm9ybWF0XShodHRwczovL2dlbm9tZS51Y3NjLmVkdS9GQVEvRkFRZm9ybWF0Lmh0bWwjZm9ybWF0MSkgZm9yIG1vcmUgaW5mb3JtYXRpb24uIAoKR1RGIGZpbGVzIGluc3RlYWQgYXJlIGdlbmUtY2VudHJpYyBhbm5vdGF0aW9ucywgaW4gd2hpY2ggYSBnZW5lIGNhbiBiZSBkZXNjcmliZWQgYnkgbXVsdGlwbGUgcm93cy4gRWFjaCByb3cgY29udGFpbnMgdGhlIGNvb3JkaW5hdGVzIGFuZCBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9mIGEgcGFydGljdWxhciBnZW5lIGZlYXR1cmUuIFBsZWFzZSBjaGVjayB0aGUgZnVsbCBbR1RGIGRlc2NyaXB0aW9uXShodHRwOi8vbWJsYWIud3VzdGwuZWR1L0dURjIyLmh0bWwpCgoKKipFeGVyY2lzZSAyLjMuMSoqCgoKR2V0IEQuIG1lbGFub2dhc3RlciBnZW5lIGFubm90YXRpb24gZmlsZXMgZm9yIGBkbTZgIGFzc2VtYmx5IGluIGZyb20gW1VDU0MgVGFibGUgQnJvd3Nlcl0oaHR0cDovL2dlbm9tZS1ldXJvLnVjc2MuZWR1L2NnaS1iaW4vaGdUYWJsZXMpLiBDaG9vc2luZyB0aGUgZm9sbG93aW5nIHZhbHVlczoKCiogY2xhZGU6IEluc2VjdC4KKiBnZW5vbWU6IEQuIG1lbGFub2dhc3Rlci4KKiBhc3NlbWJseTogQXVnLiAyMDE0IChCREdQIFJlbGVhc2UgNiArIElTTzEgTVQvZG02KS4KKiBncm91cDogR2VuZSBhbmQgR2VuZSBQcmVkaWN0aW9ucy4KKiB0cmFjazogRW5zZW1ibCBHZW5lcy4KKiB0YWJsZTogZW5zR2VuZS4KCkFuZCBnZXQgdGhlIGFubm90YXRpb24gZmlsZXMgYXMgQkVEIGFuZCBHVEYgKGNob29zaW5nIHRoZSByaWdodCBvdXRwdXQgZm9ybWF0cykuIFNhdmUgdGhlIEJFRCBmaWxlIGFzIGBkbTYuRW5zZW1ibC5nZW5lcy5iZWQxMmAgYW5kIEdURiBhcyBgZG02LkVuc2VtYmwuZ2VuZXMuZ3RmYCBhdCBgR2VuZV9hbm5vdGF0aW9uYCBmb2xkZXIuCgoKKipFeGVyY2lzZSAyLjMuMioqCgpQcm9jZXNzIGBkbTYuRW5zZW1ibC5nZW5lcy5iZWQxMmAgdG8gZmluZCB0aGUgZml2ZSB0cmFuc2NyaXB0cyB3aXRoIHRoZSBoaWdoZXN0IG51bWJlciBvZiBleG9ucy4gKGhpbnQgdXNlIGBzb3J0YCwgbG9vayBmb3IgYC1yYCBhbmQgYC1rYCBmbGFncyBhdCBpdHMgbWFudWFsKS4gCgoqKkV4ZXJjaXNlIDIuMy4zKioKClByb2Nlc3MgYGRtNi5FbnNlbWJsLmdlbmVzLmd0ZmAgdG8gZmluZCB0aGUgdG90YWwgbnVtYmVyIG9mIGdlbmVzCgoKIyAzLiBRdWFsaXR5IGNvbnRyb2wgYmVmb3JlIGFsaW5nbWVudAoKCiMjIDMuMSBGQVNUUUMKCgpUbyBwZXJmb3JtIGEgUUMgb2YgdGhlIEZhc3RxIGZpbGVzIHdlIGNhbiB1c2UgKkZhc3RRQyouIFdlIGNhbiBhY2Nlc3MgdG8gYSBiYXNpYyBtYW51YWwgb2YgdGhpcyB0b29sIGJ5IHR5cGluZyBvbiBgZmFzdHFjIC0taGVscGAgb24gdGVybWluYWwuCgoKCioqRXhlcmNpc2UgMy4xLjEqKgoKQ3JlYXRlIGEgZGlyZWN0b3J5IG5hbWVkIGBRQ2AuIFJlYWQgYGZhc3RxY2AgaGVscCBtYW51YWwgdG8gcnVuIGl0IGZvciBgRkFTVFEvU1JSNzg4OTU4NS5mYXN0cS5nemAgYW5kIHN0b3JlIHRoZSByZXN1bHRzIGF0IHRoZSBuZXdseSBjcmVhdGVkIGZvbGRlciAoYFFDYCkuIFRvIHNwZWVkIGl0IHVwLCB1c2UgNyB0aHJlYWRzICh3aGljaCBpdCB3aWxsIGFsbG93IG91ciBtYWNoaW5lcyB0byB1c2UgNyBwcm9jZXNzb3JzKS4gWW91IHdpbGwgZ2V0IGFuIGh0bWwgZmlsZSBhcyBvdXRwdXQ7IE9wZW4gaXQgd2l0aCBhbiBpbnRlcm5ldCBicm93c2VyIChDaHJvbWUsIEZpcmVmb3gsIGV0YykgYW5kIGFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9uczoKCkEpIFdoYXQgaXMgdGhlIHJlYWQgbGVuZ3RoPwpCKSBEb2VzIHRoZSBxdWFsaXR5IHNjb3JlIHZlcnkgdGhyb3VnaCB0aGUgcmVhZCBsZW5ndGg/CkMpIEhvdyBpcyB0aGUgZGF0YSdzIHF1YWxpdHk/CgoKCiMjIDMuMiBNZXRhZGF0YSBhbmFseXNpcyBvbiBSLXN0dWRpbwoKClRoZSBmYXN0cS5neiBmaWxlcyB0aGF0IHdlIGhhdmUgYXQgYC9GQVNUUWAgY29ycmVzcG9uZCB0byBSTkEtc2VxIGRhdGEgZXh0cmFjdGVkIGZyb20gRC4gbWVsYW5vZ2FzdGVyIGJyYWluIHNhbXBsZXMuIFRoZSBkYXRhIGNvcnJlc3BvbmRpbmcgdG8gYSBmdWxsIHN0dWR5IHB1Ymxpc2hlZCBsYXN0IHllYXIgb24gW0NlbGwgUmVwb3J0c10oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi8vcHVibWVkLzMwMzU1NDg0KSBhbmQgdGhlIGZ1bGwgc3R1ZHkgd2FzIHB1Ymxpc2hlZCBpbiBbU1JBIGFyY2hpdmVdKGh0dHBzOi8vdHJhY2UubmNiaS5ubG0ubmloLmdvdi9UcmFjZXMvc3JhLz9zdHVkeT1TUlAxNjIzMzUpLiAKCioqRXhlcmNpc2UgMy4yLjEqKgoKQ2hlY2sgdGhlIFtzdHVkeSBydW5zXShodHRwczovL3RyYWNlLm5jYmkubmxtLm5paC5nb3YvVHJhY2VzL3N0dWR5Lz9hY2M9U1JQMTYyMzM1KSBhbmQgY29tcGFyZSB3aXRoIHRoZSBmaWxlIG5hbWVzIGZyb20gYEZBU1RRL2AgZm9sZGVyLiBXaGljaCB0aXNzdWVzIHRoZSBzYW1wbGVzIHdlcmUgZXh0cmFjdGVkIGZyb20/IFNlbGVjdCB0aGUgUnVucyB0aGF0IGNvcnJlc3BvbmQgdG8gdGhlIGZpbGVzIHRoYXQgd2UgaGF2ZSBhbmQgZG93bmxvYWQgdGhlIGBSdW5JbmZvIFRhYmxlYCBjb3JyZXNwb25kaW5nIHRvIHRoZXNlIHRhYmxlcyBhbmQgc2F2ZSBpdCBhcyBgU3JhUnVuVGFibGUudHh0YCBvbiB0aGUgY291cnNlIGZvbGRlci4gCgoqKkV4ZXJjaXNlIDMuMi4yKioKCk9wZW4gUi1zdHVkaW8gYW5kIG9wZW4gdGhlIGBEYXkxLlJtZGAgZmlsZSB0aGF0IGlzIGxvY2F0ZWQgYXQgdGhlIGNvdXJzZSBmb2xkZXIuIFRoaXMgaXMgYW4gUi1ub3RlYm9vayBmaWxlLCB0aGF0IGhhcyBhbGwgdGhlIGNvZGUgdXNlZCB0byBnZW5lcmF0ZSB0aGlzIGRvY3VtZW50LiBCdXQsIG5vdyB3aGVuIHlvdSBvcGVuIHRoaXMgZmlsZSB5b3Ugd2lsbCBiZSBhYmxlIHRvIHJ1biBgY2h1bmtzYCBvZiBjb2RlIGludGVyYWN0aXZlbHkgaW5zaWRlIFItc3R1ZGlvLiBSdW4gdGhlIGZvbGxvd2luZyBjaHVuayBieSBjbGlja2luZyBhdCB0aGUgZ3JlZW4gcGxheSBidXR0b24uCgpgYGB7cn0KCmxpYnJhcnkoZGF0YS50YWJsZSkKCm1ldGFkYXRhIDwtIGZyZWFkKCIuL1NyYVJ1blRhYmxlLnR4dCIpICNQbGVhc2UgYmUgc3VyZSB0byBwbGFjZSB0aGUgZmlsZSB1bmRlciAuL0NvdXJzZV9NYXRlcmlhbHMvMDBfUmVwcm9kdWNpYmxlX1JOQS1TZXFfUHJvY2Vzc2luZy8KCm1ldGFkYXRhCmBgYAoKCkJ5IHJ1bm5pbmcgdGhpcyBjb2RlLCB3ZSBpbXBvcnRlZCB0aGUgbWV0YWRhdGEgYXMgYSBkYXRhLnRhYmxlIG9iamVjdCwgd2hpY2ggY29ycmVzcG9uZHMgdG8gYSB2ZXJ5IGNvbnZlbmllbnQgc3RydWN0dXJlIHRvIG1hbmlwdWxhdGUgZGF0YSBpbiBSLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiB2aXNpdCB0aGlzIFtsaW5rXShodHRwczovL3d3dy5kYXRhY2FtcC5jb20vY29tbXVuaXR5L3R1dG9yaWFscy9kYXRhLXRhYmxlLWNoZWF0LXNoZWV0KS4gV2UgY2FuIG5vdyBlYXNpbHkgbWFuaXB1bGF0ZSB0aGUgZGF0YSEgRm9yIGV4YW1wbGUsIHdlIGNhbiBmaWx0ZXIgdGhlIG1ldGFkYXRhIHJvd3MsIHNvIHdlIG9ubHkgc2VlIHRoZSBvbmVzIGNvcnJlc3BvbmRpbmcgdG8gImNlbnRyYWwgbmV1cm9ucyIKCgpgYGB7cn0KbWV0YWRhdGFbc291cmNlX25hbWU9PSJjZW50cmFsIG5ldXJvbnMiICwgXQpgYGAKCgpXZSBjYW4gYWxzbyBnZXQgZXhwbG9yZSBpZiB3ZSBoYXZlIGEgbG93bHkgc2VxdWVuY2VkIHNhbXBsZSBmaWx0ZXJpbmcgYnkgdGhlIGBNQmFzZXNgIHZhbHVlcwoKYGBge3J9Cm1ldGFkYXRhW01CYXNlcyA8IDEwMCAsIF0KYGBgCgoKT3IgZ2V0IHRoZSBhdmVyYWdlIE1lZ2EgYmFzZXMgYWNyb3NzIHRoaXMgc2FtcGxlCgpgYGB7cn0KCm1ldGFkYXRhWyAgLCBtZWFuKE1CYXNlcykgXQoKYGBgCgoKVG8gZXhwbG9yZSB0aGlzIHZpc3VhbGx5LCB3ZSBjYW4gcGxvdCB3aXRoIGdncGxvdDIuIFRoaXMgaXMgb25lIG9mIHRoZSBtb3N0IHBvcHVsYXIgcGFja2FnZXMgdG8gdmlzdWFsaXplIGRhdGEuIEEgYmFzaWMgY29kZSB0byB2aXN1YWxpemUgdGhlIE1iYXNlcyBkaXN0cmlidXRpb24gY2FuIGJlIHJ1biBhczoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpnZ3Bsb3QoZGF0YSA9IG1ldGFkYXRhKSArICAjIEZyaXN0IGxheWVyIC0gRGF0YSBpbnB1dAogIGdlb21fYmFyKGFlcyh4PVJ1biwgeT1NQmFzZXMpLCBzdGF0ID0gImlkZW50aXR5IikgICAjIHNlY29uZCBsYXllciAtIHR5cGUgb2YgcGxvdCBhbmQgYXhpcwoKYGBgCgoKV2UgY2FuIHJvdGF0ZSB0aGUgdGV4dCB0byBtYWtlIGl0IG1vcmUgdmlzaWJsZQoKYGBge3J9CgpnZ3Bsb3QoZGF0YT1tZXRhZGF0YSkgKwogIGdlb21fYmFyKGFlcyh4PVJ1biwgeT1NQmFzZXMsICksIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSAgIyBUaGlyZCBsYXllciAtICB2aXN1YWwgY29uZmlndXJhdGlvbgoKYGBgCgoKaW5zaWRlIGBhZXMoIClgIGFyZSB0aGUgdmFyaWFibGVzIGFuZCB3ZSBjYW4gYWxzbyBkZWZpbmUgYSB2YXJpYWJsZSBhcyB0aGUgY29sb3VyOgoKCmBgYHtyfQpnZ3Bsb3QoZGF0YT1tZXRhZGF0YSkgKwogIGdlb21fYmFyKGFlcyh4PVJ1biwgeT1NQmFzZXMsIGNvbG91cj1zb3VyY2VfbmFtZSksIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQpgYGAKCkJ1dCBmb3IgdGhpcyBwYXJ0aWN1bGFyIHR5cGUgb2YgZ3JhcGgsIGZpbGxpbmcgdGhlIGJhciB3aXRoIG9uZSBjb2xvdXIgaXMgbW9yZSBzdWl0YWJsZQoKYGBge3J9CmdncGxvdChkYXRhPW1ldGFkYXRhKSArCiAgZ2VvbV9iYXIoYWVzKHg9UnVuLCB5PU1CYXNlcywgZmlsbD1zb3VyY2VfbmFtZSksIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQpgYGAKCgpGcm9tIHRoaXMgcGxvdCwgd2UgY2FuIGNsZWFybHkgc2VlIHRoYXQgb25lIG9mIHRoZSBzYW1wbGVzIHRoYXQgd2VyZSB0YWtlbiBmcm9tIGNlbnRyYWwgbmV1cm9ucyBpcyBtdWNoIHNtYWxsZXIgdGhhbiB0aGUgcmVzdC4gVGhpcyBmYWN0b3IgbmVlZHMgdG8gYmUgY29uc2lkZXJlZCBhdCB0aGUgdGltZSB3ZSBhbmFseXplIHRoZSBzYW1wbGVzLCBhcyB0aGlzIHBvb3JseSBzZXF1ZW5jZWQgc2FtcGxlIG1pZ2h0IGhhdmUgbGVhZCB0byBsZXNzIGFjY3VyYXRlIG1STkEgcXVhbnRpZmljYXRpb24gYW5kIGl0IG1pZ2h0IG5lZWQgdG8gYmUgcmVtb3ZlZCBmb3IgcXVhbnRpdGF0aXZlIGFuYWx5c2VzLiAKCgoKIyA0LiBNYXBwaW5nIHJlYWRzIHRvIHRoZSBnZW5vbWUgYW5kIGdldHRpbmcgcmF3IGNvdW50cwoKQWZ0ZXIgd2UgaGF2ZSBhIGRpYWdub3NpcyBvZiB0aGUgZGF0YSBxdWFsaXR5LCB3ZSBjYW4gc3RhcnQgdG8gYW5hbHlzZSB0aGUgZGF0YS4gVXN1YWxseSwgdGhlIGZpcnN0IHN0ZXAgaW50byB0aGUgYW5hbHlzaXMgcmVxdWlyZXMgbWFwcGluZyB0aGUgUk5BLXNlcSByZWFkcyB0byB0aGUgZ2Vub21lLiBUaGVyZSBhcmUgbnVtZXJvdXMgdG9vbHMgdG8gZG8gcGVyZm9ybSBzaG9ydCByZWFkIGFsaWdubWVudCBhbmQgdGhlIGNob2ljZSBvZiBpdCBzaG91bGQgYmUgY2FyZWZ1bGx5IG1hZGUgYWNjb3JkaW5nIHRvIHRoZSBhbmFseXNpcyBnb2FscyBhbmQgcmVxdWlyZW1lbnRzLiBIaXNhdDIgaXMgYSB2ZXJ5IGZhc3RxIHRvb2wgdGhhdCBoYXMgYmVlbiBzaG93biB0byBoYXZlIGEgZ29vZCBwZXJmb3JtYW5jZSBvbiBwdWJsaXNoZWQgYmVuY2htYXJrcy4gCgoKIyMgNC4xIEluZGV4aW5nIHRoZSBnZW5vbWUgZm9yIEhpc2F0MgoKClRvIHN0YXJ0IG1hcHBpbmcgUk5BLXNlcSByZWFkcyB0byB0aGUgZ2Vub21lLCB3ZSBuZWVkIHRvIGluZGV4IHRoZSBnZW5vbWUuIFRoZSBjb21tYW5kIHRvIGRvIHRoaXMgaXMgYGhpc2F0Mi1idWlsZGAuIAoKYGhpc2F0Mi1idWlsZCAtLWhlbHBgCgoqKkV4ZXJjaXNlIDQuMS4xLioqCgoKR28gdG8gYENvdXJzZV9NYXRlcmlhbHMvMDBfUmVwcm9kdWNpYmxlX1JOQS1TZXFfUHJvY2Vzc2luZ2AgZGlyZWN0b3J5IHVzaW5nIGBjZGAgKFRoaXMgaXMgZ29pbmcgdG8gYmUgb3VyIGJhc2UgZGlyZWN0b3J5IHRvIHNvbHZlIGFsbCB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlcykuIERvIGBsc2AgdG8gbGlzdCB0aGUgZGlyZWN0b3JpZXMgYW5kIGNyZWF0ZSBhIG5ldyBmb2xkZXIgY2FsbGVkIGBJbmRleGAgaW5zaWRlIGBHZW5vbWVgIGZvbGRlci4gVGhlbiBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kOiAKCmBoaXNhdDItYnVpbGQgLXAgNyBHZW5vbWUvZG02LmZhIEdlbm9tZS9JbmRleC9kbTZgCgpUaGlzIGNvbW1hbmQgd2lsbCB1c2UgdGhlIGdlbm9tZSAobG9jYXRlZCBhdCBgR2Vub21lL2RtNi5mYWApIGFuZCBpdCB3aWxsIGdlbmVyYXRlIHRoZSBpbmRleCBmaWxlcyBvbiBgR2Vub21lL0luZGV4L2AuIEFsbCB0aGUgZmlsZXMgd2lsbCBzdGFydCB3aXRoIGBkbTZgIHByZWZpeC4gVGFrZSBhIGxvb2sgYXQgYGhpc2F0Mi1idWlsZGAgaGVscCwgCgpBKSBXaHkgZG8gd2UgdXNlIGAtcCA3YCBhbmQgd2hhdCBpcyB0aGUgbWF4aW11bj1tIHZhbHVlIHdlIHNob3VsZCB1c2Ugb24gdGhlc2UgbWFjaGluZXM/CkIpIEhvdyBtYW55IGZpbGVzIGFyZSBjcmVhdGVkIG9uIHRoaXMgcHJvY2Vzcz8gCgoKIyMgNC4yIEhpc2F0MgoKClRvIG1hcCB0aGUgcmVhZHMgdG8gdGhlIGdlbm9tZSB3ZSBuZWVkIHRvIHJ1biBoaXNhdDIuIFRha2UgYSBxdWljayBsb29rIHRvIGhpc2F0MidzIGRlc2NyaXB0aW9uCgpgaGlzYXQyIC0taGVscGAKCioqRXhlcmNpc2UgNC4yLjEqKgoKUnVuIGhpc2F0MiBmb3IgdGhlIHNtYWxsZXN0IGZpbGUsIGxvY2F0ZWQgYXQgRkFTVFEgZm9sZGVyIHVzaW5nIDcgcHJvY2Nlc29ycy4gU2F2ZSB0aGUgcmVzdWx0cyBpbnNpZGUgYSBmb2xkZXIgbmFtZWQgYGhpc2F0MmAgKGNyZWF0ZSBpdCBiZWZvcmUgdXNpbmcgYG1rZGlyYCkgYW5kIHNhdmUgdGhlIHJlc3VsdHMgdXNpbmcgdGhlIHJpZ2h0IGV4dGVuc2lvbiAoYC5zYW1gKS4KaGludDogdXNlIGBoaXNhdCAtLWhlbHBgIGFuZCBsb29rIGZvciAtcCAtVSAteCBmbGFncyBhbmQgdHQgdGhlIGVuZCBvZiB0aGUgY29tbWFuZCB1c2UgYD5gIHRvIHNhdmUgdGhlIHJlc3VscyB0byBhIGZpbGUuIAoKCiMjIDQuMyBTYW10b29scwoKVGhlIG91dHB1dCBvZiBoaXNhdDIgaXMgYSBTQU0gZmlsZSwgd2hpY2ggaXMgYSBwbGFpbiB0ZXh0IGZpbGUgdGhhdCBoYXMgdGhlIGFsaWdubWVudCBpbmZvcm1hdGlvbi4gQXMgdGhleSB0ZW5kIHRvIGJlIHZlcnkgbGFyZ2UsIGlzIG5vdCBhIGdvb2QgaWRlYSB0byBzdG9yZSB0aGVtIGZvcmV2ZXIuIEJBTSBmaWxlcyBhcmUgdGhlIGJpbmFyeSBmb3JtIG9mIFNBTSBmaWxlcywgd2hpY2ggbWVhbnMgdGhlaXIgaW5mb3JtYXRpb24gaXMgbXVjaCBtb3JlIGNvbXByZXNzZWQsIHdoaWNoIG1ha2UgdGhlbSBlYXNpZXIgdG8gc3RvcmUgdGhlbSwgYnV0IGFsc28gZW5hYmxlIHF1aWNrZXIgcHJvY2Vzc2luZyBvZiB0aGVpciBkYXRhLiBXZSBjYW4gdHJhbnNmb3JtIGZyb20gU0FNIHRvIEJBTSBmb2xsb3dpbmcgdGhpcyBnZW5lcmFsIGZvcm11bGE6Cgpgc2FtdG9vbHMgdmlldyAtYiBzYW1wbGUuc2FtID4gc2FtcGxlLmJhbWAKCldoZXJlIGBzYW1wbGVgIGlzIGp1c3QgYSBnZW5lcmljIG5hbWUgdG8gcmVmZmVyIHRvIG91ciBzYW1wbGVzLiAKCioqRXhlcmNpc2UgNC4zLjEqKgoKR2V0IGEgQkFNIGZpbGUgZnJvbSB0aGUgU0FNIGZpbGUgeW91IGp1c3QgZ2VuZXJhdGVkLiAKCgojIyA0LjQgVmlzdWFsaXNlIEJBTSBmaWxlcwoKQkFNcyBjYW4gYmUgdXNlZCBmb3IgZGlmZmVyZW50IGRvd25zdHJlYW0gYW5hbHlzZXMuIEJ1dCBtb3N0IG9mIHRoZW0gcmVxdWlyZSB0aGUgQkFNIGZpbGVzIHRvIGJlIGBzb3J0ZWRgLiBXaGVuIGEgQkFNIGZpbGUgaXMgc29ydGVkLCB0aGUgYWxpZ25tZW50cyBhcmUgb3JkZXJlZCBieSB0aGUgcG9zaXRpb24gdGhleSBtYXAgdG8uIEJBTSBmaWxlcyBjYW4gYmUgc29ydGVkIHVzaW5nIGBzYW10b29scyBzb3J0YCBhbmQgZm9sbG93aW5nIHRoaXMgZm9ybXVsYToKCmBzYW10b29scyBzb3J0ICBzYW1wbGUuYmFtIC1vIHNhbXBsZS5zb3J0ZWQuYmFtYAoKVG8gdmlzdWFsaXNlIGEgQkFNJ3MgYWxpZ25tZW50LCB3ZSBuZWVkIHRvIGluZGV4IGl0IGZpcnN0LiBXaGljaCBjYW4gYmUgbWFkZSB3aXRoIGBzYW10b29scyBpbmRleGA6Cgpgc2FtdG9vbHMgaW5kZXggc2FtcGxlLnNvcnRlZC5iYW1gCgoqKkV4ZXJjaXNlIDQuNC4xKioKCkEpIFNvcnQgYW5kIEluZGV4IHlvdXIgQkFNIGZpbGUuCkIpIE9wZW4gSUdWLCBsb2FkIEQuIG1lbGFub2dhc3RlcidzIGdlbm9tZSAoZG02KSBhbmQgbG9hZCB0aGUgc29ydGVkIGJhbWZpbGUuCgoqKklHViBoZWxwKioKCipMb2FkIHRoZSByZWZlcmVuY2UgZ2Vub21lKi4gT24gdGhlIHRvcCBtZW51IGJhciBmaW5kIHRoZSBnZW5vbWVzIGRyb3Bkb3duICh0b3AtbGVmdCkgYW5kICB0aGVuIGZpbmQgIGBELiBtZWxhbm9nYXN0ZXJgIGFzc2VtYmx5IGRtNi4gWW91IG1pZ2h0IG5lZWQgdG8gY2xpY2sgb24g4oCYTW9yZS4uLuKAmSB0byBzZWUgYSBsaXN0IG9mIGF2YWlsYWJsZSBnZW5vbWVzLgoKKkxvYWQgdGhlIEJBTSBmaWxlKi4gT24gdGhlIHRvcCBtZW51IGJhciBnbyB0byDigJhGaWxlIOKAkz4gTG9hZCBmcm9tIEZpbGUuLi7igJkgYW5kIHNlbGVjdCB0aGUgc29ydGVkIEJBTSBmaWxlIHlvdSBoYXZlIGNyZWF0ZWQgb24gdGhlIHByZXZpb3VzIHN0ZXAuCgpab29tIGluIGludG8gYSBwYXJ0aWN1bGFyIGdlbmUgdG8gc2VlIHRoZSByZWFkIGFsaWdubWVudHMuIAoKCiMjIDQuNSBGZWF0dXJlQ291bnRzCgpUbyBjb3VudCB0aGUgbnVtYmVyIG9mIHJlYWRzIHdlIHdpbGwgdXNlIEZlYXR1cmVDb3VudHMsIHdoaWNoIHVzZXMgYSBnZW5lIGFubm90YXRpb24gZmlsZSAoR1RGKSB0byBwcm9jZXNzIHRoZSBnZW5vbWljIGludGVydmFscyBvZiBldmVyeSBnZW5lIGFuZCBjb3VudCBhbGwgdGhlIHJlYWRzIHRoYXQgbWFwIHRvIHRoZSBleG9uaWMgcmVnaW9ucy4gCgoqKkV4ZXJjaXNlIDQuMi4yKioKClJ1biBmZWF0dXJlQ291bnRzIHByb3ZpZGluZyB0aGUgdHJhbnNjcmlwdCBhbm5vdGF0aW9uIGFuZCB0aGUgc2FtZSBmaWxlIHlvdSBwcm9kdWNlZCB3aXRoIGhpc2F0Mi4gVG8gZG8gdGhpcywgcmVhZCB0aGUgZmVhdHVyZUNvdW50IGhlbHAgbWFudWFsIGFuZCBmaW5kIHRoZSByaWdodHMgZmxhZ3MgcnVuIGZlYXR1cmVDb3VudHMgKGhpbnQ6IHJlYWQgdGhlIGBSZXF1aXJlZCBhcmd1bWVudHNgIHNlY3Rpb24pLgoKKipFeGVyY2lzZSA0LjIuMioqCgpGaW5kIHRoZSBnZW5lIHdpdGggdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIGNvdW50cy4gQ2FuIHdlIHNheSB0aGlzIGdlbmUgaXMgdGhlIG9uZSB3aXRoIGhpZ2hlciBleHByZXNzaW9uIGxldmVscyBvbiB0aGlzIHNhbXBsZT8KCgojIDUuIEludHJvZHVjdGlvbiB0byByZXBvcmR1Y2libGUgYmlvaW5mb3JtYXRpY3MKClVudGlsIHRoaXMgcG9pbnQsIHdlIGhhdmUgaW50cm9kdWNlZCBldmVyeSBjb21tYW5kIG1hbm51YWxseSBpbiB0aGUgdGVybWluYWwuIFBsZWFzZSBjaGVjayBob3cgbWFueSBmaWxlcyBkbyB3ZSBoYXZlIGF0IGBGQVNUUS9gLiBEbyB5b3UgdGhpbmsgeW91IGNhbiBnZXQgdGhlIHJhdyBjb3VudHMgZnJvbSBhbGwgdGhlIHNhbXBsZXMgd2l0aG91dCBoYXZpbmcgZXJyb3JzPyB3aGF0IGFib3V0IHByb2Nlc3NpbmcgaHVuZHJlZCBvZiBzYW1wbGVzLCBpcyBpdCByZWFzb25hYmxlIHRvIGRvIGl0IG1hbnVhbGx5PyAgCgpUaGUgYW5zd2VyIGlzIGNsZWFybHkgKm5vKi4gV2UgbmVlZCBzeXN0ZW1hdGljIHdheXMgdG8gcHJvY2VzcyBkYXRhIHRvIGF2b2lkIGVycm9ycyBhbmQgZW5hYmxlIHJlcHJvZHVjaWJpbGl0eSBpbiBvdXIgYW5hbHlzZXMuIFRoaXMgaXMgd2h5IHdlIGFyZSBnb2luZyB0byB1c2UgYSB3b3JrZmxvdyBtYW5hZ2VyIHRvIGV4ZWN1dGUgdGhlIHJlbWFpbmluZyBzdGVwcyB0byBnZXQgdGhlIHJhdyBjb3VudHMgZnJvbSBvdXIgc2FtcGxlcy4gCgpTbmFrZW1ha2UgaXMgY3VycmVudGx5IG9uZSBtb3N0IHBvcHVsYXIgd29ya2Zsb3cgbWFuYWdlcnMgdG8gd29yayB3aXRoIGJpb2luZm9ybWF0aWMgc29mdHdhcmUuIFRvIGluc3RhbGwgc25ha2VtYWtlIHBsZWFzZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6CgpgY29uZGEgY3JlYXRlIC1uIHNuYWtlbWFrZV9lbnYgc25ha2VtYWtlIGAKCkJ5IGRvaW5nIHRoaXMgd2UgY3JlYXRlZCBhIHZpcnR1YWwgZW52aXJvbm1lbnQsIGNhbGxlZCBgc25ha2VtYWtlX2VudmAgdGhhdCBoYXMgbGF0ZXN0IHZlcnNpb24gb2Ygc25ha2VtYWtlIGFuZCBvdXIgaXQgZGVwZW5kZW5jaWVzIGluc3RhbGxlZC4gTm93IHRvIGFjdGl2YXRlIHRoaXMgZW52aXJvbm1lbnQsIHdyaXRlOgoKYGNvbmRhIGFjdGl2YXRlIHNuYWtlbWFrZV9lbnZgCgpBcyB3ZSBhbHJlYWR5IHdyb3RlIGEgYHNuYWtlbWFrZWAgcGlwZWxpbmUgZm9yIHlvdSwgd2UgYXJlIGdvaW5nIHRvIGRlbW9uc3RyYXRlIHlvdSBzb21lIG9mIGl0cyBwcm9wZXJ0aWVzIGFuZCBob3cgdG8gdXNlIGl0LiBUbyBzZWUgdGhlIGNvZGUgZnJvbSB0aGUgdGhpcyBwaXBlbGluZSwgVXNlIGBBdG9tYCAob3IgYW55IHRleHQgZWRpdG9yKSB0byBvcGVuIHRoZSBgU25ha2VmaWxlYC4gQ2FuIHlvdSByZWNvZ25pemUgc29tZSBvZiB0aGUgc3RlcHMgdGhhdCB3ZSBoYXZlIGRvbmUgYWxyZWFkeT8uIEV2ZXJ5IGBydWxlYHJlcHJlc2VudCBhIHN0ZXAgb2YgdGhlIGFuYWx5c2lzLiBGb3IgZXhhbXBsZToKCgpgYGB7cHl0aG9ufQoKcnVsZSBoaXNhdDJfR2Vub21lX2luZGV4OgogICAgaW5wdXQ6CiAgICAgICAgIkdlbm9tZS9kbTYuZmEiCiAgICBvdXRwdXQ6CiAgICAgICAgIkdlbm9tZS9JbmRleC9kbTYuMS5odDIiCiAgICB0aHJlYWRzOiA3CiAgICBjb25kYToKICAgICAgICAiZW52cy9jb3JlLnlhbWwiCiAgICBsb2c6CiAgICAgICAgImxvZ3MvaGlzYXQyX0dlbm9tZV9pbmRleC5sb2ciCiAgICBzaGVsbDoKICAgICAgICAiaGlzYXQyLWJ1aWxkIC1wIHt0aHJlYWRzfSB7aW5wdXR9IEdlbm9tZS9JbmRleC9kbTYgMj4ge2xvZ30iCmBgYAoKVGhpcyBjb2RlIGNvcnJlc3BvbmQgdG8gdGhlIGluZGV4aW5nIHN0ZXAsIGluIHdoaWNoIGl0IHRha2VzIGBHZW5vbWUvZG02LmZhYCBhcyBpbnB1dCBhbmQgYEdlbm9tZS9JbmRleC9kbTYuMS5odDJgIGFzIG91dHB1dC4gVGhlIHJ1bGVzIGhhdmUgc2V2ZXJhbCBga2V5YCB3b3JkcyBieSB3aGljaCBkaWZmZXJlbnQgcGFydHMgb2YgdGhlIGNvbW1hbmQgYXJlIGRlY2xhcmVkOgoqIGlucHV0OiBzZXQgb2YgaW50cHV0IGZpbGVzLCBpbiB0aGlzIGNhc2UganVzdCAiR2Vub21lL2RtNi5mYSIKKiBvdXRwdXQ6IHNldCBvZiBvdXRwdXQgZmlsZXMuIEluIHRoaXMgY2FzZSwgbW9yZSBvdXRwdXQgZmlsZXMgYXJlIGNyZWF0ZWQsIGJ1dCB0aGV5IGRvIG5vdCBoYXZlIHRvIGJlIHBvaW50ZWQgYnkgdGhlIGNvbW1hbmRzLCB3ZSBjYW4ganVzdCByZWZlciB0byBvbmUgb2YgdGhlIGZpbGVzIHRoYXQgaXMgY3JlYXRlZC4gU25ha2VtYWtlIHdpbGwgY2hlY2sgaWYgdGhpcyBmaWxlIGlzIHN1Y2Nlc3NmdWxseSBjcmVhdGVkIGFmdGVyIHRoZSBwcm9jZXNzIGlzIGZpbmlzaGVkLgoqIHRocmVhZHM6IG51bWJlciBvZiBwcm9jZXNzb3JzCiogY29uZGE6IHRoZSB2aXJ0dWFsIGVudmlyb25tZW50IGluIHdoaWNoIHRoZSBwcm9jZXNzIHdpbGwgYmUgcnVuLgoqIGxvZyA6IGZpbGUgdGhhdCBzdG9yZSBhbnl0aGluZyB0aGF0IGhpc2F0MiBvdXRwdXRzIHdoaWxlIGlzIGNyZWF0aW5nIHRoZSBpbmRleC4KKiBzaGVsbCA6IFRoaXMgaXMgdGhlIGZvcm11bGEgdG8gY3JlYXRlIHRoZSBzaGVsbCBjb21tYW5kIGdpdmVuIGFsbCB0aGUgcGFyYW1ldGVycyBkZXNjcmliZWQgYWJvdmUuCgpUaGUgaW5kZXhpbmcgcnVsZSBpcyBkaXJlY3RseSBjb25uZWN0ZWQgdG8gdGhlIGZvbGxvd2luZyBtYXBwaW5nIHJ1bGU6CgpgYGB7cHl0aG9ufQoKcnVsZSBoaXNhdDJfdG9fR2Vub21lOgogICAgaW5wdXQ6CiAgICAgICAgZmFzdHEgPSAiRkFTVFEve3NhbXBsZX0uZmFzdHEuZ3oiLAogICAgICAgIGdlbm9tZSA9ICJHZW5vbWUvSW5kZXgvZG02LjEuaHQyIgogICAgb3V0cHV0OgogICAgICAgIHRlbXAoImhpc2F0Mi97c2FtcGxlfS5zYW0iKSAgICMgVGVtcG9yYXJ5IG91dHB1dAogICAgdGhyZWFkczogMwogICAgY29uZGE6CiAgICAgICAgImVudnMvY29yZS55YW1sIgogICAgbG9nOgogICAgICAgICJsb2dzL2hpc2F0Ml90b19HZW5vbWUue3NhbXBsZX0ubG9nIgogICAgc2hlbGw6CiAgICAgICAgImhpc2F0MiAtcCAzIC1VIHtpbnB1dC5mYXN0cX0gLXggIEdlbm9tZS9JbmRleC9kbTYgID4ge291dHB1dH0gMj4ge2xvZ30iCgpgYGAKClRoaXMgcnVsZSB0YWtlcyBmYXN0cSBmaWxlcyBhcyBpbnB1dCBhbmQgYWxzbyB0aGUgZ2Vub21lIGluZGV4IGZpbGVzLiBBbGwgdGhlIHNhbXBsZSBuYW1lcyB3ZXJlIG9idGFpbmVkIGZyb21gTkNCSV9hY2Nlc3Npb25fbGlzdC50eHRgIGZpbGUsIHdoaWNoIGNvbnRhaW5zIHRoZSBTUkEgYWNjZXNzaW9uIGNvZGVzIGNvcnJlc3BvbmRpbmcgdG8gYWxsIHRoZSBzYW1wbGVzIHRoYXQgd2UgYXJlIGFuYWx5c2luZy4gSW5zaWRlIHRoZSBydWxlIGB7c2FtcGxlfWAgdGFrZXMgdGhlIHZhbHVlIG9mIGV2ZXJ5IGFjY2Vzc2lvbiBjb2RlLCBhbmQgYWxsb3cgc25ha2VtYWtlIHRvIGdlbmVyYXRlIGFsbCB0aGUgbWFwcGluZyBjb21tYW5kcyBmb3IgZXZlcnkgc2FtcGxlLiBBcyB3ZSBoZXJlIHNldCBgdGhyZWFkc2AgYXMgMywgZXZlcnkgbWFwcGluZyBwcm9jZXNzIHdpbGwgdXNlIDMgcHJvY2Vzc29ycywgd2hpY2ggbWVhbnMgdGhhdCAyIG1hcHBpbmcgcHJvY2Vzc2VzIGNhbiBiZSBydW4gaW4gcGFyYWxsZWwgd2hlbiA3IGNvcmVzIGFyZSBwcm92aWRlZC4gCgpUaGUgbmV4dCBydWxlIGBiYW1zdGF0c2AgdGFrZSBldmVyeSBTQU0gZmlsZSBhbmQgdHJhbnNmb3JtIGl0IHRvIEJBTSwgYnV0IGFsc28gdGhlIEJBTSBmaWxlIGlzIHNvcnRlZCBhbmQgaW5kZXhlZCBhdCB0aGUgc2FtZSB0aW1lOgoKYGBge3B5dGhvbn0KCnJ1bGUgc2FtVG9iYW06CiAgICBpbnB1dDoKICAgICAgICAiaGlzYXQyL3tzYW1wbGV9LnNhbSIKICAgIG91dHB1dDoKICAgICAgICAiaGlzYXQyL3tzYW1wbGV9LnNvcnRlZC5iYW0iCiAgICBjb25kYToKICAgICAgICAiZW52cy9jb3JlLnlhbWwiCiAgICBzaGVsbDoKICAgICAgICAic2FtdG9vbHMgdmlldyAtYiAge2lucHV0fSAgfCBzYW10b29scyBzb3J0IC0gLW8ge291dHB1dH0gJiYgc2FtdG9vbHMgaW5kZXgge291dHB1dH0gIgoKYGBgCgpCZWNhdXNlIFNBTSBmaWxlcyB3ZXJlIHByb2R1Y2VkIGFzIHRlbXBvcmFyeSBmaWxlcyAoYHRlbXAoImhpc2F0Mi97c2FtcGxlfS5zYW0iKWAgKSwgCmFzIHNvb24gYXMgYHNhbVRvYmFtYCBmaW5pc2hlcywgU0FNIGZpbGVzIGFyZSBkZWxldGVkLiBUaGlzIG9wdGltaXplcyB0aGUgZGlzayBzcGFjZSwgd2hpY2ggaXMgaW1wb3J0YW50IHdoZW4gYSBsYXJnZSBudW1iZXIgb2Ygc2FtcGxlcyBhcmUgcHJvY2Vzc2VkLiAKCkZpbmFsbHksIGFsbCB0aGVzZSBzdGVwcyBjb252ZXJnZSBhdDoKCmBgYHtweXRob259CnJ1bGUgZmVhdHVyZUNvdW50czoKICAgIGlucHV0OgogICAgICAgIGd0ZiA9ICJHZW5lX2Fubm90YXRpb24vZG02LkVuc2VtYmwuZ2VuZXMuZ3RmIiwKICAgICAgICBiYW0gPSBleHBhbmQoImhpc2F0Mi97c2FtcGxlfS5zb3J0ZWQuYmFtIiwgc2FtcGxlPVNBTVBMRVMpCiAgICBvdXRwdXQ6CiAgICAgICAgImZlYXR1cmVDb3VudHMvdG90YWxfc2FtcGxlcy5nZW5lX2NvdW50LnR4dCIKICAgIHRocmVhZHM6IDEKICAgIGNvbmRhOgogICAgICAgICJlbnZzL2NvcmUueWFtbCIKICAgIGxvZzoKICAgICAgICAibG9ncy9mZWF0dXJlQ291bnRzLnRvdGFsLmxvZyIKICAgIHNoZWxsOgogICAgICAgICJmZWF0dXJlQ291bnRzIC1hIHtpbnB1dC5ndGZ9IC1vIHtvdXRwdXR9IHtpbnB1dC5iYW19IDI+IHtsb2d9IgpgYGAKCldoZXJlIGB7aW5wdXQuZ3RmfWAgbGlzdCBhbGwgdGhlIHNvcnRlZCBiYW0gdGhhdCB3ZSBnZW5lcmF0ZWQuIE5vdGljZSB0aGF0IHRoaXMgU25ha2VmaWxlIHN0YXJ0cyB3aXRoIGBpbmNsdWRlOiAicnVsZXMvMDBfZG93bmxvYWRfZGF0YS5za20iIGAsIHdoaWNoIGlzIGEgc3RhdGVtZW50IHRoYXQgY29ubmVjdHMgdGhpcyBTbmFrZWZpbGUgd2l0aCBgcnVsZXMvMDBfZG93bmxvYWRfZGF0YS5za21gLiBUaGlzIGlzIGEgc2NyaXB0IHRoYXQgcmVhZCBhbGwgYWNjZXNzaW9uIGNvZGVzIGZyb20gYE5DQklfYWNjZXNzaW9uX2xpc3QudHh0YCBhbmQgc3RvcmVzIHRob3NlIGF0IGBTQU1QTEVTYCwgd2hpY2ggaXMgdGhlbiB1c2VkIGJ5IGBleHBhbmQoImhpc2F0Mi97c2FtcGxlfS5zb3J0ZWQuYmFtIiwgc2FtcGxlPVNBTVBMRVMpYCB0byBnZW5lcmF0ZSB0aGUgbGlzdCBvZiBhbGwgc29ydGVkIEJBTSBmaWxlcy4gCgoKIyMgNS4xIFF1YW50aWZ5aW5nIGFsbCB0aGUgc2FtcGxlcyBhdCBvbmNlCgpXZSBoYXZlIG9ubHkgcXVhbGlmaWVkIG9uZSBzYW1wbGUgc28gZmFyLCBidXQgbm93IGV4ZWN1dGluZyB0aGUgU25ha2VmaWUsIHdlIGNhbiBwcm9jZXNzIGFsbCB0aGUgb3RoZXIgc2FtcGxlcyBpbiBwYXJhbGxlbC4gRm9yIHRoaXMsIHdlIGZpcnN0IGFyZSBnb2luZyB0byBkbyBhIGBkcnktcnVuYCB0byBjaGVjayB0aGUgbGlzdCBvZiBjb21tYW5kcyB0aGF0IHNuYWtlbWFrZSB3aWxsIHJ1biBmb3IgdXMuIE9uIHRoZSBjb21tYW5kIGxpbmUgKGluIG91ciBiYXNlIGZvbGRlciwgYDAwX1JlcHJvZHVjaWJsZV9STkEtU2VxX1Byb2Nlc3NpbmdgKSwgcGxlYXNlIHdyaXRlOgoKYHNuYWtlbWFrZSAtbnAgZmVhdHVyZUNvdW50c2AKClRoaXMgY29tbWFuZCBzaG93cyB1cyBhbGwgdGhlIHN0ZXBzIHRoYXQgc25ha2VtYWtlIHdpbGwgdW50aWwgZXhlY3V0aW5nIGEgcnVsZSBuYW1lZCAqZmVhdHVyZUNvdW50cyogKHNlZSBTbmFrZWZpbGUncyBjb2RlKSB3aGljaCBydW4gYGZlYXR1cmVDb3VudHNgIG92ZXIgYWxsIHRoZSBzYW1wbGVzLiBXaGVyZSBgLW5gIHByZXZlbnQgc25ha2VtYWtlIGZyb20gcnVubmluZyB0aGUgcGlwZWxpbmUgYW5kIGAtcGAgcHJpbnRzIHRoZSBjb21tYW5kcyBmb3IgZWFjaCBzdGVwLiAgCgpUbyB2aXN1YWxpc2UgdGhlc2Ugc3RlcHMgcnVuOgoKYHNuYWtlbWFrZSBmZWF0dXJlQ291bnRzIC0tZGFnIHwgZG90IC1UcG5nID4gZmVhdHVyZUNvdW50cy5wbmdgCgpUaGlzIHdpbGwgcHJvZHVjZSB0aGUgZm9sbG93aW5nIGltYWdlOgoKIVtdKEltYWdlcy9mZWF0dXJlQ291bnRzLnBuZykKCldoaWNoIGhlbHAgdXMgdG8gdW5kZXJzdGFuZCB0aGUgcGxhbm5lZCBqb2IgZXhlY3V0aW9uLgoKRmluYWxseSwgdG8gcnVuIHRoZXNlIHN0ZXBzIHdlIG5lZWQgdG8gZW5hYmxlIHNuYWtlbWFrZSB0byB1c2UgdGhlIGVudmlyb25tZW50IGZpbGVzIGFyZSBuZWVkZWQgZm9yIGVhY2ggcnVsZSBieSBpbmNsdWRpbmcgYC0tdXNlLWNvbmRhYCBhbmQgYWxzbyB3ZSBzaG91bGQgbGltaXQgdGhlIG51bWJlciBvZiBwcm9jZXNzb3JzIHRvIDcgd2l0aCBgLS1jb3JlcyA3YC4KCioqRXhlcmNpc2UgNS4xLjEqKgoKRXhlY3V0ZSBgc25ha2VtYWtlYCB0byBxdWFudGlmeSBhbGwgdGhlIHNhbXBsZXMgdXNpbmcgZmVhdHVyZUNvdW50cy4gTG9vayBpbnNpZGUgYFNuYWtlZmlsZWBjb2RlIHRvIHNlZSB3aGVyZSB0aGUgZmluYWwgb3V0cHV0IG9mIGZlYXR1cmVDb3VudCB3aWxsIGJlIHN0b3JlZCBhbmQgY29tcGFyZSBpdCB3aXRoIHRoZSBvdXRwdXQgd2UgcHJldmlvdXNseSBoYWQgdXNpbmcgZmVhdHVyZUNvdW50cy4gIAoKCioqRXhlcmNpc2UgNS4xLjIqKgoKU25ha2VtYWtlIGNhbiBoYXZlIGluZGl2aWR1YWwgZmlsZXMgYXMgYSB0YXJnZXQuIFRoZSBmb2xsb3dpbmcgcnVsZToKCmBgYHtweXRob259CnJ1bGUgYmFtc3RhdHM6CiAgICBpbnB1dDoKICAgICAgICAiaGlzYXQyL3tzYW1wbGV9LnNvcnRlZC5iYW0iCiAgICBvdXRwdXQ6CiAgICAgICAgc3RhdHNfdHh0ID0gIlFDL3tzYW1wbGV9L3tzYW1wbGV9LnN0YXRzIiwKICAgICAgICBzdGF0c19odG1sID0gIlFDL3tzYW1wbGV9L3tzYW1wbGV9LnBsb3RzLmh0bWwiCiAgICBwYXJhbXM6CiAgICAgICAgIlFDL3tzYW1wbGV9L3tzYW1wbGV9LnBsb3RzIgogICAgY29uZGE6CiAgICAgICAgImVudnMvY29yZS55YW1sIgogICAgc2hlbGw6CiAgICAgICAgInNhbXRvb2xzIHN0YXRzIHtpbnB1dH0gPiB7b3V0cHV0LnN0YXRzX3R4dH0gJiYgcGxvdC1iYW1zdGF0cyAtcCB7cGFyYW1zfSB7b3V0cHV0LnN0YXRzX3R4dH0iCmBgYAoKV2FzIG5vdCBpbmNsdWRlZCBhcyBwYXJ0IG9mIG91ciB3b3JrZmxvdywgYXMgaXQgd2FzIG5vdCByZXF1aXJlZCB0byBydW4gZmVhdHVyZUNvdW50cy4gVG8gcnVuIHRoaXMgcnVsZSBmb3IgYSBwYXJ0aWN1bGFyIGZpbGUsIHlvdSBoYXZlIHRhcmdldCBvbmUgb2YgdGhlIG91dHB1dCB0aGF0IGlzIGdlbmVyYXRlZCBieSB0aGlzIHJ1bGUgZm9yIGEgcGFydGljdWxhciBmaWxlIHVzaW5nIHRoZSBmb2xsb3dpbmcgZm9ybXVsYToKCmBzbmFrZW1ha2UgLS11c2UtY29uZGEgUUMvU0FNUExFL1NBTVBMRS5wbG90cy5odG1sYAoKV2hlcmUgU0FNUExFIGNhbiBiZSBhbnkgb2YgdGhlIGFjY2Vzc2lvbiBjb2RlcyBmcm9tIGBOQ0JJX2FjY2Vzc2lvbl9saXN0LnR4dGAuIENhbiB5b3UgcnVuIHRoaXMgcnVsZT8gV2hhdCB1c2VmdWwgaW5mb3JtYXRpb24gY2FuIGJlIGZvdW5kIG9uIHRoZSBvdXRwdXQgaHRtbCBmaWxlPgo=