Posterior Interval by ‘Numerical Method’



### Placenta Previa example
y=seq(0,1,by=0.001)

plot(y,dbeta(y,438,544),type="l",xlim=c(0.3,0.6))  #Posterior distribution

post.y=rbeta(1000,438,544)  #Taking 1000 samples from the Post. dstn

dev.new()
hist(post.y,freq=F)  #Plotting the sample


mean(post.y)  #The posterior mean
[1] 0.4461668
quantile(post.y,probs=c(0.025,0.975))  # 95% Posterior Interval using Numerical Method
     2.5%     97.5% 
0.4183153 0.4766519 







Normal Model With Discrete Prior Distribution (Estimating the mean)


options(scipen=999)  #To disable printing your results in scientific notation.

mu=c(20,30,40,50,60,70)  #Parameter of interest
prior=c(0.1,0.15,0.25,0.25,0.15,0.1)  #Discrete Prior Distribution
y=c(38.6,42.4,57.5,40.5,51.7,67.1,33.4,60.9,64.1,40.1,40.7,6.4)  #Observations (n=10)

ybar=mean(y)
sigma=10  #Known population variance
n=length(y)
like=exp((-n/(2*sigma^2))*(mu-ybar)^2)  #Likelihood function (Refer to the notes)

unn.post=prior*like  #Unnormalized Discrete Posterior dstn 
unn.post
[1] 0.00000000000000000220148 0.00000012289485905573538 0.04683563061571816704687
[4] 0.06580160638607958356605 0.00000034081137965149324 0.00000000000000001205079
nor.post=unn.post/sum(unn.post)  #Normalized Discrete Posterior dstn (We have to Normalize it to make the Probability Distribution integrate to 1)
nor.post  #We can see that the Discrete Post. dstn is [20: 0, 30: 0, 40: 0.42, 50: 0.58, 60: 0, 70: 0]
[1] 0.00000000000000001954479 0.00000109106327884201111 0.41580776526252849478738
[4] 0.58418811794322056396567 0.00000302573097203836150 0.00000000000000010698715
dev.new()
plot(mu,nor.post)  #We can see that the most likely values are 40 and 50


s.post=sample(mu,1000,prob=nor.post,replace=T)  #Take a sample from the Post. dstn
table(s.post)  #The number of observations from values of 40 and 50
s.post
 40  50 
385 615 
mean(s.post)
[1] 46.15
sd(s.post)
[1] 4.868388







Frequentist vs Bayesian Estimators (by MSE)


#Sample Size is SMALL
n=10
theta=seq(0,1,by=0.01)  #Generate values of theta from (0,1) to see the MSE at each value of theta
#Refer to the notes for the equation of the MSEs
mse.f=theta*(1-theta)/n  #MSE of the Frequentist estimator at each value of theta
mse.b=((4-n)*theta^2-(4-n)*theta+1)/(n+2)^2  #MSE of the Bayesian estimator(=Posterior Mean) at each value of theta

dev.new()
plot(theta,mse.f,type="l")
lines(theta,mse.b,col="red")
legend(x="topright", legend=c("Freq.","Bayes."), lty=c(1,1), col=c("black","red"))  

We can see that the Bayes’ MSEs are smaller in general when the sample size is small

#Sample Size is LARGE
n=1000
theta=seq(0,1,by=0.01)  #Generate values of theta from (0,1) to see the MSE at each value of theta
#Refer to the notes for the equation of the MSEs
mse.f=theta*(1-theta)/n  #MSE of the Frequentist estimator at each value of theta
mse.b=((4-n)*theta^2-(4-n)*theta+1)/(n+2)^2  #MSE of the Bayesian estimator(=Posterior Mean) at each value of theta

dev.new()
plot(theta,mse.f,type="l")
lines(theta,mse.b,col="red")
legend(x="topright", legend=c("Freq.","Bayes."), lty=c(1,1), col=c("black","red"))  

We can see that the MSEs of the two estimators are almost identical when the sample size is large







Highest Posterior Density (HPD) Credible Set



95% Credible Interval

n = 10
y = 2

ci = qbeta(c(0.025,0.975), y+1, n-y+1)
ci
[1] 0.06021773 0.51775585
Error in dev.off() : 
  QuartzBitmap_Output - unable to open file '/Users/jaeyonglee/.local/share/rstudio/notebooks/E15CF856-Bayesian/1/13BF2920BFE883ED/ce7ecaqvv8bt5_t/_rs_chunk_plot_001.png'


95% HPD interval

# install.packages("TeachingDemos")  # hpd function is in there
library(TeachingDemos)

hpd=hpd(qbeta,shape1=y+1,shape2=n-y+1)
hpd
[1] 0.04055517 0.48372366


Visualization

theta = seq(0, 1, by=0.01)

plot(theta,dbeta(theta,y+1,n-y+1),type="l",xlab=expression(theta),ylab="Posterior Density Function", cex.lab=1)

segments(ci[1],0,ci[1],dbeta(ci[1],y+1,n-y+1),col="red",lwd=2)
segments(ci[2],0,ci[2],dbeta(ci[2],y+1,n-y+1),col="red",lwd=2)
segments(ci[1],dbeta(ci[1],y+1,n-y+1),ci[2],dbeta(ci[2],y+1,n-y+1),col="red",lwd=2)

# HPD
segments(hpd[1],0,hpd[1],dbeta(hpd[1],y+1,n-y+1),col="blue",lwd=2,lty=2)
segments(hpd[2],0,hpd[2],dbeta(hpd[2],y+1,n-y+1),col="blue",lwd=2,lty=2)
segments(hpd[1],dbeta(hpd[1],y+1,n-y+1),hpd[2],dbeta(hpd[2],y+1,n-y+1),col="blue",lwd=2,lty=2)
legend(x=0.6,y=3,legend=c("95% CI=(0.06,0.52)", "95% HPD CI=(0.04,0.48)"),col=c("red","blue"),lty=c(1,2),cex=0.8)







Calculating Posterior Predictive P-values (Bayesian P-Values)



nsim=100

y=c(1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0)
T.y=sum(diff(y)!=0)
theta=rep(NA,nsim)
T.y.rep=rep(NA,nsim)

for (i in 1:nsim){
  theta[i]<-rbeta(1,8,14)
  y.rep<-rbinom(20,1,theta[i])
  T.y.rep[i]<-sum(diff(y.rep)!=0)
}

sum(T.y.rep<=T.y)/nsim  # Bayesian P-value
[1] 0

This is the Bayesian p-value (after 100 simulations)


hist(T.y.rep)  # Posterior predictive distribution of the replicated test statistic
abline(v=3,col="red")  # The value left to the red line is the p-value







Posterior dstn for Multinomial model for Categorical data



Let’s calculate the post. dstn for theta1 - theta2. (Let’s call this diff)


We’re gonna take samples from the post. dstn of (theta1,theta2,theta3) and calculate it.


library(MCMCpack)
Loading required package: coda
Loading required package: MASS
##
## Markov Chain Monte Carlo Package (MCMCpack)
## Copyright (C) 2003-2021 Andrew D. Martin, Kevin M. Quinn, and Jong Hee Park
##
## Support provided by the U.S. National Science Foundation
## (Grants SES-0350646 and SES-0350613)
##
n=1447

y1=727
y2=583
y3=137

alpha=c(y1+1,y2+1,y3+1)  # the parameters of post. dstn of (theta1,theta2,theta3)

nsim=100  # number of simulations    

theta=rdirichlet(nsim,alpha)  # Taking samples from the post. dstn of (theta1,theta2,theta3)
diff=theta[,1]-theta[,2]
diff  # theta1 - theta2
  [1] 0.10562810 0.08850064 0.11133521 0.14880062 0.09170576 0.09004244 0.04849895 0.07814048
  [9] 0.11238263 0.09523778 0.07019925 0.07856047 0.08240375 0.09766831 0.10575962 0.10521868
 [17] 0.12542080 0.10559810 0.13319903 0.10775616 0.13554330 0.08357416 0.08696108 0.10125090
 [25] 0.13818495 0.12471304 0.09711644 0.12440268 0.07473838 0.13054324 0.11836621 0.13410864
 [33] 0.07671566 0.11473167 0.11137363 0.09173639 0.06048886 0.13933621 0.11845024 0.10651097
 [41] 0.12411735 0.07698650 0.13703001 0.08163398 0.10304243 0.07565535 0.12622887 0.13891881
 [49] 0.08686959 0.11644592 0.10733023 0.14259136 0.10831884 0.10159467 0.11397080 0.11186925
 [57] 0.09299134 0.08475031 0.09747366 0.09730852 0.12853930 0.07998293 0.07742454 0.07187104
 [65] 0.09298987 0.07714006 0.09282218 0.07540104 0.09250740 0.11414998 0.11282102 0.07785968
 [73] 0.12050435 0.09884799 0.11860044 0.10809613 0.03751695 0.10312953 0.10039184 0.07973068
 [81] 0.13225262 0.08227616 0.06086792 0.09202436 0.10271909 0.08772210 0.09410449 0.08521208
 [89] 0.09947449 0.11700026 0.11808139 0.15889028 0.09612751 0.11579798 0.11020222 0.08929781
 [97] 0.09390641 0.13181758 0.08235398 0.12179827


Histogram plot of dstn for diff


hist(diff)


Point Estimate


mean(diff)
[1] 0.1020829


Interval Estimate (alpha = 0.05)


quantile(diff,probs=c(0.025,0.975))  # Equal tailed interval for alpha = 0.05
      2.5%      97.5% 
0.06066891 0.14104516 


The count of theta1 < theta2


sum(diff<0)
[1] 0


We can see that theta1 is larger than theta2.







Monte Carlo Integration


Case I



True Value


2/3
[1] 0.6666667


Direct Computation

N<-100000
theta<-runif(N,-1,1)  # Drawing N number of values
h.theta<-2*theta^2   # The h() function

mu.h.theta<-mean(h.theta)   # MC estimate
mu.h.theta
[1] 0.6688993

Pretty close to the true value.


Iteration Method

N=10000
theta=rep(0,N)  # Initializing the places to save the values I guess
h.theta=rep(0,N)
mu.h.theta=rep(0,N)

for (i in 1:N){
  theta[i]=runif(1,-1,1)  # Drawing 1 value at a time
  h.theta[i]=2*theta[i]^2
  mu.h.theta[i]=mean(h.theta[1:i])
}

mu.h.theta[N]  # MC estimate
[1] 0.6572248
dev.new()
plot(1:N,mu.h.theta,type="l")

The h(theta) eventually converges to the true value.




Case II



True Value

1-exp(-1)
[1] 0.6321206


Direct Computation

N=10000
x=runif(N)  # Drawing N number of values

# g(x) = exp(-x)
theta.hat=mean(exp(-x))  # MC estimate
theta.hat
[1] 0.6311722

Pretty close to the true value.


Iteration method

N=10000
x=rep(0,N)  # Initializing the places to save the values I guess
h.x=rep(0,N)
mu.h.x=rep(0,N)

for (i in 1:N){
  x[i]=runif(1)
  h.x[i]=exp(-x[i])
  mu.h.x[i]=mean(h.x[1:i])
}

mu.h.x[N]  # MC estimate
[1] 0.6354287
dev.new()
plot(1:N,mu.h.x,type="l")

It eventually converges to the true value.








Rejection Sampling


Example1


Target Density, p

p <- function(x) {
  if (x >= 0 && x < 0.25)
     8 * x
  else if (x >= 0.25 && x <= 1)
     8/3 - 8 * x/3
   else 0
  }


Proposal Density, g and Constant M

g <- function(x) {
   if (x >= 0 && x <= 1)
     1
   else 0
  }

M<-3  # Try out different values for M (M is better to be smaller)


Accept/Reject algorithm

m <- 1000  # Total number of accepted values needed
n.draws <- 0  # For counting the number of accepted values
draws <- c()  # Place to store accepted values

while (n.draws < m) {
   x.c <- runif(1, 0, 1)  # Drawing a candidate from the proposal density
   accept.prob <- p(x.c)/(M * g(x.c))  # The prob. of accepting for each candidate
   u <- runif(1, 0, 1)  # The auxiliary variable used for accept/reject algo.
   
   if (accept.prob >= u) {
     draws <- c(draws, x.c)  # Storing the accepted candidate
     n.draws <- n.draws + 1  # Counting the accepted candidate
     }
   }


The accepted values

head(draws)
[1] 0.5807693 0.2013411 0.6341995 0.1950827 0.2677502 0.3024960


Visualization

