library(dplyr)
library(readr)
library(stringr)
This short notebook investigates the accuracy of population assignment for green sturgeon from the Klamath vs from the Sacramento River using the SNPs developed in the paper and using the microsatellites described in Israel et al. (2009).
This process makes use of gsi_sim
which can be downloaded from https://github.com/eriqande/gsi_sim. If you want to run it, you will need to have run the scripts in the R-main
directory of the repository to create some of the output files used here.
Microsatellites
First, we look at microsatellites. We use the data from Israel et al. (2009). The collections in that paper were from the Klamath, Rogue, and Sacramento rivers. We restrict our attention to fish from the Klamath and the Sacramento because the SNP refernce samples do not include any samples from the Rogue.
We run the microsatellite data through gsi_sim
’s self-assignment option and process the results into something that R can read:
if [ ! -d play ]; then mkdir play; fi
cd play
~/Documents/git-repos/gsi_sim/gsi_sim-Darwin -b ../data/israel-10-msats-baseline-KLA-SAC.txt --self-assign > gsi_out.txt
awk '/SELF_ASSIGN_A_LA_GC_CSV:/' gsi_out.txt | sed 's/SELF_ASSIGN_A_LA_GC_CSV:\///g;' > self-ass-for-r.txt
Then read that into a tidy data frame
msats <- read_delim(file = "../play/self-ass-for-r.txt", delim = ";", col_names = FALSE) %>%
select(X1, X2, X3, X10) %>%
setNames(c("ID", "assto", "prob", "num_loci")) %>%
mutate(from_pop = str_sub(ID, 1, 3)) %>%
select(from_pop, everything()) %>%
mutate(correct = from_pop == assto,
num_loci = as.numeric(num_loci))
Count up how many loci were successfully typed on individuals from the different populations
msats %>%
group_by(from_pop, num_loci) %>%
tally()
Let us be conservative and discard the handful of individuals with 7 or fewer typed loci out of 10. So, we are requiring that there be no more than 20% missing loci at each individual.
msat2 <- msats %>%
filter(num_loci >= 8)
Microsatellite misassignments
We can tally the number of misassignments:
msat2 %>%
group_by(from_pop, correct) %>%
tally()
So, that is about 1 to 2% incorrect from each population. Let’s look specifically at those wrong individuals.
msat2 %>%
filter(correct == FALSE)
We see that some of them have low posterior probabilities (which is good—we would rather not incorrectly be super-confident when we are wrong!). However, some of them are quite high, which suggests that either the microsatellite data are not consistenly reliable, or that perhaps these individuals are migrants or sample mixups. The latter is certainly a possibility, so in the following we will allow for the possibility that those were sample mixups, by just pretending that they were correctly assigned.
Thus we give the baseline the benefit of the doubt and imagine that all the fish were assigned to what was truly their correct popuation. Doing so we can get a sense of how powerful the baseline is by investigating the distribution of posterior probabilities. We do that by just sorting things:
msat2 %>%
arrange(prob)
That is 19 individuals with self-assignment scores less than 99%.
SNPs
Now we run through a similar process with the SNPs that we have developed. We can get the assignments by running gsi_sim on the file that was used in the analysis
if [ ! -d play ]; then mkdir play; fi
cd play
~/Documents/git-repos/gsi_sim/gsi_sim-Darwin -b ../outputs/gs_baseline.txt --self-assign > snp_out.txt
awk '/SELF_ASSIGN_A_LA_GC_CSV:/' snp_out.txt | sed 's/SELF_ASSIGN_A_LA_GC_CSV:\///g;' > snp-ass-for-r.txt
and then read those in:
snps <- read_delim(file = "../play/snp-ass-for-r.txt", delim = ";", col_names = FALSE) %>%
select(X1, X2, X3, X10) %>%
setNames(c("ID", "assto", "prob", "num_loci")) %>%
mutate(from_river = str_sub(ID, 1, 3),
from_pop = ifelse(from_river == "Sac", "SouthernDPS", "NorthernDPS")) %>%
select(from_pop, everything()) %>%
mutate(correct = from_pop == assto,
num_loci = as.numeric(num_loci))
We can tally up the number of fish that are incorrectly self-assigned. There is only 1 of those. And that fish had only 4 non-missing loci.
And now let us filter those to no more than 20% missing data and tally up some numbers
snps2 <- snps %>%
filter(num_loci/74 >= .80)
Here are the number of fish correctly and incorrectly self-assigned:
snps2 %>%
group_by(from_river, correct) %>%
tally()
So, no mistakes there.
Now let us investigate the distribution of posterior probs by sorting everyone:
snps2 %>%
arrange(prob)
And we see that pretty much that the smallest of those is 99.998. So we have a lot of confidence in being right here.
SNP-based GSI posterior probabilities in the bycatch
The baseline is relatively small, especially for the Klamath, but we can look at the distribution of the posterior probabilities for the fish from the bycatch to confirm that we have high confidence in GSI assignments (This was already obvious from the structure runs in the paper, but we will present it here with gsi_sim
using just the small baseline as well…)
# these results are available from the analysis done in the paper
byc <- readRDS("../outputs/gsi-sim-DPS-assignments-of-bycatch.rds") %>%
filter(NumLoc/74 >= 0.8) %>% # filter at num loci
mutate(prob = ifelse(DPS_gsi_sim == "north", NorthernDPS, SouthernDPS))
First, tally up how many fish there are that were assigned to the Northern or the Southern DPS:
byc %>%
group_by(DPS_gsi_sim) %>%
tally()
Now just visually look at the posterior probs with which those fish are assigned:
byc %>%
arrange(prob) %>%
select(-SouthernDPS, -NorthernDPS)
And we see that the lowest posterior probability is 0.9943, which is very close to 1.0.
Conclusion
Thus, although the microsatellites described in Israel et al. (2009) offer impressive accuracy for genetic stock identification, it should be clear from the preceding that the set of SNPs we describe allows resolution between the Sacramento and the Klamath (and the Northern and Southern DPS) with greater reliability than the microsatellites used in Israel et al. (2009).
References
Israel, Joshua A, K Jun Bando, Eric C Anderson, and Bernie May. 2009. “Polyploid microsatellite data reveal stock complexity among estuarine North American green sturgeon (Acipenser medirostris).” Canadian Journal of Fisheries and Aquatic Sciences 66: 1491–1504.
LS0tCnRpdGxlOiAiU3VwcGxlbWVudCAzIHRvIGFydGljbGUsIFwiR2VuZXRpYyBhbmQgaW5kaXZpZHVhbCBhc3NpZ25tZW50IG9mIHRldHJhcGxvaWQKZ3JlZW4gc3R1cmdlb24gd2l0aCBTTlAgYXNzYXkgZGF0YVwiIC0tLSBDb21wYXJpbmcgU05QUyB0byBNaWNyb3NhdGVsbGl0ZXMgZm9yIFBvcHVsYXRpb24gQXNzaWdubWVudCBvZiBHcmVlbiBTdHVyZ2VvbiIKYXV0aG9yOiAiRXJpYyBDLiBBbmRlcnNvbiwgVGhvbWFzIEMuIE5nLCBFcmljIEQuIENyYW5kYWxsLCBhbmQgSi4gQ2FybG9zIEdhcnphIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQpiaWJsaW9ncmFwaHk6IC4uL3RleC9zdHVyZ2Vvbi1mbHVpZGlnbS5iaWIKLS0tCgpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeShzdHJpbmdyKQpgYGAKVGhpcyBzaG9ydCBub3RlYm9vayBpbnZlc3RpZ2F0ZXMgdGhlIGFjY3VyYWN5IG9mIHBvcHVsYXRpb24gYXNzaWdubWVudCBmb3IgZ3JlZW4gc3R1cmdlb24KZnJvbSB0aGUgS2xhbWF0aCB2cyBmcm9tIHRoZSBTYWNyYW1lbnRvIFJpdmVyIHVzaW5nIHRoZSAKU05QcyBkZXZlbG9wZWQgaW4gdGhlIHBhcGVyIGFuZCB1c2luZyB0aGUgbWljcm9zYXRlbGxpdGVzIGRlc2NyaWJlZCBpbgpASXNyYWVsZXRhbDIwMDkuCgpUaGlzIHByb2Nlc3MgbWFrZXMgdXNlIG9mIGBnc2lfc2ltYCB3aGljaCBjYW4gYmUgZG93bmxvYWRlZCBmcm9tCltodHRwczovL2dpdGh1Yi5jb20vZXJpcWFuZGUvZ3NpX3NpbV0oaHR0cHM6Ly9naXRodWIuY29tL2VyaXFhbmRlL2dzaV9zaW0pLiAgSWYgeW91IHdhbnQKdG8gcnVuIGl0LCB5b3Ugd2lsbCBuZWVkIHRvIGhhdmUgcnVuIHRoZSBzY3JpcHRzIGluIHRoZSBgUi1tYWluYCBkaXJlY3Rvcnkgb2YgdGhlIApyZXBvc2l0b3J5IHRvIGNyZWF0ZSBzb21lIG9mIHRoZSBvdXRwdXQgZmlsZXMgdXNlZCBoZXJlLgoKIyMgTWljcm9zYXRlbGxpdGVzCgpGaXJzdCwgd2UgbG9vayBhdCBtaWNyb3NhdGVsbGl0ZXMuICBXZSB1c2UgdGhlIGRhdGEgZnJvbSBASXNyYWVsZXRhbDIwMDkuICBUaGUgY29sbGVjdGlvbnMgaW4gdGhhdCBwYXBlciB3ZXJlIGZyb20KdGhlIEtsYW1hdGgsIFJvZ3VlLCBhbmQgU2FjcmFtZW50byByaXZlcnMuICBXZSByZXN0cmljdCBvdXIgYXR0ZW50aW9uIHRvIGZpc2ggZnJvbSB0aGUgS2xhbWF0aCBhbmQgdGhlIFNhY3JhbWVudG8gCmJlY2F1c2UgdGhlIFNOUCByZWZlcm5jZSBzYW1wbGVzIGRvIG5vdCBpbmNsdWRlIGFueSBzYW1wbGVzIGZyb20gdGhlIFJvZ3VlLgoKV2UgcnVuIHRoZSBtaWNyb3NhdGVsbGl0ZSBkYXRhIHRocm91Z2ggYGdzaV9zaW1gJ3Mgc2VsZi1hc3NpZ25tZW50IG9wdGlvbiBhbmQgcHJvY2VzcyB0aGUgcmVzdWx0cyBpbnRvIHNvbWV0aGluZyB0aGF0ClIgY2FuIHJlYWQ6CmBgYHtzaCBydW4tZ3NpLXNpbX0KaWYgWyAhIC1kIHBsYXkgXTsgdGhlbiBta2RpciBwbGF5OyBmaQpjZCBwbGF5Cn4vRG9jdW1lbnRzL2dpdC1yZXBvcy9nc2lfc2ltL2dzaV9zaW0tRGFyd2luIC1iIC4uL2RhdGEvaXNyYWVsLTEwLW1zYXRzLWJhc2VsaW5lLUtMQS1TQUMudHh0IC0tc2VsZi1hc3NpZ24gPiBnc2lfb3V0LnR4dCAKYXdrICcvU0VMRl9BU1NJR05fQV9MQV9HQ19DU1Y6LycgZ3NpX291dC50eHQgfCBzZWQgJ3MvU0VMRl9BU1NJR05fQV9MQV9HQ19DU1Y6XC8vL2c7JyA+IHNlbGYtYXNzLWZvci1yLnR4dCAKYGBgCgpUaGVuIHJlYWQgdGhhdCBpbnRvIGEgdGlkeSBkYXRhIGZyYW1lCmBgYHtyIHJlYWQtbXNhdHMsIG1lc3NhZ2U9RkFMU0V9Cm1zYXRzIDwtIHJlYWRfZGVsaW0oZmlsZSA9ICIuLi9wbGF5L3NlbGYtYXNzLWZvci1yLnR4dCIsIGRlbGltID0gIjsiLCBjb2xfbmFtZXMgPSBGQUxTRSkgJT4lCiAgc2VsZWN0KFgxLCBYMiwgWDMsIFgxMCkgJT4lCiAgc2V0TmFtZXMoYygiSUQiLCAiYXNzdG8iLCAicHJvYiIsICJudW1fbG9jaSIpKSAlPiUKICBtdXRhdGUoZnJvbV9wb3AgPSBzdHJfc3ViKElELCAxLCAzKSkgJT4lCiAgc2VsZWN0KGZyb21fcG9wLCBldmVyeXRoaW5nKCkpICU+JQogIG11dGF0ZShjb3JyZWN0ID0gZnJvbV9wb3AgPT0gYXNzdG8sCiAgICAgICAgIG51bV9sb2NpID0gYXMubnVtZXJpYyhudW1fbG9jaSkpCmBgYAoKQ291bnQgdXAgaG93IG1hbnkgbG9jaSB3ZXJlIHN1Y2Nlc3NmdWxseSB0eXBlZCBvbiBpbmRpdmlkdWFscyBmcm9tIHRoZSBkaWZmZXJlbnQgcG9wdWxhdGlvbnMKYGBge3IgdGFsbHktbG9jaX0KbXNhdHMgJT4lIAogIGdyb3VwX2J5KGZyb21fcG9wLCBudW1fbG9jaSkgJT4lCiAgdGFsbHkoKQpgYGAKCkxldCB1cyBiZSBjb25zZXJ2YXRpdmUgYW5kIGRpc2NhcmQgdGhlIGhhbmRmdWwgb2YgaW5kaXZpZHVhbHMgd2l0aCA3IG9yIGZld2VyIHR5cGVkIGxvY2kgb3V0IG9mIDEwLgpTbywgd2UgYXJlIHJlcXVpcmluZyB0aGF0IHRoZXJlIGJlIG5vIG1vcmUgdGhhbiAyMCUgbWlzc2luZyBsb2NpIGF0IGVhY2ggaW5kaXZpZHVhbC4KCmBgYHtyIHRvc3MtbWlzc2Vyc30KbXNhdDIgPC0gbXNhdHMgJT4lCiAgZmlsdGVyKG51bV9sb2NpID49IDgpCmBgYAoKIyMjIE1pY3Jvc2F0ZWxsaXRlIG1pc2Fzc2lnbm1lbnRzCldlIGNhbiB0YWxseSB0aGUgbnVtYmVyIG9mIG1pc2Fzc2lnbm1lbnRzOgpgYGB7ciBtc2F0LW1pc3MtYXNzfQptc2F0MiAlPiUgCiAgZ3JvdXBfYnkoZnJvbV9wb3AsIGNvcnJlY3QpICU+JQogIHRhbGx5KCkKYGBgCgpTbywgdGhhdCBpcyBhYm91dCAxIHRvIDIlIGluY29ycmVjdCBmcm9tIGVhY2ggcG9wdWxhdGlvbi4gIExldCdzIGxvb2sgc3BlY2lmaWNhbGx5IGF0IHRob3NlIHdyb25nIGluZGl2aWR1YWxzLgpgYGB7ciBtc2F0LXdyb25nb3N9Cm1zYXQyICU+JQogIGZpbHRlcihjb3JyZWN0ID09IEZBTFNFKQpgYGAKV2Ugc2VlIHRoYXQgc29tZSBvZiB0aGVtIGhhdmUgbG93IHBvc3RlcmlvciBwcm9iYWJpbGl0aWVzICh3aGljaCBpcyBnb29kLS0td2Ugd291bGQgcmF0aGVyIG5vdCBpbmNvcnJlY3RseSBiZSBzdXBlci1jb25maWRlbnQgd2hlbiB3ZSBhcmUgd3JvbmchKS4gIEhvd2V2ZXIsIHNvbWUgb2YgdGhlbSBhcmUgcXVpdGUgaGlnaCwgd2hpY2ggc3VnZ2VzdHMgdGhhdCBlaXRoZXIgdGhlIG1pY3Jvc2F0ZWxsaXRlIGRhdGEgYXJlIG5vdCBjb25zaXN0ZW5seSByZWxpYWJsZSwgb3IgdGhhdCBwZXJoYXBzIHRoZXNlIGluZGl2aWR1YWxzIGFyZSBtaWdyYW50cyBvciBzYW1wbGUgbWl4dXBzLiAgVGhlIGxhdHRlciBpcyBjZXJ0YWlubHkgYSBwb3NzaWJpbGl0eSwgc28gaW4gdGhlIGZvbGxvd2luZyB3ZSB3aWxsIGFsbG93IGZvciB0aGUgcG9zc2liaWxpdHkgdGhhdCB0aG9zZSB3ZXJlIHNhbXBsZSBtaXh1cHMsIGJ5IGp1c3QgcHJldGVuZGluZyB0aGF0IHRoZXkgd2VyZSBjb3JyZWN0bHkgYXNzaWduZWQuCgpUaHVzIHdlIGdpdmUgdGhlIGJhc2VsaW5lIHRoZSBiZW5lZml0IG9mIHRoZSBkb3VidCBhbmQgaW1hZ2luZSB0aGF0IGFsbCB0aGUgZmlzaCB3ZXJlICBhc3NpZ25lZCB0byB3aGF0IHdhcyB0cnVseSB0aGVpciBjb3JyZWN0IHBvcHVhdGlvbi4gIERvaW5nIHNvIHdlIGNhbiBnZXQgYSBzZW5zZSBvZiBob3cgcG93ZXJmdWwgdGhlIGJhc2VsaW5lIGlzIGJ5IGludmVzdGlnYXRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwb3N0ZXJpb3IgcHJvYmFiaWxpdGllcy4gIFdlIGRvIHRoYXQgYnkganVzdCBzb3J0aW5nIHRoaW5nczoKYGBge3IgbXNhdC1zb3J0LCByb3dzLnByaW50ID0gMjB9Cm1zYXQyICU+JQogIGFycmFuZ2UocHJvYikKYGBgClRoYXQgaXMgMTkgaW5kaXZpZHVhbHMgd2l0aCBzZWxmLWFzc2lnbm1lbnQgc2NvcmVzIGxlc3MgdGhhbiA5OSUuCgoKIyMgU05QcwoKTm93IHdlIHJ1biB0aHJvdWdoIGEgc2ltaWxhciBwcm9jZXNzIHdpdGggdGhlIFNOUHMgdGhhdCB3ZSBoYXZlIGRldmVsb3BlZC4KV2UgY2FuIGdldCB0aGUgYXNzaWdubWVudHMgYnkgcnVubmluZyBnc2lfc2ltIG9uIHRoZSBmaWxlIHRoYXQgd2FzIHVzZWQgaW4gdGhlIGFuYWx5c2lzCmBgYHtzaCBydW4tZ3NpLXNpbS1zbnBzfQppZiBbICEgLWQgcGxheSBdOyB0aGVuIG1rZGlyIHBsYXk7IGZpCmNkIHBsYXkKfi9Eb2N1bWVudHMvZ2l0LXJlcG9zL2dzaV9zaW0vZ3NpX3NpbS1EYXJ3aW4gLWIgLi4vb3V0cHV0cy9nc19iYXNlbGluZS50eHQgLS1zZWxmLWFzc2lnbiA+IHNucF9vdXQudHh0IAphd2sgJy9TRUxGX0FTU0lHTl9BX0xBX0dDX0NTVjovJyBzbnBfb3V0LnR4dCB8IHNlZCAncy9TRUxGX0FTU0lHTl9BX0xBX0dDX0NTVjpcLy8vZzsnID4gc25wLWFzcy1mb3Itci50eHQgCmBgYAphbmQgdGhlbiByZWFkIHRob3NlIGluOgpgYGB7ciByZWFkLXNucHMsIG1lc3NhZ2U9RkFMU0V9CnNucHMgPC0gcmVhZF9kZWxpbShmaWxlID0gIi4uL3BsYXkvc25wLWFzcy1mb3Itci50eHQiLCBkZWxpbSA9ICI7IiwgY29sX25hbWVzID0gRkFMU0UpICU+JQogIHNlbGVjdChYMSwgWDIsIFgzLCBYMTApICU+JQogIHNldE5hbWVzKGMoIklEIiwgImFzc3RvIiwgInByb2IiLCAibnVtX2xvY2kiKSkgJT4lCiAgbXV0YXRlKGZyb21fcml2ZXIgPSBzdHJfc3ViKElELCAxLCAzKSwKICAgICAgICAgZnJvbV9wb3AgPSBpZmVsc2UoZnJvbV9yaXZlciA9PSAiU2FjIiwgIlNvdXRoZXJuRFBTIiwgIk5vcnRoZXJuRFBTIikpICU+JQogIHNlbGVjdChmcm9tX3BvcCwgZXZlcnl0aGluZygpKSAlPiUKICBtdXRhdGUoY29ycmVjdCA9IGZyb21fcG9wID09IGFzc3RvLAogICAgICAgICBudW1fbG9jaSA9IGFzLm51bWVyaWMobnVtX2xvY2kpKQpgYGAKCldlIGNhbiB0YWxseSB1cCB0aGUgbnVtYmVyIG9mIGZpc2ggdGhhdCBhcmUgaW5jb3JyZWN0bHkgc2VsZi1hc3NpZ25lZC4gIFRoZXJlIGlzIG9ubHkKYHIgc3VtKCFzbnBzJGNvcnJlY3QpYCBvZiB0aG9zZS4gIEFuZCB0aGF0IGZpc2ggaGFkIG9ubHkgNCBub24tbWlzc2luZyBsb2NpLgoKCkFuZCBub3cgbGV0IHVzIGZpbHRlciB0aG9zZSB0byBubyBtb3JlIHRoYW4gMjAlIG1pc3NpbmcgZGF0YSBhbmQgdGFsbHkgdXAgc29tZSBudW1iZXJzCmBgYHtyIHRvc3MtbWlzcy1zbnBzfQpzbnBzMiA8LSBzbnBzICU+JQogIGZpbHRlcihudW1fbG9jaS83NCA+PSAuODApCmBgYApIZXJlIGFyZSB0aGUgbnVtYmVyIG9mIGZpc2ggY29ycmVjdGx5IGFuZCBpbmNvcnJlY3RseSBzZWxmLWFzc2lnbmVkOgpgYGB7ciBzZWxmLWFzcy1zbnBzLW51bXN9CnNucHMyICU+JQogIGdyb3VwX2J5KGZyb21fcml2ZXIsIGNvcnJlY3QpICU+JQogIHRhbGx5KCkKYGBgClNvLCBubyBtaXN0YWtlcyB0aGVyZS4KCk5vdyBsZXQgdXMgaW52ZXN0aWdhdGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwb3N0ZXJpb3IgcHJvYnMgYnkgc29ydGluZyBldmVyeW9uZToKYGBge3Igc29ydC1zbnBzfQpzbnBzMiAlPiUKICBhcnJhbmdlKHByb2IpCmBgYAoKQW5kIHdlIHNlZSB0aGF0IHByZXR0eSBtdWNoIHRoYXQgdGhlIHNtYWxsZXN0IG9mIHRob3NlIGlzIDk5Ljk5OC4gIFNvIHdlIGhhdmUgYSBsb3Qgb2YgY29uZmlkZW5jZSBpbiBiZWluZyByaWdodCBoZXJlLiAgCgojIyMgU05QLWJhc2VkIEdTSSBwb3N0ZXJpb3IgcHJvYmFiaWxpdGllcyBpbiB0aGUgYnljYXRjaApUaGUgYmFzZWxpbmUgaXMgcmVsYXRpdmVseSBzbWFsbCwgZXNwZWNpYWxseSBmb3IgdGhlIEtsYW1hdGgsIGJ1dCB3ZSBjYW4gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBwb3N0ZXJpb3IgcHJvYmFiaWxpdGllcwpmb3IgdGhlIGZpc2ggZnJvbSB0aGUgYnljYXRjaCB0byBjb25maXJtIHRoYXQgd2UgaGF2ZSBoaWdoIGNvbmZpZGVuY2UgaW4gR1NJIGFzc2lnbm1lbnRzIChUaGlzIHdhcyBhbHJlYWR5IG9idmlvdXMgZnJvbSB0aGUgCl9zdHJ1Y3R1cmVfIHJ1bnMgaW4gdGhlIHBhcGVyLCBidXQgd2Ugd2lsbCBwcmVzZW50IGl0IGhlcmUgd2l0aCBgZ3NpX3NpbWAgdXNpbmcganVzdCB0aGUgc21hbGwgYmFzZWxpbmUgYXMgd2VsbC4uLikKYGBge3IgYnljYXRjaC1yZWFkfQojIHRoZXNlIHJlc3VsdHMgYXJlIGF2YWlsYWJsZSBmcm9tIHRoZSBhbmFseXNpcyBkb25lIGluIHRoZSBwYXBlcgpieWMgPC0gcmVhZFJEUygiLi4vb3V0cHV0cy9nc2ktc2ltLURQUy1hc3NpZ25tZW50cy1vZi1ieWNhdGNoLnJkcyIpICU+JQogIGZpbHRlcihOdW1Mb2MvNzQgPj0gMC44KSAgJT4lICAgIyBmaWx0ZXIgYXQgbnVtIGxvY2kKICBtdXRhdGUocHJvYiA9IGlmZWxzZShEUFNfZ3NpX3NpbSA9PSAibm9ydGgiLCBOb3J0aGVybkRQUywgU291dGhlcm5EUFMpKQpgYGAKCkZpcnN0LCB0YWxseSB1cCBob3cgbWFueSBmaXNoIHRoZXJlIGFyZSB0aGF0IHdlcmUgYXNzaWduZWQgdG8gdGhlIE5vcnRoZXJuIG9yIHRoZSBTb3V0aGVybiBEUFM6CmBgYHtyIHRhbGx5LWJ5Y30KYnljICU+JQogIGdyb3VwX2J5KERQU19nc2lfc2ltKSAlPiUKICB0YWxseSgpCmBgYApOb3cganVzdCB2aXN1YWxseSBsb29rIGF0IHRoZSBwb3N0ZXJpb3IgcHJvYnMgd2l0aCB3aGljaCB0aG9zZSBmaXNoIGFyZSBhc3NpZ25lZDoKYGBge3IgYnljLXByb2JzfQpieWMgJT4lIAogIGFycmFuZ2UocHJvYikgJT4lCiAgc2VsZWN0KC1Tb3V0aGVybkRQUywgLU5vcnRoZXJuRFBTKQpgYGAKQW5kIHdlIHNlZSB0aGF0IHRoZSBsb3dlc3QgcG9zdGVyaW9yIHByb2JhYmlsaXR5IGlzIDAuOTk0Mywgd2hpY2ggaXMgdmVyeSBjbG9zZSB0byAxLjAuICAKCiMjIENvbmNsdXNpb24KClRodXMsIGFsdGhvdWdoIHRoZSBtaWNyb3NhdGVsbGl0ZXMgZGVzY3JpYmVkIGluIEBJc3JhZWxldGFsMjAwOSBvZmZlciBpbXByZXNzaXZlIGFjY3VyYWN5IGZvcgpnZW5ldGljIHN0b2NrIGlkZW50aWZpY2F0aW9uLCBpdCBzaG91bGQgYmUgY2xlYXIgZnJvbSB0aGUgcHJlY2VkaW5nIHRoYXQgdGhlIHNldCBvZiBTTlBzCndlIGRlc2NyaWJlIGFsbG93cyByZXNvbHV0aW9uIGJldHdlZW4gdGhlIFNhY3JhbWVudG8gYW5kIHRoZSBLbGFtYXRoIChhbmQgdGhlIE5vcnRoZXJuIGFuZCBTb3V0aGVybiBEUFMpCndpdGggZ3JlYXRlciByZWxpYWJpbGl0eSB0aGFuIHRoZSBtaWNyb3NhdGVsbGl0ZXMgdXNlZCBpbiBASXNyYWVsZXRhbDIwMDkuCgojIyBSZWZlcmVuY2VzCg==