knitr::opts_chunk$set(echo = TRUE)

Definition of a distance

Exercice 1

  • Prove that the three axioms A1-A3 imply the non-negativity condition: \[d(\mathbf{x},\mathbf{y})\geq 0.\]

Euclidean distance

\[d(\mathbf{x},\mathbf{y})=\sqrt{\sum_{i=1}^n (x_i-y_i)^2}.\] * A1A2 ae onbvious. * The proof of A3 is provided below.

Manhattan distance

\[d(\mathbf{x},\mathbf{y}) =\sum_{i=1}^n |x_i-y_i|. \]

Manhattan distance vs Euclidean distance Graph

x = c(0, 0)
y = c(6,6)
dist(rbind(x, y), method = "euclidian")
         x
y 8.485281
6*sqrt(2)
[1] 8.485281
dist(rbind(x, y), method = "manhattan")
   x
y 12

Canberra distance

\[d(\mathbf{x},\mathbf{y}) =\sum_{i=1}^n \frac{|x_i-y_i|}{|x_i|+|y_i|}.\]

x = c(0, 0)
y = c(6,6)
dist(rbind(x, y), method = "canberra")
  x
y 2
6/6+6/6
[1] 2

Exercice 2

  • Prove that the Canberra distance is a true distance.

Minkowski distance

library("ggplot2")
x = c(0, 0)
y = c(6,6)
MinkowDist=c()
for (p in seq(1,30,.01))
{
MinkowDist=c(MinkowDist,dist(rbind(x, y), method = "minkowski", p = p))     
}
ggplot(data =data.frame(x = seq(1,30,.01), y=MinkowDist ) , mapping = aes(x = x, y = y))+geom_point(size=.1,color="red")+xlim(1,11)+xlab("p")+ylab("Minkowski Distance")+ggtitle("Minkowski distance wrt p")

Chebyshev distance

Minkowski inequality

Hölder inequality

\[ |\sum_{i=1}^nx_iy_i|\leq\sqrt{\sum_{i=1}^n x_i^2}\sqrt{\sum_{i=1}^n y_i^2}. \] * Using the dot product notation called also scalar product noation: \(\mathbf{x\cdot y}=\sum_{i=1}^nx_iy_i\), and the norm notation \(\|\mathbf{\cdot}\|_2 \|\), the Cauchy-Schwart inequality is: \[ |\mathbf{x\cdot y} | \leq \|\mathbf{x}\|_2 \| \mathbf{y}\|_2. \]

Pearson correlation distance

Cosine correlation distance

Spearman correlation distance

x=c(3, 1, 4, 15, 92)
rank(x)
[1] 2 1 3 4 5
x=c(3, 1, 4, 15, 92)
rank(x)
[1] 2 1 3 4 5
y=c(30,2 , 9, 20, 48)
rank(y)
[1] 4 1 2 3 5
d=rank(x)-rank(y)
d
[1] -2  0  1  1  0
cor(rank(x),rank(y))
[1] 0.7
1-6*sum(d^2)/(5*(5^2-1))
[1] 0.7

Kendall tau distance

x=c(3, 1, 4, 15, 92)
y=c(30,2 , 9, 20, 48)
tau=0
for (i in 1:5)
{  
tau=tau+sign(x -x[i])%*%sign(y -y[i])
}
tau=tau/(5*4)
tau
     [,1]
[1,]  0.6
cor(x,y, method="kendall")
[1] 0.6

Variables standardization

x=c(3, 1, 4, 15, 92)
y=c(30,2 , 9, 20, 48)
(x-mean(x))/sd(x)
[1] -0.5134116 -0.5647527 -0.4877410 -0.2053646  1.7712699
scale(x)
           [,1]
[1,] -0.5134116
[2,] -0.5647527
[3,] -0.4877410
[4,] -0.2053646
[5,]  1.7712699
attr(,"scaled:center")
[1] 23
attr(,"scaled:scale")
[1] 38.9551
(y-mean(y))/sd(y)
[1]  0.45263128 -1.09293895 -0.70654639 -0.09935809
[5]  1.44621214
scale(y)
            [,1]
[1,]  0.45263128
[2,] -1.09293895
[3,] -0.70654639
[4,] -0.09935809
[5,]  1.44621214
attr(,"scaled:center")
[1] 21.8
attr(,"scaled:scale")
[1] 18.11629

Distance matrix computation

