Generating a high-res (HCD) spectral search library.
Gather data and plot metrics
if (file.exists(savefile)) {
load(savefile)
} else {
mzxml_data <- sm(extract_mzxml_data(metadata,
file_column="mzxmlfile",
savefile=savefile))
}
intensity_boxplot <- sm(plot_mzxml_boxplot(mzxml_data))
pp(file="images/mzxml_intensities.png", image=intensity_boxplot)
retention_boxplot <- sm(plot_mzxml_boxplot(mzxml_data, table="scans", column="peakscount"))
pp(file="images/mzxml_retention.png", image=retention_boxplot)
mz_boxplot <- sm(plot_mzxml_boxplot(mzxml_data, table="scans", column="basepeakmz"))
pp(file="images/mzxml_mzbase.png", image=mz_boxplot)
scanintensity_boxplot <- sm(plot_mzxml_boxplot(mzxml_data, table="scans", column="basepeakintensity"))
pp(file="images/mzxml_scanintensity.png", image=scanintensity_boxplot)
intensity_wrt_mz <- sm(plot_intensity_mz(mzxml_data, x_scale="log", y_scale="log"))
pp(file="images/intensity_wrt_mz_dia.png", image=intensity_wrt_mz$plot)
Get DIA metrics
Do not forget that extract_mzxml_data() writes the acquisition window files required for openswathworkflow to run, so do not forget to run it.
Plot dia metrics
Now let us plot the dia sample data.
if (file.exists(savefile)) {
load(savefile)
} else {
mzxml_data <- sm(extract_mzxml_data(metadata,
file_column="Filename",
savefile=savefile))
}
intensity_boxplot <- plot_mzxml_boxplot(mzxml_data)
pp(file="images/201805_dia_mzxml_intensities.png", image=intensity_boxplot)
retention_boxplot <- plot_mzxml_boxplot(mzxml_data, table="scans", column="peakscount")
pp(file="images/201805_dia_mzxml_retention.png", image=retention_boxplot)
mz_boxplot <- plot_mzxml_boxplot(mzxml_data, table="scans", column="basepeakmz")
pp(file="images/201805_dia_mzxml_mzbase.png", image=mz_boxplot)
scanintensity_boxplot <- plot_mzxml_boxplot(mzxml_data, table="scans", column="basepeakintensity")
pp(file="images/201805_dia_mzxml_scanintensity.png", image=scanintensity_boxplot)
intensity_wrt_mz <- plot_intensity_mz(mzxml_data, x_scale="log", y_scale="log")
pp(file="images/201805_dia_intensity_wrt_mz_dia.png", image=intensity_wrt_mz)
Gathering parameters
In this first block, I will set a couple of variables and source a file containing the parameters for the rest of the script.
ls parameters
export VERSION="20180530"
source parameters/20180530_settings.sh
echo "Version is: ${VERSION}"
## Bad Password
Test that we have the required variables for the rest of the script.
env | grep ${VERSION}
##cd "${START}"
echo $START
## Bad Password
Run comet on our DDA data
echo "Starting run of comet using the configuration file:
comet/comet_${DDA_METHOD}_params.txt against ${DDA_INPUTS}."
for comet_input in ${DDA_INPUTS}
do
echo "The input is: ${comet_input}"
/cbcb/sw/RedHat-7-x86_64/common/local/tpp/5.1.0/bin/comet \
"-Pcomet/comet_${DDA_METHOD}_params.txt" \
"${comet_input}" \
2>>"comet/comet_${VERSION}.log" 1>&2
done
tail "comet/comet_${VERSION}.log"
## Bad Password
Refresh the comet results
Comet does not provide the alternate hits, the following should add them into the comet output files.
echo "Starting refreshparser to hopefully add back the alternate matches dropped by comet."
for refresh_input in ${PEPXML_INPUTS}
do
echo "The input is: ${refresh_input}."
RefreshParser \
"${refresh_input}" \
"${REFDB}" \
2>>${refresh_input}.log 1>&2
done
## Bad Password
Merge searches
echo "Invoking xinteract to merge searches, set decoys, and set up fdr."
mkdir -p "results/fdr_controlled_${VERSION}_${TYPE}"
echo "The input is: ${PEPXML_INPUTS}"
echo "The output is: ${FDR_RESULT}"
xinteract \
"-d${DECOY_STRING}" \
-OARPpd \
-Ow \
"-N${FDR_RESULT}" \
"mzXML/dda_${VERSION}_${TYPE}"/*.pep.xml \
2>>"${FDR_RESULT}.log" 1>&2
tail "${FDR_RESULT}.log"
grep "${TEST}" "${FDR_RESULT}" | head
## Bad Password
Combine multiple identifications
echo "Invoking the InterProphetParser to combine multiple identifications of the same peptide."
mkdir -p "results/iprophet_${VERSION}_${TYPE}"
echo "The input is: ${FDR_RESULT}"
echo "The output is: ${IPP_RESULT}"
InterProphetParser \
"DECOY=${DECOY_STRING}" \
"${FDR_RESULT}" \
"${IPP_RESULT}" \
2>"${IPP_RESULT}.log" 1>&2
tail "${IPP_RESULT}.log"
grep "${TEST}" "${IPP_RESULT}" | head
## Bad Password
Mayu
echo "Invoking mayu to standardize the fdr estimates."
mkdir -p "results/mayu_${VERSION}_${TYPE}"
echo "The input is: ${IPP_RESULT}"
Mayu.pl \
-A "${IPP_RESULT}" \
-C "${REFDB}" \
-E "${DECOY_STRING}" \
-G "${CONFIDENCE_CUTOFF}" \
-H 101 \
-I "${CLEAVAGES}" \
2>"${MAYU_OUT}" 1>&2
head "${MAYU_OUT}"
## Did it work?
## I need to figure out how to include my generated decoys...
mkdir -p mayu
mayu_prefix=$(date +%Y-%m-%d)
mv "${mayu_prefix}"* results/mayu/
## Bad Password
Initial libraries spectrast
echo "Creating initial spectral libraries with spectrast."
echo "If a single input was given, make sure to link it to comet.mzXML."
mkdir -p results/spectral_libraries
rm -f "${SPECTRAL_BASENAME}*"
echo "The input is: ${SPECTRAL_BASENAME}"
echo "The output is: ${IPP_RESULT}"
spectrast \
"-cN${SPECTRAL_BASENAME}" \
"-cI${DDA_METHOD}" \
-cf "Protein! ~ ${DECOY_STRING}" \
"-cP${IPPP}" \
-c_IRR \
"${IPP_RESULT}" \
2>>${IPP_RESULT}.log 1>&2
tail "${IPP_RESULT}.log"
grep "${TEST}" "${SPECTRAL_BASENAME}.sptxt" | head
## Bad Password
Initial consensus spectrast
echo "Making initial consensus libraries with spectrast."
echo "The input is: ${SPECTRAL_LIBRARY}"
echo "The output is: ${CONSENSUS}"
mkdir -p results/spectral_consensus
spectrast \
"-cN${CONSENSUS}" \
"-cI${DDA_METHOD}" \
-cAC \
"${SPECTRAL_LIBRARY}" \
2>>"${CONSENSUS}.log" 1>&2
tail "${CONSENSUS}.log"
grep "${TEST}" "${CONSENSUS}.sptxt" | head
## Bad Password
Converting consensus libraries to tsv for later examination
echo "Make sure you have created an acquisition window file _without_ a header."
echo "There should be some which are just bob.txt in the windows/ directory."
echo "Writing spectrast tsv files with spectrast2tsv."
echo "Making a consensus library specific for ${MZ_WINDOWS} windows."
echo "The input is: ${CONSENSUS}.sptxt"
echo "The output is: ${CONSENSUS}_${MZ_WINDOWS}.tsv"
spectrast2tsv.py \
-l 350,2000 \
-s b,y \
-x 1,2 \
-o 4 \
-n 6 \
-p "${CONFIDENCE_CUTOFF}" \
-d \
-e \
-w "windows/acquisition_${MZ_WINDOWS}.txt" \
-k openswath \
-a "${CONSENSUS}_${MZ_WINDOWS}.tsv" \
"${CONSENSUS}.sptxt" \
2>>"${CONSENSUS}_spectrast2tsv.log" 1>&2
tail "${CONSENSUS}_spectrast2tsv.log"
grep "${TEST}" "${CONSENSUS}_${MZ_WINDOWS}.tsv" | head
## Bad Password
Converting consensus libraries to TraML
echo "Converting spectral libraries to TraML."
rm -f "${CONSENSUS}_${MZ_WINDOWS}.TraML"
echo "The input is: ${CONSENSUS}_${MZ_WINDOWS}.tsv"
echo "The output is: ${CONSENSUS}_${MZ_WINDOWS}.TraML"
TargetedFileConverter \
-in "${CONSENSUS}_${MZ_WINDOWS}.tsv" \
-in_type tsv \
-out "${CONSENSUS}_${MZ_WINDOWS}.TraML" \
-out_type TraML
## Bad Password
Add decoys to the TraML
echo "Adding decoys and optimizing the spectral libraries."
rm -f "${CONSENSUS}_${MZ_WINDOWS}_decoy.TraML"
echo "Generating decoys for ${CONSENSUS}_${MZ_WINDOWS}"
echo "Optimizing the consensus library."
echo "The input is: ${CONSENSUS_TRAML}"
echo "The output is: ${OPTIMIZED_TRAML}"
OpenSwathAssayGenerator \
-in "${CONSENSUS_TRAML}" \
-out "${OPTIMIZED_TRAML}" \
-swath_windows_file "windows/openswath_${MZ_WINDOWS}.txt" \
-enable_ipf \
-unimod_file "parameters/unimod.xml" \
2>>"${OPTIMIZED_TRAML}.log" 1>&2
tail "${OPTIMIZED_TRAML}.log"
echo "Adding decoys."
echo "The input is: ${OPTIMIZED_TRAML}"
echo "The output is: ${DECOY_TRAML}"
OpenSwathDecoyGenerator \
-in "${OPTIMIZED_TRAML}" \
-out "${DECOY_TRAML}" \
-decoy_tag "${DECOY_STRING}" \
-method shuffle \
2>>"${DECOY_TRAML}.log" 1>&2
tail "${DECOY_TRAML}.log"
grep "${TEST}" "${CONSENSUS}_${MZ_WINDOWS}_decoy.TraML" | head
## Bad Password
Convert back to tsv/pqp
echo "Converting decoy-added libraries back to tsv for examination later."
rm -f "${CONSENSUS}_${MZ_WINDOWS}_decoy.tsv"
echo "The input is: ${DECOY_TRAML}"
echo "The output is: ${TRANSITION_PREFIX}.tsv"
TargetedFileConverter \
-in "${DECOY_TRAML}" \
-in_type TraML \
-out "${TRANSITION_PREFIX}.tsv" \
-out_type tsv
echo "Converting libraries with decoys for ${TRANSITION_PREFIX} to pqp."
echo "The input is: ${DECOY_TRAML}"
echo "The output is: ${TRANSITION_PREFIX}.pqp"
TargetedFileConverter \
-in "${TRANSITION_PREFIX}.tsv" \
-in_type tsv \
-out_type pqp \
-out "${TRANSITION_PREFIX}.pqp"
echo "Transition library for openswathworkflow is: ${TRANSITION_PREFIX}.pqp"
grep "${TEST}" "${TRANSITION_PREFIX}.tsv" | head
grep -c "${DECOY_STRING}" "${TRANSITION_PREFIX}.tsv"
## Bad Password
OpenSwathWorkflow against our experimental transitions
echo "Invoking the OpenSwathWorkflow."
echo "Checking in, the transition library is: ${TRANSITION_PREFIX}.pqp"
swath_inputs=$(/bin/ls "mzXML/dia_${VERSION}")
echo "Checking in, the inputs are: ${SWATH_INPUTS}"
mkdir -p "${SWATH_OUTDIR}"
for input in ${swath_inputs}
do
in_mzxml="mzXML/dia_${VERSION}/${input}"
name=$(basename "${input}" .mzXML)
echo "Starting openswath run of ${name} using ${MZ_WINDOWS} windows at $(date)."
swath_output_prefix="${SWATH_OUTDIR}/${name}_vs_${VERSION}_${TYPE}_${DDA_METHOD}_dia"
echo "Deleting previous swath output file: ${SWATH_OUTPUT_PREFIX}.osw"
rm -f "${SWATH_OUTPUT_PREFIX}.osw"
OpenSwathWorkflow \
-ini "parameters/openms_${VERSION}.ini" \
-in "${in_mzxml}" \
-swath_windows_file "windows/openswath_${name}.txt" \
-tr "${TRANSITON_PREFIX}.pqp" \
-out_osw "${swath_output_prefix}.osw" \
2>"${swath_output_prefix}_osw.log" 1>&2
echo "Scoring individual swath run: ${swath_output_prefix}"
pyprophet \
score \
--level ms1 \
--in "${swath_output_prefix}.osw" \
2>>"${swath_output_prefix}_pyprophet_ms1.log" 1>&2
pyprophet \
score \
--level ms2 \
--in "${swath_output_prefix}.osw" \
--out "${swath_output_prefix}_scored.osw" \
2>>"${swath_output_prefix}_pyprophet_ms2.log" 1>&2
pyprophet \
protein \
--in "${swath_output_prefix}_scored.osw" \
--context run-specific \
2>>"${swath_output_prefix}_pyprophet_protein.log" 1>&2
echo "Exporting individual swath run: to ${swath_output_prefix}.tsv"
pyprophet \
export \
--in "${swath_output_prefix}_scored.osw" \
--out "${swath_output_prefix}_scored.tsv" \
2>>"${swath_output_prefix}_pyprophet_export.log" 1>&2
done
## Bad Password
OpenSwathWorkflow against our the Tuberculist transitions
echo "Invoking the OpenSwathWorkflow using the tuberculist transitions."
swath_inputs=$(/bin/ls "mzXML/dia_${VERSION}")
echo "Checking in, the inputs are: ${swath_inputs}"
mkdir -p "${TUBERCULIST_OUTDIR}"
for input in ${swath_inputs}
do
in_mzxml="mzXML/dia_${VERSION}/${input}"
name=$(basename "${input}" .mzXML)
echo "Starting openswath run of ${name} using ${MZ_WINDOWS} windows at $(date)."
tb_output_prefix="${TUBERCULIST_OUTDIR}/${name}_vs_${VERSION}_${TYPE}_${DDA_METHOD}_dia"
echo "Deleting previous swath output file: ${tb_output_prefix}.osw"
rm -f "${tb_output_prefix}.osw"
OpenSwathWorkflow \
-ini "parameters/openms_${VERSION}.ini" \
-in "${in_mzxml}" \
-swath_windows_file "windows/openswath_${name}.txt" \
-tr "${TUBERCULIST_PQP}" \
-out_osw "${tb_output_prefix}.osw" \
2>"${tb_output_prefix}_osw.log" 1>&2
echo "Scoring individual swath run: ${tb_output_prefix}"
pyprophet \
score \
--level ms1 \
--in "${tb_output_prefix}.osw" \
2>>"${tb_output_prefix}_pyprophet_ms1.log" 1>&2
pyprophet \
score \
--level ms2 \
--in "${tb_output_prefix}.osw" \
--out "${tb_output_prefix}_scored.osw" \
2>>"${tb_output_prefix}_pyprophet_ms2.log" 1>&2
pyprophet \
protein \
--in "${tb_output_prefix}_scored.osw" \
--context run-specific \
2>>"${tb_output_prefix}_pyprophet_protein.log" 1>&2
echo "Exporting individual swath run: to ${tb_output_prefix}.tsv"
pyprophet \
export \
--in "${tb_output_prefix}_scored.osw" \
--out "${tb_output_prefix}_scored.tsv" \
2>>"${tb_output_prefix}_pyprophet_export.log" 1>&2
done
## Bad Password
Merging our data with TRIC
feature_alignment.py \
--force \
--in "./${SWATH_OUTDIR}/"*.tsv \
--out "${TRIC_OUTDIR}/${SEARCH_METHOD}_${DDA_METHOD}.tsv" \
--out_matrix "${TRIC_OUTDIR}/${DDA_METHOD}_outmatrix.tsv" \
--out_meta "${TRIC_OUTDIR}/${DDA_METHOD}_meta.tsv"
echo "Wrote final output to ${TRIC_OUTDIR}/${SEARCH_METHOD}_${DDA_METHOD}.tsv"
## Bad Password
Merging the Tuberculist-derived data with TRIC
tric_tb="${TRIC_OUTDIR}_tb"
feature_alignment.py \
--force \
--in "./${SWATH_OUTDIR}/"*.tsv \
--out "${tric_tb}/${SEARCH_METHOD}_${DDA_METHOD}.tsv" \
--out_matrix "${tric_tb}/${DDA_METHOD}_outmatrix.tsv" \
--out_meta "${tric_tb}/${DDA_METHOD}_meta.tsv"
echo "Wrote final output to ${tric_tb}/${SEARCH_METHOD}_${DDA_METHOD}.tsv"
## Bad Password
Index version: 20180215
TODO
if (!isTRUE(get0("skip_load"))) {
message(paste0("This is hpgltools commit: ", get_git_commit()))
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
tmp <- sm(saveme(filename=this_save))
pander::pander(sessionInfo())
}
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 4523f8cfb1df75584e2257a89e1810ee13c56a67
## R> packrat::restore()
## This is hpgltools commit: Tue May 29 16:09:33 2018 -0400: 4523f8cfb1df75584e2257a89e1810ee13c56a67
## Saving to 01_preprocessing_comet_20180508-v20180215.rda.xz
R version 3.3.1 (2016-06-21)
Platform: x86_64-pc-linux-gnu (64-bit)
locale: LC_CTYPE=en_US.utf8, LC_NUMERIC=C, LC_TIME=en_US.utf8, LC_COLLATE=en_US.utf8, LC_MONETARY=en_US.utf8, LC_MESSAGES=en_US.utf8, LC_PAPER=en_US.utf8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.utf8 and LC_IDENTIFICATION=C
attached base packages: stats, graphics, grDevices, utils, datasets, methods and base
other attached packages: runr(v.0.0.8) and hpgltools(v.2017.10)
loaded via a namespace (and not attached): Rcpp(v.0.12.15), knitr(v.1.20), magrittr(v.1.5), BiocGenerics(v.0.20.0), munsell(v.0.4.3), colorspace(v.1.3-2), foreach(v.1.4.3), highr(v.0.6), stringr(v.1.2.0), plyr(v.1.8.4), tools(v.3.3.1), parallel(v.3.3.1), grid(v.3.3.1), Biobase(v.2.34.0), data.table(v.1.10.4), gtable(v.0.2.0), htmltools(v.0.3.5), iterators(v.1.0.8), lazyeval(v.0.2.0), yaml(v.2.1.14), rprojroot(v.1.2), digest(v.0.6.12), tibble(v.1.3.0), ggplot2(v.2.2.1), base64enc(v.0.1-3), codetools(v.0.2-14), evaluate(v.0.10), rmarkdown(v.1.9), openxlsx(v.4.0.17), stringi(v.1.1.3), pander(v.0.6.0), scales(v.0.4.1) and backports(v.1.0.5)
b$stop()
LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxODA1MzA6IFByZXByb2Nlc3NpbmcgRElBIGRhdGEgd2l0aCBhIGNvbWV0IGhpZ2hyZXMgbGlicmFyeSAobW9yZSBzYW1wbGVzKS4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICAgY29sbGFwc2VkOiBmYWxzZQogICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgbGlicmFyeShocGdsdG9vbHMpCiAgbGlicmFyeShydW5yKQogIGIgPC0gcHJvY19iYXNoKHBvcnQ9MjAwMCkKICBzdGFydGVkIDwtIGIkc3RhcnQoKQogIGtuaXRyOjprbml0X2VuZ2luZXMkc2V0KGJhc2hfcnVucj1mdW5jdGlvbihvcHRpb25zKSB7CiAgICBrbml0cjo6OndyYXAoYiRleGVjKG9wdGlvbnMkY29kZSksIG9wdGlvbnMpCiAgfSkKICAjI3R0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQogIGtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTkwLAogICAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKICBrbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQogIG9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzPTQsCiAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCiAgZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCiAgdmVyIDwtICIyMDE4MDIxNSIKICBwcmV2aW91c19maWxlIDwtICIwMV9hbm5vdGF0aW9uLlJtZCIKCiAgIyN0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKSkKICBybWRfZmlsZSA8LSAiMDFfcHJlcHJvY2Vzc2luZ19jb21ldF8yMDE4MDUwOC5SbWQiCn0KYGBgCgpQcmVwcm9jZXNzaW5nIERJQSBkYXRhIHZpYSB0aGUgaW5zdHJ1Y3Rpb25zIGF0OiBodHRwOi8vZGlhLXN3YXRoLWNvdXJzZS5ldGh6LmNoL3R1dG9yaWFsczIwMTcvCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgR2VuZXJhdGluZyBhIGhpZ2gtcmVzIChIQ0QpIHNwZWN0cmFsIHNlYXJjaCBsaWJyYXJ5LgoKIyMgUmVhZGluZyBtZXRhZGF0YQoKSW4gdGhlb3J5LCBJIGhhdmUgZmlndXJlZCBvdXQgaG93IHRvIHJlbmRlciBhIG1peCBvZiBiYXNoIGFuZCByIGluIG11bHRpcGxlIGJsb2Nrcy4KVGhpcyB3b3Jrc2hlZXQgd2lsbCB0ZXN0IHRoYXQgdGhlb3J5IGJ5IGNvcHkvcGFzdGluZyBvdXQgdGhlIHZhcmlvdXMgc2VjdGlvbnMgb2YgYmFzaApyZXF1aXJlZCB0byBkbyB0aGUgcHJvY2Vzc2luZyBvZiB0aGlzIGRhdGEgaW50byBibG9ja3MgbGFiZWxlZCAnYmFzaF9ydW5yJy4KCklmIEkgYW0gY29ycmVjdCwgd2Ugd2lsbCBiZSBhYmxlIHRoZW4gdG8gdGVzdCBhbmQgcmVuZGVyIGVhY2ggcGllY2Ugb2YgdGhpcwpwcm9jZXNzIHdpdGhvdXQgaGF2aW5nIHRvIHJ1biB0aGUgZW50aXJlIHRoaW5nIGFzIGEgYmFzaCBzY3JpcHQgYXQgdGhlIGVuZC4KClRoZSBvcmlnaW5hbCBzY3JpcHQgd2hpY2ggcHJvdmlkZXMgdGhlIG1lYXQgb2YgdGhpcyBkb2N1bWVudCBpcyBzdGlsbCBoZXJlIGluCmNhc2UgdGhpcyBmYWlscyBhcyBkaWFfaW52b2NhdGlvbl9oY2RfMjAxODA1MzAuc2guCgpgYGB7ciBteV9kZGFfbWV0cmljc30Kc2FtcGxlX3NoZWV0IDwtICJzYW1wbGVfc2hlZXRzL2RkYV9zYW1wbGVzLnhsc3giCnNhdmVmaWxlIDwtICJtenhtbF9kZGFfZGF0YV8yMDE4MDUucmRhIgoKbWV0YWRhdGEgPC0gb3Blbnhsc3g6OnJlYWQueGxzeChzYW1wbGVfc2hlZXQpCmtlZXBlcl9pZHggPC0gbWV0YWRhdGFbWyJzYW1wbGVkYXRlIl1dID09ICIyMDE4MDQyMCIKbWV0YWRhdGEgPC0gbWV0YWRhdGFba2VlcGVyX2lkeCwgXQoKa25pdHI6OmthYmxlKG1ldGFkYXRhKQpgYGAKCiMjIEdhdGhlciBkYXRhIGFuZCBwbG90IG1ldHJpY3MKCmBgYHtyIGRkYV9wbG90cywgZXZhbD1GQUxTRX0KaWYgKGZpbGUuZXhpc3RzKHNhdmVmaWxlKSkgewogIGxvYWQoc2F2ZWZpbGUpCn0gZWxzZSB7CiAgbXp4bWxfZGF0YSA8LSBzbShleHRyYWN0X216eG1sX2RhdGEobWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW49Im16eG1sZmlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZWZpbGU9c2F2ZWZpbGUpKQp9CgppbnRlbnNpdHlfYm94cGxvdCA8LSBzbShwbG90X216eG1sX2JveHBsb3QobXp4bWxfZGF0YSkpCnBwKGZpbGU9ImltYWdlcy9tenhtbF9pbnRlbnNpdGllcy5wbmciLCBpbWFnZT1pbnRlbnNpdHlfYm94cGxvdCkKCnJldGVudGlvbl9ib3hwbG90IDwtIHNtKHBsb3RfbXp4bWxfYm94cGxvdChtenhtbF9kYXRhLCB0YWJsZT0ic2NhbnMiLCBjb2x1bW49InBlYWtzY291bnQiKSkKcHAoZmlsZT0iaW1hZ2VzL216eG1sX3JldGVudGlvbi5wbmciLCBpbWFnZT1yZXRlbnRpb25fYm94cGxvdCkKCm16X2JveHBsb3QgPC0gc20ocGxvdF9tenhtbF9ib3hwbG90KG16eG1sX2RhdGEsIHRhYmxlPSJzY2FucyIsIGNvbHVtbj0iYmFzZXBlYWtteiIpKQpwcChmaWxlPSJpbWFnZXMvbXp4bWxfbXpiYXNlLnBuZyIsIGltYWdlPW16X2JveHBsb3QpCgpzY2FuaW50ZW5zaXR5X2JveHBsb3QgPC0gc20ocGxvdF9tenhtbF9ib3hwbG90KG16eG1sX2RhdGEsIHRhYmxlPSJzY2FucyIsIGNvbHVtbj0iYmFzZXBlYWtpbnRlbnNpdHkiKSkKcHAoZmlsZT0iaW1hZ2VzL216eG1sX3NjYW5pbnRlbnNpdHkucG5nIiwgaW1hZ2U9c2NhbmludGVuc2l0eV9ib3hwbG90KQoKaW50ZW5zaXR5X3dydF9teiA8LSBzbShwbG90X2ludGVuc2l0eV9teihtenhtbF9kYXRhLCB4X3NjYWxlPSJsb2ciLCB5X3NjYWxlPSJsb2ciKSkKcHAoZmlsZT0iaW1hZ2VzL2ludGVuc2l0eV93cnRfbXpfZGlhLnBuZyIsIGltYWdlPWludGVuc2l0eV93cnRfbXokcGxvdCkKYGBgCgojIEdldCBESUEgbWV0cmljcwoKRG8gbm90IGZvcmdldCB0aGF0IGV4dHJhY3RfbXp4bWxfZGF0YSgpIHdyaXRlcyB0aGUgYWNxdWlzaXRpb24gd2luZG93IGZpbGVzCnJlcXVpcmVkIGZvciBvcGVuc3dhdGh3b3JrZmxvdyB0byBydW4sIHNvIGRvIG5vdCBmb3JnZXQgdG8gcnVuIGl0LgoKIyMgUmVhZCBkaWEgbWV0YWRhdGEKCmBgYHtyIGRpYV9tZXRyaWNzLCBldmFsPUZBTFNFfQpzYW1wbGVfc2hlZXQgPC0gInNhbXBsZV9zaGVldHMvTXRiX2RpYV9zYW1wbGVzLnhsc3giCnNhdmVmaWxlIDwtICJtenhtbF9kaWFfZGF0YV8yMDE4MDUucmRhIgoKbWV0YWRhdGEgPC0gb3Blbnhsc3g6OnJlYWQueGxzeChzYW1wbGVfc2hlZXQpCmtlZXBlcl9pZHggPC0gbWV0YWRhdGFbWyJleHB0X2lkIl1dID09ICJtYXkyMDE4IgprZWVwZXJfaWR4W2lzLm5hKGtlZXBlcl9pZHgpXSA8LSBGQUxTRQptZXRhZGF0YSA8LSBtZXRhZGF0YVtrZWVwZXJfaWR4LCBdCmtuaXRyOjprYWJsZShtZXRhZGF0YSkKYGBgCgojIyBQbG90IGRpYSBtZXRyaWNzCgpOb3cgbGV0IHVzIHBsb3QgdGhlIGRpYSBzYW1wbGUgZGF0YS4KCmBgYHtyIGRpYV9wbG90cywgZXZhbD1GQUxTRX0KaWYgKGZpbGUuZXhpc3RzKHNhdmVmaWxlKSkgewogIGxvYWQoc2F2ZWZpbGUpCn0gZWxzZSB7CiAgbXp4bWxfZGF0YSA8LSBzbShleHRyYWN0X216eG1sX2RhdGEobWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW49IkZpbGVuYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYXZlZmlsZT1zYXZlZmlsZSkpCn0KCmludGVuc2l0eV9ib3hwbG90IDwtIHBsb3RfbXp4bWxfYm94cGxvdChtenhtbF9kYXRhKQpwcChmaWxlPSJpbWFnZXMvMjAxODA1X2RpYV9tenhtbF9pbnRlbnNpdGllcy5wbmciLCBpbWFnZT1pbnRlbnNpdHlfYm94cGxvdCkKCnJldGVudGlvbl9ib3hwbG90IDwtIHBsb3RfbXp4bWxfYm94cGxvdChtenhtbF9kYXRhLCB0YWJsZT0ic2NhbnMiLCBjb2x1bW49InBlYWtzY291bnQiKQpwcChmaWxlPSJpbWFnZXMvMjAxODA1X2RpYV9tenhtbF9yZXRlbnRpb24ucG5nIiwgaW1hZ2U9cmV0ZW50aW9uX2JveHBsb3QpCgptel9ib3hwbG90IDwtIHBsb3RfbXp4bWxfYm94cGxvdChtenhtbF9kYXRhLCB0YWJsZT0ic2NhbnMiLCBjb2x1bW49ImJhc2VwZWFrbXoiKQpwcChmaWxlPSJpbWFnZXMvMjAxODA1X2RpYV9tenhtbF9temJhc2UucG5nIiwgaW1hZ2U9bXpfYm94cGxvdCkKCnNjYW5pbnRlbnNpdHlfYm94cGxvdCA8LSBwbG90X216eG1sX2JveHBsb3QobXp4bWxfZGF0YSwgdGFibGU9InNjYW5zIiwgY29sdW1uPSJiYXNlcGVha2ludGVuc2l0eSIpCnBwKGZpbGU9ImltYWdlcy8yMDE4MDVfZGlhX216eG1sX3NjYW5pbnRlbnNpdHkucG5nIiwgaW1hZ2U9c2NhbmludGVuc2l0eV9ib3hwbG90KQoKaW50ZW5zaXR5X3dydF9teiA8LSBwbG90X2ludGVuc2l0eV9teihtenhtbF9kYXRhLCB4X3NjYWxlPSJsb2ciLCB5X3NjYWxlPSJsb2ciKQpwcChmaWxlPSJpbWFnZXMvMjAxODA1X2RpYV9pbnRlbnNpdHlfd3J0X216X2RpYS5wbmciLCBpbWFnZT1pbnRlbnNpdHlfd3J0X216KQpgYGAKCiMgR2F0aGVyaW5nIHBhcmFtZXRlcnMKCkluIHRoaXMgZmlyc3QgYmxvY2ssIEkgd2lsbCBzZXQgYSBjb3VwbGUgb2YgdmFyaWFibGVzIGFuZCBzb3VyY2UgYSBmaWxlCmNvbnRhaW5pbmcgdGhlIHBhcmFtZXRlcnMgZm9yIHRoZSByZXN0IG9mIHRoZSBzY3JpcHQuCgpgYGB7YmFzaF9ydW5yIHBhcmFtZXRlcnN9CmxzIHBhcmFtZXRlcnMKZXhwb3J0IFZFUlNJT049IjIwMTgwNTMwIgpzb3VyY2UgcGFyYW1ldGVycy8yMDE4MDUzMF9zZXR0aW5ncy5zaAplY2hvICJWZXJzaW9uIGlzOiAke1ZFUlNJT059IgpgYGAKCmBgYHtyIHNsZWVwMSwgaW5jbHVkZT1GQUxTRX0KU3lzLnNsZWVwKDEpCmBgYAoKIyMgVGVzdCB0aGF0IHdlIGhhdmUgdGhlIHJlcXVpcmVkIHZhcmlhYmxlcyBmb3IgdGhlIHJlc3Qgb2YgdGhlIHNjcmlwdC4KCmBgYHtiYXNoX3J1bnIgdGVzdF9wYXJhbXN9CmVudiB8IGdyZXAgJHtWRVJTSU9OfQoKIyNjZCAiJHtTVEFSVH0iCmVjaG8gJFNUQVJUCmBgYAoKYGBge3Igc2xlZXAyLCBpbmNsdWRlPUZBTFNFfQpTeXMuc2xlZXAoMSkKYGBgCgojIFJ1biBjb21ldCBvbiBvdXIgRERBIGRhdGEKCmBgYHtiYXNoX3J1bnIgY29tZXR9CmVjaG8gIlN0YXJ0aW5nIHJ1biBvZiBjb21ldCB1c2luZyB0aGUgY29uZmlndXJhdGlvbiBmaWxlOgpjb21ldC9jb21ldF8ke0REQV9NRVRIT0R9X3BhcmFtcy50eHQgYWdhaW5zdCAke0REQV9JTlBVVFN9LiIKZm9yIGNvbWV0X2lucHV0IGluICR7RERBX0lOUFVUU30KZG8KICAgIGVjaG8gIlRoZSBpbnB1dCBpczogJHtjb21ldF9pbnB1dH0iCiAgICAvY2JjYi9zdy9SZWRIYXQtNy14ODZfNjQvY29tbW9uL2xvY2FsL3RwcC81LjEuMC9iaW4vY29tZXQgXAogICAgICAgICItUGNvbWV0L2NvbWV0XyR7RERBX01FVEhPRH1fcGFyYW1zLnR4dCIgXAogICAgICAgICIke2NvbWV0X2lucHV0fSIgXAogICAgICAgIDI+PiJjb21ldC9jb21ldF8ke1ZFUlNJT059LmxvZyIgMT4mMgpkb25lCnRhaWwgImNvbWV0L2NvbWV0XyR7VkVSU0lPTn0ubG9nIgpgYGAKCmBgYHtyIHNsZWVwMywgaW5jbHVkZT1GQUxTRX0KU3lzLnNsZWVwKDEpCmBgYAoKIyBSZWZyZXNoIHRoZSBjb21ldCByZXN1bHRzCgpDb21ldCBkb2VzIG5vdCBwcm92aWRlIHRoZSBhbHRlcm5hdGUgaGl0cywgdGhlIGZvbGxvd2luZyBzaG91bGQgYWRkIHRoZW0gaW50bwp0aGUgY29tZXQgb3V0cHV0IGZpbGVzLgoKYGBge2Jhc2hfcnVuciBjb21ldF9yZWZyZXNofQplY2hvICJTdGFydGluZyByZWZyZXNocGFyc2VyIHRvIGhvcGVmdWxseSBhZGQgYmFjayB0aGUgYWx0ZXJuYXRlIG1hdGNoZXMgZHJvcHBlZCBieSBjb21ldC4iCmZvciByZWZyZXNoX2lucHV0IGluICR7UEVQWE1MX0lOUFVUU30KZG8KICAgIGVjaG8gIlRoZSBpbnB1dCBpczogJHtyZWZyZXNoX2lucHV0fS4iCiAgICBSZWZyZXNoUGFyc2VyIFwKICAgICAgICAiJHtyZWZyZXNoX2lucHV0fSIgXAogICAgICAgICIke1JFRkRCfSIgXAogICAgICAgIDI+PiR7cmVmcmVzaF9pbnB1dH0ubG9nIDE+JjIKZG9uZQpgYGAKCmBgYHtyIHNsZWVwNCwgaW5jbHVkZT1GQUxTRX0KU3lzLnNsZWVwKDEpCmBgYAoKIyBNZXJnZSBzZWFyY2hlcwoKYGBge2Jhc2hfcnVuciB4aW50ZXJhY3RfbWVyZ2V9CmVjaG8gIkludm9raW5nIHhpbnRlcmFjdCB0byBtZXJnZSBzZWFyY2hlcywgc2V0IGRlY295cywgYW5kIHNldCB1cCBmZHIuIgpta2RpciAtcCAicmVzdWx0cy9mZHJfY29udHJvbGxlZF8ke1ZFUlNJT059XyR7VFlQRX0iCmVjaG8gIlRoZSBpbnB1dCBpczogJHtQRVBYTUxfSU5QVVRTfSIKZWNobyAiVGhlIG91dHB1dCBpczogJHtGRFJfUkVTVUxUfSIKeGludGVyYWN0IFwKICAgICItZCR7REVDT1lfU1RSSU5HfSIgXAogICAgLU9BUlBwZCBcCiAgICAtT3cgXAogICAgIi1OJHtGRFJfUkVTVUxUfSIgXAogICAgIm16WE1ML2RkYV8ke1ZFUlNJT059XyR7VFlQRX0iLyoucGVwLnhtbCBcCiAgICAyPj4iJHtGRFJfUkVTVUxUfS5sb2ciIDE+JjIKdGFpbCAiJHtGRFJfUkVTVUxUfS5sb2ciCmdyZXAgIiR7VEVTVH0iICIke0ZEUl9SRVNVTFR9IiB8IGhlYWQKYGBgCgpgYGB7ciBzbGVlcDUsIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgQ29tYmluZSBtdWx0aXBsZSBpZGVudGlmaWNhdGlvbnMKCmBgYHtiYXNoX3J1bnIgaW50ZXJwcm9waGV0fQplY2hvICJJbnZva2luZyB0aGUgSW50ZXJQcm9waGV0UGFyc2VyIHRvIGNvbWJpbmUgbXVsdGlwbGUgaWRlbnRpZmljYXRpb25zIG9mIHRoZSBzYW1lIHBlcHRpZGUuIgpta2RpciAtcCAicmVzdWx0cy9pcHJvcGhldF8ke1ZFUlNJT059XyR7VFlQRX0iCmVjaG8gIlRoZSBpbnB1dCBpczogJHtGRFJfUkVTVUxUfSIKZWNobyAiVGhlIG91dHB1dCBpczogJHtJUFBfUkVTVUxUfSIKSW50ZXJQcm9waGV0UGFyc2VyIFwKICAgICJERUNPWT0ke0RFQ09ZX1NUUklOR30iIFwKICAgICIke0ZEUl9SRVNVTFR9IiBcCiAgICAiJHtJUFBfUkVTVUxUfSIgXAogICAgMj4iJHtJUFBfUkVTVUxUfS5sb2ciIDE+JjIKdGFpbCAiJHtJUFBfUkVTVUxUfS5sb2ciCmdyZXAgIiR7VEVTVH0iICIke0lQUF9SRVNVTFR9IiB8IGhlYWQKYGBgCgpgYGB7ciBzbGVlcDYsIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgTWF5dQoKYGBge2Jhc2hfcnVuciBtYXl1fQplY2hvICJJbnZva2luZyBtYXl1IHRvIHN0YW5kYXJkaXplIHRoZSBmZHIgZXN0aW1hdGVzLiIKbWtkaXIgLXAgInJlc3VsdHMvbWF5dV8ke1ZFUlNJT059XyR7VFlQRX0iCmVjaG8gIlRoZSBpbnB1dCBpczogJHtJUFBfUkVTVUxUfSIKTWF5dS5wbCBcCiAgICAtQSAiJHtJUFBfUkVTVUxUfSIgXAogICAgLUMgIiR7UkVGREJ9IiBcCiAgICAtRSAiJHtERUNPWV9TVFJJTkd9IiBcCiAgICAtRyAiJHtDT05GSURFTkNFX0NVVE9GRn0iIFwKICAgIC1IIDEwMSBcCiAgICAtSSAiJHtDTEVBVkFHRVN9IiBcCiAgICAyPiIke01BWVVfT1VUfSIgMT4mMgpoZWFkICIke01BWVVfT1VUfSIKIyMgRGlkIGl0IHdvcms/CiMjIEkgbmVlZCB0byBmaWd1cmUgb3V0IGhvdyB0byBpbmNsdWRlIG15IGdlbmVyYXRlZCBkZWNveXMuLi4KbWtkaXIgLXAgbWF5dQptYXl1X3ByZWZpeD0kKGRhdGUgKyVZLSVtLSVkKQptdiAiJHttYXl1X3ByZWZpeH0iKiByZXN1bHRzL21heXUvCmBgYAoKYGBge3Igc2xlZXA3LCBpbmNsdWRlPUZBTFNFfQpTeXMuc2xlZXAoMSkKYGBgCgojIEluaXRpYWwgbGlicmFyaWVzIHNwZWN0cmFzdAoKYGBge2Jhc2hfcnVuciBzcGVjdHJhc3QxfQplY2hvICJDcmVhdGluZyBpbml0aWFsIHNwZWN0cmFsIGxpYnJhcmllcyB3aXRoIHNwZWN0cmFzdC4iCmVjaG8gIklmIGEgc2luZ2xlIGlucHV0IHdhcyBnaXZlbiwgbWFrZSBzdXJlIHRvIGxpbmsgaXQgdG8gY29tZXQubXpYTUwuIgpta2RpciAtcCByZXN1bHRzL3NwZWN0cmFsX2xpYnJhcmllcwpybSAtZiAiJHtTUEVDVFJBTF9CQVNFTkFNRX0qIgplY2hvICJUaGUgaW5wdXQgaXM6ICR7U1BFQ1RSQUxfQkFTRU5BTUV9IgplY2hvICJUaGUgb3V0cHV0IGlzOiAke0lQUF9SRVNVTFR9IgpzcGVjdHJhc3QgXAogICAgIi1jTiR7U1BFQ1RSQUxfQkFTRU5BTUV9IiBcCiAgICAiLWNJJHtEREFfTUVUSE9EfSIgXAogICAgLWNmICJQcm90ZWluISB+ICR7REVDT1lfU1RSSU5HfSIgXAogICAgIi1jUCR7SVBQUH0iIFwKICAgIC1jX0lSUiBcCiAgICAiJHtJUFBfUkVTVUxUfSIgXAogICAgMj4+JHtJUFBfUkVTVUxUfS5sb2cgMT4mMgp0YWlsICIke0lQUF9SRVNVTFR9LmxvZyIKZ3JlcCAiJHtURVNUfSIgIiR7U1BFQ1RSQUxfQkFTRU5BTUV9LnNwdHh0IiB8IGhlYWQKYGBgCgpgYGB7ciBzbGVlcDgsIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgSW5pdGlhbCBjb25zZW5zdXMgc3BlY3RyYXN0CgpgYGB7YmFzaF9ydW5yIHNwZWN0cmFzdDJ9CmVjaG8gIk1ha2luZyBpbml0aWFsIGNvbnNlbnN1cyBsaWJyYXJpZXMgd2l0aCBzcGVjdHJhc3QuIgplY2hvICJUaGUgaW5wdXQgaXM6ICR7U1BFQ1RSQUxfTElCUkFSWX0iCmVjaG8gIlRoZSBvdXRwdXQgaXM6ICR7Q09OU0VOU1VTfSIKbWtkaXIgLXAgcmVzdWx0cy9zcGVjdHJhbF9jb25zZW5zdXMKc3BlY3RyYXN0IFwKICAgICItY04ke0NPTlNFTlNVU30iIFwKICAgICItY0kke0REQV9NRVRIT0R9IiBcCiAgICAtY0FDIFwKICAgICIke1NQRUNUUkFMX0xJQlJBUll9IiBcCiAgICAyPj4iJHtDT05TRU5TVVN9LmxvZyIgMT4mMgp0YWlsICIke0NPTlNFTlNVU30ubG9nIgpncmVwICIke1RFU1R9IiAiJHtDT05TRU5TVVN9LnNwdHh0IiB8IGhlYWQKYGBgCgpgYGB7ciBzbGVlcDksIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgQ29udmVydGluZyBjb25zZW5zdXMgbGlicmFyaWVzIHRvIHRzdiBmb3IgbGF0ZXIgZXhhbWluYXRpb24KCmBgYHtiYXNoX3J1bnIgc3BlY3RyYXN0MnRzdn0KZWNobyAiTWFrZSBzdXJlIHlvdSBoYXZlIGNyZWF0ZWQgYW4gYWNxdWlzaXRpb24gd2luZG93IGZpbGUgX3dpdGhvdXRfIGEgaGVhZGVyLiIKZWNobyAiVGhlcmUgc2hvdWxkIGJlIHNvbWUgd2hpY2ggYXJlIGp1c3QgYm9iLnR4dCBpbiB0aGUgd2luZG93cy8gZGlyZWN0b3J5LiIKZWNobyAiV3JpdGluZyBzcGVjdHJhc3QgdHN2IGZpbGVzIHdpdGggc3BlY3RyYXN0MnRzdi4iCmVjaG8gIk1ha2luZyBhIGNvbnNlbnN1cyBsaWJyYXJ5IHNwZWNpZmljIGZvciAke01aX1dJTkRPV1N9IHdpbmRvd3MuIgplY2hvICJUaGUgaW5wdXQgaXM6ICR7Q09OU0VOU1VTfS5zcHR4dCIKZWNobyAiVGhlIG91dHB1dCBpczogJHtDT05TRU5TVVN9XyR7TVpfV0lORE9XU30udHN2IgpzcGVjdHJhc3QydHN2LnB5IFwKICAgIC1sIDM1MCwyMDAwIFwKICAgIC1zIGIseSBcCiAgICAteCAxLDIgXAogICAgLW8gNCBcCiAgICAtbiA2IFwKICAgIC1wICIke0NPTkZJREVOQ0VfQ1VUT0ZGfSIgXAogICAgLWQgXAogICAgLWUgXAogICAgLXcgIndpbmRvd3MvYWNxdWlzaXRpb25fJHtNWl9XSU5ET1dTfS50eHQiIFwKICAgIC1rIG9wZW5zd2F0aCBcCiAgICAtYSAiJHtDT05TRU5TVVN9XyR7TVpfV0lORE9XU30udHN2IiBcCiAgICAiJHtDT05TRU5TVVN9LnNwdHh0IiBcCiAgICAyPj4iJHtDT05TRU5TVVN9X3NwZWN0cmFzdDJ0c3YubG9nIiAxPiYyCnRhaWwgIiR7Q09OU0VOU1VTfV9zcGVjdHJhc3QydHN2LmxvZyIKZ3JlcCAiJHtURVNUfSIgIiR7Q09OU0VOU1VTfV8ke01aX1dJTkRPV1N9LnRzdiIgfCBoZWFkCmBgYAoKYGBge3Igc2xlZXAxMCwgaW5jbHVkZT1GQUxTRX0KU3lzLnNsZWVwKDEpCmBgYAoKIyBDb252ZXJ0aW5nIGNvbnNlbnN1cyBsaWJyYXJpZXMgdG8gVHJhTUwKCmBgYHtiYXNoX3J1bnIgdG90cmFtbH0KZWNobyAiQ29udmVydGluZyBzcGVjdHJhbCBsaWJyYXJpZXMgdG8gVHJhTUwuIgpybSAtZiAiJHtDT05TRU5TVVN9XyR7TVpfV0lORE9XU30uVHJhTUwiCmVjaG8gIlRoZSBpbnB1dCBpczogJHtDT05TRU5TVVN9XyR7TVpfV0lORE9XU30udHN2IgplY2hvICJUaGUgb3V0cHV0IGlzOiAke0NPTlNFTlNVU31fJHtNWl9XSU5ET1dTfS5UcmFNTCIKVGFyZ2V0ZWRGaWxlQ29udmVydGVyIFwKICAgIC1pbiAiJHtDT05TRU5TVVN9XyR7TVpfV0lORE9XU30udHN2IiBcCiAgICAtaW5fdHlwZSB0c3YgXAogICAgLW91dCAiJHtDT05TRU5TVVN9XyR7TVpfV0lORE9XU30uVHJhTUwiIFwKICAgIC1vdXRfdHlwZSBUcmFNTApgYGAKCmBgYHtyIHNsZWVwMTEsIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgQWRkIGRlY295cyB0byB0aGUgVHJhTUwKCmBgYHtiYXNoX3J1bnIgZGVjb3lfdHJhbWx9CmVjaG8gIkFkZGluZyBkZWNveXMgYW5kIG9wdGltaXppbmcgdGhlIHNwZWN0cmFsIGxpYnJhcmllcy4iCnJtIC1mICIke0NPTlNFTlNVU31fJHtNWl9XSU5ET1dTfV9kZWNveS5UcmFNTCIKZWNobyAiR2VuZXJhdGluZyBkZWNveXMgZm9yICR7Q09OU0VOU1VTfV8ke01aX1dJTkRPV1N9IgplY2hvICJPcHRpbWl6aW5nIHRoZSBjb25zZW5zdXMgbGlicmFyeS4iCmVjaG8gIlRoZSBpbnB1dCBpczogJHtDT05TRU5TVVNfVFJBTUx9IgplY2hvICJUaGUgb3V0cHV0IGlzOiAke09QVElNSVpFRF9UUkFNTH0iCk9wZW5Td2F0aEFzc2F5R2VuZXJhdG9yIFwKICAgICAtaW4gIiR7Q09OU0VOU1VTX1RSQU1MfSIgXAogICAgIC1vdXQgIiR7T1BUSU1JWkVEX1RSQU1MfSIgXAogICAgIC1zd2F0aF93aW5kb3dzX2ZpbGUgIndpbmRvd3Mvb3BlbnN3YXRoXyR7TVpfV0lORE9XU30udHh0IiBcCiAgICAgLWVuYWJsZV9pcGYgXAogICAgIC11bmltb2RfZmlsZSAicGFyYW1ldGVycy91bmltb2QueG1sIiBcCiAgICAgMj4+IiR7T1BUSU1JWkVEX1RSQU1MfS5sb2ciIDE+JjIKdGFpbCAiJHtPUFRJTUlaRURfVFJBTUx9LmxvZyIKCmVjaG8gIkFkZGluZyBkZWNveXMuIgplY2hvICJUaGUgaW5wdXQgaXM6ICR7T1BUSU1JWkVEX1RSQU1MfSIKZWNobyAiVGhlIG91dHB1dCBpczogJHtERUNPWV9UUkFNTH0iCk9wZW5Td2F0aERlY295R2VuZXJhdG9yIFwKICAgIC1pbiAiJHtPUFRJTUlaRURfVFJBTUx9IiBcCiAgICAtb3V0ICIke0RFQ09ZX1RSQU1MfSIgXAogICAgLWRlY295X3RhZyAiJHtERUNPWV9TVFJJTkd9IiBcCiAgICAtbWV0aG9kIHNodWZmbGUgXAogICAgMj4+IiR7REVDT1lfVFJBTUx9LmxvZyIgMT4mMgp0YWlsICIke0RFQ09ZX1RSQU1MfS5sb2ciCmdyZXAgIiR7VEVTVH0iICIke0NPTlNFTlNVU31fJHtNWl9XSU5ET1dTfV9kZWNveS5UcmFNTCIgfCBoZWFkCmBgYAoKYGBge3Igc2xlZXAxMiwgaW5jbHVkZT1GQUxTRX0KU3lzLnNsZWVwKDEpCmBgYAoKIyBDb252ZXJ0IGJhY2sgdG8gdHN2L3BxcAoKYGBge2Jhc2hfcnVuciBjb252ZXJ0X2JhY2t9CmVjaG8gIkNvbnZlcnRpbmcgZGVjb3ktYWRkZWQgbGlicmFyaWVzIGJhY2sgdG8gdHN2IGZvciBleGFtaW5hdGlvbiBsYXRlci4iCnJtIC1mICIke0NPTlNFTlNVU31fJHtNWl9XSU5ET1dTfV9kZWNveS50c3YiCmVjaG8gIlRoZSBpbnB1dCBpczogJHtERUNPWV9UUkFNTH0iCmVjaG8gIlRoZSBvdXRwdXQgaXM6ICR7VFJBTlNJVElPTl9QUkVGSVh9LnRzdiIKVGFyZ2V0ZWRGaWxlQ29udmVydGVyIFwKICAgIC1pbiAiJHtERUNPWV9UUkFNTH0iIFwKICAgIC1pbl90eXBlIFRyYU1MIFwKICAgIC1vdXQgIiR7VFJBTlNJVElPTl9QUkVGSVh9LnRzdiIgXAogICAgLW91dF90eXBlIHRzdgoKZWNobyAiQ29udmVydGluZyBsaWJyYXJpZXMgd2l0aCBkZWNveXMgZm9yICR7VFJBTlNJVElPTl9QUkVGSVh9IHRvIHBxcC4iCmVjaG8gIlRoZSBpbnB1dCBpczogJHtERUNPWV9UUkFNTH0iCmVjaG8gIlRoZSBvdXRwdXQgaXM6ICR7VFJBTlNJVElPTl9QUkVGSVh9LnBxcCIKVGFyZ2V0ZWRGaWxlQ29udmVydGVyIFwKICAgIC1pbiAiJHtUUkFOU0lUSU9OX1BSRUZJWH0udHN2IiBcCiAgICAtaW5fdHlwZSB0c3YgXAogICAgLW91dF90eXBlIHBxcCBcCiAgICAtb3V0ICIke1RSQU5TSVRJT05fUFJFRklYfS5wcXAiCmVjaG8gIlRyYW5zaXRpb24gbGlicmFyeSBmb3Igb3BlbnN3YXRod29ya2Zsb3cgaXM6ICR7VFJBTlNJVElPTl9QUkVGSVh9LnBxcCIKZ3JlcCAiJHtURVNUfSIgIiR7VFJBTlNJVElPTl9QUkVGSVh9LnRzdiIgfCBoZWFkCmdyZXAgLWMgIiR7REVDT1lfU1RSSU5HfSIgIiR7VFJBTlNJVElPTl9QUkVGSVh9LnRzdiIKYGBgCgpgYGB7ciBzbGVlcDEzLCBpbmNsdWRlPUZBTFNFfQpTeXMuc2xlZXAoMSkKYGBgCgojIE9wZW5Td2F0aFdvcmtmbG93IGFnYWluc3Qgb3VyIGV4cGVyaW1lbnRhbCB0cmFuc2l0aW9ucwoKYGBge2Jhc2hfcnVuciBvcGVuc3dhdGhfb3VyfQplY2hvICJJbnZva2luZyB0aGUgT3BlblN3YXRoV29ya2Zsb3cuIgplY2hvICJDaGVja2luZyBpbiwgdGhlIHRyYW5zaXRpb24gbGlicmFyeSBpczogJHtUUkFOU0lUSU9OX1BSRUZJWH0ucHFwIgpzd2F0aF9pbnB1dHM9JCgvYmluL2xzICJtelhNTC9kaWFfJHtWRVJTSU9OfSIpCmVjaG8gIkNoZWNraW5nIGluLCB0aGUgaW5wdXRzIGFyZTogJHtTV0FUSF9JTlBVVFN9Igpta2RpciAtcCAiJHtTV0FUSF9PVVRESVJ9Igpmb3IgaW5wdXQgaW4gJHtzd2F0aF9pbnB1dHN9CmRvCiAgICBpbl9tenhtbD0ibXpYTUwvZGlhXyR7VkVSU0lPTn0vJHtpbnB1dH0iCiAgICBuYW1lPSQoYmFzZW5hbWUgIiR7aW5wdXR9IiAubXpYTUwpCiAgICBlY2hvICJTdGFydGluZyBvcGVuc3dhdGggcnVuIG9mICR7bmFtZX0gdXNpbmcgJHtNWl9XSU5ET1dTfSB3aW5kb3dzIGF0ICQoZGF0ZSkuIgogICAgc3dhdGhfb3V0cHV0X3ByZWZpeD0iJHtTV0FUSF9PVVRESVJ9LyR7bmFtZX1fdnNfJHtWRVJTSU9OfV8ke1RZUEV9XyR7RERBX01FVEhPRH1fZGlhIgogICAgZWNobyAiRGVsZXRpbmcgcHJldmlvdXMgc3dhdGggb3V0cHV0IGZpbGU6ICR7U1dBVEhfT1VUUFVUX1BSRUZJWH0ub3N3IgogICAgcm0gLWYgIiR7U1dBVEhfT1VUUFVUX1BSRUZJWH0ub3N3IgogICAgT3BlblN3YXRoV29ya2Zsb3cgXAogICAgICAgIC1pbmkgInBhcmFtZXRlcnMvb3Blbm1zXyR7VkVSU0lPTn0uaW5pIiBcCiAgICAgICAgLWluICIke2luX216eG1sfSIgXAogICAgICAgIC1zd2F0aF93aW5kb3dzX2ZpbGUgIndpbmRvd3Mvb3BlbnN3YXRoXyR7bmFtZX0udHh0IiBcCiAgICAgICAgLXRyICIke1RSQU5TSVRPTl9QUkVGSVh9LnBxcCIgXAogICAgICAgIC1vdXRfb3N3ICIke3N3YXRoX291dHB1dF9wcmVmaXh9Lm9zdyIgXAogICAgICAgIDI+IiR7c3dhdGhfb3V0cHV0X3ByZWZpeH1fb3N3LmxvZyIgMT4mMgoKICAgIGVjaG8gIlNjb3JpbmcgaW5kaXZpZHVhbCBzd2F0aCBydW46ICR7c3dhdGhfb3V0cHV0X3ByZWZpeH0iCiAgICBweXByb3BoZXQgXAogICAgICAgIHNjb3JlIFwKICAgICAgICAtLWxldmVsIG1zMSBcCiAgICAgICAgLS1pbiAiJHtzd2F0aF9vdXRwdXRfcHJlZml4fS5vc3ciIFwKICAgICAgICAyPj4iJHtzd2F0aF9vdXRwdXRfcHJlZml4fV9weXByb3BoZXRfbXMxLmxvZyIgMT4mMgoKICAgIHB5cHJvcGhldCBcCiAgICAgICAgc2NvcmUgXAogICAgICAgIC0tbGV2ZWwgbXMyIFwKICAgICAgICAtLWluICIke3N3YXRoX291dHB1dF9wcmVmaXh9Lm9zdyIgXAogICAgICAgIC0tb3V0ICIke3N3YXRoX291dHB1dF9wcmVmaXh9X3Njb3JlZC5vc3ciIFwKICAgICAgICAyPj4iJHtzd2F0aF9vdXRwdXRfcHJlZml4fV9weXByb3BoZXRfbXMyLmxvZyIgMT4mMgoKICAgIHB5cHJvcGhldCBcCiAgICAgICAgcHJvdGVpbiBcCiAgICAgICAgLS1pbiAiJHtzd2F0aF9vdXRwdXRfcHJlZml4fV9zY29yZWQub3N3IiBcCiAgICAgICAgLS1jb250ZXh0IHJ1bi1zcGVjaWZpYyBcCiAgICAgICAgMj4+IiR7c3dhdGhfb3V0cHV0X3ByZWZpeH1fcHlwcm9waGV0X3Byb3RlaW4ubG9nIiAxPiYyCgogICAgZWNobyAiRXhwb3J0aW5nIGluZGl2aWR1YWwgc3dhdGggcnVuOiB0byAke3N3YXRoX291dHB1dF9wcmVmaXh9LnRzdiIKICAgIHB5cHJvcGhldCBcCiAgICAgICAgZXhwb3J0IFwKICAgICAgICAtLWluICIke3N3YXRoX291dHB1dF9wcmVmaXh9X3Njb3JlZC5vc3ciIFwKICAgICAgICAtLW91dCAiJHtzd2F0aF9vdXRwdXRfcHJlZml4fV9zY29yZWQudHN2IiBcCiAgICAgICAgMj4+IiR7c3dhdGhfb3V0cHV0X3ByZWZpeH1fcHlwcm9waGV0X2V4cG9ydC5sb2ciIDE+JjIKZG9uZQpgYGAKCmBgYHtyIHNsZWVwMTQsIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgT3BlblN3YXRoV29ya2Zsb3cgYWdhaW5zdCBvdXIgdGhlIFR1YmVyY3VsaXN0IHRyYW5zaXRpb25zCgpgYGB7YmFzaF9ydW5yIG9wZW5zd2F0aF90dWJlcmN1bGlzdH0KZWNobyAiSW52b2tpbmcgdGhlIE9wZW5Td2F0aFdvcmtmbG93IHVzaW5nIHRoZSB0dWJlcmN1bGlzdCB0cmFuc2l0aW9ucy4iCnN3YXRoX2lucHV0cz0kKC9iaW4vbHMgIm16WE1ML2RpYV8ke1ZFUlNJT059IikKZWNobyAiQ2hlY2tpbmcgaW4sIHRoZSBpbnB1dHMgYXJlOiAke3N3YXRoX2lucHV0c30iCm1rZGlyIC1wICIke1RVQkVSQ1VMSVNUX09VVERJUn0iCmZvciBpbnB1dCBpbiAke3N3YXRoX2lucHV0c30KZG8KICAgIGluX216eG1sPSJtelhNTC9kaWFfJHtWRVJTSU9OfS8ke2lucHV0fSIKICAgIG5hbWU9JChiYXNlbmFtZSAiJHtpbnB1dH0iIC5telhNTCkKICAgIGVjaG8gIlN0YXJ0aW5nIG9wZW5zd2F0aCBydW4gb2YgJHtuYW1lfSB1c2luZyAke01aX1dJTkRPV1N9IHdpbmRvd3MgYXQgJChkYXRlKS4iCiAgICB0Yl9vdXRwdXRfcHJlZml4PSIke1RVQkVSQ1VMSVNUX09VVERJUn0vJHtuYW1lfV92c18ke1ZFUlNJT059XyR7VFlQRX1fJHtEREFfTUVUSE9EfV9kaWEiCiAgICBlY2hvICJEZWxldGluZyBwcmV2aW91cyBzd2F0aCBvdXRwdXQgZmlsZTogJHt0Yl9vdXRwdXRfcHJlZml4fS5vc3ciCiAgICBybSAtZiAiJHt0Yl9vdXRwdXRfcHJlZml4fS5vc3ciCiAgICBPcGVuU3dhdGhXb3JrZmxvdyBcCiAgICAgICAgLWluaSAicGFyYW1ldGVycy9vcGVubXNfJHtWRVJTSU9OfS5pbmkiIFwKICAgICAgICAtaW4gIiR7aW5fbXp4bWx9IiBcCiAgICAgICAgLXN3YXRoX3dpbmRvd3NfZmlsZSAid2luZG93cy9vcGVuc3dhdGhfJHtuYW1lfS50eHQiIFwKICAgICAgICAtdHIgIiR7VFVCRVJDVUxJU1RfUFFQfSIgXAogICAgICAgIC1vdXRfb3N3ICIke3RiX291dHB1dF9wcmVmaXh9Lm9zdyIgXAogICAgICAgIDI+IiR7dGJfb3V0cHV0X3ByZWZpeH1fb3N3LmxvZyIgMT4mMgoKICAgIGVjaG8gIlNjb3JpbmcgaW5kaXZpZHVhbCBzd2F0aCBydW46ICR7dGJfb3V0cHV0X3ByZWZpeH0iCiAgICBweXByb3BoZXQgXAogICAgICAgIHNjb3JlIFwKICAgICAgICAtLWxldmVsIG1zMSBcCiAgICAgICAgLS1pbiAiJHt0Yl9vdXRwdXRfcHJlZml4fS5vc3ciIFwKICAgICAgICAyPj4iJHt0Yl9vdXRwdXRfcHJlZml4fV9weXByb3BoZXRfbXMxLmxvZyIgMT4mMgoKICAgIHB5cHJvcGhldCBcCiAgICAgICAgc2NvcmUgXAogICAgICAgIC0tbGV2ZWwgbXMyIFwKICAgICAgICAtLWluICIke3RiX291dHB1dF9wcmVmaXh9Lm9zdyIgXAogICAgICAgIC0tb3V0ICIke3RiX291dHB1dF9wcmVmaXh9X3Njb3JlZC5vc3ciIFwKICAgICAgICAyPj4iJHt0Yl9vdXRwdXRfcHJlZml4fV9weXByb3BoZXRfbXMyLmxvZyIgMT4mMgoKICAgIHB5cHJvcGhldCBcCiAgICAgICAgcHJvdGVpbiBcCiAgICAgICAgLS1pbiAiJHt0Yl9vdXRwdXRfcHJlZml4fV9zY29yZWQub3N3IiBcCiAgICAgICAgLS1jb250ZXh0IHJ1bi1zcGVjaWZpYyBcCiAgICAgICAgMj4+IiR7dGJfb3V0cHV0X3ByZWZpeH1fcHlwcm9waGV0X3Byb3RlaW4ubG9nIiAxPiYyCgogICAgZWNobyAiRXhwb3J0aW5nIGluZGl2aWR1YWwgc3dhdGggcnVuOiB0byAke3RiX291dHB1dF9wcmVmaXh9LnRzdiIKICAgIHB5cHJvcGhldCBcCiAgICAgICAgZXhwb3J0IFwKICAgICAgICAtLWluICIke3RiX291dHB1dF9wcmVmaXh9X3Njb3JlZC5vc3ciIFwKICAgICAgICAtLW91dCAiJHt0Yl9vdXRwdXRfcHJlZml4fV9zY29yZWQudHN2IiBcCiAgICAgICAgMj4+IiR7dGJfb3V0cHV0X3ByZWZpeH1fcHlwcm9waGV0X2V4cG9ydC5sb2ciIDE+JjIKZG9uZQpgYGAKCmBgYHtyIHNsZWVwMTUsIGluY2x1ZGU9RkFMU0V9ClN5cy5zbGVlcCgxKQpgYGAKCiMgTWVyZ2luZyBvdXIgZGF0YSB3aXRoIFRSSUMKCmBgYHtiYXNoX3J1bnJ9CmZlYXR1cmVfYWxpZ25tZW50LnB5IFwKICAgIC0tZm9yY2UgXAogICAgLS1pbiAiLi8ke1NXQVRIX09VVERJUn0vIioudHN2IFwKICAgIC0tb3V0ICIke1RSSUNfT1VURElSfS8ke1NFQVJDSF9NRVRIT0R9XyR7RERBX01FVEhPRH0udHN2IiBcCiAgICAtLW91dF9tYXRyaXggIiR7VFJJQ19PVVRESVJ9LyR7RERBX01FVEhPRH1fb3V0bWF0cml4LnRzdiIgXAogICAgLS1vdXRfbWV0YSAiJHtUUklDX09VVERJUn0vJHtEREFfTUVUSE9EfV9tZXRhLnRzdiIKZWNobyAiV3JvdGUgZmluYWwgb3V0cHV0IHRvICR7VFJJQ19PVVRESVJ9LyR7U0VBUkNIX01FVEhPRH1fJHtEREFfTUVUSE9EfS50c3YiCmBgYAoKYGBge3Igc2xlZXAxNiwgaW5jbHVkZT1GQUxTRX0KU3lzLnNsZWVwKDEpCmBgYAoKIyBNZXJnaW5nIHRoZSBUdWJlcmN1bGlzdC1kZXJpdmVkIGRhdGEgd2l0aCBUUklDCgpgYGB7YmFzaF9ydW5yfQp0cmljX3RiPSIke1RSSUNfT1VURElSfV90YiIKZmVhdHVyZV9hbGlnbm1lbnQucHkgXAogICAgLS1mb3JjZSBcCiAgICAtLWluICIuLyR7U1dBVEhfT1VURElSfS8iKi50c3YgXAogICAgLS1vdXQgIiR7dHJpY190Yn0vJHtTRUFSQ0hfTUVUSE9EfV8ke0REQV9NRVRIT0R9LnRzdiIgXAogICAgLS1vdXRfbWF0cml4ICIke3RyaWNfdGJ9LyR7RERBX01FVEhPRH1fb3V0bWF0cml4LnRzdiIgXAogICAgLS1vdXRfbWV0YSAiJHt0cmljX3RifS8ke0REQV9NRVRIT0R9X21ldGEudHN2IgplY2hvICJXcm90ZSBmaW5hbCBvdXRwdXQgdG8gJHt0cmljX3RifS8ke1NFQVJDSF9NRVRIT0R9XyR7RERBX01FVEhPRH0udHN2IgpgYGAKCiMgSW5kZXggdmVyc2lvbjogYHIgdmVyYAoKIyBUT0RPCgoqIDIwMTctMDYtMTQ6CgpgYGB7ciBzYXZlbWV9CmlmICghaXNUUlVFKGdldDAoInNraXBfbG9hZCIpKSkgewogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIHRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXJtZF9maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpCiAgbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCB0aGlzX3NhdmUpKQogIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQp9CmIkc3RvcCgpCmBgYAo=