Load our genetic data
Often, we need to consolidate data from varied sources. Concerning genomic data, the most popular format is the Variant Call Format (or VCF). There are many R packages to help you perform these tasks such as vcfR. For the sake of brevity, today, I have generated an R data object in the GenInd format that is used by a variety of R population genetics packages. Load that file below.
load("humans.RData") # load the human genome population variant data from Baxevanis et al.
#load("/opt/BIOL5436/humans.RData")
humans # let's look at what this object is
Locus summary statistics
When starting to work with any dataset, it is informatic to review determine some basic understanding of the underlying diversity in alleles. We can use this information to make decisions about how useful certain genetic loci might be for downstream applications such as generating phylogenetic relationships.
library("poppr") # Make sure poppr is loaded if you haven't done so already.
library("magrittr") # We will also use magrittr for part of this chapter
data("Pinf") # P. infestans data set from Mexico and South America
locus_table(Pinf)
As we can see, Pi33 has a low number of alleles in this particular example population. With that in mind, we may conclude that is not a good locus for certain types of analysis.
How about our human dataset?
locus_table(humans)
This particular dataset is heavily pared down and designed to allow us to do expedited calculations we will do later. So, since there is very little genetic diversity at each locus we can conclude that this data may not be extremely useful for certain types of calculations since this overall population is not very genetically diverse.
Population structure
We often want to understand how genetically distant populations and individuals are from each other, respectively.
Genetic distance
Sometimes, we need to take an individual-level perspective to undertand population structure. This is particularly important when we know little about any underlying distinct populations in a group of individuals. There are variety of measures to calculate genetic distance. Here, we’ll focus on Nei’s Distance - a commonly used metric.
Let’s see an example of calculating distance and then check out our humans.
library("poppr")
library("ape") # To visualize the tree using the "nj" function
library("magrittr")
data(microbov)
set.seed(10)
ten_samples <- sample(nInd(microbov), 10)
mic10 <- microbov[ten_samples]
(micdist <- provesti.dist(mic10))
We now have distances… Where have we used distances to infer relationships before? Phylogenetic trees!
While not a formal phylogeny, we can use trees to help build intuition about possible underlying population structure. Let’s use a stock dataset of bovine data from Africa and France.
theTree <- micdist %>%
nj() %>% # calculate neighbor-joining tree
ladderize() # organize branches by clade
plot(theTree)
add.scale.bar(length = 0.05) # add a scale bar showing 5% difference.
Question
What can we conclude about the populations of African and French cattle?
Let’s look at our humans.
humDist <- nei.dist(humans)
humTree <- humDist %>%
nj() %>%
ladderize()
plot(humTree)
Clustering
Particularly with large datasets, use of clustering techniques can help provide some insights into population structure. Clustering is a statistical approach that often employs Principle Component Analysis (PCA). Clustering is distinct from overall distance-based methods in that it allows each locus to contribute to the overall determination of similarity and differences between individuals. However, clustering methods like k-means clustering do use per locus genetic distances as the basis for PCA. This ultimately gives rise to distinct clusters of individuals if there is sufficient genetic variation in the population and similarity between individuals. That said, this approach is not good for very clonal populations.
Let’s see an example. We’ll use a fungal pathogen dataset to illustrate some concepts.
library("poppr")
data("Pinf")
Pinf
For best results, copy and past the text below into the console window.
MX <- popsub(Pinf, "North America") # here we're extracting only the samples from North America in our dataset
MXclust <- find.clusters(MX)
We can see that we can form clusters using this analysis. The utlity and meaning of these clusters are up to the investigator, however. Remember, these are just statistical outcomes based on selected parameters.
How about our humans?!
Paste the following in the console, below.
find.clusters(humans)
Discriminant Analysis of Principle Components
Another method to infer population structure is Discriminant Analysis of Principle Components. Like clustering, it is a method reliant on PCA. DAPC is a method that looks to find groups/clusters of genetically related individuals. Unlike hierarchical clustering methods like k-means (that we explored above) DAPC is able to be used on highly clonal or partially clonal populations.
Let’s explore an example to see how this works. This example examines H3N2 influenza data across epidemic years. You might need to run this twice to get plot to show up.
# DAPC requires the adegenet package. Let's load this package:
library("adegenet")
data(H3N2) # load the H3N2 influenza data. Type ?H3N2 for more info.
pop(H3N2) <- H3N2$other$epid
dapc.H3N2 <- dapc(H3N2, var.contrib = TRUE, scale = FALSE, n.pca = 30, n.da = nPop(H3N2) - 1)
scatter(dapc.H3N2, cell = 0, pch = 18:23, cstar = 0, mstree = TRUE, lwd = 2, lty = 2)
Now, how about our humans?!
DAPC.humans <- dapc(humans, var.contrib = TRUE, scale = FALSE, n.pca = 20, n.da = nPop(H3N2) - 1)
scatter(DAPC.humans)
Question
Compare these results to Figure 15.1 in Baxevanis. Do we see any similarities/differences?
LS0tCnRpdGxlOiAiTW9kdWxlIDEyIEV4ZXJjaXNlcyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyBPdmVydmlldwoKVG9kYXkgd2Ugd2lsbCBiZSBleHBsb3JpbmcgaG93IHdlIGNhbiBhbmFseXplIGdlbmV0aWMvZ2Vub21pYyBkYXRhIHVzaW5nIHZhcmlvdXMgUiBwYWNrYWdlcy4gTWFueSBvZiB0aGUgY29kZSBleGFtcGxlcyBhcmUgdGFrZW4gZnJvbSB0aGUgR3J1bndhbGQgdHV0b3JpYWwgc2hhcmVkIGluIHRoZSBDYW52YXMgbW9kdWxlLgoKT2JqZWN0aXZlczoKCi0gRGV2ZWxvcCBmYW1pbGlhcml0eSB3aXRoIHBvcHVsYXIgUiBwb3B1bGF0aW9uIGdlbmV0aWNzIGFuYWx5c2lzIHBhY2thZ2VzLgoKLSBBbmFseXplIHNvbWUgZGF0YSBmcm9tIHRoZSAxMDAwIEdlbm9tZXMgUHJvamVjdC4KCgojIFVzaW5nIFIgdG8gcGVyZm9ybSBwb3B1bGF0aW9uIGdlbmV0aWMgYW5hbHlzaXMKClRyYWRpdGlvbmFsbHksIG1hbnkgY2FsY3VsYXRpb25zIGNvdWxkIGJlIHBlcmZvcm1lZCBieSBoYW5kLiBUb2RheSwgaW4gdGhlIGdlbm9taWMgZXJhLCB3ZSBpbmNyZWFzaW5nbHkgcmVxdWlyZSBjb21wdXRlcnMgdG8gaGVscCB1cyBwZXJmb3JtIGNhbGN1bGF0aW9ucyBvbiB2ZXJ5IGxhcmdlIGdlbmV0aWMvZ2Vub21pYyBkYXRhc2V0cyBhc3NvY2lhdGVkIHdpdGggcG9wdWxhdGlvbnMuIE5vd2hlcmUgaXMgdGhpcyBtb3JlIGFwcGFyZW50IHRoYW4gYW5hbHlzaXMgb2YgaHVtYW4gZ2Vub21pYyBpbmZvcm1hdGlvbi4KCkZvcnR1bmF0ZWx5LCB0aGUgUiBlbnZpcm9ubWVudCBoYXMgYSB2ZXJ5IGxhcmdlIHVzZXIgYmFzZSBpbnZvbHZlZCBpbiBwb3B1bGF0aW9uIGdlbmV0aWNzIHJlc2VhcmNoLiBUb2RheSwgd2Ugd2lsbCB1c2UgUiB0byBjYWxjdWxhdGUgdmFyaW91cyBwb3B1bGF0aW9uIGdlbmV0aWNzIHBhcmFtZXRlcnMgYW5kIHBlcmZvcm0gcHJpbmNpcGxlIGNvbXBvbmVudCBhbmFseXNpcyBvbiBkYXRhLgoKQmVsb3cgYXJlIHNvbWUgcGFja2FnZXMgd2Ugd2lsbCB1c2UgdG8gZGF5LiBHbyBhaGVhZCBhbmQgbG9hZCB0aGVtLgoKYGBge3J9CmxpYnJhcnkocG9wcHIpCmxpYnJhcnkoYWRlZ2VuZXQpCmxpYnJhcnkobW1vZCkKYGBgCgoKIyBMb2FkIG91ciBnZW5ldGljIGRhdGEKCk9mdGVuLCB3ZSBuZWVkIHRvIGNvbnNvbGlkYXRlIGRhdGEgZnJvbSB2YXJpZWQgc291cmNlcy4gQ29uY2VybmluZyBnZW5vbWljIGRhdGEsIHRoZSBtb3N0IHBvcHVsYXIgZm9ybWF0IGlzIHRoZSBWYXJpYW50IENhbGwgRm9ybWF0IChvciBWQ0YpLiBUaGVyZSBhcmUgbWFueSBSIHBhY2thZ2VzIHRvIGhlbHAgeW91IHBlcmZvcm0gdGhlc2UgdGFza3Mgc3VjaCBhcyBgdmNmUmAuIEZvciB0aGUgc2FrZSBvZiBicmV2aXR5LCB0b2RheSwgSSBoYXZlIGdlbmVyYXRlZCBhbiBSIGRhdGEgb2JqZWN0IGluIHRoZSBHZW5JbmQgZm9ybWF0IHRoYXQgaXMgdXNlZCBieSBhIHZhcmlldHkgb2YgUiBwb3B1bGF0aW9uIGdlbmV0aWNzIHBhY2thZ2VzLiBMb2FkIHRoYXQgZmlsZSBiZWxvdy4KCmBgYHtyfQpsb2FkKCJodW1hbnMuUkRhdGEiKSAjIGxvYWQgdGhlIGh1bWFuIGdlbm9tZSBwb3B1bGF0aW9uIHZhcmlhbnQgZGF0YSBmcm9tIEJheGV2YW5pcyBldCBhbC4KI2xvYWQoIi9vcHQvQklPTDU0MzYvaHVtYW5zLlJEYXRhIikKCmh1bWFucyAjIGxldCdzIGxvb2sgYXQgd2hhdCB0aGlzIG9iamVjdCBpcwpgYGAKCiMgTG9jdXMgc3VtbWFyeSBzdGF0aXN0aWNzCgpXaGVuIHN0YXJ0aW5nIHRvIHdvcmsgd2l0aCBhbnkgZGF0YXNldCwgaXQgaXMgaW5mb3JtYXRpYyB0byByZXZpZXcgZGV0ZXJtaW5lIHNvbWUgYmFzaWMgdW5kZXJzdGFuZGluZyBvZiB0aGUgdW5kZXJseWluZyBkaXZlcnNpdHkgaW4gYWxsZWxlcy4gV2UgY2FuIHVzZSB0aGlzIGluZm9ybWF0aW9uIHRvIG1ha2UgZGVjaXNpb25zIGFib3V0IGhvdyB1c2VmdWwgY2VydGFpbiBnZW5ldGljIGxvY2kgbWlnaHQgYmUgZm9yIGRvd25zdHJlYW0gYXBwbGljYXRpb25zIHN1Y2ggYXMgZ2VuZXJhdGluZyBwaHlsb2dlbmV0aWMgcmVsYXRpb25zaGlwcy4KCmBgYHtyfQpsaWJyYXJ5KCJwb3BwciIpICAgICAjIE1ha2Ugc3VyZSBwb3BwciBpcyBsb2FkZWQgaWYgeW91IGhhdmVuJ3QgZG9uZSBzbyBhbHJlYWR5LgpsaWJyYXJ5KCJtYWdyaXR0ciIpICAjIFdlIHdpbGwgYWxzbyB1c2UgbWFncml0dHIgZm9yIHBhcnQgb2YgdGhpcyBjaGFwdGVyCmRhdGEoIlBpbmYiKSAgICAgICAgICMgUC4gaW5mZXN0YW5zIGRhdGEgc2V0IGZyb20gTWV4aWNvIGFuZCBTb3V0aCBBbWVyaWNhCmxvY3VzX3RhYmxlKFBpbmYpCmBgYAoKQXMgd2UgY2FuIHNlZSwgUGkzMyBoYXMgYSBsb3cgbnVtYmVyIG9mIGFsbGVsZXMgaW4gdGhpcyBwYXJ0aWN1bGFyIGV4YW1wbGUgcG9wdWxhdGlvbi4gV2l0aCB0aGF0IGluIG1pbmQsIHdlIG1heSBjb25jbHVkZSB0aGF0IGlzIG5vdCBhIGdvb2QgbG9jdXMgZm9yIGNlcnRhaW4gdHlwZXMgb2YgYW5hbHlzaXMuCgpIb3cgYWJvdXQgb3VyIGh1bWFuIGRhdGFzZXQ/CgpgYGB7cn0KbG9jdXNfdGFibGUoaHVtYW5zKQpgYGAKClRoaXMgcGFydGljdWxhciBkYXRhc2V0IGlzIGhlYXZpbHkgcGFyZWQgZG93biBhbmQgZGVzaWduZWQgdG8gYWxsb3cgdXMgdG8gZG8gZXhwZWRpdGVkIGNhbGN1bGF0aW9ucyB3ZSB3aWxsIGRvIGxhdGVyLiBTbywgc2luY2UgdGhlcmUgaXMgdmVyeSBsaXR0bGUgZ2VuZXRpYyBkaXZlcnNpdHkgYXQgZWFjaCBsb2N1cyB3ZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGlzIGRhdGEgbWF5IG5vdCBiZSBleHRyZW1lbHkgdXNlZnVsIGZvciBjZXJ0YWluIHR5cGVzIG9mIGNhbGN1bGF0aW9ucyBzaW5jZSB0aGlzIG92ZXJhbGwgcG9wdWxhdGlvbiBpcyBub3QgdmVyeSBnZW5ldGljYWxseSBkaXZlcnNlLgoKIyBQb3B1bGF0aW9uIHN0cnVjdHVyZQoKV2Ugb2Z0ZW4gd2FudCB0byB1bmRlcnN0YW5kIGhvdyBnZW5ldGljYWxseSBkaXN0YW50IHBvcHVsYXRpb25zIGFuZCBpbmRpdmlkdWFscyBhcmUgZnJvbSBlYWNoIG90aGVyLCByZXNwZWN0aXZlbHkuIAoKIyMgR3N0IChhIGdlbm9taWMgZm9ybSBvZiBGc3QpCgpUaGVyZSBhcmUgc29tZSBzaW1wbGUgZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiBSIHRvIGNhbGN1bGF0ZSBHc3QgKGFuIGFuYWxvZyBvZiBGc3QpLiBSZWNhbGwgdGhhdCBGc3QgKG9yIEdzdCkgYXJlIGxvb2tpbmcgdG8gdW5kZXJzdGFuZCB0aGUgYW1vdW50IG9mIGdlbmV0aWMgdmFyaWF0aW9uIHdpdGhpbiBhIHN1YnBvcHVsYXRpb24gY29tcGFyZWQgdG8gYSBicm9hZGVyIHBvcHVsYXRpb24uIEdzdCA9IDAgaW1wbGllcyB0aGF0IHRoZSB2YXJpYXRpb24gb2JzZXJ2ZWQgaW4gdGhlIHN1YnBvcHVsYXRpb24gaXMgaW5kaXN0aWd1aXNoYWJsZSBmcm9tIG90aGVyIGdyb3VwcyB3aGVyZWFzIEdzdCA9IDEgaW1wbGllcyB0aGF0IHRoZSB2YXJpYXRpb24gaW4gc3VicG9wdWxhdGlvbiBpcyBkaXN0aW5jdCBmcm9tIG90aGVyIHBvcHVsYXRpb25zIChpLmUuIGl0IGlzIGRpZmZlcmVudGlhdGluZykuIAoKSGVyZSdzIGFuIGV4YW1wbGUuLi4KCmBgYHtyfQpsaWJyYXJ5KCJtbW9kIikKZGF0YSgibmFuY3ljYXRzIikKbmFuY3ljYXRzCmBgYApgYGB7cn0KR3N0X05laShuYW5jeWNhdHMpCmBgYAoKSG93IGFib3V0IGZvciBvdXIgc3Vic2V0IG9mIGh1bWFucz8KCmBgYHtyfQpHc3RfTmVpKGh1bWFucykKYGBgCgpPbiBhIHBlciBsb2N1cyBiYXNpcywgd2Ugc2VlIHRoZXJlIGlzIHZhcmlhYmlsaXR5IGluIEdzdCB2YWx1ZXMuIEFzIHdlIHNlZSwgc29tZSB2YWx1ZXMgYXJlIHF1aXRlIGxvdyAoZXZlbiBuZWdhdGl2ZT8pLiBUaGVzZSB2YWx1ZXMgaW5kaWNhdGUgdGhlcmUgaXMgbm8gZGlmZmVyZW5jZXMgaW4gdmFyaWF0aW9uIGF0IHRob3NlIGxvY2kgb3IgdGhlcmUgbWF5IGJlIGxvdyBoZXRlcm96eWdvc2l0eS4gT3ZlcmFsbCwgd2Ugc2VlIGEgR3N0IHZhbHVlIG9uIHBhciB3aXRoIHdoYXQgd2UgZXhwZWN0IC0gYXJvdW5kIDExLTE1JS4KCiMjIEdlbmV0aWMgZGlzdGFuY2UKClNvbWV0aW1lcywgd2UgbmVlZCB0byB0YWtlIGFuIGluZGl2aWR1YWwtbGV2ZWwgcGVyc3BlY3RpdmUgdG8gdW5kZXJ0YW5kIHBvcHVsYXRpb24gc3RydWN0dXJlLiBUaGlzIGlzIHBhcnRpY3VsYXJseSBpbXBvcnRhbnQgd2hlbiB3ZSBrbm93IGxpdHRsZSBhYm91dCBhbnkgdW5kZXJseWluZyBkaXN0aW5jdCBwb3B1bGF0aW9ucyBpbiBhIGdyb3VwIG9mIGluZGl2aWR1YWxzLiBUaGVyZSBhcmUgdmFyaWV0eSBvZiBtZWFzdXJlcyB0byBjYWxjdWxhdGUgZ2VuZXRpYyBkaXN0YW5jZS4gSGVyZSwgd2UnbGwgZm9jdXMgb24gTmVpJ3MgRGlzdGFuY2UgLSBhIGNvbW1vbmx5IHVzZWQgbWV0cmljLgoKTGV0J3Mgc2VlIGFuIGV4YW1wbGUgb2YgY2FsY3VsYXRpbmcgZGlzdGFuY2UgYW5kIHRoZW4gY2hlY2sgb3V0IG91ciBodW1hbnMuCgpgYGB7cn0KbGlicmFyeSgicG9wcHIiKQpsaWJyYXJ5KCJhcGUiKSAjIFRvIHZpc3VhbGl6ZSB0aGUgdHJlZSB1c2luZyB0aGUgIm5qIiBmdW5jdGlvbgpsaWJyYXJ5KCJtYWdyaXR0ciIpCmRhdGEobWljcm9ib3YpCnNldC5zZWVkKDEwKQp0ZW5fc2FtcGxlcyA8LSBzYW1wbGUobkluZChtaWNyb2JvdiksIDEwKQptaWMxMCAgICAgICA8LSBtaWNyb2Jvdlt0ZW5fc2FtcGxlc10KKG1pY2Rpc3QgICAgPC0gcHJvdmVzdGkuZGlzdChtaWMxMCkpCmBgYAoKV2Ugbm93IGhhdmUgZGlzdGFuY2VzLi4uIFdoZXJlIGhhdmUgd2UgdXNlZCBkaXN0YW5jZXMgdG8gaW5mZXIgcmVsYXRpb25zaGlwcyBiZWZvcmU/IFBoeWxvZ2VuZXRpYyB0cmVlcyEKCldoaWxlIG5vdCBhIGZvcm1hbCBwaHlsb2dlbnksIHdlIGNhbiB1c2UgdHJlZXMgdG8gaGVscCBidWlsZCBpbnR1aXRpb24gYWJvdXQgcG9zc2libGUgdW5kZXJseWluZyBwb3B1bGF0aW9uIHN0cnVjdHVyZS4gTGV0J3MgdXNlIGEgc3RvY2sgZGF0YXNldCBvZiBib3ZpbmUgZGF0YSBmcm9tIEFmcmljYSBhbmQgRnJhbmNlLgoKYGBge3J9CnRoZVRyZWUgPC0gbWljZGlzdCAlPiUKICBuaigpICU+JSAgICAjIGNhbGN1bGF0ZSBuZWlnaGJvci1qb2luaW5nIHRyZWUKICBsYWRkZXJpemUoKSAjIG9yZ2FuaXplIGJyYW5jaGVzIGJ5IGNsYWRlCnBsb3QodGhlVHJlZSkKYWRkLnNjYWxlLmJhcihsZW5ndGggPSAwLjA1KSAjIGFkZCBhIHNjYWxlIGJhciBzaG93aW5nIDUlIGRpZmZlcmVuY2UuCmBgYAoKLS0tCgoqKlF1ZXN0aW9uKioKCldoYXQgY2FuIHdlIGNvbmNsdWRlIGFib3V0IHRoZSBwb3B1bGF0aW9ucyBvZiBBZnJpY2FuIGFuZCBGcmVuY2ggY2F0dGxlPwoKLS0tCgpMZXQncyBsb29rIGF0IG91ciBodW1hbnMuCgpgYGB7cn0KaHVtRGlzdCA8LSBuZWkuZGlzdChodW1hbnMpCgpodW1UcmVlIDwtIGh1bURpc3QgJT4lCiAgbmooKSAlPiUKICBsYWRkZXJpemUoKQoKcGxvdChodW1UcmVlKQoKYGBgCgojIyBDbHVzdGVyaW5nCgpQYXJ0aWN1bGFybHkgd2l0aCBsYXJnZSBkYXRhc2V0cywgdXNlIG9mIGNsdXN0ZXJpbmcgdGVjaG5pcXVlcyBjYW4gaGVscCBwcm92aWRlIHNvbWUgaW5zaWdodHMgaW50byBwb3B1bGF0aW9uIHN0cnVjdHVyZS4gQ2x1c3RlcmluZyBpcyBhIHN0YXRpc3RpY2FsIGFwcHJvYWNoIHRoYXQgb2Z0ZW4gZW1wbG95cyBQcmluY2lwbGUgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpLiBDbHVzdGVyaW5nIGlzIGRpc3RpbmN0IGZyb20gb3ZlcmFsbCBkaXN0YW5jZS1iYXNlZCBtZXRob2RzIGluIHRoYXQgaXQgYWxsb3dzIGVhY2ggbG9jdXMgdG8gY29udHJpYnV0ZSB0byB0aGUgb3ZlcmFsbCBkZXRlcm1pbmF0aW9uIG9mIHNpbWlsYXJpdHkgYW5kIGRpZmZlcmVuY2VzIGJldHdlZW4gaW5kaXZpZHVhbHMuIEhvd2V2ZXIsIGNsdXN0ZXJpbmcgbWV0aG9kcyBsaWtlIGstbWVhbnMgY2x1c3RlcmluZyBkbyB1c2UgcGVyIGxvY3VzIGdlbmV0aWMgZGlzdGFuY2VzIGFzIHRoZSBiYXNpcyBmb3IgUENBLiBUaGlzIHVsdGltYXRlbHkgZ2l2ZXMgcmlzZSB0byBkaXN0aW5jdCBjbHVzdGVycyBvZiBpbmRpdmlkdWFscyBpZiB0aGVyZSBpcyBzdWZmaWNpZW50IGdlbmV0aWMgdmFyaWF0aW9uIGluIHRoZSBwb3B1bGF0aW9uIGFuZCBzaW1pbGFyaXR5IGJldHdlZW4gaW5kaXZpZHVhbHMuIFRoYXQgc2FpZCwgdGhpcyBhcHByb2FjaCBpcyBub3QgZ29vZCBmb3IgdmVyeSBjbG9uYWwgcG9wdWxhdGlvbnMuCgpMZXQncyBzZWUgYW4gZXhhbXBsZS4gV2UnbGwgdXNlIGEgZnVuZ2FsIHBhdGhvZ2VuIGRhdGFzZXQgdG8gaWxsdXN0cmF0ZSBzb21lIGNvbmNlcHRzLgoKYGBge3J9CmxpYnJhcnkoInBvcHByIikKZGF0YSgiUGluZiIpClBpbmYKYGBgCgpGb3IgYmVzdCByZXN1bHRzLCBjb3B5IGFuZCBwYXN0IHRoZSB0ZXh0IGJlbG93IGludG8gdGhlIGNvbnNvbGUgd2luZG93LgpgYGB7fQpNWCA8LSBwb3BzdWIoUGluZiwgIk5vcnRoIEFtZXJpY2EiKSAjIGhlcmUgd2UncmUgZXh0cmFjdGluZyBvbmx5IHRoZSBzYW1wbGVzIGZyb20gTm9ydGggQW1lcmljYSBpbiBvdXIgZGF0YXNldApNWGNsdXN0IDwtIGZpbmQuY2x1c3RlcnMoTVgpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHdlIGNhbiBmb3JtIGNsdXN0ZXJzIHVzaW5nIHRoaXMgYW5hbHlzaXMuIFRoZSB1dGxpdHkgYW5kIG1lYW5pbmcgb2YgdGhlc2UgY2x1c3RlcnMgYXJlIHVwIHRvIHRoZSBpbnZlc3RpZ2F0b3IsIGhvd2V2ZXIuIFJlbWVtYmVyLCB0aGVzZSBhcmUganVzdCBzdGF0aXN0aWNhbCBvdXRjb21lcyBiYXNlZCBvbiBzZWxlY3RlZCBwYXJhbWV0ZXJzLgoKSG93IGFib3V0IG91ciBodW1hbnM/IQoKUGFzdGUgdGhlIGZvbGxvd2luZyBpbiB0aGUgY29uc29sZSwgYmVsb3cuCmBgYHt9CmZpbmQuY2x1c3RlcnMoaHVtYW5zKQpgYGAKCiMjIERpc2NyaW1pbmFudCBBbmFseXNpcyBvZiBQcmluY2lwbGUgQ29tcG9uZW50cwoKQW5vdGhlciBtZXRob2QgdG8gaW5mZXIgcG9wdWxhdGlvbiBzdHJ1Y3R1cmUgaXMgRGlzY3JpbWluYW50IEFuYWx5c2lzIG9mIFByaW5jaXBsZSBDb21wb25lbnRzLiBMaWtlIGNsdXN0ZXJpbmcsIGl0IGlzIGEgbWV0aG9kIHJlbGlhbnQgb24gUENBLiBEQVBDIGlzIGEgbWV0aG9kIHRoYXQgbG9va3MgdG8gZmluZCBncm91cHMvY2x1c3RlcnMgb2YgZ2VuZXRpY2FsbHkgcmVsYXRlZCBpbmRpdmlkdWFscy4gVW5saWtlIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG1ldGhvZHMgbGlrZSBrLW1lYW5zICh0aGF0IHdlIGV4cGxvcmVkIGFib3ZlKSBEQVBDIGlzIGFibGUgdG8gYmUgdXNlZCBvbiBoaWdobHkgY2xvbmFsIG9yIHBhcnRpYWxseSBjbG9uYWwgcG9wdWxhdGlvbnMuCgpMZXQncyBleHBsb3JlIGFuIGV4YW1wbGUgdG8gc2VlIGhvdyB0aGlzIHdvcmtzLiBUaGlzIGV4YW1wbGUgZXhhbWluZXMgSDNOMiBpbmZsdWVuemEgZGF0YSBhY3Jvc3MgZXBpZGVtaWMgeWVhcnMuIFlvdSBtaWdodCBuZWVkIHRvIHJ1biB0aGlzIHR3aWNlIHRvIGdldCBwbG90IHRvIHNob3cgdXAuCgpgYGB7cn0KIyBEQVBDIHJlcXVpcmVzIHRoZSBhZGVnZW5ldCBwYWNrYWdlLiBMZXQncyBsb2FkIHRoaXMgcGFja2FnZToKbGlicmFyeSgiYWRlZ2VuZXQiKQpkYXRhKEgzTjIpICMgbG9hZCB0aGUgSDNOMiBpbmZsdWVuemEgZGF0YS4gVHlwZSA/SDNOMiBmb3IgbW9yZSBpbmZvLgpwb3AoSDNOMikgPC0gSDNOMiRvdGhlciRlcGlkCmRhcGMuSDNOMiA8LSBkYXBjKEgzTjIsIHZhci5jb250cmliID0gVFJVRSwgc2NhbGUgPSBGQUxTRSwgbi5wY2EgPSAzMCwgbi5kYSA9IG5Qb3AoSDNOMikgLSAxKQpzY2F0dGVyKGRhcGMuSDNOMiwgY2VsbCA9IDAsIHBjaCA9IDE4OjIzLCBjc3RhciA9IDAsIG1zdHJlZSA9IFRSVUUsIGx3ZCA9IDIsIGx0eSA9IDIpCmBgYAoKTm93LCBob3cgYWJvdXQgb3VyIGh1bWFucz8hCgpgYGB7cn0KREFQQy5odW1hbnMgPC0gZGFwYyhodW1hbnMsIHZhci5jb250cmliID0gVFJVRSwgc2NhbGUgPSBGQUxTRSwgbi5wY2EgPSAyMCwgbi5kYSA9IG5Qb3AoSDNOMikgLSAxKQpzY2F0dGVyKERBUEMuaHVtYW5zKQpgYGAKCi0tLQoKKipRdWVzdGlvbioqCgpDb21wYXJlIHRoZXNlIHJlc3VsdHMgdG8gRmlndXJlIDE1LjEgaW4gQmF4ZXZhbmlzLiBEbyB3ZSBzZWUgYW55IHNpbWlsYXJpdGllcy9kaWZmZXJlbmNlcz8KCi0tLQ==