This is the companion notebook to the course on Bayesian inference. We start by loading the packages and the data.

library(tidyverse)
# Then change your working directory
if (!require("expm")) install.packages("expm") # Only installs if missing
if (!require("markovchain")) install.packages("markovchain") # Only installs if missing
load("anes.RData")

First analysis: Beta conjugates

The simplest case when inferring proportions. Combining binomial likelihood with beta prior is appealing, given the form of the densities. The posterior distribution follows a \[B(a+y,b+n-y)\] distribution, where n is the sample size, y is the number of ‘correct’ occurrences and a and b are the prior Beta parameters.

anes_1996 <- anes %>% filter(Date == 1996)          # We keep a year with low number of respondents
y <- sum(anes_1996$Party_simple == "Republican")    # Number of Republicans
n <- nrow(anes_1996)                                # Number of observations
a <- 15                                             # Initial Beta parameter
b <- 30                                             # Initial Beta parameter
ggplot(data.frame(x = c(0,0.6)), aes(x = x)) + 
  stat_function(fun = dbeta, args = list(shape1 = a, shape2 = b), aes(color = "PRIOR")) +
  stat_function(fun = dbeta, args = list(shape1 = y , shape2 = n - y ), aes(color = "LIKELIHOOD")) +
  stat_function(fun = dbeta, args = list(shape1 = y + a, shape2 = n - y + b), aes(color = "POSTERIOR"))

# CASE when the prior is strongly concentrated around 1/3
a <- 150 # Initial Beta parameter
b <- 300 # Initial Beta parameter
ggplot(data.frame(x = c(0,0.6)), aes(x = x)) + 
  stat_function(fun = dbeta, args = list(shape1 = a, shape2 = b), aes(color = "PRIOR")) +
  stat_function(fun = dbeta, args = list(shape1 = y , shape2 = n - y ), aes(color = "LIKELIHOOD")) +
  stat_function(fun = dbeta, args = list(shape1 = y + a, shape2 = n - y + b), aes(color = "POSTERIOR"))

In the first case, the prior is diluted because the sample is already large (346 observations). One way around that is to increase the magnitude of prior parameters. This increases their relative importance in the final output.

Second analysis: non-conjugage priors on grids

A more flexible approach is to approximate the posterior distribution by means of discretisation. Below, we show what this approximation can look like if the grid is coarse.

# Illustration first: approximative rectangles via sampling
sample <- rnorm(10^5) 
sample %>% data.frame() %>% ggplot(aes(x = sample)) + geom_histogram(aes(y = ..density..)) + 
  stat_function(fun = dnorm, args = list(mean = 0, sd = 1), color = "red")

Next, we apply this technique to determine the proportion of Republicans in 1996. We choose a fine grid, with 1000 points. We use a Gaussian prior. All the steps are commented in the code.

# Inspired by Kruschke's Doing Bayesian Data Analysis
theta <- seq(0, 1, length = 1001)                # The grid for the distribution of theta
prior <- dnorm(theta, mean = 0.3, sd = 0.03)     # Specifying the prior: use your imagination to test different shapes!
prior <- prior / sum(prior)                      # The prior sums to one
k <- sum(anes_1996$Party_simple == "Republican") # Number of successes
n <- nrow(anes_1996)                             # Number of trials
likelihood <- theta^k * (1-theta)^(n-k)          # p(Data|Theta)
likelihood <- likelihood / sum(likelihood)       # Normalization => for plotting essentially
posterior <- prior * likelihood                  # p(Theta|Data)
posterior <- posterior / sum(posterior)          # Normalization
df <- data.frame(theta, prior, likelihood, posterior) %>% gather(key = distribution, value = value , -theta)
ggplot(df, aes(x = theta, y = value)) + geom_line(aes(color = distribution)) + xlim(0.1,0.6)

Given the large number of points, the curves are quite smooth.

Below, we try this approach on sampled data. We aim to plot the distribution of the mean of a Gaussian distribution with known sd (= 1).

n_sample <- 20                                  # Data size
n_grid <- 100                                   # Number of grid points
sample <- rnorm(n_sample)                       # Generating the data
m <- seq(-0.7, 0.7, length = n_grid + 1)        # The grid for the distribution of theta (the parameter: here, it's m)
m_prior <- 0.1                                  # Prior parameter (mean)
s_prior <- 0.2                                  # Prior parameter (sd)
prior <- dnorm(m, mean = m_prior, sd = s_prior) # Specifying the prior: use your imagination to test other/different shapes!
prior <- prior / sum(prior)                     # The prior sums to one
likelihood <- sapply(m, function(x) dnorm(sample, mean = x, sd = 1)) %>%
  apply(., 2, prod)                             # p(Data|Theta). NOTE: only works on small samples.
