Early illustrations

Generating simple variates.

library(tidyverse)
library(MASS)
n_samples <- 15
runif(n_samples, min = 2, max = 5)
 [1] 2.573535 3.092167 2.586157 3.052016 4.399478 3.220121 3.479837 2.986623 3.142103 2.093352 3.694454 4.293629 2.769909
[14] 2.817124 4.581841
rnorm(n_samples, mean = 3, sd = 3)
 [1]  1.1318897  3.6915188 -2.4295416  3.9406064  7.8308073  1.7218378 -0.2284897  7.2920913  3.2799805  4.8685947 -0.1446002
[12]  2.9702466  3.9845434  1.0724392  8.2346965
rgamma(n_samples, shape = 1, rate = 2)
 [1] 0.61505432 0.10864060 0.83338904 0.06296618 0.53718863 0.87058523 0.41055802 1.54278747 0.13515218 2.12089713 0.21183433
[12] 0.21186035 0.56357650 0.06307413 0.67400431

Simulating football outcomes

Simple case

Four teams compete. Their strengths (or scores, out of 100) are:

France Brazil Germany Vatican
85 92 85 55
countries <- c("France", "Brazil", "Germany", "Vatican")
strength <- c(85, 92, 85, 55)
foot <- data.frame(countries, strength)

First round: France-Brazil and Germany-Vatican. The winners play the final. During a game, the probability Team 1 wins over Team 2 is \(s_1/(s_1+s_2)\), where the \(s_i\) are the scores. The purpose is to compute the probability of winning the tournament for each team.

n_sim <- 10^3
winner <- c()
for(n in 1:n_sim){   # We resort to a loop for clarity. We recommend the SimDesign package to the interested reader! Or to the map() wrapper
  odds <- foot$strength[1]/(foot$strength[1]+foot$strength[2])
  if(runif(1)<odds){win_1 <- 1} else win_1 <- 2 # First round, first game, win_1 stores the winner
  odds <- foot$strength[3]/(foot$strength[3]+foot$strength[4])
  if(runif(1)<odds){win_2 <- 3} else win_2 <- 4 # First round, second game, win_2 stores the winner
  odds <- foot$strength[win_1]/(foot$strength[win_1]+foot$strength[win_2])
  if(runif(1)<odds){win <- win_1} else win <- win_2 # Second round, win is the final winner
  winner[n] <- win
}
summary(as.factor(winner))/n_sim
    1     2     3     4 
0.228 0.317 0.315 0.140 

Complex case

A more detailed approach with offense and defense scores:

France Brazil Germany Vatican
Defense 0.90 0.80 0.86 0.54
Offense 0.88 0.94 0.90 0.56
rho 0.90 0.90 0.90 0.30
countries <- c("France", "Brazil", "Germany", "Vatican")
defense <- c(0.90, 0.80, 0.86, 0.54)
offense <- c(0.88, 0.94, 0.90, 0.56)
rho <- c(0.9, 0.9, 0.9, 0.3)
foot <- data.frame(countries, defense, offense, rho)

The sequence is the same. The outcome of the matches are determined as follows. For each team, defense and offense are simulated as a Gaussian variable with unit variance and mean equal to the scores given in the table above. The correlation between the two outcomes is rho.

