Sample to sample variability
National Health NHanes study
- Since 1960 individuals of all ages are interviewed in their homes every year
- The health examination component of the survey is conducted in a mobile examination centre (MEC).
- We will use this large study to select random subjects from the American population.
- This will help us to understand how the results of an analysis and the conclusions vary from sample to sample.
library(NHANES)
head(NHANES)
Rows: 10,000
Columns: 76
$ ID <int> 51624, 51624, 51624, 51625, 51630, 51638, 51646, 5164…
$ SurveyYr <fct> 2009_10, 2009_10, 2009_10, 2009_10, 2009_10, 2009_10,…
$ Gender <fct> male, male, male, male, female, male, male, female, f…
$ Age <int> 34, 34, 34, 4, 49, 9, 8, 45, 45, 45, 66, 58, 54, 10, …
$ AgeDecade <fct> 30-39, 30-39, 30-39, 0-9, 40-49, 0-9, 0-9, 40…
$ AgeMonths <int> 409, 409, 409, 49, 596, 115, 101, 541, 541, 541, 795,…
$ Race1 <fct> White, White, White, Other, White, White, White, Whit…
$ Race3 <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Education <fct> High School, High School, High School, NA, Some Colle…
$ MaritalStatus <fct> Married, Married, Married, NA, LivePartner, NA, NA, M…
$ HHIncome <fct> 25000-34999, 25000-34999, 25000-34999, 20000-24999, 3…
$ HHIncomeMid <int> 30000, 30000, 30000, 22500, 40000, 87500, 60000, 8750…
$ Poverty <dbl> 1.36, 1.36, 1.36, 1.07, 1.91, 1.84, 2.33, 5.00, 5.00,…
$ HomeRooms <int> 6, 6, 6, 9, 5, 6, 7, 6, 6, 6, 5, 10, 6, 10, 10, 4, 3,…
$ HomeOwn <fct> Own, Own, Own, Own, Rent, Rent, Own, Own, Own, Own, O…
$ Work <fct> NotWorking, NotWorking, NotWorking, NA, NotWorking, N…
$ Weight <dbl> 87.4, 87.4, 87.4, 17.0, 86.7, 29.8, 35.2, 75.7, 75.7,…
$ Length <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ HeadCirc <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Height <dbl> 164.7, 164.7, 164.7, 105.4, 168.4, 133.1, 130.6, 166.…
$ BMI <dbl> 32.22, 32.22, 32.22, 15.30, 30.57, 16.82, 20.64, 27.2…
$ BMICatUnder20yrs <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ BMI_WHO <fct> 30.0_plus, 30.0_plus, 30.0_plus, 12.0_18.5, 30.0_plus…
$ Pulse <int> 70, 70, 70, NA, 86, 82, 72, 62, 62, 62, 60, 62, 76, 8…
$ BPSysAve <int> 113, 113, 113, NA, 112, 86, 107, 118, 118, 118, 111, …
$ BPDiaAve <int> 85, 85, 85, NA, 75, 47, 37, 64, 64, 64, 63, 74, 85, 6…
$ BPSys1 <int> 114, 114, 114, NA, 118, 84, 114, 106, 106, 106, 124, …
$ BPDia1 <int> 88, 88, 88, NA, 82, 50, 46, 62, 62, 62, 64, 76, 86, 6…
$ BPSys2 <int> 114, 114, 114, NA, 108, 84, 108, 118, 118, 118, 108, …
$ BPDia2 <int> 88, 88, 88, NA, 74, 50, 36, 68, 68, 68, 62, 72, 88, 6…
$ BPSys3 <int> 112, 112, 112, NA, 116, 88, 106, 118, 118, 118, 114, …
$ BPDia3 <int> 82, 82, 82, NA, 76, 44, 38, 60, 60, 60, 64, 76, 82, 7…
$ Testosterone <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ DirectChol <dbl> 1.29, 1.29, 1.29, NA, 1.16, 1.34, 1.55, 2.12, 2.12, 2…
$ TotChol <dbl> 3.49, 3.49, 3.49, NA, 6.70, 4.86, 4.09, 5.82, 5.82, 5…
$ UrineVol1 <int> 352, 352, 352, NA, 77, 123, 238, 106, 106, 106, 113, …
$ UrineFlow1 <dbl> NA, NA, NA, NA, 0.094, 1.538, 1.322, 1.116, 1.116, 1.…
$ UrineVol2 <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ UrineFlow2 <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Diabetes <fct> No, No, No, No, No, No, No, No, No, No, No, No, No, N…
$ DiabetesAge <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ HealthGen <fct> Good, Good, Good, NA, Good, NA, NA, Vgood, Vgood, Vgo…
$ DaysPhysHlthBad <int> 0, 0, 0, NA, 0, NA, NA, 0, 0, 0, 10, 0, 4, NA, NA, 0,…
$ DaysMentHlthBad <int> 15, 15, 15, NA, 10, NA, NA, 3, 3, 3, 0, 0, 0, NA, NA,…
$ LittleInterest <fct> Most, Most, Most, NA, Several, NA, NA, None, None, No…
$ Depressed <fct> Several, Several, Several, NA, Several, NA, NA, None,…
$ nPregnancies <int> NA, NA, NA, NA, 2, NA, NA, 1, 1, 1, NA, NA, NA, NA, N…
$ nBabies <int> NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Age1stBaby <int> NA, NA, NA, NA, 27, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ SleepHrsNight <int> 4, 4, 4, NA, 8, NA, NA, 8, 8, 8, 7, 5, 4, NA, 5, 7, N…
$ SleepTrouble <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No, No, Y…
$ PhysActive <fct> No, No, No, NA, No, NA, NA, Yes, Yes, Yes, Yes, Yes, …
$ PhysActiveDays <int> NA, NA, NA, NA, NA, NA, NA, 5, 5, 5, 7, 5, 1, NA, 2, …
$ TVHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ CompHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ TVHrsDayChild <int> NA, NA, NA, 4, NA, 5, 1, NA, NA, NA, NA, NA, NA, 4, N…
$ CompHrsDayChild <int> NA, NA, NA, 1, NA, 0, 6, NA, NA, NA, NA, NA, NA, 3, N…
$ Alcohol12PlusYr <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, Yes, Y…
$ AlcoholDay <int> NA, NA, NA, NA, 2, NA, NA, 3, 3, 3, 1, 2, 6, NA, NA, …
$ AlcoholYear <int> 0, 0, 0, NA, 20, NA, NA, 52, 52, 52, 100, 104, 364, N…
$ SmokeNow <fct> No, No, No, NA, Yes, NA, NA, NA, NA, NA, No, NA, NA, …
$ Smoke100 <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, Yes, No, …
$ Smoke100n <fct> Smoker, Smoker, Smoker, NA, Smoker, NA, NA, Non-Smoke…
$ SmokeAge <int> 18, 18, 18, NA, 38, NA, NA, NA, NA, NA, 13, NA, NA, N…
$ Marijuana <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, NA, Ye…
$ AgeFirstMarij <int> 17, 17, 17, NA, 18, NA, NA, 13, 13, 13, NA, 19, 15, N…
$ RegularMarij <fct> No, No, No, NA, No, NA, NA, No, No, No, NA, Yes, Yes,…
$ AgeRegMarij <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 20, 15, N…
$ HardDrugs <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No, Yes, …
$ SexEver <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, Yes, Y…
$ SexAge <int> 16, 16, 16, NA, 12, NA, NA, 13, 13, 13, 17, 22, 12, N…
$ SexNumPartnLife <int> 8, 8, 8, NA, 10, NA, NA, 20, 20, 20, 15, 7, 100, NA, …
$ SexNumPartYear <int> 1, 1, 1, NA, 1, NA, NA, 0, 0, 0, NA, 1, 1, NA, NA, 1,…
$ SameSex <fct> No, No, No, NA, Yes, NA, NA, Yes, Yes, Yes, No, No, N…
$ SexOrientation <fct> Heterosexual, Heterosexual, Heterosexual, NA, Heteros…
$ PregnantNow <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
Data exploration
Suppose that we are interested in assessing the difference in direct cholesterol levels between males and females older than 25 years.
- We pipe the dataset to the function
filter
to filter the data according to age.
- We plot the direct cholesterol levels.
- We select the data with the command
ggplot(aes(x=DirectChol))
- We add a histogram with the command
geom_histogram()
- We make to vertical panels using the command
facet_grid(Gender~.)
- We customize the label of the x-axis with the
xlab
command.
NHANES %>%
filter(Age > 25) %>%
ggplot(aes(x = DirectChol)) +
geom_histogram() +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (mg/dl)")
- Cholesterol levels and concentration measurements are often skewed.
- Concentrations cannot be lower than 0.
- They are often log transformed.
NHANES %>%
filter(Age > 25) %>%
ggplot(aes(x = DirectChol %>% log2())) +
geom_histogram() +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log2)")
We see that the data are more or less bell shaped upon log transformation.
We will now create a subset of the data that we will use to sample from in the next sections.
- We filter on age and remove subjects with missing values (NA).
- We only select the variables Gender and DirectChol from the dataset to avoid unnecessary variables.
- With the mutate function we can add a new variable logChol with log transformed direct cholesterol levels.
nhanesSub <- NHANES %>%
filter(Age > 25 & !is.na(DirectChol)) %>%
select(c("Gender", "DirectChol")) %>%
mutate(cholLog = log2(DirectChol))
We will calculate the summary statistics for the cholLog variable for males and females in the large dataset.
So we group by Gender
cholLogSum <- nhanesSub %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
cholLogSum
Experiment
- Suppose that we have no access to cholesterol levels of the American population,
- we will have to setup an experiment.
- Suppose we have a budget for assessing 10 females and 10 males,
- we will subset 10 females and 10 males at random from the American population and measure their direct cholesterol levels.
fem <- nhanesSub %>%
filter(Gender == "female") %>%
sample_n(size = 10)
mal <- nhanesSub %>%
filter(Gender == "male") %>%
sample_n(size = 10)
samp <- rbind(fem, mal)
samp
We will now plot the data with a histogram and boxplots
samp %>%
ggplot(aes(x = cholLog)) +
geom_histogram(binwidth = .1) +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log2)")
samp %>%
ggplot(aes(x = Gender, y = cholLog)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter")
We summarize the data
samp %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
Note that the sample mean is different from that of the large experiment (“population”) we sampled from.
We test for the difference between Males and females
t.test(cholLog ~ Gender, samp, var.equal = TRUE)
Two Sample t-test
data: cholLog by Gender
t = 1.8919, df = 18, p-value = 0.0747
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
-0.03588746 0.68570738
sample estimates:
mean in group female mean in group male
0.34776170 0.02285174
Repeat the experiment
If we do the experiment again we select other people and we obtain different results.
fem <- nhanesSub %>%
filter(Gender == "female") %>%
sample_n(size = 10)
mal <- nhanesSub %>%
filter(Gender == "male") %>%
sample_n(size = 10)
samp2 <- rbind(fem, mal)
samp2 %>%
ggplot(aes(x = DirectChol %>% log())) +
geom_histogram(binwidth = .1) +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log)")
samp2 %>%
ggplot(aes(x = Gender, y = cholLog)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter")
samp2 %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
t.test(cholLog ~ Gender, samp2, var.equal = TRUE)
Two Sample t-test
data: cholLog by Gender
t = 1.7522, df = 18, p-value = 0.09675
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
-0.07604904 0.84039821
sample estimates:
mean in group female mean in group male
0.6420087 0.2598341
And again
set.seed(12857)
fem <- nhanesSub %>%
filter(Gender == "female") %>%
sample_n(size = 10)
mal <- nhanesSub %>%
filter(Gender == "male") %>%
sample_n(size = 10)
samp3 <- rbind(fem, mal)
samp3 %>%
ggplot(aes(x = DirectChol %>% log())) +
geom_histogram(binwidth = .1) +
facet_grid(Gender ~ .) +
xlab("Direct cholesterol (log)")
samp3 %>%
ggplot(aes(x = Gender, y = cholLog)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter")
samp3 %>%
group_by(Gender) %>%
summarize(
mean = mean(cholLog, na.rm = TRUE),
sd = sd(cholLog, na.rm = TRUE),
n = n()
) %>%
mutate(se = sd / sqrt(n))
t.test(cholLog ~ Gender, samp3, var.equal = TRUE)
Two Sample t-test
data: cholLog by Gender
t = -2.4449, df = 18, p-value = 0.02501
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
-0.7049891 -0.0533427
sample estimates:
mean in group female mean in group male
0.2585913 0.6377572
Summary
Because we sampled other subjects in each sample, we obtain different cholesterol levels.
However, not only the cholesterol levels differ from sample to sample but also the summary statistics: means, standard deviations and standard errors.
Note, that in the last sample the log cholesterol levels are on average lower for females than for males; based on this sample we even would wrongly conclude that the cholesterol levels for females are on average larger than those of males.
This implies that our conclusions are also subjected to uncertainty and might change from sample to sample.
Samples as the one where the effect swaps and is statistically significant, however, are very rare.
This is illustrated with the code below, where we will draw 20000 repeated samples with sample size 10 for females and males from the NHanes study.
nsim <- 20000
nSamp <- 10
res <- matrix(0, nrow = nsim, ncol = 2)
fem <- nhanesSub %>% filter(Gender == "female")
mal <- nhanesSub %>% filter(Gender == "male")
for (i in 1:nsim)
{
femSamp <- sample(fem$cholLog, nSamp)
malSamp <- sample(mal$cholLog, nSamp)
meanFem <- mean(femSamp)
meanMal <- mean(malSamp)
delta <- meanFem - meanMal
sdFem <- sd(femSamp)
sdMal <- sd(malSamp)
seFem <- sdFem / sqrt(nSamp)
seFem <- sdFem / sqrt(nSamp)
sdPool <- sqrt((sdFem^2 * (nSamp - 1) + sdMal^2 * (nSamp - 1)) / (2 * nSamp - 2))
tvalue <- (delta) / (sdPool * sqrt(1 / nSamp + 1 / nSamp))
pvalue <- pt(abs(tvalue), lower.tail = FALSE, df = 2 * nSamp - 2) * 2
res[i, ] <- c(delta, pvalue)
}
sum(res[, 2] < 0.05 & res[, 1] > 0)
[1] 7785
[1] 12212
sum(res[, 2] < 0.05 & res[, 1] < 0)
[1] 3
res <- res %>% as.data.frame()
names(res) <- c("delta", "pvalue")
res %>%
ggplot(aes(x = delta, y = -log10(pvalue), color = pvalue < 0.05)) +
geom_point() +
xlab("Average cholesterol difference") +
ylab("- log10(pvalue)") +
scale_color_manual(values = c("black", "red"))
res %>%
ggplot(aes(y = delta)) +
geom_boxplot() +
geom_point(aes(x = 0, y = c(mean(fem$cholLog) - mean(mal$cholLog)), color = "pop. diff")) +
xlab("")
Only in 3 out of 20000 samples we conclude that the mean cholesterol level of males is significantly lower than for females. For the remaining samples the cholesterol levels for males were on average significantly lower than for females (7785 samples) or the average difference in cholesterol levels were not statistically significant (12212 samples). The latter is because the power is rather low to detect the difference with 10 samples in each group.
Assignment
- Copy the code chunk with the simulation study
- Add it here below
- Modify the sample size to 50.
- What do you observe?
Control of false positives
Wat happens when there is no difference between both groups?
We will have to simulate experiments for which the cholestorol levels are the same for both groups.
We can do this by sampling data for both groups from the subset of women in the study.
We do this again for 10 subjects per group
nsim <- 20000
nSamp <- 10
res <- matrix(0, nrow = nsim, ncol = 2)
fem <- nhanesSub %>% filter(Gender == "female")
mal <- nhanesSub %>% filter(Gender == "male")
for (i in 1:nsim)
{
femSamp <- sample(fem$cholLog, nSamp)
fem2Samp <- sample(fem$cholLog, nSamp)
meanFem <- mean(femSamp)
meanFem2 <- mean(fem2Samp)
delta <- meanFem - meanFem2
sdFem <- sd(femSamp)
sdFem2 <- sd(fem2Samp)
seFem <- sdFem / sqrt(nSamp)
seFem <- sdFem2 / sqrt(nSamp)
sdPool <- sqrt((sdFem^2 * (nSamp - 1) + sdFem2^2 * (nSamp - 1)) / (2 * nSamp - 2))
tvalue <- (delta) / (sdPool * sqrt(1 / nSamp + 1 / nSamp))
pvalue <- pt(abs(tvalue), lower.tail = FALSE, df = 2 * nSamp - 2) * 2
res[i, ] <- c(delta, pvalue)
}
sum(res[, 2] < 0.05 & res[, 1] > 0)
[1] 480
[1] 18960
sum(res[, 2] < 0.05 & res[, 1] < 0)
[1] 560
res <- res %>% as.data.frame()
names(res) <- c("delta", "pvalue")
res %>%
ggplot(aes(x = delta, y = -log10(pvalue), color = pvalue < 0.05)) +
geom_point() +
xlab("Average cholesterol difference") +
ylab("- log10(pvalue)") +
scale_color_manual(values = c("black", "red"))
res %>%
ggplot(aes(y = delta)) +
geom_boxplot() +
geom_point(aes(x = 0, y = 0, color = "pop. diff")) +
xlab("")
Note, that the number of false positives are on 1040 on 20000 experiments and are nicely controlled at the 5% level.
What happens if we increase the sample size to 50 subjects per group?
LS0tCnRpdGxlOiAiMS4gSW50cm9kdWN0aW9uOiBXaHkgZG8gd2UgbmVlZCBzdGF0aXN0aWNzIgphdXRob3I6ICJMaWV2ZW4gQ2xlbWVudCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY2FjaGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBUUlVFCikKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyBNb3RpdmF0aW9uCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+Cgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL1NDdzY1amphWFB3P3NpPW0yd19OcURnamdDOWtiZjkiIHRpdGxlPSJZb3VUdWJlIHZpZGVvIHBsYXllciIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlOyB3ZWItc2hhcmUiIHJlZmVycmVycG9saWN5PSJzdHJpY3Qtb3JpZ2luLXdoZW4tY3Jvc3Mtb3JpZ2luIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+Cgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL1BBSkwyMDc4TzIwP3NpPVpPMkJuRWhib1g2RjUzeDUiIHRpdGxlPSJZb3VUdWJlIHZpZGVvIHBsYXllciIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlOyB3ZWItc2hhcmUiIHJlZmVycmVycG9saWN5PSJzdHJpY3Qtb3JpZ2luLXdoZW4tY3Jvc3Mtb3JpZ2luIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CgohW10oLi9maWd1cmVzL3dwR3JhcGguanBlZykKCi0gV2UgbGl2ZSBpbiBhIGJpZyBkYXRhIGVyYQotIERhdGEgb24gbG9jYXRpb24sIGNsaWNrcywgZS1jb21tZXJjZSwgc29jaWFsIG1lZGlhIC4uLgotIExpZmUgU2NpZW5jZXM6IG1lYXN1cmUgZXhwcmVzc2lvbiBvZiB0aG91c2FuZHMgb2YgZ2VuZXMsIHByb3RlaW5zLCAuLi4gZm9yIGVhY2ggc3ViamVjdCBvciBldmVuIGluZGl2aWR1YWwgY2VsbHMKLSBEYXRhIGRyaXZlbiBqb3VybmFsaXNtCi0gLi4uCgpTdGF0aXN0aWNzIGlzIHRoZSBzY2llbmNlIHRvIGxlYXJuIGZyb20gZW1waXJpY2FsIGRhdGEuCgpTdGF0aXN0aWNhbCBsaXRlcmFjeSBpcyBrZXkgdG8gaW50ZXJwcmV0IHJlc3VsdHMgZnJvbSBzY2llbnRpZmljIHB1YmxpY2F0aW9ucy4KCiMgTGVhcm5pbmcgb2JqZWN0aXZlcyAKCjEuIEluIHRoaXMgaW50cm9kdWN0aW9uIHlvdSB3aWxsIGZhbWlsaWFyaXplIHlvdXJzZWxmIHdpdGggdGhyZWUgaW1wb3J0YW50IHRhc2tzIG9mIHN0YXRpc3RpY3MgCgogIC0gRXhwZXJpbWVudGFsIGRlc2lnbgogIC0gRGF0YSBFeHBsb3JhdGlvbgogIC0gRXN0aW1hdGlvbiBhbmQgc3RhdGlzdGljYWwgaW5mZXJlbmNlIAoKMi4gWW91IHVuZGVyc3RhbmQgaG93IHRoZSBkYXRhLCB0aGUgZXN0aW1hdGVkIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiBhbmQgY29uY2x1c2lvbnMgb2YgYSBzdGF0aXN0aWNhbCBkYXRhIGFuYWx5c2lzIGNhbiBjaGFuZ2UgZnJvbSBleHBlcmltZW50IHRvIGV4cGVyaW1lbnQgCgozLiBZb3UgaGF2ZSBub3RpY2Ugb24gaG93IAoKICAtIHN0YXRpc3RpY2FsIHRlc3RzIGNhbiBjb250cm9sIGZvciBmYWxzZSBwb3NpdGl2ZXMgCiAgLSB0aGUgcG93ZXIgdG8gcGljayB1cCBhbiBlZmZlY3QgZGVwZW5kcyBvbiB0aGUgc2FtcGxlIHNpemUgCgo0LiBZb3UgY2FuIGV4cGxhaW4gdGhlIGltcG9ydGFuY2Ugb2YgdXNpbmcgYSBnb29kIGNvbnRyb2wgCgo1LiBZb3UgY2FuIGV4cGxhaW4gd2hhdCBjb25mb3VuZGluZyBpcwoKIyBTbWVsbHkgYXJtcGl0IGV4YW1wbGUKCi0gU21lbGx5IGFybXBpdHMgYXJlIG5vdCBjYXVzZWQgYnkgc3dlYXQgaXRzZWxmLiBUaGUgc21lbGwgaXMgY2F1c2VkIGJ5IHNwZWNpZmljIG1pY3JvLW9yZ2FuaXNtcyBiZWxvbmdpbmcgdG8gdGhlIGdyb3VwIG9mICpDb3J5bmViYWN0ZXJpdW0gc3BwLiogdGhhdCBtZXRhYm9saXNlIHN3ZWF0LgpBbm90aGVyIGdyb3VwIG9mIGFidW5kYW50IGJhY3RlcmlhIGFyZSB0aGUgKlN0YXBoeWxvY29jY3VzIHNwcC4qLCB0aGVzZSBiYWN0ZXJpYSBkbyBub3QgbWV0YWJvbGlzZSBzd2VhdCBpbiBzbWVsbHkgY29tcG91bmRzLgoKLSBUaGUgQ01FVC1ncm9lcCBhdCBHaGVudCBVbml2ZXJzaXR5IGRvZXMgcmVzZWFyY2ggb24gdHJhbnNwbGFudGluZyB0aGUgYXJtcGl0IG1pY3JvYmlvbWUgdG8gc2F2ZSBwZW9wbGUgd2l0aCBzbWVsbHkgYXJtcGl0cy4KCi0gUHJvcG9zZWQgVGhlcmFweToKICAJMS4gUmVtb3ZlIGFybXBpdC1taWNyb2Jpb21lIHdpdGggYW50aWJpb3RpY3MKICAgIDIuIEluZmx1ZW5jZSBhcm1waXQgbWljcm9iaW9tZSB3aXRoIG1pY3JvYmlhbCAgdHJhbnNwbGFudCAoaHR0cHM6Ly95b3V0dS5iZS85UklGeXFMWGRWdykKCgpgYGB7ciBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiICVpbiUgbHMoKSkgcm0oInBpIikKa29wdm9ldGVyIDwtIGZ1bmN0aW9uKHgsIHksIGFuZ2xlID0gMCwgbCA9IC4yLCBjZXguZG90ID0gLjUsIHBjaCA9IDE5LCBjb2wgPSAiYmxhY2siKSB7CiAgYW5nbGUgPC0gYW5nbGUgLyAxODAgKiBwaQogIHBvaW50cyh4LCB5LCBjZXggPSBjZXguZG90LCBwY2ggPSBwY2gsIGNvbCA9IGNvbCkKICBsaW5lcyhjKHgsIHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSkpLCBjKHksIHkgKyBsICogc2luKC1waSAvIDIgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIGNvcyhhbmdsZSkpLCBjKHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogc2luKGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSArIGwgLyA0ICogY29zKHBpICsgYW5nbGUpKSwgYyh5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIHNpbihwaSArIGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgcGkgLyA0ICsgYW5nbGUpKSwgYyh5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIHBpIC8gNCArIGFuZ2xlKSksIGNvbCA9IGNvbCkKICBsaW5lcyhjKHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gMiAqIGNvcygtcGkgLyAyIC0gcGkgLyA0ICsgYW5nbGUpKSwgYyh5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpLCB5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBzaW4oLXBpIC8gMiAtIHBpIC8gNCArIGFuZ2xlKSksIGNvbCA9IGNvbCkKfQoKcGFyKG1hciA9IGMoMCwgMCwgMCwgMCksIG1haSA9IGMoMCwgMCwgMCwgMCkpCnBsb3QoMCwgMCwgeGxhYiA9ICIiLCB5bGFiID0gIiIsIHhsaW0gPSBjKDAsIDEwKSwgeWxpbSA9IGMoMCwgMTApLCBjb2wgPSAwLCB4YXh0ID0gIm5vbmUiLCB5YXh0ID0gIm5vbmUiLCBheGVzID0gRkFMU0UpCnJlY3QoMCwgNiwgMTAsIDEwLCBib3JkZXIgPSAicmVkIiwgbHdkID0gMikKdGV4dCguNSwgOCwgInBvcHVsYXRpb24iLCBzcnQgPSA5MCwgY29sID0gInJlZCIsIGNleCA9IDIpCnN5bWJvbHMoMywgOCwgY2lyY2xlcyA9IDEuNSwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUsIGZnID0gInJlZCIsIGluY2hlcyA9IEZBTFNFLCBsd2QgPSAyKQpzZXQuc2VlZCgzMzApCmdyaWQgPC0gc2VxKDAsIDEuMywgLjAxKQoKZm9yIChpIGluIDE6NTApCnsKICBhbmdsZTEgPC0gcnVuaWYobiA9IDEsIG1pbiA9IDAsIG1heCA9IDM2MCkKICBhbmdsZTIgPC0gcnVuaWYobiA9IDEsIG1pbiA9IDAsIG1heCA9IDM2MCkKICByYWRpdXMgPC0gc2FtcGxlKGdyaWQsIHByb2IgPSBncmlkXjIgKiBwaSAvIHN1bShncmlkXjIgKiBwaSksIHNpemUgPSAxKQogIGtvcHZvZXRlcigzICsgcmFkaXVzICogY29zKGFuZ2xlMSAvIDE4MCAqIHBpKSwgOCArIHJhZGl1cyAqIHNpbihhbmdsZTEgLyAxODAgKiBwaSksIGFuZ2xlID0gYW5nbGUyKQp9CnRleHQoNy41LCA4LCAiTWljcm9iaW9tZSBpbiBwb3B1bGF0aW9uIiwgY29sID0gInJlZCIsIGNleCA9IDEuMikKCnJlY3QoMCwgMCwgMTAsIDQsIGJvcmRlciA9ICJibHVlIiwgbHdkID0gMikKdGV4dCguNSwgMiwgInNhbXBsZSIsIHNydCA9IDkwLCBjb2wgPSAiYmx1ZSIsIGNleCA9IDIpCnN5bWJvbHMoMywgMiwgY2lyY2xlcyA9IDEuNSwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUsIGZnID0gImJsdWUiLCBpbmNoZXMgPSBGQUxTRSwgbHdkID0gMikKZm9yIChpIGluIDA6MSkgewogIGZvciAoaiBpbiAwOjQpCiAgewogICAga29wdm9ldGVyKDIuMSArIGogKiAoMy45IC0gMi4xKSAvIDQsIDEuMSArIGkgLyAyLCBjb2wgPSAicHVycGxlIikKICB9Cn0KZm9yIChpIGluIDI6MykgewogIGZvciAoaiBpbiAwOjQpCiAgewogICAga29wdm9ldGVyKDIuMSArIGogKiAoMy45IC0gMi4xKSAvIDQsIDEuNiArIGkgLyAyLCBjb2wgPSAib3JhbmdlIikKICB9Cn0KdGV4dCg3LjUsIDIsICJNaWNyb2Jpb21lIGluIHNhbXBsZSIsIGNvbCA9ICJibHVlIiwgY2V4ID0gMS4yKQoKYXJyb3dzKDMsIDUuOSwgMywgNC4xLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAzKQp0ZXh0KDEuNSwgNSwgIkVYUC4gREVTSUdOICgxKSIsIGNvbCA9ICJibGFjayIsIGNleCA9IDEuMikKdGV4dCg3LjUsIC41LCAiREFUQSBFWFBMT1JBVElPTiAmXG5ERVNDUklQVElWRSBTVEFUSVNUSUNTICgyKSIsIGNvbCA9ICJibGFjayIsIGNleCA9IDEuMikKYXJyb3dzKDcsIDQuMSwgNywgNS45LCBjb2wgPSAiYmxhY2siLCBsd2QgPSAzKQp0ZXh0KDguNSwgNSwgIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsIGNvbCA9ICJibGFjayIsIGNleCA9IDEuMikKYGBgCgoKLSBFeHBlcmltZW50OgoKICAgIC0gMjAgc3ViamVjdHMgd2l0aCBzbWVsbHkgYXJtcGl0cyBhcmUgYXR0cmlidXRlZCB0byBvbmUgb2YgdHdvIHRyZWF0bWVudCBncm91cHMKICAgIC0gcGxhY2VibyAob25seSBhbnRpYmlvdGljcykKICAgIC0gdHJhbnNwbGFudCAoYW50aWJpb3RpY3MgZm9sbG93ZWQgYnkgbWljcm9iaWFsIHRyYW5zcGxhbnQpLgogICAgLSBUaGUgbWljcm9iaW9tZSBpcyBzYW1wbGVkIDYgd2Vla3MgdXBvbiB0aGUgdHJlYXRtZW50LgogICAgLSBUaGUgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mICpTdGFwaHlsb2NvY2N1cyBzcHAuKiBvbiAqQ29yeW5lYmFjdGVyaXVtIHNwcC4qICsgKlN0YXBoeWxvY29jY3VzIHNwcC4qIGluIHRoZSBtaWNyb2Jpb21lIGlzIG1lYXN1cmVkIHZpYSBER0dFICgqRGVuYXR1cmluZyBHcmFkaWVudCBHZWwgRWxlY3Ryb3Bob3Jlc2lzKikuCgotLS0KCiMjIEltcG9ydCB0aGUgZGF0YQpgYGB7cn0KcmVhZF9saW5lcygiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQpgYGAKClRoZSBmaWxlIGlzIGNvbW1hIHNlcGFyYXRlZCBhbmQgaW4gdGlkeSBmb3JtYXQKCmBgYHtyfQphcCA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQphcApgYGAKCi0tLQoKIyMgRGF0YSBFeHBsb3JhdGlvbiBhbmQgRGVzY3JpcHRpdmUgU3RhdGlzdGljcwoKLSBEYXRhIGV4cGxvcmF0aW9uIGlzIGV4dHJlbWVseSBpbXBvcnRhbnQgdG8gZ2V0IGluc2lnaHQgaW4gdGhlIGRhdGEuCi0gSXQgaXMgb2Z0ZW4gdW5kZXJyYXRlZCBhbmQgb3Zlcmxvb2tlZC4KCiMjIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzCgpXZSBmaXJzdCBzdW1tYXJpemUgdGhlIGRhdGEgYW5kIGNhbGN1bGF0ZSB0aGUgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uLCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGFuZCBzdGFuZGFyZCBlcnJvciBhbmQgc3RvcmUgdGhlIHJlc3VsdCBpbiBhbiBvYmplY3QgYXBSZWxTdW0gdmlhIGBhcFJlbFN1bTwtYAoKMS4gV2UgcGlwZSB0aGUgYGFwYCBkYXRhZnJhbWUgdG8gdGhlIGdyb3VwX2J5IGZ1bmN0aW9uIHRvIGdyb3VwIHRoZSBkYXRhIGJ5IHRyZWF0bWVudCB0cnQgYGdyb3VwX2J5KHRydClgCjIuIFdlIHBpcGUgdGhlIHJlc3VsdCB0byB0aGUgYHN1bW1hcml6ZWAgZnVuY3Rpb24gdG8gc3VtbWFyaXplIHRoZSAicmVsIiB2YXJpYWJsZSBhbmQgY2FsY3VsYXRlIHRoZSBtZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24gYW5kIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zCjMuIFdlIHBpcGUgdGhlIHJlc3VsdCB0byB0aGUgYG11dGF0ZWAgZnVuY3Rpb24gdG8gbWFrZSBhIG5ldyB2YXJpYWJsZSBpbiB0aGUgZGF0YSBmcmFtZSBgc2VgIGZvciB3aGljaCB3ZSBjYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGVycm9yCgoKYGBge3J9CmFwUmVsU3VtIDwtIGFwICU+JQogIGdyb3VwX2J5KHRydCkgJT4lCiAgc3VtbWFyaXplKAogICAgbWVhbiA9IG1lYW4ocmVsLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgPSBzZChyZWwsIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpCiAgKSAlPiUKICBtdXRhdGUoc2UgPSBzZCAvIHNxcnQobikpCgphcFJlbFN1bQpgYGAKCi0tLQoKIyMjIFBsb3RzCgpXZSB3aWxsIHVzZSBnZ3Bsb3QyIHRvIG1ha2Ugb3VyIHBsb3RzLgpXaXRoIHRoZSBnZ3Bsb3QyIGxpYnJhcnkgd2UgY2FuIGVhc2lseSBidWlsZCBwbG90cyBieSBhZGRpbmcgbGF5ZXJzLgoKIyMjIyBiYXJwbG90CgoxLiBXZSBwaXBlIG91ciBzdW1tYXJpemVkIGRhdGEgdG8gdGhlIGBnZ3Bsb3RgIGZ1bmN0aW9uIGFuZCB3ZSBzZWxlY3QgdGhlIHRyZWF0bWVudCB2YXJpYWJsZSB0cnQgYW5kIHRoZSB2YXJpYWJsZSBtZWFuIGZvciBwbG90dGluZyBgYWVzKHg9dHJ0LHk9bWVhbilgCgoyLiBXZSBtYWtlIGEgYmFycGxvdCBiYXNlZCBvbiB0aGlzIGRhdGEgdXNpbmcgdGhlIGBnZW9tX2JhcmAgZnVuY3Rpb24uIFRoZSBzdGF0aXN0aWMgaXMgYHN0YXQ9ImlkZW50aXR5ImAgYmVjYXVzZSB0aGUgYmFyIGhlaWdodCBzaG91bGQgYmUgZXF1YWwgdGhlIHZhbHVlIGZvciB0aGUgbWVhbiBvZiB0aGUgcmVsYXRpdmUgYWJ1bmRhbmNlLgoKYGBge3J9CmFwUmVsU3VtICU+JQogIGdncGxvdChhZXMoeCA9IHRydCwgeSA9IG1lYW4pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpCmBgYAoKLSBJcyB0aGlzIHBsb3QgaW5mb3JtYXRpdmU/PwoKLS0tCgpXZSB3aWxsIG5vdyBhZGQgc3RhbmRhcmQgZXJyb3JzIHRvIHRoZSBwbG90CnVzaW5nIGBnZW9tX2Vycm9yYmFyYCBmdW5jdGlvbiBhbmQgc3BlY2lmeSB0aGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZSBmb3Igb2YgdGhlIGVycm9yIGJhciwgdGhlIHdpZHRoIGNvbW1hbmQgaXMgdXNlZCB0byBzZXQgdGhlIHdpZHRoIG9mIHRoZSBlcnJvciBiYXIgc21hbGxlciB0aGFuIHRoZSB3aWR0aCBvZiB0aGUgYmFyLgoKYGBge3J9CmFwUmVsU3VtICU+JQogIGdncGxvdChhZXMoeCA9IHRydCwgeSA9IG1lYW4pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbiAtIHNlLCB5bWF4ID0gbWVhbiArIHNlKSwgd2lkdGggPSAuMikKYGBgCgotIElzIHRoaXMgcGxvdCBpbmZvcm1hdGl2ZT8/CgotLS0KCiMjIyMgYm94cGxvdHMKCkkgY29uc2lkZXIgYmFycGxvdHMgdG8gYmUgYmFkIHBsb3RzCgotIFRoZXkgYXJlIG5vdCBpbmZvcm1hdGl2ZQotIFRoZXkganVzdCB2aXN1YWxpemUgYSB0d28gcG9pbnQgc3VtbWFyeSBvZiB0aGUgZGF0YS4gSXQgaXMgYmV0dGVyIHRvIGRvIHRoaXMgaW4gYSB0YWJsZQotIFRoZXkgdXNlIGEgbG90IG9mIHNwYWNlIChlLmcuIGZyb20gemVybyB1cCB0byB0aGUgbWluaW11bSByZWxhdGl2ZSBhYnVuZGFuY2UpIHdoZXJlIG5vIGRhdGEgYXJlIHByZXNlbnQuCgpJdCBpcyBiZXR0ZXIgdG8gZ2V0IGEgdmlldyBvbiB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhLiBXZSBjYW4gdXNlIGEgYm94cGxvdCBmb3IgdGhpcyBwdXJwb3NlLgpXZSBmaXJzdCBleHBsYWluIHdoYXQgYSBib3hwbG90LgoKLS0tCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KZmVtIDwtIE5IQU5FUzo6TkhBTkVTICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIgJiAhaXMubmEoRGlyZWN0Q2hvbCkpICU+JQogIHNlbGVjdChEaXJlY3RDaG9sKQpib3hwbG90KGZlbSREaXJlY3RDaG9sLCB5bGFiID0gIkRpcmVjdCBjaG9sZXN0ZXJvbCIsIGNleC5sYWIgPSAxLjUsIGNleC5heGlzID0gMS41LCBjZXgubWFpbiA9IDEuNSkKcmFuZ2VDbCA8LSBxdWFudGlsZShmZW0kRGlyZWN0Q2hvbCwgYyguMjUsIC43NSkpICsgYygtMSwgMSkgKiBkaWZmKHF1YW50aWxlKGZlbSREaXJlY3RDaG9sLCBjKC4yNSwgLjc1KSkpICogMS41CmJveFlzIDwtIGMocmFuZ2UoZmVtJERpcmVjdENob2xbZmVtJERpcmVjdENob2wgPD0gcmFuZ2VDbFsyXSAmIGZlbSREaXJlY3RDaG9sID49IHJhbmdlQ2xbMV1dKSwgcXVhbnRpbGUoZmVtJERpcmVjdENob2wsIGMoLjI1LCAuNSwgLjc1KSksIHJhbmdlQ2xbMl0gKyAobWF4KGZlbSREaXJlY3RDaG9sKSAtIHJhbmdlQ2xbMl0pIC8gMikKdGV4dCgxLjMsIGJveFlzLCBsYWJlbHMgPSBjKCJ3aXNrZXIiLCAid2lza2VyIiwgIngyNSIsICJtZWRpYW4iLCAieDc1IiwgIm91dGxpZXJzIiksIHBvcyA9IDQsIGNleCA9IDEuMykKbGluZXMoYygxLjEsIDEuMywgMS4zLCAxLjEpLCBjKHJhbmdlQ2xbMl0sIHJhbmdlQ2xbMl0gKyAobWF4KGZlbSREaXJlY3RDaG9sKSAtIHJhbmdlQ2xbMl0pIC8gMiwgcmFuZ2VDbFsyXSArIChtYXgoZmVtJERpcmVjdENob2wpIC0gcmFuZ2VDbFsyXSkgLyAyLCBtYXgoZmVtJERpcmVjdENob2wpKSwgbHR5ID0gMikKYGBgCgotLS0KCldlIHdpbGwgbm93IG1ha2UgYSBib3hwbG90IGZvciB0aGUgYXAgZGF0YQoKMS4gV2UgcGlwZSB0aGUgYGFwYCBkYXRhZnJhbWUgdG8gdGhlIGdncGxvdCBjb21tYW5kCjIuIFdlIHNlbGVjdCB0aGUgZGF0YSB3aXRoIHRoZSBjb21tYW5kIGBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSlgCjMuIFdlIGFkZCBhIGJveHBsb3Qgd2l0aCB0aGUgY29tbWFuZCBgZ2VvbV9ib3hwbG90KClgCgpgYGB7cn0KYXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdHJ0LCB5ID0gcmVsKSkgKwogIGdlb21fYm94cGxvdCgpCmBgYAoKLS0tCgotIE5vdGUsIHRoYXQgd2UgZG8gbm90IGhhdmUgc28gbWFueSBvYnNlcnZhdGlvbnMuCgotIEl0IGlzIGFsd2F5cyBiZXR0ZXIgdG8gc2hvdyB0aGUgZGF0YSBhcyByYXcgYXMgcG9zc2libGUhCgpXZSB3aWxsIG5vdyBhZGQgdGhlIHJhdyBkYXRhIHRvIHRoZSBwbG90LgoKLSBOb3RlIHRoYXQgd2Ugc2V0IHRoZSBvdXRsaWVyLnNoYXBlPU5BIGluIHRoZSBnZW9tX2JveHBsb3QgZnVuY3Rpb24gYmVjYXVzZSBiZWNhdXNlIHdlIHdpbGwgYWRkIGFsbCByYXcgZGF0YSBhbnl3YXkuCi0gV2UgYWRkIHRoZSByYXcgZGF0YSB1c2luZyBgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIilgLCB3aXRoIHRoZSBhcmd1bWVudCBwb3NpdGlvbj0naml0dGVyJyB3ZSB3aWxsIGFkZCBzb21lIHJhbmRvbSBub2lzZSB0byB0aGUgeCBjb29yZGluYXRlIHNvIHRoYXQgd2UgY2FuIHNlZSBhbGwgZGF0YS4KCmBgYHtyfQphcCAlPiUKICBnZ3Bsb3QoYWVzKHggPSB0cnQsIHkgPSByZWwpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikKYGBgCgpUaGlzIGlzIGFuIGluZm9ybWF0aXZlIHBsb3QhCgotLS0KCi0gV2Ugb2JzZXJ2ZWQgYW4gZWZmZWN0IG9mIHRoZSB0cmFuc3BsYW50YXRpb24gb24gdGhlIHJlbGF0aWV2ZSBhYnVuZGFudGllIG9mIFN0YXBoeWxvY29jY3VzLgoKLSBJcyB0aGF0IGVmZmVjdCBsYXJnZSBlbm91Z2ggdG8gY29uY2x1ZGUgdGhhdCB0aGUgdHJlYXRtZW50IHdvcmtzPwoKLS0tCgojIyBFc3RpbWF0aW9uIGFuZCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UKCi0gSW5kdWN0aW9uOiBXaXRoIHN0YXRpc3RpY2FsIGluZmVyZW5jZSB3ZSBjYW4gZ2VuZXJhbGl6ZSB3aGF0IHdlIG9ic2VydmUgaW4gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uLgoKLSBUaGUgcHJpY2UgdGhhdCB3ZSBoYXZlIHRvIHBheTogdW5jZXJ0YWludHkgb24gb3VyIGNvbmNsdXNpb25zIQoKLS0tCgotIFdpdGggZGF0YSB3ZSBjYW5ub3QgcHJvdmUgdGhhdCB0aGUgdHJlYXRtZW50IHdvcmtzCgotIEZhbHNpZmljYXRpb24gcHJpbmNpcGxlIG9mIFBvcHBlcjogV2l0aCBkYXRhIHdlIGNhbiBvbmx5ICByZWplY3QgYSBoeXBvdGhlc2lzIG9yIHRoZW9yeS4KCi0gV2l0aCBzdGF0cyB3ZSBjYW4gdGh1cyBub3QgcHJvdmUgdGhhdCB0aGUgdHJlYXRtZW50IHdvcmtzLgoKLSBCdXQgc3RhdHMgd2lsbCBhbGxvdyB1cyB0byBmYWxjaWZ5IHRoZSBvcHBvc2l0ZSBoeXBvdGhlc2lzOiBob3cgbXVjaCBldmlkZW5jZSBpcyB0aGVyZSBpbiB0aGUgZGF0YSBhZ2FpbnN0IHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlcmUgaXMgbm8gZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQ/CgotIFdpdGggc3RhdHMgd2UgY2FuIGNhbGN1bGF0ZSBob3cgbGlrZWx5IGl0IGlzIHRvIGRyYXcgYSByYW5kb20gc2FtcGxlICh3aGVuIHlvdSB3b3VsZCByZXBlYXQgdGhlIGV4cGVyaW1lbnQpIHdpdGggYSBtZWFuIGRpZmZlcmVuY2UgaW4gcmVsYXRpdmUgYWJ1bmRhbmNlIGJldHdlZW4gdHJhbnNwbGFudCBhbmQgcGxhY2VibyBncm91cCB0aGF0IGlzIGF0IGxlYXN0IGFzIGxhcmdlIGFzIHdoYXQgd2Ugb2JzZXJ2ZWQgaW4gb3VyIHNhbXBsZSB3aGVuIHRoZXJlIHdvdWxkIGJlIG5vIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50LgoKLSBUaGlzIHByb2JhYmlsaXR5IGlzIGNhbGxlZCBhIHAtdmFsdWUuCgotIElmIHAgaXMgdmVyeSBzbWFsbCwgaXQgaXMgdmVyeSB1bmxpa2VseSB0byBvYnNlcnZlIGEgc2FtcGxlIGxpa2Ugb3VycyBieSByYW5kb20gY2hhbmdlIHdoZW4gdGhlcmUgd291bGQgYmUgbm8gZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQuCgotIFdlIHR5cGljYWxseSBjb21wYXJlIHAgd2l0aCA1JS4gSWYgdGhlcmUgaXMgbm8gZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQgd2Ugd2lsbCB0aHVzIHRvbGVyYXRlIGEgcHJvYmFiaWxpdHkgb2YgNSUgb24gYSBmYWxzZSBwb3NpdGl2ZSBjb25jbHVzaW9uLgoKLSBUbyBjYWxjdWxhdGUgcCB3ZSB3aWxsIGhhdmUgdG8gbW9kZWwgdGhlIGRhdGEgdXNpbmcgIHN0YXRpc3RpY2FsIG1vZGVscy4KCi0tLQoKSW4gY2hhcHRlciA1IHdlIHdpbGwgbGVhcm4gdGhhdCB3ZSBjYW4gdXNlIGEgdHdvLXNhbXBsZSB0LXRlc3QgdG8gZ2VuZXJhbGlzZSB3aGF0IHdlIG9ic2VydmUgaW4gdGhlIG1pY3JvYmlvbWUgZGF0YXNldCB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uLgoKYGBge3J9CnQudGVzdChyZWwgfiB0cnQsIGRhdGEgPSBhcCkKYGBgCgpDb25jbHVzaW9uOgoKV2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBTdGFwaHlsb2NvY2N1cyBpbiB0aGUgbWljcm9iaW9tZSBvZiBpbmRpdmlkdWFscyB3aXRoIHNtZWxseSBhcm1waXRzICBpcyBgciBmb3JtYXQoYXBSZWxTdW0kbWVhblsyXS1hcFJlbFN1bSRtZWFuWzFdLGRpZ2l0cz0zKWAlIGhpZ2hlciB1cG9uIHRoZSB0cmFuc3BsYW50IHRoYW4gdXBvbiB0aGUgcGxhY2VibyB0cmVhdG1lbnQgKHAgPCAwLjAwMSkuCgotLS0KCiMjIFNvbWUgY29uY2VwdHMKCldoYXQgYXJlIHRoZSBjb25zZXF1ZW5jZXMgb2YgdXNpbmcgYSBzYW1wbGUgYW5kIHJhbmRvbWlzYXRpb24/CgotIFJhbmRvbSBzYW1wbGluZyBpcyBjbG9zZWx5IHJlbGF0ZWQgdG8gdGhlIGNvbmNlcHQgb2YgdGhlIHBvcHVsYXRpb24gb3IgdGhlIHNjb3BlIG9mIHRoZSBzdHVkeS4KCi0gQmFzZWQgb24gYSBzYW1wbGUgb2Ygc3ViamVjdHMsIHRoZSByZXNlYXJjaGVycyB3YW50IHRvIGNvbWUgdG8gY29uY2x1c2lvbnMgdGhhdCBob2xkIGZvcgoKICAgIC0gYWxsIGtpbmRzIG9mIHBlb3BsZQogICAgLSBvbmx5IG1hbGUgc3R1ZGVudHMKCi0gU2NvcGUgb2YgdGhlIHN0dWR5IHNob3VsZCBiZSB3ZWxsIHNwZWNpZmllZCBiZWZvcmUgdGhlIHN0YXJ0IG9mIHRoZSBzdHVkeS4KCi0gRm9yIHRoZSBzdGF0aXN0aWNhbCBhbmFseXNpcyB0byBiZSB2YWxpZCwgaXQgaXMgcmVxdWlyZWQgdGhhdCB0aGUgc3ViamVjdHMgYXJlIHNlbGVjdGVkIGNvbXBsZXRlbHkgYXQgcmFuZG9tIGZyb20gdGhlIHBvcHVsYXRpb24gdG8gd2hpY2ggd2Ugd2FudCB0byBnZW5lcmFsaXplIG91ciBjb25jbHVzaW9ucy4KCi0gU2VsZWN0aW5nIGNvbXBsZXRlbHkgYXQgcmFuZG9tIGZyb20gYSBwb3B1bGF0aW9uIGltcGxpZXM6CiAgICAtIGFsbCBzdWJqZWN0cyBpbiB0aGUgcG9wdWxhdGlvbiBzaG91bGQgaGF2ZSB0aGUgc2FtZSBwcm9iYWJpbGl0eSBvZiBiZWluZyBzZWxlY3RlZCBpbiB0aGUgc2FtcGxlLAogICAgLSB0aGUgc2VsZWN0aW9uIG9mIGEgc3ViamVjdCBpbiB0aGUgc2FtcGxlIHNob3VsZCBiZSBpbmRlcGVuZGVudCBmcm9tIHRoZSBzZWxlY3Rpb24gb2YgdGhlIG90aGVyIHN1YmplY3RzIGluIHRoZSBzYW1wbGUuCgotIFRoZSBzYW1wbGUgaXMgdGh1cyBzdXBwb3NlZCB0byBiZSByZXByZXNlbnRhdGl2ZSBmb3IgdGhlIHBvcHVsYXRpb24sIGJ1dCBzdGlsbCBpdCBpcyByYW5kb20uCgotIFdoYXQgZG9lcyB0aGlzIGltcGx5PwoKLS0tCgojIFNhbXBsZSB0byBzYW1wbGUgdmFyaWFiaWxpdHkKCk5hdGlvbmFsIEhlYWx0aCBOSGFuZXMgc3R1ZHkKCiAgLSBTaW5jZSAxOTYwIGluZGl2aWR1YWxzIG9mIGFsbCBhZ2VzIGFyZSBpbnRlcnZpZXdlZCBpbiB0aGVpciBob21lcyBldmVyeSB5ZWFyCiAgLSBUaGUgaGVhbHRoIGV4YW1pbmF0aW9uIGNvbXBvbmVudCBvZiB0aGUgc3VydmV5IGlzIGNvbmR1Y3RlZCBpbiBhIG1vYmlsZSBleGFtaW5hdGlvbiBjZW50cmUgKE1FQykuCiAgLSBXZSB3aWxsIHVzZSB0aGlzIGxhcmdlIHN0dWR5IHRvIHNlbGVjdCByYW5kb20gc3ViamVjdHMgZnJvbSB0aGUgQW1lcmljYW4gcG9wdWxhdGlvbi4KICAtIFRoaXMgd2lsbCBoZWxwIHVzIHRvIHVuZGVyc3RhbmQgaG93IHRoZSByZXN1bHRzIG9mIGFuIGFuYWx5c2lzIGFuZCB0aGUgY29uY2x1c2lvbnMgdmFyeSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuCgotLS0KCmBgYHtyfQpsaWJyYXJ5KE5IQU5FUykKaGVhZChOSEFORVMpCmdsaW1wc2UoTkhBTkVTKQpgYGAKCi0tLQoKIyMgRGF0YSBleHBsb3JhdGlvbgoKClN1cHBvc2UgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBhc3Nlc3NpbmcgdGhlIGRpZmZlcmVuY2UgaW4gZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscyBiZXR3ZWVuIG1hbGVzIGFuZCBmZW1hbGVzIG9sZGVyIHRoYW4gMjUgeWVhcnMuCgoxLiBXZSBwaXBlIHRoZSBkYXRhc2V0IHRvIHRoZSBmdW5jdGlvbiBgZmlsdGVyYCB0byBmaWx0ZXIgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIGFnZS4KMi4gV2UgcGxvdCB0aGUgZGlyZWN0IGNob2xlc3Rlcm9sIGxldmVscy4KICAgIC0gV2Ugc2VsZWN0IHRoZSBkYXRhIHdpdGggdGhlIGNvbW1hbmQgYGdncGxvdChhZXMoeD1EaXJlY3RDaG9sKSlgCiAgICAtIFdlIGFkZCBhIGhpc3RvZ3JhbSB3aXRoIHRoZSBjb21tYW5kIGBnZW9tX2hpc3RvZ3JhbSgpYAogICAgLSBXZSBtYWtlIHRvIHZlcnRpY2FsIHBhbmVscyB1c2luZyB0aGUgY29tbWFuZCBgZmFjZXRfZ3JpZChHZW5kZXJ+LilgCiAgICAtIFdlIGN1c3RvbWl6ZSB0aGUgbGFiZWwgb2YgdGhlIHgtYXhpcyB3aXRoIHRoZSBgeGxhYmAgY29tbWFuZC4KCmBgYHtyfQpOSEFORVMgJT4lCiAgZmlsdGVyKEFnZSA+IDI1KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBEaXJlY3RDaG9sKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X2dyaWQoR2VuZGVyIH4gLikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobWcvZGwpIikKYGBgCgotLS0KCi0gQ2hvbGVzdGVyb2wgbGV2ZWxzIGFuZCBjb25jZW50cmF0aW9uIG1lYXN1cmVtZW50cyBhcmUgb2Z0ZW4gc2tld2VkLgotIENvbmNlbnRyYXRpb25zIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuCi0gVGhleSBhcmUgb2Z0ZW4gbG9nIHRyYW5zZm9ybWVkLgoKYGBge3J9Ck5IQU5FUyAlPiUKICBmaWx0ZXIoQWdlID4gMjUpICU+JQogIGdncGxvdChhZXMoeCA9IERpcmVjdENob2wgJT4lIGxvZzIoKSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF9ncmlkKEdlbmRlciB+IC4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZzIpIikKYGBgCgpXZSBzZWUgdGhhdCB0aGUgZGF0YSBhcmUgbW9yZSBvciBsZXNzIGJlbGwgc2hhcGVkIHVwb24gbG9nIHRyYW5zZm9ybWF0aW9uLgoKLS0tCgpXZSB3aWxsIG5vdyBjcmVhdGUgYSBzdWJzZXQgb2YgdGhlIGRhdGEgdGhhdCB3ZSB3aWxsIHVzZSB0byBzYW1wbGUgZnJvbSBpbiB0aGUgbmV4dCBzZWN0aW9ucy4KCiAgMS4gV2UgZmlsdGVyIG9uIGFnZSBhbmQgcmVtb3ZlIHN1YmplY3RzIHdpdGggbWlzc2luZyB2YWx1ZXMgKE5BKS4KICAyLiBXZSBvbmx5IHNlbGVjdCB0aGUgdmFyaWFibGVzIEdlbmRlciBhbmQgRGlyZWN0Q2hvbCBmcm9tIHRoZSBkYXRhc2V0IHRvIGF2b2lkIHVubmVjZXNzYXJ5IHZhcmlhYmxlcy4KICAzLiBXaXRoIHRoZSBtdXRhdGUgZnVuY3Rpb24gd2UgY2FuIGFkZCBhIG5ldyB2YXJpYWJsZSBsb2dDaG9sIHdpdGggbG9nIHRyYW5zZm9ybWVkIGRpcmVjdCBjaG9sZXN0ZXJvbCBsZXZlbHMuCgpgYGB7cn0KbmhhbmVzU3ViIDwtIE5IQU5FUyAlPiUKICBmaWx0ZXIoQWdlID4gMjUgJiAhaXMubmEoRGlyZWN0Q2hvbCkpICU+JQogIHNlbGVjdChjKCJHZW5kZXIiLCAiRGlyZWN0Q2hvbCIpKSAlPiUKICBtdXRhdGUoY2hvbExvZyA9IGxvZzIoRGlyZWN0Q2hvbCkpCmBgYAoKLS0tCgpXZSB3aWxsIGNhbGN1bGF0ZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgY2hvbExvZyB2YXJpYWJsZSBmb3IgbWFsZXMgYW5kIGZlbWFsZXMgaW4gdGhlIGxhcmdlIGRhdGFzZXQuClNvIHdlIGdyb3VwIGJ5IEdlbmRlcgoKYGBge3J9CmNob2xMb2dTdW0gPC0gbmhhbmVzU3ViICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplKAogICAgbWVhbiA9IG1lYW4oY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIHNkID0gc2QoY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkKICApICU+JQogIG11dGF0ZShzZSA9IHNkIC8gc3FydChuKSkKCmNob2xMb2dTdW0KYGBgCgotLS0KCiMjIEV4cGVyaW1lbnQKCi0gU3VwcG9zZSB0aGF0IHdlIGhhdmUgbm8gYWNjZXNzIHRvIGNob2xlc3Rlcm9sIGxldmVscyBvZiB0aGUgQW1lcmljYW4gcG9wdWxhdGlvbiwKLSB3ZSB3aWxsIGhhdmUgdG8gc2V0dXAgYW4gZXhwZXJpbWVudC4KLSBTdXBwb3NlIHdlIGhhdmUgYSBidWRnZXQgZm9yIGFzc2Vzc2luZyAxMCBmZW1hbGVzIGFuZCAxMCBtYWxlcywKLSB3ZSB3aWxsIHN1YnNldCAxMCBmZW1hbGVzIGFuZCAxMCBtYWxlcyBhdCByYW5kb20gZnJvbSB0aGUgQW1lcmljYW4gcG9wdWxhdGlvbiBhbmQgbWVhc3VyZSB0aGVpciBkaXJlY3QgY2hvbGVzdGVyb2wgbGV2ZWxzLgoKYGBge3J9CmZlbSA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplID0gMTApCgpzYW1wIDwtIHJiaW5kKGZlbSwgbWFsKQpzYW1wCmBgYAoKLS0tCgpXZSB3aWxsIG5vdyBwbG90IHRoZSBkYXRhIHdpdGggYSBoaXN0b2dyYW0gYW5kIGJveHBsb3RzCgpgYGB7cn0Kc2FtcCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjaG9sTG9nKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjEpICsKICBmYWNldF9ncmlkKEdlbmRlciB+IC4pICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZzIpIikKCnNhbXAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gR2VuZGVyLCB5ID0gY2hvbExvZykpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKQpgYGAKCi0tLQoKV2Ugc3VtbWFyaXplIHRoZSBkYXRhCmBgYHtyfQpzYW1wICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplKAogICAgbWVhbiA9IG1lYW4oY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIHNkID0gc2QoY2hvbExvZywgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkKICApICU+JQogIG11dGF0ZShzZSA9IHNkIC8gc3FydChuKSkKYGBgCgpOb3RlIHRoYXQgdGhlIHNhbXBsZSBtZWFuIGlzIGRpZmZlcmVudCBmcm9tIHRoYXQgb2YgdGhlIGxhcmdlIGV4cGVyaW1lbnQgKCJwb3B1bGF0aW9uIikgd2Ugc2FtcGxlZCBmcm9tLgoKV2UgdGVzdCBmb3IgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBNYWxlcyBhbmQgZmVtYWxlcwoKYGBge3J9CnQudGVzdChjaG9sTG9nIH4gR2VuZGVyLCBzYW1wLCB2YXIuZXF1YWwgPSBUUlVFKQpgYGAKCi0tLQoKIyMgUmVwZWF0IHRoZSBleHBlcmltZW50CgpJZiB3ZSBkbyB0aGUgZXhwZXJpbWVudCBhZ2FpbiB3ZSBzZWxlY3Qgb3RoZXIgcGVvcGxlIGFuZCB3ZSBvYnRhaW4gZGlmZmVyZW50IHJlc3VsdHMuCgoKYGBge3J9CmZlbSA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZSA9IDEwKQptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplID0gMTApCgpzYW1wMiA8LSByYmluZChmZW0sIG1hbCkKc2FtcDIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRGlyZWN0Q2hvbCAlPiUgbG9nKCkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAuMSkgKwogIGZhY2V0X2dyaWQoR2VuZGVyIH4gLikgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nKSIpCgpzYW1wMiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBHZW5kZXIsIHkgPSBjaG9sTG9nKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpCgpzYW1wMiAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHN1bW1hcml6ZSgKICAgIG1lYW4gPSBtZWFuKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBzZCA9IHNkKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpCiAgKSAlPiUKICBtdXRhdGUoc2UgPSBzZCAvIHNxcnQobikpCgp0LnRlc3QoY2hvbExvZyB+IEdlbmRlciwgc2FtcDIsIHZhci5lcXVhbCA9IFRSVUUpCmBgYAoKLS0tCgojIyBBbmQgYWdhaW4KCmBgYHtyfQpzZXQuc2VlZCgxMjg1NykKZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplID0gMTApCm1hbCA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAibWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemUgPSAxMCkKCnNhbXAzIDwtIHJiaW5kKGZlbSwgbWFsKQpzYW1wMyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBEaXJlY3RDaG9sICU+JSBsb2coKSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC4xKSArCiAgZmFjZXRfZ3JpZChHZW5kZXIgfiAuKSArCiAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIChsb2cpIikKCnNhbXAzICU+JQogIGdncGxvdChhZXMoeCA9IEdlbmRlciwgeSA9IGNob2xMb2cpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikKCgpzYW1wMyAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHN1bW1hcml6ZSgKICAgIG1lYW4gPSBtZWFuKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBzZCA9IHNkKGNob2xMb2csIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpCiAgKSAlPiUKICBtdXRhdGUoc2UgPSBzZCAvIHNxcnQobikpCgp0LnRlc3QoY2hvbExvZyB+IEdlbmRlciwgc2FtcDMsIHZhci5lcXVhbCA9IFRSVUUpCmBgYAoKLS0tCgojIyBTdW1tYXJ5CgotIEJlY2F1c2Ugd2Ugc2FtcGxlZCBvdGhlciBzdWJqZWN0cyBpbiBlYWNoIHNhbXBsZSwgd2Ugb2J0YWluIGRpZmZlcmVudCBjaG9sZXN0ZXJvbCBsZXZlbHMuCi0gSG93ZXZlciwgbm90IG9ubHkgdGhlIGNob2xlc3Rlcm9sIGxldmVscyBkaWZmZXIgZnJvbSBzYW1wbGUgdG8gc2FtcGxlIGJ1dCBhbHNvIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3M6IG1lYW5zLCBzdGFuZGFyZCBkZXZpYXRpb25zIGFuZCBzdGFuZGFyZCBlcnJvcnMuCi0gTm90ZSwgdGhhdCBpbiB0aGUgbGFzdCBzYW1wbGUgdGhlIGxvZyBjaG9sZXN0ZXJvbCBsZXZlbHMgYXJlIG9uIGF2ZXJhZ2UgbG93ZXIgZm9yIGZlbWFsZXMgdGhhbiBmb3IgbWFsZXM7IGJhc2VkIG9uIHRoaXMgc2FtcGxlIHdlIGV2ZW4gd291bGQgd3JvbmdseSBjb25jbHVkZSB0aGF0IHRoZSBjaG9sZXN0ZXJvbCBsZXZlbHMgZm9yIGZlbWFsZXMgYXJlIG9uIGF2ZXJhZ2UgbGFyZ2VyIHRoYW4gdGhvc2Ugb2YgbWFsZXMuCgotIFRoaXMgaW1wbGllcyB0aGF0IG91ciBjb25jbHVzaW9ucyBhcmUgYWxzbyBzdWJqZWN0ZWQgdG8gdW5jZXJ0YWludHkgYW5kIG1pZ2h0IGNoYW5nZSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuCgotIFNhbXBsZXMgYXMgdGhlIG9uZSB3aGVyZSB0aGUgZWZmZWN0IHN3YXBzIGFuZCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBob3dldmVyLCBhcmUgdmVyeSByYXJlLgotIFRoaXMgaXMgaWxsdXN0cmF0ZWQgd2l0aCB0aGUgY29kZSBiZWxvdywgd2hlcmUgd2Ugd2lsbCBkcmF3IDIwMDAwIHJlcGVhdGVkIHNhbXBsZXMgd2l0aCBzYW1wbGUgc2l6ZSAxMCBmb3IgZmVtYWxlcyBhbmQgbWFsZXMgZnJvbSB0aGUgTkhhbmVzIHN0dWR5LgoKYGBge3J9Cm5zaW0gPC0gMjAwMDAKblNhbXAgPC0gMTAKcmVzIDwtIG1hdHJpeCgwLCBucm93ID0gbnNpbSwgbmNvbCA9IDIpCmZlbSA8LSBuaGFuZXNTdWIgJT4lIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpCm1hbCA8LSBuaGFuZXNTdWIgJT4lIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKQoKZm9yIChpIGluIDE6bnNpbSkKewogIGZlbVNhbXAgPC0gc2FtcGxlKGZlbSRjaG9sTG9nLCBuU2FtcCkKICBtYWxTYW1wIDwtIHNhbXBsZShtYWwkY2hvbExvZywgblNhbXApCgogIG1lYW5GZW0gPC0gbWVhbihmZW1TYW1wKQogIG1lYW5NYWwgPC0gbWVhbihtYWxTYW1wKQogIGRlbHRhIDwtIG1lYW5GZW0gLSBtZWFuTWFsCiAgc2RGZW0gPC0gc2QoZmVtU2FtcCkKICBzZE1hbCA8LSBzZChtYWxTYW1wKQogIHNlRmVtIDwtIHNkRmVtIC8gc3FydChuU2FtcCkKICBzZUZlbSA8LSBzZEZlbSAvIHNxcnQoblNhbXApCiAgc2RQb29sIDwtIHNxcnQoKHNkRmVtXjIgKiAoblNhbXAgLSAxKSArIHNkTWFsXjIgKiAoblNhbXAgLSAxKSkgLyAoMiAqIG5TYW1wIC0gMikpCiAgdHZhbHVlIDwtIChkZWx0YSkgLyAoc2RQb29sICogc3FydCgxIC8gblNhbXAgKyAxIC8gblNhbXApKQogIHB2YWx1ZSA8LSBwdChhYnModHZhbHVlKSwgbG93ZXIudGFpbCA9IEZBTFNFLCBkZiA9IDIgKiBuU2FtcCAtIDIpICogMgogIHJlc1tpLCBdIDwtIGMoZGVsdGEsIHB2YWx1ZSkKfQpzdW0ocmVzWywgMl0gPCAwLjA1ICYgcmVzWywgMV0gPiAwKQpzdW0ocmVzWywgMl0gPiAwLjA1KQpzdW0ocmVzWywgMl0gPCAwLjA1ICYgcmVzWywgMV0gPCAwKQoKcmVzIDwtIHJlcyAlPiUgYXMuZGF0YS5mcmFtZSgpCm5hbWVzKHJlcykgPC0gYygiZGVsdGEiLCAicHZhbHVlIikKcmVzICU+JQogIGdncGxvdChhZXMoeCA9IGRlbHRhLCB5ID0gLWxvZzEwKHB2YWx1ZSksIGNvbG9yID0gcHZhbHVlIDwgMC4wNSkpICsKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkF2ZXJhZ2UgY2hvbGVzdGVyb2wgZGlmZmVyZW5jZSIpICsKICB5bGFiKCItIGxvZzEwKHB2YWx1ZSkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgInJlZCIpKQoKcmVzICU+JQogIGdncGxvdChhZXMoeSA9IGRlbHRhKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gMCwgeSA9IGMobWVhbihmZW0kY2hvbExvZykgLSBtZWFuKG1hbCRjaG9sTG9nKSksIGNvbG9yID0gInBvcC4gZGlmZiIpKSArCiAgeGxhYigiIikKYGBgCgpPbmx5IGluIGByIHN1bShyZXNbLDJdPDAuMDUmcmVzWywxXTwwKWAgb3V0IG9mIDIwMDAwIHNhbXBsZXMgd2UgY29uY2x1ZGUgdGhhdCB0aGUgbWVhbiBjaG9sZXN0ZXJvbCBsZXZlbCBvZiBtYWxlcyBpcyBzaWduaWZpY2FudGx5IGxvd2VyIHRoYW4gZm9yIGZlbWFsZXMuIEZvciB0aGUgcmVtYWluaW5nIHNhbXBsZXMgdGhlIGNob2xlc3Rlcm9sIGxldmVscyBmb3IgbWFsZXMgd2VyZSBvbiBhdmVyYWdlIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiBmb3IgZmVtYWxlcyAoYHIgc3VtKHJlc1ssMl08MC4wNSZyZXNbLDFdPjApYCBzYW1wbGVzKSBvciB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGluIGNob2xlc3Rlcm9sIGxldmVscyB3ZXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChgciBzdW0ocmVzWywyXT4wLjA1KWAgc2FtcGxlcykuIFRoZSBsYXR0ZXIgaXMgYmVjYXVzZSB0aGUgcG93ZXIgaXMgcmF0aGVyIGxvdyB0byBkZXRlY3QgdGhlIGRpZmZlcmVuY2Ugd2l0aCAxMCBzYW1wbGVzIGluIGVhY2ggZ3JvdXAuCgotLS0KCiMjIEFzc2lnbm1lbnQKCjEuIENvcHkgdGhlIGNvZGUgY2h1bmsgd2l0aCB0aGUgc2ltdWxhdGlvbiBzdHVkeQoyLiBBZGQgaXQgaGVyZSBiZWxvdwozLiBNb2RpZnkgdGhlIHNhbXBsZSBzaXplIHRvIDUwLgo0LiBXaGF0IGRvIHlvdSBvYnNlcnZlPwoKCi0tLQoKIyMgQ29udHJvbCBvZiBmYWxzZSBwb3NpdGl2ZXMKCldhdCBoYXBwZW5zIHdoZW4gdGhlcmUgaXMgbm8gZGlmZmVyZW5jZSBiZXR3ZWVuIGJvdGggZ3JvdXBzPwoKLSBXZSB3aWxsIGhhdmUgdG8gc2ltdWxhdGUgZXhwZXJpbWVudHMgZm9yIHdoaWNoIHRoZSBjaG9sZXN0b3JvbCBsZXZlbHMgYXJlIHRoZSBzYW1lIGZvciBib3RoIGdyb3Vwcy4KCgotIFdlIGNhbiBkbyB0aGlzIGJ5IHNhbXBsaW5nIGRhdGEgZm9yIGJvdGggZ3JvdXBzIGZyb20gdGhlIHN1YnNldCBvZiB3b21lbiBpbiB0aGUgc3R1ZHkuCgotIFdlIGRvIHRoaXMgYWdhaW4gZm9yIDEwIHN1YmplY3RzIHBlciBncm91cAoKCmBgYHtyfQpuc2ltIDwtIDIwMDAwCm5TYW1wIDwtIDEwCnJlcyA8LSBtYXRyaXgoMCwgbnJvdyA9IG5zaW0sIG5jb2wgPSAyKQpmZW0gPC0gbmhhbmVzU3ViICU+JSBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQptYWwgPC0gbmhhbmVzU3ViICU+JSBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikKCmZvciAoaSBpbiAxOm5zaW0pCnsKICBmZW1TYW1wIDwtIHNhbXBsZShmZW0kY2hvbExvZywgblNhbXApCiAgZmVtMlNhbXAgPC0gc2FtcGxlKGZlbSRjaG9sTG9nLCBuU2FtcCkKCiAgbWVhbkZlbSA8LSBtZWFuKGZlbVNhbXApCiAgbWVhbkZlbTIgPC0gbWVhbihmZW0yU2FtcCkKICBkZWx0YSA8LSBtZWFuRmVtIC0gbWVhbkZlbTIKICBzZEZlbSA8LSBzZChmZW1TYW1wKQogIHNkRmVtMiA8LSBzZChmZW0yU2FtcCkKICBzZUZlbSA8LSBzZEZlbSAvIHNxcnQoblNhbXApCiAgc2VGZW0gPC0gc2RGZW0yIC8gc3FydChuU2FtcCkKICBzZFBvb2wgPC0gc3FydCgoc2RGZW1eMiAqIChuU2FtcCAtIDEpICsgc2RGZW0yXjIgKiAoblNhbXAgLSAxKSkgLyAoMiAqIG5TYW1wIC0gMikpCiAgdHZhbHVlIDwtIChkZWx0YSkgLyAoc2RQb29sICogc3FydCgxIC8gblNhbXAgKyAxIC8gblNhbXApKQogIHB2YWx1ZSA8LSBwdChhYnModHZhbHVlKSwgbG93ZXIudGFpbCA9IEZBTFNFLCBkZiA9IDIgKiBuU2FtcCAtIDIpICogMgogIHJlc1tpLCBdIDwtIGMoZGVsdGEsIHB2YWx1ZSkKfQpzdW0ocmVzWywgMl0gPCAwLjA1ICYgcmVzWywgMV0gPiAwKQpzdW0ocmVzWywgMl0gPj0gMC4wNSkKc3VtKHJlc1ssIDJdIDwgMC4wNSAmIHJlc1ssIDFdIDwgMCkKCnJlcyA8LSByZXMgJT4lIGFzLmRhdGEuZnJhbWUoKQpuYW1lcyhyZXMpIDwtIGMoImRlbHRhIiwgInB2YWx1ZSIpCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkZWx0YSwgeSA9IC1sb2cxMChwdmFsdWUpLCBjb2xvciA9IHB2YWx1ZSA8IDAuMDUpKSArCiAgZ2VvbV9wb2ludCgpICsKICB4bGFiKCJBdmVyYWdlIGNob2xlc3Rlcm9sIGRpZmZlcmVuY2UiKSArCiAgeWxhYigiLSBsb2cxMChwdmFsdWUpIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBkZWx0YSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IDAsIHkgPSAwLCBjb2xvciA9ICJwb3AuIGRpZmYiKSkgKwogIHhsYWIoIiIpCmBgYAoKTm90ZSwgdGhhdCB0aGUgbnVtYmVyIG9mIGZhbHNlIHBvc2l0aXZlcyBhcmUgb24gYHIgc3VtKHJlc1ssMl08MC4wNSlgIG9uIGByIGZvcm1hdChuc2ltLGRpZ2l0cz01KWAgZXhwZXJpbWVudHMgYW5kIGFyZSBuaWNlbHkgY29udHJvbGxlZCBhdCB0aGUgNSUgbGV2ZWwuCgpXaGF0IGhhcHBlbnMgaWYgd2UgaW5jcmVhc2UgdGhlIHNhbXBsZSBzaXplIHRvIDUwIHN1YmplY3RzIHBlciBncm91cD8KCgotLS0KCiMgU2FsayBTdHVkeQoKLSBJbiAxOTE2LCB0aGUgVVMgZXhwZXJpZW5jZWQgdGhlIGZpcnN0IGxhcmdlIGVwaWRlbWljIG9mIHBvbGlvLgotIEpvaG4gU2FsayBkZXZlbG9wZWQgYSB2YWNjaW5lIHdpdGggcHJvbWlzaW5nIHJlc3VsdHMgaW4gdGhlIGxhYiBpbiB0aGUgZWFybHkgZmlmdGllcy4KLSBJbiAxOTU0LCB0aGUgTmF0aW9uYWwgRm91bmRhdGlvbgpmb3IgSW5mYW50aWxlIFBhcmFseXNpcyAoTkZJUCkgaGFzIHNldHVwIGEgbGFyZ2Ugc3R1ZHkgdG8gYXNzZXNzIHRoZSBlZmZlY3RpdmVuZXNzIG9mIHRoZSBTYWxrIHZhY2NpbmUuCi0gU3VwcG9zZSB0aGF0IHRoZSBORklQIHdvdWxkIGhhdmUgdmFjY2luYXRlZCBhIGxhcmdlIG51bWJlciBvZiBjaGlsZHJlbiBpbiAxOTU0IGFuZCB3b3VsZCBoYXZlIG9ic2VydmVkIHRoYXQgdGhlIHBvbGlvIGluY2lkZW5jZSBpbiAxOTU0IHdhcyBsb3dlciB0aGFuIGluIDE5NTMuIENvdWxkIHRoZXkgaGF2ZSBjb25jbHVkZWQgdGhhdCB0aGUgdmFjY2luZSB3YXMgZWZmZWN0aXZlPwoKLS0tCgojIyBORklQIFN0dWR5CgojIyMgRGVzaWduCgotIExhcmdlIHNpbXVsdGFuZW91cyBzdHVkeSB3aXRoIGNhc2VzLCB2YWNjaW5hdGVkIGNoaWxkcmVuLCBhbmQgY29udHJvbHMsICBub24tdmFjY2luYXRlZCBjaGlsZHJlbi4KLSBBbGwgc2Nob29scyBpbiBkaXN0cmljdHMgd2l0aCBoaWdoIHBvbGlvIGluY2lkZW5jZQotIENhc2VzOiBjaGlsZHJlbiB3aXRoIGNvbnNlbnQgZm9yIHZhY2NpbmF0aW9uIGZyb20gc2Vjb25kIGdyYWRlIG9mIHByaW1hcnkgc2Nob29sLgotIENvbnRyb2xzOiBjaGlsZHJlbiBmcm9tICBmaXJzdCBhbmQgdGhpcmQgZ3JhZGUuCgojIyMgRGF0YQoKYGBge3J9Cm5maXAgPC0gZGF0YS5mcmFtZShncm91cCA9IGMoImNhc2VzIiwgImNvbnRyb2wiLCAibm9Db25jZW50IiksIGdyYWRlID0gYygiZzIiLCAiZzFnMyIsICJnMiIpLCB2YWNjaW4gPSBjKCJ5ZXMiLCAibm8iLCAibm8iKSwgdG90YWwgPSBjKDIyMTk5OCwgNzI1MTczLCAxMjM2MDUpLCBwb2xpbyA9IGMoNTQsIDM5MSwgNTYpKQpuZmlwJG5vUG9saW8gPC0gbmZpcCR0b3RhbCAtIG5maXAkcG9saW8Ka25pdHI6OmthYmxlKG5maXApCmBgYAoKQ29tcGFyZSBwb2xpbyBpbmNpZGVuY2U/CgpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KbmZpcCRpbmNpZGVuY2VQTSA8LSByb3VuZChuZmlwJHBvbGlvIC8gbmZpcCR0b3RhbCAqIDFlNiwgMCkKa25pdHI6OmthYmxlKG5maXApCmBgYAoKV2hhdCBjYW4gd2UgY29uY2x1ZGU/CgotLS0KCiMjIENvbmZvdW5kaW5nCgpgYGB7cixlY2hvPUZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIixvdXQud2lkdGggPSAnNTAlJ30KcGxvdChjKDAsIDAsIDEpLCBjKC0yLCAyLCAwKSwgcGNoID0gYygiUyIsICJWIiwgIlAiKSwgeGF4dCA9ICJub25lIiwgeWF4dCA9ICJub25lIiwgYXhlcyA9IEZBTFNFLCB4bGFiID0gIiIsIHlsYWIgPSAiIiwgY2V4ID0gNCwgeWxpbSA9IGMoLTIuMiwgMi4yKSkKYXJyb3dzKHgwID0gMC4xLCB4MSA9IC45LCB5MCA9IDEuOCwgeTEgPSAwLjEsIGx3ZCA9IDQpCmFycm93cyh4MCA9IDAuMSwgeDEgPSAuOSwgeTAgPSAtMS44LCB5MSA9IC0wLjIsIGx3ZCA9IDQpCmFycm93cyh4MCA9IDAsIHgxID0gMCwgeTAgPSAtMS40LCB5MSA9IDEuNCwgbHdkID0gNCkKYGBgCgoKLSBXZSBvYnNlcnZlIGEgbG93ZXIgcG9saW8gKFApIGluY2lkZW5jZSBmb3IgY2hpbGRyZW4gZm9yIHdobyBubyBjb25zZW50IHdhcyBnaXZlbiB0aGFuIGZvciB0aGUgY2hpbGRyZW4gaW4gdGhlIGNvbnRyb2wgZ3JvdXAuCgotIENvbnNlbnQgZm9yIHZhY2NpbmF0aW9uIChWKSB3YXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzb2Npby1lY29ub21pYyBzdGF0dXMgKFMpLgoKLSBDaGlsZHJlbiBvZiBsb3dlciBzb2Npby1lY29ub21pYyBzdGF0dXMgd2VyZSBtb3JlIHJlc2lzdGFudCB0byB0aGUgZGlzZWFzZS4KCi0gVGhlIGdyb3VwcyBvZiBjYXNlcyBhbmQgY29udHJvbHMgYXJlIG5vdCBjb21wYXJhYmxlOgogICAgLSBkaWZmZXJlbmNlIGluIGFnZSwKICAgIC0gZGlmZmVyZW5jZSBpbiBzb2Npby1lY29ub21pYyBzdGF0dXMgYW5kCiAgICAtIGRpZmZlcmVuY2UgaW4gc3VzY2VwdGlibGUgZm9yIGRpc2Vhc2UuCgotLS0KCiMjIFNhbGsgU3R1ZHkKCiMjIyBEZXNpZ24KCkEgbmV3IHN0dWR5IHdhcyBjb25kdWN0ZWQ6IFJhbmRvbWl6ZWQgZG91YmxlIGJsaW5kIHN0dWR5CgogIC0gQ2hpbGRyZW4gYXJlIGFzc2lnbmVkIGF0IHJhbmRvbSB0byB0aGUgY29udHJvbCBvciBjYXNlIHRyZWF0bWVudCBhcm0gYWZ0ZXIgY29uc2VudCB3YXMgZ2l2ZW4gYnkgdGhlIHBhcmVudHMuCiAgLSBDb250cm9sOiB2YWNjaW5hdGlvbiB3aXRoIHBsYWNlYm8KICAtIFRyZWF0bWVudDogdmFjY2luYXRpb24gd2l0aCB2YWNjaW5lCiAgLSBkb3VibGUgYmxpbmRpbmc6CiAgICAtIHBhcmVudHMgZGlkIG5vdCBrbm93IGlmIHRoZWlyIGNoaWxkIHdhcyB2YWNjaW5hdGVkIG9yIHJlY2VpdmVkIHRoZSBwbGFjZWJvCiAgICAtIGNhcmUtZ2l2ZXIvcmVzZWFyY2hlcnMgZGlkIG5vdCBrbm93IGlmIHRoZSBjaGlsZCB3YXMgdmFjY2luYXRlZCAgb3IgcmVjZWl2ZWQgcGxhY2VibwoKLS0tCgojIyMgRGF0YQoKYGBge3J9CnNhbGsgPC0gZGF0YS5mcmFtZShncm91cCA9IGMoImNhc2VzIiwgImNvbnRyb2wiLCAibm9Db25jZW50IiksIHRyZWF0bWVudCA9IGMoInZhY2NpbmUiLCAicGxhY2VibyIsICJub25lIiksIHRvdGFsID0gYygKICAyMDA3NDUsCiAgMjAxMjI5LCAzMzg3NzgKKSwgcG9saW8gPSBjKDU3LCAxNDIsIDE1NykpCnNhbGskbm9Qb2xpbyA8LSBzYWxrJHRvdGFsIC0gc2FsayRwb2xpbwpzYWxrJGluY2lkZW5jZVBNIDwtIHJvdW5kKHNhbGskcG9saW8gLyBzYWxrJHRvdGFsICogMWU2LCAwKQprbml0cjo6a2FibGUoc2FsaykKYGBgCgotIFdlIG9ic2VydmUgYSBtdWNoIGxhcmdlciBlZmZlY3Qgbm93IHRoYXQgdGhlIGNhc2VzIGFuZCB0aGUgY29udHJvbHMgYXJlIGNvbXBhcmFibGUsIGluY2lkZW5jZSBvZiBgciBzYWxrJGluY2lkZW5jZVBNWzFdYCAgYW5kIGByIHNhbGskaW5jaWRlbmNlUE1bMl1gIHBlciBtaWxsaW9uLCByZXNwZWN0aXZlbHkuCgotIFRoZSBwb2xpbyBpbmNpZGVuY2UgZm9yIGNoaWxkcmVuIHdpdGggbm8gY29uc2VudCByZW1haW5zIHNpbWlsYXIsIGByIG5maXAkaW5jaWRlbmNlUE1bM11gIGFuZCBgciBzYWxrJGluY2lkZW5jZVBNWzNdYCBwZXIgbWlsbGlvbiBpbiB0aGUgTkZJUCBhbmQgU2FsayBzdHVkeSwgcmVzcGVjdGl2ZWx5LgoKLS0tCgojIFJvbGUgb2YgU3RhdGlzdGljcyBpbiB0aGUgTGlmZSBTY2llbmNlcwoKLSBXZSBoYXZlIHNlZW4gdGhhdAogICAgLSBpdCBpcyBpbXBvcnRhbnQgdG8gY2FyZWZ1bGx5IHNwZWNpZnkgdGhlIHNjb3BlIG9mIHRoZSBzdHVkeSBiZWZvcmUgdGhlIGV4cGVyaW1lbnQsCiAgICAtIHRoZSBzYW1wbGUgc2l6ZSBtYXR0ZXJzLAogICAgLSB3ZSBzaG91bGQgYmUgYXdhcmUgb2YgY29uZm91bmRpbmcsIGFuZAogICAgLSBhIHByb3BlciBjb250cm9sIGlzIHJlcXVpcmVkLgoKJFxyaWdodGFycm93JCBHb29kIGV4cGVyaW1lbnRhbCBkZXNpZ24gaXMgY3J1Y2lhbCEKCi0gV2UgYWxzbyBvYnNlcnZlZCB0aGF0IHRoZXJlIGlzIHZhcmlhYmlsaXR5IGluIHRoZSBwb3B1bGF0aW9uIGFuZCBiZWNhdXNlIHdlIGNhbiBvbmx5IHNhbXBsZSBhIHNtYWxsIHBhcnQgb2YgdGhlIHBvcHVsYXRpb24gb3VyIHJlc3VsdHMgYW5kIGNvbmNsdXNpb25zIGFyZSBzdWJqZWN0ZWQgdG8gdW5jZXJ0YWludHkuCgotIFN0YXRpc3RpY3MgaXMgdGhlIHNjaWVuY2Ugb24KICAgIDEuIGNvbGxlY3RpbmcgKGV4cGVyaW1lbnRhbCBkZXNpZ24pLAogICAgMi4gZXhwbG9yaW5nIChkYXRhIGV4cGxvcmF0aW9uKSBhbmQKICAgIDMuIGxlYXJuaW5nIGZyb20gZGF0YSBhbmQgdG8gZ2VuZXJhbGl6ZSB3aGF0IHdlIG9ic2VydmUgaW4gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uIHdoaWxlIHF1YW50aWZ5aW5nLCBjb250cm9sbGluZyBhbmQgcmVwb3J0aW5nIHZhcmlhYmlsaXR5IGFuZCB1bmNlcnRhaW50eSAoc3RhdGlzdGljYWwgbW9kZWxsaW5nIGFuZCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UpLgoKLSBUaGVyZWZvcmUsIHN0YXRpc3RpY3MgcGxheXMgYW4gaW1wb3J0YW50IHJvbGUgaW4gYWxtb3N0IGFsbCBzY2llbmNlcyAoZS5nLiBjb2x1bW4gInBvaW50cyBvZiBzaWduaWZpY2FuY2UiIGluIE5hdHVyZSBNZXRob2RzLiBodHRwOi8vYmxvZ3MubmF0dXJlLmNvbS9tZXRoYWdvcmEvMjAxMy8wOC9naXZpbmdfc3RhdGlzdGljc190aGVfYXR0ZW50aW9uX2l0X2Rlc2VydmVzLmh0bWwpCgotLS0KCmBgYHtyIHBvcDJTYW1wMlBvcCwgb3V0LndpZHRoPSc4MCUnLGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQppZiAoInBpIiAlaW4lIGxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlciA8LSBmdW5jdGlvbih4LCB5LCBhbmdsZSA9IDAsIGwgPSAuMiwgY2V4LmRvdCA9IC41LCBwY2ggPSAxOSwgY29sID0gImJsYWNrIikgewogIGFuZ2xlIDwtIGFuZ2xlIC8gMTgwICogcGkKICBwb2ludHMoeCwgeSwgY2V4ID0gY2V4LmRvdCwgcGNoID0gcGNoLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4LCB4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpKSwgYyh5LCB5ICsgbCAqIHNpbigtcGkgLyAyICsgYW5nbGUpKSwgY29sID0gY29sKQogIGxpbmVzKGMoeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSksIHggKyBsIC8gMiAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBjb3MoYW5nbGUpKSwgYyh5ICsgbCAvIDIgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIHNpbihhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIGFuZ2xlKSwgeCArIGwgLyAyICogY29zKC1waSAvIDIgKyBhbmdsZSkgKyBsIC8gNCAqIGNvcyhwaSArIGFuZ2xlKSksIGMoeSArIGwgLyAyICogc2luKC1waSAvIDIgKyBhbmdsZSksIHkgKyBsIC8gMiAqIHNpbigtcGkgLyAyICsgYW5nbGUpICsgbCAvIDQgKiBzaW4ocGkgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBjb3MoLXBpIC8gMiArIHBpIC8gNCArIGFuZ2xlKSksIGMoeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogc2luKC1waSAvIDIgKyBwaSAvIDQgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCiAgbGluZXMoYyh4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpLCB4ICsgbCAqIGNvcygtcGkgLyAyICsgYW5nbGUpICsgbCAvIDIgKiBjb3MoLXBpIC8gMiAtIHBpIC8gNCArIGFuZ2xlKSksIGMoeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSwgeSArIGwgKiBzaW4oLXBpIC8gMiArIGFuZ2xlKSArIGwgLyAyICogc2luKC1waSAvIDIgLSBwaSAvIDQgKyBhbmdsZSkpLCBjb2wgPSBjb2wpCn0KCnBhcihtYXIgPSBjKDAsIDAsIDAsIDApLCBtYWkgPSBjKDAsIDAsIDAsIDApKQpwbG90KDAsIDAsIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCB4bGltID0gYygwLCAxMCksIHlsaW0gPSBjKDAsIDEwKSwgY29sID0gMCwgeGF4dCA9ICJub25lIiwgeWF4dCA9ICJub25lIiwgYXhlcyA9IEZBTFNFKQpyZWN0KDAsIDYsIDEwLCAxMCwgYm9yZGVyID0gInJlZCIsIGx3ZCA9IDIpCnRleHQoLjUsIDgsICJwb3B1bGF0aW9uIiwgc3J0ID0gOTAsIGNvbCA9ICJyZWQiLCBjZXggPSAyKQpzeW1ib2xzKDMsIDgsIGNpcmNsZXMgPSAxLjUsIGNvbCA9ICJyZWQiLCBhZGQgPSBUUlVFLCBmZyA9ICJyZWQiLCBpbmNoZXMgPSBGQUxTRSwgbHdkID0gMikKc2V0LnNlZWQoMzMwKQpncmlkIDwtIHNlcSgwLCAxLjMsIC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CiAgYW5nbGUxIDwtIHJ1bmlmKG4gPSAxLCBtaW4gPSAwLCBtYXggPSAzNjApCiAgYW5nbGUyIDwtIHJ1bmlmKG4gPSAxLCBtaW4gPSAwLCBtYXggPSAzNjApCiAgcmFkaXVzIDwtIHNhbXBsZShncmlkLCBwcm9iID0gZ3JpZF4yICogcGkgLyBzdW0oZ3JpZF4yICogcGkpLCBzaXplID0gMSkKICBrb3B2b2V0ZXIoMyArIHJhZGl1cyAqIGNvcyhhbmdsZTEgLyAxODAgKiBwaSksIDggKyByYWRpdXMgKiBzaW4oYW5nbGUxIC8gMTgwICogcGkpLCBhbmdsZSA9IGFuZ2xlMikKfQp0ZXh0KDcuNSwgOCwgImNob2xlc3Rlcm9sIGluIHBvcHVsYXRpb24iLCBjb2wgPSAicmVkIiwgY2V4ID0gMS4yKQoKcmVjdCgwLCAwLCAxMCwgNCwgYm9yZGVyID0gImJsdWUiLCBsd2QgPSAyKQp0ZXh0KC41LCAyLCAic2FtcGxlIiwgc3J0ID0gOTAsIGNvbCA9ICJibHVlIiwgY2V4ID0gMikKc3ltYm9scygzLCAyLCBjaXJjbGVzID0gMS41LCBjb2wgPSAicmVkIiwgYWRkID0gVFJVRSwgZmcgPSAiYmx1ZSIsIGluY2hlcyA9IEZBTFNFLCBsd2QgPSAyKQpmb3IgKGkgaW4gMDoyKSB7CiAgZm9yIChqIGluIDA6NCkKICB7CiAgICBrb3B2b2V0ZXIoMi4xICsgaiAqICgzLjkgLSAyLjEpIC8gNCwgMS4xICsgaSkKICB9Cn0KdGV4dCg3LjUsIDIsICJjaG9sZXN0ZXJvbCBpbiBzYW1wbGUiLCBjb2wgPSAiYmx1ZSIsIGNleCA9IDEuMikKCmFycm93cygzLCA1LjksIDMsIDQuMSwgY29sID0gImJsYWNrIiwgbHdkID0gMykKYXJyb3dzKDcsIDQuMSwgNywgNS45LCBjb2wgPSAiYmxhY2siLCBsd2QgPSAzKQp0ZXh0KDEuNSwgNSwgIkVYUC4gREVTSUdOICgxKSIsIGNvbCA9ICJibGFjayIsIGNleCA9IDEuMikKdGV4dCg4LjUsIDUsICJFU1RJTUFUSU9OICZcbklORkVSRU5DRSAoMykiLCBjb2wgPSAiYmxhY2siLCBjZXggPSAxLjIpCnRleHQoNy41LCAuNSwgIkRBVEEgRVhQTE9SQVRJT04gJlxuREVTQ1JJUFRJVkUgU1RBVElTVElDUyAoMikiLCBjb2wgPSAiYmxhY2siLCBjZXggPSAxLjIpCmBgYAo=