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

  • Jaccards distance
vegdist(hyp_data, method = "jaccard")
          1         2         3
2 0.1000000                    
3 0.5333333 0.5000000          
4 0.8888889 0.8823529 0.5333333
  • Kulczynski distance
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==