n_sim <- 10^3
winner <- c()
for(n in 1:n_sim){   # We resort to a loop for clarity (again). 
  mu_1 <- c(foot$defense[1], foot$offense[1]) # Obviously, these lines could be automated => see below
  Sig_1 <- rbind(c(1,foot$rho[1]),c(foot$rho[1],1))
  score_1 <- mvrnorm(1, mu = mu_1, Sigma = Sig_1) %>% sum()
  mu_2 <- c(foot$defense[2], foot$offense[2])
  Sig_2 <- rbind(c(1,foot$rho[2]),c(foot$rho[2],1))
  score_2 <- mvrnorm(1, mu = mu_2, Sigma = Sig_2) %>% sum()
  if(score_1 > score_2){win_1 <- 1} else win_1 <- 2 # First round, first game
  mu_3 <- c(foot$defense[3], foot$offense[3])
  Sig_3 <- rbind(c(1,foot$rho[3]),c(foot$rho[3],1))
  score_3 <- mvrnorm(1, mu = mu_3, Sigma = Sig_3) %>% sum()
  mu_4 <- c(foot$defense[4], foot$offense[4])
  Sig_4 <- rbind(c(1,foot$rho[4]),c(foot$rho[4],1))
  score_4 <- mvrnorm(1, mu = mu_4, Sigma = Sig_4) %>% sum()
  if(score_3 > score_4){win_2 <- 3} else win_2 <- 4 # First round, second game
  mu_1 <- c(foot$defense[win_1], foot$offense[win_1]) # Obviously, these lines could be automated => see below
  Sig_1 <- rbind(c(1,foot$rho[win_1]),c(foot$rho[win_1],1))
  score_1 <- mvrnorm(1, mu = mu_1, Sigma = Sig_1) %>% sum()
  mu_2 <- c(foot$defense[win_2], foot$offense[win_2])
  Sig_2 <- rbind(c(1,foot$rho[win_2]),c(foot$rho[win_2],1))
  score_2 <- mvrnorm(1, mu = mu_2, Sigma = Sig_2) %>% sum()
  if(score_1 > score_2){win <- win_1} else win <- win_2 # Second round
  winner[n] <- win
}
summary(as.factor(winner))/n_sim
    1     2     3     4 
0.278 0.263 0.293 0.166 

Below, a more compact version in which an additional parameter v is added to reduce randomness. The probabilities are more concentrated when variance is smaller.

n_sim <- 10^3
v <- 0.1     # The impact of variance
score <- c() # We must initialize the variables we will use later on
win <- c()
winner <- c()
for(n in 1:n_sim){        # The loop over all simulations
  for(i in 1:nrow(foot)){ # Compute the scores in a loop
    mu <- c(foot$defense[i], foot$offense[i])
    Sig <- v*rbind(c(1,foot$rho[i]),c(foot$rho[i],1))
    score[i] <- mvrnorm(1, mu = mu, Sigma = Sig) %>% sum()
  }
  if(score[1] > score[2]){win[1] <- 1} else win[1] <- 2 # First round, first game
  if(score[3] > score[4]){win[2] <- 3} else win[2] <- 4 # First round, second game
  for(i in 1:2){ # Compute the scores in a loop
    mu <- c(foot$defense[win[i]], foot$offense[win[i]])
    Sig <- v*rbind(c(1,foot$rho[win[i]]),c(foot$rho[win[i]],1))
    score[i] <- mvrnorm(1, mu = mu, Sigma = Sig) %>% sum()
  } # Be very careful in the line below, the values 3 & 4 in 'score' have not been erased!
  if(score[1] > score[2]){winner[n] <- win[1]} else winner[n] <- win[2] # First round, first game
}
summary(as.factor(winner))/n_sim
    1     2     3     4 
0.303 0.257 0.400 0.040 

Exercises

Approximating Pi

The equation for the unit circle is: y^2 + x^2 = 1. The surface of a circle with unit radius is equal to Pi. With this in mind, can you compute a Monte-Carlo based estimation of Pi?
How many simulations would you need to reach with a high level of confidence the number 3.14159?

Musical predictions

The imaginary sovereign city-state of Atlantis is voting for the best singer of all time. There are 6 finalists and their relative popularity is:

Elvis Presley: 78%
Madonna: 72%
John Lennon: 67%
Freddie Mercury: 64%
Beyoncé: 62%
Bob Marley: 60%

Source: Atlantis Daily News.
The vote takes place in two rounds (there is a run-off). After the first round, the best two contenders face each other to win the title.

In order to simulate who will win, we proceed as follows: for each candidate, an exponential law is drawn with parameter equal to his/her popularity. The two candidates with smallest values win. Same procedure for the final round. What are the winning probabilities for each candidate? What happens if we change the parameter of the exponential distribution and we multiply the popularity by 100?

Generating artificial data

We want to generate profiles for 100 imaginary male athletes. We want their age (years), height (cm), weight (kg) and their best running time on 100m (s).
The ranges of variables are included in: (18-30) for age, (165-194) for height (65-90) for weight and (10.1-11.0) for running time.
Choose a simulation protocol that can smartly match these ranges. The round() functions cuts decimals. Any idea how to introduce some correlation between height and weight?