likelihood <- likelihood / sum(likelihood)      # Normalization => for plotting purpose essentially
posterior <- prior * likelihood                 # p(Theta|Data)
posterior <- posterior / sum(posterior)         # Normalization
df <- data.frame(m, prior, likelihood, posterior) %>% gather(key = distribution, value = value , -m)
ggplot(df, aes(x = m, y = value)) + geom_line(aes(color = distribution))

# Comparison with analytical formula
s_star <- sqrt(1/(1/s_prior^2+length(sample)/1))
m_star <- (m_prior/s_prior^2+sum(sample)/1)/(1/s_star^2)
analytical <- data.frame(m, value = dnorm(m, mean = m_star, sd = s_star) )
analytical$value <- analytical$value / sum(analytical$value)
ggplot(df, aes(x = m, y = value * n_sample )) + geom_line(aes(color = distribution)) +
  geom_line(data = analytical, aes(color = "analytical"))

The curves completely coincide: the red one is printed over the turquoise one.

Markov Chains

Below, we introduce the concept of Markov chain. We consider the canonical example: sleep-eat-play. The transition between the states is driven by the following matrix:

S E P
S 0.85 0.10 0.05
E 0.50 0.00 0.50
P 0.50 0.20 0.30

The first column is the current state whereas the first row is the future state. Hence, if the individual is currently playing, there is a 20% chance that he/she will be eating next.

P <- rbind(c(0.85,0.10,0.05), c(0.5,0,0.5), c(0.5,0.2,0.3)) # Transition matrix
x <- c(0,1,0)                                               # Initial state: eating
x %*% P                                                     # Prob. in t+1
     [,1] [,2] [,3]
[1,]  0.5    0  0.5
x %*% P %*% P                                               # Prob. in t+2
      [,1] [,2]  [,3]
[1,] 0.675 0.15 0.175
x %*% (P %^% 10) %>% round(3)                               # Long term probability (10 steps)
      [,1]  [,2]  [,3]
[1,] 0.769 0.103 0.128

Above, we computed the probabilities of each state (starting at the second one): one step ahead, two steps ahead and 10 steps ahead.

Below, we keep track of these probabilities and plot them. We start at state 2, which is eating (try other starting points!).

N <- 20                                                     # Number of steps
z <- matrix(0, ncol = 3, nrow = N)                          # Create matrix of probability evolution
z[1,] <- x                                                  # Initialise starting point: eat!
for(i in 2:N){                                              # Loop on time
  z[i, ] <- z[i-1, ] %*% P                                  # Updating the probability
}
z <- data.frame(1:N,z)                                      # Gathering the data
colnames(z) <- c("Hour", "Sleep", "Eat", "Play")
z <- z %>% gather(key = State, value = Value, -Hour)        # Putting in ggplot format
ggplot(z, aes(x = Hour, y = Value, color = State)) + geom_line() # Showing the convergence

Finally, we compare the terminal value with the fixed-point of the system.

Q <- cbind(P - diag(3), 1) # Adding the sum(Prob.) = 1 constraint
b <- c(0,0,0,1) 
b %*% t(Q) %*% solve(Q %*% t(Q)) # Ha! Same as the long-term probbabilities
          [,1]      [,2]      [,3]
[1,] 0.7692308 0.1025641 0.1282051

Now, there also exists a package for Markov-Chain simulations.

library(markovchain) # Great package for multi-treatment of Markov Chains
MC <- new("markovchain", states = c("Sleep", "Eat", "Play"),
          transitionMatrix = P, name="MC")
plot(MC, package="diagram", box.size = 0.08)    # Plot the transition system

simul <- rmarkovchain(1000, MC) %>% as.factor() # Simulate!
summary(simul)                                  # Do the proportions match?
  Eat  Play Sleep 
   97   117   786 

If you want to go further towards Markov-Chain Monte-Carlo, have a look at the mcmc package, or at: https://nicercode.github.io/guides/mcmc/

Exercises

Grid approximation

  1. Sample 150 observations of a Normal (mean = 0.5, sd = 0.1) distribution.
  2. Have a look at the histogram (take 15 bins): could be a beta law, don’t you think? Let’s say we know the first parameter of the beta law is equal to a = 4. Pick any prior you want and compute the posterior density / histogram of the second parameter of the corresponding beta law.

Monty Hall by Monte-Carlo

Create a Monte-Carlo simulation that replicates the Monty-Hall problem. Show that the probability of winning when changing the original choice is close to.