# Initializing variables for the plots
x <- seq(0, 1, by = 0.01)
y=rep(0,length(x))
for (i in 1:length(x)){
  y[i]=p(x[i])
}

dev.new()
par(mfrow=c(1,3))
plot(x,y,type="l",ylim=c(0,4),col="black", main="Plot of p() and Mg()")
abline(h=M,col="red")
legend("topright", legend=c("p()", "Mg()"), col=c("black", "red"), lty=1, cex=0.8)

plot(x,y,type="l",ylim=c(0,4),col="black", main="Plot of p() and the density\n of the accepted values")
lines(density(draws),col="red")
legend("topright", legend=c("p()", "acc"), col=c("black", "red"), lty=1, cex=0.8)

hist(draws,freq=F,ylim=c(0,4), xlab="x", ylab="y", main="Histogram of accepted values")
lines(x,y,type="l",col="black")




Example2


Target Density, p

x.grid=seq(-5,5,by=0.01)
p=dnorm(x.grid,0,1)


Proposal Density, g and Constant M.

g=dnorm(x.grid,0,2)
M=2


Accept/Reject algorithm

N=10000  # Total number of iterations
         # This time we will be checking the general acceptance rate
x=rep(0,N)  # Places to store the accepted values
            # The unaccepted ones will be 0 so we can count how many nonzeros there
            # out of N to calculate the general acceptance rate

for (i in 1:(N)){
  x_star=rnorm(1,0,2)  # Drawing a candidate from the proposal density
  accept.prob=dnorm(x_star,0,1)/(M*dnorm(x_star,0,2))  # Prob. of accepting
  U=runif(1,0,1)  # The auxiliary variable
  if (accept.prob>=U){x[i]=x_star}
}


The general acceptance rate

i.e. how many values were accepted out of N candidates

accept.rate=sum(x!=0)/N
accept.rate
[1] 0.5078

From this we can deduce that the number of accepted values is about half of N


Visualization

dev.new()
par(mfrow=c(1,3))
plot(x.grid,p,type="l",ylim=c(0,0.6), xlab="x", ylab="y", main="Plot of p() and Mg()")
lines(x.grid,M*g,type="l",col="red")
legend("topright", legend=c("p()", "Mg()"), col=c("black", "red"), lty=1, cex=0.8)


nonzero = x[x!=0]  # We don't need 0s to plot the density

plot(x.grid,p,type="l", main="Plot of p() and the density\n of the accepted values")
lines(density(nonzero),col="red")
legend("topright", legend=c("p()", "acc"), col=c("black", "red"), lty=1, cex=0.8)

hist(nonzero,freq=F,ylim=c(0,0.5), ylab="y", main="Histogram of accepted values")
lines(x.grid, dnorm(x.grid,0,1))








Importance Sampling


True Value

1-pnorm(3)
[1] 0.001349898


Importance Sampling Estimate

N=100000  # Number of samples to extract from the proposal dstn
x=rnorm(N,4,1)  # Samples from the proposal dstn
f.x=dnorm(x,0,1)  # To calculate the weight ftn
g.x=dnorm(x,4,1)  # To calculate the weight ftn
h.x=as.numeric(x>=3)  # Target
w.x=f.x/g.x  # Weight ftn

h.x_IS=mean(h.x*w.x)  # Importance Sampling estimate
h.x_IS
[1] 0.001357118

We can see that it is pretty close


Sampling Error of the IS estimate

sd(h.x*w.x)
[1] 0.00312042

We can see that the sampling error is very small which is an indicator of a good estimate.



Comparison to MC (CaseII)


Direct Computation

N=10000  # Number of samples to extract
x=runif(N,0,3)  # Samples extracted from Unif(0,3)
g.x=1/sqrt(2*pi)*exp(-0.5*x^2)  # The g() ftn
1/2-3*mean(g.x)  # MC estimate
[1] -0.004296541


Sampling Error of the MC estimate

sd(g.x)
[1] 0.1394672

We can see that the sampling error is a lot bigger than IS estimate’s.


Iteration Method

N=10000  # Number of samples to extract
x=rep(0,N)  # Storage for samples
g.x=rep(0,N)  # Storage for values of g()
mu.g.x=rep(0,N)  # Storage for values of mean of g()

for (i in 1:N){
  x[i]=runif(1,0,3)  # Extracting a sample
  g.x[i]=1/sqrt(2*pi)*exp(-1/2*x[i]^2)
  mu.g.x[i]=mean(g.x[1:i])
}

1/2-3*mu.g.x[N]  # MC estimate
[1] -0.005483052


Visualization

dev.new()
plot(1:N,0.5-3*mu.g.x,type="l", ylim=c(0,0.15))


Sampling Error of the MC estimate (Iteration method)

sd(g.x)
[1] 0.1393593


Comparison tp MC (Case I)

N=100000  # Number of samples to extract
x=rnorm(N)  # Samples taken from N(0,1)
h.x=as.numeric(x>=3)  # h() = P(X>=3) ; X ~ N(0,1)
h.x_MC=mean(h.x)  # MC estimate
h.x_MC
[1] 0.00132


Sample Error of MC (Case I)

sd(h.x)
[1] 0.036308

Case I has a better sample error than case II.








Markov Chain



Prediction

nsim=100
P=matrix(c(0.9,0.5,0.1,0.5),2,2)  # Transition matrix
x=matrix(c(0,1),nsim,2,byrow=T)  # Initial states

for(i in 1:(nsim-1)){
  x[i+1,]=x[i,]%*%P  # Matrix multiplication
}

dev.new()
plot(1:nsim,x[,1],type="l",ylim=c(0,1),col="red")
lines(1:nsim,x[,2],type="l",col="blue")
legend("topright", legend=c("Sunny", "Rainy"), col=c("red", "blue"), lty=1, cex=0.8)

We can see that it converges.








Gibbs Sampler (One of MCMC methods)



N=10000  # Total number of iterations(time)
burn=N/2  # Burn-in period is half of N I guess

# data (a single obs.)
y1=0
y2=0

# correlation
rho=0.8

# initial values
theta.1=rep(1,N)  # Starting point is 1 for theta1
theta.2=rep(-10,N)  # Starting point is -10 for theta2
theta=cbind(theta.1,theta.2)  # Theta binded

# iterations
for (i in 1:(N-1)){
  # Taking samples from the conditional dstns of theta1 and theta2 respectively
  theta.1[i+1]=rnorm(1,y1+rho*(theta.2[i]-y2),sqrt(1-rho^2))
  theta.2[i+1]=rnorm(1,y2+rho*(theta.1[i+1]-y1),sqrt(1-rho^2))
  # Samples binded
  theta[i+1,]=c(theta.1[i+1],theta.2[i+1])
}

head(theta)
        theta.1    theta.2
[1,]  1.0000000 -10.000000
[2,] -7.4826999  -5.727806
[3,] -4.8542972  -3.540300
[4,] -3.4723206  -1.958079
[5,] -1.5681786  -0.440435
[6,] -0.2940323   0.667433


Visualizations

# check traceplots
dev.new()
par(mfrow=c(2,1))
plot(1:N,theta.1,type="l")
plot(1:N,theta.2,type="l")

The values of theta1 and theta2 converge.


dev.new()
par(mfrow=c(1,1))
plot(theta)

A simple visualization.


ntr=1000 
dev.new()
par(mfrow=c(1,1))
plot(theta.1[1:ntr],theta.2[1:ntr],type="l")
text(theta.1[1:ntr],theta.2[1:ntr],labels=1:10,cex=1, font=5)

With this plot, we can see the movement of the convergence I guess.


The averages of thetas: these are the estimates

colMeans(theta)
    theta.1     theta.2 
-0.01851583 -0.02379488 


The correlation of thetas from the samples using conditional dstns

cor(theta)
          theta.1   theta.2
theta.1 1.0000000 0.7815042
theta.2 0.7815042 1.0000000


The correlation of thetas without the Burn-in period

cor(theta[burn:N,])
          theta.1   theta.2
theta.1 1.0000000 0.7764459
theta.2 0.7764459 1.0000000

Excluding the Burn-in period might and might not improve, I guess.


The actual dstn

library(mvtnorm)  # To sample from an actual BVN dstn

joint.s=rmvnorm(N/2,mean=c(y1,y2),sig=matrix(c(1,rho,rho,1),2,2))  # The actual dstn

head(joint.s)
           [,1]        [,2]
[1,] -1.4267623 -2.27127038
[2,] -1.4242776 -1.08538234
[3,]  1.6142546  1.97821223
[4,]  0.1976566  0.13710940
[5,] -0.5978071 -0.07247639
[6,]  1.2196402  0.23673397

Visualization

plot(xlim=c(-10,4), ylim=c(-10,4), joint.s)

The averages of thetas : these are the estimates

colMeans(joint.s)
[1] 0.01367316 0.02207730

The correlation of thetas from the samples using the actual dstn

cor(joint.s)
          [,1]      [,2]
[1,] 1.0000000 0.8009714
[2,] 0.8009714 1.0000000








Metropolis algorithm


Example1


N=10000
burn.in=N/2  # Burn-in period is half of N I guess

# data (a single obs.)
y1=0
y2=0

# correlation
rho=0.8

# initial value
sig2=1-rho^2    # variance for posterior density
sig2.prop=0.1   # variance for proposal density
theta.1=rep(1,N)  # Initial value is 1 I guess
theta.2=rep(1,N)


# iterations
for (i in 1:(N-1)){
  
  # for theta.1
  theta.1.star=rnorm(1,theta.1[i],sqrt(sig2.prop))  # Sample from the proposal dstn
  U.1=runif(1,0,1)  # U: auxiliary variable
  
  # Ratio of the two densities
  ratio.1=dnorm(theta.1.star,y1+rho*(theta.2[i]-y2),1-rho^2)/dnorm(theta.1[i],y1+rho*(theta.2[i]-y2),1-rho^2)
  
  # Probability of move
  alpha.1=min(ratio.1,1)
  
  if (U.1<=alpha.1){theta.1[i+1]=theta.1.star}  # Accepted
  else theta.1[i+1]=theta.1[i]
  
  
  ## for theta.2
  theta.2.star=rnorm(1,theta.2[i],sqrt(sig2.prop))
  U.2=runif(1,0,1)
  
  # Ratio of the two densities
  ratio.2=dnorm(theta.2.star,y2+rho*(theta.1[i+1]-y1),1-rho^2)/dnorm(theta.2[i],y2+rho*(theta.1[i+1]-y1),1-rho^2)
  
  # Probability of move
  alpha.2=min(ratio.2,1)
  
  if (U.2<=alpha.2){theta.2[i+1]=theta.2.star}  # Accepted
  else theta.2[i+1]=theta.2[i]
  
}

theta=cbind(theta.1,theta.2)  # Binding the thetas together

head(theta)
       theta.1   theta.2
[1,] 1.0000000 1.0000000
[2,] 1.0768556 1.0000000
[3,] 1.3101948 0.8304043
[4,] 1.3101948 0.5861109
[5,] 1.2283990 0.5861109
[6,] 0.7631203 0.5752664


Visualizations

# traceplots
dev.new()
par(mfrow=c(2,1))
plot(1:N,theta.1,type="l")
plot(1:N,theta.2,type="l")


dev.new()
par(mfrow=c(1,2))
hist(theta[(burn.in+1):N,1])
hist(theta[(burn.in+1):N,1])


dev.new()
par(mfrow=c(1,1))
plot(theta[(burn.in+1):N,])


The averages of theta1 and theta2: These are the estimates

colMeans(theta[(burn.in+1):N,])
   theta.1    theta.2 
0.01982588 0.02451556 


The correlation of theta1 and theta2

cor(theta[(burn.in+1):N,])
          theta.1   theta.2
theta.1 1.0000000 0.8035538
theta.2 0.8035538 1.0000000




Example2


The metropolis algorithm made into a function (because we need to run for 4 different variances)

mh=function(v,sigma,x0,N){
  x=numeric(N)  # Making N number of 0s
  x[1]=x0  # Starting point
  k=0
  for (i in 2:N){  # Starts at 2 because 1 is the starting point
    y=rnorm(1,x[i-1],sigma)  # Sampling the candidate from the proposal dstn with 
                             # mean: previous value and variance: sigma
    u=runif(1)  # The auxiliary variable
    alpha=min(dt(y,v)/dt(x[i-1],v),1)  # Calculating the probability of move
                             # The ratio r is p(candidate|y)/p(previous value|y)
                             # Where p() is in this case the t dstn with df=v
    if (u<=alpha){x[i]=y}  # Accepting the candidate
    else {x[i]=x[i-1]
    k=k+1  # Counting the number of rejections
    }
  }
  return(list(x=x,k=k))
}


