# ============================================================
# 1. LOAD PACKAGES AND DATA
# ============================================================
library(rjags)
Loading required package: coda
Linked to JAGS 4.3.2
Loaded modules: basemod,bugs
library(coda)
propertyData <- read.csv(
"/Users/chamudi/Desktop/2nd Year 2nd Semester/Applied Bayesian Statistics/Assignment/A2/Assignment2PropertyPrices.csv"
)
head(propertyData)
str(propertyData)
'data.frame': 10000 obs. of 6 variables:
$ SalePrice.100K.: num 17.1 14.8 10.8 24.1 16 ...
$ Area : int 1051 908 662 1489 981 845 1013 723 910 461 ...
$ Bedrooms : int 6 5 4 8 6 5 6 4 5 3 ...
$ Bathrooms : int 3 3 3 2 2 3 1 3 1 2 ...
$ CarParks : int 3 3 0 1 2 1 4 3 1 3 ...
$ PropertyType : int 1 1 0 0 1 0 0 0 1 0 ...
summary(propertyData)
SalePrice.100K. Area Bedrooms Bathrooms CarParks PropertyType
Min. : 3.05 Min. : 177.0 Min. :1.0 Min. :1.000 Min. :0.000 Min. :0.0000
1st Qu.:10.11 1st Qu.: 619.0 1st Qu.:4.0 1st Qu.:2.000 1st Qu.:1.000 1st Qu.:0.0000
Median :12.61 Median : 774.0 Median :5.0 Median :2.000 Median :2.000 Median :0.0000
Mean :13.06 Mean : 802.7 Mean :4.7 Mean :2.135 Mean :2.095 Mean :0.4985
3rd Qu.:15.57 3rd Qu.: 959.0 3rd Qu.:6.0 3rd Qu.:3.000 3rd Qu.:3.000 3rd Qu.:1.0000
Max. :35.31 Max. :2185.0 Max. :8.0 Max. :3.000 Max. :7.000 Max. :1.0000
SalePrice <- propertyData$SalePrice.100K.
Area <- propertyData$Area
Bedrooms <- propertyData$Bedrooms
Bathrooms <- propertyData$Bathrooms
CarParks <- propertyData$CarParks
PropertyType <- propertyData$PropertyType
descriptiveStats <- data.frame(
Variable = c(
"SalePrice",
"Area",
"Bedrooms",
"Bathrooms",
"CarParks"
),
Mean = c(
mean(SalePrice),
mean(Area),
mean(Bedrooms),
mean(Bathrooms),
mean(CarParks)
),
SD = c(
sd(SalePrice),
sd(Area),
sd(Bedrooms),
sd(Bathrooms),
sd(CarParks)
),
Min = c(
min(SalePrice),
min(Area),
min(Bedrooms),
min(Bathrooms),
min(CarParks)
),
Max = c(
max(SalePrice),
max(Area),
max(Bedrooms),
max(Bathrooms),
max(CarParks)
)
)
descriptiveStats[, 2:5] <- round(
descriptiveStats[, 2:5],
3
)
descriptiveStats
table(PropertyType)
PropertyType
0 1
5015 4985
prop.table(
table(PropertyType)
)
PropertyType
0 1
0.5015 0.4985
hist(
SalePrice,
breaks = 30,
probability = TRUE,
main = "Distribution of Property Sale Prices",
xlab = "Sale Price ($100,000 AUD)",
ylab = "Density"
)
lines(
density(SalePrice),
lwd = 2
)

# Area
plot(
Area,
SalePrice,
main = "Sale Price versus Property Area",
xlab = "Area (m²)",
ylab = "Sale Price ($100,000 AUD)",
pch = 16,
cex = 0.5
)

cor(Area, SalePrice)
[1] 0.9999688
# Bedrooms
plot(
Bedrooms,
SalePrice,
main = "Sale Price versus Number of Bedrooms",
xlab = "Number of Bedrooms",
ylab = "Sale Price ($100,000 AUD)",
pch = 16,
cex = 0.5
)

cor(Bedrooms, SalePrice)
[1] 0.9720416
# Bathrooms
boxplot(
SalePrice ~ Bathrooms,
main = "Sale Price versus Number of Bathrooms",
xlab = "Number of Bathrooms",
ylab = "Sale Price ($100,000 AUD)"
)

cor(Bathrooms, SalePrice)
[1] -0.01223181
# Car parks
boxplot(
SalePrice ~ CarParks,
main = "Sale Price versus Number of Car Parks",
xlab = "Number of Car Parks",
ylab = "Sale Price ($100,000 AUD)"
)

cor(CarParks, SalePrice)
[1] 0.01530944
# Property type
boxplot(
SalePrice ~ PropertyType,
names = c("House", "Unit"),
main = "Sale Price versus Property Type",
xlab = "Property Type",
ylab = "Sale Price ($100,000 AUD)"
)