Conjugate prior: gender bias

Given the anes_1996 dataset, compute (i.e., plot) the posterior distribution of the proportion of women (assume a Beta prior so that the distribution is easily derived).

LS0tCnRpdGxlOiAiQmF5ZXNpYW4gaW5mZXJlbmNlIgpvdXRwdXQ6IAogICBodG1sX25vdGVib29rOgogICMgICB0b2M6IHRydWUKICAjICAgdG9jX2Zsb2F0OiB0cnVlCiAgI2dpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAotLS0KCgpUaGlzIGlzIHRoZSBjb21wYW5pb24gbm90ZWJvb2sgdG8gdGhlIGNvdXJzZSBvbiBCYXllc2lhbiBpbmZlcmVuY2UuIFdlIHN0YXJ0IGJ5IGxvYWRpbmcgdGhlIHBhY2thZ2VzIGFuZCB0aGUgZGF0YS4KCmBgYHtyIHBhY2thZ2UgJiBkYXRhLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCiMgVGhlbiBjaGFuZ2UgeW91ciB3b3JraW5nIGRpcmVjdG9yeQppZiAoIXJlcXVpcmUoImV4cG0iKSkgaW5zdGFsbC5wYWNrYWdlcygiZXhwbSIpICMgT25seSBpbnN0YWxscyBpZiBtaXNzaW5nCmlmICghcmVxdWlyZSgibWFya292Y2hhaW4iKSkgaW5zdGFsbC5wYWNrYWdlcygibWFya292Y2hhaW4iKSAjIE9ubHkgaW5zdGFsbHMgaWYgbWlzc2luZwpsb2FkKCJhbmVzLlJEYXRhIikKYGBgCgojIyBGaXJzdCBhbmFseXNpczogQmV0YSBjb25qdWdhdGVzClRoZSBzaW1wbGVzdCBjYXNlIHdoZW4gaW5mZXJyaW5nIHByb3BvcnRpb25zLiBDb21iaW5pbmcgYmlub21pYWwgbGlrZWxpaG9vZCB3aXRoIGJldGEgcHJpb3IgaXMgYXBwZWFsaW5nLCBnaXZlbiB0aGUgZm9ybSBvZiB0aGUgZGVuc2l0aWVzLiBUaGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBmb2xsb3dzIGEgJCRCKGEreSxiK24teSkkJCBkaXN0cmlidXRpb24sIHdoZXJlIG4gaXMgdGhlIHNhbXBsZSBzaXplLCB5IGlzIHRoZSBudW1iZXIgb2YgJ2NvcnJlY3QnIG9jY3VycmVuY2VzIGFuZCBhIGFuZCBiIGFyZSB0aGUgcHJpb3IgQmV0YSBwYXJhbWV0ZXJzLgpgYGB7ciBiZXRhLCBtZXNzYWdlID0gRkFMU0V9CmFuZXNfMTk5NiA8LSBhbmVzICU+JSBmaWx0ZXIoRGF0ZSA9PSAxOTk2KSAgICAgICAgICAjIFdlIGtlZXAgYSB5ZWFyIHdpdGggbG93IG51bWJlciBvZiByZXNwb25kZW50cwp5IDwtIHN1bShhbmVzXzE5OTYkUGFydHlfc2ltcGxlID09ICJSZXB1YmxpY2FuIikgICAgIyBOdW1iZXIgb2YgUmVwdWJsaWNhbnMKbiA8LSBucm93KGFuZXNfMTk5NikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTnVtYmVyIG9mIG9ic2VydmF0aW9ucwphIDwtIDE1ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBJbml0aWFsIEJldGEgcGFyYW1ldGVyCmIgPC0gMzAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEluaXRpYWwgQmV0YSBwYXJhbWV0ZXIKZ2dwbG90KGRhdGEuZnJhbWUoeCA9IGMoMCwwLjYpKSwgYWVzKHggPSB4KSkgKyAKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRiZXRhLCBhcmdzID0gbGlzdChzaGFwZTEgPSBhLCBzaGFwZTIgPSBiKSwgYWVzKGNvbG9yID0gIlBSSU9SIikpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRiZXRhLCBhcmdzID0gbGlzdChzaGFwZTEgPSB5ICwgc2hhcGUyID0gbiAtIHkgKSwgYWVzKGNvbG9yID0gIkxJS0VMSUhPT0QiKSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZGJldGEsIGFyZ3MgPSBsaXN0KHNoYXBlMSA9IHkgKyBhLCBzaGFwZTIgPSBuIC0geSArIGIpLCBhZXMoY29sb3IgPSAiUE9TVEVSSU9SIikpCgojIENBU0Ugd2hlbiB0aGUgcHJpb3IgaXMgc3Ryb25nbHkgY29uY2VudHJhdGVkIGFyb3VuZCAxLzMKYSA8LSAxNTAgIyBJbml0aWFsIEJldGEgcGFyYW1ldGVyCmIgPC0gMzAwICMgSW5pdGlhbCBCZXRhIHBhcmFtZXRlcgpnZ3Bsb3QoZGF0YS5mcmFtZSh4ID0gYygwLDAuNikpLCBhZXMoeCA9IHgpKSArIAogIHN0YXRfZnVuY3Rpb24oZnVuID0gZGJldGEsIGFyZ3MgPSBsaXN0KHNoYXBlMSA9IGEsIHNoYXBlMiA9IGIpLCBhZXMoY29sb3IgPSAiUFJJT1IiKSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZGJldGEsIGFyZ3MgPSBsaXN0KHNoYXBlMSA9IHkgLCBzaGFwZTIgPSBuIC0geSApLCBhZXMoY29sb3IgPSAiTElLRUxJSE9PRCIpKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkYmV0YSwgYXJncyA9IGxpc3Qoc2hhcGUxID0geSArIGEsIHNoYXBlMiA9IG4gLSB5ICsgYiksIGFlcyhjb2xvciA9ICJQT1NURVJJT1IiKSkKYGBgCgoKSW4gdGhlIGZpcnN0IGNhc2UsIHRoZSBwcmlvciBpcyBkaWx1dGVkIGJlY2F1c2UgdGhlIHNhbXBsZSBpcyBhbHJlYWR5IGxhcmdlICgzNDYgb2JzZXJ2YXRpb25zKS4gT25lIHdheSBhcm91bmQgdGhhdCBpcyB0byBpbmNyZWFzZSB0aGUgbWFnbml0dWRlIG9mIHByaW9yIHBhcmFtZXRlcnMuIFRoaXMgaW5jcmVhc2VzIHRoZWlyIHJlbGF0aXZlIGltcG9ydGFuY2UgaW4gdGhlIGZpbmFsIG91dHB1dC4KCgojIyBTZWNvbmQgYW5hbHlzaXM6IG5vbi1jb25qdWdhZ2UgcHJpb3JzIG9uIGdyaWRzCkEgbW9yZSBmbGV4aWJsZSBhcHByb2FjaCBpcyB0byBhcHByb3hpbWF0ZSB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBieSBtZWFucyBvZiBkaXNjcmV0aXNhdGlvbi4gQmVsb3csIHdlIHNob3cgd2hhdCB0aGlzIGFwcHJveGltYXRpb24gY2FuIGxvb2sgbGlrZSBpZiB0aGUgZ3JpZCBpcyBjb2Fyc2UuCmBgYHtyIGdyaWR9CiMgSWxsdXN0cmF0aW9uIGZpcnN0OiBhcHByb3hpbWF0aXZlIHJlY3RhbmdsZXMgdmlhIHNhbXBsaW5nCnNhbXBsZSA8LSBybm9ybSgxMF41KSAKc2FtcGxlICU+JSBkYXRhLmZyYW1lKCkgJT4lIGdncGxvdChhZXMoeCA9IHNhbXBsZSkpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLikpICsgCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IDAsIHNkID0gMSksIGNvbG9yID0gInJlZCIpCmBgYAoKTmV4dCwgd2UgYXBwbHkgdGhpcyB0ZWNobmlxdWUgdG8gZGV0ZXJtaW5lIHRoZSBwcm9wb3J0aW9uIG9mIFJlcHVibGljYW5zIGluIDE5OTYuIFdlIGNob29zZSBhIGZpbmUgZ3JpZCwgd2l0aCAxMDAwIHBvaW50cy4gV2UgdXNlIGEgR2F1c3NpYW4gcHJpb3IuIEFsbCB0aGUgc3RlcHMgYXJlIGNvbW1lbnRlZCBpbiB0aGUgY29kZS4KYGBge3IgZ3JpZCBCaW5vbWlhbCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CiMgSW5zcGlyZWQgYnkgS3J1c2Noa2UncyBEb2luZyBCYXllc2lhbiBEYXRhIEFuYWx5c2lzCnRoZXRhIDwtIHNlcSgwLCAxLCBsZW5ndGggPSAxMDAxKSAgICAgICAgICAgICAgICAjIFRoZSBncmlkIGZvciB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZXRhCnByaW9yIDwtIGRub3JtKHRoZXRhLCBtZWFuID0gMC4zLCBzZCA9IDAuMDMpICAgICAjIFNwZWNpZnlpbmcgdGhlIHByaW9yOiB1c2UgeW91ciBpbWFnaW5hdGlvbiB0byB0ZXN0IGRpZmZlcmVudCBzaGFwZXMhCnByaW9yIDwtIHByaW9yIC8gc3VtKHByaW9yKSAgICAgICAgICAgICAgICAgICAgICAjIFRoZSBwcmlvciBzdW1zIHRvIG9uZQprIDwtIHN1bShhbmVzXzE5OTYkUGFydHlfc2ltcGxlID09ICJSZXB1YmxpY2FuIikgIyBOdW1iZXIgb2Ygc3VjY2Vzc2VzCm4gPC0gbnJvdyhhbmVzXzE5OTYpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE51bWJlciBvZiB0cmlhbHMKbGlrZWxpaG9vZCA8LSB0aGV0YV5rICogKDEtdGhldGEpXihuLWspICAgICAgICAgICMgcChEYXRhfFRoZXRhKQpsaWtlbGlob29kIDwtIGxpa2VsaWhvb2QgLyBzdW0obGlrZWxpaG9vZCkgICAgICAgIyBOb3JtYWxpemF0aW9uID0+IGZvciBwbG90dGluZyBlc3NlbnRpYWxseQpwb3N0ZXJpb3IgPC0gcHJpb3IgKiBsaWtlbGlob29kICAgICAgICAgICAgICAgICAgIyBwKFRoZXRhfERhdGEpCnBvc3RlcmlvciA8LSBwb3N0ZXJpb3IgLyBzdW0ocG9zdGVyaW9yKSAgICAgICAgICAjIE5vcm1hbGl6YXRpb24KZGYgPC0gZGF0YS5mcmFtZSh0aGV0YSwgcHJpb3IsIGxpa2VsaWhvb2QsIHBvc3RlcmlvcikgJT4lIGdhdGhlcihrZXkgPSBkaXN0cmlidXRpb24sIHZhbHVlID0gdmFsdWUgLCAtdGhldGEpCmdncGxvdChkZiwgYWVzKHggPSB0aGV0YSwgeSA9IHZhbHVlKSkgKyBnZW9tX2xpbmUoYWVzKGNvbG9yID0gZGlzdHJpYnV0aW9uKSkgKyB4bGltKDAuMSwwLjYpCmBgYAoKR2l2ZW4gdGhlIGxhcmdlIG51bWJlciBvZiBwb2ludHMsIHRoZSBjdXJ2ZXMgYXJlIHF1aXRlIHNtb290aC4KCkJlbG93LCB3ZSB0cnkgdGhpcyBhcHByb2FjaCBvbiBzYW1wbGVkIGRhdGEuIFdlIGFpbSB0byBwbG90IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4gb2YgYSBHYXVzc2lhbiBkaXN0cmlidXRpb24gd2l0aCBrbm93biBzZCAoPSAxKS4KYGBge3IgZ3JpZCBHYXVzc2lhbn0Kbl9zYW1wbGUgPC0gMjAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBEYXRhIHNpemUKbl9ncmlkIDwtIDEwMCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBOdW1iZXIgb2YgZ3JpZCBwb2ludHMKc2FtcGxlIDwtIHJub3JtKG5fc2FtcGxlKSAgICAgICAgICAgICAgICAgICAgICAgIyBHZW5lcmF0aW5nIHRoZSBkYXRhCm0gPC0gc2VxKC0wLjcsIDAuNywgbGVuZ3RoID0gbl9ncmlkICsgMSkgICAgICAgICMgVGhlIGdyaWQgZm9yIHRoZSBkaXN0cmlidXRpb24gb2YgdGhldGEgKHRoZSBwYXJhbWV0ZXI6IGhlcmUsIGl0J3MgbSkKbV9wcmlvciA8LSAwLjEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBQcmlvciBwYXJhbWV0ZXIgKG1lYW4pCnNfcHJpb3IgPC0gMC4yICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUHJpb3IgcGFyYW1ldGVyIChzZCkKcHJpb3IgPC0gZG5vcm0obSwgbWVhbiA9IG1fcHJpb3IsIHNkID0gc19wcmlvcikgIyBTcGVjaWZ5aW5nIHRoZSBwcmlvcjogdXNlIHlvdXIgaW1hZ2luYXRpb24gdG8gdGVzdCBvdGhlci9kaWZmZXJlbnQgc2hhcGVzIQpwcmlvciA8LSBwcmlvciAvIHN1bShwcmlvcikgICAgICAgICAgICAgICAgICAgICAjIFRoZSBwcmlvciBzdW1zIHRvIG9uZQpsaWtlbGlob29kIDwtIHNhcHBseShtLCBmdW5jdGlvbih4KSBkbm9ybShzYW1wbGUsIG1lYW4gPSB4LCBzZCA9IDEpKSAlPiUKICBhcHBseSguLCAyLCBwcm9kKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwKERhdGF8VGhldGEpLiBOT1RFOiBvbmx5IHdvcmtzIG9uIHNtYWxsIHNhbXBsZXMuCmxpa2VsaWhvb2QgPC0gbGlrZWxpaG9vZCAvIHN1bShsaWtlbGlob29kKSAgICAgICMgTm9ybWFsaXphdGlvbiA9PiBmb3IgcGxvdHRpbmcgcHVycG9zZSBlc3NlbnRpYWxseQpwb3N0ZXJpb3IgPC0gcHJpb3IgKiBsaWtlbGlob29kICAgICAgICAgICAgICAgICAjIHAoVGhldGF8RGF0YSkKcG9zdGVyaW9yIDwtIHBvc3RlcmlvciAvIHN1bShwb3N0ZXJpb3IpICAgICAgICAgIyBOb3JtYWxpemF0aW9uCmRmIDwtIGRhdGEuZnJhbWUobSwgcHJpb3IsIGxpa2VsaWhvb2QsIHBvc3RlcmlvcikgJT4lIGdhdGhlcihrZXkgPSBkaXN0cmlidXRpb24sIHZhbHVlID0gdmFsdWUgLCAtbSkKZ2dwbG90KGRmLCBhZXMoeCA9IG0sIHkgPSB2YWx1ZSkpICsgZ2VvbV9saW5lKGFlcyhjb2xvciA9IGRpc3RyaWJ1dGlvbikpCiMgQ29tcGFyaXNvbiB3aXRoIGFuYWx5dGljYWwgZm9ybXVsYQpzX3N0YXIgPC0gc3FydCgxLygxL3NfcHJpb3JeMitsZW5ndGgoc2FtcGxlKS8xKSkKbV9zdGFyIDwtIChtX3ByaW9yL3NfcHJpb3JeMitzdW0oc2FtcGxlKS8xKS8oMS9zX3N0YXJeMikKYW5hbHl0aWNhbCA8LSBkYXRhLmZyYW1lKG0sIHZhbHVlID0gZG5vcm0obSwgbWVhbiA9IG1fc3Rhciwgc2QgPSBzX3N0YXIpICkKYW5hbHl0aWNhbCR2YWx1ZSA8LSBhbmFseXRpY2FsJHZhbHVlIC8gc3VtKGFuYWx5dGljYWwkdmFsdWUpCmdncGxvdChkZiwgYWVzKHggPSBtLCB5ID0gdmFsdWUgKiBuX3NhbXBsZSApKSArIGdlb21fbGluZShhZXMoY29sb3IgPSBkaXN0cmlidXRpb24pKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBhbmFseXRpY2FsLCBhZXMoY29sb3IgPSAiYW5hbHl0aWNhbCIpKQpgYGAKClRoZSBjdXJ2ZXMgY29tcGxldGVseSBjb2luY2lkZTogdGhlIHJlZCBvbmUgaXMgcHJpbnRlZCBvdmVyIHRoZSB0dXJxdW9pc2Ugb25lLiAKCgojIyBNYXJrb3YgQ2hhaW5zCkJlbG93LCB3ZSBpbnRyb2R1Y2UgdGhlIGNvbmNlcHQgb2YgTWFya292IGNoYWluLiBXZSBjb25zaWRlciB0aGUgY2Fub25pY2FsIGV4YW1wbGU6IHNsZWVwLWVhdC1wbGF5LiBUaGUgdHJhbnNpdGlvbiBiZXR3ZWVuIHRoZSBzdGF0ZXMgaXMgZHJpdmVuIGJ5IHRoZSBmb2xsb3dpbmcgbWF0cml4OgoKICB8ICAgICB8IFMgICAgICB8IEUgICAgfCBQICAgIHwKICB8Oi0tLTp8Oi0tLTogICB8Oi0tLTogfDotLS06IHwKICB8IFMgICB8IDAuODUgICB8IDAuMTAgfCAwLjA1IHwKICB8IEUgICB8IDAuNTAgICB8IDAuMDAgfCAwLjUwIHwKICB8IFAgICB8IDAuNTAgICB8IDAuMjAgfCAwLjMwIHwKClRoZSBmaXJzdCBjb2x1bW4gaXMgdGhlIGN1cnJlbnQgc3RhdGUgd2hlcmVhcyB0aGUgZmlyc3Qgcm93IGlzIHRoZSBmdXR1cmUgc3RhdGUuIEhlbmNlLCBpZiB0aGUgaW5kaXZpZHVhbCBpcyBjdXJyZW50bHkgcGxheWluZywgdGhlcmUgaXMgYSAyMCUgY2hhbmNlIHRoYXQgaGUvc2hlIHdpbGwgYmUgZWF0aW5nIG5leHQuCgpgYGB7ciBNQ19zaW1wbGVfY2FzZX0KUCA8LSByYmluZChjKDAuODUsMC4xMCwwLjA1KSwgYygwLjUsMCwwLjUpLCBjKDAuNSwwLjIsMC4zKSkgIyBUcmFuc2l0aW9uIG1hdHJpeAp4IDwtIGMoMCwxLDApICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIEluaXRpYWwgc3RhdGU6IGVhdGluZwp4ICUqJSBQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFByb2IuIGluIHQrMQp4ICUqJSBQICUqJSBQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFByb2IuIGluIHQrMgp4ICUqJSAoUCAlXiUgMTApICU+JSByb3VuZCgzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIExvbmcgdGVybSBwcm9iYWJpbGl0eSAoMTAgc3RlcHMpCmBgYApBYm92ZSwgd2UgY29tcHV0ZWQgdGhlIHByb2JhYmlsaXRpZXMgb2YgZWFjaCBzdGF0ZSAoc3RhcnRpbmcgYXQgdGhlIHNlY29uZCBvbmUpOiBvbmUgc3RlcCBhaGVhZCwgdHdvIHN0ZXBzIGFoZWFkIGFuZCAxMCBzdGVwcyBhaGVhZC4KCkJlbG93LCB3ZSBrZWVwIHRyYWNrIG9mIHRoZXNlIHByb2JhYmlsaXRpZXMgYW5kIHBsb3QgdGhlbS4gV2Ugc3RhcnQgYXQgc3RhdGUgMiwgd2hpY2ggaXMgZWF0aW5nICh0cnkgb3RoZXIgc3RhcnRpbmcgcG9pbnRzISkuIApgYGB7ciBNQ19zaW1wbGVfc2ltfQpOIDwtIDIwICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE51bWJlciBvZiBzdGVwcwp6IDwtIG1hdHJpeCgwLCBuY29sID0gMywgbnJvdyA9IE4pICAgICAgICAgICAgICAgICAgICAgICAgICAjIENyZWF0ZSBtYXRyaXggb2YgcHJvYmFiaWxpdHkgZXZvbHV0aW9uCnpbMSxdIDwtIHggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSW5pdGlhbGlzZSBzdGFydGluZyBwb2ludDogZWF0IQpmb3IoaSBpbiAyOk4peyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIExvb3Agb24gdGltZQogIHpbaSwgXSA8LSB6W2ktMSwgXSAlKiUgUCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFVwZGF0aW5nIHRoZSBwcm9iYWJpbGl0eQp9CnogPC0gZGF0YS5mcmFtZSgxOk4seikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgR2F0aGVyaW5nIHRoZSBkYXRhCmNvbG5hbWVzKHopIDwtIGMoIkhvdXIiLCAiU2xlZXAiLCAiRWF0IiwgIlBsYXkiKQp6IDwtIHogJT4lIGdhdGhlcihrZXkgPSBTdGF0ZSwgdmFsdWUgPSBWYWx1ZSwgLUhvdXIpICAgICAgICAjIFB1dHRpbmcgaW4gZ2dwbG90IGZvcm1hdApnZ3Bsb3QoeiwgYWVzKHggPSBIb3VyLCB5ID0gVmFsdWUsIGNvbG9yID0gU3RhdGUpKSArIGdlb21fbGluZSgpICMgU2hvd2luZyB0aGUgY29udmVyZ2VuY2UKYGBgCgpGaW5hbGx5LCB3ZSBjb21wYXJlIHRoZSB0ZXJtaW5hbCB2YWx1ZSB3aXRoIHRoZSBmaXhlZC1wb2ludCBvZiB0aGUgc3lzdGVtLgpgYGB7ciBTdGVhZHlfc3RhdGV9ClEgPC0gY2JpbmQoUCAtIGRpYWcoMyksIDEpICMgQWRkaW5nIHRoZSBzdW0oUHJvYi4pID0gMSBjb25zdHJhaW50CmIgPC0gYygwLDAsMCwxKSAKYiAlKiUgdChRKSAlKiUgc29sdmUoUSAlKiUgdChRKSkgIyBIYSEgU2FtZSBhcyB0aGUgbG9uZy10ZXJtIHByb2JiYWJpbGl0aWVzCmBgYAoKTm93LCB0aGVyZSBhbHNvIGV4aXN0cyBhIHBhY2thZ2UgZm9yIE1hcmtvdi1DaGFpbiBzaW11bGF0aW9ucy4KYGBge3IgTUNfcGFja30KbGlicmFyeShtYXJrb3ZjaGFpbikgIyBHcmVhdCBwYWNrYWdlIGZvciBtdWx0aS10cmVhdG1lbnQgb2YgTWFya292IENoYWlucwpNQyA8LSBuZXcoIm1hcmtvdmNoYWluIiwgc3RhdGVzID0gYygiU2xlZXAiLCAiRWF0IiwgIlBsYXkiKSwKICAgICAgICAgIHRyYW5zaXRpb25NYXRyaXggPSBQLCBuYW1lPSJNQyIpCnBsb3QoTUMsIHBhY2thZ2U9ImRpYWdyYW0iLCBib3guc2l6ZSA9IDAuMDgpICAgICMgUGxvdCB0aGUgdHJhbnNpdGlvbiBzeXN0ZW0Kc2ltdWwgPC0gcm1hcmtvdmNoYWluKDEwMDAsIE1DKSAlPiUgYXMuZmFjdG9yKCkgIyBTaW11bGF0ZSEKc3VtbWFyeShzaW11bCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBEbyB0aGUgcHJvcG9ydGlvbnMgbWF0Y2g/CmBgYApJZiB5b3Ugd2FudCB0byBnbyBmdXJ0aGVyIHRvd2FyZHMgTWFya292LUNoYWluIE1vbnRlLUNhcmxvLCBoYXZlIGEgbG9vayBhdCB0aGUgbWNtYyBwYWNrYWdlLCBvciBhdDogaHR0cHM6Ly9uaWNlcmNvZGUuZ2l0aHViLmlvL2d1aWRlcy9tY21jLwoKIyMgRXhlcmNpc2VzCiMjIyBHcmlkIGFwcHJveGltYXRpb24KMSkgU2FtcGxlIDE1MCBvYnNlcnZhdGlvbnMgb2YgYSBOb3JtYWwgKG1lYW4gPSAwLjUsIHNkID0gMC4xKSBkaXN0cmlidXRpb24uICAKMikgSGF2ZSBhIGxvb2sgYXQgdGhlIGhpc3RvZ3JhbSAodGFrZSAxNSBiaW5zKTogY291bGQgYmUgYSBiZXRhIGxhdywgZG9uJ3QgeW91IHRoaW5rPwpMZXQncyBzYXkgd2Uga25vdyB0aGUgZmlyc3QgcGFyYW1ldGVyIG9mIHRoZSBiZXRhIGxhdyBpcyBlcXVhbCB0byBhID0gNC4KUGljayBhbnkgcHJpb3IgeW91IHdhbnQgYW5kIGNvbXB1dGUgdGhlIHBvc3RlcmlvciBkZW5zaXR5IC8gaGlzdG9ncmFtIG9mIHRoZSBzZWNvbmQgcGFyYW1ldGVyIG9mIHRoZSBjb3JyZXNwb25kaW5nIGJldGEgbGF3LgoKCiMjIyBNb250eSBIYWxsIGJ5IE1vbnRlLUNhcmxvCkNyZWF0ZSBhIE1vbnRlLUNhcmxvIHNpbXVsYXRpb24gdGhhdCByZXBsaWNhdGVzIHRoZSBNb250eS1IYWxsIHByb2JsZW0uIFNob3cgdGhhdCB0aGUgcHJvYmFiaWxpdHkgb2Ygd2lubmluZyB3aGVuIGNoYW5naW5nIHRoZSBvcmlnaW5hbCBjaG9pY2UgaXMgY2xvc2UgdG8uCgoKIyMjIENvbmp1Z2F0ZSBwcmlvcjogZ2VuZGVyIGJpYXMKR2l2ZW4gdGhlIGFuZXNfMTk5NiBkYXRhc2V0LCBjb21wdXRlIChpLmUuLCBwbG90KSB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcHJvcG9ydGlvbiBvZiB3b21lbiAoYXNzdW1lIGEgQmV0YSBwcmlvciBzbyB0aGF0IHRoZSBkaXN0cmlidXRpb24gaXMgZWFzaWx5IGRlcml2ZWQpLgo=