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