tapply(
SalePrice,
PropertyType,
mean
)
0 1
12.97098 13.15551
predictorCorrelation <- cbind(
Area,
Bedrooms,
Bathrooms,
CarParks,
PropertyType
)
round(
cor(predictorCorrelation),
3
)
Area Bedrooms Bathrooms CarParks PropertyType
Area 1.000 0.972 -0.014 0.014 0.015
Bedrooms 0.972 1.000 -0.013 0.010 0.015
Bathrooms -0.014 -0.013 1.000 0.018 0.017
CarParks 0.014 0.010 0.018 1.000 -0.007
PropertyType 0.015 0.015 0.017 -0.007 1.000
y <- SalePrice
x <- cbind(
Area,
Bedrooms,
Bathrooms,
CarParks,
PropertyType
)
colnames(x) <- c(
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType"
)
Ntotal <- length(y)
Nx <- ncol(x)
Ntotal
[1] 10000
Nx
[1] 5
dim(x)
[1] 10000 5
xPred <- matrix(
c(
2600, 4, 2, 1, 0,
800, 2, 1, 4, 1,
1850, 3, 1, 2, 1,
5500, 7, 4, 5, 0,
550, 2, 2, 1, 1
),
nrow = 5,
byrow = TRUE
)
colnames(xPred) <- c(
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType"
)
xPred
Area Bedrooms Bathrooms CarParks PropertyType
[1,] 2600 4 2 1 0
[2,] 800 2 1 4 1
[3,] 1850 3 1 2 1
[4,] 5500 7 4 5 0
[5,] 550 2 2 1 1
priorMean <- c(
0.0009,
1.0,
0,
1.2,
-1.5
)
names(priorMean) <- c(
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType"
)
priorMean
Area Bedrooms Bathrooms CarParks PropertyType
0.0009 1.0000 0.0000 1.2000 -1.5000
priorVarMain <- c(
1e-8,
1.00,
4.00,
0.0625,
0.01
)
names(priorVarMain) <- names(priorMean)
priorVarMain
Area Bedrooms Bathrooms CarParks PropertyType
1.00e-08 1.00e+00 4.00e+00 6.25e-02 1.00e-02
sqrt(
priorVarMain
)
Area Bedrooms Bathrooms CarParks PropertyType
0.0001 1.0000 2.0000 0.2500 0.1000
priorVarStrong <- priorVarMain / 4
priorVarWeak <- priorVarMain * 4
priorSensitivityTable <- data.frame(
Predictor = names(priorMean),
PriorMean = priorMean,
StrongerVariance = priorVarStrong,
MainVariance = priorVarMain,
WeakerVariance = priorVarWeak
)
priorSensitivityTable
modelString <- "
data {
ysd <- sd(y)
for (i in 1:Ntotal) {
zy[i] <- y[i] / ysd
}
for (j in 1:Nx) {
xsd[j] <- sd(x[,j])
for (i in 1:Ntotal) {
zx[i,j] <- x[i,j] / xsd[j]
}
}
for (j in 1:Nx) {
zPriorMean[j] <-
priorMean[j] *
xsd[j] /
ysd
zPriorVar[j] <-
priorVar[j] *
pow(
xsd[j] / ysd,
2
)
}
}
model {
for (i in 1:Ntotal) {
mu[i] <-
zbeta0 +
sum(
zbeta[1:Nx] *
zx[i,1:Nx]
)
zy[i] ~ dgamma(
pow(mu[i],2) / zVar,
mu[i] / zVar
)
}
zbeta0 ~ dnorm(
0,
1 / pow(2,2)
)
for (j in 1:Nx) {
zbeta[j] ~ dnorm(
zPriorMean[j],
1 / zPriorVar[j]
)
}
zVar ~ dgamma(
0.01,
0.001
)
for (j in 1:Nx) {
beta[j] <-
(zbeta[j] / xsd[j]) *
ysd
}
beta0 <-
zbeta0 *
ysd
tau <-
zVar *
pow(
ysd,
2
)
for (p in 1:5) {
pred[p] <-
beta0 +
beta[1] * xPred[p,1] +
beta[2] * xPred[p,2] +
beta[3] * xPred[p,3] +
beta[4] * xPred[p,4] +
beta[5] * xPred[p,5]
}
}
"
writeLines(
modelString,
con = "TEMPmodel.txt"
)
file.exists(
"TEMPmodel.txt"
)
[1] TRUE
ysdR <- sd(y)
xsdR <- apply(
x,
2,
sd
)
zPriorMeanR <-
priorMean *
xsdR /
ysdR
initsList <- list(
list(
zbeta0 = 1.5,
zbeta = zPriorMeanR,
zVar = 1
),
list(
zbeta0 = 2.0,
zbeta = zPriorMeanR,
zVar = 1.5
),
list(
zbeta0 = 2.5,
zbeta = zPriorMeanR,
zVar = 2
)
)
parameters <- c(
"beta0",
"beta",
"tau",
"pred"
)
nChains <- 3
nAdapt <- 500
nBurnin <- 10000
nIterations <- 150000
nThin <- 10
# ============================================================
# FUNCTION TO RUN A PRIOR SETTING
# ============================================================
runBayesianModel <- function(priorVariance) {
dataList <- list(
y = y,
x = x,
Ntotal = Ntotal,
Nx = Nx,
priorMean = priorMean,
priorVar = priorVariance,
xPred = xPred
)
jagsModel <- jags.model(
file = "TEMPmodel.txt",
data = dataList,
inits = initsList,
n.chains = nChains,
n.adapt = nAdapt
)
update(
jagsModel,
n.iter = nBurnin
)
samples <- coda.samples(
model = jagsModel,
variable.names = parameters,
n.iter = nIterations,
thin = nThin
)
return(
samples
)
}
mainSamplesFinal <- runBayesianModel(
priorVarMain
)
Compiling data graph
Resolving undeclared variables
Allocating nodes
Initializing
Reading data back into data table
Compiling model graph
Resolving undeclared variables
Allocating nodes
Graph information:
Observed stochastic nodes: 10000
Unobserved stochastic nodes: 7
Total graph size: 178331
Initializing model
|
| | 0%
|
|+ | 2%
|
|++ | 4%
|
|+++ | 6%
|
|++++ | 8%
|
|+++++ | 10%
|
|++++++ | 12%
|
|+++++++ | 14%
|
|++++++++ | 16%
|
|+++++++++ | 18%
|
|++++++++++ | 20%
|
|+++++++++++ | 22%
|
|++++++++++++ | 24%
|
|+++++++++++++ | 26%
|
|++++++++++++++ | 28%
|
|+++++++++++++++ | 30%
|
|++++++++++++++++ | 32%
|
|+++++++++++++++++ | 34%
|
|++++++++++++++++++ | 36%
|
|+++++++++++++++++++ | 38%
|
|++++++++++++++++++++ | 40%
|
|+++++++++++++++++++++ | 42%
|
|++++++++++++++++++++++ | 44%
|
|+++++++++++++++++++++++ | 46%
|
|++++++++++++++++++++++++ | 48%
|
|+++++++++++++++++++++++++ | 50%
|
|++++++++++++++++++++++++++ | 52%
|
|+++++++++++++++++++++++++++ | 54%
|
|++++++++++++++++++++++++++++ | 56%
|
|+++++++++++++++++++++++++++++ | 58%
|
|++++++++++++++++++++++++++++++ | 60%
|
|+++++++++++++++++++++++++++++++ | 62%
|
|++++++++++++++++++++++++++++++++ | 64%
|
|+++++++++++++++++++++++++++++++++ | 66%
|
|++++++++++++++++++++++++++++++++++ | 68%
|
|+++++++++++++++++++++++++++++++++++ | 70%
|
|++++++++++++++++++++++++++++++++++++ | 72%
|
|+++++++++++++++++++++++++++++++++++++ | 74%
|
|++++++++++++++++++++++++++++++++++++++ | 76%
|
|+++++++++++++++++++++++++++++++++++++++ | 78%
|
|++++++++++++++++++++++++++++++++++++++++ | 80%
|
|+++++++++++++++++++++++++++++++++++++++++ | 82%
|
|++++++++++++++++++++++++++++++++++++++++++ | 84%
|
|+++++++++++++++++++++++++++++++++++++++++++ | 86%
|
|++++++++++++++++++++++++++++++++++++++++++++ | 88%
|
|+++++++++++++++++++++++++++++++++++++++++++++ | 90%
|
|++++++++++++++++++++++++++++++++++++++++++++++ | 92%
|
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94%
|
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96%
|
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98%
|
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100%
|
| | 0%
|
|* | 2%
|
|** | 4%
|
|*** | 6%
|
|**** | 8%
|
|***** | 10%
|
|****** | 12%
|
|******* | 14%
|
|******** | 16%
|
|********* | 18%
|
|********** | 20%
|
|*********** | 22%
|
|************ | 24%
|
|************* | 26%
|
|************** | 28%
|
|*************** | 30%
|
|**************** | 32%
|
|***************** | 34%
|
|****************** | 36%
|
|******************* | 38%
|
|******************** | 40%
|
|********************* | 42%
|
|********************** | 44%
|
|*********************** | 46%
|
|************************ | 48%
|
|************************* | 50%
|
|************************** | 52%
|
|*************************** | 54%
|
|**************************** | 56%
|
|***************************** | 58%
|
|****************************** | 60%
|
|******************************* | 62%
|
|******************************** | 64%
|
|********************************* | 66%
|
|********************************** | 68%
|
|*********************************** | 70%
|
|************************************ | 72%
|
|************************************* | 74%
|
|************************************** | 76%
|
|*************************************** | 78%
|
|**************************************** | 80%
|
|***************************************** | 82%
|
|****************************************** | 84%
|
|******************************************* | 86%
|
|******************************************** | 88%
|
|********************************************* | 90%
|
|********************************************** | 92%
|
|*********************************************** | 94%
|
|************************************************ | 96%
|
|************************************************* | 98%
|
|**************************************************| 100%
|
| | 0%
|
|* | 2%
|
|** | 4%
|
|*** | 6%
|
|**** | 8%
|
|***** | 10%
|
|****** | 12%
|
|******* | 14%
|
|******** | 16%
|
|********* | 18%
|
|********** | 20%
|
|*********** | 22%
|
|************ | 24%
|
|************* | 26%
|
|************** | 28%
|
|*************** | 30%
|
|**************** | 32%
|
|***************** | 34%
|
|****************** | 36%
|
|******************* | 38%
|
|******************** | 40%
|
|********************* | 42%
|
|********************** | 44%
|
|*********************** | 46%
|
|************************ | 48%
|
|************************* | 50%
|
|************************** | 52%
|
|*************************** | 54%
|
|**************************** | 56%
|
|***************************** | 58%
|
|****************************** | 60%
|
|******************************* | 62%
|
|******************************** | 64%
|
|********************************* | 66%
|
|********************************** | 68%
|
|*********************************** | 70%
|
|************************************ | 72%
|
|************************************* | 74%
|
|************************************** | 76%
|
|*************************************** | 78%
|
|**************************************** | 80%
|
|***************************************** | 82%
|
|****************************************** | 84%
|
|******************************************* | 86%
|
|******************************************** | 88%
|
|********************************************* | 90%
|
|********************************************** | 92%
|
|*********************************************** | 94%
|
|************************************************ | 96%
|
|************************************************* | 98%
|
|**************************************************| 100%
saveRDS(
mainSamplesFinal,
"mainSamplesFinal_150K.rds"
)
weakSamplesFinal <- runBayesianModel(
priorVarWeak
)
Compiling data graph
Resolving undeclared variables
Allocating nodes
Initializing
Reading data back into data table
Compiling model graph
Resolving undeclared variables
Allocating nodes
Graph information:
Observed stochastic nodes: 10000
Unobserved stochastic nodes: 7
Total graph size: 178331
Initializing model
|
| | 0%
|
|+ | 2%
|
|++ | 4%
|
|+++ | 6%
|
|++++ | 8%
|
|+++++ | 10%
|
|++++++ | 12%
|
|+++++++ | 14%
|
|++++++++ | 16%
|
|+++++++++ | 18%
|
|++++++++++ | 20%
|
|+++++++++++ | 22%
|
|++++++++++++ | 24%
|
|+++++++++++++ | 26%
|
|++++++++++++++ | 28%
|
|+++++++++++++++ | 30%
|
|++++++++++++++++ | 32%
|
|+++++++++++++++++ | 34%
|
|++++++++++++++++++ | 36%
|
|+++++++++++++++++++ | 38%
|
|++++++++++++++++++++ | 40%
|
|+++++++++++++++++++++ | 42%
|
|++++++++++++++++++++++ | 44%
|
|+++++++++++++++++++++++ | 46%
|
|++++++++++++++++++++++++ | 48%
|
|+++++++++++++++++++++++++ | 50%
|
|++++++++++++++++++++++++++ | 52%
|
|+++++++++++++++++++++++++++ | 54%
|
|++++++++++++++++++++++++++++ | 56%
|
|+++++++++++++++++++++++++++++ | 58%
|
|++++++++++++++++++++++++++++++ | 60%
|
|+++++++++++++++++++++++++++++++ | 62%
|
|++++++++++++++++++++++++++++++++ | 64%
|
|+++++++++++++++++++++++++++++++++ | 66%
|
|++++++++++++++++++++++++++++++++++ | 68%
|
|+++++++++++++++++++++++++++++++++++ | 70%
|
|++++++++++++++++++++++++++++++++++++ | 72%
|
|+++++++++++++++++++++++++++++++++++++ | 74%
|
|++++++++++++++++++++++++++++++++++++++ | 76%
|
|+++++++++++++++++++++++++++++++++++++++ | 78%
|
|++++++++++++++++++++++++++++++++++++++++ | 80%
|
|+++++++++++++++++++++++++++++++++++++++++ | 82%
|
|++++++++++++++++++++++++++++++++++++++++++ | 84%
|
|+++++++++++++++++++++++++++++++++++++++++++ | 86%
|
|++++++++++++++++++++++++++++++++++++++++++++ | 88%
|
|+++++++++++++++++++++++++++++++++++++++++++++ | 90%
|
|++++++++++++++++++++++++++++++++++++++++++++++ | 92%
|
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94%
|
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96%
|
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98%
|
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100%
|
| | 0%
|
|* | 2%
|
|** | 4%
|
|*** | 6%
|
|**** | 8%
|
|***** | 10%
|
|****** | 12%
|
|******* | 14%
|
|******** | 16%
|
|********* | 18%
|
|********** | 20%
|
|*********** | 22%
|
|************ | 24%
|
|************* | 26%
|
|************** | 28%
|
|*************** | 30%
|
|**************** | 32%
|
|***************** | 34%
|
|****************** | 36%
|
|******************* | 38%
|
|******************** | 40%
|
|********************* | 42%
|
|********************** | 44%
|
|*********************** | 46%
|
|************************ | 48%
|
|************************* | 50%
|
|************************** | 52%
|
|*************************** | 54%
|
|**************************** | 56%
|
|***************************** | 58%
|
|****************************** | 60%
|
|******************************* | 62%
|
|******************************** | 64%
|
|********************************* | 66%
|
|********************************** | 68%
|
|*********************************** | 70%
|
|************************************ | 72%
|
|************************************* | 74%
|
|************************************** | 76%
|
|*************************************** | 78%
|
|**************************************** | 80%
|
|***************************************** | 82%
|
|****************************************** | 84%
|
|******************************************* | 86%
|
|******************************************** | 88%
|
|********************************************* | 90%
|
|********************************************** | 92%
|
|*********************************************** | 94%
|
|************************************************ | 96%
|
|************************************************* | 98%
|
|**************************************************| 100%
|
| | 0%
|
|* | 2%
|
|** | 4%
|
|*** | 6%
|
|**** | 8%
|
|***** | 10%
|
|****** | 12%
|
|******* | 14%
|
|******** | 16%
|
|********* | 18%
|
|********** | 20%
|
|*********** | 22%
|
|************ | 24%
|
|************* | 26%
|
|************** | 28%
|
|*************** | 30%
|
|**************** | 32%
|
|***************** | 34%
|
|****************** | 36%
|
|******************* | 38%
|
|******************** | 40%
|
|********************* | 42%
|
|********************** | 44%
|
|*********************** | 46%
|
|************************ | 48%
|
|************************* | 50%
|
|************************** | 52%
|
|*************************** | 54%
|
|**************************** | 56%
|
|***************************** | 58%
|
|****************************** | 60%
|
|******************************* | 62%
|
|******************************** | 64%
|
|********************************* | 66%
|
|********************************** | 68%
|
|*********************************** | 70%
|
|************************************ | 72%
|
|************************************* | 74%
|
|************************************** | 76%
|
|*************************************** | 78%
|
|**************************************** | 80%
|
|***************************************** | 82%
|
|****************************************** | 84%
|
|******************************************* | 86%
|
|******************************************** | 88%
|
|********************************************* | 90%
|
|********************************************** | 92%
|
|*********************************************** | 94%
|
|************************************************ | 96%
|
|************************************************* | 98%
|
|**************************************************| 100%
saveRDS(
weakSamplesFinal,
"weakSamplesFinal_150K.rds"
)
strongSamplesFinal <- runBayesianModel(
priorVarStrong
)
Compiling data graph
Resolving undeclared variables
Allocating nodes
Initializing
Reading data back into data table
Compiling model graph
Resolving undeclared variables
Allocating nodes
Graph information:
Observed stochastic nodes: 10000
Unobserved stochastic nodes: 7
Total graph size: 178331
Initializing model
|
| | 0%
|
|+ | 2%
|
|++ | 4%
|
|+++ | 6%
|
|++++ | 8%
|
|+++++ | 10%
|
|++++++ | 12%
|
|+++++++ | 14%
|
|++++++++ | 16%
|
|+++++++++ | 18%
|
|++++++++++ | 20%
|
|+++++++++++ | 22%
|
|++++++++++++ | 24%
|
|+++++++++++++ | 26%
|
|++++++++++++++ | 28%
|
|+++++++++++++++ | 30%
|
|++++++++++++++++ | 32%
|
|+++++++++++++++++ | 34%
|
|++++++++++++++++++ | 36%
|
|+++++++++++++++++++ | 38%
|
|++++++++++++++++++++ | 40%
|
|+++++++++++++++++++++ | 42%
|
|++++++++++++++++++++++ | 44%
|
|+++++++++++++++++++++++ | 46%
|
|++++++++++++++++++++++++ | 48%
|
|+++++++++++++++++++++++++ | 50%
|
|++++++++++++++++++++++++++ | 52%
|
|+++++++++++++++++++++++++++ | 54%
|
|++++++++++++++++++++++++++++ | 56%
|
|+++++++++++++++++++++++++++++ | 58%
|
|++++++++++++++++++++++++++++++ | 60%
|
|+++++++++++++++++++++++++++++++ | 62%
|
|++++++++++++++++++++++++++++++++ | 64%
|
|+++++++++++++++++++++++++++++++++ | 66%
|
|++++++++++++++++++++++++++++++++++ | 68%
|
|+++++++++++++++++++++++++++++++++++ | 70%
|
|++++++++++++++++++++++++++++++++++++ | 72%
|
|+++++++++++++++++++++++++++++++++++++ | 74%
|
|++++++++++++++++++++++++++++++++++++++ | 76%
|
|+++++++++++++++++++++++++++++++++++++++ | 78%
|
|++++++++++++++++++++++++++++++++++++++++ | 80%
|
|+++++++++++++++++++++++++++++++++++++++++ | 82%
|
|++++++++++++++++++++++++++++++++++++++++++ | 84%
|
|+++++++++++++++++++++++++++++++++++++++++++ | 86%
|
|++++++++++++++++++++++++++++++++++++++++++++ | 88%
|
|+++++++++++++++++++++++++++++++++++++++++++++ | 90%
|
|++++++++++++++++++++++++++++++++++++++++++++++ | 92%
|
|+++++++++++++++++++++++++++++++++++++++++++++++ | 94%
|
|++++++++++++++++++++++++++++++++++++++++++++++++ | 96%
|
|+++++++++++++++++++++++++++++++++++++++++++++++++ | 98%
|
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100%
|
| | 0%
|
|* | 2%
|
|** | 4%
|
|*** | 6%
|
|**** | 8%
|
|***** | 10%
|
|****** | 12%
|
|******* | 14%
|
|******** | 16%
|
|********* | 18%
|
|********** | 20%
|
|*********** | 22%
|
|************ | 24%
|
|************* | 26%
|
|************** | 28%
|
|*************** | 30%
|
|**************** | 32%
|
|***************** | 34%
|
|****************** | 36%
|
|******************* | 38%
|
|******************** | 40%
|
|********************* | 42%
|
|********************** | 44%
|
|*********************** | 46%
|
|************************ | 48%
|
|************************* | 50%
|
|************************** | 52%
|
|*************************** | 54%
|
|**************************** | 56%
|
|***************************** | 58%
|
|****************************** | 60%
|
|******************************* | 62%
|
|******************************** | 64%
|
|********************************* | 66%
|
|********************************** | 68%
|
|*********************************** | 70%
|
|************************************ | 72%
|
|************************************* | 74%
|
|************************************** | 76%
|
|*************************************** | 78%
|
|**************************************** | 80%
|
|***************************************** | 82%
|
|****************************************** | 84%
|
|******************************************* | 86%
|
|******************************************** | 88%
|
|********************************************* | 90%
|
|********************************************** | 92%
|
|*********************************************** | 94%
|
|************************************************ | 96%
|
|************************************************* | 98%
|
|**************************************************| 100%
|
| | 0%
|
|* | 2%
|
|** | 4%
|
|*** | 6%
|
|**** | 8%
|
|***** | 10%
|
|****** | 12%
|
|******* | 14%
|
|******** | 16%
|
|********* | 18%
|
|********** | 20%
|
|*********** | 22%
|
|************ | 24%
|
|************* | 26%
|
|************** | 28%
|
|*************** | 30%
|
|**************** | 32%
|
|***************** | 34%
|
|****************** | 36%
|
|******************* | 38%
|
|******************** | 40%
|
|********************* | 42%
|
|********************** | 44%
|
|*********************** | 46%
|
|************************ | 48%
|
|************************* | 50%
|
|************************** | 52%
|
|*************************** | 54%
|
|**************************** | 56%
|
|***************************** | 58%
|
|****************************** | 60%
|
|******************************* | 62%
|
|******************************** | 64%
|
|********************************* | 66%
|
|********************************** | 68%
|
|*********************************** | 70%
|
|************************************ | 72%
|
|************************************* | 74%
|
|************************************** | 76%
|
|*************************************** | 78%
|
|**************************************** | 80%
|
|***************************************** | 82%
|
|****************************************** | 84%
|
|******************************************* | 86%
|
|******************************************** | 88%
|
|********************************************* | 90%
|
|********************************************** | 92%
|
|*********************************************** | 94%
|
|************************************************ | 96%
|
|************************************************* | 98%
|
|**************************************************| 100%
saveRDS(
strongSamplesFinal,
"strongSamplesFinal_150K.rds"
)
# ============================================================
# FUNCTION FOR MCMC DIAGNOSTICS
# ============================================================
getDiagnostics <- function(samples) {
gelmanResult <- gelman.diag(
samples,
autoburnin = FALSE,
multivariate = FALSE
)
essResult <- effectiveSize(
samples
)
sampleMatrix <- as.matrix(
samples
)
sampleSD <- apply(
sampleMatrix,
2,
sd
)
mcseResult <-
sampleSD /
sqrt(
essResult
)
diagnosticTable <- data.frame(
Parameter = names(essResult),
ESS = as.numeric(essResult),
SD = sampleSD[names(essResult)],
MCSE = mcseResult[names(essResult)]
)
return(
list(
Gelman = gelmanResult,
DiagnosticTable = diagnosticTable
)
)
}
mainDiagnostics <- getDiagnostics(
mainSamplesFinal
)
mainDiagnostics$Gelman
Potential scale reduction factors:
Point est. Upper C.I.
beta[1] 1 1
beta[2] 1 1
beta[3] 1 1
beta[4] 1 1
beta[5] 1 1
beta0 1 1
pred[1] 1 1
pred[2] 1 1
pred[3] 1 1
pred[4] 1 1
pred[5] 1 1
tau 1 1
mainDiagnostics$DiagnosticTable
mainDiagnostics$DiagnosticTable[
order(
mainDiagnostics$DiagnosticTable$ESS
),
]
modelParameterNames <- c(
"beta0",
"beta[1]",
"beta[2]",
"beta[3]",
"beta[4]",
"beta[5]",
"tau"
)
for (parameterName in modelParameterNames) {
plot(
mainSamplesFinal[
,
parameterName
]
)
}