Back to Pi

We consider the first exercise. The point here is to visually grasp the convergence of the estimator as the number of simulations increases. Create a dataframe that stores the values obtained for the following 12 values of number of simulations: 3^(1:12). Then, plot the result, as well as a vertical line at 3.14.

BONUS

Use Monte-Carlo simulations to compute the surface of an equilateral triangle with unit side length.
A bit of help: if you draw bivariate uniform samples on (-1,1), the equation is: max(-2y, y-sqrt(3)x, y+sqrt(3)x) < sqrt(4/3) .
The true value is sqrt(3)/4, which is approximately equal to 0.433.

LS0tCnRpdGxlOiAiTW9udGUtQ2FybG8gU2ltdWxhdGlvbnMiCm91dHB1dDogCiAgIGh0bWxfbm90ZWJvb2s6CiAgIyAgIHRvYzogdHJ1ZQogICMgICB0b2NfZmxvYXQ6IHRydWUKICAjIGdpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAotLS0KCiMjIEVhcmx5IGlsbHVzdHJhdGlvbnMKR2VuZXJhdGluZyBzaW1wbGUgdmFyaWF0ZXMuCmBgYHtyIHNpbXBsZSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KE1BU1MpCm5fc2FtcGxlcyA8LSAxNQpydW5pZihuX3NhbXBsZXMsIG1pbiA9IDIsIG1heCA9IDUpCnJub3JtKG5fc2FtcGxlcywgbWVhbiA9IDMsIHNkID0gMykKcmdhbW1hKG5fc2FtcGxlcywgc2hhcGUgPSAxLCByYXRlID0gMikKYGBgCgoKCgojIyBTaW11bGF0aW5nIGZvb3RiYWxsIG91dGNvbWVzCiMjIyBTaW1wbGUgY2FzZQpGb3VyIHRlYW1zIGNvbXBldGUuIFRoZWlyIHN0cmVuZ3RocyAob3Igc2NvcmVzLCBvdXQgb2YgMTAwKSBhcmU6Cgp8IEZyYW5jZSB8IEJyYXppbCB8IEdlcm1hbnkgfCBWYXRpY2FuIHwKfC0tLSAgICAgfC0tLSAgICAgfCAtLS0gICAgIHwgLS0tICAgICB8Cnw4NSAgICAgIHwgOTIgICAgIHwgODUgICAgICB8IDU1ICAgICAgfAoKCmBgYHtyIHN0cmVuZ3Roc30KY291bnRyaWVzIDwtIGMoIkZyYW5jZSIsICJCcmF6aWwiLCAiR2VybWFueSIsICJWYXRpY2FuIikKc3RyZW5ndGggPC0gYyg4NSwgOTIsIDg1LCA1NSkKZm9vdCA8LSBkYXRhLmZyYW1lKGNvdW50cmllcywgc3RyZW5ndGgpCmBgYAoKRmlyc3Qgcm91bmQ6IEZyYW5jZS1CcmF6aWwgYW5kIEdlcm1hbnktVmF0aWNhbi4gVGhlIHdpbm5lcnMgcGxheSB0aGUgZmluYWwuIER1cmluZyBhIGdhbWUsIHRoZSBwcm9iYWJpbGl0eSBUZWFtIDEgd2lucyBvdmVyIFRlYW0gMiBpcyAkc18xLyhzXzErc18yKSQsIHdoZXJlIHRoZSAkc19pJCBhcmUgdGhlIHNjb3Jlcy4gVGhlIHB1cnBvc2UgaXMgdG8gY29tcHV0ZSB0aGUgcHJvYmFiaWxpdHkgb2Ygd2lubmluZyB0aGUgdG91cm5hbWVudCBmb3IgZWFjaCB0ZWFtLgoKCmBgYHtyIHNpbXVsXzF9Cm5fc2ltIDwtIDEwXjMKd2lubmVyIDwtIGMoKQpmb3IobiBpbiAxOm5fc2ltKXsgICAjIFdlIHJlc29ydCB0byBhIGxvb3AgZm9yIGNsYXJpdHkuIFdlIHJlY29tbWVuZCB0aGUgU2ltRGVzaWduIHBhY2thZ2UgdG8gdGhlIGludGVyZXN0ZWQgcmVhZGVyISBPciB0byB0aGUgbWFwKCkgd3JhcHBlcgogIG9kZHMgPC0gZm9vdCRzdHJlbmd0aFsxXS8oZm9vdCRzdHJlbmd0aFsxXStmb290JHN0cmVuZ3RoWzJdKQogIGlmKHJ1bmlmKDEpPG9kZHMpe3dpbl8xIDwtIDF9IGVsc2Ugd2luXzEgPC0gMiAjIEZpcnN0IHJvdW5kLCBmaXJzdCBnYW1lLCB3aW5fMSBzdG9yZXMgdGhlIHdpbm5lcgogIG9kZHMgPC0gZm9vdCRzdHJlbmd0aFszXS8oZm9vdCRzdHJlbmd0aFszXStmb290JHN0cmVuZ3RoWzRdKQogIGlmKHJ1bmlmKDEpPG9kZHMpe3dpbl8yIDwtIDN9IGVsc2Ugd2luXzIgPC0gNCAjIEZpcnN0IHJvdW5kLCBzZWNvbmQgZ2FtZSwgd2luXzIgc3RvcmVzIHRoZSB3aW5uZXIKICBvZGRzIDwtIGZvb3Qkc3RyZW5ndGhbd2luXzFdLyhmb290JHN0cmVuZ3RoW3dpbl8xXStmb290JHN0cmVuZ3RoW3dpbl8yXSkKICBpZihydW5pZigxKTxvZGRzKXt3aW4gPC0gd2luXzF9IGVsc2Ugd2luIDwtIHdpbl8yICMgU2Vjb25kIHJvdW5kLCB3aW4gaXMgdGhlIGZpbmFsIHdpbm5lcgogIHdpbm5lcltuXSA8LSB3aW4KfQpzdW1tYXJ5KGFzLmZhY3Rvcih3aW5uZXIpKS9uX3NpbQpgYGAKCiMjIyBDb21wbGV4IGNhc2UKQSBtb3JlIGRldGFpbGVkIGFwcHJvYWNoIHdpdGggb2ZmZW5zZSBhbmQgZGVmZW5zZSBzY29yZXM6IAoKfCAgICAgICB8IEZyYW5jZSB8IEJyYXppbCB8IEdlcm1hbnkgfCBWYXRpY2FuIHwKfCAgLS0tICB8LS0tICAgICB8LS0tICAgICB8IC0tLSAgICAgfCAtLS0gICAgIHwKfERlZmVuc2V8MC45MCAgICB8IDAuODAgICB8IDAuODYgICAgfCAwLjU0ICAgIHwKfE9mZmVuc2V8MC44OCAgICB8IDAuOTQgICB8IDAuOTAgICAgfCAwLjU2ICAgIHwKfHJobyAgICB8MC45MCAgICB8IDAuOTAgICB8IDAuOTAgICAgfCAwLjMwICAgIHwKCgpgYGB7ciBkJm8gcGFyYW1ldGVyc30gCmNvdW50cmllcyA8LSBjKCJGcmFuY2UiLCAiQnJhemlsIiwgIkdlcm1hbnkiLCAiVmF0aWNhbiIpCmRlZmVuc2UgPC0gYygwLjkwLCAwLjgwLCAwLjg2LCAwLjU0KQpvZmZlbnNlIDwtIGMoMC44OCwgMC45NCwgMC45MCwgMC41NikKcmhvIDwtIGMoMC45LCAwLjksIDAuOSwgMC4zKQpmb290IDwtIGRhdGEuZnJhbWUoY291bnRyaWVzLCBkZWZlbnNlLCBvZmZlbnNlLCByaG8pCmBgYAoKVGhlIHNlcXVlbmNlIGlzIHRoZSBzYW1lLiBUaGUgb3V0Y29tZSBvZiB0aGUgbWF0Y2hlcyBhcmUgZGV0ZXJtaW5lZCBhcyBmb2xsb3dzLiBGb3IgZWFjaCB0ZWFtLCBkZWZlbnNlIGFuZCBvZmZlbnNlIGFyZSBzaW11bGF0ZWQgYXMgYSBHYXVzc2lhbiB2YXJpYWJsZSB3aXRoIHVuaXQgdmFyaWFuY2UgYW5kIG1lYW4gZXF1YWwgdG8gdGhlIHNjb3JlcyBnaXZlbiBpbiB0aGUgdGFibGUgYWJvdmUuIFRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28gb3V0Y29tZXMgaXMgcmhvLiAKCmBgYHtyIHNpbXVsXzJ9Cm5fc2ltIDwtIDEwXjMKd2lubmVyIDwtIGMoKQpmb3IobiBpbiAxOm5fc2ltKXsgICAjIFdlIHJlc29ydCB0byBhIGxvb3AgZm9yIGNsYXJpdHkgKGFnYWluKS4gCiAgbXVfMSA8LSBjKGZvb3QkZGVmZW5zZVsxXSwgZm9vdCRvZmZlbnNlWzFdKSAjIE9idmlvdXNseSwgdGhlc2UgbGluZXMgY291bGQgYmUgYXV0b21hdGVkID0+IHNlZSBiZWxvdwogIFNpZ18xIDwtIHJiaW5kKGMoMSxmb290JHJob1sxXSksYyhmb290JHJob1sxXSwxKSkKICBzY29yZV8xIDwtIG12cm5vcm0oMSwgbXUgPSBtdV8xLCBTaWdtYSA9IFNpZ18xKSAlPiUgc3VtKCkKICBtdV8yIDwtIGMoZm9vdCRkZWZlbnNlWzJdLCBmb290JG9mZmVuc2VbMl0pCiAgU2lnXzIgPC0gcmJpbmQoYygxLGZvb3QkcmhvWzJdKSxjKGZvb3QkcmhvWzJdLDEpKQogIHNjb3JlXzIgPC0gbXZybm9ybSgxLCBtdSA9IG11XzIsIFNpZ21hID0gU2lnXzIpICU+JSBzdW0oKQogIGlmKHNjb3JlXzEgPiBzY29yZV8yKXt3aW5fMSA8LSAxfSBlbHNlIHdpbl8xIDwtIDIgIyBGaXJzdCByb3VuZCwgZmlyc3QgZ2FtZQogIG11XzMgPC0gYyhmb290JGRlZmVuc2VbM10sIGZvb3Qkb2ZmZW5zZVszXSkKICBTaWdfMyA8LSByYmluZChjKDEsZm9vdCRyaG9bM10pLGMoZm9vdCRyaG9bM10sMSkpCiAgc2NvcmVfMyA8LSBtdnJub3JtKDEsIG11ID0gbXVfMywgU2lnbWEgPSBTaWdfMykgJT4lIHN1bSgpCiAgbXVfNCA8LSBjKGZvb3QkZGVmZW5zZVs0XSwgZm9vdCRvZmZlbnNlWzRdKQogIFNpZ180IDwtIHJiaW5kKGMoMSxmb290JHJob1s0XSksYyhmb290JHJob1s0XSwxKSkKICBzY29yZV80IDwtIG12cm5vcm0oMSwgbXUgPSBtdV80LCBTaWdtYSA9IFNpZ180KSAlPiUgc3VtKCkKICBpZihzY29yZV8zID4gc2NvcmVfNCl7d2luXzIgPC0gM30gZWxzZSB3aW5fMiA8LSA0ICMgRmlyc3Qgcm91bmQsIHNlY29uZCBnYW1lCiAgbXVfMSA8LSBjKGZvb3QkZGVmZW5zZVt3aW5fMV0sIGZvb3Qkb2ZmZW5zZVt3aW5fMV0pICMgT2J2aW91c2x5LCB0aGVzZSBsaW5lcyBjb3VsZCBiZSBhdXRvbWF0ZWQgPT4gc2VlIGJlbG93CiAgU2lnXzEgPC0gcmJpbmQoYygxLGZvb3QkcmhvW3dpbl8xXSksYyhmb290JHJob1t3aW5fMV0sMSkpCiAgc2NvcmVfMSA8LSBtdnJub3JtKDEsIG11ID0gbXVfMSwgU2lnbWEgPSBTaWdfMSkgJT4lIHN1bSgpCiAgbXVfMiA8LSBjKGZvb3QkZGVmZW5zZVt3aW5fMl0sIGZvb3Qkb2ZmZW5zZVt3aW5fMl0pCiAgU2lnXzIgPC0gcmJpbmQoYygxLGZvb3QkcmhvW3dpbl8yXSksYyhmb290JHJob1t3aW5fMl0sMSkpCiAgc2NvcmVfMiA8LSBtdnJub3JtKDEsIG11ID0gbXVfMiwgU2lnbWEgPSBTaWdfMikgJT4lIHN1bSgpCiAgaWYoc2NvcmVfMSA+IHNjb3JlXzIpe3dpbiA8LSB3aW5fMX0gZWxzZSB3aW4gPC0gd2luXzIgIyBTZWNvbmQgcm91bmQKICB3aW5uZXJbbl0gPC0gd2luCn0Kc3VtbWFyeShhcy5mYWN0b3Iod2lubmVyKSkvbl9zaW0KYGBgCgoKQmVsb3csIGEgbW9yZSBjb21wYWN0IHZlcnNpb24gaW4gd2hpY2ggYW4gYWRkaXRpb25hbCBwYXJhbWV0ZXIgdiBpcyBhZGRlZCB0byByZWR1Y2UgcmFuZG9tbmVzcy4gVGhlIHByb2JhYmlsaXRpZXMgYXJlIG1vcmUgY29uY2VudHJhdGVkIHdoZW4gdmFyaWFuY2UgaXMgc21hbGxlci4KCmBgYHtyIHNpbXVsXzIgaW1wcm92ZWR9Cm5fc2ltIDwtIDEwXjMKdiA8LSAwLjEgICAgICMgVGhlIGltcGFjdCBvZiB2YXJpYW5jZQpzY29yZSA8LSBjKCkgIyBXZSBtdXN0IGluaXRpYWxpemUgdGhlIHZhcmlhYmxlcyB3ZSB3aWxsIHVzZSBsYXRlciBvbgp3aW4gPC0gYygpCndpbm5lciA8LSBjKCkKZm9yKG4gaW4gMTpuX3NpbSl7ICAgICAgICAjIFRoZSBsb29wIG92ZXIgYWxsIHNpbXVsYXRpb25zCiAgZm9yKGkgaW4gMTpucm93KGZvb3QpKXsgIyBDb21wdXRlIHRoZSBzY29yZXMgaW4gYSBsb29wCiAgICBtdSA8LSBjKGZvb3QkZGVmZW5zZVtpXSwgZm9vdCRvZmZlbnNlW2ldKQogICAgU2lnIDwtIHYqcmJpbmQoYygxLGZvb3QkcmhvW2ldKSxjKGZvb3QkcmhvW2ldLDEpKQogICAgc2NvcmVbaV0gPC0gbXZybm9ybSgxLCBtdSA9IG11LCBTaWdtYSA9IFNpZykgJT4lIHN1bSgpCiAgfQogIGlmKHNjb3JlWzFdID4gc2NvcmVbMl0pe3dpblsxXSA8LSAxfSBlbHNlIHdpblsxXSA8LSAyICMgRmlyc3Qgcm91bmQsIGZpcnN0IGdhbWUKICBpZihzY29yZVszXSA+IHNjb3JlWzRdKXt3aW5bMl0gPC0gM30gZWxzZSB3aW5bMl0gPC0gNCAjIEZpcnN0IHJvdW5kLCBzZWNvbmQgZ2FtZQogIGZvcihpIGluIDE6Mil7ICMgQ29tcHV0ZSB0aGUgc2NvcmVzIGluIGEgbG9vcAogICAgbXUgPC0gYyhmb290JGRlZmVuc2Vbd2luW2ldXSwgZm9vdCRvZmZlbnNlW3dpbltpXV0pCiAgICBTaWcgPC0gdipyYmluZChjKDEsZm9vdCRyaG9bd2luW2ldXSksYyhmb290JHJob1t3aW5baV1dLDEpKQogICAgc2NvcmVbaV0gPC0gbXZybm9ybSgxLCBtdSA9IG11LCBTaWdtYSA9IFNpZykgJT4lIHN1bSgpCiAgfSAjIEJlIHZlcnkgY2FyZWZ1bCBpbiB0aGUgbGluZSBiZWxvdywgdGhlIHZhbHVlcyAzICYgNCBpbiAnc2NvcmUnIGhhdmUgbm90IGJlZW4gZXJhc2VkIQogIGlmKHNjb3JlWzFdID4gc2NvcmVbMl0pe3dpbm5lcltuXSA8LSB3aW5bMV19IGVsc2Ugd2lubmVyW25dIDwtIHdpblsyXSAjIEZpcnN0IHJvdW5kLCBmaXJzdCBnYW1lCn0Kc3VtbWFyeShhcy5mYWN0b3Iod2lubmVyKSkvbl9zaW0KYGBgCgojIyBFeGVyY2lzZXMKCiMjIyBBcHByb3hpbWF0aW5nIFBpClRoZSBlcXVhdGlvbiBmb3IgdGhlIHVuaXQgY2lyY2xlIGlzOiB5XjIgKyB4XjIgPSAxLiBUaGUgc3VyZmFjZSBvZiBhIGNpcmNsZSB3aXRoIHVuaXQgcmFkaXVzIGlzIGVxdWFsIHRvIFBpLiAKV2l0aCB0aGlzIGluIG1pbmQsIGNhbiB5b3UgY29tcHV0ZSBhIE1vbnRlLUNhcmxvIGJhc2VkIGVzdGltYXRpb24gb2YgUGk/ICAKSG93IG1hbnkgc2ltdWxhdGlvbnMgd291bGQgeW91IG5lZWQgdG8gcmVhY2ggd2l0aCBhIGhpZ2ggbGV2ZWwgb2YgY29uZmlkZW5jZSB0aGUgbnVtYmVyIDMuMTQxNTk/CgojIyMgTXVzaWNhbCBwcmVkaWN0aW9ucwpUaGUgaW1hZ2luYXJ5IHNvdmVyZWlnbiBjaXR5LXN0YXRlIG9mIEF0bGFudGlzIGlzIHZvdGluZyBmb3IgdGhlIGJlc3Qgc2luZ2VyIG9mIGFsbCB0aW1lLiBUaGVyZSBhcmUgNiBmaW5hbGlzdHMgYW5kIHRoZWlyIHJlbGF0aXZlIHBvcHVsYXJpdHkgaXM6ICAKICAKKipFbHZpcyBQcmVzbGV5Kio6IDc4JSAgCioqTWFkb25uYSoqOiA3MiUgIAoqKkpvaG4gTGVubm9uKio6IDY3JSAgCioqRnJlZGRpZSBNZXJjdXJ5Kio6IDY0JSAgCioqQmV5b25jw6kqKjogNjIlICAKKipCb2IgTWFybGV5Kio6IDYwJSAgCiAgClNvdXJjZTogQXRsYW50aXMgRGFpbHkgTmV3cy4gIApUaGUgdm90ZSB0YWtlcyBwbGFjZSBpbiB0d28gcm91bmRzICh0aGVyZSBpcyBhIHJ1bi1vZmYpLiBBZnRlciB0aGUgZmlyc3Qgcm91bmQsIHRoZSBiZXN0IHR3byBjb250ZW5kZXJzIGZhY2UgZWFjaCBvdGhlciB0byB3aW4gdGhlIHRpdGxlLiAgCgpJbiBvcmRlciB0byBzaW11bGF0ZSB3aG8gd2lsbCB3aW4sIHdlIHByb2NlZWQgYXMgZm9sbG93czogZm9yIGVhY2ggY2FuZGlkYXRlLCBhbiBleHBvbmVudGlhbCBsYXcgaXMgZHJhd24gd2l0aCBwYXJhbWV0ZXIgZXF1YWwgdG8gaGlzL2hlciBwb3B1bGFyaXR5LiBUaGUgdHdvIGNhbmRpZGF0ZXMgd2l0aCAqKnNtYWxsZXN0KiogdmFsdWVzIHdpbi4gU2FtZSBwcm9jZWR1cmUgZm9yIHRoZSBmaW5hbCByb3VuZC4gV2hhdCBhcmUgdGhlIHdpbm5pbmcgcHJvYmFiaWxpdGllcyBmb3IgZWFjaCBjYW5kaWRhdGU/IFdoYXQgaGFwcGVucyBpZiB3ZSBjaGFuZ2UgdGhlIHBhcmFtZXRlciBvZiB0aGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIGFuZCB3ZSBtdWx0aXBseSB0aGUgcG9wdWxhcml0eSBieSAxMDA/CgoKCiMjIyBHZW5lcmF0aW5nIGFydGlmaWNpYWwgZGF0YQpXZSB3YW50IHRvIGdlbmVyYXRlIHByb2ZpbGVzIGZvciAxMDAgaW1hZ2luYXJ5IG1hbGUgYXRobGV0ZXMuIFdlIHdhbnQgdGhlaXIgYWdlICh5ZWFycyksIGhlaWdodCAoY20pLCB3ZWlnaHQgKGtnKSBhbmQgdGhlaXIgYmVzdCBydW5uaW5nIHRpbWUgb24gMTAwbSAocykuICAKVGhlIHJhbmdlcyBvZiB2YXJpYWJsZXMgYXJlIGluY2x1ZGVkIGluOiAoMTgtMzApIGZvciBhZ2UsICgxNjUtMTk0KSBmb3IgaGVpZ2h0ICg2NS05MCkgZm9yIHdlaWdodCBhbmQgKDEwLjEtMTEuMCkgZm9yIHJ1bm5pbmcgdGltZS4gIApDaG9vc2UgYSBzaW11bGF0aW9uIHByb3RvY29sIHRoYXQgY2FuIHNtYXJ0bHkgbWF0Y2ggdGhlc2UgcmFuZ2VzLiBUaGUgcm91bmQoKSBmdW5jdGlvbnMgY3V0cyBkZWNpbWFscy4gCkFueSBpZGVhIGhvdyB0byBpbnRyb2R1Y2Ugc29tZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGhlaWdodCBhbmQgd2VpZ2h0PwoKIyMjIEJhY2sgdG8gUGkgCldlIGNvbnNpZGVyIHRoZSBmaXJzdCBleGVyY2lzZS4gVGhlIHBvaW50IGhlcmUgaXMgdG8gdmlzdWFsbHkgZ3Jhc3AgdGhlIGNvbnZlcmdlbmNlIG9mIHRoZSBlc3RpbWF0b3IgYXMgdGhlIG51bWJlciBvZiBzaW11bGF0aW9ucyBpbmNyZWFzZXMuCkNyZWF0ZSBhIGRhdGFmcmFtZSB0aGF0IHN0b3JlcyB0aGUgdmFsdWVzIG9idGFpbmVkIGZvciB0aGUgZm9sbG93aW5nIDEyIHZhbHVlcyBvZiBudW1iZXIgb2Ygc2ltdWxhdGlvbnM6IDNeKDE6MTIpLgpUaGVuLCBwbG90IHRoZSByZXN1bHQsIGFzIHdlbGwgYXMgYSB2ZXJ0aWNhbCBsaW5lIGF0IDMuMTQuCgoKIyMjICoqQk9OVVMqKgpVc2UgTW9udGUtQ2FybG8gc2ltdWxhdGlvbnMgdG8gY29tcHV0ZSB0aGUgc3VyZmFjZSBvZiBhbiBlcXVpbGF0ZXJhbCB0cmlhbmdsZSB3aXRoIHVuaXQgc2lkZSBsZW5ndGguICAKQSBiaXQgb2YgaGVscDogaWYgeW91IGRyYXcgYml2YXJpYXRlIHVuaWZvcm0gc2FtcGxlcyBvbiAoLTEsMSksIHRoZSBlcXVhdGlvbiBpczogbWF4KC0yeSwgeS1zcXJ0KDMpeCwgeStzcXJ0KDMpeCkgPCBzcXJ0KDQvMykgLiAgClRoZSB0cnVlIHZhbHVlIGlzIHNxcnQoMykvNCwgd2hpY2ggaXMgYXBwcm94aW1hdGVseSBlcXVhbCB0byAwLjQzMy4K