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

\[ d(\mathbf{x},\mathbf{y})=\max_{i=1,\cdots,n}(|x_i-y_i|)=\lim_{p\rightarrow\infty} \left[\sum_{i=1} |x_i-y_i|^{p}\right]^{1/p}. \]

Minkowski inequality

\[ \left[\sum_{i=1}^n (a_i+b_i)^{p}\right]^{1/p}\leq \left[\sum_{i=1}^n a_i^{p}\right]^{1/p} + \left[\sum_{i=1}^n b_i^{p}\right]^{1/p}. \]

\[ \sum_{i=1}^n|x_i-z_i|^{p}= \sum_{i=1}^n|(x_i-y_i)+(y_i-z_i)|^{p}. \] * Since for any reals \(x,y\), we have: \(|x+y|\leq |x|+|y|\), and using the fact that \(x^p\) is increasing in \(x\geq 0\), we obtain: \[ \sum_{i=1}^n|x_i-z_i|^{p}\leq \sum_{i=1}^n(|x_i-y_i|+|y_i-z_i|)^{p}. \]

Hölder inequality

\[ \sum_{i=1}^n a_ib_i\leq \left[\sum_{i=1}^n a_i^{p}\right]^{1/p} \left[\sum_{i=1}^n b_i^{q}\right]^{1/q} \] * The proof of the Hölder inequality relies on the Young inequality: * For any \(a,b>0\), we have \[ ab\leq \frac{a^p}{p}+\frac{b^q}{q}, \] with equality occuring iff: \(a^p=b^q\). * To prove the Young inequality, one can use the (strict) convexity of the exponential function. * For any reals \(x,y\), we have: \[ e^{\frac{x}{p}+\frac{y}{q} }\leq \frac{e^{x}}{p}+\frac{e^{y}}{q}. \] * We then set: \(x=p\ln a\) and \(y=q\ln b\) to get the Young inequality. * A good reference on inequalities is: Z. Cvetkovski, Inequalities: theorems, techniques and selected problems, 2012, Springer Science & Business Media. # Cauchy-Schwartz inequality * Note that the triangular inequality for the Minkowski distance implies

\[ \sum_{i=1}^n |x_i|\leq \left[\sum_{i=1}^n |x_i|^{p}\right]^{1/p}. \] * Note that for \(p=2\), we have \(q=2\). The Hölder inequality implies for that special case \[ \sum_{i=1}^n|x_iy_i|\leq\sqrt{\sum_{i=1}^n x_i^2}\sqrt{\sum_{i=1}^n y_i^2}. \] * Since the LHS od thes above inequality is greater then \(|\sum_{i=1}^nx_iy_i|\), we get the Cauchy-Schwartz 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)
scale(x)
(y-mean(y))/sd(y)
scale(y)

Distance matrix computation