install.packages("FactoMineR")
Error in install.packages : Updating loaded packages
library("FactoMineR")
data("USArrests") # Loading
head(USArrests, 3) # Print the first 3 rows
set.seed(123)
ss <- sample(1:50, 15) # Take 15 random rows
df <- USArrests[ss, ] # Subset the 15 rows
df.scaled <- scale(df) # Standardize the variables
LS0tCnRpdGxlOiAiRGlzdGFuY2UgYW5kIGRpc3NpbWlsYXJpdGllcyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCgoKIyBEZWZpbml0aW9uIG9mIGEgZGlzdGFuY2UKCiogQSBkaXN0YW5jZSBmdW5jdGlvbiBvciBhIG1ldHJpYyBvbiAkXG1hdGhiYntSfV5uLFw6blxnZXEgMSQsIGlzIGEgZnVuY3Rpb24gJGQ6XG1hdGhiYntSfV5uXHRpbWVzXG1hdGhiYntSfV5uXHJpZ2h0YXJyb3cgXG1hdGhiYntSfSQuCiogQSBkaXN0YW5jZSBmdW5jdGlvbiBtdXN0IHNhdGlzZnkgc29tZSByZXF1aXJlZCBwcm9wZXJ0aWVzIG9yIGF4aW9tcy4gCiogVGhlcmUgYXJlIHRocmVlIG1haW4gYXhpb21zLgoqIEExLiAkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPSAwXGlmZiBcbWF0aGJme3h9PVxtYXRoYmZ7eX0kIChpZGVudGl0eSBvZiBpbmRpc2Nlcm5pYmxlcyk7CiogQTIuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9IGQoXG1hdGhiZnt5fSxcbWF0aGJme3h9KSQgKHN5bW1ldHJ5KTsKCiogQTMuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt6fSlcbGVxIGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KStkKFxtYXRoYmZ7eX0sXG1hdGhiZnt6fSkkICAodHJpYW5nbGUgaW5lcXVhbGl0eSksCndoZXJlICRcbWF0aGJme3h9PSh4XzEsXGNkb3RzLHhfbikkLCAkXG1hdGhiZnt5fT0oeV8xLFxjZG90cyx5X24pJCBhbmQgJFxtYXRoYmZ7en09KHpfMSxcY2RvdHMsel9uKSQgYXJlIGFsbCB2ZWN0b3JzIG9mICRcbWF0aGJie1J9Xm4kLgoqIFdlIHNob3VsZCB1c2UgdGhlIHRlcm0gX2Rpc3NpbWlsYXJpdHlfIHJhdGhlciB0aGFuIF9kaXN0YW5jZV8gd2hlbiBub3QgYWxsIHRoZSB0aHJlZSBheGlvbXMgQTEtQTMgYXJlIHZhbGlkLgoqIE1vc3Qgb2YgdGhlIHRpbWUsIHdlIHNoYWxsIHVzZSwgd2l0aCBzb21lIGFidXNlIG9mIHZvY2FidWxhcnksIHRoZSB0ZXJtIGRpc3RhbmNlLgoKIyMgRXhlcmNpY2UgMQoKKiBQcm92ZSB0aGF0IHRoZSB0aHJlZSBheGlvbXMgQTEtQTMgaW1wbHkgdGhlIG5vbi1uZWdhdGl2aXR5IGNvbmRpdGlvbjogJCRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSlcZ2VxIDAuJCQKCgojIEV1Y2xpZGVhbiBkaXN0YW5jZQoKCiogSXQgaXMgZGVmaW5lZCBieToKCiQkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPVxzcXJ0e1xzdW1fe2k9MX1ebiAoeF9pLXlfaSleMn0uJCQKKiBBMUEyIGFlIG9uYnZpb3VzLgoqIFRoZSBwcm9vZiBvZiBBMyBpcyBwcm92aWRlZCBiZWxvdy4KCgojIE1hbmhhdHRhbiBkaXN0YW5jZQoKKiBUaGUgTWFuaGF0dGFuIGRpc3RhbmNlIGFsc28gY2FsbGVkICB0YXhpLWNhYiBtZXRyaWMgb3IgY2l0eS1ibG9jayBtZXRyaWMgaXMgZGVmaW5lZCBieToKCiQkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pCj1cc3VtX3tpPTF9Xm4gfHhfaS15X2l8LgokJAoKKiBBMS1BMiBob2xkLgoqIEEzIGFsc28gaG9sZHMgdXNpbmcgdGhlIGZhY3QgdGhhdCAkfGErYnxcbGVxIHxhfCt8YnwkIGZvciBhbnkgcmVhbHMgJGEsYiQuCiogVGhlcmUgZXhpc3RzIGFsc28gYSB3ZWlnaHRlZCB2ZXJzaW9uICBvZiB0aGUgTWFuaGF0dGFuIGRpc3RhbmNlIGNhbGxlZCB0aGUgQ2FuYmVycmEgZGlzdGFuY2UuCgpbTWFuaGF0dGFuIGRpc3RhbmNlIHZzIEV1Y2xpZGVhbiBkaXN0YW5jZSBHcmFwaF0oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy8wLzA4L01hbmhhdHRhbl9kaXN0YW5jZS5zdmcpCgpgYGB7cn0KeCA9IGMoMCwgMCkKeSA9IGMoNiw2KQpkaXN0KHJiaW5kKHgsIHkpLCBtZXRob2QgPSAiZXVjbGlkaWFuIikKNipzcXJ0KDIpCmRpc3QocmJpbmQoeCwgeSksIG1ldGhvZCA9ICJtYW5oYXR0YW4iKQpgYGAKCgojIENhbmJlcnJhIGRpc3RhbmNlCgoqIEl0IGlzIGRlZmluZWQgYnk6CgokJGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KQo9XHN1bV97aT0xfV5uIFxmcmFje3x4X2kteV9pfH17fHhfaXwrfHlfaXx9LiQkCgoqIE5vdGUgdGhhdCB0aGUgdGVybSAkfHhfaSDiiJIgeV9pfC8ofHhfaXwrfHlfaXwpJCBpcyBub3QgcHJvcGVybHkgZGVmaW5lZCB3aGVuICR4X2k9eV9pPTAkLgoqIEJ5IGNvbnZlbnRpb24gd2Ugc2V0IHRoZSByYXRpbyB0byBiZSB6ZXJvIGluIHRoYXQgY2FzZS4KKiBUaGUgQ2FuYmVycmEgZGlzdGFuY2UgaXMgc3BlY2lhbGx5IHNlbnNpdGl2ZSB0byBzbWFsbCBjaGFuZ2VzIG5lYXIgemVyby4KCgpgYGB7cn0KeCA9IGMoMCwgMCkKeSA9IGMoNiw2KQpkaXN0KHJiaW5kKHgsIHkpLCBtZXRob2QgPSAiY2FuYmVycmEiKQo2LzYrNi82CmBgYAoKCiMjIEV4ZXJjaWNlIDIKCiogUHJvdmUgdGhhdCB0aGUgQ2FuYmVycmEgZGlzdGFuY2UgaXMgYSB0cnVlIGRpc3RhbmNlLgoKIyBNaW5rb3dza2kgZGlzdGFuY2UKKiBCb3RoIHRoZSBFdWNsaWRpYW4gYW5kIHRoZSBNYW5hdHRhbiBkaXN0YW5jZXMgYXJlIHNwZWNpYWwgY2FzZXMgb2YgIHRoZSBNaW5rb3dza2kgZGlzdGFuY2Ugd2hpY2ggaXMgZGVmaW5lZCwgZm9yICRwXGdlcSAxJCwgYnk6IAokJApkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9ClxsZWZ0W1xzdW1fe2k9MX0gfHhfaS15X2l8XntwfVxyaWdodF1eezEvcH0uCiQkCiAqIEZvciAkcD0xJCwgd2UgZ2V0IHRoZSBNYW5oYXR0YW4gZGlzdGFuY2UuCiAqIEZvciAkcD0yJCwgd2UgZ2V0IHRoZSBFdWNsaWRpYW4gZGlzdGFuY2UuCiogTGV0IHVzIGFsc28gZGVmaW5lOiAKJCRcfFxtYXRoYmZ7eH1cfF9wXGVxdWl2XGxlZnRbXHN1bV97aT0xfV5uIHx4X2l8XntwfVxyaWdodF1eezEvcH0sJCQKd2hlcmUgJFx8XG1hdGhiZntcY2RvdH1cfF9wJCBpcyBrbm93biBhcyB0aGUgJHAkLW5vcm0gb3IgTWlua293c2tpIG5vcm0uCiogTm90ZSB0aGF0IHRoZSBNaW5rb3dza2kgZGlzdGFuY2UgYW5kIG5vcm0gYXJlIHJlbGF0ZWQgYnk6CiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT1cfFxtYXRoYmZ7eH0tXG1hdGhiZnt5fVx8X3AuCiQkCiogQ29udmVyc2VseSwgd2UgaGF2ZToKJCQKXHxcbWF0aGJme3h9XHxfcD1kKFxtYXRoYmZ7eH0sXG1hdGhiZnswfSksCiQkCndoZXJlICRcbWF0aGJmezB9JCBpcyB0aGUgbnVsbC12ZXRvciBvZiAkXG1hdGhiYntSfV5uJC4KCmBgYHtyfQpsaWJyYXJ5KCJnZ3Bsb3QyIikKeCA9IGMoMCwgMCkKeSA9IGMoNiw2KQpNaW5rb3dEaXN0PWMoKQpmb3IgKHAgaW4gc2VxKDEsMzAsLjAxKSkKewpNaW5rb3dEaXN0PWMoTWlua293RGlzdCxkaXN0KHJiaW5kKHgsIHkpLCBtZXRob2QgPSAibWlua293c2tpIiwgcCA9IHApKSAgICAgCn0KZ2dwbG90KGRhdGEgPWRhdGEuZnJhbWUoeCA9IHNlcSgxLDMwLC4wMSksIHk9TWlua293RGlzdCApICwgbWFwcGluZyA9IGFlcyh4ID0geCwgeSA9IHkpKStnZW9tX3BvaW50KHNpemU9LjEsY29sb3I9InJlZCIpK3hsaW0oMSwxMSkreGxhYigicCIpK3lsYWIoIk1pbmtvd3NraSBEaXN0YW5jZSIpK2dndGl0bGUoIk1pbmtvd3NraSBkaXN0YW5jZSB3cnQgcCIpCmBgYAoKIyBDaGVieXNoZXYgZGlzdGFuY2UgCiogQXQgdGhlIGxpbWl0LCB3ZSBnZXQgdGhlIENoZWJ5c2hldiBkaXN0YW5jZSB3aGljaCBpcyBkZWZpbmVkIGJ5OgokJApkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9XG1heF97aT0xLFxjZG90cyxufSh8eF9pLXlfaXwpPVxsaW1fe3BccmlnaHRhcnJvd1xpbmZ0eX0KXGxlZnRbXHN1bV97aT0xfSB8eF9pLXlfaXxee3B9XHJpZ2h0XV57MS9wfS4KJCQKKiBUaGUgY29ycmVzcG9uZGluZyBub3JtIGlzOgokJApcfFxtYXRoYmZ7eH18X1xpbmZ0eT1cbWF4X3tpPTEsXGNkb3RzLG59KHx4X2l8KS4KJCQKCiMgTWlua293c2tpIGluZXF1YWxpdHkKCiogVGhlIHByb29mIG9mIHRoZSB0cmlhbmd1bGFyIGluZXF1YWxpdHkgQTMgaXMgYmFzZWQgb24gdGhlIE1pbmtvd3NraSBpbmVxdWFsaXR5OgoqIEZvciBhbnkgbm9ubmVnYXRpdmUgcmVhbCBudW1iZXJzICRhXzEsXGNkb3RzLGFfbiQ7ICRiXzEsXGNkb3RzLGJfbiQsIGFuZCBmb3IgYW55ICRwXGdlcSAxJCwgd2UgaGF2ZToKJCQKXGxlZnRbXHN1bV97aT0xfV5uIChhX2krYl9pKV57cH1ccmlnaHRdXnsxL3B9XGxlcQpcbGVmdFtcc3VtX3tpPTF9Xm4gYV9pXntwfVxyaWdodF1eezEvcH0KK1xsZWZ0W1xzdW1fe2k9MX1ebiBiX2lee3B9XHJpZ2h0XV57MS9wfS4KJCQKKiBUbyBwcm92ZSB0aGF0IHRoZSBNaW5rb3dza2kgZGlzdGFuY2Ugc2F0aXNmaWVzIEEzLCBub3RpY2UgdGhhdCAKJCQKIFxzdW1fe2k9MX1ebnx4X2ktel9pfF57cH09IFxzdW1fe2k9MX1ebnwoeF9pLXlfaSkrKHlfaS16X2kpfF57cH0uCiQkCiogU2luY2UgZm9yIGFueSByZWFscyAkeCx5JCwgd2UgaGF2ZTogJHx4K3l8XGxlcSB8eHwrfHl8JCwgYW5kIHVzaW5nIHRoZSBmYWN0IHRoYXQgJHhecCQgaXMgaW5jcmVhc2luZyBpbiAkeFxnZXEgMCQsIHdlIG9idGFpbjoKJCQKIFxzdW1fe2k9MX1ebnx4X2ktel9pfF57cH1cbGVxIFxzdW1fe2k9MX1ebih8eF9pLXlfaXwrfHlfaS16X2l8KV57cH0uCiQkCgoqIEFwcGx5aW5nIHRoZSBNaW5rb3dza2kgaW5lcXVhbGl0eSB3aXRoICRhX2k9fHhfaS15X2l8JCBhbmQgJGJfaT18eV9pLXpfaXwkLCAkaT0xLFxjZG90cyxuJCwgd2UgZ2V0OgokJAogXHN1bV97aT0xfV5ufHhfaS16X2l8XntwfVxsZXEgXGxlZnQoXHN1bV97aT0xfV5uIHx4X2kteV9pfF57cH1ccmlnaHQpXnsxL3B9K1xsZWZ0KFxzdW1fe2k9MX1ebiB8eV9pLXpfaXxee3B9XHJpZ2h0KV57MS9wfS4KJCQKCiMgSMO2bGRlciBpbmVxdWFsaXR5CgoqIFRoZSBwcm9vZiBvZiB0aGUgTWlua293c2tpIGluZXF1YWxpdHkgaXRzZWxmIHJlcXVpcmVzIHRoZSBIw7ZsZGVyIGluZXF1YWxpdHk6CiogRm9yIGFueSBub25uZWdhdGl2ZSByZWFsIG51bWJlcnMgJGFfMSxcY2RvdHMsYV9uJDsgJGJfMSxcY2RvdHMsYl9uJCwgYW5kIGFueSAkcCxxPjEkIHdpdGggJDEvcCsxL3E9MSQsIHdlIGhhdmU6CiQkClxzdW1fe2k9MX1ebiBhX2liX2lcbGVxClxsZWZ0W1xzdW1fe2k9MX1ebiBhX2lee3B9XHJpZ2h0XV57MS9wfQpcbGVmdFtcc3VtX3tpPTF9Xm4gYl9pXntxfVxyaWdodF1eezEvcX0KJCQKKiBUaGUgcHJvb2Ygb2YgdGhlIEjDtmxkZXIgaW5lcXVhbGl0eSByZWxpZXMgb24gdGhlIFlvdW5nIGluZXF1YWxpdHk6CiogRm9yIGFueSAkYSxiPjAkLCB3ZSBoYXZlCiQkCmFiXGxlcSBcZnJhY3thXnB9e3B9K1xmcmFje2JecX17cX0sCiQkCndpdGggZXF1YWxpdHkgb2NjdXJpbmcgaWZmOiAkYV5wPWJecSQuIAoqIFRvIHByb3ZlIHRoZSBZb3VuZyBpbmVxdWFsaXR5LCBvbmUgY2FuIHVzZSB0aGUgKHN0cmljdCkgY29udmV4aXR5IG9mIHRoZSBleHBvbmVudGlhbCBmdW5jdGlvbi4KKiBGb3IgYW55IHJlYWxzICR4LHkkLCB3ZSBoYXZlOgokJAplXntcZnJhY3t4fXtwfStcZnJhY3t5fXtxfSB9XGxlcSBcZnJhY3tlXnt4fX17cH0rXGZyYWN7ZV57eX19e3F9LiAKJCQKKiBXZSB0aGVuIHNldDogJHg9cFxsbiBhJCBhbmQgJHk9cVxsbiBiJCB0byBnZXQgdGhlIFlvdW5nIGluZXF1YWxpdHkuCiogQSBnb29kIHJlZmVyZW5jZSBvbiBpbmVxdWFsaXRpZXMgaXM6IFouIEN2ZXRrb3Zza2ksICBJbmVxdWFsaXRpZXM6IHRoZW9yZW1zLCB0ZWNobmlxdWVzIGFuZCBzZWxlY3RlZCBwcm9ibGVtcywgMjAxMiwgU3ByaW5nZXIgU2NpZW5jZSAmIEJ1c2luZXNzIE1lZGlhLgogIyBDYXVjaHktU2Nod2FydHogaW5lcXVhbGl0eQoqIE5vdGUgdGhhdCB0aGUgdHJpYW5ndWxhciBpbmVxdWFsaXR5IGZvciB0aGUgTWlua293c2tpIGRpc3RhbmNlIGltcGxpZXM6IAokJApcc3VtX3tpPTF9Xm4gfHhfaXxcbGVxClxsZWZ0W1xzdW1fe2k9MX1ebiB8eF9pfF57cH1ccmlnaHRdXnsxL3B9LgokJAoqIE5vdGUgdGhhdCBmb3IgJHA9MiQsIHdlIGhhdmUgJHE9MiQuIFRoZSBIw7ZsZGVyIGluZXF1YWxpdHkgaW1wbGllcyBmb3IgdGhhdCBzcGVjaWFsIGNhc2UKJCQKXHN1bV97aT0xfV5ufHhfaXlfaXxcbGVxXHNxcnR7XHN1bV97aT0xfV5uIHhfaV4yfVxzcXJ0e1xzdW1fe2k9MX1ebiB5X2leMn0uIAokJAoqIFNpbmNlIHRoZSBMSFMgb2QgdGhlcyBhYm92ZSBpbmVxdWFsaXR5IGlzIGdyZWF0ZXIgdGhlbiAkfFxzdW1fe2k9MX1ebnhfaXlfaXwkLCB3ZSBnZXQgdGhlIENhdWNoeS1TY2h3YXJ0eiBpbmVxdWFsaXR5CgokJAp8XHN1bV97aT0xfV5ueF9peV9pfFxsZXFcc3FydHtcc3VtX3tpPTF9Xm4geF9pXjJ9XHNxcnR7XHN1bV97aT0xfV5uIHlfaV4yfS4gCiQkCiogVXNpbmcgdGhlIGRvdCBwcm9kdWN0IG5vdGF0aW9uIGNhbGxlZCBhbHNvIHNjYWxhciBwcm9kdWN0IG5vYXRpb246ICRcbWF0aGJme3hcY2RvdCB5fT1cc3VtX3tpPTF9Xm54X2l5X2kkLCBhbmQgdGhlIG5vcm0gbm90YXRpb24gJFx8XG1hdGhiZntcY2RvdH1cfF8yIFx8JCwgdGhlIENhdWNoeS1TY2h3YXJ0IGluZXF1YWxpdHkgaXM6CiQkCnxcbWF0aGJme3hcY2RvdCB5fSB8IFxsZXEgXHxcbWF0aGJme3h9XHxfMiBcfCBcbWF0aGJme3l9XHxfMi4KJCQKCiMgUGVhcnNvbiBjb3JyZWxhdGlvbiBkaXN0YW5jZSAKCiogVGhlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgYSBzaW1pbGFyaXR5IG1lYXN1cmUgb24gJFxtYXRoYmJ7Un1ebiQgZGVmaW5lZCBieToKJCQKXHJobyhcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPQpcZnJhY3tcc3VtX3tpPTF9Xm4gKHhfaS1cYmFye1xtYXRoYmZ7eH19KSh5X2ktXGJhcntcbWF0aGJme3l9fSl9e3tcc3FydHtcc3VtX3tpPTF9Xm4gKHhfaS1cYmFye1xtYXRoYmZ7eH19KV4yXHN1bV97aT0xfV5uICh5X2ktXGJhcntcbWF0aGJme3l9fSleMn19fSwKJCQKd2hlcmUgJFxiYXJ7XG1hdGhiZnt4fX0kIGlzIHRoZSBtZWFuIG9mIHRoZSB2ZWN0b3IgJFxtYXRoYmZ7eH0kIGRlZmluZWQgYnk6IAokJFxiYXJ7XG1hdGhiZnt4fX09XGZyYWN7MX17bn1cc3VtX3tpPTF9Xm4geF9pLCQkCiogTm90ZSB0aGF0IHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IHNhdGlzZmllcyBQMiBhbmQgIGlzIGludmFyaWFudCB0byBhbnkgcG9zaXRpdmUgbGluZWFyIHRyYW5zZm9ybWF0aW9uLCBpLmUuOiAkJFxyaG8oXGFscGhhXG1hdGhiZnt4fSxcbWF0aGJme3l9KT1ccmhvKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSksJCQgZm9yIGFueSAkXGFscGhhPjAkLgoqIFRoZSBQZWFyc29uIGRpc3RhbmNlIChvciBjb3JyZWxhdGlvbiBkaXN0YW5jZSkgaXMgZGVmaW5lZCBieToKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPTEtXHJobyhcbWF0aGJme3h9LFxtYXRoYmZ7eX0pLiQkCgoqIE5vdGUgdGhhdCB0aGUgUGVhcnNvbiBkaXN0YW5jZSBkb2VzIG5vdCBzYXRpc2Z5IEExIHNpbmNlICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt4fSk9MCQgZm9yIGFueSBub24temVybyB2ZWN0b3IgJFxtYXRoYmZ7eH0kLiBJdCBuZWl0aGVyIHNhdGlzZmllcyB0aGUgdHJpYW5nbGUgaW5lcXVhbGl0eS4gSG93ZXZlciwgdGhlIHN5bW1ldHJ5IHByb3BlcnR5IGlzIGZ1bGxmaWxsZWQuIAoKIyBDb3NpbmUgY29ycmVsYXRpb24gZGlzdGFuY2UKCiogVGhlIGNvc2luZSBvZiB0aGUgYW5nbGUgJFx0aGV0YSQgYmV0d2VlbiB0d28gdmVjdG9ycyAkXG1hdGhiZnt4fSQgYW5kICRcbWF0aGJme3l9JCBpcyBhIG1lYXN1cmUgb2Ygc2ltaWxhcml0eSBnaXZlbiBieToKJCQKXGNvcyhcdGhldGEpPVxmcmFje1xtYXRoYmZ7eH1cY2RvdCBcbWF0aGJme3l9fXtcfFxtYXRoYmZ7eH1cfF8yXHxcbWF0aGJme3l9XHxfMn09XGZyYWN7XHN1bV97aT0xfV5uIHhfaSB5X2l9e3tcc3FydHtcc3VtX3tpPTF9Xm4geF9pXjJcc3VtX3tpPTF9Xm4geV9pXjJ9fX0uCiQkCiogTm90ZSB0aGF0IHRoZSBjb3NpbmUgb2YgdGhlIGFuZ2xlIGJldHdlZW4gdGhlIHR3byBjZW50cmVkIHZlY3RvcnMgJCh4XzEtXGJhcntcbWF0aGJme3h9fSxcY2RvdHMseF9uLVxiYXJ7XG1hdGhiZnt4fX0pJCBhbmQgJCh5XzEtXGJhcntcbWF0aGJme3l9fSxcY2RvdHMseV9uLVxiYXJ7XG1hdGhiZnt5fX0pJCBjb2luY2lkZXMgd2l0aCB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAkXG1hdGhiZnt4fSQgYW5kICRcbWF0aGJme3l9JC4gIAoqIFRoZSBjb3NpbmUgY29ycmVsYXRpb24gZGlzdGFuY2UgaXMgZGVmaW5lZCBieToKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPTEtXGNvcyhcdGhldGEpLgokJAoqIEl0IHNoYXJlcyBzaW1pbGFyIHByb3BlcnRpZXMgdGhhbiB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBkaXN0YW5jZS4gTGlrZXdpc2UsIEF4aW9tcyBBMSBhbmQgQTMgYXJlIG5vdCBzYXRpc2ZpZWQuCgojIFNwZWFybWFuIGNvcnJlbGF0aW9uIGRpc3RhbmNlIAoKKiBUbyBjYWxjdWxhdGUgdGhlIFNwZWFybWFuJ3MgcmFuay1vcmRlciBjb3JyZWxhdGlvbiwgd2UgbmVlZCB0byBtYXAgc2VwZXJhdGVseSBlYWNoIG9mIHRoZSB2ZWN0b3JzIHRvIHJhbmtlZCBkYXRhIHZhbHVlczogCiQkXG1hdGhiZnt4fVxyaWdodGFycm93IFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eH0pPSh4XzFecixcY2RvdHMseF9uXnIpLiQkCiogSGVyZSwgJHhfaV5yJCBpcyB0aGUgcmFuayBvZiAkeF9pJCBhbW9uZyB0aGUgc2V0IG9mIHZhbHVlcyBvZiAkXG1hdGhiZnt4fSQuCiogV2UgaWxsdXN0cmF0ZSB0aGlzIHRyYW5zZm9ybWF0aW9uIHdpdGggYSBzaW1wbGUgZXhhbXBsZToKKiBJZiAkXG1hdGhiZnt4fT0oMywgMSwgNCwgMTUsIDkyKSQsIHRoZW4gdGhlIHJhbmstb3JkZXIgdmVjdG9yIGlzICRcdGV4dHtyYW5rfShcbWF0aGJme3h9KT0oMiwxLDMsNCw1KSQuICAKCmBgYHtyfQp4PWMoMywgMSwgNCwgMTUsIDkyKQpyYW5rKHgpCmBgYAoKKiBUaGUgU3BlYXJtYW4ncyByYW5rIGNvcnJlbGF0aW9uIG9mIHR3byBudW1lcmljYWwgdmFyaWFibGVzICRcbWF0aGJme3h9JCAgYW5kICRcbWF0aGJme3l9JCBpcyBzaW1wbHkgdGhlIFBlYXJzb24gY29ycmVsYXRpb24gb2YgdGhlIHR3byBjb3JyZXNwbmRpbmcgcmFuay1vcmRlciB2YXJpYWJsZXMgJFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eH0pJCBhbmQgJFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eX0pJCwgaS5lLiAkXHJobyhcdGV4dHtyYW5rfShcbWF0aGJme3h9KSxcdGV4dHtyYW5rfShcbWF0aGJme3l9KSkkLiBUaGlzIG1lYXN1cmUgaXMgaXMgdXNlZnVsIGJlY2F1c2UgaXQgaXMgbW9yZSByb2J1c3QgYWdhaW5zdCBvdXRsaWVycyB0aGFuIHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uLgoqIElmIGFsbCAgdGhlICRuJCAgcmFua3MgYXJlIGRpc3RpbmN0LCBpdCBjYW4gYmUgY29tcHV0ZWQgdXNpbmcgdGhlIGZvbGxvd2luZyBmb3JtdWxhOgokJApccmhvKFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eH0pLFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eX0pKT0xLVxmcmFjezZcc3VtX3tpPTF9Xm4gZF9pXjJ9e24obl4yLTEpfSwKJCQKd2hlcmUgJGRfaT14X2leci15X2lecixcOmk9MSxcY2RvdHMsbiQuCiAqIFRoZSBzcGVhcm1hbiBkaXN0YW5jZSBpcyB0aGVuIGRlZmluZWQgYnk6CiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0xLVxyaG8oXHRleHR7cmFua30oXG1hdGhiZnt4fSksXHRleHR7cmFua30oXG1hdGhiZnt5fSkpLgokJAoqIEl0IGNhbiBiZSBzaG93biB0aGF0IGVhc2FseSB0aGF0IGl0IGlzIG5vdCBhIHByb3BlciBkaXN0YW5jZS4KKiBJZiBhbGwgIHRoZSAkbiQgIHJhbmtzIGFyZSBkaXN0aW5jdCwgd2UgZ2V0OgokJApkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9XGZyYWN7NlxzdW1fe2k9MX1ebiBkX2leMn17bihuXjItMSl9LgokJAoKYGBge3J9Cng9YygzLCAxLCA0LCAxNSwgOTIpCnJhbmsoeCkKeT1jKDMwLDIgLCA5LCAyMCwgNDgpCnJhbmsoeSkKZD1yYW5rKHgpLXJhbmsoeSkKZApjb3IocmFuayh4KSxyYW5rKHkpKQoxLTYqc3VtKGReMikvKDUqKDVeMi0xKSkKYGBgCgoKIyBLZW5kYWxsIHRhdSBkaXN0YW5jZSAKCiogVGhlIEtlbmRhbGwgcmFuayBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBpcyBjYWxjdWxhdGVkIGZyb20gdGhlIG51bWJlciBvZiBjb3JyZXNwb25kYW5jZXMgYmV0d2VlbiB0aGUgcmFua2luZ3Mgb2YgJFxtYXRoYmZ7eH0kIGFuZCB0aGUgcmFua2luZ3Mgb2YgJFxtYXRoYmZ7eX0kLgoqICAgVGhlIG51bWJlciBvZiBwYWlycyBvZiBvYnNlcnZhdGlvbnMgYW1vbmcgJG4kIG9ic2VydmF0aW9ucyBvciB2YWx1ZXMgaXM6IAokJHtuIFxjaG9vc2UgMn0gPVxmcmFje24obi0xKX17Mn0uJCQKKiBUaGUgcGFpcnMgb2Ygb2JzZXJ2YXRpb25zICQoeF97aX0seF97an0pJCAgYW5kICAkKHlfe2l9LHlfe2p9KSQgYXJlIHNhaWQgdG8gYmUgX2NvbmNvcmRhbnRfIGlmOiAkJFx0ZXh0e3NpZ259KHhfai14X2kpPVx0ZXh0e3NpZ259KHlfai15X2kpLCQkIGFuZCB0byBiZSBfZGlzY29yZGFudF8gaWY6ICAkJFx0ZXh0e3NpZ259KHhfai14X2kpPS1cdGV4dHtzaWdufSh5X2oteV9pKSwkJAp3aGVyZSAkXHRleHR7c2lnbn0oXGNkb3QpJCByZXR1cm5zICAkMSQgZm9yIHBvc2l0aXZlIG51bWJlcnMgYW5kICAkLTEkIG5lZ2F0aXZlIG51bWJlcnMgYW5kICQwJCBvdGhlcndpc2UuCiogSWYgJHhfaT14X2okIG9yICR5X2k9eV9qJCAob3IgYm90aCksIHRoZXJlIGlzIGEgdGllLgoqIFRoZSBLZW5kYWxsICRcdGF1JCBjb2VmZmljaWVudCBpcyBkZWZpbmVkIGJ5IChuZWdsZWN0aW5nIHRpZXMpOgokJFx0YXUgPVxmcmFjIHsxfXtuKG4tMSl9XHN1bV97aT0xfV57bn1cc3VtX3tqPTF9Xm5cdGV4dHtzaWdufSh4X2oteF9pKVx0ZXh0e3NpZ259KHlfai15X2kpLiQkCiogTGV0ICRuX2MkIChyZXNwLiAkbl9kJCkgYmUgdGhlIG51bWJlciBvZiBjb25jb3JkYW50IChyZXNwLiBkaXNjb3JkYW50KSBwYWlycywgd2UgaGF2ZSAkJFx0YXUgPVxmcmFjIHsyKG5fYy1uX2QpfXtuKG4tMSl9LiQkIAoqIFRoZSBLZW5kYWxsIHRhdSBkaXN0YW5jZSBpcyB0aGVuOiAkJGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0xLVx0YXUuICQkCiogUmVtYXJrOiB0aGUgdHJpYW5ndWxhciBpbmVxdWFsaXR5IG1heSBmYWlsIGluIGNhc2VzIHdoZXJlIHRoZXJlIGFyZSB0aWVzLgoKYGBge3J9Cng9YygzLCAxLCA0LCAxNSwgOTIpCnk9YygzMCwyICwgOSwgMjAsIDQ4KQp0YXU9MApmb3IgKGkgaW4gMTo1KQp7ICAKdGF1PXRhdStzaWduKHggLXhbaV0pJSolc2lnbih5IC15W2ldKQp9CnRhdT10YXUvKDUqNCkKdGF1CmNvcih4LHksIG1ldGhvZD0ia2VuZGFsbCIpCmBgYAoKIyBWYXJpYWJsZXMgc3RhbmRhcmRpemF0aW9uCgoqIFZhcmlhYmxlcyBhcmUgb2Z0ZW4gc3RhbmRhcmRpemVkIGJlZm9yZSBtZWFzdXJpbmcgZGlzc2ltaWxhcml0aWVzLgoqIFN0YW5kYXJkaXphdGlvbiBjb252ZXJ0cyB0aGUgb3JpZ2luYWwgdmFyaWFibGVzIGludG8gdW5pdGVsZXNzIHZhcmlhYmxlcy4KKiBBIHdlbGwga25vd24gbWV0aG9kIGlzIHRoZSB6LXNjb3JlIHRyYW5zZm9ybWF0aW9uOiAKJCQKXG1hdGhiZnt4fVxyaWdodGFycm93IChcZnJhY3t4XzEtXGJhcntcbWF0aGJme3h9fX17c19cbWF0aGJme3h9fSxcY2RvdHMsXGZyYWN7eF9uLVxiYXJ7XG1hdGhiZnt4fX19e3NfXG1hdGhiZnt4fX0pLAokJCAKd2hlcmUgJHNfXG1hdGhiZnt4fSQgaXMgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gZ2l2ZW4gYnk6CiQkCnNfXG1hdGhiZnt4fT1cZnJhY3sxfXtuLTF9XHN1bV97aT0xfV5uKHhfaS1cYmFye1xtYXRoYmZ7eH19KV4yLgokJAoqIFRoZSB0cmFuc2Zvcm1lZCB2YXJpYWJsZSB3aWxsIGhhdmUgYSBtZWFuIG9mICQwJCBhbmQgYSB2YXJpYW5jZSBvZiAkMSQuCiogVGhlIHJlc3VsdCBvYnRhaW5lZCB3aXRoIFBlYXJzb24gY29ycmVsYXRpb24gbWVhc3VyZXMgYW5kIHN0YW5kYXJkaXplZCBFdWNsaWRlYW4gZGlzdGFuY2VzIGFyZSBjb21wYXJhYmxlLgoqIEZvciBvdGhlciBtZXRob2RzLCBzZWU6IE1pbGxpZ2FuLCBHLiBXLiwgJiBDb29wZXIsIE0uIEMuICgxOTg4KS4gQSBzdHVkeSBvZiBzdGFuZGFyZGl6YXRpb24gb2YgdmFyaWFibGVzIGluIGNsdXN0ZXIgYW5hbHlzaXMuIF9Kb3VybmFsIG9mIGNsYXNzaWZpY2F0aW9uXywgXzVfKDIpLCAxODEtMjA0LgoKYGBge3J9Cng9YygzLCAxLCA0LCAxNSwgOTIpCnk9YygzMCwyICwgOSwgMjAsIDQ4KQooeC1tZWFuKHgpKS9zZCh4KQpzY2FsZSh4KQooeS1tZWFuKHkpKS9zZCh5KQpzY2FsZSh5KQpgYGAKCiMgRGlzdGFuY2UgbWF0cml4IGNvbXB1dGF0aW9uCiogV2XigJlsbCB1c2UgYSBzdWJzZXQgb2YgdGhlIGRhdGEgVVNBcnJlc3RzCiogIFdl4oCZbGwgdXNlIG9ubHkgYSBieSB0YWtpbmcgMTUgcmFuZG9tIHJvd3MgYW1vbmcgdGhlIDUwIHJvd3MgaW4gdGhlIGRhdGEgc2V0LiAKKiBOZXh0LCB3ZSBzdGFuZGFyZGl6ZSB0aGUgZGF0YSB1c2luZyB0aGUgZnVuY3Rpb24gc2NhbGUoKToKCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJGYWN0b01pbmVSIikKbGlicmFyeSgiRmFjdG9NaW5lUiIpCmRhdGEoIlVTQXJyZXN0cyIpICMgTG9hZGluZwpoZWFkKFVTQXJyZXN0cywgMykgIyBQcmludCB0aGUgZmlyc3QgMyByb3dzCnNldC5zZWVkKDEyMykKc3MgPC0gc2FtcGxlKDE6NTAsIDE1KSAjIFRha2UgMTUgcmFuZG9tIHJvd3MKZGYgPC0gVVNBcnJlc3RzW3NzLCBdICMgU3Vic2V0IHRoZSAxNSByb3dzCmRmLnNjYWxlZCA8LSBzY2FsZShkZikgIyBTdGFuZGFyZGl6ZSB0aGUgdmFyaWFibGVzCmBgYAoKCgo=