knitr::opts_chunk$set(echo = TRUE)

Definition of a distance

Exercice 1

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")
6*sqrt(2)
dist(rbind(x, y), method = "manhattan")

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")
6/6+6/6

Exercice 2

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)
x=c(3, 1, 4, 15, 92)
rank(x)
y=c(30,2 , 9, 20, 48)
rank(y)
d=rank(x)-rank(y)
d
cor(rank(x),rank(y))
1-6*sum(d^2)/(5*(5^2-1))

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
cor(x,y, method="kendall")

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
Ci0tLQp0aXRsZTogIkRpc3RhbmNlIGFuZCBkaXNzaW1pbGFyaXRpZXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPVRSVUV9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgoKIyBEZWZpbml0aW9uIG9mIGEgZGlzdGFuY2UKCiogQSBkaXN0YW5jZSBmdW5jdGlvbiBvciBhIG1ldHJpYyBvbiAkXG1hdGhiYntSfV5uLFw6blxnZXEgMSQsIGlzIGEgZnVuY3Rpb24gJGQ6XG1hdGhiYntSfV5uXHRpbWVzXG1hdGhiYntSfV5uXHJpZ2h0YXJyb3cgXG1hdGhiYntSfSQuCiogQSBkaXN0YW5jZSBmdW5jdGlvbiBtdXN0IHNhdGlzZnkgc29tZSByZXF1aXJlZCBwcm9wZXJ0aWVzIG9yIGF4aW9tcy4gCiogVGhlcmUgYXJlIHRocmVlIG1haW4gYXhpb21zLgoqIEExLiAkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPSAwXGlmZiBcbWF0aGJme3h9PVxtYXRoYmZ7eX0kIChpZGVudGl0eSBvZiBpbmRpc2Nlcm5pYmxlcyk7CiogQTIuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9IGQoXG1hdGhiZnt5fSxcbWF0aGJme3h9KSQgKHN5bW1ldHJ5KTsKCiogQTMuICRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt6fSlcbGVxIGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KStkKFxtYXRoYmZ7eX0sXG1hdGhiZnt6fSkkICAodHJpYW5nbGUgaW5lcXVhbGl0eSksCndoZXJlICRcbWF0aGJme3h9PSh4XzEsXGNkb3RzLHhfbikkLCAkXG1hdGhiZnt5fT0oeV8xLFxjZG90cyx5X24pJCBhbmQgJFxtYXRoYmZ7en09KHpfMSxcY2RvdHMsel9uKSQgYXJlIGFsbCB2ZWN0b3JzIG9mICRcbWF0aGJie1J9Xm4kLgoqIFdlIHNob3VsZCB1c2UgdGhlIHRlcm0gX2Rpc3NpbWlsYXJpdHlfIHJhdGhlciB0aGFuIF9kaXN0YW5jZV8gd2hlbiBub3QgYWxsIHRoZSB0aHJlZSBheGlvbXMgQTEtQTMgYXJlIHZhbGlkLgoqIE1vc3Qgb2YgdGhlIHRpbWUsIHdlIHNoYWxsIHVzZSwgd2l0aCBzb21lIGFidXNlIG9mIHZvY2FidWxhcnksIHRoZSB0ZXJtIGRpc3RhbmNlLgoKIyBFeGVyY2ljZSAxCgoqIFByb3ZlIHRoYXQgdGhlIHRocmVlIGF4aW9tcyBBMS1BMyBpbXBseSB0aGUgbm9uLW5lZ2F0aXZpdHkgY29uZGl0aW9uOiAkJGQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KVxnZXEgMC4kJAoKCiMgRXVjbGlkZWFuIGRpc3RhbmNlCgoKKiBJdCBpcyBkZWZpbmVkIGJ5OgoKJCRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9XHNxcnR7XHN1bV97aT0xfV5uICh4X2kteV9pKV4yfS4kJAoqIEExQTIgYWUgb25idmlvdXMuCiogVGhlIHByb29mIG9mIEEzIGlzIHByb3ZpZGVkIGJlbG93LgoKCiMgTWFuaGF0dGFuIGRpc3RhbmNlCgoqIFRoZSBNYW5oYXR0YW4gZGlzdGFuY2UgYWxzbyBjYWxsZWQgIHRheGktY2FiIG1ldHJpYyBvciBjaXR5LWJsb2NrIG1ldHJpYyBpcyBkZWZpbmVkIGJ5OgoKJCRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSkKPVxzdW1fe2k9MX1ebiB8eF9pLXlfaXwuCiQkCgoqIEExLUEyIGhvbGQuCiogQTMgYWxzbyBob2xkcyB1c2luZyB0aGUgZmFjdCB0aGF0ICR8YStifFxsZXEgfGF8K3xifCQgZm9yIGFueSByZWFscyAkYSxiJC4KKiBUaGVyZSBleGlzdHMgYWxzbyBhIHdlaWdodGVkIHZlcnNpb24gIG9mIHRoZSBNYW5oYXR0YW4gZGlzdGFuY2UgY2FsbGVkIHRoZSBDYW5iZXJyYSBkaXN0YW5jZS4KCltNYW5oYXR0YW4gZGlzdGFuY2UgdnMgRXVjbGlkZWFuIGRpc3RhbmNlIEdyYXBoXShodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zLzAvMDgvTWFuaGF0dGFuX2Rpc3RhbmNlLnN2ZykKCmBgYHtyfQp4ID0gYygwLCAwKQp5ID0gYyg2LDYpCmRpc3QocmJpbmQoeCwgeSksIG1ldGhvZCA9ICJldWNsaWRpYW4iKQo2KnNxcnQoMikKZGlzdChyYmluZCh4LCB5KSwgbWV0aG9kID0gIm1hbmhhdHRhbiIpCmBgYAoKCiMgQ2FuYmVycmEgZGlzdGFuY2UKCiogSXQgaXMgZGVmaW5lZCBieToKCiQkZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pCj1cc3VtX3tpPTF9Xm4gXGZyYWN7fHhfaS15X2l8fXt8eF9pfCt8eV9pfH0uJCQKCiogTm90ZSB0aGF0IHRoZSB0ZXJtICR8eF9pIOKIkiB5X2l8Lyh8eF9pfCt8eV9pfCkkIGlzIG5vdCBwcm9wZXJseSBkZWZpbmVkIHdoZW4gJHhfaT15X2k9MCQuCiogQnkgY29udmVudGlvbiB3ZSBzZXQgdGhlIHJhdGlvIHRvIGJlIHplcm8gaW4gdGhhdCBjYXNlLgoqIFRoZSBDYW5iZXJyYSBkaXN0YW5jZSBpcyBzcGVjaWFsbHkgc2Vuc2l0aXZlIHRvIHNtYWxsIGNoYW5nZXMgbmVhciB6ZXJvLgoKCmBgYHtyfQp4ID0gYygwLCAwKQp5ID0gYyg2LDYpCmRpc3QocmJpbmQoeCwgeSksIG1ldGhvZCA9ICJjYW5iZXJyYSIpCjYvNis2LzYKYGBgCgoKIyBFeGVyY2ljZSAyCgoqIFByb3ZlIHRoYXQgdGhlIENhbmJlcnJhIGRpc3RhbmNlIGlzIGEgdHJ1ZSBkaXN0YW5jZS4KCiMgTWlua293c2tpIGRpc3RhbmNlCiogQm90aCB0aGUgRXVjbGlkaWFuIGFuZCB0aGUgTWFuYXR0YW4gZGlzdGFuY2VzIGFyZSBzcGVjaWFsIGNhc2VzIG9mICB0aGUgTWlua293c2tpIGRpc3RhbmNlIHdoaWNoIGlzIGRlZmluZWQsIGZvciAkcFxnZXEgMSQsIGJ5OiAKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPQpcbGVmdFtcc3VtX3tpPTF9IHx4X2kteV9pfF57cH1ccmlnaHRdXnsxL3B9LgokJAogKiBGb3IgJHA9MSQsIHdlIGdldCB0aGUgTWFuaGF0dGFuIGRpc3RhbmNlLgogKiBGb3IgJHA9MiQsIHdlIGdldCB0aGUgRXVjbGlkaWFuIGRpc3RhbmNlLgoqIExldCB1cyBhbHNvIGRlZmluZTogCiQkXHxcbWF0aGJme3h9XHxfcFxlcXVpdlxsZWZ0W1xzdW1fe2k9MX1ebiB8eF9pfF57cH1ccmlnaHRdXnsxL3B9LCQkCndoZXJlICRcfFxtYXRoYmZ7XGNkb3R9XHxfcCQgaXMga25vd24gYXMgdGhlICRwJC1ub3JtIG9yIE1pbmtvd3NraSBub3JtLgoqIE5vdGUgdGhhdCB0aGUgTWlua293c2tpIGRpc3RhbmNlIGFuZCBub3JtIGFyZSByZWxhdGVkIGJ5OgokJApkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9XHxcbWF0aGJme3h9LVxtYXRoYmZ7eX1cfF9wLgokJAoqIENvbnZlcnNlbHksIHdlIGhhdmU6CiQkClx8XG1hdGhiZnt4fVx8X3A9ZChcbWF0aGJme3h9LFxtYXRoYmZ7MH0pLAokJAp3aGVyZSAkXG1hdGhiZnswfSQgaXMgdGhlIG51bGwtdmV0b3Igb2YgJFxtYXRoYmJ7Un1ebiQuCgpgYGB7cn0KbGlicmFyeSgiZ2dwbG90MiIpCnggPSBjKDAsIDApCnkgPSBjKDYsNikKTWlua293RGlzdD1jKCkKZm9yIChwIGluIHNlcSgxLDMwLC4wMSkpCnsKTWlua293RGlzdD1jKE1pbmtvd0Rpc3QsZGlzdChyYmluZCh4LCB5KSwgbWV0aG9kID0gIm1pbmtvd3NraSIsIHAgPSBwKSkgICAgIAp9CmdncGxvdChkYXRhID1kYXRhLmZyYW1lKHggPSBzZXEoMSwzMCwuMDEpLCB5PU1pbmtvd0Rpc3QgKSAsIG1hcHBpbmcgPSBhZXMoeCA9IHgsIHkgPSB5KSkrZ2VvbV9wb2ludChzaXplPS4xLGNvbG9yPSJyZWQiKSt4bGltKDEsMTEpK3hsYWIoInAiKSt5bGFiKCJNaW5rb3dza2kgRGlzdGFuY2UiKStnZ3RpdGxlKCJNaW5rb3dza2kgZGlzdGFuY2Ugd3J0IHAiKQpgYGAKCiMgQ2hlYnlzaGV2IGRpc3RhbmNlIAoqIEF0IHRoZSBsaW1pdCwgd2UgZ2V0IHRoZSBDaGVieXNoZXYgZGlzdGFuY2Ugd2hpY2ggaXMgZGVmaW5lZCBieToKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPVxtYXhfe2k9MSxcY2RvdHMsbn0ofHhfaS15X2l8KT1cbGltX3twXHJpZ2h0YXJyb3dcaW5mdHl9ClxsZWZ0W1xzdW1fe2k9MX0gfHhfaS15X2l8XntwfVxyaWdodF1eezEvcH0uCiQkCiogVGhlIGNvcnJlc3BvbmRpbmcgbm9ybSBpczoKJCQKXHxcbWF0aGJme3h9fF9caW5mdHk9XG1heF97aT0xLFxjZG90cyxufSh8eF9pfCkuCiQkCgojIE1pbmtvd3NraSBpbmVxdWFsaXR5CgoqIFRoZSBwcm9vZiBvZiB0aGUgdHJpYW5ndWxhciBpbmVxdWFsaXR5IEEzIGlzIGJhc2VkIG9uIHRoZSBNaW5rb3dza2kgaW5lcXVhbGl0eToKKiBGb3IgYW55IG5vbm5lZ2F0aXZlIHJlYWwgbnVtYmVycyAkYV8xLFxjZG90cyxhX24kOyAkYl8xLFxjZG90cyxiX24kLCBhbmQgZm9yIGFueSAkcFxnZXEgMSQsIHdlIGhhdmU6CiQkClxsZWZ0W1xzdW1fe2k9MX1ebiAoYV9pK2JfaSlee3B9XHJpZ2h0XV57MS9wfVxsZXEKXGxlZnRbXHN1bV97aT0xfV5uIGFfaV57cH1ccmlnaHRdXnsxL3B9CitcbGVmdFtcc3VtX3tpPTF9Xm4gYl9pXntwfVxyaWdodF1eezEvcH0uCiQkCiogVG8gcHJvdmUgdGhhdCB0aGUgTWlua293c2tpIGRpc3RhbmNlIHNhdGlzZmllcyBBMywgbm90aWNlIHRoYXQgCiQkCiBcc3VtX3tpPTF9Xm58eF9pLXpfaXxee3B9PSBcc3VtX3tpPTF9Xm58KHhfaS15X2kpKyh5X2ktel9pKXxee3B9LgokJAoqIFNpbmNlIGZvciBhbnkgcmVhbHMgJHgseSQsIHdlIGhhdmU6ICR8eCt5fFxsZXEgfHh8K3x5fCQsIGFuZCB1c2luZyB0aGUgZmFjdCB0aGF0ICR4XnAkIGlzIGluY3JlYXNpbmcgaW4gJHhcZ2VxIDAkLCB3ZSBvYnRhaW46CiQkCiBcc3VtX3tpPTF9Xm58eF9pLXpfaXxee3B9XGxlcSBcc3VtX3tpPTF9Xm4ofHhfaS15X2l8K3x5X2ktel9pfClee3B9LgokJAoKKiBBcHBseWluZyB0aGUgTWlua293c2tpIGluZXF1YWxpdHkgd2l0aCAkYV9pPXx4X2kteV9pfCQgYW5kICRiX2k9fHlfaS16X2l8JCwgJGk9MSxcY2RvdHMsbiQsIHdlIGdldDoKJCQKIFxzdW1fe2k9MX1ebnx4X2ktel9pfF57cH1cbGVxIFxsZWZ0KFxzdW1fe2k9MX1ebiB8eF9pLXlfaXxee3B9XHJpZ2h0KV57MS9wfStcbGVmdChcc3VtX3tpPTF9Xm4gfHlfaS16X2l8XntwfVxyaWdodCleezEvcH0uCiQkCgojIEjDtmxkZXIgaW5lcXVhbGl0eQoKKiBUaGUgcHJvb2Ygb2YgdGhlIE1pbmtvd3NraSBpbmVxdWFsaXR5IGl0c2VsZiByZXF1aXJlcyB0aGUgSMO2bGRlciBpbmVxdWFsaXR5OgoqIEZvciBhbnkgbm9ubmVnYXRpdmUgcmVhbCBudW1iZXJzICRhXzEsXGNkb3RzLGFfbiQ7ICRiXzEsXGNkb3RzLGJfbiQsIGFuZCBhbnkgJHAscT4xJCB3aXRoICQxL3ArMS9xPTEkLCB3ZSBoYXZlOgokJApcc3VtX3tpPTF9Xm4gYV9pYl9pXGxlcQpcbGVmdFtcc3VtX3tpPTF9Xm4gYV9pXntwfVxyaWdodF1eezEvcH0KXGxlZnRbXHN1bV97aT0xfV5uIGJfaV57cX1ccmlnaHRdXnsxL3F9CiQkCiogVGhlIHByb29mIG9mIHRoZSBIw7ZsZGVyIGluZXF1YWxpdHkgcmVsaWVzIG9uIHRoZSBZb3VuZyBpbmVxdWFsaXR5OgoqIEZvciBhbnkgJGEsYj4wJCwgd2UgaGF2ZQokJAphYlxsZXEgXGZyYWN7YV5wfXtwfStcZnJhY3tiXnF9e3F9LAokJAp3aXRoIGVxdWFsaXR5IG9jY3VyaW5nIGlmZjogJGFecD1iXnEkLiAKKiBUbyBwcm92ZSB0aGUgWW91bmcgaW5lcXVhbGl0eSwgb25lIGNhbiB1c2UgdGhlIChzdHJpY3QpIGNvbnZleGl0eSBvZiB0aGUgZXhwb25lbnRpYWwgZnVuY3Rpb24uCiogRm9yIGFueSByZWFscyAkeCx5JCwgd2UgaGF2ZToKJCQKZV57XGZyYWN7eH17cH0rXGZyYWN7eX17cX0gfVxsZXEgXGZyYWN7ZV57eH19e3B9K1xmcmFje2Vee3l9fXtxfS4gCiQkCiogV2UgdGhlbiBzZXQ6ICR4PXBcbG4gYSQgYW5kICR5PXFcbG4gYiQgdG8gZ2V0IHRoZSBZb3VuZyBpbmVxdWFsaXR5LgoqIEEgZ29vZCByZWZlcmVuY2Ugb24gaW5lcXVhbGl0aWVzIGlzOiBaLiBDdmV0a292c2tpLCAgSW5lcXVhbGl0aWVzOiB0aGVvcmVtcywgdGVjaG5pcXVlcyBhbmQgc2VsZWN0ZWQgcHJvYmxlbXMsIDIwMTIsIFNwcmluZ2VyIFNjaWVuY2UgJiBCdXNpbmVzcyBNZWRpYS4KICMgQ2F1Y2h5LVNjaHdhcnR6IGluZXF1YWxpdHkKKiBOb3RlIHRoYXQgdGhlIHRyaWFuZ3VsYXIgaW5lcXVhbGl0eSBmb3IgdGhlIE1pbmtvd3NraSBkaXN0YW5jZSBpbXBsaWVzOiAKJCQKXHN1bV97aT0xfV5uIHx4X2l8XGxlcQpcbGVmdFtcc3VtX3tpPTF9Xm4gfHhfaXxee3B9XHJpZ2h0XV57MS9wfS4KJCQKKiBOb3RlIHRoYXQgZm9yICRwPTIkLCB3ZSBoYXZlICRxPTIkLiBUaGUgSMO2bGRlciBpbmVxdWFsaXR5IGltcGxpZXMgZm9yIHRoYXQgc3BlY2lhbCBjYXNlCiQkClxzdW1fe2k9MX1ebnx4X2l5X2l8XGxlcVxzcXJ0e1xzdW1fe2k9MX1ebiB4X2leMn1cc3FydHtcc3VtX3tpPTF9Xm4geV9pXjJ9LiAKJCQKKiBTaW5jZSB0aGUgTEhTIG9kIHRoZXMgYWJvdmUgaW5lcXVhbGl0eSBpcyBncmVhdGVyIHRoZW4gJHxcc3VtX3tpPTF9Xm54X2l5X2l8JCwgd2UgZ2V0IHRoZSBDYXVjaHktU2Nod2FydHogaW5lcXVhbGl0eQoKJCQKfFxzdW1fe2k9MX1ebnhfaXlfaXxcbGVxXHNxcnR7XHN1bV97aT0xfV5uIHhfaV4yfVxzcXJ0e1xzdW1fe2k9MX1ebiB5X2leMn0uIAokJAoqIFVzaW5nIHRoZSBkb3QgcHJvZHVjdCBub3RhdGlvbiBjYWxsZWQgYWxzbyBzY2FsYXIgcHJvZHVjdCBub2F0aW9uOiAkXG1hdGhiZnt4XGNkb3QgeX09XHN1bV97aT0xfV5ueF9peV9pJCwgYW5kIHRoZSBub3JtIG5vdGF0aW9uICRcfFxtYXRoYmZ7XGNkb3R9XHxfMiBcfCQsIHRoZSBDYXVjaHktU2Nod2FydCBpbmVxdWFsaXR5IGlzOgokJAp8XG1hdGhiZnt4XGNkb3QgeX0gfCBcbGVxIFx8XG1hdGhiZnt4fVx8XzIgXHwgXG1hdGhiZnt5fVx8XzIuCiQkCgojIFBlYXJzb24gY29ycmVsYXRpb24gZGlzdGFuY2UgCgoqIFRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGlzIGEgc2ltaWxhcml0eSBtZWFzdXJlIG9uICRcbWF0aGJie1J9Xm4kIGRlZmluZWQgYnk6CiQkClxyaG8oXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0KXGZyYWN7XHN1bV97aT0xfV5uICh4X2ktXGJhcntcbWF0aGJme3h9fSkoeV9pLVxiYXJ7XG1hdGhiZnt5fX0pfXt7XHNxcnR7XHN1bV97aT0xfV5uICh4X2ktXGJhcntcbWF0aGJme3h9fSleMlxzdW1fe2k9MX1ebiAoeV9pLVxiYXJ7XG1hdGhiZnt5fX0pXjJ9fX0sCiQkCndoZXJlICRcYmFye1xtYXRoYmZ7eH19JCBpcyB0aGUgbWVhbiBvZiB0aGUgdmVjdG9yICRcbWF0aGJme3h9JCBkZWZpbmVkIGJ5OiAKJCRcYmFye1xtYXRoYmZ7eH19PVxmcmFjezF9e259XHN1bV97aT0xfV5uIHhfaSwkJAoqIE5vdGUgdGhhdCB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBzYXRpc2ZpZXMgUDIgYW5kICBpcyBpbnZhcmlhbnQgdG8gYW55IHBvc2l0aXZlIGxpbmVhciB0cmFuc2Zvcm1hdGlvbiwgaS5lLjogJCRccmhvKFxhbHBoYVxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9XHJobyhcbWF0aGJme3h9LFxtYXRoYmZ7eX0pLCQkIGZvciBhbnkgJFxhbHBoYT4wJC4KKiBUaGUgUGVhcnNvbiBkaXN0YW5jZSAob3IgY29ycmVsYXRpb24gZGlzdGFuY2UpIGlzIGRlZmluZWQgYnk6CiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0xLVxyaG8oXG1hdGhiZnt4fSxcbWF0aGJme3l9KS4kJAoKKiBOb3RlIHRoYXQgdGhlIFBlYXJzb24gZGlzdGFuY2UgZG9lcyBub3Qgc2F0aXNmeSBBMSBzaW5jZSAkZChcbWF0aGJme3h9LFxtYXRoYmZ7eH0pPTAkIGZvciBhbnkgbm9uLXplcm8gdmVjdG9yICRcbWF0aGJme3h9JC4gSXQgbmVpdGhlciBzYXRpc2ZpZXMgdGhlIHRyaWFuZ2xlIGluZXF1YWxpdHkuIEhvd2V2ZXIsIHRoZSBzeW1tZXRyeSBwcm9wZXJ0eSBpcyBmdWxsZmlsbGVkLiAKCiMgQ29zaW5lIGNvcnJlbGF0aW9uIGRpc3RhbmNlCgoqIFRoZSBjb3NpbmUgb2YgdGhlIGFuZ2xlICRcdGhldGEkIGJldHdlZW4gdHdvIHZlY3RvcnMgJFxtYXRoYmZ7eH0kIGFuZCAkXG1hdGhiZnt5fSQgaXMgYSBtZWFzdXJlIG9mIHNpbWlsYXJpdHkgZ2l2ZW4gYnk6CiQkClxjb3MoXHRoZXRhKT1cZnJhY3tcbWF0aGJme3h9XGNkb3QgXG1hdGhiZnt5fX17XHxcbWF0aGJme3h9XHxfMlx8XG1hdGhiZnt5fVx8XzJ9PVxmcmFje1xzdW1fe2k9MX1ebiB4X2kgeV9pfXt7XHNxcnR7XHN1bV97aT0xfV5uIHhfaV4yXHN1bV97aT0xfV5uIHlfaV4yfX19LgokJAoqIE5vdGUgdGhhdCB0aGUgY29zaW5lIG9mIHRoZSBhbmdsZSBiZXR3ZWVuIHRoZSB0d28gY2VudHJlZCB2ZWN0b3JzICQoeF8xLVxiYXJ7XG1hdGhiZnt4fX0sXGNkb3RzLHhfbi1cYmFye1xtYXRoYmZ7eH19KSQgYW5kICQoeV8xLVxiYXJ7XG1hdGhiZnt5fX0sXGNkb3RzLHlfbi1cYmFye1xtYXRoYmZ7eX19KSQgY29pbmNpZGVzIHdpdGggdGhlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgJFxtYXRoYmZ7eH0kIGFuZCAkXG1hdGhiZnt5fSQuICAKKiBUaGUgY29zaW5lIGNvcnJlbGF0aW9uIGRpc3RhbmNlIGlzIGRlZmluZWQgYnk6CiQkCmQoXG1hdGhiZnt4fSxcbWF0aGJme3l9KT0xLVxjb3MoXHRoZXRhKS4KJCQKKiBJdCBzaGFyZXMgc2ltaWxhciBwcm9wZXJ0aWVzIHRoYW4gdGhlIFBlYXJzb24gY29ycmVsYXRpb24gZGlzdGFuY2UuIExpa2V3aXNlLCBBeGlvbXMgQTEgYW5kIEEzIGFyZSBub3Qgc2F0aXNmaWVkLgoKIyBTcGVhcm1hbiBjb3JyZWxhdGlvbiBkaXN0YW5jZSAKCiogVG8gY2FsY3VsYXRlIHRoZSBTcGVhcm1hbidzIHJhbmstb3JkZXIgY29ycmVsYXRpb24sIHdlIG5lZWQgdG8gbWFwIHNlcGVyYXRlbHkgZWFjaCBvZiB0aGUgdmVjdG9ycyB0byByYW5rZWQgZGF0YSB2YWx1ZXM6IAokJFxtYXRoYmZ7eH1ccmlnaHRhcnJvdyBcdGV4dHtyYW5rfShcbWF0aGJme3h9KT0oeF8xXnIsXGNkb3RzLHhfbl5yKS4kJAoqIEhlcmUsICR4X2leciQgaXMgdGhlIHJhbmsgb2YgJHhfaSQgYW1vbmcgdGhlIHNldCBvZiB2YWx1ZXMgb2YgJFxtYXRoYmZ7eH0kLgoqIFdlIGlsbHVzdHJhdGUgdGhpcyB0cmFuc2Zvcm1hdGlvbiB3aXRoIGEgc2ltcGxlIGV4YW1wbGU6CiogSWYgJFxtYXRoYmZ7eH09KDMsIDEsIDQsIDE1LCA5MikkLCB0aGVuIHRoZSByYW5rLW9yZGVyIHZlY3RvciBpcyAkXHRleHR7cmFua30oXG1hdGhiZnt4fSk9KDIsMSwzLDQsNSkkLiAgCgpgYGB7cn0KeD1jKDMsIDEsIDQsIDE1LCA5MikKcmFuayh4KQpgYGAKCiogVGhlIFNwZWFybWFuJ3MgcmFuayBjb3JyZWxhdGlvbiBvZiB0d28gbnVtZXJpY2FsIHZhcmlhYmxlcyAkXG1hdGhiZnt4fSQgIGFuZCAkXG1hdGhiZnt5fSQgaXMgc2ltcGx5IHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIG9mIHRoZSB0d28gY29ycmVzcG5kaW5nIHJhbmstb3JkZXIgdmFyaWFibGVzICRcdGV4dHtyYW5rfShcbWF0aGJme3h9KSQgYW5kICRcdGV4dHtyYW5rfShcbWF0aGJme3l9KSQsIGkuZS4gJFxyaG8oXHRleHR7cmFua30oXG1hdGhiZnt4fSksXHRleHR7cmFua30oXG1hdGhiZnt5fSkpJC4gVGhpcyBtZWFzdXJlIGlzIGlzIHVzZWZ1bCBiZWNhdXNlIGl0IGlzIG1vcmUgcm9idXN0IGFnYWluc3Qgb3V0bGllcnMgdGhhbiB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbi4KKiBJZiBhbGwgIHRoZSAkbiQgIHJhbmtzIGFyZSBkaXN0aW5jdCwgaXQgY2FuIGJlIGNvbXB1dGVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgZm9ybXVsYToKJCQKXHJobyhcdGV4dHtyYW5rfShcbWF0aGJme3h9KSxcdGV4dHtyYW5rfShcbWF0aGJme3l9KSk9MS1cZnJhY3s2XHN1bV97aT0xfV5uIGRfaV4yfXtuKG5eMi0xKX0sCiQkCndoZXJlICRkX2k9eF9pXnIteV9pXnIsXDppPTEsXGNkb3RzLG4kLgogKiBUaGUgc3BlYXJtYW4gZGlzdGFuY2UgaXMgdGhlbiBkZWZpbmVkIGJ5OgokJApkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9MS1ccmhvKFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eH0pLFx0ZXh0e3Jhbmt9KFxtYXRoYmZ7eX0pKS4KJCQKKiBJdCBjYW4gYmUgc2hvd24gdGhhdCBlYXNhbHkgdGhhdCBpdCBpcyBub3QgYSBwcm9wZXIgZGlzdGFuY2UuCiogSWYgYWxsICB0aGUgJG4kICByYW5rcyBhcmUgZGlzdGluY3QsIHdlIGdldDoKJCQKZChcbWF0aGJme3h9LFxtYXRoYmZ7eX0pPVxmcmFjezZcc3VtX3tpPTF9Xm4gZF9pXjJ9e24obl4yLTEpfS4KJCQKCmBgYHtyfQp4PWMoMywgMSwgNCwgMTUsIDkyKQpyYW5rKHgpCnk9YygzMCwyICwgOSwgMjAsIDQ4KQpyYW5rKHkpCmQ9cmFuayh4KS1yYW5rKHkpCmQKY29yKHJhbmsoeCkscmFuayh5KSkKMS02KnN1bShkXjIpLyg1Kig1XjItMSkpCmBgYAoKCiMgS2VuZGFsbCB0YXUgZGlzdGFuY2UgCgoqIFRoZSBLZW5kYWxsIHJhbmsgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgY2FsY3VsYXRlZCBmcm9tIHRoZSBudW1iZXIgb2YgY29ycmVzcG9uZGFuY2VzIGJldHdlZW4gdGhlIHJhbmtpbmdzIG9mICRcbWF0aGJme3h9JCBhbmQgdGhlIHJhbmtpbmdzIG9mICRcbWF0aGJme3l9JC4KKiAgIFRoZSBudW1iZXIgb2YgcGFpcnMgb2Ygb2JzZXJ2YXRpb25zIGFtb25nICRuJCBvYnNlcnZhdGlvbnMgb3IgdmFsdWVzIGlzOiAKJCR7biBcY2hvb3NlIDJ9ID1cZnJhY3tuKG4tMSl9ezJ9LiQkCiogVGhlIHBhaXJzIG9mIG9ic2VydmF0aW9ucyAkKHhfe2l9LHhfe2p9KSQgIGFuZCAgJCh5X3tpfSx5X3tqfSkkIGFyZSBzYWlkIHRvIGJlIF9jb25jb3JkYW50XyBpZjogJCRcdGV4dHtzaWdufSh4X2oteF9pKT1cdGV4dHtzaWdufSh5X2oteV9pKSwkJCBhbmQgdG8gYmUgX2Rpc2NvcmRhbnRfIGlmOiAgJCRcdGV4dHtzaWdufSh4X2oteF9pKT0tXHRleHR7c2lnbn0oeV9qLXlfaSksJCQKd2hlcmUgJFx0ZXh0e3NpZ259KFxjZG90KSQgcmV0dXJucyAgJDEkIGZvciBwb3NpdGl2ZSBudW1iZXJzIGFuZCAgJC0xJCBuZWdhdGl2ZSBudW1iZXJzIGFuZCAkMCQgb3RoZXJ3aXNlLgoqIElmICR4X2k9eF9qJCBvciAkeV9pPXlfaiQgKG9yIGJvdGgpLCB0aGVyZSBpcyBhIHRpZS4KKiBUaGUgS2VuZGFsbCAkXHRhdSQgY29lZmZpY2llbnQgaXMgZGVmaW5lZCBieSAobmVnbGVjdGluZyB0aWVzKToKJCRcdGF1ID1cZnJhYyB7MX17bihuLTEpfVxzdW1fe2k9MX1ee259XHN1bV97aj0xfV5uXHRleHR7c2lnbn0oeF9qLXhfaSlcdGV4dHtzaWdufSh5X2oteV9pKS4kJAoqIExldCAkbl9jJCAocmVzcC4gJG5fZCQpIGJlIHRoZSBudW1iZXIgb2YgY29uY29yZGFudCAocmVzcC4gZGlzY29yZGFudCkgcGFpcnMsIHdlIGhhdmUgJCRcdGF1ID1cZnJhYyB7MihuX2Mtbl9kKX17bihuLTEpfS4kJCAKKiBUaGUgS2VuZGFsbCB0YXUgZGlzdGFuY2UgaXMgdGhlbjogJCRkKFxtYXRoYmZ7eH0sXG1hdGhiZnt5fSk9MS1cdGF1LiAkJAoqIFJlbWFyazogdGhlIHRyaWFuZ3VsYXIgaW5lcXVhbGl0eSBtYXkgZmFpbCBpbiBjYXNlcyB3aGVyZSB0aGVyZSBhcmUgdGllcy4KCmBgYHtyfQp4PWMoMywgMSwgNCwgMTUsIDkyKQp5PWMoMzAsMiAsIDksIDIwLCA0OCkKdGF1PTAKZm9yIChpIGluIDE6NSkKeyAgCnRhdT10YXUrc2lnbih4IC14W2ldKSUqJXNpZ24oeSAteVtpXSkKfQp0YXU9dGF1Lyg1KjQpCnRhdQpjb3IoeCx5LCBtZXRob2Q9ImtlbmRhbGwiKQpgYGAKCiMgVmFyaWFibGVzIHN0YW5kYXJkaXphdGlvbgoKKiBWYXJpYWJsZXMgYXJlIG9mdGVuIHN0YW5kYXJkaXplZCBiZWZvcmUgbWVhc3VyaW5nIGRpc3NpbWlsYXJpdGllcy4KKiBTdGFuZGFyZGl6YXRpb24gY29udmVydHMgdGhlIG9yaWdpbmFsIHZhcmlhYmxlcyBpbnRvIHVuaXRlbGVzcyB2YXJpYWJsZXMuCiogQSB3ZWxsIGtub3duIG1ldGhvZCBpcyB0aGUgei1zY29yZSB0cmFuc2Zvcm1hdGlvbjogCiQkClxtYXRoYmZ7eH1ccmlnaHRhcnJvdyAoXGZyYWN7eF8xLVxiYXJ7XG1hdGhiZnt4fX19e3NfXG1hdGhiZnt4fX0sXGNkb3RzLFxmcmFje3hfbi1cYmFye1xtYXRoYmZ7eH19fXtzX1xtYXRoYmZ7eH19KSwKJCQgCndoZXJlICRzX1xtYXRoYmZ7eH0kIGlzIHRoZSBzYW1wbGUgc3RhbmRhcmQgZGV2aWF0aW9uIGdpdmVuIGJ5OgokJApzX1xtYXRoYmZ7eH09XGZyYWN7MX17bi0xfVxzdW1fe2k9MX1ebih4X2ktXGJhcntcbWF0aGJme3h9fSleMi4KJCQKKiBUaGUgdHJhbnNmb3JtZWQgdmFyaWFibGUgd2lsbCBoYXZlIGEgbWVhbiBvZiAkMCQgYW5kIGEgdmFyaWFuY2Ugb2YgJDEkLgoqIFRoZSByZXN1bHQgb2J0YWluZWQgd2l0aCBQZWFyc29uIGNvcnJlbGF0aW9uIG1lYXN1cmVzIGFuZCBzdGFuZGFyZGl6ZWQgRXVjbGlkZWFuIGRpc3RhbmNlcyBhcmUgY29tcGFyYWJsZS4KKiBGb3Igb3RoZXIgbWV0aG9kcywgc2VlOiBNaWxsaWdhbiwgRy4gVy4sICYgQ29vcGVyLCBNLiBDLiAoMTk4OCkuIEEgc3R1ZHkgb2Ygc3RhbmRhcmRpemF0aW9uIG9mIHZhcmlhYmxlcyBpbiBjbHVzdGVyIGFuYWx5c2lzLiBfSm91cm5hbCBvZiBjbGFzc2lmaWNhdGlvbl8sIF81XygyKSwgMTgxLTIwNC4KCmBgYHtyfQp4PWMoMywgMSwgNCwgMTUsIDkyKQp5PWMoMzAsMiAsIDksIDIwLCA0OCkKKHgtbWVhbih4KSkvc2QoeCkKc2NhbGUoeCkKKHktbWVhbih5KSkvc2QoeSkKc2NhbGUoeSkKYGBgCgojIERpc3RhbmNlIG1hdHJpeCBjb21wdXRhdGlvbgoqIFdl4oCZbGwgdXNlIGEgc3Vic2V0IG9mIHRoZSBkYXRhIFVTQXJyZXN0cwoqICBXZeKAmWxsIHVzZSBvbmx5IGEgYnkgdGFraW5nIDE1IHJhbmRvbSByb3dzIGFtb25nIHRoZSA1MCByb3dzIGluIHRoZSBkYXRhIHNldC4gCiogTmV4dCwgd2Ugc3RhbmRhcmRpemUgdGhlIGRhdGEgdXNpbmcgdGhlIGZ1bmN0aW9uIHNjYWxlKCk6CgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiRmFjdG9NaW5lUiIpCmxpYnJhcnkoIkZhY3RvTWluZVIiKQpkYXRhKCJVU0FycmVzdHMiKSAjIExvYWRpbmcKaGVhZChVU0FycmVzdHMsIDMpICMgUHJpbnQgdGhlIGZpcnN0IDMgcm93cwpzZXQuc2VlZCgxMjMpCnNzIDwtIHNhbXBsZSgxOjUwLCAxNSkgIyBUYWtlIDE1IHJhbmRvbSByb3dzCmRmIDwtIFVTQXJyZXN0c1tzcywgXSAjIFN1YnNldCB0aGUgMTUgcm93cwpkZi5zY2FsZWQgPC0gc2NhbGUoZGYpICMgU3RhbmRhcmRpemUgdGhlIHZhcmlhYmxlcwpgYGAKCjwhLS1zdGFja2VkaXRfZGF0YToKZXlKb2FYTjBiM0o1SWpwYkxURTFNakUwT1RJeE1Ua3NNVFk0TlRNNU9Ua3hYWDA9Ci0tPg==