Load the libraries we will use today
Similarity and distances
To illustrate the concept of similarity and distance, lets envison a data matrix with 4 sites and 2 species
Lets plot these in 2 dimensions to show the relationships
How can we quantify that distance? One of the simplest methods is the Euclidean distance
The problem with this function that we wrote is that its not easily able to calculate all the distances.
Common distance measures
There are approximately 30 similarity or distances commonly used. Legendre and Legendre 2012
The choice of which distance you are going to use depends on the data type and the type of analysis you will do.
Euclidean distance
\[ ED_{ij} = \sum_{i = 1}^p \sqrt{(x_{ij} - x_{ik})^2} \] - Most appealing measure because it has true “metric” properties - Column standardization to remove potential issues with scale - Applied to any data of any scale - Used in eigenvector ordinations (e.g., PCA) - Assume that variables are not correlated - Emphasizes outliers - Loose sensitivity with heterogeneous data - Distances are not proportional
vegdist(hyp_data, method = "euclidean")
1 2 3
2 1.000000
3 5.830952 5.385165
4 11.313708 10.630146 5.830952
City block (Manhattan) distance
- Most ecologically meaningful dissimilarities are Manhattan types
- Less weight to outliers compared to Euclidean
- Retains sensitivity with heterogenous data
- Distances are not proportional
vegdist(hyp_data, method = "manhattan")
1 2 3
2 1
3 8 7
4 16 15 8
Proportional distances
- Manhattan distances expressed as a proportion of the max distance
- 2 communities with nothing in common would be 1
vegdist(hyp_data, method = "manhattan")/max_dist
1 2 3
2 0.0625
3 0.5000 0.4375
4 1.0000 0.9375 0.5000
Sorensen or Bray-Curtis distance
- Percent dissimilarity
- Commonly used with species abundance but it can be used with data of any scale
- Gives less weight to outliers than euclidean
- Retains sensitivity with heteregenous data
- Max when no species are in common
- NOT metric and can not be used with DA, PCA, or CCA
vegdist(hyp_data, method = "bray")
1 2 3
2 0.05263158
3 0.36363636 0.33333333
4 0.80000000 0.78947368 0.36363636
Some other proportional distances exist and differ how they weigh the dissimilarity. Two examples are
vegdist(hyp_data, method = "jaccard")
1 2 3
2 0.1000000
3 0.5333333 0.5000000
4 0.8888889 0.8823529 0.5333333
vegdist(hyp_data, method = "kulczynski")
1 2 3
2 0.0500000
3 0.3583333 0.3194444
4 0.8000000 0.7888889 0.3583333
Euclidean distances based on species profiles
Chord distance
- Similar conceptually to euclidean, but data are row normalized
- Useful in species abundance because it removes differences in total abundance
- Gives low weights to variables with low counts and many zeros
decostand(hyp_data, method = "normalize")
SpeciesA SpeciesB
[1,] 0.1104315 0.9938837
[2,] 0.1240347 0.9922779
[3,] 0.7071068 0.7071068
[4,] 0.9938837 0.1104315
attr(,"decostand")
[1] "normalize"
Chi-square distances
- Euclidean distances after completing a chi-square standardization
- Distance used in correspondance analysis (CA) and canonical correspondance analysis (CCA)
vegdist(decostand(hyp_data, method = "chi.square"), method = "euclidean")
1 2 3
2 0.02255336
3 0.81192099 0.78936762
4 1.62384197 1.60128861 0.81192099
Species profile distance
- Euclidean distances on relative abundance
- Variables with higher values and fewer zeros contribute more to the distance
vegdist(decostand(hyp_data, method = "total", MARGIN = 1), method = "euclidean")
1 2 3
2 0.01571348
3 0.56568542 0.54997194
4 1.13137085 1.11565737 0.56568542
Hellinger distance
- Euclidean distance on the hellinger standardization
- Give low weights to variables with low counts and many zeros
vegdist(decostand(hyp_data, method = "hellinger"), method = "euclidean")
1 2 3
2 0.01808611
3 0.45950584 0.44188477
4 0.89442719 0.87821391 0.45950584
Distances on binary data
pa_data
[,1] [,2] [,3] [,4]
[1,] 0 1 1 1
[2,] 1 1 0 0
[3,] 1 0 1 0
[4,] 0 1 0 1
vegdist(pa_data, binary = TRUE, method = "jaccard")
1 2 3
2 0.7500000
3 0.7500000 0.6666667
4 0.3333333 0.6666667 1.0000000
Binomial
- Null hypothesis two communites are equal
vegdist(pa_data, binary = TRUE, method = "binomial")
1 2 3
2 2.0794415
3 2.0794415 1.3862944
4 0.6931472 1.3862944 2.7725887
Raup
- Probablistic index based on presence/absence data
- Non-metric
vegdist(pa_data, binary = TRUE, method = "raup")
1 2 3
2 1.0000000
3 1.0000000 0.8333333
4 0.5000000 0.8333333 1.0000000
Categorical and mixed data
Gowers distance
- For each variable, a particular distance metric that works well for that data type and is used to scale between 0-1
- Then a linear combination of those user specied weights (most simply an average) is calculated to create the final distance matrix
- for quantitative data = range normalzed Manhattan distance
- ordinal = variable is first ranked then Manhattan with adjustment for ties
- nominal = variables of k categories are first converted into k binary columns and then a Dice coefficient is used
as.matrix(daisy(df, metric = "gower", type = list(asym = c(2,3))))
1 2 3 4 5 6 7
1 0.0000000 0.5749818 0.2292435 0.6173067 0.6699906 0.3176680 0.7372010
2 0.5749818 0.0000000 0.5776599 0.3290653 0.3113710 0.7376149 0.3421992
3 0.2292435 0.5776599 0.0000000 0.6155740 0.6217465 0.2546933 0.6187765
4 0.6173067 0.3290653 0.6155740 0.0000000 0.1165022 0.4421957 0.2865609
5 0.6699906 0.3113710 0.6217465 0.1165022 0.0000000 0.4654749 0.3493142
6 0.3176680 0.7376149 0.2546933 0.4421957 0.4654749 0.0000000 0.6120648
7 0.7372010 0.3421992 0.6187765 0.2865609 0.3493142 0.6120648 0.0000000
8 0.5794467 0.5822714 0.4104376 0.4621400 0.4719496 0.4484787 0.2979355
9 0.4471714 0.6888198 0.6018221 0.5264212 0.6171620 0.5137954 0.4431129
8 9
1 0.5794467 0.4471714
2 0.5822714 0.6888198
3 0.4104376 0.6018221
4 0.4621400 0.5264212
5 0.4719496 0.6171620
6 0.4484787 0.5137954
7 0.2979355 0.4431129
8 0.0000000 0.2853586
9 0.2853586 0.0000000
LS0tDQp0aXRsZTogIkFwcGxpZWQgTXVsdGl2YXJpYXRlOiAgRGlzdGFuY2UgbWF0cmljZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KLmxpYlBhdGhzKCJQOi9STGlicmFyeTIiKQ0KYGBgDQoNCkxvYWQgdGhlIGxpYnJhcmllcyB3ZSB3aWxsIHVzZSB0b2RheQ0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodmVnYW4pDQpsaWJyYXJ5KGNsdXN0ZXIpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmBgYA0KDQojIyMgU2ltaWxhcml0eSBhbmQgZGlzdGFuY2VzDQoNClRvIGlsbHVzdHJhdGUgdGhlIGNvbmNlcHQgb2Ygc2ltaWxhcml0eSBhbmQgZGlzdGFuY2UsIGxldHMgZW52aXNvbiBhIGRhdGEgbWF0cml4IHdpdGggNCBzaXRlcyBhbmQgMiBzcGVjaWVzDQoNCmBgYHtyfQ0KaHlwX2RhdGEgPC0gbWF0cml4KGMoMSw5LDEsOCw2LDYsOSwxKSwgYnlyb3cgPSBUUlVFLCBuY29sID0gMikNCmNvbG5hbWVzKGh5cF9kYXRhKTwtYygiU3BlY2llc0EiLCAiU3BlY2llc0IiKQ0KaHlwX2RhdGENCmBgYA0KDQpMZXRzIHBsb3QgdGhlc2UgaW4gMiBkaW1lbnNpb25zIHRvIHNob3cgdGhlIHJlbGF0aW9uc2hpcHMNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGFzLmRhdGEuZnJhbWUoaHlwX2RhdGEpKSArIA0KICBnZW9tX3BvaW50KGFlcyh4ID0gU3BlY2llc0EsIHk9U3BlY2llc0IpLHNpemUgPSAzLCBjb2xvdXIgPSAicmVkIikgKw0KICBnZW9tX3RleHQoYWVzKHggPSBTcGVjaWVzQSwgeT1TcGVjaWVzQiwgbGFiZWw9IHBhc3RlKCJTaXRlIiwxOjQpKSkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwxMCksIHlsaW0gPSBjKDAsMTApLCBleHBhbmQgPSBGKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQoNCkhvdyBjYW4gd2UgcXVhbnRpZnkgdGhhdCBkaXN0YW5jZT8gIE9uZSBvZiB0aGUgc2ltcGxlc3QgbWV0aG9kcyBpcyB0aGUgRXVjbGlkZWFuIGRpc3RhbmNlDQoNCmBgYHtyfQ0KZXVjX2Rpc3RhbmNlIDwtIGZ1bmN0aW9uKHgseSl7DQogIHggPSB4WzJdIC0geFsxXQ0KICB5ID0geVsyXSAtIHlbMV0NCiAgaCA9IHNxcnQoeF4yICsgeV4yKQ0KICByZXR1cm4oaCkNCn0NCg0KZXVjX2Rpc3RhbmNlKGh5cF9kYXRhW2MoMiwzKSwiU3BlY2llc0EiXSwgaHlwX2RhdGFbYygyLDMpLCJTcGVjaWVzQiJdKQ0KYGBgDQoNClRoZSBwcm9ibGVtIHdpdGggdGhpcyBmdW5jdGlvbiB0aGF0IHdlIHdyb3RlIGlzIHRoYXQgaXRzIG5vdCBlYXNpbHkgYWJsZSB0byBjYWxjdWxhdGUgYWxsIHRoZSBkaXN0YW5jZXMuDQoNCmBgYHtyfQ0KZGlzdChoeXBfZGF0YSkNCg0KZGlzdChoeXBfZGF0YSwgZGlhZyA9IFRSVUUsIHVwcGVyID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCmh5cF9kYXRhMiA8LSBjYmluZChkYXRhLmZyYW1lKGh5cF9kYXRhKSwgZGF0YS5mcmFtZSh4ID0gOSwgeSA9IDEpKQ0KDQpnZ3Bsb3QoZGF0YSA9IGFzLmRhdGEuZnJhbWUoaHlwX2RhdGEpKSArIA0KICBnZW9tX3NlZ21lbnQoZGF0YSA9IGh5cF9kYXRhMiwgYWVzKHggPSB4LCB5ID0geSwgeGVuZCA9IFNwZWNpZXNBLCB5ZW5kID0gU3BlY2llc0IpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSBTcGVjaWVzQSwgeT1TcGVjaWVzQiksc2l6ZSA9IDMsIGNvbG91ciA9ICJyZWQiKSArDQogIGdlb21fdGV4dChhZXMoeCA9IFNwZWNpZXNBLCB5PVNwZWNpZXNCLCBsYWJlbD0gcGFzdGUoIlNpdGUiLDE6NCkpKSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDEwKSwgeWxpbSA9IGMoMCwxMCksIGV4cGFuZCA9IEYpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KIyMjIENvbW1vbiBkaXN0YW5jZSBtZWFzdXJlcyANCg0KVGhlcmUgYXJlIGFwcHJveGltYXRlbHkgMzAgc2ltaWxhcml0eSBvciBkaXN0YW5jZXMgY29tbW9ubHkgdXNlZC4gW0xlZ2VuZHJlIGFuZCBMZWdlbmRyZSAyMDEyXShodHRwOi8vd3d3LmlldmJyYXMucnUvZWNvc3RhdC9LaXJpbC9SL0JpYmxpby9TdGF0aXN0aWMvTGVnZW5kcmUlMjBQLiwlMjBMZWdlbmRyZSUyMEwuJTIwTnVtZXJpY2FsJTIwZWNvbG9neS5wZGYpIA0KDQpUaGUgY2hvaWNlIG9mIHdoaWNoIGRpc3RhbmNlIHlvdSBhcmUgZ29pbmcgdG8gdXNlIGRlcGVuZHMgb24gdGhlIGRhdGEgdHlwZSBhbmQgdGhlIHR5cGUgb2YgYW5hbHlzaXMgeW91IHdpbGwgZG8uIA0KDQojIyMjIEV1Y2xpZGVhbiBkaXN0YW5jZQ0KDQokJCBFRF97aWp9ID0gXHN1bV97aSA9IDF9XnAgXHNxcnR7KHhfe2lqfSAtIHhfe2lrfSleMn0gJCQNCi0gTW9zdCBhcHBlYWxpbmcgbWVhc3VyZSBiZWNhdXNlIGl0IGhhcyB0cnVlICJtZXRyaWMiIHByb3BlcnRpZXMNCi0gQ29sdW1uIHN0YW5kYXJkaXphdGlvbiB0byByZW1vdmUgcG90ZW50aWFsIGlzc3VlcyB3aXRoIHNjYWxlDQotIEFwcGxpZWQgdG8gYW55IGRhdGEgb2YgYW55IHNjYWxlDQotIFVzZWQgaW4gZWlnZW52ZWN0b3Igb3JkaW5hdGlvbnMgKGUuZy4sIFBDQSkNCi0gQXNzdW1lIHRoYXQgdmFyaWFibGVzIGFyZSBub3QgY29ycmVsYXRlZA0KLSBFbXBoYXNpemVzIG91dGxpZXJzIA0KLSBMb29zZSBzZW5zaXRpdml0eSB3aXRoIGhldGVyb2dlbmVvdXMgZGF0YSANCi0gRGlzdGFuY2VzIGFyZSBub3QgcHJvcG9ydGlvbmFsIA0KDQpgYGB7cn0NCnZlZ2Rpc3QoaHlwX2RhdGEsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQ0KYGBgDQoNCmBgYHtyfQ0KZXVjX2Rpc3Q8LWFzLmRhdGEuZnJhbWUoYXMubWF0cml4KHZlZ2Rpc3QoaHlwX2RhdGEsIG1ldGhvZCA9ICJldWNsaWRlYW4iLCBkaWFnID0gVFJVRSwgdXBwZXIgPSBUUlVFKSkpDQoNCmV1Y19kaXN0JHJvdyA8LXJvd25hbWVzKGV1Y19kaXN0KQ0KDQpldWNfZGlzdCAlPiUgDQogIGdhdGhlcihjb2wsIHZhbHVlLCAtcm93KSAlPiUgDQogIG11dGF0ZShjb2wgPSBhcy5udW1lcmljKGNvbCksDQogICAgICAgICByb3cgPSBhcy5udW1lcmljKHJvdykpIC0+IGV1Y19sb25nDQoNCmdncGxvdChkYXRhID0gZXVjX2xvbmcpICsgDQogIGdlb21fcmFzdGVyKGFlcyh4ID0gY29sLCB5ID0gcm93LCBmaWxsID0gdmFsdWUpKSsNCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAicmVkIiwgaGlnaCA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgbWlkcG9pbnQgPSA1KSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KDQpgYGANCg0KIyMjIyBDaXR5IGJsb2NrIChNYW5oYXR0YW4pIGRpc3RhbmNlDQoNCi0gTW9zdCBlY29sb2dpY2FsbHkgbWVhbmluZ2Z1bCBkaXNzaW1pbGFyaXRpZXMgYXJlIE1hbmhhdHRhbiB0eXBlcw0KLSBMZXNzIHdlaWdodCB0byBvdXRsaWVycyBjb21wYXJlZCB0byBFdWNsaWRlYW4NCi0gUmV0YWlucyBzZW5zaXRpdml0eSB3aXRoIGhldGVyb2dlbm91cyBkYXRhDQotIERpc3RhbmNlcyBhcmUgbm90IHByb3BvcnRpb25hbCANCg0KYGBge3J9DQp2ZWdkaXN0KGh5cF9kYXRhLCBtZXRob2QgPSAibWFuaGF0dGFuIikNCmBgYA0KDQojIyMjIFByb3BvcnRpb25hbCBkaXN0YW5jZXMNCg0KLSBNYW5oYXR0YW4gZGlzdGFuY2VzIGV4cHJlc3NlZCBhcyBhIHByb3BvcnRpb24gb2YgdGhlIG1heCBkaXN0YW5jZQ0KLSAyIGNvbW11bml0aWVzIHdpdGggbm90aGluZyBpbiBjb21tb24gd291bGQgYmUgMQ0KDQpgYGB7cn0NCm1heF9kaXN0IDwtIG1heCh2ZWdkaXN0KGh5cF9kYXRhLCBtZXRob2QgPSAibWFuaGF0dGFuIikpDQoNCnZlZ2Rpc3QoaHlwX2RhdGEsIG1ldGhvZCA9ICJtYW5oYXR0YW4iKS9tYXhfZGlzdA0KYGBgDQoNCiMjIyMgU29yZW5zZW4gb3IgQnJheS1DdXJ0aXMgZGlzdGFuY2UNCg0KLSBQZXJjZW50IGRpc3NpbWlsYXJpdHkNCi0gQ29tbW9ubHkgdXNlZCB3aXRoIHNwZWNpZXMgYWJ1bmRhbmNlIGJ1dCBpdCBjYW4gYmUgdXNlZCB3aXRoIGRhdGEgb2YgYW55IHNjYWxlDQotIEdpdmVzIGxlc3Mgd2VpZ2h0IHRvIG91dGxpZXJzIHRoYW4gZXVjbGlkZWFuDQotIFJldGFpbnMgc2Vuc2l0aXZpdHkgd2l0aCBoZXRlcmVnZW5vdXMgZGF0YQ0KLSBNYXggd2hlbiBubyBzcGVjaWVzIGFyZSBpbiBjb21tb24NCi0gTk9UIG1ldHJpYyBhbmQgY2FuIG5vdCBiZSB1c2VkIHdpdGggREEsIFBDQSwgb3IgQ0NBDQoNCmBgYHtyfQ0KdmVnZGlzdChoeXBfZGF0YSwgbWV0aG9kID0gImJyYXkiKQ0KYGBgDQoNClNvbWUgb3RoZXIgcHJvcG9ydGlvbmFsIGRpc3RhbmNlcyBleGlzdCBhbmQgZGlmZmVyIGhvdyB0aGV5IHdlaWdoIHRoZSBkaXNzaW1pbGFyaXR5LiAgVHdvIGV4YW1wbGVzIGFyZSANCg0KLSBKYWNjYXJkcyBkaXN0YW5jZQ0KDQpgYGB7cn0NCnZlZ2Rpc3QoaHlwX2RhdGEsIG1ldGhvZCA9ICJqYWNjYXJkIikNCmBgYA0KDQotIEt1bGN6eW5za2kgZGlzdGFuY2UgDQoNCmBgYHtyfQ0KdmVnZGlzdChoeXBfZGF0YSwgbWV0aG9kID0gImt1bGN6eW5za2kiKQ0KYGBgDQoNCiMjIyBFdWNsaWRlYW4gZGlzdGFuY2VzIGJhc2VkIG9uIHNwZWNpZXMgcHJvZmlsZXMNCg0KIyMjIyBDaG9yZCBkaXN0YW5jZSANCg0KLSBTaW1pbGFyIGNvbmNlcHR1YWxseSB0byBldWNsaWRlYW4sIGJ1dCBkYXRhIGFyZSByb3cgbm9ybWFsaXplZA0KLSBVc2VmdWwgaW4gc3BlY2llcyBhYnVuZGFuY2UgYmVjYXVzZSBpdCByZW1vdmVzIGRpZmZlcmVuY2VzIGluIHRvdGFsIGFidW5kYW5jZQ0KLSBHaXZlcyBsb3cgd2VpZ2h0cyB0byB2YXJpYWJsZXMgd2l0aCBsb3cgY291bnRzIGFuZCBtYW55IHplcm9zDQoNCmBgYHtyfQ0KdmVnZGlzdChkZWNvc3RhbmQoaHlwX2RhdGEsIG1ldGhvZCA9ICJub3JtYWxpemUiKSwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQpgYGANCg0KIyMjIyBDaGktc3F1YXJlIGRpc3RhbmNlcw0KDQotIEV1Y2xpZGVhbiBkaXN0YW5jZXMgYWZ0ZXIgY29tcGxldGluZyBhIGNoaS1zcXVhcmUgc3RhbmRhcmRpemF0aW9uDQotIERpc3RhbmNlIHVzZWQgaW4gY29ycmVzcG9uZGFuY2UgYW5hbHlzaXMgKENBKSBhbmQgY2Fub25pY2FsIGNvcnJlc3BvbmRhbmNlIGFuYWx5c2lzIChDQ0EpDQoNCg0KYGBge3J9DQp2ZWdkaXN0KGRlY29zdGFuZChoeXBfZGF0YSwgbWV0aG9kID0gImNoaS5zcXVhcmUiKSwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQpgYGANCg0KIyMjIyBTcGVjaWVzIHByb2ZpbGUgZGlzdGFuY2UgDQoNCi0gRXVjbGlkZWFuIGRpc3RhbmNlcyBvbiByZWxhdGl2ZSBhYnVuZGFuY2UNCi0gVmFyaWFibGVzIHdpdGggaGlnaGVyIHZhbHVlcyBhbmQgZmV3ZXIgemVyb3MgY29udHJpYnV0ZSBtb3JlIHRvIHRoZSBkaXN0YW5jZQ0KDQpgYGB7cn0NCg0KdmVnZGlzdChkZWNvc3RhbmQoaHlwX2RhdGEsIG1ldGhvZCA9ICJ0b3RhbCIsIE1BUkdJTiA9IDEpLCBtZXRob2QgPSAiZXVjbGlkZWFuIikNCmBgYA0KDQojIyMjIEhlbGxpbmdlciBkaXN0YW5jZQ0KDQotIEV1Y2xpZGVhbiBkaXN0YW5jZSBvbiB0aGUgaGVsbGluZ2VyIHN0YW5kYXJkaXphdGlvbg0KLSBHaXZlIGxvdyB3ZWlnaHRzIHRvIHZhcmlhYmxlcyB3aXRoIGxvdyBjb3VudHMgYW5kIG1hbnkgemVyb3MNCg0KYGBge3J9DQp2ZWdkaXN0KGRlY29zdGFuZChoeXBfZGF0YSwgbWV0aG9kID0gImhlbGxpbmdlciIpLCBtZXRob2QgPSAiZXVjbGlkZWFuIikNCmBgYA0KDQojIyMgRGlzdGFuY2VzIG9uIGJpbmFyeSBkYXRhDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzNCkNCnBhX2RhdGEgPC0gbWF0cml4KGMoc2FtcGxlKGMoMCwxKSwgOCwgcmVwbGFjZSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICBzYW1wbGUoYygwLDEpLCA4LCBwcm9iID0gYygwLjY1LCAwLjM1KSxyZXBsYWNlID0gVFJVRSkpLA0KICAgICAgICAgICAgICAgICAgYnlyb3cgPSBUUlVFLCBuY29sID0gNCkNCnBhX2RhdGENCg0KDQpgYGANCg0KYGBge3J9DQp2ZWdkaXN0KHBhX2RhdGEsIGJpbmFyeSA9IFRSVUUsIG1ldGhvZCA9ICJqYWNjYXJkIikNCmBgYA0KDQojIyMjIEJpbm9taWFsDQoNCi0gTnVsbCBoeXBvdGhlc2lzICB0d28gY29tbXVuaXRlcyBhcmUgZXF1YWwNCg0KYGBge3J9DQp2ZWdkaXN0KHBhX2RhdGEsIGJpbmFyeSA9IFRSVUUsIG1ldGhvZCA9ICJiaW5vbWlhbCIpDQpgYGANCg0KIyMjIyBSYXVwIA0KLSBQcm9iYWJsaXN0aWMgaW5kZXggYmFzZWQgb24gcHJlc2VuY2UvYWJzZW5jZSBkYXRhDQotIE5vbi1tZXRyaWMNCg0KYGBge3J9DQp2ZWdkaXN0KHBhX2RhdGEsIGJpbmFyeSA9IFRSVUUsIG1ldGhvZCA9ICJyYXVwIikNCmBgYA0KDQoNCiMjIyMgQ2F0ZWdvcmljYWwgYW5kIG1peGVkIGRhdGEgDQoNCiMjIyMgR293ZXJzIGRpc3RhbmNlDQotIEZvciBlYWNoIHZhcmlhYmxlLCBhIHBhcnRpY3VsYXIgZGlzdGFuY2UgbWV0cmljIHRoYXQgd29ya3Mgd2VsbCBmb3IgdGhhdCBkYXRhIHR5cGUgYW5kIGlzIHVzZWQgdG8gc2NhbGUgYmV0d2VlbiAwLTENCi0gVGhlbiBhIGxpbmVhciBjb21iaW5hdGlvbiBvZiB0aG9zZSB1c2VyIHNwZWNpZWQgd2VpZ2h0cyAobW9zdCBzaW1wbHkgYW4gYXZlcmFnZSkgaXMgY2FsY3VsYXRlZCB0byBjcmVhdGUgdGhlIGZpbmFsIGRpc3RhbmNlIG1hdHJpeCANCiAgICAtIGZvciBxdWFudGl0YXRpdmUgZGF0YSA9IHJhbmdlIG5vcm1hbHplZCBNYW5oYXR0YW4gZGlzdGFuY2UNCiAgICAtIG9yZGluYWwgPSB2YXJpYWJsZSBpcyBmaXJzdCByYW5rZWQgdGhlbiBNYW5oYXR0YW4gd2l0aCBhZGp1c3RtZW50IGZvciB0aWVzDQogICAgLSBub21pbmFsID0gdmFyaWFibGVzIG9mIGsgY2F0ZWdvcmllcyBhcmUgZmlyc3QgY29udmVydGVkIGludG8gayBiaW5hcnkgY29sdW1ucyBhbmQgdGhlbiBhIERpY2UgY29lZmZpY2llbnQgaXMgdXNlZA0KICAgIA0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQojIENyZWF0ZSBhIG5vbWlhbCB2YXJpYWJsZSANCm5vbSA8LSBmYWN0b3IocmVwKGxldHRlcnNbMTozXSwgZWFjaCA9IDMpKQ0KDQojIENyZWF0ZSBzb21lIGJpbmFyeSBkYXRhDQpiaW4gPC0gYXMubWF0cml4KHJlcGxpY2F0ZSgyLCByZXAoc2FtcGxlKGMoMCwxKSwgOSwgcmVwbGFjZSA9IFRSVUUpKSkpDQoNCiNOdW1lcmljYWwgdmFyaWFibGVzDQp2YXJzIDwtIGFzLm1hdHJpeChyZXBsaWNhdGUoMywgcm5vcm0oOSkpKQ0KDQpkZiA8LSBkYXRhLmZyYW1lKG5vbSwgYmluLCB2YXJzKQ0KDQoNCmFzLm1hdHJpeChkYWlzeShkZiwgbWV0cmljID0gImdvd2VyIiwgdHlwZSA9IGxpc3QoYXN5bSA9IGMoMiwzKSkpKQ0KYGBgDQoNCg==