Let’s run the algorithm

N=1000  # Number of samples
burn.in=N/2  # The Burn-in period
v=4  # df of t dstn
x0=1  # Starting point
sigma=c(0.05,0.5,2,16)  # Different variances for proposal dstns

mh1=mh(v,sigma[1],x0,N)
mh2=mh(v,sigma[2],x0,N)
mh3=mh(v,sigma[3],x0,N)
mh4=mh(v,sigma[4],x0,N)


The number of candidates rejected by each variance

c(mh1$k,mh2$k,mh3$k,mh4$k)/N
[1] 0.023 0.146 0.462 0.892

We can see that, when the variance(low) => Few rejected, variance(high) => Many rejected.


Visualizations

dev.new()
par(mfrow=c(2,2))
plot(1:N,mh1$x,type="l")  # The trace plots
plot(1:N,mh2$x,type="l")
plot(1:N,mh3$x,type="l")
plot(1:N,mh4$x,type="l")

The frequent horizontal lines in the trace plot means that there were many rejections. Horizontal line means that previous values were used many times because candidates were rejected.


a=seq(-5,5,by=0.01)  # To plot the t dstn

dev.new()
par(mfrow=c(2,2))

hist(mh1$x[(burn.in+1):N],freq=F,ylim=c(0,0.7))  # Histogram of the samples
                                                 # without the Burn-in period
lines(a,dt(a,df=4))  # t dstn with df=4: The actual dstn

hist(mh2$x[(burn.in+1):N],freq=F,ylim=c(0,0.4))
lines(a,dt(a,df=4))

hist(mh3$x[(burn.in+1):N],freq=F,ylim=c(0,0.4))
lines(a,dt(a,df=4))

hist(mh4$x[(burn.in+1):N],freq=F,ylim=c(0,0.4))
lines(a,dt(a,df=4))

We can see that when the variance is too low or high, the dstn of the samples were not approximate to the actual dstn. Whereas when the variance is modest, the samples were pretty approximate to the actual dstn.








Metropolis-Hastings algorithm


Example1


The M-H algorithm

N=10000  # Number of samples
burn.in=N/2  # The Burn-in period
sigma=4  # of the Rayleigh dstn
x=numeric(N)  # Initializing the spaces for the chain
x[1]=rchisq(1,df=1)  # Starting point
k=0  # Number of rejected candidates

for (i in 2:N){  # Starts from 2 because 1 is the starting point
  x.star=rchisq(1,df=x[i-1])  # Candidate taken from chisq dstn with df=previous value
  u=runif(1)  # Auxiliary variable
  
  # For calculating the ratio r
  num=(x.star/(sigma^2)*exp(-x.star^2/(2*sigma^2)))/dchisq(x.star,df=x[i-1])
  den=(x[i-1]/(sigma^2)*exp(-x[i-1]^2/(2*sigma^2)))/dchisq(x[i-1],df=x.star)
  
  alpha=min(num/den,1)  # The probability of move
  if (u<=alpha){x[i]=x.star}  # Accepting the candidate
  else {x[i]=x[i-1]
  k=k+1 # Counting the number of rejected candidates
  }
}


Visualizations

dev.new()
plot(1:N,x,type="l")  # The trace plot


# install.packages("VGAM")
library(VGAM) # For drayleigh()
Loading required package: stats4
Loading required package: splines

Attaching package: ‘VGAM’

The following object is masked from ‘package:coda’:

    nvar
xgrid=seq(0,20,by=0.1)
ytrue=drayleigh(xgrid,scale=sigma)  # The density of the actual dstn

dev.new()
hist(x[(burn.in+1):N],freq=F, main="Comparison to the actual dstn")  # freq=F: to display density on y axis not the frequency
lines(xgrid,ytrue,type="l")  # The actual dstn

We can see that the samples(the histogram) is pretty approximate to the actual dstn(the line).




Example2


N=100000  # Number of samples
burn.in=N/2  # Burn-in period

## initial value
sig2=100  # variance of the proposal dstn
theta=rep(0,N)  # Initializing the space for theta

p.th=function(th){   # The actual dstn
  0.3*exp(-0.2*th^2)+0.7*exp(-0.2*(th-10)^2)
}

## iterations
for (i in 1:(N-1)){  # No value for starting point was given so I guess it's 0
  
  theta.star=rnorm(1,theta[i],sqrt(sig2))  # candidate
  U=runif(1,0,1)  # auxiliary variable
  
  ratio=p.th(theta.star)/p.th(theta[i])  # the ratio r
  # Note that since the proposal dstn is symmetric, the ratio r is just like Metropolis'
  
  alpha=min(ratio,1)  # The probability of move
  
  if (U<=alpha){theta[i+1]=theta.star}  # Accepting the candidate
  else theta[i+1]=theta[i]
  
}


Visualizations

dev.new()
par(mfrow=c(1,1))
plot(burn.in+1:N,theta,type="l")  # the trace plot


th.grid=seq(-10,20,by=1)
th.true=rep(0,length(th.grid))
for (i in 1:length(th.grid)){
  th.true[i]=p.th(th.grid[i])
}
th.true=th.true/sum(th.true)  # Normalizing I guess? This makes sum(th.true) = 1

dev.new()
par(mfrow=c(1,1))
hist(theta,freq=FALSE, main="Comparison to the actual dstn")
lines(th.grid,th.true,type="l")


Estimate for the mean of the target dstn I guess?

mean(theta[(burn.in+1):N])
[1] 6.886633