install.packages("FactoMineR")
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
LS0tCnRpdGxlOiAiRGlzdGFuY2UgYW5kIGRpc3NpbWlsYXJpdGllcyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICBkZl9wcmludDogcGFnZWQKLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCgoKIyBEZWZpbml0aW9uIG9mIGEgZGlzdGFuY2UKCiogQSBkaXN0YW5jZSBmdW5jdGlvbiBvciBhIG1ldHJpYyBvbiB0aGUgc3BhY2UgJFxtYXRoYmJ7Un1ebixcOm5cZ2VxIDEkLCBpcyBhIGZ1bmN0aW9uICRkOlxtYXRoYmJ7Un1eblx0aW1lc1xtYXRoYmJ7Un1eblxyaWdodGFycm93IFxtYXRoYmJ7Un0kLgoqIEEgZGlzdGFuY2UgZnVuY3Rpb24gbXVzdCBzYXRpc2Z5IHNvbWUgcmVxdWlyZWQgcHJvcGVydGllcyBvciBheGlvbXMuIAoqIFRoZXJlIGFyZSB0aHJlZSBtYWluIGF4aW9tcy4KCiogQTEuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9IDBcaWZmIFxtYXRoYmZ7eH09XG1hdGhiZnt5fSQgKGlkZW50aXR5IG9mIGluZGlzY2VybmlibGVzKTsKCiogQTIuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9IGQoXG1hdGhiZnt5fSxcbWF0aGJme3h9KSQgKHN5bW1ldHJ5KTsKCiogQTMuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt6fSlcbGVxIGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KStkKFxtYXRoYmZ7eX0sXG1hdGhiZnt6fSkkICAodHJpYW5nbGUgaW5lcXVhbGl0eSksCndoZXJlICRcbWF0aGJme3h9PSh4XzEsXGNkb3RzLHhfbikkLCAkXG1hdGhiZnt5fT0oeV8xLFxjZG90cyx5X24pJCBhbmQgJFxtYXRoYmZ7en09KHpfMSxcY2RvdHMsel9uKSQgYXJlIGFsbCB2ZWN0b3JzIG9mICRcbWF0aGJie1J9Xm4kLgoqIFdlIHNob3VsZCB1c2UgdGhlIHRlcm0gX2Rpc3NpbWlsYXJpdHlfIHJhdGhlciB0aGFuIF9kaXN0YW5jZV8gd2hlbiBub3QgYWxsIHRoZSB0aHJlZSBheGlvbXMgQTEtQTMgYXJlIHZhbGlkLgoqIE1vc3Qgb2YgdGhlIHRpbWUsIHdlIHNoYWxsIHVzZSwgd2l0aCBzb21lIGFidXNlIG9mIHZvY2FidWxhcnksIHRoZSB0ZXJtIGRpc3RhbmNlLgoKIyMgRXhlcmNpY2UgMQoKKiBQcm92ZSB0aGF0IHRoZSB0aHJlZSBheGlvbXMgQTEtQTMgaW1wbHkgdGhlIG5vbi1uZWdhdGl2aXR5IGNvbmRpdGlvbjogJCRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSlcZ2VxIDAuJCQKCgojIEV1Y2xpZGVhbiBkaXN0YW5jZQoKCiogSXQgaXMgZGVmaW5lZCBieToKCiQkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPVxzcXJ0e1xzdW1fe2k9MX1ebiAoeF9pLXlfaSleMn0uJCQKKiBBMUEyIGFlIG9uYnZpb3VzLgoqIFRoZSBwcm9vZiBvZiBBMyBpcyBwcm92aWRlZCBiZWxvdy4KCgojIE1hbmhhdHRhbiBkaXN0YW5jZQoKKiBUaGUgTWFuaGF0dGFuIGRpc3RhbmNlIGFsc28gY2FsbGVkICB0YXhpLWNhYiBtZXRyaWMgb3IgY2l0eS1ibG9jayBtZXRyaWMgaXMgZGVmaW5lZCBieToKCiQkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pCj1cc3VtX3tpPTF9Xm4gfHhfaS15X2l8LgokJAoKKiBBMS1BMiBob2xkLgoqIEEzIGFsc28gaG9sZHMgdXNpbmcgdGhlIGZhY3QgdGhhdCAkfGErYnxcbGVxIHxhfCt8YnwkIGZvciBhbnkgcmVhbHMgJGEsYiQuCiogVGhlcmUgZXhpc3RzIGFsc28gYSB3ZWlnaHRlZCB2ZXJzaW9uICBvZiB0aGUgTWFuaGF0dGFuIGRpc3RhbmNlIGNhbGxlZCB0aGUgQ2FuYmVycmEgZGlzdGFuY2UuCgpbTWFuaGF0dGFuIGRpc3RhbmNlIHZzIEV1Y2xpZGVhbiBkaXN0YW5jZSBHcmFwaF0oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy8wLzA4L01hbmhhdHRhbl9kaXN0YW5jZS5zdmcpCgpgYGB7cn0KeCA9IGMoMCwgMCkKeSA9IGMoNiw2KQpkaXN0KHJiaW5kKHgsIHkpLCBtZXRob2QgPSAiZXVjbGlkaWFuIikKNipzcXJ0KDIpCmRpc3QocmJpbmQoeCwgeSksIG1ldGhvZCA9ICJtYW5oYXR0YW4iKQpgYGAKCgojIENhbmJlcnJhIGRpc3RhbmNlCgoqIEl0IGlzIGRlZmluZWQgYnk6CgokJGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KQo9XHN1bV97aT0xfV5uIFxmcmFje3x4X2kteV9pfH17fHhfaXwrfHlfaXx9LiQkCgoqIE5vdGUgdGhhdCB0aGUgdGVybSAkfHhfaSDiiJIgeV9pfC8ofHhfaXwrfHlfaXwpJCBpcyBub3QgcHJvcGVybHkgZGVmaW5lZCB3aGVuICR4X2k9eV9pPTAkLgoqIEJ5IGNvbnZlbnRpb24gd2Ugc2V0IHRoZSByYXRpbyB0byBiZSB6ZXJvIGluIHRoYXQgY2FzZS4KKiBUaGUgQ2FuYmVycmEgZGlzdGFuY2UgaXMgc3BlY2lhbGx5IHNlbnNpdGl2ZSB0byBzbWFsbCBjaGFuZ2VzIG5lYXIgemVyby4KCgpgYGB7cn0KeCA9IGMoMCwgMCkKeSA9IGMoNiw2KQpkaXN0KHJiaW5kKHgsIHkpLCBtZXRob2QgPSAiY2FuYmVycmEiKQo2LzYrNi82CmBgYAoKCiMjIEV4ZXJjaWNlIDIKCiogUHJvdmUgdGhhdCB0aGUgQ2FuYmVycmEgZGlzdGFuY2UgaXMgYSB0cnVlIGRpc3RhbmNlLgoKIyBNaW5rb3dza2kgZGlzdGFuY2UKCiogQm90aCB0aGUgRXVjbGlkaWFuIGFuZCB0aGUgTWFuYXR0YW4gZGlzdGFuY2VzIGFyZSBzcGVjaWFsIGNhc2VzIG9mICB0aGUgTWlua293c2tpIGRpc3RhbmNlIHdoaWNoIGlzIGRlZmluZWQsIGZvciAkcFxnZXEgMSQsIGJ5OiAKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPQpcbGVmdFtcc3VtX3tpPTF9IHx4X2kteV9pfF57cH1ccmlnaHRdXnsxL3B9LgokJAogKiBGb3IgJHA9MSQsIHdlIGdldCB0aGUgTWFuaGF0dGFuIGRpc3RhbmNlLgogKiBGb3IgJHA9MiQsIHdlIGdldCB0aGUgRXVjbGlkaWFuIGRpdGFuY2UuCgoKKiBMZXQgdXMgYWxzbyBkZWZpbmU6IAokJFx8XG1hdGhiZnt4fVx8X3BcZXF1aXZcbGVmdFtcc3VtX3tpPTF9Xm4gfHhfaXxee3B9XHJpZ2h0XV57MS9wfSwkJAp3aGVyZSAkXHxcbWF0aGJme1xjZG90fVx8X3AkIGlzIGtub3duIGFzIHRoZSAkcCQtbm9ybSBvciBNaW5rb3dza2kgbm9ybS4KKiBOb3RlIHRoYXQgdGhlIE1pbmtvd3NraSBkaXN0YW5jZSBhbmQgbm9ybSBhcmUgcmVsYXRlZCBieToKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPVx8XG1hdGhiZnt4fS1cbWF0aGJme3l9XHxfcC4KJCQKKiBDb252ZXJzZWx5LCB3ZSBoYXZlOgokJApcfFxtYXRoYmZ7eH1cfF9wPWQoXG1hdGhiZnt4fSxcbWF0aGJmezB9KSwKJCQKd2hlcmUgJFxtYXRoYmZ7MH0kIGlzIHRoZSBudWxsLXZldG9yIG9mICRcbWF0aGJie1J9Xm4kLgoKYGBge3J9CmxpYnJhcnkoImdncGxvdDIiKQp4ID0gYygwLCAwKQp5ID0gYyg2LDYpCk1pbmtvd0Rpc3Q9YygpCmZvciAocCBpbiBzZXEoMSwzMCwuMDEpKQp7Ck1pbmtvd0Rpc3Q9YyhNaW5rb3dEaXN0LGRpc3QocmJpbmQoeCwgeSksIG1ldGhvZCA9ICJtaW5rb3dza2kiLCBwID0gcCkpICAgICAKfQpnZ3Bsb3QoZGF0YSA9ZGF0YS5mcmFtZSh4ID0gc2VxKDEsMzAsLjAxKSwgeT1NaW5rb3dEaXN0ICkgLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSkpK2dlb21fcG9pbnQoc2l6ZT0uMSxjb2xvcj0icmVkIikreGxpbSgxLDExKSt4bGFiKCJwIikreWxhYigiTWlua293c2tpIERpc3RhbmNlIikrZ2d0aXRsZSgiTWlua293c2tpIGRpc3RhbmNlIHdydCBwIikKCmBgYAoKIyBDaGVieXNoZXYgZGlzdGFuY2UgCgoqIEF0IHRoZSBsaW1pdCwgd2UgZ2V0IHRoZSBDaGVieXNoZXYgZGlzdGFuY2Ugd2hpY2ggaXMgZGVmaW5lZCBieToKCiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT1cbWF4X3tpPTEsXGNkb3RzLG59KHx4X2kteV9pfCk9XGxpbV97cFxyaWdodGFycm93XGluZnR5fQpcbGVmdFtcc3VtX3tpPTF9IHx4X2kteV9pfF57cH1ccmlnaHRdXnsxL3B9LgokJAoKKiBUaGUgY29ycmVzcG9uZGluZyBub3JtIGlzOgokJApcfFxtYXRoYmZ7eH18X1xpbmZ0eT1cbWF4X3tpPTEsXGNkb3RzLG59KHx4X2l8KS4KJCQKCgoKIyBNaW5rb3dza2kgaW5lcXVhbGl0eQoKKiBUaGUgcHJvb2Ygb2YgdGhlIHRyaWFuZ3VsYXIgaW5lcXVhbGl0eSBBMyBpcyBiYXNlZCBvbiB0aGUgTWlua293c2tpIGluZXF1YWxpdHk6CiogRm9yIGFueSBub25uZWdhdGl2ZSByZWFsIG51bWJlcnMgJGFfMSxcY2RvdHMsYV9uJDsgJGJfMSxcY2RvdHMsYl9uJCwgYW5kIGZvciBhbnkgJHBcZ2VxIDEkLCB3ZSBoYXZlOgoKJCQKXGxlZnRbXHN1bV97aT0xfV5uIChhX2krYl9pKV57cH1ccmlnaHRdXnsxL3B9XGxlcQpcbGVmdFtcc3VtX3tpPTF9Xm4gYV9pXntwfVxyaWdodF1eezEvcH0KKwpcbGVmdFtcc3VtX3tpPTF9Xm4gYl9pXntwfVxyaWdodF1eezEvcH0uCiQkCgoqIFRvIHByb3ZlIHRoYXQgdGhlIE1pbmtvd3NraSBkaXN0YW5jZSBzYXRpc2ZpZXMgQTMsIG5vdGljZSB0aGF0IAoKJCQKIFxzdW1fe2k9MX1ebnx4X2ktel9pfF57cH09IFxzdW1fe2k9MX1ebnwoeF9pLXlfaSkrKHlfaS16X2kpfF57cH0uCiQkCiogU2luY2UgZm9yIGFueSByZWFscyAkeCx5JCwgd2UgaGF2ZTogJHx4K3l8XGxlcSB8eHwrfHl8JCwgYW5kIHVzaW5nIHRoZSBmYWN0IHRoYXQgJHhecCQgaXMgaW5jcmVhc2luZyBpbiAkeFxnZXEgMCQsIHdlIG9idGFpbjoKJCQKIFxzdW1fe2k9MX1ebnx4X2ktel9pfF57cH1cbGVxIFxzdW1fe2k9MX1ebih8eF9pLXlfaXwrfHlfaS16X2l8KV57cH0uCiQkCgoqIEFwcGx5aW5nIHRoZSBNaW5rb3dza2kgaW5lcXVhbGl0eSB3aXRoICRhX2k9fHhfaS15X2l8JCBhbmQgJGJfaT18eV9pLXpfaXwkLCAkaT0xLFxjZG90cyxuJCwgd2UgZ2V0OgokJAogXHN1bV97aT0xfV5ufHhfaS16X2l8XntwfVxsZXEgXGxlZnQoXHN1bV97aT0xfV5uIHx4X2kteV9pfF57cH1ccmlnaHQpXnsxL3B9K1xsZWZ0KFxzdW1fe2k9MX1ebiB8eV9pLXpfaXxee3B9XHJpZ2h0KV57MS9wfS4KJCQKCgojIEjDtmxkZXIgaW5lcXVhbGl0eQoKKiBUaGUgcHJvb2Ygb2YgdGhlIE1pbmtvd3NraSBpbmVxdWFsaXR5IGl0c2VsZiByZXF1aXJlcyB0aGUgSMO2bGRlciBpbmVxdWFsaXR5OgoqIEZvciBhbnkgbm9ubmVnYXRpdmUgcmVhbCBudW1iZXJzICRhXzEsXGNkb3RzLGFfbiQ7ICRiXzEsXGNkb3RzLGJfbiQsIGFuZCBhbnkgJHAscT4xJCB3aXRoICQxL3ArMS9xPTEkLCB3ZSBoYXZlCgokJApcc3VtX3tpPTF9Xm4gYV9pYl9pXGxlcQpcbGVmdFtcc3VtX3tpPTF9Xm4gYV9pXntwfVxyaWdodF1eezEvcH0KXGxlZnRbXHN1bV97aT0xfV5uIGJfaV57cX1ccmlnaHRdXnsxL3F9CiQkCiogVGhlIHByb29mIG9mIHRoZSBIw7ZsZGVyIGluZXF1YWxpdHkgcmVsaWVzIG9uIHRoZSBZb3VuZyBpbmVxdWFsaXR5OgoqIEZvciBhbnkgJGEsYj4wJCwgd2UgaGF2ZQokJAphYlxsZXEgXGZyYWN7YV5wfXtwfStcZnJhY3tiXnF9e3F9LAokJAp3aXRoIGVxdWFsaXR5IG9jY3VyaW5nIGlmZjogJGFecD1iXnEkLiAKKiBUbyBwcm92ZSB0aGUgWW91bmcgaW5lcXVhbGl0eSwgb25lIGNhbiB1c2UgdGhlIChzdHJpY3QpIGNvbnZleGl0eSBvZiB0aGUgZXhwb25lbnRpYWwgZnVuY3Rpb24uCiogRm9yIGFueSByZWFscyAkeCx5JCwgd2UgaGF2ZToKJCQKZV57XGZyYWN7eH17cH0rXGZyYWN7eX17cX0gfVxsZXEgXGZyYWN7ZV57eH19e3B9K1xmcmFje2Vee3l9fXtxfS4gCiQkCiogV2UgdGhlbiBzZXQ6ICR4PXBcbG4gYSQgYW5kICR5PXFcbG4gYiQgdG8gZ2V0IHRoZSBZb3VuZyBpbmVxdWFsaXR5LgoqIEEgZ29vZCByZWZlcmVuY2Ugb24gaW5lcXVhbGl0aWVzIGlzOiBaLiBDdmV0a292c2tpLCAgSW5lcXVhbGl0aWVzOiB0aGVvcmVtcywgdGVjaG5pcXVlcyBhbmQgc2VsZWN0ZWQgcHJvYmxlbXMsIDIwMTIsIFNwcmluZ2VyIFNjaWVuY2UgJiBCdXNpbmVzcyBNZWRpYS4KICMgQ2F1Y2h5LVNjaHdhcnR6IGluZXF1YWxpdHkKKiBOb3RlIHRoYXQgdGhlIHRyaWFuZ3VsYXIgaW5lcXVhbGl0eSBmb3IgdGhlIE1pbmtvd3NraSBkaXN0YW5jZSBpbXBsaWVzIAoKJCQKXHN1bV97aT0xfV5uIHx4X2l8XGxlcQpcbGVmdFtcc3VtX3tpPTF9Xm4gfHhfaXxee3B9XHJpZ2h0XV57MS9wfS4KJCQKKiBOb3RlIHRoYXQgZm9yICRwPTIkLCB3ZSBoYXZlICRxPTIkLiBUaGUgSMO2bGRlciBpbmVxdWFsaXR5IGltcGxpZXMgZm9yIHRoYXQgc3BlY2lhbCBjYXNlCiQkClxzdW1fe2k9MX1ebnx4X2l5X2l8XGxlcVxzcXJ0e1xzdW1fe2k9MX1ebiB4X2leMn1cc3FydHtcc3VtX3tpPTF9Xm4geV9pXjJ9LiAKJCQKKiBTaW5jZSB0aGUgTEhTIG9kIHRoZXMgYWJvdmUgaW5lcXVhbGl0eSBpcyBncmVhdGVyIHRoZW4gJHxcc3VtX3tpPTF9Xm54X2l5X2l8JCwgd2UgZ2V0IHRoZSBDYXVjaHktU2Nod2FydHogaW5lcXVhbGl0eQoKJCQKfFxzdW1fe2k9MX1ebnhfaXlfaXxcbGVxXHNxcnR7XHN1bV97aT0xfV5uIHhfaV4yfVxzcXJ0e1xzdW1fe2k9MX1ebiB5X2leMn0uIAokJAoqIFVzaW5nIHRoZSBkb3QgcHJvZHVjdCBub3RhdGlvbiBjYWxsZWQgYWxzbyBzY2FsYXIgcHJvZHVjdCBub2F0aW9uOiAkXG1hdGhiZnt4XGNkb3QgeX09XHN1bV97aT0xfV5ueF9peV9pJCwgYW5kIHRoZSBub3JtIG5vdGF0aW9uICRcfFxtYXRoYmZ7XGNkb3R9XHxfMiBcfCQsIHRoZSBDYXVjaHktU2Nod2FydCBpbmVxdWFsaXR5IGlzOgoKJCR8XG1hdGhiZnt4XGNkb3QgeX0gfCBcbGVxIFx8XG1hdGhiZnt4fVx8XzIgXHwgXG1hdGhiZnt5fVx8XzIuJCQKCiMgUGVhcnNvbiBjb3JyZWxhdGlvbiBkaXN0YW5jZSAKCiogVGhlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgYSBzaW1pbGFyaXR5IG1lYXN1cmUgb24gJFxtYXRoYmJ7Un1ebiQgZGVmaW5lZCBieToKJCQKXHJobyhcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPQpcZnJhY3tcc3VtX3tpPTF9Xm4gKHhfaS1cYmFye1xtYXRoYmZ7eH19KSh5X2ktXGJhcntcbWF0aGJme3l9fSl9e3tcc3FydHtcc3VtX3tpPTF9Xm4gKHhfaS1cYmFye1xtYXRoYmZ7eH19KV4yXHN1bV97aT0xfV5uICh5X2ktXGJhcntcbWF0aGJme3l9fSleMn19fSwKJCQKd2hlcmUgJFxiYXJ7XG1hdGhiZnt4fX0kIGlzIHRoZSBtZWFuIG9mIHRoZSB2ZWN0b3IgJFxtYXRoYmZ7eH0kIGRlZmluZWQgYnk6IAokJFxiYXJ7XG1hdGhiZnt4fX09XGZyYWN7MX17bn1cc3VtX3tpPTF9Xm4geF9pLCQkCiogTm90ZSB0aGF0IHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IHNhdGlzZmllcyBQMiBhbmQgIGlzIGludmFyaWFudCB0byBhbnkgcG9zaXRpdmUgbGluZWFyIHRyYW5zZm9ybWF0aW9uLCBpLmUuOiAkJFxyaG8oXGFscGhhXG1hdGhiZnt4fSxcbWF0aGJme3l9KT1ccmhvKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSksJCQgZm9yIGFueSAkXGFscGhhPjAkLgoqIFRoZSBQZWFyc29uIGRpc3RhbmNlIChvciBjb3JyZWxhdGlvbiBkaXN0YW5jZSkgaXMgZGVmaW5lZCBieToKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPTEtXHJobyhcbWF0aGJme3h9LFxtYXRoYmZ7eX0pLiQkCgoqIE5vdGUgdGhhdCB0aGUgUGVhcnNvbiBkaXN0YW5jZSBkb2VzIG5vdCBzYXRpc2Z5IEExIHNpbmNlICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt4fSk9MCQgZm9yIGFueSBub24temVybyB2ZWN0b3IgJFxtYXRoYmZ7eH0kLiBJdCBuZWl0aGVyIHNhdGlzZmllcyB0aGUgdHJpYW5nbGUgaW5lcXVhbGl0eS4gSG93ZXZlciwgdGhlIHN5bW1ldHJ5IHByb3BlcnR5IGlzIGZ1bGxmaWxsZWQuIAoKIyBDb3NpbmUgY29ycmVsYXRpb24gZGlzdGFuY2UKCiogVGhlIGNvc2luZSBvZiB0aGUgYW5nbGUgJFx0aGV0YSQgYmV0d2VlbiB0d28gdmVjdG9ycyAkXG1hdGhiZnt4fSQgYW5kICRcbWF0aGJme3l9JCBpcyBhIG1lYXN1cmUgb2Ygc2ltaWxhcml0eSBnaXZlbiBieToKJCQKXGNvcyhcdGhldGEpPVxmcmFje1xtYXRoYmZ7eH1cY2RvdCBcbWF0aGJme3l9fXtcfFxtYXRoYmZ7eH1cfF8yXHxcbWF0aGJme3l9XHxfMn09XGZyYWN7XHN1bV97aT0xfV5uIHhfaSB5X2l9e3tcc3FydHtcc3VtX3tpPTF9Xm4geF9pXjJcc3VtX3tpPTF9Xm4geV9pXjJ9fX0uCiQkCiogTm90ZSB0aGF0IHRoZSBjb3NpbmUgb2YgdGhlIGFuZ2xlIGJldHdlZW4gdGhlIHR3byBjZW50cmVkIHZlY3RvcnMgJCh4XzEtXGJhcntcbWF0aGJme3h9fSxcY2RvdHMseF9uLVxiYXJ7XG1hdGhiZnt4fX0pJCBhbmQgJCh5XzEtXGJhcntcbWF0aGJme3l9fSxcY2RvdHMseV9uLVxiYXJ7XG1hdGhiZnt5fX0pJCBjb2luY2lkZXMgd2l0aCB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAkXG1hdGhiZnt4fSQgYW5kICRcbWF0aGJme3l9JC4gIAoKKiBUaGUgY29zaW5lIGNvcnJlbGF0aW9uIGRpc3RhbmNlIGlzIGRlZmluZWQgYnk6CiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0xLVxjb3MoXHRoZXRhKS4KJCQKKiBJdCBzaGFyZXMgc2ltaWxhciBwcm9wZXJ0aWVzIHRoYW4gdGhlIFBlYXJzb24gY29ycmVsYXRpb24gZGlzdGFuY2UuIExpa2V3aXNlLCBBeGlvbXMgUDEgYW5kIFAzIGFyZSBub3Qgc2F0aXNmaWVkLgoKIyBTcGVhcm1hbiBjb3JyZWxhdGlvbiBkaXN0YW5jZSAKCiogVG8gY2FsY3VsYXRlIHRoZSBTcGVhcm1hbidzIHJhbmstb3JkZXIgY29ycmVsYXRpb24sIHdlIG5lZWQgdG8gbWFwIHNlcGVyYXRlbHkgZWFjaCBvZiB0aGUgdmVjdG9ycyB0byByYW5rZWQgZGF0YSB2YWx1ZXM6IAokJFxtYXRoYmZ7eH1ccmlnaHRhcnJvdyBcdGV4dHtyYW5rfShcbWF0aGJme3h9KT0oeF8xXnIsXGNkb3RzLHhfbl5yKS4kJAoqIEhlcmUsICR4X2leciQgaXMgdGhlIHJhbmsgb2YgJHhfaSQgYW1vbmcgdGhlIHNldCBvZiB2YWx1ZXMgb2YgJFxtYXRoYmZ7eH0kLgoqIFdlIGlsbHVzdHJhdGUgdGhpcyB0cmFuc2Zvcm1hdGlvbiB3aXRoIGEgc2ltcGxlIGV4YW1wbGU6CiogSWYgJFxtYXRoYmZ7eH09KDMsIDEsIDQsIDE1LCA5MikkLCB0aGVuIHRoZSByYW5rLW9yZGVyIHZlY3RvciBpcyAkXHRleHR7cmFua30oXG1hdGhiZnt4fSk9KDIsMSwzLDQsNSkkLiAgCgpgYGB7cn0KeD1jKDMsIDEsIDQsIDE1LCA5MikKcmFuayh4KQpgYGAKCiogVGhlIFNwZWFybWFuJ3MgcmFuayBjb3JyZWxhdGlvbiBvZiB0d28gbnVtZXJpY2FsIHZhcmlhYmxlcyAkXG1hdGhiZnt4fSQgIGFuZCAkXG1hdGhiZnt5fSQgaXMgc2ltcGx5IHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIG9mIHRoZSB0d28gY29ycmVzcG5kaW5nIHJhbmstb3JkZXIgdmFyaWFibGVzICRcdGV4dHtyYW5rfShcbWF0aGJme3h9KSQgYW5kICRcdGV4dHtyYW5rfShcbWF0aGJme3l9KSQsIGkuZS4gJFxyaG8oXHRleHR7cmFua30oXG1hdGhiZnt4fSksXHRleHR7cmFua30oXG1hdGhiZnt5fSkpJC4gVGhpcyBtZWFzdXJlIGlzIGlzIHVzZWZ1bCBiZWNhdXNlIGl0IGlzIG1vcmUgcm9idXN0IGFnYWluc3Qgb3V0bGllcnMgdGhhbiB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbi4KKiBJZiBhbGwgIHRoZSAkbiQgIHJhbmtzIGFyZSBkaXN0aW5jdCwgaXQgY2FuIGJlIGNvbXB1dGVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgZm9ybXVsYToKJCQKXHJobyhcdGV4dHtyYW5rfShcbWF0aGJme3h9KSxcdGV4dHtyYW5rfShcbWF0aGJme3l9KSk9MS1cZnJhY3s2XHN1bV97aT0xfV5uIGRfaV4yfXtuKG5eMi0xKX0sCiQkCndoZXJlICRkX2k9eF9pXnIteV9pXnIsXDppPTEsXGNkb3RzLG4kLgogKiBUaGUgc3BlYXJtYW4gZGlzdGFuY2UgaXMgdGhlbiBkZWZpbmVkIGJ5OgokJApkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9MS1ccmhvKFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eH0pLFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eX0pKS4KJCQKKiBJdCBjYW4gYmUgc2hvd24gdGhhdCBlYXNhbHkgdGhhdCBpdCBpcyBub3QgYSBwcm9wZXIgZGlzdGFuY2UuCgoqIElmIGFsbCAgdGhlICRuJCAgcmFua3MgYXJlIGRpc3RpbmN0LCB3ZSBnZXQ6CiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT1cZnJhY3s2XHN1bV97aT0xfV5uIGRfaV4yfXtuKG5eMi0xKX0uCiQkCgpgYGB7cn0KeD1jKDMsIDEsIDQsIDE1LCA5MikKcmFuayh4KQp5PWMoMzAsMiAsIDksIDIwLCA0OCkKcmFuayh5KQpkPXJhbmsoeCktcmFuayh5KQpkCmNvcihyYW5rKHgpLHJhbmsoeSkpCjEtNipzdW0oZF4yKS8oNSooNV4yLTEpKQpgYGAKCgojIEtlbmRhbGwgdGF1IGRpc3RhbmNlIAoKKiBUaGUgS2VuZGFsbCByYW5rIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGlzIGNhbGN1bGF0ZWQgZnJvbSB0aGUgbnVtYmVyIG9mIGNvcnJlc3BvbmRhbmNlcyBiZXR3ZWVuIHRoZSByYW5raW5ncyBvZiAkXG1hdGhiZnt4fSQgYW5kIHRoZSByYW5raW5ncyBvZiAkXG1hdGhiZnt5fSQuCiogICBUaGUgbnVtYmVyIG9mIHBhaXJzIG9mIG9ic2VydmF0aW9ucyBhbW9uZyAkbiQgb2JzZXJ2YXRpb25zIG9yIHZhbHVlcyBpczogCiQke24gXGNob29zZSAyfSA9XGZyYWN7bihuLTEpfXsyfS4kJAoKKiBUaGUgcGFpcnMgb2Ygb2JzZXJ2YXRpb25zICQoeF97aX0seF97an0pJCAgYW5kICAkKHlfe2l9LHlfe2p9KSQgYXJlIHNhaWQgdG8gYmUgX2NvbmNvcmRhbnRfIGlmOiAkJFx0ZXh0e3NpZ259KHhfai14X2kpPVx0ZXh0e3NpZ259KHlfai15X2kpLCQkIGFuZCB0byBiZSBfZGlzY29yZGFudF8gaWY6ICAkJFx0ZXh0e3NpZ259KHhfai14X2kpPS1cdGV4dHtzaWdufSh5X2oteV9pKSwkJAp3aGVyZSAkXHRleHR7c2lnbn0oXGNkb3QpJCByZXR1cm5zICAkMSQgZm9yIHBvc2l0aXZlIG51bWJlcnMgYW5kICAkLTEkIG5lZ2F0aXZlIG51bWJlcnMgYW5kICQwJCBvdGhlcndpc2UuCiogSWYgJHhfaT14X2okIG9yICR5X2k9eV9qJCAob3IgYm90aCksIHRoZXJlIGlzIGEgdGllLgoqIFRoZSBLZW5kYWxsICRcdGF1JCBjb2VmZmljaWVudCBpcyBkZWZpbmVkIGJ5IChuZWdsZWN0aW5nIHRpZXMpOgokJFx0YXUgPVxmcmFjIHsxfXtuKG4tMSl9XHN1bV97aT0xfV57bn1cc3VtX3tqPTF9Xm5cdGV4dHtzaWdufSh4X2oteF9pKVx0ZXh0e3NpZ259KHlfai15X2kpLiQkCiogTGV0ICRuX2MkIChyZXNwLiAkbl9kJCkgYmUgdGhlIG51bWJlciBvZiBjb25jb3JkYW50IChyZXNwLiBkaXNjb3JkYW50KSBwYWlycywgd2UgaGF2ZSAkJFx0YXUgPVxmcmFjIHsyKG5fYy1uX2QpfXtuKG4tMSl9LiQkIAoqIFRoZSBLZW5kYWxsIHRhdSBkaXN0YW5jZSBpcyB0aGVuOiAkJGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0xLVx0YXUuICQkCiogUmVtYXJrOiB0aGUgdHJpYW5ndWxhciBpbmVxdWFsaXR5IG1heSBmYWlsIGluIGNhc2VzIHdoZXJlIHRoZXJlIGFyZSB0aWVzLgoKYGBge3J9Cng9YygzLCAxLCA0LCAxNSwgOTIpCnk9YygzMCwyICwgOSwgMjAsIDQ4KQp0YXU9MApmb3IgKGkgaW4gMTo1KQp7ICAKdGF1PXRhdStzaWduKHggLXhbaV0pJSolc2lnbih5IC15W2ldKQp9CnRhdT10YXUvKDUqNCkKdGF1CmNvcih4LHksIG1ldGhvZD0ia2VuZGFsbCIpCmBgYAoKIyBWYXJpYWJsZXMgc3RhbmRhcmRpemF0aW9uCgoqIFZhcmlhYmxlcyBhcmUgb2Z0ZW4gc3RhbmRhcmRpemVkIGJlZm9yZSBtZWFzdXJpbmcgZGlzc2ltaWxhcml0aWVzLgoqIFN0YW5kYXJkaXphdGlvbiBjb252ZXJ0cyB0aGUgb3JpZ2luYWwgdmFyaWFibGVzIGludG8gdW5pdGVsZXNzIHZhcmlhYmxlcy4KKiBBIHdlbGwga25vd24gbWV0aG9kIGlzIHRoZSB6LXNjb3JlIHRyYW5zZm9ybWF0aW9uOiAKJCQKXG1hdGhiZnt4fVxyaWdodGFycm93IChcZnJhY3t4XzEtXGJhcntcbWF0aGJme3h9fX17c19cbWF0aGJme3h9fSxcY2RvdHMsXGZyYWN7eF9uLVxiYXJ7XG1hdGhiZnt4fX19e3NfXG1hdGhiZnt4fX0pLAokJCAKd2hlcmUgJHNfXG1hdGhiZnt4fSQgaXMgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gZ2l2ZW4gYnk6CiQkCnNfXG1hdGhiZnt4fT1cZnJhY3sxfXtuLTF9XHN1bV97aT0xfV5uKHhfaS1cYmFye1xtYXRoYmZ7eH19KV4yLgokJCAKCiogVGhlIHRyYW5zZm9ybWVkIHZhcmlhYmxlIHdpbGwgaGF2ZSBhIG1lYW4gb2YgJDAkIGFuZCBhIHZhcmlhbmNlIG9mICQxJC4KKiBUaGUgcmVzdWx0IG9idGFpbmVkIHdpdGggUGVhcnNvbiBjb3JyZWxhdGlvbiBtZWFzdXJlcyBhbmQgc3RhbmRhcmRpemVkIEV1Y2xpZGVhbiBkaXN0YW5jZXMgYXJlIGNvbXBhcmFibGUuCiogRm9yIG90aGVyIG1ldGhvZHMsIHNlZTogTWlsbGlnYW4sIEcuIFcuLCAmIENvb3BlciwgTS4gQy4gKDE5ODgpLiBBIHN0dWR5IG9mIHN0YW5kYXJkaXphdGlvbiBvZiB2YXJpYWJsZXMgaW4gY2x1c3RlciBhbmFseXNpcy4gX0pvdXJuYWwgb2YgY2xhc3NpZmljYXRpb25fLCBfNV8oMiksIDE4MS0yMDQuCgpgYGB7cn0KeD1jKDMsIDEsIDQsIDE1LCA5MikKeT1jKDMwLDIgLCA5LCAyMCwgNDgpCih4LW1lYW4oeCkpL3NkKHgpCnNjYWxlKHgpCih5LW1lYW4oeSkpL3NkKHkpCnNjYWxlKHkpCmBgYAoKIyBEaXN0YW5jZSBtYXRyaXggY29tcHV0YXRpb24KKiBXZeKAmWxsIHVzZSBhIHN1YnNldCBvZiB0aGUgZGF0YSBVU0FycmVzdHMKKiAgV2XigJlsbCB1c2Ugb25seSBhIGJ5IHRha2luZyAxNSByYW5kb20gcm93cyBhbW9uZyB0aGUgNTAgcm93cyBpbiB0aGUgZGF0YSBzZXQuIAoqIE5leHQsIHdlIHN0YW5kYXJkaXplIHRoZSBkYXRhIHVzaW5nIHRoZSBmdW5jdGlvbiBzY2FsZSgpOgojIERhdGEKCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJGYWN0b01pbmVSIikKbGlicmFyeSgiRmFjdG9NaW5lUiIpCmRhdGEoIlVTQXJyZXN0cyIpICMgTG9hZGluZwpoZWFkKFVTQXJyZXN0cywgMykgIyBQcmludCB0aGUgZmlyc3QgMyByb3dzCnNldC5zZWVkKDEyMykKc3MgPC0gc2FtcGxlKDE6NTAsIDE1KSAjIFRha2UgMTUgcmFuZG9tIHJvd3MKZGYgPC0gVVNBcnJlc3RzW3NzLCBdICMgU3Vic2V0IHRoZSAxNSByb3dzCmRmLnNjYWxlZCA8LSBzY2FsZShkZikgIyBTdGFuZGFyZGl6ZSB0aGUgdmFyaWFibGVzCmBgYAoKCgo=