for (parameterName in modelParameterNames) {
autocorr.plot(
mainSamplesFinal[
,
parameterName
]
)
}





















weakDiagnostics <- getDiagnostics(
weakSamplesFinal
)
weakDiagnostics$Gelman
Potential scale reduction factors:
Point est. Upper C.I.
beta[1] 1 1.01
beta[2] 1 1.01
beta[3] 1 1.00
beta[4] 1 1.00
beta[5] 1 1.00
beta0 1 1.00
pred[1] 1 1.01
pred[2] 1 1.01
pred[3] 1 1.01
pred[4] 1 1.01
pred[5] 1 1.01
tau 1 1.00
weakDiagnostics$DiagnosticTable
weakDiagnostics$DiagnosticTable[
order(
weakDiagnostics$DiagnosticTable$ESS
),
]
strongDiagnostics <- getDiagnostics(
strongSamplesFinal
)
strongDiagnostics$Gelman
Potential scale reduction factors:
Point est. Upper C.I.
beta[1] 1 1
beta[2] 1 1
beta[3] 1 1
beta[4] 1 1
beta[5] 1 1
beta0 1 1
pred[1] 1 1
pred[2] 1 1
pred[3] 1 1
pred[4] 1 1
pred[5] 1 1
tau 1 1
strongDiagnostics$DiagnosticTable
strongDiagnostics$DiagnosticTable[
order(
strongDiagnostics$DiagnosticTable$ESS
),
]
coefNames <- c(
"beta0",
"beta[1]",
"beta[2]",
"beta[3]",
"beta[4]",
"beta[5]"
)
coefMatrix <- as.matrix(
mainSamplesFinal[
,
coefNames
]
)
coefMean <- colMeans(
coefMatrix
)
coefHDI <- HPDinterval(
mcmc(
coefMatrix
),
prob = 0.95
)
finalCoefficientTable <- data.frame(
Parameter = c(
"Intercept",
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType"
),
PosteriorMean =
as.numeric(
coefMean
),
HDILower =
coefHDI[
,
"lower"
],
HDIUpper =
coefHDI[
,
"upper"
]
)
finalCoefficientTable
tauValues <- as.matrix(
mainSamplesFinal[
,
"tau"
]
)
tauMean <- mean(
tauValues
)
tauHDI <- HPDinterval(
mcmc(
tauValues
),
prob = 0.95
)
tauSummary <- data.frame(
Parameter = "tau",
PosteriorMean = tauMean,
HDILower = tauHDI[1, "lower"],
HDIUpper = tauHDI[1, "upper"]
)
tauSummary
predictionEquation <- paste0(
"Predicted SalePrice = ",
round(
coefMean["beta0"],
6
),
" + (",
round(
coefMean["beta[1]"],
6
),
" x Area)",
" + (",
round(
coefMean["beta[2]"],
6
),
" x Bedrooms)",
" + (",
round(
coefMean["beta[3]"],
6
),
" x Bathrooms)",
" + (",
round(
coefMean["beta[4]"],
6
),
" x CarParks)",
" + (",
round(
coefMean["beta[5]"],
6
),
" x PropertyType)"
)
predictionEquation
[1] "Predicted SalePrice = 0.096442 + (0.016024 x Area) + (0.008372 x Bedrooms) + (0.010528 x Bathrooms) + (0.006055 x CarParks) + (0.060132 x PropertyType)"
predictionNames <- c(
"pred[1]",
"pred[2]",
"pred[3]",
"pred[4]",
"pred[5]"
)
predictionMatrix <- as.matrix(
mainSamplesFinal[
,
predictionNames
]
)
predictionMean <- colMeans(
predictionMatrix
)
predictionHDI <- HPDinterval(
mcmc(
predictionMatrix
),
prob = 0.95
)
finalPredictionTable <- data.frame(
Property = 1:5,
Area =
xPred[, 1],
Bedrooms =
xPred[, 2],
Bathrooms =
xPred[, 3],
CarParks =
xPred[, 4],
PropertyType = c(
"House",
"Unit",
"Unit",
"House",
"Unit"
),
BayesianEstimateAUD =
predictionMean *
100000,
HDILowerAUD =
predictionHDI[
,
"lower"
] *
100000,
HDIUpperAUD =
predictionHDI[
,
"upper"
] *
100000
)
finalPredictionTable
getCoefficientSummary <- function(samples) {
coefMatrix <- as.matrix(
samples[
,
c(
"beta[1]",
"beta[2]",
"beta[3]",
"beta[4]",
"beta[5]"
)
]
)
coefMean <- colMeans(
coefMatrix
)
coefHDI <- HPDinterval(
mcmc(
coefMatrix
),
prob = 0.95
)
return(
list(
Mean = coefMean,
HDI = coefHDI
)
)
}
strongCoef <- getCoefficientSummary(
strongSamplesFinal
)
mainCoef <- getCoefficientSummary(
mainSamplesFinal
)
weakCoef <- getCoefficientSummary(
weakSamplesFinal
)
coefficientSensitivityTable <- data.frame(
Parameter = c(
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType"
),
StrongerMean =
as.numeric(
strongCoef$Mean
),
StrongerLower =
strongCoef$HDI[
,
"lower"
],
StrongerUpper =
strongCoef$HDI[
,
"upper"
],
MainMean =
as.numeric(
mainCoef$Mean
),
MainLower =
mainCoef$HDI[
,
"lower"
],
MainUpper =
mainCoef$HDI[
,
"upper"
],
WeakerMean =
as.numeric(
weakCoef$Mean
),
WeakerLower =
weakCoef$HDI[
,
"lower"
],
WeakerUpper =
weakCoef$HDI[
,
"upper"
]
)
coefficientSensitivityTable
getPredictionSummary <- function(samples) {
predictionMatrix <- as.matrix(
samples[
,
predictionNames
]
)
predictionMean <- colMeans(
predictionMatrix
)
predictionHDI <- HPDinterval(
mcmc(
predictionMatrix
),
prob = 0.95
)
return(
list(
Mean = predictionMean,
HDI = predictionHDI
)
)
}
strongPrediction <- getPredictionSummary(
strongSamplesFinal
)
mainPrediction <- getPredictionSummary(
mainSamplesFinal
)
weakPrediction <- getPredictionSummary(
weakSamplesFinal
)
predictionSensitivityTable <- data.frame(
Property = 1:5,
StrongerMeanAUD =
strongPrediction$Mean *
100000,
StrongerLowerAUD =
strongPrediction$HDI[
,
"lower"
] *
100000,
StrongerUpperAUD =
strongPrediction$HDI[
,
"upper"
] *
100000,
MainMeanAUD =
mainPrediction$Mean *
100000,
MainLowerAUD =
mainPrediction$HDI[
,
"lower"
] *
100000,
MainUpperAUD =
mainPrediction$HDI[
,
"upper"
] *
100000,
WeakerMeanAUD =
weakPrediction$Mean *
100000,
WeakerLowerAUD =
weakPrediction$HDI[
,
"lower"
] *
100000,
WeakerUpperAUD =
weakPrediction$HDI[
,
"upper"
] *
100000
)
predictionSensitivityTable
getTauSummary <- function(samples) {
tauValues <- as.matrix(
samples[
,
"tau"
]
)
tauMean <- mean(
tauValues
)
tauHDI <- HPDinterval(
mcmc(
tauValues
),
prob = 0.95
)
return(
c(
Mean = tauMean,
Lower = tauHDI[1, "lower"],
Upper = tauHDI[1, "upper"]
)
)
}
strongTau <- getTauSummary(
strongSamplesFinal
)
mainTau <- getTauSummary(
mainSamplesFinal
)
weakTau <- getTauSummary(
weakSamplesFinal
)
tauSensitivityTable <- data.frame(
PriorSetting = c(
"Stronger",
"Main",
"Weaker"
),
PosteriorMean = c(
strongTau["Mean"],
mainTau["Mean"],
weakTau["Mean"]
),
HDILower = c(
strongTau["Lower"],
mainTau["Lower"],
weakTau["Lower"]
),
HDIUpper = c(
strongTau["Upper"],
mainTau["Upper"],
weakTau["Upper"]
)
)
tauSensitivityTable
saveRDS(
mainSamplesFinal,
"mainSamplesFinal_150K.rds"
)
saveRDS(
weakSamplesFinal,
"weakSamplesFinal_150K.rds"
)
saveRDS(
strongSamplesFinal,
"strongSamplesFinal_150K.rds"
)
coefficientSensitivityTable[, c(
"Parameter",
"StrongerMean", "StrongerLower", "StrongerUpper",
"MainMean", "MainLower", "MainUpper",
"WeakerMean", "WeakerLower", "WeakerUpper"
)]
coefficientSensitivityTable[, c(
"Parameter",
"WeakerMean",
"WeakerLower",
"WeakerUpper"
)]
predictionSensitivityTable[, c(
"Property",
"StrongerMeanAUD",
"StrongerLowerAUD",
"StrongerUpperAUD",
"MainMeanAUD",
"MainLowerAUD",
"MainUpperAUD",
"WeakerMeanAUD",
"WeakerLowerAUD",
"WeakerUpperAUD"
)]
predictionSensitivityTable[, c(
"Property",
"WeakerMeanAUD",
"WeakerLowerAUD",
"WeakerUpperAUD"
)]
file.exists("DBDA2E-utilities.R")
[1] TRUE
source("DBDA2E-utilities.R")
*********************************************************************
Kruschke, J. K. (2015). Doing Bayesian Data Analysis, Second Edition:
A Tutorial with R, JAGS, and Stan. Academic Press / Elsevier.
*********************************************************************
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.4/compute.es_0.2-6.tgz'
Content type 'application/x-gzip' length 365180 bytes (356 KB)
==================================================
downloaded 356 KB
The downloaded binary packages are in
/var/folders/79/r69zm8dn68x000_5vc6nyxp00000gn/T//RtmpcXaNIJ/downloaded_packages
exists("diagMCMC")
[1] TRUE
grep(
"diagMCMC",
readLines("DBDA2E-utilities.R"),
value = TRUE
)
[1] "diagMCMC = function( codaObject , parName=varnames(codaObject)[1] ,"
X11()
dev.list()
X11cairo
2
plot(1:10)
dev.list()
X11cairo
2
parameterNames <- c(
"beta0",
"beta[1]",
"beta[2]",
"beta[3]",
"beta[4]",
"beta[5]",
"tau"
)
fileNames <- c(
"Intercept",
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType",
"Tau"
)
for (i in seq_along(parameterNames)) {
diagMCMC(
codaObject = mainSamplesFinal,
parName = parameterNames[i],
saveName = paste0("Final_Diagnostic_", fileNames[i]),
saveType = "jpg"
)
}
# POSTERIOR DISTRIBUTIONS FOR THE FIVE PREDICTIONS
predictionNames <- c(
"pred[1]",
"pred[2]",
"pred[3]",
"pred[4]",
"pred[5]"
)
# Convert MCMC samples to numeric matrix
predictionMatrix <- as.matrix(
mainSamplesFinal[, predictionNames]
)
# Convert from $100,000 units to AUD
predictionMatrixAUD <- predictionMatrix * 100000
args(plotPost)
function (paramSampleVec, cenTend = c("mode", "median", "mean")[1],
compVal = NULL, ROPE = NULL, credMass = 0.95, HDItextPlace = 0.7,
xlab = NULL, xlim = NULL, yaxt = NULL, ylab = NULL, main = NULL,
cex = NULL, cex.lab = NULL, col = NULL, border = NULL, showCurve = FALSE,
breaks = NULL, ...)
NULL
par(mfrow = c(2, 3))
for (i in 1:5) {
plotPost(
predictionMatrix[, i],
cenTend = "mean",
main = paste("Property", i),
xlab = "Predicted Sale Price ($100,000 AUD)"
)
}
par(mfrow = c(1, 1))

