The purpose of this notebook is to account for broader copy number changes.
Set up
Libraries and functions
library(tidyverse)
Registered S3 method overwritten by 'dplyr':
method from
print.rowwise_df
[37m── [1mAttaching packages[22m ─────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──[39m
[37m[32m✔[37m [34mggplot2[37m 3.2.0 [32m✔[37m [34mpurrr [37m 0.3.2
[32m✔[37m [34mtibble [37m 2.1.3 [32m✔[37m [34mdplyr [37m 0.8.3
[32m✔[37m [34mtidyr [37m 0.8.3 [32m✔[37m [34mstringr[37m 1.4.0
[32m✔[37m [34mreadr [37m 1.3.1 [32m✔[37m [34mforcats[37m 0.4.0[39m
[37m── [1mConflicts[22m ────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
[31m✖[37m [34mdplyr[37m::[32mfilter()[37m masks [34mstats[37m::filter()
[31m✖[37m [34mdplyr[37m::[32mlag()[37m masks [34mstats[37m::lag()[39m
Directories
# Detect the ".git" folder -- this will in the project root directory.
# Use this as the root directory to ensure proper sourcing of functions no
# matter where this is called from
root_dir <- rprojroot::find_root(rprojroot::has_dir(".git"))
# Set path to results directory
results_dir <-
file.path(root_dir, "analyses", "focal-cn-file-preparation", "results")
if (!dir.exists(results_dir)) {
dir.create(results_dir)
}
Output files
all_status_df_file <- file.path(
results_dir,
"consensus_autosomes_with_arm_and_cytoband_values.tsv.gz"
)
long_regions_df_file <- file.path(
results_dir,
"consensus_autosomes_largest_region_tidy.tsv.gz"
)
Get a mapping between gene symbols and cytobands
In 03-prepare-cn-file.R, we used the org.Hs.eg.db package to map between the Ensembl gene identifiers and cytobands. We’ll extract cytobands that contain any Entrez IDs and then use those Entrez IDs to get gene symbols. We can also potentially use the cytoband data from UCSC, but it was generally in agreement with the cytoband data from this package.
Here’s a quote from an earlier version of this module:
The decision to implement the UCSC hg38 cytoband file was made based on a comparison done between the cytoband calls in the org.Hs.eg.db package and the calls in the UCSC file. We found that they disagreed in ~11,800 calls out of ~800,000 and the UCSC file contains more cytoband calls.
# These steps are taken from the org.Hs.eg.db reference manual
band_object <- org.Hs.eg.db::org.Hs.egMAP2EG
# Get the cytobands that are mapped to any entrez gene id
mapped_bands <- AnnotationDbi::mappedkeys(band_object)
# Convert to a list
mapped_band_list <- as.list(band_object[mapped_bands])
# Make a data.frame that contains the cytoband to gene symbol mapping
mapped_band_df <- reshape2::melt(mapped_band_list)
colnames(mapped_band_df) <- c("entrez_id", "cytoband")
mapped_band_df <- mapped_band_df %>%
# The entrez_id column is a factor, mapIds need a character
mutate(entrez_id = as.character(entrez_id)) %>%
# We're using the default behavior for mapIds
# "only the 1st thing that comes back will be returned"
# https://www.rdocumentation.org/packages/AnnotationDbi/versions/1.30.1/topics/AnnotationDb-objects
mutate(gene_symbol = AnnotationDbi::mapIds(org.Hs.eg.db::org.Hs.eg.db,
keys = entrez_id,
column = "SYMBOL",
keytype = "ENTREZID")) %>%
# drop the Entrez IDs
select(-entrez_id)
'select()' returned 1:1 mapping between keys and columns
# remove the unneeded objects
rm(band_object, mapped_bands, mapped_band_list)
GISTIC
Read in GISTIC chromosome arm file
# We are using the consensus GISTIC results! Advanced access!
# TODO: use the version included in the data download
# Path to gistic results directory
gistic_results <- file.path(root_dir,
"analyses",
"focal-cn-file-preparation",
"gistic-results",
"2019-01-28-consensus-cnv")
gistic_arm_file <- file.path(gistic_results, "broad_values_by_arm.txt")
# Read in broad values by arm GISTIC output file
gistic_arm_df <- data.table::fread(gistic_arm_file, data.table = FALSE)
Registered S3 method overwritten by 'data.table':
method from
print.data.table
tidy_gistic_arm_df <- gistic_arm_df %>%
column_to_rownames("Chromosome Arm") %>%
t() %>%
as.data.frame() %>%
rownames_to_column("Kids_First_Biospecimen_ID") %>%
reshape2::melt(variable.name = "chromosome_arm",
value.name = "gistic_arm_value") %>%
mutate(gistic_arm_status = case_when(
gistic_arm_value < 0 ~ "loss",
gistic_arm_value > 0 ~ "gain",
TRUE ~ "neutral"
))
Using Kids_First_Biospecimen_ID as id variables
–>
Tidy the GISTIC arm data
The GISTIC arm data contains chromosome arms in the first column and all other columns correspond to a WGS biospecimen identifier. We want to get this into long format.
autosomes_file <- file.path(results_dir,
"consensus_seg_annotated_cn_autosomes.tsv.gz")
annotated_autosomes_df <- read_tsv(autosomes_file)
Parsed with column specification:
cols(
biospecimen_id = [31mcol_character()[39m,
status = [31mcol_character()[39m,
copy_number = [32mcol_double()[39m,
ploidy = [32mcol_double()[39m,
ensembl = [31mcol_character()[39m,
gene_symbol = [31mcol_character()[39m,
cytoband = [31mcol_character()[39m
)
There are no sex chromosome values in this version of the GISTIC file.
Annotated consensus copy number data
# Add a column that tells us the position of the p or q and then use this to
# split the cytoband column
annotated_autosomes_df <- annotated_autosomes_df %>%
add_column(arm_position = str_locate(annotated_autosomes_df$cytoband,
"p|q")[[1]]) %>%
mutate(annotated_arm = str_sub(cytoband, 1, arm_position)) %>%
select(-arm_position)
Create an arm column using the cytoband column
seg_gistic_df <- annotated_autosomes_df %>%
left_join(tidy_gistic_arm_df, by = c("biospecimen_id" = "Kids_First_Biospecimen_ID",
"annotated_arm" = "chromosome_arm"))
Column `annotated_arm`/`chromosome_arm` joining character vector and factor, coercing into character vector
Join together GISTIC and annotated SEG file
# add a column to the data.frame that contains the mapping between the cytoband
# and gene symbol that counts how many symbols are mapped to that cytoband
symbols_per_cytoband <- mapped_band_df %>%
group_by(cytoband) %>%
tally(name = "num_symbol")
What about cytoband status?
If the majority of the gene symbols in a cytoband are called as the same alteration, make that the cytoband status.
symbol_count_df <- seg_gistic_df %>%
group_by(biospecimen_id, cytoband, status) %>%
summarize(num_symbols_with_status = length(unique(gene_symbol))) %>%
left_join(symbols_per_cytoband) %>%
mutate(cytoband_proportion = (num_symbols_with_status / num_symbol))
Joining, by = "cytoband"
What proportion of the gene symbols in the cytoband are called as the same status?
seg_gistic_cytoband_df <- symbol_count_df %>%
ungroup() %>%
select(biospecimen_id, cytoband, status, cytoband_proportion) %>%
inner_join(seg_gistic_df) %>%
mutate(cytoband_status = case_when(
cytoband_proportion > 0.5 ~ status,
TRUE ~ "NA"
))
Joining, by = c("biospecimen_id", "cytoband", "status")
Add the cytoband proportion and status
seg_gistic_cytoband_df %>%
write_tsv(all_status_df_file)
Write to file.
seg_gistic_cytoband_df %>%
group_by(gistic_arm_status, cytoband_status) %>%
tally()
Do these statuses tend to agree?
arm_status_df <- seg_gistic_cytoband_df %>%
filter(gistic_arm_status != "neutral") %>%
select(Kids_First_Biospecimen_ID = biospecimen_id,
region = annotated_arm,
status = gistic_arm_status) %>%
distinct()
Make a long table with the “broadest regions” as status
An example – If chromosome 10p is lost, we don’t also want to call the 10p cytobands lost and the gene symbols in 10p as lost. Instead, label 10p a loss and filter out the smaller regions.
Non-neutral arm data
cytoband_status_df <- seg_gistic_cytoband_df %>%
filter(gistic_arm_status == "neutral",
cytoband_status != "NA") %>%
select(Kids_First_Biospecimen_ID = biospecimen_id,
region = cytoband,
status = cytoband_status) %>%
distinct()
Non-neutral cytoband data
For instances where the arm status is neutral, but there is cytoband status…
gene_status_df <- seg_gistic_cytoband_df %>%
filter(gistic_arm_status == "neutral",
cytoband_status == "NA") %>%
select(Kids_First_Biospecimen_ID = biospecimen_id,
region = gene_symbol,
status = status) %>%
distinct()
Gene-level data
Get the gene symbol for instances where the other two levels are neutral or NA.
long_status_df <- bind_rows(
arm_status_df,
cytoband_status_df,
gene_status_df
) %>%
write_tsv(long_regions_df_file)
Join all together and write to file
long_status_df <- bind_rows(
arm_status_df,
cytoband_status_df,
gene_status_df
) %>%
write_tsv(long_regions_df_file)
LS0tCnRpdGxlOiAiTWFwIHRvIGJyb2FkZXIgc2VnbWVudHM6IGN5dG9iYW5kcywgY2hyb21vc29tZSBhcm1zIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQphdXRob3I6IENoYW50ZSBCZXRoZWxsIGFuZCBKYWNseW4gVGFyb25pIGZvciBBTFNGIENDREwKZGF0ZTogMjAyMAotLS0KClRoZSBwdXJwb3NlIG9mIHRoaXMgbm90ZWJvb2sgaXMgdG8gYWNjb3VudCBmb3IgYnJvYWRlciBjb3B5IG51bWJlciBjaGFuZ2VzLgoKIyMgU2V0IHVwIAoKIyMjIExpYnJhcmllcyBhbmQgZnVuY3Rpb25zCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyMjIERpcmVjdG9yaWVzCgpgYGB7cn0KIyBEZXRlY3QgdGhlICIuZ2l0IiBmb2xkZXIgLS0gdGhpcyB3aWxsIGluIHRoZSBwcm9qZWN0IHJvb3QgZGlyZWN0b3J5LgojIFVzZSB0aGlzIGFzIHRoZSByb290IGRpcmVjdG9yeSB0byBlbnN1cmUgcHJvcGVyIHNvdXJjaW5nIG9mIGZ1bmN0aW9ucyBubwojIG1hdHRlciB3aGVyZSB0aGlzIGlzIGNhbGxlZCBmcm9tCnJvb3RfZGlyIDwtIHJwcm9qcm9vdDo6ZmluZF9yb290KHJwcm9qcm9vdDo6aGFzX2RpcigiLmdpdCIpKQoKIyBTZXQgcGF0aCB0byByZXN1bHRzIGRpcmVjdG9yeQpyZXN1bHRzX2RpciA8LQogIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwgImZvY2FsLWNuLWZpbGUtcHJlcGFyYXRpb24iLCAicmVzdWx0cyIpCmlmICghZGlyLmV4aXN0cyhyZXN1bHRzX2RpcikpIHsKICBkaXIuY3JlYXRlKHJlc3VsdHNfZGlyKQp9CmBgYAoKIyMjIE91dHB1dCBmaWxlcwoKYGBge3J9CmFsbF9zdGF0dXNfZGZfZmlsZSA8LSBmaWxlLnBhdGgoCiAgcmVzdWx0c19kaXIsCiAgImNvbnNlbnN1c19hdXRvc29tZXNfd2l0aF9hcm1fYW5kX2N5dG9iYW5kX3ZhbHVlcy50c3YuZ3oiCikKbG9uZ19yZWdpb25zX2RmX2ZpbGUgPC0gZmlsZS5wYXRoKAogIHJlc3VsdHNfZGlyLAogICJjb25zZW5zdXNfYXV0b3NvbWVzX2xhcmdlc3RfcmVnaW9uX3RpZHkudHN2Lmd6IgopCmBgYAoKIyMgR2V0IGEgbWFwcGluZyBiZXR3ZWVuIGdlbmUgc3ltYm9scyBhbmQgY3l0b2JhbmRzCgpJbiBgMDMtcHJlcGFyZS1jbi1maWxlLlJgLCB3ZSB1c2VkIHRoZSBgb3JnLkhzLmVnLmRiYCBwYWNrYWdlIHRvIG1hcCBiZXR3ZWVuIHRoZSBFbnNlbWJsIGdlbmUgaWRlbnRpZmllcnMgYW5kIGN5dG9iYW5kcy4KV2UnbGwgZXh0cmFjdCBjeXRvYmFuZHMgdGhhdCBjb250YWluIGFueSBFbnRyZXogSURzIGFuZCB0aGVuIHVzZSB0aG9zZSBFbnRyZXogSURzIHRvIGdldCBnZW5lIHN5bWJvbHMuCldlIGNhbiBhbHNvIHBvdGVudGlhbGx5IHVzZSB0aGUgY3l0b2JhbmQgZGF0YSBmcm9tIFVDU0MsIGJ1dCBpdCB3YXMgZ2VuZXJhbGx5IGluIGFncmVlbWVudCB3aXRoIHRoZSBjeXRvYmFuZCBkYXRhIGZyb20gdGhpcyBwYWNrYWdlLgoKSGVyZSdzIGEgcXVvdGUgW2Zyb20gYW4gZWFybGllciB2ZXJzaW9uIG9mIHRoaXMgbW9kdWxlXShodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuUEJUQS1hbmFseXNpcy9ibG9iL2I0YjUyMzAwYWRiYTk1YmI4MTVmNGU5ZmY5MjVkYThjNzQxNTk4ODkvYW5hbHlzZXMvZm9jYWwtY24tZmlsZS1wcmVwYXJhdGlvbi8wMS1wcmVwYXJlLWNuLWZpbGUuUiNMMjU3KToKCj4gVGhlIGRlY2lzaW9uIHRvIGltcGxlbWVudCB0aGUgVUNTQyBoZzM4IGN5dG9iYW5kIGZpbGUgd2FzIG1hZGUgYmFzZWQgb24gYSBjb21wYXJpc29uIGRvbmUgYmV0d2VlbiB0aGUgY3l0b2JhbmQgY2FsbHMgaW4gdGhlIGBvcmcuSHMuZWcuZGJgIHBhY2thZ2UgYW5kIHRoZSBjYWxscyBpbiB0aGUgVUNTQyBmaWxlLiBXZSBmb3VuZCB0aGF0IHRoZXkgZGlzYWdyZWVkIGluIH4xMSw4MDAgY2FsbHMgb3V0IG9mIH44MDAsMDAwIGFuZCB0aGUgYFVDU0MgZmlsZWAgY29udGFpbnMgbW9yZSBjeXRvYmFuZCBjYWxscy4KCmBgYHtyfQojIFRoZXNlIHN0ZXBzIGFyZSB0YWtlbiBmcm9tIHRoZSBvcmcuSHMuZWcuZGIgcmVmZXJlbmNlIG1hbnVhbApiYW5kX29iamVjdCA8LSBvcmcuSHMuZWcuZGI6Om9yZy5Icy5lZ01BUDJFRwojIEdldCB0aGUgY3l0b2JhbmRzIHRoYXQgYXJlIG1hcHBlZCB0byBhbnkgZW50cmV6IGdlbmUgaWQKbWFwcGVkX2JhbmRzIDwtIEFubm90YXRpb25EYmk6Om1hcHBlZGtleXMoYmFuZF9vYmplY3QpCiMgQ29udmVydCB0byBhIGxpc3QKbWFwcGVkX2JhbmRfbGlzdCA8LSBhcy5saXN0KGJhbmRfb2JqZWN0W21hcHBlZF9iYW5kc10pIAoKIyBNYWtlIGEgZGF0YS5mcmFtZSB0aGF0IGNvbnRhaW5zIHRoZSBjeXRvYmFuZCB0byBnZW5lIHN5bWJvbCBtYXBwaW5nCm1hcHBlZF9iYW5kX2RmIDwtIHJlc2hhcGUyOjptZWx0KG1hcHBlZF9iYW5kX2xpc3QpCmNvbG5hbWVzKG1hcHBlZF9iYW5kX2RmKSA8LSBjKCJlbnRyZXpfaWQiLCAiY3l0b2JhbmQiKQptYXBwZWRfYmFuZF9kZiA8LSBtYXBwZWRfYmFuZF9kZiAlPiUKICAjIFRoZSBlbnRyZXpfaWQgY29sdW1uIGlzIGEgZmFjdG9yLCBtYXBJZHMgbmVlZCBhIGNoYXJhY3RlcgogIG11dGF0ZShlbnRyZXpfaWQgPSBhcy5jaGFyYWN0ZXIoZW50cmV6X2lkKSkgJT4lCiAgIyBXZSdyZSB1c2luZyB0aGUgZGVmYXVsdCBiZWhhdmlvciBmb3IgbWFwSWRzIAogICMgIm9ubHkgdGhlIDFzdCB0aGluZyB0aGF0IGNvbWVzIGJhY2sgd2lsbCBiZSByZXR1cm5lZCIKICAjIGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9Bbm5vdGF0aW9uRGJpL3ZlcnNpb25zLzEuMzAuMS90b3BpY3MvQW5ub3RhdGlvbkRiLW9iamVjdHMKICBtdXRhdGUoZ2VuZV9zeW1ib2wgPSBBbm5vdGF0aW9uRGJpOjptYXBJZHMob3JnLkhzLmVnLmRiOjpvcmcuSHMuZWcuZGIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleXMgPSBlbnRyZXpfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbiA9ICJTWU1CT0wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXl0eXBlID0gIkVOVFJFWklEIikpICU+JQogICMgZHJvcCB0aGUgRW50cmV6IElEcwogIHNlbGVjdCgtZW50cmV6X2lkKQoKIyByZW1vdmUgdGhlIHVubmVlZGVkIG9iamVjdHMKcm0oYmFuZF9vYmplY3QsIG1hcHBlZF9iYW5kcywgbWFwcGVkX2JhbmRfbGlzdCkKYGBgCgojIyBHSVNUSUMKCiMjIyBSZWFkIGluIEdJU1RJQyBjaHJvbW9zb21lIGFybSBmaWxlCgpgYGB7cn0KIyBXZSBhcmUgdXNpbmcgdGhlIGNvbnNlbnN1cyBHSVNUSUMgcmVzdWx0cyEgQWR2YW5jZWQgYWNjZXNzIQojIFRPRE86IHVzZSB0aGUgdmVyc2lvbiBpbmNsdWRlZCBpbiB0aGUgZGF0YSBkb3dubG9hZAojIFBhdGggdG8gZ2lzdGljIHJlc3VsdHMgZGlyZWN0b3J5Cmdpc3RpY19yZXN1bHRzIDwtIGZpbGUucGF0aChyb290X2RpciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbmFseXNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZm9jYWwtY24tZmlsZS1wcmVwYXJhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ2lzdGljLXJlc3VsdHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTktMDEtMjgtY29uc2Vuc3VzLWNudiIpCgpnaXN0aWNfYXJtX2ZpbGUgPC0gZmlsZS5wYXRoKGdpc3RpY19yZXN1bHRzLCAiYnJvYWRfdmFsdWVzX2J5X2FybS50eHQiKQoKIyBSZWFkIGluIGJyb2FkIHZhbHVlcyBieSBhcm0gR0lTVElDIG91dHB1dCBmaWxlCmdpc3RpY19hcm1fZGYgPC0gZGF0YS50YWJsZTo6ZnJlYWQoZ2lzdGljX2FybV9maWxlLCBkYXRhLnRhYmxlID0gRkFMU0UpCmBgYAoKPCEtLVdoZW4gd2UgdXNlIHRoZSB2MTQrIEdJU1RJQyBkYXRhIGluY2x1ZGVkIGluIHRoZSBkYXRhIGRvd25sb2FkIHRoaXMgc2VjdGlvbiBpcyByZWxldmFudAoKYGBge3J9CiMgUGF0aCB0byBnaXN0aWMgemlwIGZpbGUgcmVzdWx0cwpnaXN0aWNfemlwIDwtCiAgZmlsZS5wYXRoKHJvb3RfZGlyLCAiZGF0YSIsICJwYnRhLWNudi1jbnZraXQtZ2lzdGljLnppcCIpCgojIEdldCB0aGUgbmFtZSBvZiB0aGUgZm9sZGVyIGZpcnN0IHNpbmNlIHRoaXMgY2hhbmdlcyB3aXRoIHVwZGF0ZXMgdG8gdGhlIGRhdGUKZm9sZGVyX25hbWUgPC0gdW56aXAoemlwZmlsZSA9IGdpc3RpY196aXAsIGxpc3QgPSBUUlVFKSAlPiUKICBkcGx5cjo6ZmlsdGVyKExlbmd0aCA9PSAwKSAlPiUKICBkcGx5cjo6cHVsbCgiTmFtZSIpCgojIFBhdGggdG8gZ2lzdGljIHJlc3VsdHMgZGlyZWN0b3J5Cmdpc3RpY19yZXN1bHRzIDwtCiAgZmlsZS5wYXRoKHJvb3RfZGlyLAogICAgICAgICAgICAiYW5hbHlzZXMiLAogICAgICAgICAgICAiZm9jYWwtY24tZmlsZS1wcmVwYXJhdGlvbiIsCiAgICAgICAgICAgICJnaXN0aWMtcmVzdWx0cyIpCgojIEV4dHJhY3QgZmlsZXMgaWYgaXQgaGFzbid0IGJlZW4gZG9uZSB5ZXQKaWYgKCFkaXIuZXhpc3RzKGdpc3RpY19yZXN1bHRzKSkgewogICMgVW56aXAgYnV0IG9ubHkgZXh0cmFjdCB0aGUgZmlsZXMgbm90IHRoZSBmb2xkZXIKICB1bnppcCh6aXBmaWxlID0gZ2lzdGljX3ppcCwKICAgICAgICBleGRpciA9IGdpc3RpY19yZXN1bHRzKQp9CiMgRGVzaWduYXRlIEdJU1RJQyByZXN1bHRzIGZvbGRlciB0byBleHRyYWN0IHRvCmdpc3RpY19yZXN1bHRzIDwtIGZpbGUucGF0aChnaXN0aWNfcmVzdWx0cywgZm9sZGVyX25hbWUpCgojIFJlYWQgaW4gYnJvYWQgdmFsdWVzIGJ5IGFybSBHSVNUSUMgb3V0cHV0IGZpbGUKZ2lzdGljX2RmIDwtCiAgZGF0YS50YWJsZTo6ZnJlYWQoCiAgICBwYXN0ZTAoCiAgICAgIGdpc3RpY19yZXN1bHRzLAogICAgICAiYnJvYWRfdmFsdWVzX2J5X2FybS50eHQiCiAgICApLAogICAgZGF0YS50YWJsZSA9IEZBTFNFCiAgKQpgYGAKLS0+CgojIyMgVGlkeSB0aGUgR0lTVElDIGFybSBkYXRhCgpUaGUgR0lTVElDIGFybSBkYXRhIGNvbnRhaW5zIGNocm9tb3NvbWUgYXJtcyBpbiB0aGUgZmlyc3QgY29sdW1uIGFuZCBhbGwgb3RoZXIgY29sdW1ucyBjb3JyZXNwb25kIHRvIGEgV0dTIGJpb3NwZWNpbWVuIGlkZW50aWZpZXIuCldlIHdhbnQgdG8gZ2V0IHRoaXMgaW50byBsb25nIGZvcm1hdC4KCmBgYHtyfQp0aWR5X2dpc3RpY19hcm1fZGYgPC0gZ2lzdGljX2FybV9kZiAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoIkNocm9tb3NvbWUgQXJtIikgJT4lCiAgdCgpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICByb3duYW1lc190b19jb2x1bW4oIktpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQiKSAlPiUKICByZXNoYXBlMjo6bWVsdCh2YXJpYWJsZS5uYW1lID0gImNocm9tb3NvbWVfYXJtIiwKICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gImdpc3RpY19hcm1fdmFsdWUiKSAlPiUKICBtdXRhdGUoZ2lzdGljX2FybV9zdGF0dXMgPSBjYXNlX3doZW4oCiAgICBnaXN0aWNfYXJtX3ZhbHVlIDwgMCB+ICJsb3NzIiwKICAgIGdpc3RpY19hcm1fdmFsdWUgPiAwIH4gImdhaW4iLAogICAgVFJVRSB+ICJuZXV0cmFsIgogICkpCmBgYAoKVGhlcmUgYXJlIG5vIHNleCBjaHJvbW9zb21lIHZhbHVlcyBpbiB0aGlzIHZlcnNpb24gb2YgdGhlIEdJU1RJQyBmaWxlLgoKIyMgQW5ub3RhdGVkIGNvbnNlbnN1cyBjb3B5IG51bWJlciBkYXRhCgpgYGB7cn0KYXV0b3NvbWVzX2ZpbGUgPC0gZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb25zZW5zdXNfc2VnX2Fubm90YXRlZF9jbl9hdXRvc29tZXMudHN2Lmd6IikKYW5ub3RhdGVkX2F1dG9zb21lc19kZiA8LSByZWFkX3RzdihhdXRvc29tZXNfZmlsZSkKYGBgCgpDcmVhdGUgYW4gYXJtIGNvbHVtbiB1c2luZyB0aGUgY3l0b2JhbmQgY29sdW1uCgpgYGB7cn0KIyBBZGQgYSBjb2x1bW4gdGhhdCB0ZWxscyB1cyB0aGUgcG9zaXRpb24gb2YgdGhlIHAgb3IgcSBhbmQgdGhlbiB1c2UgdGhpcyB0bwojIHNwbGl0IHRoZSBjeXRvYmFuZCBjb2x1bW4KYW5ub3RhdGVkX2F1dG9zb21lc19kZiA8LSBhbm5vdGF0ZWRfYXV0b3NvbWVzX2RmICU+JQogIGFkZF9jb2x1bW4oYXJtX3Bvc2l0aW9uID0gc3RyX2xvY2F0ZShhbm5vdGF0ZWRfYXV0b3NvbWVzX2RmJGN5dG9iYW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB8cSIpW1sxXV0pICU+JQogIG11dGF0ZShhbm5vdGF0ZWRfYXJtID0gc3RyX3N1YihjeXRvYmFuZCwgMSwgYXJtX3Bvc2l0aW9uKSkgJT4lCiAgc2VsZWN0KC1hcm1fcG9zaXRpb24pCmBgYAoKIyMjIEpvaW4gdG9nZXRoZXIgR0lTVElDIGFuZCBhbm5vdGF0ZWQgU0VHIGZpbGUKCmBgYHtyfQpzZWdfZ2lzdGljX2RmIDwtIGFubm90YXRlZF9hdXRvc29tZXNfZGYgJT4lCiAgbGVmdF9qb2luKHRpZHlfZ2lzdGljX2FybV9kZiwgYnkgPSBjKCJiaW9zcGVjaW1lbl9pZCIgPSAiS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbm5vdGF0ZWRfYXJtIiA9ICJjaHJvbW9zb21lX2FybSIpKQpgYGAKCiMjIFdoYXQgYWJvdXQgY3l0b2JhbmQgc3RhdHVzPwoKSWYgdGhlIG1ham9yaXR5IG9mIHRoZSBnZW5lIHN5bWJvbHMgaW4gYSBjeXRvYmFuZCBhcmUgY2FsbGVkIGFzIHRoZSBzYW1lIGFsdGVyYXRpb24sIG1ha2UgdGhhdCB0aGUgY3l0b2JhbmQgc3RhdHVzLgoKYGBge3J9CiMgYWRkIGEgY29sdW1uIHRvIHRoZSBkYXRhLmZyYW1lIHRoYXQgY29udGFpbnMgdGhlIG1hcHBpbmcgYmV0d2VlbiB0aGUgY3l0b2JhbmQKIyBhbmQgZ2VuZSBzeW1ib2wgdGhhdCBjb3VudHMgaG93IG1hbnkgc3ltYm9scyBhcmUgbWFwcGVkIHRvIHRoYXQgY3l0b2JhbmQKc3ltYm9sc19wZXJfY3l0b2JhbmQgPC0gbWFwcGVkX2JhbmRfZGYgJT4lCiAgZ3JvdXBfYnkoY3l0b2JhbmQpICU+JQogIHRhbGx5KG5hbWUgPSAibnVtX3N5bWJvbCIpCmBgYAoKV2hhdCBwcm9wb3J0aW9uIG9mIHRoZSBnZW5lIHN5bWJvbHMgaW4gdGhlIGN5dG9iYW5kIGFyZSBjYWxsZWQgYXMgdGhlIHNhbWUgc3RhdHVzPwoKYGBge3J9CnN5bWJvbF9jb3VudF9kZiA8LSBzZWdfZ2lzdGljX2RmICU+JQogIGdyb3VwX2J5KGJpb3NwZWNpbWVuX2lkLCBjeXRvYmFuZCwgc3RhdHVzKSAlPiUKICBzdW1tYXJpemUobnVtX3N5bWJvbHNfd2l0aF9zdGF0dXMgPSBsZW5ndGgodW5pcXVlKGdlbmVfc3ltYm9sKSkpICU+JQogIGxlZnRfam9pbihzeW1ib2xzX3Blcl9jeXRvYmFuZCkgJT4lCiAgbXV0YXRlKGN5dG9iYW5kX3Byb3BvcnRpb24gPSAobnVtX3N5bWJvbHNfd2l0aF9zdGF0dXMgLyBudW1fc3ltYm9sKSkKYGBgCgojIyMgQWRkIHRoZSBjeXRvYmFuZCBwcm9wb3J0aW9uIGFuZCBzdGF0dXMKCmBgYHtyfQpzZWdfZ2lzdGljX2N5dG9iYW5kX2RmIDwtIHN5bWJvbF9jb3VudF9kZiAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGJpb3NwZWNpbWVuX2lkLCBjeXRvYmFuZCwgc3RhdHVzLCBjeXRvYmFuZF9wcm9wb3J0aW9uKSAlPiUKICBpbm5lcl9qb2luKHNlZ19naXN0aWNfZGYpICU+JQogIG11dGF0ZShjeXRvYmFuZF9zdGF0dXMgPSBjYXNlX3doZW4oCiAgICBjeXRvYmFuZF9wcm9wb3J0aW9uID4gMC41IH4gc3RhdHVzLAogICAgVFJVRSB+ICJOQSIKICApKSAKYGBgCgpXcml0ZSB0byBmaWxlLgoKYGBge3J9CnNlZ19naXN0aWNfY3l0b2JhbmRfZGYgJT4lCiAgd3JpdGVfdHN2KGFsbF9zdGF0dXNfZGZfZmlsZSkKYGBgCgpEbyB0aGVzZSBzdGF0dXNlcyB0ZW5kIHRvIGFncmVlPwoKYGBge3J9CnNlZ19naXN0aWNfY3l0b2JhbmRfZGYgJT4lCiAgZ3JvdXBfYnkoZ2lzdGljX2FybV9zdGF0dXMsIGN5dG9iYW5kX3N0YXR1cykgJT4lCiAgdGFsbHkoKQpgYGAKCiMjIE1ha2UgYSBsb25nIHRhYmxlIHdpdGggdGhlICJicm9hZGVzdCByZWdpb25zIiBhcyBzdGF0dXMKCkFuIGV4YW1wbGUgLS0gSWYgY2hyb21vc29tZSAxMHAgaXMgbG9zdCwgd2UgZG9uJ3QgYWxzbyB3YW50IHRvIGNhbGwgdGhlIDEwcCBjeXRvYmFuZHMgbG9zdCBhbmQgdGhlIGdlbmUgc3ltYm9scyBpbiAxMHAgYXMgbG9zdC4KSW5zdGVhZCwgbGFiZWwgMTBwIGEgbG9zcyBhbmQgZmlsdGVyIG91dCB0aGUgc21hbGxlciByZWdpb25zLgoKIyMjIE5vbi1uZXV0cmFsIGFybSBkYXRhCgpgYGB7cn0KYXJtX3N0YXR1c19kZiA8LSBzZWdfZ2lzdGljX2N5dG9iYW5kX2RmICU+JQogIGZpbHRlcihnaXN0aWNfYXJtX3N0YXR1cyAhPSAibmV1dHJhbCIpICU+JQogIHNlbGVjdChLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEID0gYmlvc3BlY2ltZW5faWQsCiAgICAgICAgIHJlZ2lvbiA9IGFubm90YXRlZF9hcm0sCiAgICAgICAgIHN0YXR1cyA9IGdpc3RpY19hcm1fc3RhdHVzKSAlPiUKICBkaXN0aW5jdCgpCmBgYAoKIyMjIE5vbi1uZXV0cmFsIGN5dG9iYW5kIGRhdGEKCkZvciBpbnN0YW5jZXMgd2hlcmUgdGhlIGFybSBzdGF0dXMgaXMgbmV1dHJhbCwgYnV0IHRoZXJlICppcyogY3l0b2JhbmQgc3RhdHVzLi4uCgpgYGB7cn0KY3l0b2JhbmRfc3RhdHVzX2RmIDwtIHNlZ19naXN0aWNfY3l0b2JhbmRfZGYgJT4lCiAgZmlsdGVyKGdpc3RpY19hcm1fc3RhdHVzID09ICJuZXV0cmFsIiwKICAgICAgICAgY3l0b2JhbmRfc3RhdHVzICE9ICJOQSIpICU+JQogIHNlbGVjdChLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEID0gYmlvc3BlY2ltZW5faWQsCiAgICAgICAgIHJlZ2lvbiA9IGN5dG9iYW5kLAogICAgICAgICBzdGF0dXMgPSBjeXRvYmFuZF9zdGF0dXMpICU+JQogIGRpc3RpbmN0KCkKYGBgCgojIyMgR2VuZS1sZXZlbCBkYXRhCgpHZXQgdGhlIGdlbmUgc3ltYm9sIGZvciBpbnN0YW5jZXMgd2hlcmUgdGhlIG90aGVyIHR3byBsZXZlbHMgYXJlIG5ldXRyYWwgb3IgTkEuCgpgYGB7cn0KZ2VuZV9zdGF0dXNfZGYgPC0gc2VnX2dpc3RpY19jeXRvYmFuZF9kZiAlPiUKICBmaWx0ZXIoZ2lzdGljX2FybV9zdGF0dXMgPT0gIm5ldXRyYWwiLAogICAgICAgICBjeXRvYmFuZF9zdGF0dXMgPT0gIk5BIikgJT4lCiAgc2VsZWN0KEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQgPSBiaW9zcGVjaW1lbl9pZCwKICAgICAgICAgcmVnaW9uID0gZ2VuZV9zeW1ib2wsCiAgICAgICAgIHN0YXR1cyA9IHN0YXR1cykgJT4lCiAgZGlzdGluY3QoKQpgYGAKCiMjIyBKb2luIGFsbCB0b2dldGhlciBhbmQgd3JpdGUgdG8gZmlsZQoKYGBge3J9Cmxvbmdfc3RhdHVzX2RmIDwtIGJpbmRfcm93cygKICBhcm1fc3RhdHVzX2RmLAogIGN5dG9iYW5kX3N0YXR1c19kZiwKICBnZW5lX3N0YXR1c19kZgopICU+JQogIHdyaXRlX3Rzdihsb25nX3JlZ2lvbnNfZGZfZmlsZSkKYGBgCgo=