LS0tCnRpdGxlOiAiQmF5ZXNpYW4gU3RhdGlzdGljcyAtIHB0LjEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKLS0tCgpcClwKXApcCgojIFBvc3RlcmlvciBJbnRlcnZhbCBieSAnTnVtZXJpY2FsIE1ldGhvZCcKClwKCmBgYHtyfQoKIyMjIFBsYWNlbnRhIFByZXZpYSBleGFtcGxlCnk9c2VxKDAsMSxieT0wLjAwMSkKCnBsb3QoeSxkYmV0YSh5LDQzOCw1NDQpLHR5cGU9ImwiLHhsaW09YygwLjMsMC42KSkgICNQb3N0ZXJpb3IgZGlzdHJpYnV0aW9uCgpwb3N0Lnk9cmJldGEoMTAwMCw0MzgsNTQ0KSAgI1Rha2luZyAxMDAwIHNhbXBsZXMgZnJvbSB0aGUgUG9zdC4gZHN0bgoKZGV2Lm5ldygpCmhpc3QocG9zdC55LGZyZXE9RikgICNQbG90dGluZyB0aGUgc2FtcGxlCgptZWFuKHBvc3QueSkgICNUaGUgcG9zdGVyaW9yIG1lYW4KcXVhbnRpbGUocG9zdC55LHByb2JzPWMoMC4wMjUsMC45NzUpKSAgIyA5NSUgUG9zdGVyaW9yIEludGVydmFsIHVzaW5nIE51bWVyaWNhbCBNZXRob2QKCmBgYAoKXApcClwKXApcClwKCiMgTm9ybWFsIE1vZGVsIFdpdGggRGlzY3JldGUgUHJpb3IgRGlzdHJpYnV0aW9uIChFc3RpbWF0aW5nIHRoZSBtZWFuKQoKXAoKYGBge3J9Cm9wdGlvbnMoc2NpcGVuPTk5OSkgICNUbyBkaXNhYmxlIHByaW50aW5nIHlvdXIgcmVzdWx0cyBpbiBzY2llbnRpZmljIG5vdGF0aW9uLgoKbXU9YygyMCwzMCw0MCw1MCw2MCw3MCkgICNQYXJhbWV0ZXIgb2YgaW50ZXJlc3QKcHJpb3I9YygwLjEsMC4xNSwwLjI1LDAuMjUsMC4xNSwwLjEpICAjRGlzY3JldGUgUHJpb3IgRGlzdHJpYnV0aW9uCnk9YygzOC42LDQyLjQsNTcuNSw0MC41LDUxLjcsNjcuMSwzMy40LDYwLjksNjQuMSw0MC4xLDQwLjcsNi40KSAgI09ic2VydmF0aW9ucyAobj0xMCkKCnliYXI9bWVhbih5KQpzaWdtYT0xMCAgI0tub3duIHBvcHVsYXRpb24gdmFyaWFuY2UKbj1sZW5ndGgoeSkKbGlrZT1leHAoKC1uLygyKnNpZ21hXjIpKSoobXUteWJhcileMikgICNMaWtlbGlob29kIGZ1bmN0aW9uIChSZWZlciB0byB0aGUgbm90ZXMpCgp1bm4ucG9zdD1wcmlvcipsaWtlICAjVW5ub3JtYWxpemVkIERpc2NyZXRlIFBvc3RlcmlvciBkc3RuIAp1bm4ucG9zdAoKbm9yLnBvc3Q9dW5uLnBvc3Qvc3VtKHVubi5wb3N0KSAgI05vcm1hbGl6ZWQgRGlzY3JldGUgUG9zdGVyaW9yIGRzdG4gKFdlIGhhdmUgdG8gTm9ybWFsaXplIGl0IHRvIG1ha2UgdGhlIFByb2JhYmlsaXR5IERpc3RyaWJ1dGlvbiBpbnRlZ3JhdGUgdG8gMSkKbm9yLnBvc3QgICNXZSBjYW4gc2VlIHRoYXQgdGhlIERpc2NyZXRlIFBvc3QuIGRzdG4gaXMgWzIwOiAwLCAzMDogMCwgNDA6IDAuNDIsIDUwOiAwLjU4LCA2MDogMCwgNzA6IDBdCgpkZXYubmV3KCkKcGxvdChtdSxub3IucG9zdCkgICNXZSBjYW4gc2VlIHRoYXQgdGhlIG1vc3QgbGlrZWx5IHZhbHVlcyBhcmUgNDAgYW5kIDUwCgpzLnBvc3Q9c2FtcGxlKG11LDEwMDAscHJvYj1ub3IucG9zdCxyZXBsYWNlPVQpICAjVGFrZSBhIHNhbXBsZSBmcm9tIHRoZSBQb3N0LiBkc3RuCnRhYmxlKHMucG9zdCkgICNUaGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmcm9tIHZhbHVlcyBvZiA0MCBhbmQgNTAKbWVhbihzLnBvc3QpCnNkKHMucG9zdCkKCmBgYAoKXApcClwKXApcClwKCiMgRnJlcXVlbnRpc3QgdnMgQmF5ZXNpYW4gRXN0aW1hdG9ycyAoYnkgTVNFKQoKXAoKYGBge3J9CiNTYW1wbGUgU2l6ZSBpcyBTTUFMTApuPTEwCnRoZXRhPXNlcSgwLDEsYnk9MC4wMSkgICNHZW5lcmF0ZSB2YWx1ZXMgb2YgdGhldGEgZnJvbSAoMCwxKSB0byBzZWUgdGhlIE1TRSBhdCBlYWNoIHZhbHVlIG9mIHRoZXRhCiNSZWZlciB0byB0aGUgbm90ZXMgZm9yIHRoZSBlcXVhdGlvbiBvZiB0aGUgTVNFcwptc2UuZj10aGV0YSooMS10aGV0YSkvbiAgI01TRSBvZiB0aGUgRnJlcXVlbnRpc3QgZXN0aW1hdG9yIGF0IGVhY2ggdmFsdWUgb2YgdGhldGEKbXNlLmI9KCg0LW4pKnRoZXRhXjItKDQtbikqdGhldGErMSkvKG4rMileMiAgI01TRSBvZiB0aGUgQmF5ZXNpYW4gZXN0aW1hdG9yKD1Qb3N0ZXJpb3IgTWVhbikgYXQgZWFjaCB2YWx1ZSBvZiB0aGV0YQoKZGV2Lm5ldygpCnBsb3QodGhldGEsbXNlLmYsdHlwZT0ibCIpCmxpbmVzKHRoZXRhLG1zZS5iLGNvbD0icmVkIikKbGVnZW5kKHg9InRvcHJpZ2h0IiwgbGVnZW5kPWMoIkZyZXEuIiwiQmF5ZXMuIiksIGx0eT1jKDEsMSksIGNvbD1jKCJibGFjayIsInJlZCIpKSAgCmBgYAoKIyMjIyBXZSBjYW4gc2VlIHRoYXQgdGhlIEJheWVzJyBNU0VzIGFyZSBzbWFsbGVyIGluIGdlbmVyYWwgd2hlbiB0aGUgc2FtcGxlIHNpemUgaXMgc21hbGwKCgpgYGB7cn0KI1NhbXBsZSBTaXplIGlzIExBUkdFCm49MTAwMAp0aGV0YT1zZXEoMCwxLGJ5PTAuMDEpICAjR2VuZXJhdGUgdmFsdWVzIG9mIHRoZXRhIGZyb20gKDAsMSkgdG8gc2VlIHRoZSBNU0UgYXQgZWFjaCB2YWx1ZSBvZiB0aGV0YQojUmVmZXIgdG8gdGhlIG5vdGVzIGZvciB0aGUgZXF1YXRpb24gb2YgdGhlIE1TRXMKbXNlLmY9dGhldGEqKDEtdGhldGEpL24gICNNU0Ugb2YgdGhlIEZyZXF1ZW50aXN0IGVzdGltYXRvciBhdCBlYWNoIHZhbHVlIG9mIHRoZXRhCm1zZS5iPSgoNC1uKSp0aGV0YV4yLSg0LW4pKnRoZXRhKzEpLyhuKzIpXjIgICNNU0Ugb2YgdGhlIEJheWVzaWFuIGVzdGltYXRvcig9UG9zdGVyaW9yIE1lYW4pIGF0IGVhY2ggdmFsdWUgb2YgdGhldGEKCmRldi5uZXcoKQpwbG90KHRoZXRhLG1zZS5mLHR5cGU9ImwiKQpsaW5lcyh0aGV0YSxtc2UuYixjb2w9InJlZCIpCmxlZ2VuZCh4PSJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJGcmVxLiIsIkJheWVzLiIpLCBsdHk9YygxLDEpLCBjb2w9YygiYmxhY2siLCJyZWQiKSkgIApgYGAKCiMjIyMgV2UgY2FuIHNlZSB0aGF0IHRoZSBNU0VzIG9mIHRoZSB0d28gZXN0aW1hdG9ycyBhcmUgYWxtb3N0IGlkZW50aWNhbCB3aGVuIHRoZSBzYW1wbGUgc2l6ZSBpcyBsYXJnZQoKXApcClwKXApcClwKCiMgSGlnaGVzdCBQb3N0ZXJpb3IgRGVuc2l0eSAoSFBEKSBDcmVkaWJsZSBTZXQKClwKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDA4Ni5qcGVnKQoKXAoKIyMjIDk1JSBDcmVkaWJsZSBJbnRlcnZhbAoKYGBge3J9Cm4gPSAxMAp5ID0gMgoKY2kgPSBxYmV0YShjKDAuMDI1LDAuOTc1KSwgeSsxLCBuLXkrMSkKY2kKYGBgCgpcCgojIyMgOTUlIEhQRCBpbnRlcnZhbAoKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygiVGVhY2hpbmdEZW1vcyIpICAjIGhwZCBmdW5jdGlvbiBpcyBpbiB0aGVyZQpsaWJyYXJ5KFRlYWNoaW5nRGVtb3MpCgpocGQ9aHBkKHFiZXRhLHNoYXBlMT15KzEsc2hhcGUyPW4teSsxKQpocGQKYGBgCgpcCgojIyMgVmlzdWFsaXphdGlvbgoKYGBge3J9CnRoZXRhID0gc2VxKDAsIDEsIGJ5PTAuMDEpCgpwbG90KHRoZXRhLGRiZXRhKHRoZXRhLHkrMSxuLXkrMSksdHlwZT0ibCIseGxhYj1leHByZXNzaW9uKHRoZXRhKSx5bGFiPSJQb3N0ZXJpb3IgRGVuc2l0eSBGdW5jdGlvbiIsIGNleC5sYWI9MSkKCnNlZ21lbnRzKGNpWzFdLDAsY2lbMV0sZGJldGEoY2lbMV0seSsxLG4teSsxKSxjb2w9InJlZCIsbHdkPTIpCnNlZ21lbnRzKGNpWzJdLDAsY2lbMl0sZGJldGEoY2lbMl0seSsxLG4teSsxKSxjb2w9InJlZCIsbHdkPTIpCnNlZ21lbnRzKGNpWzFdLGRiZXRhKGNpWzFdLHkrMSxuLXkrMSksY2lbMl0sZGJldGEoY2lbMl0seSsxLG4teSsxKSxjb2w9InJlZCIsbHdkPTIpCgojIEhQRApzZWdtZW50cyhocGRbMV0sMCxocGRbMV0sZGJldGEoaHBkWzFdLHkrMSxuLXkrMSksY29sPSJibHVlIixsd2Q9MixsdHk9MikKc2VnbWVudHMoaHBkWzJdLDAsaHBkWzJdLGRiZXRhKGhwZFsyXSx5KzEsbi15KzEpLGNvbD0iYmx1ZSIsbHdkPTIsbHR5PTIpCnNlZ21lbnRzKGhwZFsxXSxkYmV0YShocGRbMV0seSsxLG4teSsxKSxocGRbMl0sZGJldGEoaHBkWzJdLHkrMSxuLXkrMSksY29sPSJibHVlIixsd2Q9MixsdHk9MikKbGVnZW5kKHg9MC42LHk9MyxsZWdlbmQ9YygiOTUlIENJPSgwLjA2LDAuNTIpIiwgIjk1JSBIUEQgQ0k9KDAuMDQsMC40OCkiKSxjb2w9YygicmVkIiwiYmx1ZSIpLGx0eT1jKDEsMiksY2V4PTAuOCkKYGBgCgpcClwKXApcClwKXAoKIyBDYWxjdWxhdGluZyBQb3N0ZXJpb3IgUHJlZGljdGl2ZSBQLXZhbHVlcyAoQmF5ZXNpYW4gUC1WYWx1ZXMpCgpcCgohW10oL1VzZXJzL2phZXlvbmdsZWUvRG9jdW1lbnRzL0NvbGxlZ2UvQmFjaGVsb3IvNHlfMnMvYmF5ZXMvUi9pbWFnZXMvSU1HXzAwODMuanBlZykKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDA4NC5qcGVnKQoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL0JhY2hlbG9yLzR5XzJzL2JheWVzL1IvaW1hZ2VzL0lNR18wMDg1LmpwZWcpCgpcCgpgYGB7cn0KbnNpbT0xMDAKCnk9YygxLDEsMCwwLDAsMCwwLDEsMSwxLDEsMSwwLDAsMCwwLDAsMCwwLDApClQueT1zdW0oZGlmZih5KSE9MCkKdGhldGE9cmVwKE5BLG5zaW0pClQueS5yZXA9cmVwKE5BLG5zaW0pCgpmb3IgKGkgaW4gMTpuc2ltKXsKICB0aGV0YVtpXTwtcmJldGEoMSw4LDE0KQogIHkucmVwPC1yYmlub20oMjAsMSx0aGV0YVtpXSkKICBULnkucmVwW2ldPC1zdW0oZGlmZih5LnJlcCkhPTApCn0KCnN1bShULnkucmVwPD1ULnkpL25zaW0gICMgQmF5ZXNpYW4gUC12YWx1ZQoKYGBgCgojIyMjIFRoaXMgaXMgdGhlIEJheWVzaWFuIHAtdmFsdWUgKGFmdGVyIDEwMCBzaW11bGF0aW9ucykKClwKCmBgYHtyfQpoaXN0KFQueS5yZXApICAjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcmVwbGljYXRlZCB0ZXN0IHN0YXRpc3RpYwphYmxpbmUodj0zLGNvbD0icmVkIikgICMgVGhlIHZhbHVlIGxlZnQgdG8gdGhlIHJlZCBsaW5lIGlzIHRoZSBwLXZhbHVlCmBgYAoKXApcClwKXApcClwKCiMgUG9zdGVyaW9yIGRzdG4gZm9yIE11bHRpbm9taWFsIG1vZGVsIGZvciBDYXRlZ29yaWNhbCBkYXRhCgpcCgohW10oL1VzZXJzL2phZXlvbmdsZWUvRG9jdW1lbnRzL0NvbGxlZ2UvQmFjaGVsb3IvNHlfMnMvYmF5ZXMvUi9pbWFnZXMvc3MucG5nKQoKXAoKIyMjIyBMZXQncyBjYWxjdWxhdGUgdGhlIHBvc3QuIGRzdG4gZm9yIHRoZXRhMSAtIHRoZXRhMi4gKExldCdzIGNhbGwgdGhpcyBkaWZmKQoKXAoKIyMjIyBXZSdyZSBnb25uYSB0YWtlIHNhbXBsZXMgZnJvbSB0aGUgcG9zdC4gZHN0biBvZiAodGhldGExLHRoZXRhMix0aGV0YTMpIGFuZCBjYWxjdWxhdGUgaXQuCgpcCmBgYHtyfQpsaWJyYXJ5KE1DTUNwYWNrKQoKbj0xNDQ3Cgp5MT03MjcKeTI9NTgzCnkzPTEzNwoKYWxwaGE9Yyh5MSsxLHkyKzEseTMrMSkgICMgdGhlIHBhcmFtZXRlcnMgb2YgcG9zdC4gZHN0biBvZiAodGhldGExLHRoZXRhMix0aGV0YTMpCgpuc2ltPTEwMCAgIyBudW1iZXIgb2Ygc2ltdWxhdGlvbnMgICAgCgp0aGV0YT1yZGlyaWNobGV0KG5zaW0sYWxwaGEpICAjIFRha2luZyBzYW1wbGVzIGZyb20gdGhlIHBvc3QuIGRzdG4gb2YgKHRoZXRhMSx0aGV0YTIsdGhldGEzKQpkaWZmPXRoZXRhWywxXS10aGV0YVssMl0KZGlmZiAgIyB0aGV0YTEgLSB0aGV0YTIKYGBgCgpcCgojIyMgSGlzdG9ncmFtIHBsb3Qgb2YgZHN0biBmb3IgZGlmZgoKXAoKYGBge3J9Cmhpc3QoZGlmZikKYGBgCgpcCgojIyMgUG9pbnQgRXN0aW1hdGUKClwKCmBgYHtyfQptZWFuKGRpZmYpCmBgYAoKXAoKIyMjIEludGVydmFsIEVzdGltYXRlIChhbHBoYSA9IDAuMDUpCgpcCgpgYGB7cn0KcXVhbnRpbGUoZGlmZixwcm9icz1jKDAuMDI1LDAuOTc1KSkgICMgRXF1YWwgdGFpbGVkIGludGVydmFsIGZvciBhbHBoYSA9IDAuMDUKYGBgCgpcCgojIyMgVGhlIGNvdW50IG9mIHRoZXRhMSA8IHRoZXRhMgoKXAoKYGBge3J9CnN1bShkaWZmPDApCmBgYAoKXAoKIyMjIFdlIGNhbiBzZWUgdGhhdCB0aGV0YTEgaXMgbGFyZ2VyIHRoYW4gdGhldGEyLgoKXApcClwKXApcClwKCiMgTW9udGUgQ2FybG8gSW50ZWdyYXRpb24KClwKCiMjIENhc2UgSQoKXAoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL0JhY2hlbG9yLzR5XzJzL2JheWVzL1IvaW1hZ2VzL0lNR18wMTUzLmpwZWcpCgohW10oL1VzZXJzL2phZXlvbmdsZWUvRG9jdW1lbnRzL0NvbGxlZ2UvQmFjaGVsb3IvNHlfMnMvYmF5ZXMvUi9pbWFnZXMvSU1HXzAxNTIuanBlZykKClwKCiMjIyBUcnVlIFZhbHVlCgpcCgpgYGB7cn0KMi8zCmBgYAoKXAoKIyMjIERpcmVjdCBDb21wdXRhdGlvbgoKYGBge3J9Ck48LTEwMDAwMAp0aGV0YTwtcnVuaWYoTiwtMSwxKSAgIyBEcmF3aW5nIE4gbnVtYmVyIG9mIHZhbHVlcwpoLnRoZXRhPC0yKnRoZXRhXjIgICAjIFRoZSBoKCkgZnVuY3Rpb24KCm11LmgudGhldGE8LW1lYW4oaC50aGV0YSkgICAjIE1DIGVzdGltYXRlCm11LmgudGhldGEKYGBgCgojIyMjIFByZXR0eSBjbG9zZSB0byB0aGUgdHJ1ZSB2YWx1ZS4KClwKCiMjIyBJdGVyYXRpb24gTWV0aG9kCgpgYGB7cn0KTj0xMDAwMAp0aGV0YT1yZXAoMCxOKSAgIyBJbml0aWFsaXppbmcgdGhlIHBsYWNlcyB0byBzYXZlIHRoZSB2YWx1ZXMgSSBndWVzcwpoLnRoZXRhPXJlcCgwLE4pCm11LmgudGhldGE9cmVwKDAsTikKCmZvciAoaSBpbiAxOk4pewogIHRoZXRhW2ldPXJ1bmlmKDEsLTEsMSkgICMgRHJhd2luZyAxIHZhbHVlIGF0IGEgdGltZQogIGgudGhldGFbaV09Mip0aGV0YVtpXV4yCiAgbXUuaC50aGV0YVtpXT1tZWFuKGgudGhldGFbMTppXSkKfQoKbXUuaC50aGV0YVtOXSAgIyBNQyBlc3RpbWF0ZQpgYGAKCmBgYHtyfQpkZXYubmV3KCkKcGxvdCgxOk4sbXUuaC50aGV0YSx0eXBlPSJsIikKYGBgCgojIyMjIFRoZSBoKHRoZXRhKSBldmVudHVhbGx5IGNvbnZlcmdlcyB0byB0aGUgdHJ1ZSB2YWx1ZS4KClwKXApcCgojIyBDYXNlIElJCgpcCgohW10oL1VzZXJzL2phZXlvbmdsZWUvRG9jdW1lbnRzL0NvbGxlZ2UvQmFjaGVsb3IvNHlfMnMvYmF5ZXMvUi9pbWFnZXMvSU1HXzAxNTQuanBlZykKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDE1NS5qcGVnKQoKXAoKIyMjIFRydWUgVmFsdWUKCmBgYHtyfQoxLWV4cCgtMSkKYGBgCgpcCgojIyMgRGlyZWN0IENvbXB1dGF0aW9uCgpgYGB7cn0KTj0xMDAwMAp4PXJ1bmlmKE4pICAjIERyYXdpbmcgTiBudW1iZXIgb2YgdmFsdWVzCgojIGcoeCkgPSBleHAoLXgpCnRoZXRhLmhhdD1tZWFuKGV4cCgteCkpICAjIE1DIGVzdGltYXRlCnRoZXRhLmhhdApgYGAKCiMjIyMgUHJldHR5IGNsb3NlIHRvIHRoZSB0cnVlIHZhbHVlLgoKXAoKIyMjIEl0ZXJhdGlvbiBtZXRob2QKCmBgYHtyfQpOPTEwMDAwCng9cmVwKDAsTikgICMgSW5pdGlhbGl6aW5nIHRoZSBwbGFjZXMgdG8gc2F2ZSB0aGUgdmFsdWVzIEkgZ3Vlc3MKaC54PXJlcCgwLE4pCm11LmgueD1yZXAoMCxOKQoKZm9yIChpIGluIDE6Til7CiAgeFtpXT1ydW5pZigxKQogIGgueFtpXT1leHAoLXhbaV0pCiAgbXUuaC54W2ldPW1lYW4oaC54WzE6aV0pCn0KCm11LmgueFtOXSAgIyBNQyBlc3RpbWF0ZQpgYGAKCmBgYHtyfQpkZXYubmV3KCkKcGxvdCgxOk4sbXUuaC54LHR5cGU9ImwiKQpgYGAKCiMjIyMgSXQgZXZlbnR1YWxseSBjb252ZXJnZXMgdG8gdGhlIHRydWUgdmFsdWUuCgpcClwKXApcClwKXApcCgojIFJlamVjdGlvbiBTYW1wbGluZwoKXAoKIyMgRXhhbXBsZTEKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDE1Ny5qcGVnKQoKXAoKIyMjIFRhcmdldCBEZW5zaXR5LCBwCgpgYGB7cn0KcCA8LSBmdW5jdGlvbih4KSB7CiAgaWYgKHggPj0gMCAmJiB4IDwgMC4yNSkKICAgICA4ICogeAogIGVsc2UgaWYgKHggPj0gMC4yNSAmJiB4IDw9IDEpCiAgICAgOC8zIC0gOCAqIHgvMwogICBlbHNlIDAKICB9CmBgYAoKXAoKIyMjIFByb3Bvc2FsIERlbnNpdHksIGcgYW5kIENvbnN0YW50IE0KCmBgYHtyfQpnIDwtIGZ1bmN0aW9uKHgpIHsKICAgaWYgKHggPj0gMCAmJiB4IDw9IDEpCiAgICAgMQogICBlbHNlIDAKICB9CgpNPC0zICAjIFRyeSBvdXQgZGlmZmVyZW50IHZhbHVlcyBmb3IgTSAoTSBpcyBiZXR0ZXIgdG8gYmUgc21hbGxlcikKYGBgCgpcCgojIyMgQWNjZXB0L1JlamVjdCBhbGdvcml0aG0KCmBgYHtyfQptIDwtIDEwMDAgICMgVG90YWwgbnVtYmVyIG9mIGFjY2VwdGVkIHZhbHVlcyBuZWVkZWQKbi5kcmF3cyA8LSAwICAjIEZvciBjb3VudGluZyB0aGUgbnVtYmVyIG9mIGFjY2VwdGVkIHZhbHVlcwpkcmF3cyA8LSBjKCkgICMgUGxhY2UgdG8gc3RvcmUgYWNjZXB0ZWQgdmFsdWVzCgp3aGlsZSAobi5kcmF3cyA8IG0pIHsKICAgeC5jIDwtIHJ1bmlmKDEsIDAsIDEpICAjIERyYXdpbmcgYSBjYW5kaWRhdGUgZnJvbSB0aGUgcHJvcG9zYWwgZGVuc2l0eQogICBhY2NlcHQucHJvYiA8LSBwKHguYykvKE0gKiBnKHguYykpICAjIFRoZSBwcm9iLiBvZiBhY2NlcHRpbmcgZm9yIGVhY2ggY2FuZGlkYXRlCiAgIHUgPC0gcnVuaWYoMSwgMCwgMSkgICMgVGhlIGF1eGlsaWFyeSB2YXJpYWJsZSB1c2VkIGZvciBhY2NlcHQvcmVqZWN0IGFsZ28uCiAgIAogICBpZiAoYWNjZXB0LnByb2IgPj0gdSkgewogICAgIGRyYXdzIDwtIGMoZHJhd3MsIHguYykgICMgU3RvcmluZyB0aGUgYWNjZXB0ZWQgY2FuZGlkYXRlCiAgICAgbi5kcmF3cyA8LSBuLmRyYXdzICsgMSAgIyBDb3VudGluZyB0aGUgYWNjZXB0ZWQgY2FuZGlkYXRlCiAgICAgfQogICB9CmBgYAoKXAoKIyMjIFRoZSBhY2NlcHRlZCB2YWx1ZXMKCmBgYHtyfQpoZWFkKGRyYXdzKQpgYGAKClwKCiMjIyBWaXN1YWxpemF0aW9uCgpgYGB7cn0KIyBJbml0aWFsaXppbmcgdmFyaWFibGVzIGZvciB0aGUgcGxvdHMKeCA8LSBzZXEoMCwgMSwgYnkgPSAwLjAxKQp5PXJlcCgwLGxlbmd0aCh4KSkKZm9yIChpIGluIDE6bGVuZ3RoKHgpKXsKICB5W2ldPXAoeFtpXSkKfQoKZGV2Lm5ldygpCnBhcihtZnJvdz1jKDEsMykpCnBsb3QoeCx5LHR5cGU9ImwiLHlsaW09YygwLDQpLGNvbD0iYmxhY2siLCBtYWluPSJQbG90IG9mIHAoKSBhbmQgTWcoKSIpCmFibGluZShoPU0sY29sPSJyZWQiKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoInAoKSIsICJNZygpIiksIGNvbD1jKCJibGFjayIsICJyZWQiKSwgbHR5PTEsIGNleD0wLjgpCgpwbG90KHgseSx0eXBlPSJsIix5bGltPWMoMCw0KSxjb2w9ImJsYWNrIiwgbWFpbj0iUGxvdCBvZiBwKCkgYW5kIHRoZSBkZW5zaXR5XG4gb2YgdGhlIGFjY2VwdGVkIHZhbHVlcyIpCmxpbmVzKGRlbnNpdHkoZHJhd3MpLGNvbD0icmVkIikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJwKCkiLCAiYWNjIiksIGNvbD1jKCJibGFjayIsICJyZWQiKSwgbHR5PTEsIGNleD0wLjgpCgpoaXN0KGRyYXdzLGZyZXE9Rix5bGltPWMoMCw0KSwgeGxhYj0ieCIsIHlsYWI9InkiLCBtYWluPSJIaXN0b2dyYW0gb2YgYWNjZXB0ZWQgdmFsdWVzIikKbGluZXMoeCx5LHR5cGU9ImwiLGNvbD0iYmxhY2siKQpgYGAKClwKXApcCgojIyBFeGFtcGxlMgoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL0JhY2hlbG9yLzR5XzJzL2JheWVzL1IvaW1hZ2VzL0lNR18wMTU4LmpwZWcpCgpcCgojIyMgVGFyZ2V0IERlbnNpdHksIHAKCmBgYHtyfQp4LmdyaWQ9c2VxKC01LDUsYnk9MC4wMSkKcD1kbm9ybSh4LmdyaWQsMCwxKQpgYGAKClwKCiMjIyBQcm9wb3NhbCBEZW5zaXR5LCBnIGFuZCBDb25zdGFudCBNLgoKYGBge3J9Cmc9ZG5vcm0oeC5ncmlkLDAsMikKTT0yCmBgYAoKXAoKIyMjIEFjY2VwdC9SZWplY3QgYWxnb3JpdGhtCgpgYGB7cn0KTj0xMDAwMCAgIyBUb3RhbCBudW1iZXIgb2YgaXRlcmF0aW9ucwogICAgICAgICAjIFRoaXMgdGltZSB3ZSB3aWxsIGJlIGNoZWNraW5nIHRoZSBnZW5lcmFsIGFjY2VwdGFuY2UgcmF0ZQp4PXJlcCgwLE4pICAjIFBsYWNlcyB0byBzdG9yZSB0aGUgYWNjZXB0ZWQgdmFsdWVzCiAgICAgICAgICAgICMgVGhlIHVuYWNjZXB0ZWQgb25lcyB3aWxsIGJlIDAgc28gd2UgY2FuIGNvdW50IGhvdyBtYW55IG5vbnplcm9zIHRoZXJlCiAgICAgICAgICAgICMgb3V0IG9mIE4gdG8gY2FsY3VsYXRlIHRoZSBnZW5lcmFsIGFjY2VwdGFuY2UgcmF0ZQoKZm9yIChpIGluIDE6KE4pKXsKICB4X3N0YXI9cm5vcm0oMSwwLDIpICAjIERyYXdpbmcgYSBjYW5kaWRhdGUgZnJvbSB0aGUgcHJvcG9zYWwgZGVuc2l0eQogIGFjY2VwdC5wcm9iPWRub3JtKHhfc3RhciwwLDEpLyhNKmRub3JtKHhfc3RhciwwLDIpKSAgIyBQcm9iLiBvZiBhY2NlcHRpbmcKICBVPXJ1bmlmKDEsMCwxKSAgIyBUaGUgYXV4aWxpYXJ5IHZhcmlhYmxlCiAgaWYgKGFjY2VwdC5wcm9iPj1VKXt4W2ldPXhfc3Rhcn0KfQpgYGAKClwKCiMjIyBUaGUgZ2VuZXJhbCBhY2NlcHRhbmNlIHJhdGUKCiMjIyMgaS5lLiBob3cgbWFueSB2YWx1ZXMgd2VyZSBhY2NlcHRlZCBvdXQgb2YgTiBjYW5kaWRhdGVzCgpgYGB7cn0KYWNjZXB0LnJhdGU9c3VtKHghPTApL04KYWNjZXB0LnJhdGUKYGBgCgojIyMjIEZyb20gdGhpcyB3ZSBjYW4gZGVkdWNlIHRoYXQgdGhlIG51bWJlciBvZiBhY2NlcHRlZCB2YWx1ZXMgaXMgYWJvdXQgaGFsZiBvZiBOCgpcCgojIyMgVmlzdWFsaXphdGlvbgoKYGBge3J9CmRldi5uZXcoKQpwYXIobWZyb3c9YygxLDMpKQpwbG90KHguZ3JpZCxwLHR5cGU9ImwiLHlsaW09YygwLDAuNiksIHhsYWI9IngiLCB5bGFiPSJ5IiwgbWFpbj0iUGxvdCBvZiBwKCkgYW5kIE1nKCkiKQpsaW5lcyh4LmdyaWQsTSpnLHR5cGU9ImwiLGNvbD0icmVkIikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJwKCkiLCAiTWcoKSIpLCBjb2w9YygiYmxhY2siLCAicmVkIiksIGx0eT0xLCBjZXg9MC44KQoKCm5vbnplcm8gPSB4W3ghPTBdICAjIFdlIGRvbid0IG5lZWQgMHMgdG8gcGxvdCB0aGUgZGVuc2l0eQoKcGxvdCh4LmdyaWQscCx0eXBlPSJsIiwgbWFpbj0iUGxvdCBvZiBwKCkgYW5kIHRoZSBkZW5zaXR5XG4gb2YgdGhlIGFjY2VwdGVkIHZhbHVlcyIpCmxpbmVzKGRlbnNpdHkobm9uemVybyksY29sPSJyZWQiKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoInAoKSIsICJhY2MiKSwgY29sPWMoImJsYWNrIiwgInJlZCIpLCBsdHk9MSwgY2V4PTAuOCkKCmhpc3Qobm9uemVybyxmcmVxPUYseWxpbT1jKDAsMC41KSwgeWxhYj0ieSIsIG1haW49Ikhpc3RvZ3JhbSBvZiBhY2NlcHRlZCB2YWx1ZXMiKQpsaW5lcyh4LmdyaWQsIGRub3JtKHguZ3JpZCwwLDEpKQpgYGAKClwKXApcClwKXApcClwKCiMgSW1wb3J0YW5jZSBTYW1wbGluZwoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL0JhY2hlbG9yLzR5XzJzL2JheWVzL1IvaW1hZ2VzL0lNR18wMTYwLmpwZWcpCgpcCgojIyMgVHJ1ZSBWYWx1ZQoKYGBge3J9CjEtcG5vcm0oMykKYGBgCgpcCgojIyMgSW1wb3J0YW5jZSBTYW1wbGluZyBFc3RpbWF0ZQoKYGBge3J9Ck49MTAwMDAwICAjIE51bWJlciBvZiBzYW1wbGVzIHRvIGV4dHJhY3QgZnJvbSB0aGUgcHJvcG9zYWwgZHN0bgp4PXJub3JtKE4sNCwxKSAgIyBTYW1wbGVzIGZyb20gdGhlIHByb3Bvc2FsIGRzdG4KZi54PWRub3JtKHgsMCwxKSAgIyBUbyBjYWxjdWxhdGUgdGhlIHdlaWdodCBmdG4KZy54PWRub3JtKHgsNCwxKSAgIyBUbyBjYWxjdWxhdGUgdGhlIHdlaWdodCBmdG4KaC54PWFzLm51bWVyaWMoeD49MykgICMgVGFyZ2V0CncueD1mLngvZy54ICAjIFdlaWdodCBmdG4KCmgueF9JUz1tZWFuKGgueCp3LngpICAjIEltcG9ydGFuY2UgU2FtcGxpbmcgZXN0aW1hdGUKaC54X0lTCmBgYAoKIyMjIyBXZSBjYW4gc2VlIHRoYXQgaXQgaXMgcHJldHR5IGNsb3NlCgpcCgojIyMgU2FtcGxpbmcgRXJyb3Igb2YgdGhlIElTIGVzdGltYXRlCgpgYGB7cn0Kc2QoaC54KncueCkKYGBgCgojIyMjIFdlIGNhbiBzZWUgdGhhdCB0aGUgc2FtcGxpbmcgZXJyb3IgaXMgdmVyeSBzbWFsbCB3aGljaCBpcyBhbiBpbmRpY2F0b3Igb2YgYSBnb29kIGVzdGltYXRlLgoKXApcCgojIyBDb21wYXJpc29uIHRvIE1DIChDYXNlSUkpCgpcCgojIyMgRGlyZWN0IENvbXB1dGF0aW9uCgpgYGB7cn0KTj0xMDAwMCAgIyBOdW1iZXIgb2Ygc2FtcGxlcyB0byBleHRyYWN0Cng9cnVuaWYoTiwwLDMpICAjIFNhbXBsZXMgZXh0cmFjdGVkIGZyb20gVW5pZigwLDMpCmcueD0xL3NxcnQoMipwaSkqZXhwKC0wLjUqeF4yKSAgIyBUaGUgZygpIGZ0bgoxLzItMyptZWFuKGcueCkgICMgTUMgZXN0aW1hdGUKYGBgCgpcCgojIyMgU2FtcGxpbmcgRXJyb3Igb2YgdGhlIE1DIGVzdGltYXRlCgpgYGB7cn0Kc2QoZy54KQpgYGAKCiMjIyMgV2UgY2FuIHNlZSB0aGF0IHRoZSBzYW1wbGluZyBlcnJvciBpcyBhIGxvdCBiaWdnZXIgdGhhbiBJUyBlc3RpbWF0ZSdzLgoKXAoKIyMjIEl0ZXJhdGlvbiBNZXRob2QKCmBgYHtyfQpOPTEwMDAwICAjIE51bWJlciBvZiBzYW1wbGVzIHRvIGV4dHJhY3QKeD1yZXAoMCxOKSAgIyBTdG9yYWdlIGZvciBzYW1wbGVzCmcueD1yZXAoMCxOKSAgIyBTdG9yYWdlIGZvciB2YWx1ZXMgb2YgZygpCm11LmcueD1yZXAoMCxOKSAgIyBTdG9yYWdlIGZvciB2YWx1ZXMgb2YgbWVhbiBvZiBnKCkKCmZvciAoaSBpbiAxOk4pewogIHhbaV09cnVuaWYoMSwwLDMpICAjIEV4dHJhY3RpbmcgYSBzYW1wbGUKICBnLnhbaV09MS9zcXJ0KDIqcGkpKmV4cCgtMS8yKnhbaV1eMikKICBtdS5nLnhbaV09bWVhbihnLnhbMTppXSkKfQoKMS8yLTMqbXUuZy54W05dICAjIE1DIGVzdGltYXRlCmBgYAoKXAoKIyMjIFZpc3VhbGl6YXRpb24KCmBgYHtyfQpkZXYubmV3KCkKcGxvdCgxOk4sMC41LTMqbXUuZy54LHR5cGU9ImwiLCB5bGltPWMoMCwwLjE1KSkKYGBgCgpcCgojIyMgU2FtcGxpbmcgRXJyb3Igb2YgdGhlIE1DIGVzdGltYXRlIChJdGVyYXRpb24gbWV0aG9kKQoKYGBge3J9CnNkKGcueCkKYGBgCgpcCgojIyBDb21wYXJpc29uIHRwIE1DIChDYXNlIEkpCgpgYGB7cn0KTj0xMDAwMDAgICMgTnVtYmVyIG9mIHNhbXBsZXMgdG8gZXh0cmFjdAp4PXJub3JtKE4pICAjIFNhbXBsZXMgdGFrZW4gZnJvbSBOKDAsMSkKaC54PWFzLm51bWVyaWMoeD49MykgICMgaCgpID0gUChYPj0zKSA7IFggfiBOKDAsMSkKaC54X01DPW1lYW4oaC54KSAgIyBNQyBlc3RpbWF0ZQpoLnhfTUMKYGBgCgpcCgojIyMgU2FtcGxlIEVycm9yIG9mIE1DIChDYXNlIEkpCgpgYGB7cn0Kc2QoaC54KQpgYGAKCiMjIyMgQ2FzZSBJIGhhcyBhIGJldHRlciBzYW1wbGUgZXJyb3IgdGhhbiBjYXNlIElJLgoKXApcClwKXApcClwKXAoKIyBNYXJrb3YgQ2hhaW4KClwKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDE4Ny5qcGVnKQoKXAoKIyMjIFByZWRpY3Rpb24KCmBgYHtyfQpuc2ltPTEwMApQPW1hdHJpeChjKDAuOSwwLjUsMC4xLDAuNSksMiwyKSAgIyBUcmFuc2l0aW9uIG1hdHJpeAp4PW1hdHJpeChjKDAsMSksbnNpbSwyLGJ5cm93PVQpICAjIEluaXRpYWwgc3RhdGVzCgpmb3IoaSBpbiAxOihuc2ltLTEpKXsKICB4W2krMSxdPXhbaSxdJSolUCAgIyBNYXRyaXggbXVsdGlwbGljYXRpb24KfQoKZGV2Lm5ldygpCnBsb3QoMTpuc2ltLHhbLDFdLHR5cGU9ImwiLHlsaW09YygwLDEpLGNvbD0icmVkIikKbGluZXMoMTpuc2ltLHhbLDJdLHR5cGU9ImwiLGNvbD0iYmx1ZSIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQ9YygiU3VubnkiLCAiUmFpbnkiKSwgY29sPWMoInJlZCIsICJibHVlIiksIGx0eT0xLCBjZXg9MC44KQpgYGAKCiMjIyMgV2UgY2FuIHNlZSB0aGF0IGl0IGNvbnZlcmdlcy4KClwKXApcClwKXApcClwKCiMgR2liYnMgU2FtcGxlciAoT25lIG9mIE1DTUMgbWV0aG9kcykKClwKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDE4OS5qcGVnKQoKXAoKYGBge3J9Ck49MTAwMDAgICMgVG90YWwgbnVtYmVyIG9mIGl0ZXJhdGlvbnModGltZSkKYnVybj1OLzIgICMgQnVybi1pbiBwZXJpb2QgaXMgaGFsZiBvZiBOIEkgZ3Vlc3MKCiMgZGF0YSAoYSBzaW5nbGUgb2JzLikKeTE9MAp5Mj0wCgojIGNvcnJlbGF0aW9uCnJobz0wLjgKCiMgaW5pdGlhbCB2YWx1ZXMKdGhldGEuMT1yZXAoMSxOKSAgIyBTdGFydGluZyBwb2ludCBpcyAxIGZvciB0aGV0YTEKdGhldGEuMj1yZXAoLTEwLE4pICAjIFN0YXJ0aW5nIHBvaW50IGlzIC0xMCBmb3IgdGhldGEyCnRoZXRhPWNiaW5kKHRoZXRhLjEsdGhldGEuMikgICMgVGhldGEgYmluZGVkCgojIGl0ZXJhdGlvbnMKZm9yIChpIGluIDE6KE4tMSkpewogICMgVGFraW5nIHNhbXBsZXMgZnJvbSB0aGUgY29uZGl0aW9uYWwgZHN0bnMgb2YgdGhldGExIGFuZCB0aGV0YTIgcmVzcGVjdGl2ZWx5CiAgdGhldGEuMVtpKzFdPXJub3JtKDEseTErcmhvKih0aGV0YS4yW2ldLXkyKSxzcXJ0KDEtcmhvXjIpKQogIHRoZXRhLjJbaSsxXT1ybm9ybSgxLHkyK3JobyoodGhldGEuMVtpKzFdLXkxKSxzcXJ0KDEtcmhvXjIpKQogICMgU2FtcGxlcyBiaW5kZWQKICB0aGV0YVtpKzEsXT1jKHRoZXRhLjFbaSsxXSx0aGV0YS4yW2krMV0pCn0KCmhlYWQodGhldGEpCmBgYAoKXAoKIyMjIFZpc3VhbGl6YXRpb25zCgpgYGB7cn0KIyBjaGVjayB0cmFjZXBsb3RzCmRldi5uZXcoKQpwYXIobWZyb3c9YygyLDEpKQpwbG90KDE6Tix0aGV0YS4xLHR5cGU9ImwiKQpwbG90KDE6Tix0aGV0YS4yLHR5cGU9ImwiKQpgYGAKCiMjIyMgVGhlIHZhbHVlcyBvZiB0aGV0YTEgYW5kIHRoZXRhMiBjb252ZXJnZS4KClwKCmBgYHtyfQpkZXYubmV3KCkKcGFyKG1mcm93PWMoMSwxKSkKcGxvdCh0aGV0YSkKYGBgCgojIyMjIEEgc2ltcGxlIHZpc3VhbGl6YXRpb24uCgpcCgpgYGB7cn0KbnRyPTEwMDAgCmRldi5uZXcoKQpwYXIobWZyb3c9YygxLDEpKQpwbG90KHRoZXRhLjFbMTpudHJdLHRoZXRhLjJbMTpudHJdLHR5cGU9ImwiKQp0ZXh0KHRoZXRhLjFbMTpudHJdLHRoZXRhLjJbMTpudHJdLGxhYmVscz0xOjEwLGNleD0xLCBmb250PTUpCmBgYAoKIyMjIyBXaXRoIHRoaXMgcGxvdCwgd2UgY2FuIHNlZSB0aGUgbW92ZW1lbnQgb2YgdGhlIGNvbnZlcmdlbmNlIEkgZ3Vlc3MuCgpcCgojIyMgVGhlIGF2ZXJhZ2VzIG9mIHRoZXRhczogdGhlc2UgYXJlIHRoZSBlc3RpbWF0ZXMKCmBgYHtyfQpjb2xNZWFucyh0aGV0YSkKYGBgCgpcCgojIyMgVGhlIGNvcnJlbGF0aW9uIG9mIHRoZXRhcyBmcm9tIHRoZSBzYW1wbGVzIHVzaW5nIGNvbmRpdGlvbmFsIGRzdG5zCgpgYGB7cn0KY29yKHRoZXRhKQpgYGAKClwKCiMjIyBUaGUgY29ycmVsYXRpb24gb2YgdGhldGFzIHdpdGhvdXQgdGhlIEJ1cm4taW4gcGVyaW9kCgpgYGB7cn0KY29yKHRoZXRhW2J1cm46TixdKQpgYGAKCiMjIyMgRXhjbHVkaW5nIHRoZSBCdXJuLWluIHBlcmlvZCBtaWdodCBhbmQgbWlnaHQgbm90IGltcHJvdmUsIEkgZ3Vlc3MuCgpcCgojIyMgVGhlIGFjdHVhbCBkc3RuCgpgYGB7cn0KbGlicmFyeShtdnRub3JtKSAgIyBUbyBzYW1wbGUgZnJvbSBhbiBhY3R1YWwgQlZOIGRzdG4KCmpvaW50LnM9cm12bm9ybShOLzIsbWVhbj1jKHkxLHkyKSxzaWc9bWF0cml4KGMoMSxyaG8scmhvLDEpLDIsMikpICAjIFRoZSBhY3R1YWwgZHN0bgoKaGVhZChqb2ludC5zKQpgYGAKCiMjIyBWaXN1YWxpemF0aW9uCgpgYGB7cn0KcGxvdCh4bGltPWMoLTEwLDQpLCB5bGltPWMoLTEwLDQpLCBqb2ludC5zKQpgYGAKCiMjIyBUaGUgYXZlcmFnZXMgb2YgdGhldGFzIDogdGhlc2UgYXJlIHRoZSBlc3RpbWF0ZXMKCmBgYHtyfQpjb2xNZWFucyhqb2ludC5zKQpgYGAKCiMjIyBUaGUgY29ycmVsYXRpb24gb2YgdGhldGFzIGZyb20gdGhlIHNhbXBsZXMgdXNpbmcgdGhlIGFjdHVhbCBkc3RuCgpgYGB7cn0KY29yKGpvaW50LnMpCmBgYAoKXApcClwKXApcClwKXAoKIyBNZXRyb3BvbGlzIGFsZ29yaXRobQoKXAoKIyMgRXhhbXBsZTEKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDE5MS5qcGcpCgpcCgpgYGB7cn0KTj0xMDAwMApidXJuLmluPU4vMiAgIyBCdXJuLWluIHBlcmlvZCBpcyBoYWxmIG9mIE4gSSBndWVzcwoKIyBkYXRhIChhIHNpbmdsZSBvYnMuKQp5MT0wCnkyPTAKCiMgY29ycmVsYXRpb24KcmhvPTAuOAoKIyBpbml0aWFsIHZhbHVlCnNpZzI9MS1yaG9eMiAgICAjIHZhcmlhbmNlIGZvciBwb3N0ZXJpb3IgZGVuc2l0eQpzaWcyLnByb3A9MC4xICAgIyB2YXJpYW5jZSBmb3IgcHJvcG9zYWwgZGVuc2l0eQp0aGV0YS4xPXJlcCgxLE4pICAjIEluaXRpYWwgdmFsdWUgaXMgMSBJIGd1ZXNzCnRoZXRhLjI9cmVwKDEsTikKCgojIGl0ZXJhdGlvbnMKZm9yIChpIGluIDE6KE4tMSkpewogIAogICMgZm9yIHRoZXRhLjEKICB0aGV0YS4xLnN0YXI9cm5vcm0oMSx0aGV0YS4xW2ldLHNxcnQoc2lnMi5wcm9wKSkgICMgU2FtcGxlIGZyb20gdGhlIHByb3Bvc2FsIGRzdG4KICBVLjE9cnVuaWYoMSwwLDEpICAjIFU6IGF1eGlsaWFyeSB2YXJpYWJsZQogIAogICMgUmF0aW8gb2YgdGhlIHR3byBkZW5zaXRpZXMKICByYXRpby4xPWRub3JtKHRoZXRhLjEuc3Rhcix5MStyaG8qKHRoZXRhLjJbaV0teTIpLDEtcmhvXjIpL2Rub3JtKHRoZXRhLjFbaV0seTErcmhvKih0aGV0YS4yW2ldLXkyKSwxLXJob14yKQogIAogICMgUHJvYmFiaWxpdHkgb2YgbW92ZQogIGFscGhhLjE9bWluKHJhdGlvLjEsMSkKICAKICBpZiAoVS4xPD1hbHBoYS4xKXt0aGV0YS4xW2krMV09dGhldGEuMS5zdGFyfSAgIyBBY2NlcHRlZAogIGVsc2UgdGhldGEuMVtpKzFdPXRoZXRhLjFbaV0KICAKICAKICAjIyBmb3IgdGhldGEuMgogIHRoZXRhLjIuc3Rhcj1ybm9ybSgxLHRoZXRhLjJbaV0sc3FydChzaWcyLnByb3ApKQogIFUuMj1ydW5pZigxLDAsMSkKICAKICAjIFJhdGlvIG9mIHRoZSB0d28gZGVuc2l0aWVzCiAgcmF0aW8uMj1kbm9ybSh0aGV0YS4yLnN0YXIseTIrcmhvKih0aGV0YS4xW2krMV0teTEpLDEtcmhvXjIpL2Rub3JtKHRoZXRhLjJbaV0seTIrcmhvKih0aGV0YS4xW2krMV0teTEpLDEtcmhvXjIpCiAgCiAgIyBQcm9iYWJpbGl0eSBvZiBtb3ZlCiAgYWxwaGEuMj1taW4ocmF0aW8uMiwxKQogIAogIGlmIChVLjI8PWFscGhhLjIpe3RoZXRhLjJbaSsxXT10aGV0YS4yLnN0YXJ9ICAjIEFjY2VwdGVkCiAgZWxzZSB0aGV0YS4yW2krMV09dGhldGEuMltpXQogIAp9Cgp0aGV0YT1jYmluZCh0aGV0YS4xLHRoZXRhLjIpICAjIEJpbmRpbmcgdGhlIHRoZXRhcyB0b2dldGhlcgoKaGVhZCh0aGV0YSkKYGBgCgpcCgojIyMgVmlzdWFsaXphdGlvbnMKCmBgYHtyfQojIHRyYWNlcGxvdHMKZGV2Lm5ldygpCnBhcihtZnJvdz1jKDIsMSkpCnBsb3QoMTpOLHRoZXRhLjEsdHlwZT0ibCIpCnBsb3QoMTpOLHRoZXRhLjIsdHlwZT0ibCIpCmBgYAoKXAoKYGBge3J9CmRldi5uZXcoKQpwYXIobWZyb3c9YygxLDIpKQpoaXN0KHRoZXRhWyhidXJuLmluKzEpOk4sMV0pCmhpc3QodGhldGFbKGJ1cm4uaW4rMSk6TiwxXSkKYGBgCgpcCgpgYGB7cn0KZGV2Lm5ldygpCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QodGhldGFbKGJ1cm4uaW4rMSk6TixdKQpgYGAKClwKCiMjIyBUaGUgYXZlcmFnZXMgb2YgdGhldGExIGFuZCB0aGV0YTI6IFRoZXNlIGFyZSB0aGUgZXN0aW1hdGVzCgpgYGB7cn0KY29sTWVhbnModGhldGFbKGJ1cm4uaW4rMSk6TixdKQpgYGAKClwKCiMjIyBUaGUgY29ycmVsYXRpb24gb2YgdGhldGExIGFuZCB0aGV0YTIKCmBgYHtyfQpjb3IodGhldGFbKGJ1cm4uaW4rMSk6TixdKQpgYGAKClwKXApcCgojIyBFeGFtcGxlMgoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL0JhY2hlbG9yLzR5XzJzL2JheWVzL1IvaW1hZ2VzL0lNR18wMTkyLmpwZWcpCgpcCgojIyMgVGhlIG1ldHJvcG9saXMgYWxnb3JpdGhtIG1hZGUgaW50byBhIGZ1bmN0aW9uIChiZWNhdXNlIHdlIG5lZWQgdG8gcnVuIGZvciA0IGRpZmZlcmVudCB2YXJpYW5jZXMpCgpgYGB7cn0KbWg9ZnVuY3Rpb24odixzaWdtYSx4MCxOKXsKICB4PW51bWVyaWMoTikgICMgTWFraW5nIE4gbnVtYmVyIG9mIDBzCiAgeFsxXT14MCAgIyBTdGFydGluZyBwb2ludAogIGs9MAogIGZvciAoaSBpbiAyOk4peyAgIyBTdGFydHMgYXQgMiBiZWNhdXNlIDEgaXMgdGhlIHN0YXJ0aW5nIHBvaW50CiAgICB5PXJub3JtKDEseFtpLTFdLHNpZ21hKSAgIyBTYW1wbGluZyB0aGUgY2FuZGlkYXRlIGZyb20gdGhlIHByb3Bvc2FsIGRzdG4gd2l0aCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lYW46IHByZXZpb3VzIHZhbHVlIGFuZCB2YXJpYW5jZTogc2lnbWEKICAgIHU9cnVuaWYoMSkgICMgVGhlIGF1eGlsaWFyeSB2YXJpYWJsZQogICAgYWxwaGE9bWluKGR0KHksdikvZHQoeFtpLTFdLHYpLDEpICAjIENhbGN1bGF0aW5nIHRoZSBwcm9iYWJpbGl0eSBvZiBtb3ZlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgcmF0aW8gciBpcyBwKGNhbmRpZGF0ZXx5KS9wKHByZXZpb3VzIHZhbHVlfHkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBXaGVyZSBwKCkgaXMgaW4gdGhpcyBjYXNlIHRoZSB0IGRzdG4gd2l0aCBkZj12CiAgICBpZiAodTw9YWxwaGEpe3hbaV09eX0gICMgQWNjZXB0aW5nIHRoZSBjYW5kaWRhdGUKICAgIGVsc2Uge3hbaV09eFtpLTFdCiAgICBrPWsrMSAgIyBDb3VudGluZyB0aGUgbnVtYmVyIG9mIHJlamVjdGlvbnMKICAgIH0KICB9CiAgcmV0dXJuKGxpc3QoeD14LGs9aykpCn0KYGBgCgpcCgojIyMgTGV0J3MgcnVuIHRoZSBhbGdvcml0aG0KCmBgYHtyfQpOPTEwMDAgICMgTnVtYmVyIG9mIHNhbXBsZXMKYnVybi5pbj1OLzIgICMgVGhlIEJ1cm4taW4gcGVyaW9kCnY9NCAgIyBkZiBvZiB0IGRzdG4KeDA9MSAgIyBTdGFydGluZyBwb2ludApzaWdtYT1jKDAuMDUsMC41LDIsMTYpICAjIERpZmZlcmVudCB2YXJpYW5jZXMgZm9yIHByb3Bvc2FsIGRzdG5zCgptaDE9bWgodixzaWdtYVsxXSx4MCxOKQptaDI9bWgodixzaWdtYVsyXSx4MCxOKQptaDM9bWgodixzaWdtYVszXSx4MCxOKQptaDQ9bWgodixzaWdtYVs0XSx4MCxOKQpgYGAKClwKCiMjIyBUaGUgbnVtYmVyIG9mIGNhbmRpZGF0ZXMgcmVqZWN0ZWQgYnkgZWFjaCB2YXJpYW5jZQoKYGBge3J9CmMobWgxJGssbWgyJGssbWgzJGssbWg0JGspL04KYGBgCgojIyMjIFdlIGNhbiBzZWUgdGhhdCwgd2hlbiB0aGUgdmFyaWFuY2UobG93KSA9PiBGZXcgcmVqZWN0ZWQsIHZhcmlhbmNlKGhpZ2gpID0+IE1hbnkgcmVqZWN0ZWQuCgpcCgojIyMgVmlzdWFsaXphdGlvbnMKCmBgYHtyfQpkZXYubmV3KCkKcGFyKG1mcm93PWMoMiwyKSkKcGxvdCgxOk4sbWgxJHgsdHlwZT0ibCIpICAjIFRoZSB0cmFjZSBwbG90cwpwbG90KDE6TixtaDIkeCx0eXBlPSJsIikKcGxvdCgxOk4sbWgzJHgsdHlwZT0ibCIpCnBsb3QoMTpOLG1oNCR4LHR5cGU9ImwiKQpgYGAKCiMjIyMgVGhlIGZyZXF1ZW50IGhvcml6b250YWwgbGluZXMgaW4gdGhlIHRyYWNlIHBsb3QgbWVhbnMgdGhhdCB0aGVyZSB3ZXJlIG1hbnkgcmVqZWN0aW9ucy4gSG9yaXpvbnRhbCBsaW5lIG1lYW5zIHRoYXQgcHJldmlvdXMgdmFsdWVzIHdlcmUgdXNlZCBtYW55IHRpbWVzIGJlY2F1c2UgY2FuZGlkYXRlcyB3ZXJlIHJlamVjdGVkLgoKXAoKYGBge3J9CmE9c2VxKC01LDUsYnk9MC4wMSkgICMgVG8gcGxvdCB0aGUgdCBkc3RuCgpkZXYubmV3KCkKcGFyKG1mcm93PWMoMiwyKSkKCmhpc3QobWgxJHhbKGJ1cm4uaW4rMSk6Tl0sZnJlcT1GLHlsaW09YygwLDAuNykpICAjIEhpc3RvZ3JhbSBvZiB0aGUgc2FtcGxlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB3aXRob3V0IHRoZSBCdXJuLWluIHBlcmlvZApsaW5lcyhhLGR0KGEsZGY9NCkpICAjIHQgZHN0biB3aXRoIGRmPTQ6IFRoZSBhY3R1YWwgZHN0bgoKaGlzdChtaDIkeFsoYnVybi5pbisxKTpOXSxmcmVxPUYseWxpbT1jKDAsMC40KSkKbGluZXMoYSxkdChhLGRmPTQpKQoKaGlzdChtaDMkeFsoYnVybi5pbisxKTpOXSxmcmVxPUYseWxpbT1jKDAsMC40KSkKbGluZXMoYSxkdChhLGRmPTQpKQoKaGlzdChtaDQkeFsoYnVybi5pbisxKTpOXSxmcmVxPUYseWxpbT1jKDAsMC40KSkKbGluZXMoYSxkdChhLGRmPTQpKQpgYGAKCiMjIyMgV2UgY2FuIHNlZSB0aGF0IHdoZW4gdGhlIHZhcmlhbmNlIGlzIHRvbyBsb3cgb3IgaGlnaCwgdGhlIGRzdG4gb2YgdGhlIHNhbXBsZXMgd2VyZSBub3QgYXBwcm94aW1hdGUgdG8gdGhlIGFjdHVhbCBkc3RuLiBXaGVyZWFzIHdoZW4gdGhlIHZhcmlhbmNlIGlzIG1vZGVzdCwgdGhlIHNhbXBsZXMgd2VyZSBwcmV0dHkgYXBwcm94aW1hdGUgdG8gdGhlIGFjdHVhbCBkc3RuLgoKXApcClwKXApcClwKXAoKIyBNZXRyb3BvbGlzLUhhc3RpbmdzIGFsZ29yaXRobQoKXAoKIyMgRXhhbXBsZTEKCiFbXSgvVXNlcnMvamFleW9uZ2xlZS9Eb2N1bWVudHMvQ29sbGVnZS9CYWNoZWxvci80eV8ycy9iYXllcy9SL2ltYWdlcy9JTUdfMDE5My5qcGVnKQoKXAoKIyMjIFRoZSBNLUggYWxnb3JpdGhtCgpgYGB7cn0KTj0xMDAwMCAgIyBOdW1iZXIgb2Ygc2FtcGxlcwpidXJuLmluPU4vMiAgIyBUaGUgQnVybi1pbiBwZXJpb2QKc2lnbWE9NCAgIyBvZiB0aGUgUmF5bGVpZ2ggZHN0bgp4PW51bWVyaWMoTikgICMgSW5pdGlhbGl6aW5nIHRoZSBzcGFjZXMgZm9yIHRoZSBjaGFpbgp4WzFdPXJjaGlzcSgxLGRmPTEpICAjIFN0YXJ0aW5nIHBvaW50Cms9MCAgIyBOdW1iZXIgb2YgcmVqZWN0ZWQgY2FuZGlkYXRlcwoKZm9yIChpIGluIDI6Til7ICAjIFN0YXJ0cyBmcm9tIDIgYmVjYXVzZSAxIGlzIHRoZSBzdGFydGluZyBwb2ludAogIHguc3Rhcj1yY2hpc3EoMSxkZj14W2ktMV0pICAjIENhbmRpZGF0ZSB0YWtlbiBmcm9tIGNoaXNxIGRzdG4gd2l0aCBkZj1wcmV2aW91cyB2YWx1ZQogIHU9cnVuaWYoMSkgICMgQXV4aWxpYXJ5IHZhcmlhYmxlCiAgCiAgIyBGb3IgY2FsY3VsYXRpbmcgdGhlIHJhdGlvIHIKICBudW09KHguc3Rhci8oc2lnbWFeMikqZXhwKC14LnN0YXJeMi8oMipzaWdtYV4yKSkpL2RjaGlzcSh4LnN0YXIsZGY9eFtpLTFdKQogIGRlbj0oeFtpLTFdLyhzaWdtYV4yKSpleHAoLXhbaS0xXV4yLygyKnNpZ21hXjIpKSkvZGNoaXNxKHhbaS0xXSxkZj14LnN0YXIpCiAgCiAgYWxwaGE9bWluKG51bS9kZW4sMSkgICMgVGhlIHByb2JhYmlsaXR5IG9mIG1vdmUKICBpZiAodTw9YWxwaGEpe3hbaV09eC5zdGFyfSAgIyBBY2NlcHRpbmcgdGhlIGNhbmRpZGF0ZQogIGVsc2Uge3hbaV09eFtpLTFdCiAgaz1rKzEgIyBDb3VudGluZyB0aGUgbnVtYmVyIG9mIHJlamVjdGVkIGNhbmRpZGF0ZXMKICB9Cn0KYGBgCgpcCgojIyMgVmlzdWFsaXphdGlvbnMKCmBgYHtyfQpkZXYubmV3KCkKcGxvdCgxOk4seCx0eXBlPSJsIikgICMgVGhlIHRyYWNlIHBsb3QKYGBgCgpcCgpgYGB7cn0KIyBpbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikKbGlicmFyeShWR0FNKSAjIEZvciBkcmF5bGVpZ2goKQoKeGdyaWQ9c2VxKDAsMjAsYnk9MC4xKQp5dHJ1ZT1kcmF5bGVpZ2goeGdyaWQsc2NhbGU9c2lnbWEpICAjIFRoZSBkZW5zaXR5IG9mIHRoZSBhY3R1YWwgZHN0bgoKZGV2Lm5ldygpCmhpc3QoeFsoYnVybi5pbisxKTpOXSxmcmVxPUYsIG1haW49IkNvbXBhcmlzb24gdG8gdGhlIGFjdHVhbCBkc3RuIikgICMgZnJlcT1GOiB0byBkaXNwbGF5IGRlbnNpdHkgb24geSBheGlzIG5vdCB0aGUgZnJlcXVlbmN5CmxpbmVzKHhncmlkLHl0cnVlLHR5cGU9ImwiKSAgIyBUaGUgYWN0dWFsIGRzdG4KYGBgCgojIyMjIFdlIGNhbiBzZWUgdGhhdCB0aGUgc2FtcGxlcyh0aGUgaGlzdG9ncmFtKSBpcyBwcmV0dHkgYXBwcm94aW1hdGUgdG8gdGhlIGFjdHVhbCBkc3RuKHRoZSBsaW5lKS4KClwKXApcCgojIyBFeGFtcGxlMgoKIVtdKC9Vc2Vycy9qYWV5b25nbGVlL0RvY3VtZW50cy9Db2xsZWdlL0JhY2hlbG9yLzR5XzJzL2JheWVzL1IvaW1hZ2VzL0lNR18wMTk0LmpwZWcpCgpcCgpgYGB7cn0KTj0xMDAwMDAgICMgTnVtYmVyIG9mIHNhbXBsZXMKYnVybi5pbj1OLzIgICMgQnVybi1pbiBwZXJpb2QKCiMjIGluaXRpYWwgdmFsdWUKc2lnMj0xMDAgICMgdmFyaWFuY2Ugb2YgdGhlIHByb3Bvc2FsIGRzdG4KdGhldGE9cmVwKDAsTikgICMgSW5pdGlhbGl6aW5nIHRoZSBzcGFjZSBmb3IgdGhldGEKCnAudGg9ZnVuY3Rpb24odGgpeyAgICMgVGhlIGFjdHVhbCBkc3RuCiAgMC4zKmV4cCgtMC4yKnRoXjIpKzAuNypleHAoLTAuMioodGgtMTApXjIpCn0KCiMjIGl0ZXJhdGlvbnMKZm9yIChpIGluIDE6KE4tMSkpeyAgIyBObyB2YWx1ZSBmb3Igc3RhcnRpbmcgcG9pbnQgd2FzIGdpdmVuIHNvIEkgZ3Vlc3MgaXQncyAwCiAgCiAgdGhldGEuc3Rhcj1ybm9ybSgxLHRoZXRhW2ldLHNxcnQoc2lnMikpICAjIGNhbmRpZGF0ZQogIFU9cnVuaWYoMSwwLDEpICAjIGF1eGlsaWFyeSB2YXJpYWJsZQogIAogIHJhdGlvPXAudGgodGhldGEuc3RhcikvcC50aCh0aGV0YVtpXSkgICMgdGhlIHJhdGlvIHIKICAjIE5vdGUgdGhhdCBzaW5jZSB0aGUgcHJvcG9zYWwgZHN0biBpcyBzeW1tZXRyaWMsIHRoZSByYXRpbyByIGlzIGp1c3QgbGlrZSBNZXRyb3BvbGlzJwogIAogIGFscGhhPW1pbihyYXRpbywxKSAgIyBUaGUgcHJvYmFiaWxpdHkgb2YgbW92ZQogIAogIGlmIChVPD1hbHBoYSl7dGhldGFbaSsxXT10aGV0YS5zdGFyfSAgIyBBY2NlcHRpbmcgdGhlIGNhbmRpZGF0ZQogIGVsc2UgdGhldGFbaSsxXT10aGV0YVtpXQogIAp9CmBgYAoKXAoKIyMjIFZpc3VhbGl6YXRpb25zCgpgYGB7cn0KZGV2Lm5ldygpCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QoYnVybi5pbisxOk4sdGhldGEsdHlwZT0ibCIpICAjIHRoZSB0cmFjZSBwbG90CmBgYAoKXAoKYGBge3J9CnRoLmdyaWQ9c2VxKC0xMCwyMCxieT0xKQp0aC50cnVlPXJlcCgwLGxlbmd0aCh0aC5ncmlkKSkKZm9yIChpIGluIDE6bGVuZ3RoKHRoLmdyaWQpKXsKICB0aC50cnVlW2ldPXAudGgodGguZ3JpZFtpXSkKfQp0aC50cnVlPXRoLnRydWUvc3VtKHRoLnRydWUpICAjIE5vcm1hbGl6aW5nIEkgZ3Vlc3M/IFRoaXMgbWFrZXMgc3VtKHRoLnRydWUpID0gMQoKZGV2Lm5ldygpCnBhcihtZnJvdz1jKDEsMSkpCmhpc3QodGhldGEsZnJlcT1GQUxTRSwgbWFpbj0iQ29tcGFyaXNvbiB0byB0aGUgYWN0dWFsIGRzdG4iKQpsaW5lcyh0aC5ncmlkLHRoLnRydWUsdHlwZT0ibCIpCmBgYAoKXAoKIyMjIEVzdGltYXRlIGZvciB0aGUgbWVhbiBvZiB0aGUgdGFyZ2V0IGRzdG4gSSBndWVzcz8KCmBgYHtyfQptZWFuKHRoZXRhWyhidXJuLmluKzEpOk5dKQpgYGAKClwKXApcCg==