# ============================================================
# HYPOTHESIS TESTS USING 95% HDIs
# ============================================================
getHypothesisTests <- function(samples, priorSetting) {
coefficientNames <- c(
"beta[1]",
"beta[2]",
"beta[3]",
"beta[4]",
"beta[5]"
)
parameterNames <- c(
"Area",
"Bedrooms",
"Bathrooms",
"CarParks",
"PropertyType"
)
# Convert posterior samples to matrix
coefficientMatrix <- as.matrix(
samples[, coefficientNames]
)
# Posterior means
posteriorMean <- colMeans(
coefficientMatrix
)
# 95% HDIs
coefficientHDI <- HPDinterval(
mcmc(coefficientMatrix),
prob = 0.95
)
# Check whether zero lies inside each 95% HDI
zeroInHDI <-
coefficientHDI[, "lower"] <= 0 &
coefficientHDI[, "upper"] >= 0
# HDI-based hypothesis conclusion
hypothesisConclusion <- ifelse(
zeroInHDI,
"Do not reject H0",
"Reject H0"
)
# Direction of posterior coefficient
coefficientDirection <- ifelse(
coefficientHDI[, "lower"] > 0,
"Positive",
ifelse(
coefficientHDI[, "upper"] < 0,
"Negative",
"Includes zero"
)
)
result <- data.frame(
PriorSetting = priorSetting,
Parameter = parameterNames,
PosteriorMean = as.numeric(posteriorMean),
HDILower = coefficientHDI[, "lower"],
HDIUpper = coefficientHDI[, "upper"],
ZeroIn95HDI = zeroInHDI,
HypothesisConclusion = hypothesisConclusion,
Direction = coefficientDirection
)
return(result)
}
# ============================================================
# MAIN PRIOR HYPOTHESIS TESTS
# ============================================================
mainHypothesisTests <- getHypothesisTests(
mainSamplesFinal,
"Main"
)
mainHypothesisTests
# ============================================================
# STRONGER PRIOR HYPOTHESIS TESTS
# ============================================================
strongHypothesisTests <- getHypothesisTests(
strongSamplesFinal,
"Stronger"
)
strongHypothesisTests
# ============================================================
# WEAKER PRIOR HYPOTHESIS TESTS
# ============================================================
weakHypothesisTests <- getHypothesisTests(
weakSamplesFinal,
"Weaker"
)
weakHypothesisTests
# ============================================================
# SENSITIVITY OF HYPOTHESIS CONCLUSIONS
# ============================================================
hypothesisSensitivityTable <- data.frame(
Parameter = mainHypothesisTests$Parameter,
Stronger95HDI = paste0(
"[",
round(strongHypothesisTests$HDILower, 6),
", ",
round(strongHypothesisTests$HDIUpper, 6),
"]"
),
StrongerConclusion =
strongHypothesisTests$HypothesisConclusion,
StrongerDirection =
strongHypothesisTests$Direction,
Main95HDI = paste0(
"[",
round(mainHypothesisTests$HDILower, 6),
", ",
round(mainHypothesisTests$HDIUpper, 6),
"]"
),
MainConclusion =
mainHypothesisTests$HypothesisConclusion,
MainDirection =
mainHypothesisTests$Direction,
Weaker95HDI = paste0(
"[",
round(weakHypothesisTests$HDILower, 6),
", ",
round(weakHypothesisTests$HDIUpper, 6),
"]"
),
WeakerConclusion =
weakHypothesisTests$HypothesisConclusion,
WeakerDirection =
weakHypothesisTests$Direction
)
hypothesisSensitivityTable
LS0tCnRpdGxlOiAiRmluYWxfVmVyc2lvbl9BMiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CiMgMS4gTE9BRCBQQUNLQUdFUyBBTkQgREFUQQoKbGlicmFyeShyamFncykKbGlicmFyeShjb2RhKQoKcHJvcGVydHlEYXRhIDwtIHJlYWQuY3N2KAogICIvVXNlcnMvY2hhbXVkaS9EZXNrdG9wLzJuZCBZZWFyIDJuZCBTZW1lc3Rlci9BcHBsaWVkIEJheWVzaWFuIFN0YXRpc3RpY3MvQXNzaWdubWVudC9BMi9Bc3NpZ25tZW50MlByb3BlcnR5UHJpY2VzLmNzdiIKKQoKaGVhZChwcm9wZXJ0eURhdGEpCnN0cihwcm9wZXJ0eURhdGEpCnN1bW1hcnkocHJvcGVydHlEYXRhKQoKU2FsZVByaWNlIDwtIHByb3BlcnR5RGF0YSRTYWxlUHJpY2UuMTAwSy4KQXJlYSA8LSBwcm9wZXJ0eURhdGEkQXJlYQpCZWRyb29tcyA8LSBwcm9wZXJ0eURhdGEkQmVkcm9vbXMKQmF0aHJvb21zIDwtIHByb3BlcnR5RGF0YSRCYXRocm9vbXMKQ2FyUGFya3MgPC0gcHJvcGVydHlEYXRhJENhclBhcmtzClByb3BlcnR5VHlwZSA8LSBwcm9wZXJ0eURhdGEkUHJvcGVydHlUeXBlCmBgYAoKYGBge3J9CmRlc2NyaXB0aXZlU3RhdHMgPC0gZGF0YS5mcmFtZSgKICBWYXJpYWJsZSA9IGMoCiAgICAiU2FsZVByaWNlIiwKICAgICJBcmVhIiwKICAgICJCZWRyb29tcyIsCiAgICAiQmF0aHJvb21zIiwKICAgICJDYXJQYXJrcyIKICApLAoKICBNZWFuID0gYygKICAgIG1lYW4oU2FsZVByaWNlKSwKICAgIG1lYW4oQXJlYSksCiAgICBtZWFuKEJlZHJvb21zKSwKICAgIG1lYW4oQmF0aHJvb21zKSwKICAgIG1lYW4oQ2FyUGFya3MpCiAgKSwKCiAgU0QgPSBjKAogICAgc2QoU2FsZVByaWNlKSwKICAgIHNkKEFyZWEpLAogICAgc2QoQmVkcm9vbXMpLAogICAgc2QoQmF0aHJvb21zKSwKICAgIHNkKENhclBhcmtzKQogICksCgogIE1pbiA9IGMoCiAgICBtaW4oU2FsZVByaWNlKSwKICAgIG1pbihBcmVhKSwKICAgIG1pbihCZWRyb29tcyksCiAgICBtaW4oQmF0aHJvb21zKSwKICAgIG1pbihDYXJQYXJrcykKICApLAoKICBNYXggPSBjKAogICAgbWF4KFNhbGVQcmljZSksCiAgICBtYXgoQXJlYSksCiAgICBtYXgoQmVkcm9vbXMpLAogICAgbWF4KEJhdGhyb29tcyksCiAgICBtYXgoQ2FyUGFya3MpCiAgKQopCgpkZXNjcmlwdGl2ZVN0YXRzWywgMjo1XSA8LSByb3VuZCgKICBkZXNjcmlwdGl2ZVN0YXRzWywgMjo1XSwKICAzCikKCmRlc2NyaXB0aXZlU3RhdHMKYGBgCgpgYGB7cn0KdGFibGUoUHJvcGVydHlUeXBlKQoKcHJvcC50YWJsZSgKICB0YWJsZShQcm9wZXJ0eVR5cGUpCikKYGBgCgpgYGB7cn0KaGlzdCgKICBTYWxlUHJpY2UsCiAgYnJlYWtzID0gMzAsCiAgcHJvYmFiaWxpdHkgPSBUUlVFLAogIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIFByb3BlcnR5IFNhbGUgUHJpY2VzIiwKICB4bGFiID0gIlNhbGUgUHJpY2UgKCQxMDAsMDAwIEFVRCkiLAogIHlsYWIgPSAiRGVuc2l0eSIKKQoKCmxpbmVzKAogIGRlbnNpdHkoU2FsZVByaWNlKSwKICBsd2QgPSAyCikKYGBgCgpgYGB7cn0KIyBBcmVhCgpwbG90KAogIEFyZWEsCiAgU2FsZVByaWNlLAogIG1haW4gPSAiU2FsZSBQcmljZSB2ZXJzdXMgUHJvcGVydHkgQXJlYSIsCiAgeGxhYiA9ICJBcmVhIChtwrIpIiwKICB5bGFiID0gIlNhbGUgUHJpY2UgKCQxMDAsMDAwIEFVRCkiLAogIHBjaCA9IDE2LAogIGNleCA9IDAuNQopCgpjb3IoQXJlYSwgU2FsZVByaWNlKQoKCgojIEJlZHJvb21zCgpwbG90KAogIEJlZHJvb21zLAogIFNhbGVQcmljZSwKICBtYWluID0gIlNhbGUgUHJpY2UgdmVyc3VzIE51bWJlciBvZiBCZWRyb29tcyIsCiAgeGxhYiA9ICJOdW1iZXIgb2YgQmVkcm9vbXMiLAogIHlsYWIgPSAiU2FsZSBQcmljZSAoJDEwMCwwMDAgQVVEKSIsCiAgcGNoID0gMTYsCiAgY2V4ID0gMC41CikKCmNvcihCZWRyb29tcywgU2FsZVByaWNlKQoKCgojIEJhdGhyb29tcwoKYm94cGxvdCgKICBTYWxlUHJpY2UgfiBCYXRocm9vbXMsCiAgbWFpbiA9ICJTYWxlIFByaWNlIHZlcnN1cyBOdW1iZXIgb2YgQmF0aHJvb21zIiwKICB4bGFiID0gIk51bWJlciBvZiBCYXRocm9vbXMiLAogIHlsYWIgPSAiU2FsZSBQcmljZSAoJDEwMCwwMDAgQVVEKSIKKQoKY29yKEJhdGhyb29tcywgU2FsZVByaWNlKQoKCgojIENhciBwYXJrcwoKYm94cGxvdCgKICBTYWxlUHJpY2UgfiBDYXJQYXJrcywKICBtYWluID0gIlNhbGUgUHJpY2UgdmVyc3VzIE51bWJlciBvZiBDYXIgUGFya3MiLAogIHhsYWIgPSAiTnVtYmVyIG9mIENhciBQYXJrcyIsCiAgeWxhYiA9ICJTYWxlIFByaWNlICgkMTAwLDAwMCBBVUQpIgopCgpjb3IoQ2FyUGFya3MsIFNhbGVQcmljZSkKCgoKIyBQcm9wZXJ0eSB0eXBlCgpib3hwbG90KAogIFNhbGVQcmljZSB+IFByb3BlcnR5VHlwZSwKICBuYW1lcyA9IGMoIkhvdXNlIiwgIlVuaXQiKSwKICBtYWluID0gIlNhbGUgUHJpY2UgdmVyc3VzIFByb3BlcnR5IFR5cGUiLAogIHhsYWIgPSAiUHJvcGVydHkgVHlwZSIsCiAgeWxhYiA9ICJTYWxlIFByaWNlICgkMTAwLDAwMCBBVUQpIgopCgoKdGFwcGx5KAogIFNhbGVQcmljZSwKICBQcm9wZXJ0eVR5cGUsCiAgbWVhbgopCmBgYAoKYGBge3J9CnByZWRpY3RvckNvcnJlbGF0aW9uIDwtIGNiaW5kKAogIEFyZWEsCiAgQmVkcm9vbXMsCiAgQmF0aHJvb21zLAogIENhclBhcmtzLAogIFByb3BlcnR5VHlwZQopCgoKcm91bmQoCiAgY29yKHByZWRpY3RvckNvcnJlbGF0aW9uKSwKICAzCikKYGBgCgpgYGB7cn0KeSA8LSBTYWxlUHJpY2UKCnggPC0gY2JpbmQoCiAgQXJlYSwKICBCZWRyb29tcywKICBCYXRocm9vbXMsCiAgQ2FyUGFya3MsCiAgUHJvcGVydHlUeXBlCikKCmNvbG5hbWVzKHgpIDwtIGMoCiAgIkFyZWEiLAogICJCZWRyb29tcyIsCiAgIkJhdGhyb29tcyIsCiAgIkNhclBhcmtzIiwKICAiUHJvcGVydHlUeXBlIgopCgpOdG90YWwgPC0gbGVuZ3RoKHkpCk54IDwtIG5jb2woeCkKCk50b3RhbApOeApkaW0oeCkKYGBgCgpgYGB7cn0KeFByZWQgPC0gbWF0cml4KAogIGMoCiAgICAyNjAwLCA0LCAyLCAxLCAwLAogICAgODAwLCAgMiwgMSwgNCwgMSwKICAgIDE4NTAsIDMsIDEsIDIsIDEsCiAgICA1NTAwLCA3LCA0LCA1LCAwLAogICAgNTUwLCAgMiwgMiwgMSwgMQogICksCiAgbnJvdyA9IDUsCiAgYnlyb3cgPSBUUlVFCikKCmNvbG5hbWVzKHhQcmVkKSA8LSBjKAogICJBcmVhIiwKICAiQmVkcm9vbXMiLAogICJCYXRocm9vbXMiLAogICJDYXJQYXJrcyIsCiAgIlByb3BlcnR5VHlwZSIKKQoKeFByZWQKYGBgCgpgYGB7cn0KcHJpb3JNZWFuIDwtIGMoCiAgMC4wMDA5LAogIDEuMCwKICAwLAogIDEuMiwKICAtMS41CikKCm5hbWVzKHByaW9yTWVhbikgPC0gYygKICAiQXJlYSIsCiAgIkJlZHJvb21zIiwKICAiQmF0aHJvb21zIiwKICAiQ2FyUGFya3MiLAogICJQcm9wZXJ0eVR5cGUiCikKCnByaW9yTWVhbgpgYGAKCmBgYHtyfQpwcmlvclZhck1haW4gPC0gYygKICAxZS04LAogIDEuMDAsCiAgNC4wMCwKICAwLjA2MjUsCiAgMC4wMQopCgpuYW1lcyhwcmlvclZhck1haW4pIDwtIG5hbWVzKHByaW9yTWVhbikKCnByaW9yVmFyTWFpbgoKc3FydCgKICBwcmlvclZhck1haW4KKQpgYGAKCmBgYHtyfQpwcmlvclZhclN0cm9uZyA8LSBwcmlvclZhck1haW4gLyA0CgpwcmlvclZhcldlYWsgPC0gcHJpb3JWYXJNYWluICogNAoKcHJpb3JTZW5zaXRpdml0eVRhYmxlIDwtIGRhdGEuZnJhbWUoCiAgUHJlZGljdG9yID0gbmFtZXMocHJpb3JNZWFuKSwKICBQcmlvck1lYW4gPSBwcmlvck1lYW4sCiAgU3Ryb25nZXJWYXJpYW5jZSA9IHByaW9yVmFyU3Ryb25nLAogIE1haW5WYXJpYW5jZSA9IHByaW9yVmFyTWFpbiwKICBXZWFrZXJWYXJpYW5jZSA9IHByaW9yVmFyV2VhawopCgpwcmlvclNlbnNpdGl2aXR5VGFibGUKYGBgCgpgYGB7cn0KbW9kZWxTdHJpbmcgPC0gIgoKZGF0YSB7CgogIHlzZCA8LSBzZCh5KQoKICBmb3IgKGkgaW4gMTpOdG90YWwpIHsKICAgIHp5W2ldIDwtIHlbaV0gLyB5c2QKICB9CgogIGZvciAoaiBpbiAxOk54KSB7CgogICAgeHNkW2pdIDwtIHNkKHhbLGpdKQoKICAgIGZvciAoaSBpbiAxOk50b3RhbCkgewogICAgICB6eFtpLGpdIDwtIHhbaSxqXSAvIHhzZFtqXQogICAgfQogIH0KCiAgZm9yIChqIGluIDE6TngpIHsKCiAgICB6UHJpb3JNZWFuW2pdIDwtCiAgICAgIHByaW9yTWVhbltqXSAqCiAgICAgIHhzZFtqXSAvCiAgICAgIHlzZAoKICAgIHpQcmlvclZhcltqXSA8LQogICAgICBwcmlvclZhcltqXSAqCiAgICAgIHBvdygKICAgICAgICB4c2Rbal0gLyB5c2QsCiAgICAgICAgMgogICAgICApCiAgfQp9CgoKbW9kZWwgewoKICBmb3IgKGkgaW4gMTpOdG90YWwpIHsKCiAgICBtdVtpXSA8LQogICAgICB6YmV0YTAgKwogICAgICBzdW0oCiAgICAgICAgemJldGFbMTpOeF0gKgogICAgICAgIHp4W2ksMTpOeF0KICAgICAgKQoKICAgIHp5W2ldIH4gZGdhbW1hKAogICAgICBwb3cobXVbaV0sMikgLyB6VmFyLAogICAgICBtdVtpXSAvIHpWYXIKICAgICkKICB9CgoKICB6YmV0YTAgfiBkbm9ybSgKICAgIDAsCiAgICAxIC8gcG93KDIsMikKICApCgoKICBmb3IgKGogaW4gMTpOeCkgewoKICAgIHpiZXRhW2pdIH4gZG5vcm0oCiAgICAgIHpQcmlvck1lYW5bal0sCiAgICAgIDEgLyB6UHJpb3JWYXJbal0KICAgICkKICB9CgoKICB6VmFyIH4gZGdhbW1hKAogICAgMC4wMSwKICAgIDAuMDAxCiAgKQoKCiAgZm9yIChqIGluIDE6TngpIHsKCiAgICBiZXRhW2pdIDwtCiAgICAgICh6YmV0YVtqXSAvIHhzZFtqXSkgKgogICAgICB5c2QKICB9CgoKICBiZXRhMCA8LQogICAgemJldGEwICoKICAgIHlzZAoKCiAgdGF1IDwtCiAgICB6VmFyICoKICAgIHBvdygKICAgICAgeXNkLAogICAgICAyCiAgICApCgoKICBmb3IgKHAgaW4gMTo1KSB7CgogICAgcHJlZFtwXSA8LQogICAgICBiZXRhMCArCiAgICAgIGJldGFbMV0gKiB4UHJlZFtwLDFdICsKICAgICAgYmV0YVsyXSAqIHhQcmVkW3AsMl0gKwogICAgICBiZXRhWzNdICogeFByZWRbcCwzXSArCiAgICAgIGJldGFbNF0gKiB4UHJlZFtwLDRdICsKICAgICAgYmV0YVs1XSAqIHhQcmVkW3AsNV0KICB9Cn0KIgoKd3JpdGVMaW5lcygKICBtb2RlbFN0cmluZywKICBjb24gPSAiVEVNUG1vZGVsLnR4dCIKKQoKZmlsZS5leGlzdHMoCiAgIlRFTVBtb2RlbC50eHQiCikKYGBgCgoKYGBge3J9CnlzZFIgPC0gc2QoeSkKCnhzZFIgPC0gYXBwbHkoCiAgeCwKICAyLAogIHNkCikKCnpQcmlvck1lYW5SIDwtCiAgcHJpb3JNZWFuICoKICB4c2RSIC8KICB5c2RSCgppbml0c0xpc3QgPC0gbGlzdCgKCiAgbGlzdCgKICAgIHpiZXRhMCA9IDEuNSwKICAgIHpiZXRhID0gelByaW9yTWVhblIsCiAgICB6VmFyID0gMQogICksCgogIGxpc3QoCiAgICB6YmV0YTAgPSAyLjAsCiAgICB6YmV0YSA9IHpQcmlvck1lYW5SLAogICAgelZhciA9IDEuNQogICksCgogIGxpc3QoCiAgICB6YmV0YTAgPSAyLjUsCiAgICB6YmV0YSA9IHpQcmlvck1lYW5SLAogICAgelZhciA9IDIKICApCikKYGBgCgpgYGB7cn0KcGFyYW1ldGVycyA8LSBjKAogICJiZXRhMCIsCiAgImJldGEiLAogICJ0YXUiLAogICJwcmVkIgopCmBgYAoKYGBge3J9Cm5DaGFpbnMgPC0gMwpuQWRhcHQgPC0gNTAwCm5CdXJuaW4gPC0gMTAwMDAKbkl0ZXJhdGlvbnMgPC0gMTUwMDAwCm5UaGluIDwtIDEwCmBgYAoKYGBge3J9CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgRlVOQ1RJT04gVE8gUlVOIEEgUFJJT1IgU0VUVElORwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKcnVuQmF5ZXNpYW5Nb2RlbCA8LSBmdW5jdGlvbihwcmlvclZhcmlhbmNlKSB7CgogIGRhdGFMaXN0IDwtIGxpc3QoCiAgICB5ID0geSwKICAgIHggPSB4LAogICAgTnRvdGFsID0gTnRvdGFsLAogICAgTnggPSBOeCwKICAgIHByaW9yTWVhbiA9IHByaW9yTWVhbiwKICAgIHByaW9yVmFyID0gcHJpb3JWYXJpYW5jZSwKICAgIHhQcmVkID0geFByZWQKICApCgogIGphZ3NNb2RlbCA8LSBqYWdzLm1vZGVsKAogICAgZmlsZSA9ICJURU1QbW9kZWwudHh0IiwKICAgIGRhdGEgPSBkYXRhTGlzdCwKICAgIGluaXRzID0gaW5pdHNMaXN0LAogICAgbi5jaGFpbnMgPSBuQ2hhaW5zLAogICAgbi5hZGFwdCA9IG5BZGFwdAogICkKCiAgdXBkYXRlKAogICAgamFnc01vZGVsLAogICAgbi5pdGVyID0gbkJ1cm5pbgogICkKCiAgc2FtcGxlcyA8LSBjb2RhLnNhbXBsZXMoCiAgICBtb2RlbCA9IGphZ3NNb2RlbCwKICAgIHZhcmlhYmxlLm5hbWVzID0gcGFyYW1ldGVycywKICAgIG4uaXRlciA9IG5JdGVyYXRpb25zLAogICAgdGhpbiA9IG5UaGluCiAgKQoKICByZXR1cm4oCiAgICBzYW1wbGVzCiAgKQp9CmBgYAoKYGBge3J9Cm1haW5TYW1wbGVzRmluYWwgPC0gcnVuQmF5ZXNpYW5Nb2RlbCgKICBwcmlvclZhck1haW4KKQoKc2F2ZVJEUygKICBtYWluU2FtcGxlc0ZpbmFsLAogICJtYWluU2FtcGxlc0ZpbmFsXzE1MEsucmRzIgopCmBgYAoKYGBge3J9CndlYWtTYW1wbGVzRmluYWwgPC0gcnVuQmF5ZXNpYW5Nb2RlbCgKICBwcmlvclZhcldlYWsKKQoKc2F2ZVJEUygKICB3ZWFrU2FtcGxlc0ZpbmFsLAogICJ3ZWFrU2FtcGxlc0ZpbmFsXzE1MEsucmRzIgopCmBgYAoKYGBge3J9CnN0cm9uZ1NhbXBsZXNGaW5hbCA8LSBydW5CYXllc2lhbk1vZGVsKAogIHByaW9yVmFyU3Ryb25nCikKCnNhdmVSRFMoCiAgc3Ryb25nU2FtcGxlc0ZpbmFsLAogICJzdHJvbmdTYW1wbGVzRmluYWxfMTUwSy5yZHMiCikKYGBgCgpgYGB7cn0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBGVU5DVElPTiBGT1IgTUNNQyBESUFHTk9TVElDUwojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKZ2V0RGlhZ25vc3RpY3MgPC0gZnVuY3Rpb24oc2FtcGxlcykgewoKICBnZWxtYW5SZXN1bHQgPC0gZ2VsbWFuLmRpYWcoCiAgICBzYW1wbGVzLAogICAgYXV0b2J1cm5pbiA9IEZBTFNFLAogICAgbXVsdGl2YXJpYXRlID0gRkFMU0UKICApCgogIGVzc1Jlc3VsdCA8LSBlZmZlY3RpdmVTaXplKAogICAgc2FtcGxlcwogICkKCiAgc2FtcGxlTWF0cml4IDwtIGFzLm1hdHJpeCgKICAgIHNhbXBsZXMKICApCgogIHNhbXBsZVNEIDwtIGFwcGx5KAogICAgc2FtcGxlTWF0cml4LAogICAgMiwKICAgIHNkCiAgKQoKICBtY3NlUmVzdWx0IDwtCiAgICBzYW1wbGVTRCAvCiAgICBzcXJ0KAogICAgICBlc3NSZXN1bHQKICAgICkKCiAgZGlhZ25vc3RpY1RhYmxlIDwtIGRhdGEuZnJhbWUoCiAgICBQYXJhbWV0ZXIgPSBuYW1lcyhlc3NSZXN1bHQpLAogICAgRVNTID0gYXMubnVtZXJpYyhlc3NSZXN1bHQpLAogICAgU0QgPSBzYW1wbGVTRFtuYW1lcyhlc3NSZXN1bHQpXSwKICAgIE1DU0UgPSBtY3NlUmVzdWx0W25hbWVzKGVzc1Jlc3VsdCldCiAgKQoKICByZXR1cm4oCiAgICBsaXN0KAogICAgICBHZWxtYW4gPSBnZWxtYW5SZXN1bHQsCiAgICAgIERpYWdub3N0aWNUYWJsZSA9IGRpYWdub3N0aWNUYWJsZQogICAgKQogICkKfQpgYGAKCmBgYHtyfQptYWluRGlhZ25vc3RpY3MgPC0gZ2V0RGlhZ25vc3RpY3MoCiAgbWFpblNhbXBsZXNGaW5hbAopCgptYWluRGlhZ25vc3RpY3MkR2VsbWFuCgptYWluRGlhZ25vc3RpY3MkRGlhZ25vc3RpY1RhYmxlCgptYWluRGlhZ25vc3RpY3MkRGlhZ25vc3RpY1RhYmxlWwogIG9yZGVyKAogICAgbWFpbkRpYWdub3N0aWNzJERpYWdub3N0aWNUYWJsZSRFU1MKICApLApdCmBgYAoKYGBge3J9Cm1vZGVsUGFyYW1ldGVyTmFtZXMgPC0gYygKICAiYmV0YTAiLAogICJiZXRhWzFdIiwKICAiYmV0YVsyXSIsCiAgImJldGFbM10iLAogICJiZXRhWzRdIiwKICAiYmV0YVs1XSIsCiAgInRhdSIKKQoKZm9yIChwYXJhbWV0ZXJOYW1lIGluIG1vZGVsUGFyYW1ldGVyTmFtZXMpIHsKCiAgcGxvdCgKICAgIG1haW5TYW1wbGVzRmluYWxbCiAgICAgICwKICAgICAgcGFyYW1ldGVyTmFtZQogICAgXQogICkKfQpgYGAKCmBgYHtyfQpmb3IgKHBhcmFtZXRlck5hbWUgaW4gbW9kZWxQYXJhbWV0ZXJOYW1lcykgewoKICBhdXRvY29yci5wbG90KAogICAgbWFpblNhbXBsZXNGaW5hbFsKICAgICAgLAogICAgICBwYXJhbWV0ZXJOYW1lCiAgICBdCiAgKQp9CmBgYAoKYGBge3J9CndlYWtEaWFnbm9zdGljcyA8LSBnZXREaWFnbm9zdGljcygKICB3ZWFrU2FtcGxlc0ZpbmFsCikKCndlYWtEaWFnbm9zdGljcyRHZWxtYW4KCndlYWtEaWFnbm9zdGljcyREaWFnbm9zdGljVGFibGUKCndlYWtEaWFnbm9zdGljcyREaWFnbm9zdGljVGFibGVbCiAgb3JkZXIoCiAgICB3ZWFrRGlhZ25vc3RpY3MkRGlhZ25vc3RpY1RhYmxlJEVTUwogICksCl0KYGBgCgpgYGB7cn0Kc3Ryb25nRGlhZ25vc3RpY3MgPC0gZ2V0RGlhZ25vc3RpY3MoCiAgc3Ryb25nU2FtcGxlc0ZpbmFsCikKCnN0cm9uZ0RpYWdub3N0aWNzJEdlbG1hbgoKc3Ryb25nRGlhZ25vc3RpY3MkRGlhZ25vc3RpY1RhYmxlCgpzdHJvbmdEaWFnbm9zdGljcyREaWFnbm9zdGljVGFibGVbCiAgb3JkZXIoCiAgICBzdHJvbmdEaWFnbm9zdGljcyREaWFnbm9zdGljVGFibGUkRVNTCiAgKSwKXQpgYGAKCmBgYHtyfQpjb2VmTmFtZXMgPC0gYygKICAiYmV0YTAiLAogICJiZXRhWzFdIiwKICAiYmV0YVsyXSIsCiAgImJldGFbM10iLAogICJiZXRhWzRdIiwKICAiYmV0YVs1XSIKKQoKY29lZk1hdHJpeCA8LSBhcy5tYXRyaXgoCiAgbWFpblNhbXBsZXNGaW5hbFsKICAgICwKICAgIGNvZWZOYW1lcwogIF0KKQoKY29lZk1lYW4gPC0gY29sTWVhbnMoCiAgY29lZk1hdHJpeAopCgpjb2VmSERJIDwtIEhQRGludGVydmFsKAogIG1jbWMoCiAgICBjb2VmTWF0cml4CiAgKSwKICBwcm9iID0gMC45NQopCgpmaW5hbENvZWZmaWNpZW50VGFibGUgPC0gZGF0YS5mcmFtZSgKICBQYXJhbWV0ZXIgPSBjKAogICAgIkludGVyY2VwdCIsCiAgICAiQXJlYSIsCiAgICAiQmVkcm9vbXMiLAogICAgIkJhdGhyb29tcyIsCiAgICAiQ2FyUGFya3MiLAogICAgIlByb3BlcnR5VHlwZSIKICApLAoKICBQb3N0ZXJpb3JNZWFuID0KICAgIGFzLm51bWVyaWMoCiAgICAgIGNvZWZNZWFuCiAgICApLAoKICBIRElMb3dlciA9CiAgICBjb2VmSERJWwogICAgICAsCiAgICAgICJsb3dlciIKICAgIF0sCgogIEhESVVwcGVyID0KICAgIGNvZWZIRElbCiAgICAgICwKICAgICAgInVwcGVyIgogICAgXQopCgpmaW5hbENvZWZmaWNpZW50VGFibGUKYGBgCgpgYGB7cn0KdGF1VmFsdWVzIDwtIGFzLm1hdHJpeCgKICBtYWluU2FtcGxlc0ZpbmFsWwogICAgLAogICAgInRhdSIKICBdCikKCnRhdU1lYW4gPC0gbWVhbigKICB0YXVWYWx1ZXMKKQoKdGF1SERJIDwtIEhQRGludGVydmFsKAogIG1jbWMoCiAgICB0YXVWYWx1ZXMKICApLAogIHByb2IgPSAwLjk1CikKCnRhdVN1bW1hcnkgPC0gZGF0YS5mcmFtZSgKICBQYXJhbWV0ZXIgPSAidGF1IiwKICBQb3N0ZXJpb3JNZWFuID0gdGF1TWVhbiwKICBIRElMb3dlciA9IHRhdUhESVsxLCAibG93ZXIiXSwKICBIRElVcHBlciA9IHRhdUhESVsxLCAidXBwZXIiXQopCgp0YXVTdW1tYXJ5CmBgYAoKYGBge3J9CnByZWRpY3Rpb25FcXVhdGlvbiA8LSBwYXN0ZTAoCgogICJQcmVkaWN0ZWQgU2FsZVByaWNlID0gIiwKCiAgcm91bmQoCiAgICBjb2VmTWVhblsiYmV0YTAiXSwKICAgIDYKICApLAoKICAiICsgKCIsCiAgcm91bmQoCiAgICBjb2VmTWVhblsiYmV0YVsxXSJdLAogICAgNgogICksCiAgIiB4IEFyZWEpIiwKCiAgIiArICgiLAogIHJvdW5kKAogICAgY29lZk1lYW5bImJldGFbMl0iXSwKICAgIDYKICApLAogICIgeCBCZWRyb29tcykiLAoKICAiICsgKCIsCiAgcm91bmQoCiAgICBjb2VmTWVhblsiYmV0YVszXSJdLAogICAgNgogICksCiAgIiB4IEJhdGhyb29tcykiLAoKICAiICsgKCIsCiAgcm91bmQoCiAgICBjb2VmTWVhblsiYmV0YVs0XSJdLAogICAgNgogICksCiAgIiB4IENhclBhcmtzKSIsCgogICIgKyAoIiwKICByb3VuZCgKICAgIGNvZWZNZWFuWyJiZXRhWzVdIl0sCiAgICA2CiAgKSwKICAiIHggUHJvcGVydHlUeXBlKSIKKQoKcHJlZGljdGlvbkVxdWF0aW9uCmBgYAoKYGBge3J9CnByZWRpY3Rpb25OYW1lcyA8LSBjKAogICJwcmVkWzFdIiwKICAicHJlZFsyXSIsCiAgInByZWRbM10iLAogICJwcmVkWzRdIiwKICAicHJlZFs1XSIKKQoKcHJlZGljdGlvbk1hdHJpeCA8LSBhcy5tYXRyaXgoCiAgbWFpblNhbXBsZXNGaW5hbFsKICAgICwKICAgIHByZWRpY3Rpb25OYW1lcwogIF0KKQoKcHJlZGljdGlvbk1lYW4gPC0gY29sTWVhbnMoCiAgcHJlZGljdGlvbk1hdHJpeAopCgpwcmVkaWN0aW9uSERJIDwtIEhQRGludGVydmFsKAogIG1jbWMoCiAgICBwcmVkaWN0aW9uTWF0cml4CiAgKSwKICBwcm9iID0gMC45NQopCgpmaW5hbFByZWRpY3Rpb25UYWJsZSA8LSBkYXRhLmZyYW1lKAoKICBQcm9wZXJ0eSA9IDE6NSwKCiAgQXJlYSA9CiAgICB4UHJlZFssIDFdLAoKICBCZWRyb29tcyA9CiAgICB4UHJlZFssIDJdLAoKICBCYXRocm9vbXMgPQogICAgeFByZWRbLCAzXSwKCiAgQ2FyUGFya3MgPQogICAgeFByZWRbLCA0XSwKCiAgUHJvcGVydHlUeXBlID0gYygKICAgICJIb3VzZSIsCiAgICAiVW5pdCIsCiAgICAiVW5pdCIsCiAgICAiSG91c2UiLAogICAgIlVuaXQiCiAgKSwKCiAgQmF5ZXNpYW5Fc3RpbWF0ZUFVRCA9CiAgICBwcmVkaWN0aW9uTWVhbiAqCiAgICAxMDAwMDAsCgogIEhESUxvd2VyQVVEID0KICAgIHByZWRpY3Rpb25IRElbCiAgICAgICwKICAgICAgImxvd2VyIgogICAgXSAqCiAgICAxMDAwMDAsCgogIEhESVVwcGVyQVVEID0KICAgIHByZWRpY3Rpb25IRElbCiAgICAgICwKICAgICAgInVwcGVyIgogICAgXSAqCiAgICAxMDAwMDAKKQoKZmluYWxQcmVkaWN0aW9uVGFibGUKYGBgCgpgYGB7cn0KZ2V0Q29lZmZpY2llbnRTdW1tYXJ5IDwtIGZ1bmN0aW9uKHNhbXBsZXMpIHsKCiAgY29lZk1hdHJpeCA8LSBhcy5tYXRyaXgoCiAgICBzYW1wbGVzWwogICAgICAsCiAgICAgIGMoCiAgICAgICAgImJldGFbMV0iLAogICAgICAgICJiZXRhWzJdIiwKICAgICAgICAiYmV0YVszXSIsCiAgICAgICAgImJldGFbNF0iLAogICAgICAgICJiZXRhWzVdIgogICAgICApCiAgICBdCiAgKQoKICBjb2VmTWVhbiA8LSBjb2xNZWFucygKICAgIGNvZWZNYXRyaXgKICApCgogIGNvZWZIREkgPC0gSFBEaW50ZXJ2YWwoCiAgICBtY21jKAogICAgICBjb2VmTWF0cml4CiAgICApLAogICAgcHJvYiA9IDAuOTUKICApCgogIHJldHVybigKICAgIGxpc3QoCiAgICAgIE1lYW4gPSBjb2VmTWVhbiwKICAgICAgSERJID0gY29lZkhESQogICAgKQogICkKfQpgYGAKCmBgYHtyfQpzdHJvbmdDb2VmIDwtIGdldENvZWZmaWNpZW50U3VtbWFyeSgKICBzdHJvbmdTYW1wbGVzRmluYWwKKQoKbWFpbkNvZWYgPC0gZ2V0Q29lZmZpY2llbnRTdW1tYXJ5KAogIG1haW5TYW1wbGVzRmluYWwKKQoKd2Vha0NvZWYgPC0gZ2V0Q29lZmZpY2llbnRTdW1tYXJ5KAogIHdlYWtTYW1wbGVzRmluYWwKKQoKY29lZmZpY2llbnRTZW5zaXRpdml0eVRhYmxlIDwtIGRhdGEuZnJhbWUoCgogIFBhcmFtZXRlciA9IGMoCiAgICAiQXJlYSIsCiAgICAiQmVkcm9vbXMiLAogICAgIkJhdGhyb29tcyIsCiAgICAiQ2FyUGFya3MiLAogICAgIlByb3BlcnR5VHlwZSIKICApLAoKICBTdHJvbmdlck1lYW4gPQogICAgYXMubnVtZXJpYygKICAgICAgc3Ryb25nQ29lZiRNZWFuCiAgICApLAoKICBTdHJvbmdlckxvd2VyID0KICAgIHN0cm9uZ0NvZWYkSERJWwogICAgICAsCiAgICAgICJsb3dlciIKICAgIF0sCgogIFN0cm9uZ2VyVXBwZXIgPQogICAgc3Ryb25nQ29lZiRIRElbCiAgICAgICwKICAgICAgInVwcGVyIgogICAgXSwKCiAgTWFpbk1lYW4gPQogICAgYXMubnVtZXJpYygKICAgICAgbWFpbkNvZWYkTWVhbgogICAgKSwKCiAgTWFpbkxvd2VyID0KICAgIG1haW5Db2VmJEhESVsKICAgICAgLAogICAgICAibG93ZXIiCiAgICBdLAoKICBNYWluVXBwZXIgPQogICAgbWFpbkNvZWYkSERJWwogICAgICAsCiAgICAgICJ1cHBlciIKICAgIF0sCgogIFdlYWtlck1lYW4gPQogICAgYXMubnVtZXJpYygKICAgICAgd2Vha0NvZWYkTWVhbgogICAgKSwKCiAgV2Vha2VyTG93ZXIgPQogICAgd2Vha0NvZWYkSERJWwogICAgICAsCiAgICAgICJsb3dlciIKICAgIF0sCgogIFdlYWtlclVwcGVyID0KICAgIHdlYWtDb2VmJEhESVsKICAgICAgLAogICAgICAidXBwZXIiCiAgICBdCikKCmNvZWZmaWNpZW50U2Vuc2l0aXZpdHlUYWJsZQpgYGAKCmBgYHtyfQpnZXRQcmVkaWN0aW9uU3VtbWFyeSA8LSBmdW5jdGlvbihzYW1wbGVzKSB7CgogIHByZWRpY3Rpb25NYXRyaXggPC0gYXMubWF0cml4KAogICAgc2FtcGxlc1sKICAgICAgLAogICAgICBwcmVkaWN0aW9uTmFtZXMKICAgIF0KICApCgogIHByZWRpY3Rpb25NZWFuIDwtIGNvbE1lYW5zKAogICAgcHJlZGljdGlvbk1hdHJpeAogICkKCiAgcHJlZGljdGlvbkhESSA8LSBIUERpbnRlcnZhbCgKICAgIG1jbWMoCiAgICAgIHByZWRpY3Rpb25NYXRyaXgKICAgICksCiAgICBwcm9iID0gMC45NQogICkKCiAgcmV0dXJuKAogICAgbGlzdCgKICAgICAgTWVhbiA9IHByZWRpY3Rpb25NZWFuLAogICAgICBIREkgPSBwcmVkaWN0aW9uSERJCiAgICApCiAgKQp9CmBgYAoKYGBge3J9CnN0cm9uZ1ByZWRpY3Rpb24gPC0gZ2V0UHJlZGljdGlvblN1bW1hcnkoCiAgc3Ryb25nU2FtcGxlc0ZpbmFsCikKCm1haW5QcmVkaWN0aW9uIDwtIGdldFByZWRpY3Rpb25TdW1tYXJ5KAogIG1haW5TYW1wbGVzRmluYWwKKQoKd2Vha1ByZWRpY3Rpb24gPC0gZ2V0UHJlZGljdGlvblN1bW1hcnkoCiAgd2Vha1NhbXBsZXNGaW5hbAopCgpwcmVkaWN0aW9uU2Vuc2l0aXZpdHlUYWJsZSA8LSBkYXRhLmZyYW1lKAoKICBQcm9wZXJ0eSA9IDE6NSwKCiAgU3Ryb25nZXJNZWFuQVVEID0KICAgIHN0cm9uZ1ByZWRpY3Rpb24kTWVhbiAqCiAgICAxMDAwMDAsCgogIFN0cm9uZ2VyTG93ZXJBVUQgPQogICAgc3Ryb25nUHJlZGljdGlvbiRIRElbCiAgICAgICwKICAgICAgImxvd2VyIgogICAgXSAqCiAgICAxMDAwMDAsCgogIFN0cm9uZ2VyVXBwZXJBVUQgPQogICAgc3Ryb25nUHJlZGljdGlvbiRIRElbCiAgICAgICwKICAgICAgInVwcGVyIgogICAgXSAqCiAgICAxMDAwMDAsCgogIE1haW5NZWFuQVVEID0KICAgIG1haW5QcmVkaWN0aW9uJE1lYW4gKgogICAgMTAwMDAwLAoKICBNYWluTG93ZXJBVUQgPQogICAgbWFpblByZWRpY3Rpb24kSERJWwogICAgICAsCiAgICAgICJsb3dlciIKICAgIF0gKgogICAgMTAwMDAwLAoKICBNYWluVXBwZXJBVUQgPQogICAgbWFpblByZWRpY3Rpb24kSERJWwogICAgICAsCiAgICAgICJ1cHBlciIKICAgIF0gKgogICAgMTAwMDAwLAoKICBXZWFrZXJNZWFuQVVEID0KICAgIHdlYWtQcmVkaWN0aW9uJE1lYW4gKgogICAgMTAwMDAwLAoKICBXZWFrZXJMb3dlckFVRCA9CiAgICB3ZWFrUHJlZGljdGlvbiRIRElbCiAgICAgICwKICAgICAgImxvd2VyIgogICAgXSAqCiAgICAxMDAwMDAsCgogIFdlYWtlclVwcGVyQVVEID0KICAgIHdlYWtQcmVkaWN0aW9uJEhESVsKICAgICAgLAogICAgICAidXBwZXIiCiAgICBdICoKICAgIDEwMDAwMAopCgpwcmVkaWN0aW9uU2Vuc2l0aXZpdHlUYWJsZQpgYGAKCmBgYHtyfQpnZXRUYXVTdW1tYXJ5IDwtIGZ1bmN0aW9uKHNhbXBsZXMpIHsKCiAgdGF1VmFsdWVzIDwtIGFzLm1hdHJpeCgKICAgIHNhbXBsZXNbCiAgICAgICwKICAgICAgInRhdSIKICAgIF0KICApCgogIHRhdU1lYW4gPC0gbWVhbigKICAgIHRhdVZhbHVlcwogICkKCiAgdGF1SERJIDwtIEhQRGludGVydmFsKAogICAgbWNtYygKICAgICAgdGF1VmFsdWVzCiAgICApLAogICAgcHJvYiA9IDAuOTUKICApCgogIHJldHVybigKICAgIGMoCiAgICAgIE1lYW4gPSB0YXVNZWFuLAogICAgICBMb3dlciA9IHRhdUhESVsxLCAibG93ZXIiXSwKICAgICAgVXBwZXIgPSB0YXVIRElbMSwgInVwcGVyIl0KICAgICkKICApCn0KCnN0cm9uZ1RhdSA8LSBnZXRUYXVTdW1tYXJ5KAogIHN0cm9uZ1NhbXBsZXNGaW5hbAopCgptYWluVGF1IDwtIGdldFRhdVN1bW1hcnkoCiAgbWFpblNhbXBsZXNGaW5hbAopCgp3ZWFrVGF1IDwtIGdldFRhdVN1bW1hcnkoCiAgd2Vha1NhbXBsZXNGaW5hbAopCgp0YXVTZW5zaXRpdml0eVRhYmxlIDwtIGRhdGEuZnJhbWUoCgogIFByaW9yU2V0dGluZyA9IGMoCiAgICAiU3Ryb25nZXIiLAogICAgIk1haW4iLAogICAgIldlYWtlciIKICApLAoKICBQb3N0ZXJpb3JNZWFuID0gYygKICAgIHN0cm9uZ1RhdVsiTWVhbiJdLAogICAgbWFpblRhdVsiTWVhbiJdLAogICAgd2Vha1RhdVsiTWVhbiJdCiAgKSwKCiAgSERJTG93ZXIgPSBjKAogICAgc3Ryb25nVGF1WyJMb3dlciJdLAogICAgbWFpblRhdVsiTG93ZXIiXSwKICAgIHdlYWtUYXVbIkxvd2VyIl0KICApLAoKICBIRElVcHBlciA9IGMoCiAgICBzdHJvbmdUYXVbIlVwcGVyIl0sCiAgICBtYWluVGF1WyJVcHBlciJdLAogICAgd2Vha1RhdVsiVXBwZXIiXQogICkKKQoKdGF1U2Vuc2l0aXZpdHlUYWJsZQpgYGAKCmBgYHtyfQpzYXZlUkRTKAogIG1haW5TYW1wbGVzRmluYWwsCiAgIm1haW5TYW1wbGVzRmluYWxfMTUwSy5yZHMiCikKCnNhdmVSRFMoCiAgd2Vha1NhbXBsZXNGaW5hbCwKICAid2Vha1NhbXBsZXNGaW5hbF8xNTBLLnJkcyIKKQoKc2F2ZVJEUygKICBzdHJvbmdTYW1wbGVzRmluYWwsCiAgInN0cm9uZ1NhbXBsZXNGaW5hbF8xNTBLLnJkcyIKKQpgYGAKCmBgYHtyfQpjb2VmZmljaWVudFNlbnNpdGl2aXR5VGFibGVbLCBjKAogICJQYXJhbWV0ZXIiLAogICJTdHJvbmdlck1lYW4iLCAiU3Ryb25nZXJMb3dlciIsICJTdHJvbmdlclVwcGVyIiwKICAiTWFpbk1lYW4iLCAiTWFpbkxvd2VyIiwgIk1haW5VcHBlciIsCiAgIldlYWtlck1lYW4iLCAiV2Vha2VyTG93ZXIiLCAiV2Vha2VyVXBwZXIiCildCmBgYAoKYGBge3J9CmNvZWZmaWNpZW50U2Vuc2l0aXZpdHlUYWJsZVssIGMoCiAgIlBhcmFtZXRlciIsCiAgIldlYWtlck1lYW4iLAogICJXZWFrZXJMb3dlciIsCiAgIldlYWtlclVwcGVyIgopXQpgYGAKCmBgYHtyfQpwcmVkaWN0aW9uU2Vuc2l0aXZpdHlUYWJsZVssIGMoCiAgIlByb3BlcnR5IiwKICAiU3Ryb25nZXJNZWFuQVVEIiwKICAiU3Ryb25nZXJMb3dlckFVRCIsCiAgIlN0cm9uZ2VyVXBwZXJBVUQiLAogICJNYWluTWVhbkFVRCIsCiAgIk1haW5Mb3dlckFVRCIsCiAgIk1haW5VcHBlckFVRCIsCiAgIldlYWtlck1lYW5BVUQiLAogICJXZWFrZXJMb3dlckFVRCIsCiAgIldlYWtlclVwcGVyQVVEIgopXQpgYGAKCgpgYGB7cn0KcHJlZGljdGlvblNlbnNpdGl2aXR5VGFibGVbLCBjKAogICJQcm9wZXJ0eSIsCiAgIldlYWtlck1lYW5BVUQiLAogICJXZWFrZXJMb3dlckFVRCIsCiAgIldlYWtlclVwcGVyQVVEIgopXQpgYGAKCmBgYHtyfQpmaWxlLmV4aXN0cygiREJEQTJFLXV0aWxpdGllcy5SIikKYGBgCgpgYGB7cn0Kc291cmNlKCJEQkRBMkUtdXRpbGl0aWVzLlIiKQpleGlzdHMoImRpYWdNQ01DIikKCmdyZXAoCiAgImRpYWdNQ01DIiwKICByZWFkTGluZXMoIkRCREEyRS11dGlsaXRpZXMuUiIpLAogIHZhbHVlID0gVFJVRQopCmBgYAoKYGBge3J9ClgxMSgpCgpkZXYubGlzdCgpCgpwbG90KDE6MTApCgpkZXYubGlzdCgpCmBgYAoKYGBge3J9CnBhcmFtZXRlck5hbWVzIDwtIGMoCiAgImJldGEwIiwKICAiYmV0YVsxXSIsCiAgImJldGFbMl0iLAogICJiZXRhWzNdIiwKICAiYmV0YVs0XSIsCiAgImJldGFbNV0iLAogICJ0YXUiCikKCmZpbGVOYW1lcyA8LSBjKAogICJJbnRlcmNlcHQiLAogICJBcmVhIiwKICAiQmVkcm9vbXMiLAogICJCYXRocm9vbXMiLAogICJDYXJQYXJrcyIsCiAgIlByb3BlcnR5VHlwZSIsCiAgIlRhdSIKKQoKZm9yIChpIGluIHNlcV9hbG9uZyhwYXJhbWV0ZXJOYW1lcykpIHsKCiAgZGlhZ01DTUMoCiAgICBjb2RhT2JqZWN0ID0gbWFpblNhbXBsZXNGaW5hbCwKICAgIHBhck5hbWUgPSBwYXJhbWV0ZXJOYW1lc1tpXSwKICAgIHNhdmVOYW1lID0gcGFzdGUwKCJGaW5hbF9EaWFnbm9zdGljXyIsIGZpbGVOYW1lc1tpXSksCiAgICBzYXZlVHlwZSA9ICJqcGciCiAgKQp9CmBgYAoKYGBge3J9CiMgUE9TVEVSSU9SIERJU1RSSUJVVElPTlMgRk9SIFRIRSBGSVZFIFBSRURJQ1RJT05TCgoKcHJlZGljdGlvbk5hbWVzIDwtIGMoCiAgInByZWRbMV0iLAogICJwcmVkWzJdIiwKICAicHJlZFszXSIsCiAgInByZWRbNF0iLAogICJwcmVkWzVdIgopCgojIENvbnZlcnQgTUNNQyBzYW1wbGVzIHRvIG51bWVyaWMgbWF0cml4CnByZWRpY3Rpb25NYXRyaXggPC0gYXMubWF0cml4KAogIG1haW5TYW1wbGVzRmluYWxbLCBwcmVkaWN0aW9uTmFtZXNdCikKCiMgQ29udmVydCBmcm9tICQxMDAsMDAwIHVuaXRzIHRvIEFVRApwcmVkaWN0aW9uTWF0cml4QVVEIDwtIHByZWRpY3Rpb25NYXRyaXggKiAxMDAwMDAKYGBgCgpgYGB7cn0KYXJncyhwbG90UG9zdCkKYGBgCgpgYGB7cn0KcGFyKG1mcm93ID0gYygyLCAzKSkKCmZvciAoaSBpbiAxOjUpIHsKCiAgcGxvdFBvc3QoCiAgICBwcmVkaWN0aW9uTWF0cml4WywgaV0sCiAgICBjZW5UZW5kID0gIm1lYW4iLAogICAgbWFpbiA9IHBhc3RlKCJQcm9wZXJ0eSIsIGkpLAogICAgeGxhYiA9ICJQcmVkaWN0ZWQgU2FsZSBQcmljZSAoJDEwMCwwMDAgQVVEKSIKICApCn0KCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKYGBge3J9CiMgSFlQT1RIRVNJUyBURVNUUyBVU0lORyA5NSUgSERJcwoKZ2V0SHlwb3RoZXNpc1Rlc3RzIDwtIGZ1bmN0aW9uKHNhbXBsZXMsIHByaW9yU2V0dGluZykgewoKICBjb2VmZmljaWVudE5hbWVzIDwtIGMoCiAgICAiYmV0YVsxXSIsCiAgICAiYmV0YVsyXSIsCiAgICAiYmV0YVszXSIsCiAgICAiYmV0YVs0XSIsCiAgICAiYmV0YVs1XSIKICApCgogIHBhcmFtZXRlck5hbWVzIDwtIGMoCiAgICAiQXJlYSIsCiAgICAiQmVkcm9vbXMiLAogICAgIkJhdGhyb29tcyIsCiAgICAiQ2FyUGFya3MiLAogICAgIlByb3BlcnR5VHlwZSIKICApCgogICMgQ29udmVydCBwb3N0ZXJpb3Igc2FtcGxlcyB0byBtYXRyaXgKICBjb2VmZmljaWVudE1hdHJpeCA8LSBhcy5tYXRyaXgoCiAgICBzYW1wbGVzWywgY29lZmZpY2llbnROYW1lc10KICApCgogICMgUG9zdGVyaW9yIG1lYW5zCiAgcG9zdGVyaW9yTWVhbiA8LSBjb2xNZWFucygKICAgIGNvZWZmaWNpZW50TWF0cml4CiAgKQoKICAjIDk1JSBIRElzCiAgY29lZmZpY2llbnRIREkgPC0gSFBEaW50ZXJ2YWwoCiAgICBtY21jKGNvZWZmaWNpZW50TWF0cml4KSwKICAgIHByb2IgPSAwLjk1CiAgKQoKICAjIENoZWNrIHdoZXRoZXIgemVybyBsaWVzIGluc2lkZSBlYWNoIDk1JSBIREkKICB6ZXJvSW5IREkgPC0KICAgIGNvZWZmaWNpZW50SERJWywgImxvd2VyIl0gPD0gMCAmCiAgICBjb2VmZmljaWVudEhESVssICJ1cHBlciJdID49IDAKCiAgIyBIREktYmFzZWQgaHlwb3RoZXNpcyBjb25jbHVzaW9uCiAgaHlwb3RoZXNpc0NvbmNsdXNpb24gPC0gaWZlbHNlKAogICAgemVyb0luSERJLAogICAgIkRvIG5vdCByZWplY3QgSDAiLAogICAgIlJlamVjdCBIMCIKICApCgogICMgRGlyZWN0aW9uIG9mIHBvc3RlcmlvciBjb2VmZmljaWVudAogIGNvZWZmaWNpZW50RGlyZWN0aW9uIDwtIGlmZWxzZSgKICAgIGNvZWZmaWNpZW50SERJWywgImxvd2VyIl0gPiAwLAogICAgIlBvc2l0aXZlIiwKICAgIGlmZWxzZSgKICAgICAgY29lZmZpY2llbnRIRElbLCAidXBwZXIiXSA8IDAsCiAgICAgICJOZWdhdGl2ZSIsCiAgICAgICJJbmNsdWRlcyB6ZXJvIgogICAgKQogICkKCiAgcmVzdWx0IDwtIGRhdGEuZnJhbWUoCiAgICBQcmlvclNldHRpbmcgPSBwcmlvclNldHRpbmcsCiAgICBQYXJhbWV0ZXIgPSBwYXJhbWV0ZXJOYW1lcywKICAgIFBvc3Rlcmlvck1lYW4gPSBhcy5udW1lcmljKHBvc3Rlcmlvck1lYW4pLAogICAgSERJTG93ZXIgPSBjb2VmZmljaWVudEhESVssICJsb3dlciJdLAogICAgSERJVXBwZXIgPSBjb2VmZmljaWVudEhESVssICJ1cHBlciJdLAogICAgWmVyb0luOTVIREkgPSB6ZXJvSW5IREksCiAgICBIeXBvdGhlc2lzQ29uY2x1c2lvbiA9IGh5cG90aGVzaXNDb25jbHVzaW9uLAogICAgRGlyZWN0aW9uID0gY29lZmZpY2llbnREaXJlY3Rpb24KICApCgogIHJldHVybihyZXN1bHQpCn0KYGBgCgpgYGB7cn0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBNQUlOIFBSSU9SIEhZUE9USEVTSVMgVEVTVFMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCm1haW5IeXBvdGhlc2lzVGVzdHMgPC0gZ2V0SHlwb3RoZXNpc1Rlc3RzKAogIG1haW5TYW1wbGVzRmluYWwsCiAgIk1haW4iCikKCm1haW5IeXBvdGhlc2lzVGVzdHMKYGBgCgpgYGB7cn0KIyBTVFJPTkdFUiBQUklPUiBIWVBPVEhFU0lTIFRFU1RTCgpzdHJvbmdIeXBvdGhlc2lzVGVzdHMgPC0gZ2V0SHlwb3RoZXNpc1Rlc3RzKAogIHN0cm9uZ1NhbXBsZXNGaW5hbCwKICAiU3Ryb25nZXIiCikKCnN0cm9uZ0h5cG90aGVzaXNUZXN0cwpgYGAKCmBgYHtyfQojIFdFQUtFUiBQUklPUiBIWVBPVEhFU0lTIFRFU1RTCgoKd2Vha0h5cG90aGVzaXNUZXN0cyA8LSBnZXRIeXBvdGhlc2lzVGVzdHMoCiAgd2Vha1NhbXBsZXNGaW5hbCwKICAiV2Vha2VyIgopCgp3ZWFrSHlwb3RoZXNpc1Rlc3RzCmBgYAoKYGBge3J9CiMgU0VOU0lUSVZJVFkgT0YgSFlQT1RIRVNJUyBDT05DTFVTSU9OUwoKCmh5cG90aGVzaXNTZW5zaXRpdml0eVRhYmxlIDwtIGRhdGEuZnJhbWUoCgogIFBhcmFtZXRlciA9IG1haW5IeXBvdGhlc2lzVGVzdHMkUGFyYW1ldGVyLAoKICBTdHJvbmdlcjk1SERJID0gcGFzdGUwKAogICAgIlsiLAogICAgcm91bmQoc3Ryb25nSHlwb3RoZXNpc1Rlc3RzJEhESUxvd2VyLCA2KSwKICAgICIsICIsCiAgICByb3VuZChzdHJvbmdIeXBvdGhlc2lzVGVzdHMkSERJVXBwZXIsIDYpLAogICAgIl0iCiAgKSwKCiAgU3Ryb25nZXJDb25jbHVzaW9uID0KICAgIHN0cm9uZ0h5cG90aGVzaXNUZXN0cyRIeXBvdGhlc2lzQ29uY2x1c2lvbiwKCiAgU3Ryb25nZXJEaXJlY3Rpb24gPQogICAgc3Ryb25nSHlwb3RoZXNpc1Rlc3RzJERpcmVjdGlvbiwKCiAgTWFpbjk1SERJID0gcGFzdGUwKAogICAgIlsiLAogICAgcm91bmQobWFpbkh5cG90aGVzaXNUZXN0cyRIRElMb3dlciwgNiksCiAgICAiLCAiLAogICAgcm91bmQobWFpbkh5cG90aGVzaXNUZXN0cyRIRElVcHBlciwgNiksCiAgICAiXSIKICApLAoKICBNYWluQ29uY2x1c2lvbiA9CiAgICBtYWluSHlwb3RoZXNpc1Rlc3RzJEh5cG90aGVzaXNDb25jbHVzaW9uLAoKICBNYWluRGlyZWN0aW9uID0KICAgIG1haW5IeXBvdGhlc2lzVGVzdHMkRGlyZWN0aW9uLAoKICBXZWFrZXI5NUhESSA9IHBhc3RlMCgKICAgICJbIiwKICAgIHJvdW5kKHdlYWtIeXBvdGhlc2lzVGVzdHMkSERJTG93ZXIsIDYpLAogICAgIiwgIiwKICAgIHJvdW5kKHdlYWtIeXBvdGhlc2lzVGVzdHMkSERJVXBwZXIsIDYpLAogICAgIl0iCiAgKSwKCiAgV2Vha2VyQ29uY2x1c2lvbiA9CiAgICB3ZWFrSHlwb3RoZXNpc1Rlc3RzJEh5cG90aGVzaXNDb25jbHVzaW9uLAoKICBXZWFrZXJEaXJlY3Rpb24gPQogICAgd2Vha0h5cG90aGVzaXNUZXN0cyREaXJlY3Rpb24KKQoKaHlwb3RoZXNpc1NlbnNpdGl2aXR5VGFibGUKYGBgCgo=