Hypothetical population

Here we’ll try to understand the differences between Risk Ratio (RR) and Odds Ratio (OR) in a hypothetical scenario. First I’ll set a population of 1 million people, and this population will be divided in 20% who smoke and 80% who don’t smoke.

pop <- data.frame(smoke = sample(c("Smokes", "NeverSmoked"), 1e6, prob = c(0.2, 0.8), rep= T))

I want a relative risk of ~2 when considering the probability of someone who smokes to get cancer. Therefore, I’ll set 2% of the smoking population to have cancer, and 1% of nonsmoking population to have cancer.

pop[which(pop$smoke=="Smokes"), "cancer"] <- sample(c("Cancer", "Healthy"), sum(pop$smoke=="Smokes"), prob = c(0.02, 0.98), rep= T)
pop[which(pop$smoke=="NeverSmoked"), "cancer"] <- sample(c("Cancer", "Healthy"), sum(pop$smoke=="NeverSmoked"), prob = c(0.01, 0.99), rep= T)

# Plot the simulated population in a treemap
library(treemap)
package 㤼㸱treemap㤼㸲 was built under R version 3.5.3
pop2 <- unique(pop)
for(i in 1:nrow(pop2)){
  pop2[i, "counts"] <- sum(pop$smoke==pop2[i, "smoke"] & pop$cancer==pop2[i, "cancer"])
}

treemap(pop2, index = c("smoke", "cancer"), aspRatio = 1,
        vSize = "counts", vColor = "cancer", border.lwds = c(1,1),
        title = 'Distribution of cancer between smokers and no smokers',
        #palette = "OrRd",
        type = "categorical")
with=FALSE ignored, it isn't needed when using :=. See ?':=' for examples.

Cohort simulation

So if we calculate RR, we would find a ~2x risk of cancer in people who smoke, compared to those who don’t smoke. However, cohort studies are performed with a random sample of the population, not the whole population.

To get a sample, let’s first determine the adequate sample size, and then draw the estimates.

# Determine sample size with alpha = 5% and power = 80%
sample.size <- power.prop.test(p1 = 0.02, p2 = 0.01, power = 0.8)

# Now let's draw this amount of patients from each condition in our dataset.
## Draw a sample from smokers (we still don't know if they will get cancer or not)
sample.smokes <- pop[which(pop$smoke=="Smokes"),][sample(c(1:sum(pop$smoke=="Smokes")), sample.size$n, replace = F),]
## Draw a sample from nonsmokers (we still don't know if they will get cancer or not)
sample.neversmoked <- pop[which(pop$smoke=="NeverSmoked"),][sample(c(1:sum(pop$smoke=="NeverSmoked")), sample.size$n, replace = F),]

# Check our RR
a <- sum(sample.smokes$cancer == "Cancer")/sum(nrow(sample.smokes))
b <- sum(sample.neversmoked$cancer == "Cancer")/sum(nrow(sample.neversmoked))
a/b
[1] 1.896552

We see that everytime this script is run, it returns a different value for RR. This is because sampling error occurs, that is why alpha is 5% and power is 80%. We expect a rate of false positives and false negatives.

We can plot the differences in RR after 40 different measurements (which is equivalent to 40 different studies looking at the same population, each one finding a different RR value.

Multiple plots

# Real RR
a <- sum(pop$smoke=="Smokes" & pop$cancer=="Cancer")/sum(pop$smoke=="Smokes")
b <- sum(pop$smoke=="NeverSmoked" & pop$cancer=="Cancer")/sum(pop$smoke=="NeverSmoked")
RealRR <- a/b

# Sample RR
SampleRR <- c()
for(i in 1:40){
  sample.smokes <- pop[which(pop$smoke=="Smokes"),][sample(c(1:sum(pop$smoke=="Smokes")), sample.size$n, replace = F),]
  sample.neversmoked <- pop[which(pop$smoke=="NeverSmoked"),][sample(c(1:sum(pop$smoke=="NeverSmoked")), sample.size$n, replace = F),]
  a <- sum(sample.smokes$cancer == "Cancer")/sum(nrow(sample.smokes))
  b <- sum(sample.neversmoked$cancer == "Cancer")/sum(nrow(sample.neversmoked))
  SampleRR[i] <- a/b
}

# Plot differences
library(ggplot2)
package 㤼㸱ggplot2㤼㸲 was built under R version 3.5.3Need help getting started? Try the R Graphics Cookbok:
https://r-graphics.org
ggplot(data = data.frame(RR = c(RealRR, SampleRR), 
                         Group = c("Real", rep("Sample", 40))),
       aes(x = Group, y = RR)) +
  geom_boxplot(aes(colour=Group)) +
  geom_point(size = 3, aes(colour=Group))

Now we can see the error introduced by sampling. Let’s jump to a case-control simulation to see what we can learn.

Case-control simulation

Let’s proceed to the estimate of Odds Ratio in a case-control simulation. For a case-control study, we’ll draw a sample from random people who have cancer, and the same number of people who don’t have cancer, and check if they have smoked or not in the past.

# Define the sample size for a case-control study
library(epiR)
package 㤼㸱epiR㤼㸲 was built under R version 3.5.3Carregando pacotes exigidos: survival
package 㤼㸱survival㤼㸲 was built under R version 3.5.3Package epiR 1.0-14 is loaded
Type help(epi.about) for summary information
Type browseVignettes(package = 'epiR') to learn how to use epiR for applied epidemiological analyses
sample.size.cc <- epi.sscc(OR = 2, p0 = 0.2, power = 0.8, n = NA)$n.case

# Draw samples of people who have cancer or not.
sample.cancer <- pop[which(pop$cancer=="Cancer"),][sample(c(1:sum(pop$cancer=="Cancer")), sample.size.cc, replace = F),]
sample.healthy <- pop[which(pop$cancer=="Healthy"),][sample(c(1:sum(pop$cancer=="Healthy")), sample.size.cc, replace = F),]

# Determine 40 OR calculations
OR80 <- c()
for(i in 1:40){
  sample.cancer <- pop[which(pop$cancer=="Cancer"),][sample(c(1:sum(pop$cancer=="Cancer")), sample.size.cc, replace = F),]
sample.healthy <- pop[which(pop$cancer=="Healthy"),][sample(c(1:sum(pop$cancer=="Healthy")), sample.size.cc, replace = F),]
  a <- sum(sample.cancer$smoke == "Smokes")/sum(sample.healthy$smoke == "Smokes")
  b <- sum(sample.cancer$smoke == "NeverSmoked")/sum(sample.healthy$smoke == "NeverSmoked")
  OR80[i] <- a/b
}

# Plot differences
library(ggplot2)
ggplot(data = data.frame(RR = c(RealRR, OR80), 
                         Group = c("Real", rep("Odds Ratio", 40))),
       aes(x = Group, y = RR)) +
  geom_boxplot(aes(colour=Group)) +
  geom_point(size = 3, aes(colour=Group))

The OR distribution is very close to the distribution of the RR calculations.

All plots compared

Let us compare the Odds Ratio and the Risk Ratio obtained previously.

ggplot(data = data.frame(RR = c(RealRR, SampleRR, OR80), 
                         Group = c("Real", rep("Risk Ratio", 40), rep("Odds Ratio", 40))),
       aes(x = Group, y = RR)) +
  geom_boxplot(aes(colour=Group)) +
  geom_point(size = 3, aes(colour=Group))

We can see very clearly than under optimal circumstances, the Odds Ratio is very close to the Risk Ratio, which in turn is a good, but far from perfect, estimate of the true risk.

Not let’s try something forbidden by the rules of statistics. The Risk Ratio should not be calculated using a case-control design (see below the Math section), but let’s do it here, because many people learns best when they see images. Additionally, I’ll calculate an Odds Ratio from the Cohort study above, which is allowed.

# Determine 40 forbidden RR calculations from case-control studies
forbiddenRR <- c()
for(i in 1:40){
  sample.cancer <- pop[which(pop$cancer=="Cancer"),][sample(c(1:sum(pop$cancer=="Cancer")), sample.size.cc, replace = F),]
sample.healthy <- pop[which(pop$cancer=="Healthy"),][sample(c(1:sum(pop$cancer=="Healthy")), sample.size.cc, replace = F),]
  smoked <- sum(sample.cancer$smoke == "Smokes") + sum(sample.healthy$smoke == "Smokes")
  neversmoked <- sum(sample.cancer$smoke == "NeverSmoked") + sum(sample.healthy$smoke == "NeverSmoked")
  a <- sum(sample.cancer$smoke == "Smokes")/smoked
  b <- sum(sample.cancer$smoke == "NeverSmoked")/neversmoked
  forbiddenRR[i] <- a/b
}

# Determine 40 allowed OR calculations from cohort studies
allowedOR <- c()
for(i in 1:40){
  sample.smokes <- pop[which(pop$smoke=="Smokes"),][sample(c(1:sum(pop$smoke=="Smokes")), sample.size$n, replace = F),]
  sample.neversmoked <- pop[which(pop$smoke=="NeverSmoked"),][sample(c(1:sum(pop$smoke=="NeverSmoked")), sample.size$n, replace = F),]
  a <- sum(sample.smokes$cancer == "Cancer")/sum(sample.smokes$cancer == "Healthy")
  b <- sum(sample.neversmoked$cancer == "Cancer")/sum(sample.neversmoked$cancer == "Healthy")
  allowedOR[i] <- a/b
}

# Plot differences
library(ggplot2)
ggplot(data = data.frame(RR = c(RealRR, OR80, forbiddenRR, SampleRR, allowedOR), 
                         Effect.size = c("Real", 
                                   rep("OR", 40), 
                                   rep("RR", 40), 
                                   rep("RR", 40), 
                                   rep("OR", 40)),
                         Study.type = c("Real", 
                                   rep("case-control", 40),
                                   rep("case-control", 40), 
                                   rep("cohort", 40), 
                                   rep("cohort", 40))),
       aes(x = Study.type, y = RR)) +
  geom_boxplot(aes(colour=Effect.size)) +
  geom_point(position = position_dodge(width=0.75), aes(colour=Effect.size))

This shows something really interesting. We can see that the distributions of the “allowed” calculations are all similar, and they wander around the true risk figure. However, the “forbidden” calculation, which is the RR in a case-control study, has a really narrow distribution of values that never get close to the true figure. Now let’s try to understand some math behind this.

Math

Before I proceed, let me explain some notations. \(P(X)\) is the probability of X happening. \(P(X|Y)\) is the probability of X happening, given that Y have already happened. This is a Bayesian probability. There are ways to expand a bayesian probability to deal with different situations, for example:

\(P(X) = 1 - P(\neg{X})\)

\(P(X) = P(X|Y)P(Y) + P(X|\neg{Y})P(\neg{Y})\)

\(P(X|Y) = \frac{P(X)P(Y|X)}{P(Y)}\)

\(P(X|Y) = \frac{P(X|\neg{}Y)P(\neg{}Y)P(Y|X)}{P(\neg{}Y|X)P(Y)}\)

\(P(X|Y) = 1 - P(\neg{X}|Y)\)

These are just a few examples of arithmetics that can be done when the measures are binary.

Also, to avoid gigantic formulas ahead, let’s replace “cancer” (binary outcome) and “smoked” (binary exposure) with X and Y, respectively.

\(X = cancer\)

\(Y = smoked\)

\(\neg{X}=healthy\)

\(\neg{Y}=neversmoked\)

Population risk

So if you had the complete data for the whole population, it would be easy to calculate the risks and the odds. The absolute risk of having cancer, if you smoked, would be: \[Risk_{pop} = P(X|Y)\] And the risk ratio between having cancer if you smoked, and having cancer if you didn’t smoke, would be: \[RR_{pop} = \frac{P(X|Y)}{P(X|\neg{Y})}\] ## Sample risk

Now, if you are sampling from a population, things get a little different, depending on the sampling design. That’s because when you sample, you’re drawing from a population with a specific probability. If you sample people based on their exposure status (cohort design), and then wait until you see the outcome, you would have \[Risk_{cohort}=\frac{P(X|Y)}{P(X|Y)+P(\neg{X}|Y)}=\frac{P(X|Y)}{1}=Risk_{pop}\] Which is precisely the same as calculating the population risk. Then if you try calculating the risk ratio

\[RR_{cohort} = \frac{\frac{P(X|Y)}{P(X|Y)+P(\neg{X}|Y)}}{\frac{P(X|\neg{Y})}{P(X|\neg{Y})+P(\neg{X}|\neg{Y})}}=\frac{\frac{P(X|Y)}{1}}{\frac{P(X|\neg{Y})}{1}}=RR_{pop}\]

You would also find that it would be mathematically the same as the population RR. So a cohort study has the perfect design for calculating the population risk, given that the sampling was random.

However, if you sampled people based on their outcome status (case-control design), and then checked whether they were exposed or not, you would get a very different probability, that is the probability of finding an exposure, given that you know the outcome: \[Risk_{case-control}=\frac{P(Y|X)}{P(Y|X)+P(Y|\neg{X})}\ne{}P(X|Y), Risk_{case-control}\ne{}Risk_{pop}\] \[RR_{case-control} = \frac{\frac{P(Y|X)}{P(Y|X)+P(Y|\neg{X})}}{\frac{P(\neg{Y}|X)}{P(\neg{Y}|X)+P(\neg{Y}|\neg{X})}}\ne{}\frac{P(X|Y)}{P(X|\neg{Y})}, RR_{case-control}\ne{}RR_{pop}\] If you try to solve it, you wil find that \(RR_{case-control}\ne{RR}\).

Population odds

The odds of something happening is the probability of it happening divided by the probability of it not happening. For example, you would have 4 times (odds) more chance of winning than of losing if the probability of winning was 80%, because you would divide 80% by 20%. So the chance of cancer, if you smoked, would be:

\[Odds_{pop} = \frac{P(X|Y)}{P(\neg{X|Y})}\] And the Odds Ratio would be the ratio between the odds of cancer if you smoked, and the odds of cancer, if you didn’t smoke.

\[OR_{pop} = \frac{\frac{P(X|Y)}{P(\neg{X|Y})}}{\frac{P(X|\neg{}Y)}{P(\neg{X|\neg{}Y})}}\]

Sample odds

If you were doing a case-control study, in which the Odds Ratio would be the choice for measuring the effect size, you would be calculating this:

\[OR_{case-control} = \frac{\frac{\frac{P(Y)P(X|Y)}{P(X)}}{\frac{P(Y)P(\neg{}X|Y)}{P(\neg{}X)}}}{\frac{\frac{P(\neg{}Y)P(X|\neg{}Y)}{P(X)}}{\frac{P(\neg{}Y)P(\neg{}X|\neg{}Y)}{P(\neg{}X)}}} = \frac{\frac{\frac{1.P(X|Y)}{1}}{\frac{1.P(\neg{}X|Y)}{1}}}{\frac{\frac{1.P(X|\neg{}Y)}{1}}{\frac{1.P(\neg{}X|\neg{}Y)}{1}}} = \frac{\frac{P(X|Y)}{P(\neg{}X|Y)}}{\frac{P(X|\neg{}Y)}{P(\neg{}X|\neg{}Y)}} = OR_{pop}\]

I won’t write here the equation for the Odds Ratio in a case-control study, because it would be exactly the same as the population odds ratio, therefore they are the same.

When OR ~ RR

Whenever the population risk of a certain disease is close to zero (e.g. one in a million), we can assume that:

plot(x = c(1:10), y = c(1:10), col = "white", ylab = "",xlab = "", axes=F)
abline(h = c(5, 1, 9), v = c(6.5,3,10))
text(x=c(4.5, 8, 2, 2), y=c(10, 10, 7, 3), c("outcome", "no outcome", "exposure", "no exposure"))
text(x=c(4.5, 8, 4.5, 8), y=c(7, 7, 3, 3), c("a", "b", "c", "d"))

\[\lim\limits_{a,c \to 0}RR=\frac{\frac{a}{a+b}}{\frac{c}{c+d}}\approx\frac{a/b}{c/d}\approx OR\]

Therefore, given the rare disease assumption, OR is a good and simplified approximation of RR.

Conclusion

Here I tried to explain in a visual and a theoretical way why the Odds Ratio is an effect size measurement that can be calculated in either a cohort or a case-control study, because they are mathematically the same. However, the risk ratio can only be calculated using a cohort study design, while a case-control will only be able to offer an odds ratio, and that is mathematically true.

Also, I explained why an odds ratio is a good approximation of the risk ratio in populations where the outcome is very rare, because when the probability of an outcome is near zero, the odds ratio becomes the risk ratio.

LS0tDQp0aXRsZTogIkEgc2ltdWxhdGlvbiBzdHVkeSINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogeWVzDQotLS0NCiMgSHlwb3RoZXRpY2FsIHBvcHVsYXRpb24NCg0KSGVyZSB3ZSdsbCB0cnkgdG8gdW5kZXJzdGFuZCB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBSaXNrIFJhdGlvIChSUikgYW5kIE9kZHMgUmF0aW8gKE9SKSBpbiBhIGh5cG90aGV0aWNhbCBzY2VuYXJpby4gRmlyc3QgSSdsbCBzZXQgYSBwb3B1bGF0aW9uIG9mIDEgbWlsbGlvbiBwZW9wbGUsIGFuZCB0aGlzIHBvcHVsYXRpb24gd2lsbCBiZSBkaXZpZGVkIGluIDIwJSB3aG8gc21va2UgYW5kIDgwJSB3aG8gZG9uJ3Qgc21va2UuDQoNCmBgYHtyfQ0KcG9wIDwtIGRhdGEuZnJhbWUoc21va2UgPSBzYW1wbGUoYygiU21va2VzIiwgIk5ldmVyU21va2VkIiksIDFlNiwgcHJvYiA9IGMoMC4yLCAwLjgpLCByZXA9IFQpKQ0KYGBgDQoNCkkgd2FudCBhIHJlbGF0aXZlIHJpc2sgb2YgfjIgd2hlbiBjb25zaWRlcmluZyB0aGUgcHJvYmFiaWxpdHkgb2Ygc29tZW9uZSB3aG8gc21va2VzIHRvIGdldCBjYW5jZXIuIFRoZXJlZm9yZSwgSSdsbCBzZXQgMiUgb2YgdGhlIHNtb2tpbmcgcG9wdWxhdGlvbiB0byBoYXZlIGNhbmNlciwgYW5kIDElIG9mIG5vbnNtb2tpbmcgcG9wdWxhdGlvbiB0byBoYXZlIGNhbmNlci4NCg0KYGBge3J9DQpwb3Bbd2hpY2gocG9wJHNtb2tlPT0iU21va2VzIiksICJjYW5jZXIiXSA8LSBzYW1wbGUoYygiQ2FuY2VyIiwgIkhlYWx0aHkiKSwgc3VtKHBvcCRzbW9rZT09IlNtb2tlcyIpLCBwcm9iID0gYygwLjAyLCAwLjk4KSwgcmVwPSBUKQ0KcG9wW3doaWNoKHBvcCRzbW9rZT09Ik5ldmVyU21va2VkIiksICJjYW5jZXIiXSA8LSBzYW1wbGUoYygiQ2FuY2VyIiwgIkhlYWx0aHkiKSwgc3VtKHBvcCRzbW9rZT09Ik5ldmVyU21va2VkIiksIHByb2IgPSBjKDAuMDEsIDAuOTkpLCByZXA9IFQpDQoNCiMgUGxvdCB0aGUgc2ltdWxhdGVkIHBvcHVsYXRpb24gaW4gYSB0cmVlbWFwDQpsaWJyYXJ5KHRyZWVtYXApDQpwb3AyIDwtIHVuaXF1ZShwb3ApDQpmb3IoaSBpbiAxOm5yb3cocG9wMikpew0KICBwb3AyW2ksICJjb3VudHMiXSA8LSBzdW0ocG9wJHNtb2tlPT1wb3AyW2ksICJzbW9rZSJdICYgcG9wJGNhbmNlcj09cG9wMltpLCAiY2FuY2VyIl0pDQp9DQoNCnRyZWVtYXAocG9wMiwgaW5kZXggPSBjKCJzbW9rZSIsICJjYW5jZXIiKSwgYXNwUmF0aW8gPSAxLA0KICAgICAgICB2U2l6ZSA9ICJjb3VudHMiLCB2Q29sb3IgPSAiY2FuY2VyIiwgYm9yZGVyLmx3ZHMgPSBjKDEsMSksDQogICAgICAgIHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBjYW5jZXIgYmV0d2VlbiBzbW9rZXJzIGFuZCBubyBzbW9rZXJzJywNCiAgICAgICAgI3BhbGV0dGUgPSAiT3JSZCIsDQogICAgICAgIHR5cGUgPSAiY2F0ZWdvcmljYWwiKQ0KYGBgDQoNCiMgQ29ob3J0IHNpbXVsYXRpb24NCg0KU28gaWYgd2UgY2FsY3VsYXRlIFJSLCB3ZSB3b3VsZCBmaW5kIGEgfjJ4IHJpc2sgb2YgY2FuY2VyIGluIHBlb3BsZSB3aG8gc21va2UsIGNvbXBhcmVkIHRvIHRob3NlIHdobyBkb24ndCBzbW9rZS4gSG93ZXZlciwgY29ob3J0IHN0dWRpZXMgYXJlIHBlcmZvcm1lZCB3aXRoIGEgcmFuZG9tIHNhbXBsZSBvZiB0aGUgcG9wdWxhdGlvbiwgbm90IHRoZSB3aG9sZSBwb3B1bGF0aW9uLiANCg0KVG8gZ2V0IGEgc2FtcGxlLCBsZXQncyBmaXJzdCBkZXRlcm1pbmUgdGhlIGFkZXF1YXRlIHNhbXBsZSBzaXplLCBhbmQgdGhlbiBkcmF3IHRoZSBlc3RpbWF0ZXMuDQoNCmBgYHtyfQ0KIyBEZXRlcm1pbmUgc2FtcGxlIHNpemUgd2l0aCBhbHBoYSA9IDUlIGFuZCBwb3dlciA9IDgwJQ0Kc2FtcGxlLnNpemUgPC0gcG93ZXIucHJvcC50ZXN0KHAxID0gMC4wMiwgcDIgPSAwLjAxLCBwb3dlciA9IDAuOCkNCg0KIyBOb3cgbGV0J3MgZHJhdyB0aGlzIGFtb3VudCBvZiBwYXRpZW50cyBmcm9tIGVhY2ggY29uZGl0aW9uIGluIG91ciBkYXRhc2V0Lg0KIyMgRHJhdyBhIHNhbXBsZSBmcm9tIHNtb2tlcnMgKHdlIHN0aWxsIGRvbid0IGtub3cgaWYgdGhleSB3aWxsIGdldCBjYW5jZXIgb3Igbm90KQ0Kc2FtcGxlLnNtb2tlcyA8LSBwb3Bbd2hpY2gocG9wJHNtb2tlPT0iU21va2VzIiksXVtzYW1wbGUoYygxOnN1bShwb3Akc21va2U9PSJTbW9rZXMiKSksIHNhbXBsZS5zaXplJG4sIHJlcGxhY2UgPSBGKSxdDQojIyBEcmF3IGEgc2FtcGxlIGZyb20gbm9uc21va2VycyAod2Ugc3RpbGwgZG9uJ3Qga25vdyBpZiB0aGV5IHdpbGwgZ2V0IGNhbmNlciBvciBub3QpDQpzYW1wbGUubmV2ZXJzbW9rZWQgPC0gcG9wW3doaWNoKHBvcCRzbW9rZT09Ik5ldmVyU21va2VkIiksXVtzYW1wbGUoYygxOnN1bShwb3Akc21va2U9PSJOZXZlclNtb2tlZCIpKSwgc2FtcGxlLnNpemUkbiwgcmVwbGFjZSA9IEYpLF0NCg0KIyBDaGVjayBvdXIgUlINCmEgPC0gc3VtKHNhbXBsZS5zbW9rZXMkY2FuY2VyID09ICJDYW5jZXIiKS9zdW0obnJvdyhzYW1wbGUuc21va2VzKSkNCmIgPC0gc3VtKHNhbXBsZS5uZXZlcnNtb2tlZCRjYW5jZXIgPT0gIkNhbmNlciIpL3N1bShucm93KHNhbXBsZS5uZXZlcnNtb2tlZCkpDQphL2INCmBgYA0KDQpXZSBzZWUgdGhhdCBldmVyeXRpbWUgdGhpcyBzY3JpcHQgaXMgcnVuLCBpdCByZXR1cm5zIGEgZGlmZmVyZW50IHZhbHVlIGZvciBSUi4gVGhpcyBpcyBiZWNhdXNlIHNhbXBsaW5nIGVycm9yIG9jY3VycywgdGhhdCBpcyB3aHkgYWxwaGEgaXMgNSUgYW5kIHBvd2VyIGlzIDgwJS4gV2UgZXhwZWN0IGEgcmF0ZSBvZiBmYWxzZSBwb3NpdGl2ZXMgYW5kIGZhbHNlIG5lZ2F0aXZlcy4NCg0KV2UgY2FuIHBsb3QgdGhlIGRpZmZlcmVuY2VzIGluIFJSIGFmdGVyIDQwIGRpZmZlcmVudCBtZWFzdXJlbWVudHMgKHdoaWNoIGlzIGVxdWl2YWxlbnQgdG8gNDAgZGlmZmVyZW50IHN0dWRpZXMgbG9va2luZyBhdCB0aGUgc2FtZSBwb3B1bGF0aW9uLCBlYWNoIG9uZSBmaW5kaW5nIGEgZGlmZmVyZW50IFJSIHZhbHVlLg0KDQojIyBNdWx0aXBsZSBwbG90cw0KDQpgYGB7ciBlY2hvPVRSVUV9DQojIFJlYWwgUlINCmEgPC0gc3VtKHBvcCRzbW9rZT09IlNtb2tlcyIgJiBwb3AkY2FuY2VyPT0iQ2FuY2VyIikvc3VtKHBvcCRzbW9rZT09IlNtb2tlcyIpDQpiIDwtIHN1bShwb3Akc21va2U9PSJOZXZlclNtb2tlZCIgJiBwb3AkY2FuY2VyPT0iQ2FuY2VyIikvc3VtKHBvcCRzbW9rZT09Ik5ldmVyU21va2VkIikNClJlYWxSUiA8LSBhL2INCg0KIyBTYW1wbGUgUlINClNhbXBsZVJSIDwtIGMoKQ0KZm9yKGkgaW4gMTo0MCl7DQogIHNhbXBsZS5zbW9rZXMgPC0gcG9wW3doaWNoKHBvcCRzbW9rZT09IlNtb2tlcyIpLF1bc2FtcGxlKGMoMTpzdW0ocG9wJHNtb2tlPT0iU21va2VzIikpLCBzYW1wbGUuc2l6ZSRuLCByZXBsYWNlID0gRiksXQ0KICBzYW1wbGUubmV2ZXJzbW9rZWQgPC0gcG9wW3doaWNoKHBvcCRzbW9rZT09Ik5ldmVyU21va2VkIiksXVtzYW1wbGUoYygxOnN1bShwb3Akc21va2U9PSJOZXZlclNtb2tlZCIpKSwgc2FtcGxlLnNpemUkbiwgcmVwbGFjZSA9IEYpLF0NCiAgYSA8LSBzdW0oc2FtcGxlLnNtb2tlcyRjYW5jZXIgPT0gIkNhbmNlciIpL3N1bShucm93KHNhbXBsZS5zbW9rZXMpKQ0KICBiIDwtIHN1bShzYW1wbGUubmV2ZXJzbW9rZWQkY2FuY2VyID09ICJDYW5jZXIiKS9zdW0obnJvdyhzYW1wbGUubmV2ZXJzbW9rZWQpKQ0KICBTYW1wbGVSUltpXSA8LSBhL2INCn0NCg0KIyBQbG90IGRpZmZlcmVuY2VzDQpsaWJyYXJ5KGdncGxvdDIpDQpnZ3Bsb3QoZGF0YSA9IGRhdGEuZnJhbWUoUlIgPSBjKFJlYWxSUiwgU2FtcGxlUlIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBHcm91cCA9IGMoIlJlYWwiLCByZXAoIlNhbXBsZSIsIDQwKSkpLA0KICAgICAgIGFlcyh4ID0gR3JvdXAsIHkgPSBSUikpICsNCiAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvdXI9R3JvdXApKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFlcyhjb2xvdXI9R3JvdXApKQ0KYGBgDQoNCk5vdyB3ZSBjYW4gc2VlIHRoZSBlcnJvciBpbnRyb2R1Y2VkIGJ5IHNhbXBsaW5nLiBMZXQncyBqdW1wIHRvIGEgY2FzZS1jb250cm9sIHNpbXVsYXRpb24gdG8gc2VlIHdoYXQgd2UgY2FuIGxlYXJuLg0KDQojIENhc2UtY29udHJvbCBzaW11bGF0aW9uDQoNCkxldCdzIHByb2NlZWQgdG8gdGhlIGVzdGltYXRlIG9mIE9kZHMgUmF0aW8gaW4gYSBjYXNlLWNvbnRyb2wgc2ltdWxhdGlvbi4gRm9yIGEgY2FzZS1jb250cm9sIHN0dWR5LCB3ZSdsbCBkcmF3IGEgc2FtcGxlIGZyb20gcmFuZG9tIHBlb3BsZSB3aG8gaGF2ZSBjYW5jZXIsIGFuZCB0aGUgc2FtZSBudW1iZXIgb2YgcGVvcGxlIHdobyBkb24ndCBoYXZlIGNhbmNlciwgYW5kIGNoZWNrIGlmIHRoZXkgaGF2ZSBzbW9rZWQgb3Igbm90IGluIHRoZSBwYXN0Lg0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSBzYW1wbGUgc2l6ZSBmb3IgYSBjYXNlLWNvbnRyb2wgc3R1ZHkNCmxpYnJhcnkoZXBpUikNCnNhbXBsZS5zaXplLmNjIDwtIGVwaS5zc2NjKE9SID0gMiwgcDAgPSAwLjIsIHBvd2VyID0gMC44LCBuID0gTkEpJG4uY2FzZQ0KDQojIERyYXcgc2FtcGxlcyBvZiBwZW9wbGUgd2hvIGhhdmUgY2FuY2VyIG9yIG5vdC4NCnNhbXBsZS5jYW5jZXIgPC0gcG9wW3doaWNoKHBvcCRjYW5jZXI9PSJDYW5jZXIiKSxdW3NhbXBsZShjKDE6c3VtKHBvcCRjYW5jZXI9PSJDYW5jZXIiKSksIHNhbXBsZS5zaXplLmNjLCByZXBsYWNlID0gRiksXQ0Kc2FtcGxlLmhlYWx0aHkgPC0gcG9wW3doaWNoKHBvcCRjYW5jZXI9PSJIZWFsdGh5IiksXVtzYW1wbGUoYygxOnN1bShwb3AkY2FuY2VyPT0iSGVhbHRoeSIpKSwgc2FtcGxlLnNpemUuY2MsIHJlcGxhY2UgPSBGKSxdDQoNCiMgRGV0ZXJtaW5lIDQwIE9SIGNhbGN1bGF0aW9ucw0KT1I4MCA8LSBjKCkNCmZvcihpIGluIDE6NDApew0KICBzYW1wbGUuY2FuY2VyIDwtIHBvcFt3aGljaChwb3AkY2FuY2VyPT0iQ2FuY2VyIiksXVtzYW1wbGUoYygxOnN1bShwb3AkY2FuY2VyPT0iQ2FuY2VyIikpLCBzYW1wbGUuc2l6ZS5jYywgcmVwbGFjZSA9IEYpLF0NCnNhbXBsZS5oZWFsdGh5IDwtIHBvcFt3aGljaChwb3AkY2FuY2VyPT0iSGVhbHRoeSIpLF1bc2FtcGxlKGMoMTpzdW0ocG9wJGNhbmNlcj09IkhlYWx0aHkiKSksIHNhbXBsZS5zaXplLmNjLCByZXBsYWNlID0gRiksXQ0KICBhIDwtIHN1bShzYW1wbGUuY2FuY2VyJHNtb2tlID09ICJTbW9rZXMiKS9zdW0oc2FtcGxlLmhlYWx0aHkkc21va2UgPT0gIlNtb2tlcyIpDQogIGIgPC0gc3VtKHNhbXBsZS5jYW5jZXIkc21va2UgPT0gIk5ldmVyU21va2VkIikvc3VtKHNhbXBsZS5oZWFsdGh5JHNtb2tlID09ICJOZXZlclNtb2tlZCIpDQogIE9SODBbaV0gPC0gYS9iDQp9DQoNCiMgUGxvdCBkaWZmZXJlbmNlcw0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKFJSID0gYyhSZWFsUlIsIE9SODApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBHcm91cCA9IGMoIlJlYWwiLCByZXAoIk9kZHMgUmF0aW8iLCA0MCkpKSwNCiAgICAgICBhZXMoeCA9IEdyb3VwLCB5ID0gUlIpKSArDQogIGdlb21fYm94cGxvdChhZXMoY29sb3VyPUdyb3VwKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBhZXMoY29sb3VyPUdyb3VwKSkNCmBgYA0KDQpUaGUgT1IgZGlzdHJpYnV0aW9uIGlzIHZlcnkgY2xvc2UgdG8gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgUlIgY2FsY3VsYXRpb25zLiANCg0KIyMgQWxsIHBsb3RzIGNvbXBhcmVkDQoNCkxldCB1cyBjb21wYXJlIHRoZSBPZGRzIFJhdGlvIGFuZCB0aGUgUmlzayBSYXRpbyBvYnRhaW5lZCBwcmV2aW91c2x5Lg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZGF0YS5mcmFtZShSUiA9IGMoUmVhbFJSLCBTYW1wbGVSUiwgT1I4MCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIEdyb3VwID0gYygiUmVhbCIsIHJlcCgiUmlzayBSYXRpbyIsIDQwKSwgcmVwKCJPZGRzIFJhdGlvIiwgNDApKSksDQogICAgICAgYWVzKHggPSBHcm91cCwgeSA9IFJSKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGNvbG91cj1Hcm91cCkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywgYWVzKGNvbG91cj1Hcm91cCkpDQpgYGANCg0KV2UgY2FuIHNlZSB2ZXJ5IGNsZWFybHkgdGhhbiB1bmRlciBvcHRpbWFsIGNpcmN1bXN0YW5jZXMsIHRoZSBPZGRzIFJhdGlvIGlzIHZlcnkgY2xvc2UgdG8gdGhlIFJpc2sgUmF0aW8sIHdoaWNoIGluIHR1cm4gaXMgYSBnb29kLCBidXQgZmFyIGZyb20gcGVyZmVjdCwgZXN0aW1hdGUgb2YgdGhlIHRydWUgcmlzay4NCg0KTm90IGxldCdzIHRyeSBzb21ldGhpbmcgZm9yYmlkZGVuIGJ5IHRoZSBydWxlcyBvZiBzdGF0aXN0aWNzLiBUaGUgUmlzayBSYXRpbyBzaG91bGQgbm90IGJlIGNhbGN1bGF0ZWQgdXNpbmcgYSBjYXNlLWNvbnRyb2wgZGVzaWduIChzZWUgYmVsb3cgdGhlICoqTWF0aCoqIHNlY3Rpb24pLCBidXQgbGV0J3MgZG8gaXQgaGVyZSwgYmVjYXVzZSBtYW55IHBlb3BsZSBsZWFybnMgYmVzdCB3aGVuIHRoZXkgc2VlIGltYWdlcy4gQWRkaXRpb25hbGx5LCBJJ2xsIGNhbGN1bGF0ZSBhbiBPZGRzIFJhdGlvIGZyb20gdGhlIENvaG9ydCBzdHVkeSBhYm92ZSwgd2hpY2ggaXMgYWxsb3dlZC4NCg0KYGBge3J9DQojIERldGVybWluZSA0MCBmb3JiaWRkZW4gUlIgY2FsY3VsYXRpb25zIGZyb20gY2FzZS1jb250cm9sIHN0dWRpZXMNCmZvcmJpZGRlblJSIDwtIGMoKQ0KZm9yKGkgaW4gMTo0MCl7DQogIHNhbXBsZS5jYW5jZXIgPC0gcG9wW3doaWNoKHBvcCRjYW5jZXI9PSJDYW5jZXIiKSxdW3NhbXBsZShjKDE6c3VtKHBvcCRjYW5jZXI9PSJDYW5jZXIiKSksIHNhbXBsZS5zaXplLmNjLCByZXBsYWNlID0gRiksXQ0Kc2FtcGxlLmhlYWx0aHkgPC0gcG9wW3doaWNoKHBvcCRjYW5jZXI9PSJIZWFsdGh5IiksXVtzYW1wbGUoYygxOnN1bShwb3AkY2FuY2VyPT0iSGVhbHRoeSIpKSwgc2FtcGxlLnNpemUuY2MsIHJlcGxhY2UgPSBGKSxdDQogIHNtb2tlZCA8LSBzdW0oc2FtcGxlLmNhbmNlciRzbW9rZSA9PSAiU21va2VzIikgKyBzdW0oc2FtcGxlLmhlYWx0aHkkc21va2UgPT0gIlNtb2tlcyIpDQogIG5ldmVyc21va2VkIDwtIHN1bShzYW1wbGUuY2FuY2VyJHNtb2tlID09ICJOZXZlclNtb2tlZCIpICsgc3VtKHNhbXBsZS5oZWFsdGh5JHNtb2tlID09ICJOZXZlclNtb2tlZCIpDQogIGEgPC0gc3VtKHNhbXBsZS5jYW5jZXIkc21va2UgPT0gIlNtb2tlcyIpL3Ntb2tlZA0KICBiIDwtIHN1bShzYW1wbGUuY2FuY2VyJHNtb2tlID09ICJOZXZlclNtb2tlZCIpL25ldmVyc21va2VkDQogIGZvcmJpZGRlblJSW2ldIDwtIGEvYg0KfQ0KDQojIERldGVybWluZSA0MCBhbGxvd2VkIE9SIGNhbGN1bGF0aW9ucyBmcm9tIGNvaG9ydCBzdHVkaWVzDQphbGxvd2VkT1IgPC0gYygpDQpmb3IoaSBpbiAxOjQwKXsNCiAgc2FtcGxlLnNtb2tlcyA8LSBwb3Bbd2hpY2gocG9wJHNtb2tlPT0iU21va2VzIiksXVtzYW1wbGUoYygxOnN1bShwb3Akc21va2U9PSJTbW9rZXMiKSksIHNhbXBsZS5zaXplJG4sIHJlcGxhY2UgPSBGKSxdDQogIHNhbXBsZS5uZXZlcnNtb2tlZCA8LSBwb3Bbd2hpY2gocG9wJHNtb2tlPT0iTmV2ZXJTbW9rZWQiKSxdW3NhbXBsZShjKDE6c3VtKHBvcCRzbW9rZT09Ik5ldmVyU21va2VkIikpLCBzYW1wbGUuc2l6ZSRuLCByZXBsYWNlID0gRiksXQ0KICBhIDwtIHN1bShzYW1wbGUuc21va2VzJGNhbmNlciA9PSAiQ2FuY2VyIikvc3VtKHNhbXBsZS5zbW9rZXMkY2FuY2VyID09ICJIZWFsdGh5IikNCiAgYiA8LSBzdW0oc2FtcGxlLm5ldmVyc21va2VkJGNhbmNlciA9PSAiQ2FuY2VyIikvc3VtKHNhbXBsZS5uZXZlcnNtb2tlZCRjYW5jZXIgPT0gIkhlYWx0aHkiKQ0KICBhbGxvd2VkT1JbaV0gPC0gYS9iDQp9DQoNCiMgUGxvdCBkaWZmZXJlbmNlcw0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKFJSID0gYyhSZWFsUlIsIE9SODAsIGZvcmJpZGRlblJSLCBTYW1wbGVSUiwgYWxsb3dlZE9SKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgRWZmZWN0LnNpemUgPSBjKCJSZWFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiT1IiLCA0MCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoIlJSIiwgNDApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJSUiIsIDQwKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiT1IiLCA0MCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIFN0dWR5LnR5cGUgPSBjKCJSZWFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiY2FzZS1jb250cm9sIiwgNDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoImNhc2UtY29udHJvbCIsIDQwKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiY29ob3J0IiwgNDApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJjb2hvcnQiLCA0MCkpKSwNCiAgICAgICBhZXMoeCA9IFN0dWR5LnR5cGUsIHkgPSBSUikpICsNCiAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvdXI9RWZmZWN0LnNpemUpKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjc1KSwgYWVzKGNvbG91cj1FZmZlY3Quc2l6ZSkpDQpgYGANCg0KDQpUaGlzIHNob3dzIHNvbWV0aGluZyByZWFsbHkgaW50ZXJlc3RpbmcuIFdlIGNhbiBzZWUgdGhhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiB0aGUgImFsbG93ZWQiIGNhbGN1bGF0aW9ucyBhcmUgYWxsIHNpbWlsYXIsIGFuZCB0aGV5IHdhbmRlciBhcm91bmQgdGhlICoqdHJ1ZSoqIHJpc2sgZmlndXJlLiBIb3dldmVyLCB0aGUgImZvcmJpZGRlbiIgY2FsY3VsYXRpb24sIHdoaWNoIGlzIHRoZSBSUiBpbiBhIGNhc2UtY29udHJvbCBzdHVkeSwgaGFzIGEgcmVhbGx5IG5hcnJvdyBkaXN0cmlidXRpb24gb2YgdmFsdWVzIHRoYXQgbmV2ZXIgZ2V0IGNsb3NlIHRvIHRoZSB0cnVlIGZpZ3VyZS4gTm93IGxldCdzIHRyeSB0byB1bmRlcnN0YW5kIHNvbWUgbWF0aCBiZWhpbmQgdGhpcy4NCg0KIyBNYXRoDQoNCkJlZm9yZSBJIHByb2NlZWQsIGxldCBtZSBleHBsYWluIHNvbWUgbm90YXRpb25zLiAkUChYKSQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIFggaGFwcGVuaW5nLiAkUChYfFkpJCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgWCBoYXBwZW5pbmcsIGdpdmVuIHRoYXQgWSBoYXZlIGFscmVhZHkgaGFwcGVuZWQuIFRoaXMgaXMgYSAqQmF5ZXNpYW4qIHByb2JhYmlsaXR5LiBUaGVyZSBhcmUgd2F5cyB0byBleHBhbmQgYSBiYXllc2lhbiBwcm9iYWJpbGl0eSB0byBkZWFsIHdpdGggZGlmZmVyZW50IHNpdHVhdGlvbnMsIGZvciBleGFtcGxlOg0KDQokUChYKSA9IDEgLSBQKFxuZWd7WH0pJA0KDQokUChYKSA9IFAoWHxZKVAoWSkgKyBQKFh8XG5lZ3tZfSlQKFxuZWd7WX0pJA0KDQokUChYfFkpID0gXGZyYWN7UChYKVAoWXxYKX17UChZKX0kDQoNCiRQKFh8WSkgPSBcZnJhY3tQKFh8XG5lZ3t9WSlQKFxuZWd7fVkpUChZfFgpfXtQKFxuZWd7fVl8WClQKFkpfSQNCg0KJFAoWHxZKSA9IDEgLSBQKFxuZWd7WH18WSkkDQoNClRoZXNlIGFyZSBqdXN0IGEgZmV3IGV4YW1wbGVzIG9mIGFyaXRobWV0aWNzIHRoYXQgY2FuIGJlIGRvbmUgd2hlbiB0aGUgbWVhc3VyZXMgYXJlIGJpbmFyeS4NCg0KQWxzbywgdG8gYXZvaWQgZ2lnYW50aWMgZm9ybXVsYXMgYWhlYWQsIGxldCdzIHJlcGxhY2UgImNhbmNlciIgKGJpbmFyeSBvdXRjb21lKSBhbmQgInNtb2tlZCIgKGJpbmFyeSBleHBvc3VyZSkgd2l0aCBYIGFuZCBZLCByZXNwZWN0aXZlbHkuDQoNCiRYID0gY2FuY2VyJA0KDQokWSA9IHNtb2tlZCQNCg0KJFxuZWd7WH09aGVhbHRoeSQNCg0KJFxuZWd7WX09bmV2ZXJzbW9rZWQkDQoNCiMjIFBvcHVsYXRpb24gcmlzaw0KDQpTbyBpZiB5b3UgaGFkIHRoZSBjb21wbGV0ZSBkYXRhIGZvciB0aGUgd2hvbGUgcG9wdWxhdGlvbiwgaXQgd291bGQgYmUgZWFzeSB0byBjYWxjdWxhdGUgdGhlIHJpc2tzIGFuZCB0aGUgb2Rkcy4gVGhlICoqYWJzb2x1dGUgcmlzayoqIG9mIGhhdmluZyBjYW5jZXIsIGlmIHlvdSBzbW9rZWQsIHdvdWxkIGJlOg0KJCRSaXNrX3twb3B9ID0gUChYfFkpJCQNCkFuZCB0aGUgKipyaXNrIHJhdGlvKiogYmV0d2VlbiBoYXZpbmcgY2FuY2VyIGlmIHlvdSBzbW9rZWQsIGFuZCBoYXZpbmcgY2FuY2VyIGlmIHlvdSBkaWRuJ3Qgc21va2UsIHdvdWxkIGJlOg0KJCRSUl97cG9wfSA9IFxmcmFje1AoWHxZKX17UChYfFxuZWd7WX0pfSQkDQojIyBTYW1wbGUgcmlzaw0KDQpOb3csIGlmIHlvdSBhcmUgKnNhbXBsaW5nKiBmcm9tIGEgcG9wdWxhdGlvbiwgdGhpbmdzIGdldCBhIGxpdHRsZSBkaWZmZXJlbnQsIGRlcGVuZGluZyBvbiB0aGUgc2FtcGxpbmcgZGVzaWduLiBUaGF0J3MgYmVjYXVzZSB3aGVuIHlvdSBzYW1wbGUsIHlvdSdyZSBkcmF3aW5nIGZyb20gYSBwb3B1bGF0aW9uIHdpdGggYSBzcGVjaWZpYyBwcm9iYWJpbGl0eS4gSWYgeW91IHNhbXBsZSBwZW9wbGUgYmFzZWQgb24gdGhlaXIgZXhwb3N1cmUgc3RhdHVzICgqKmNvaG9ydCBkZXNpZ24qKiksIGFuZCB0aGVuIHdhaXQgdW50aWwgeW91IHNlZSB0aGUgb3V0Y29tZSwgeW91IHdvdWxkIGhhdmUNCiQkUmlza197Y29ob3J0fT1cZnJhY3tQKFh8WSl9e1AoWHxZKStQKFxuZWd7WH18WSl9PVxmcmFje1AoWHxZKX17MX09Umlza197cG9wfSQkDQpXaGljaCBpcyBwcmVjaXNlbHkgdGhlIHNhbWUgYXMgY2FsY3VsYXRpbmcgdGhlIHBvcHVsYXRpb24gcmlzay4gVGhlbiBpZiB5b3UgdHJ5IGNhbGN1bGF0aW5nIHRoZSAqKnJpc2sgcmF0aW8qKg0KDQokJFJSX3tjb2hvcnR9ID0gXGZyYWN7XGZyYWN7UChYfFkpfXtQKFh8WSkrUChcbmVne1h9fFkpfX17XGZyYWN7UChYfFxuZWd7WX0pfXtQKFh8XG5lZ3tZfSkrUChcbmVne1h9fFxuZWd7WX0pfX09XGZyYWN7XGZyYWN7UChYfFkpfXsxfX17XGZyYWN7UChYfFxuZWd7WX0pfXsxfX09UlJfe3BvcH0kJA0KDQpZb3Ugd291bGQgYWxzbyBmaW5kIHRoYXQgaXQgd291bGQgYmUgbWF0aGVtYXRpY2FsbHkgdGhlIHNhbWUgYXMgdGhlIHBvcHVsYXRpb24gUlIuIFNvIGEgKipjb2hvcnQgc3R1ZHkqKiBoYXMgdGhlIHBlcmZlY3QgZGVzaWduIGZvciBjYWxjdWxhdGluZyB0aGUgcG9wdWxhdGlvbiByaXNrLCBnaXZlbiB0aGF0IHRoZSBzYW1wbGluZyB3YXMgcmFuZG9tLg0KDQpIb3dldmVyLCBpZiB5b3Ugc2FtcGxlZCBwZW9wbGUgYmFzZWQgb24gdGhlaXIgb3V0Y29tZSBzdGF0dXMgKCoqY2FzZS1jb250cm9sIGRlc2lnbioqKSwgYW5kIHRoZW4gY2hlY2tlZCB3aGV0aGVyIHRoZXkgd2VyZSBleHBvc2VkIG9yIG5vdCwgeW91IHdvdWxkIGdldCBhIHZlcnkgZGlmZmVyZW50IHByb2JhYmlsaXR5LCB0aGF0IGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBmaW5kaW5nIGFuIGV4cG9zdXJlLCBnaXZlbiB0aGF0IHlvdSBrbm93IHRoZSBvdXRjb21lOg0KJCRSaXNrX3tjYXNlLWNvbnRyb2x9PVxmcmFje1AoWXxYKX17UChZfFgpK1AoWXxcbmVne1h9KX1cbmV7fVAoWHxZKSwgUmlza197Y2FzZS1jb250cm9sfVxuZXt9Umlza197cG9wfSQkDQokJFJSX3tjYXNlLWNvbnRyb2x9ID0gXGZyYWN7XGZyYWN7UChZfFgpfXtQKFl8WCkrUChZfFxuZWd7WH0pfX17XGZyYWN7UChcbmVne1l9fFgpfXtQKFxuZWd7WX18WCkrUChcbmVne1l9fFxuZWd7WH0pfX1cbmV7fVxmcmFje1AoWHxZKX17UChYfFxuZWd7WX0pfSwgUlJfe2Nhc2UtY29udHJvbH1cbmV7fVJSX3twb3B9JCQNCklmIHlvdSB0cnkgdG8gc29sdmUgaXQsIHlvdSB3aWwgZmluZCB0aGF0ICRSUl97Y2FzZS1jb250cm9sfVxuZXtSUn0kLg0KDQojIyBQb3B1bGF0aW9uIG9kZHMNCg0KVGhlIG9kZHMgb2Ygc29tZXRoaW5nIGhhcHBlbmluZyBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgaXQgaGFwcGVuaW5nIGRpdmlkZWQgYnkgdGhlIHByb2JhYmlsaXR5IG9mIGl0IG5vdCBoYXBwZW5pbmcuIEZvciBleGFtcGxlLCB5b3Ugd291bGQgaGF2ZSA0IHRpbWVzIChvZGRzKSBtb3JlIGNoYW5jZSBvZiB3aW5uaW5nIHRoYW4gb2YgbG9zaW5nIGlmIHRoZSBwcm9iYWJpbGl0eSBvZiB3aW5uaW5nIHdhcyA4MCUsIGJlY2F1c2UgeW91IHdvdWxkIGRpdmlkZSA4MCUgYnkgMjAlLiBTbyB0aGUgY2hhbmNlIG9mIGNhbmNlciwgaWYgeW91IHNtb2tlZCwgd291bGQgYmU6DQoNCiQkT2Rkc197cG9wfSA9IFxmcmFje1AoWHxZKX17UChcbmVne1h8WX0pfSQkDQpBbmQgdGhlIE9kZHMgUmF0aW8gd291bGQgYmUgdGhlIHJhdGlvIGJldHdlZW4gdGhlIG9kZHMgb2YgY2FuY2VyIGlmIHlvdSBzbW9rZWQsIGFuZCB0aGUgb2RkcyBvZiBjYW5jZXIsIGlmIHlvdSBkaWRuJ3Qgc21va2UuDQoNCiQkT1Jfe3BvcH0gPSBcZnJhY3tcZnJhY3tQKFh8WSl9e1AoXG5lZ3tYfFl9KX19e1xmcmFje1AoWHxcbmVne31ZKX17UChcbmVne1h8XG5lZ3t9WX0pfX0kJA0KDQojIyBTYW1wbGUgb2Rkcw0KDQpJZiB5b3Ugd2VyZSBkb2luZyBhICoqY2FzZS1jb250cm9sKiogc3R1ZHksIGluIHdoaWNoIHRoZSBPZGRzIFJhdGlvIHdvdWxkIGJlIHRoZSBjaG9pY2UgZm9yIG1lYXN1cmluZyB0aGUgKiplZmZlY3Qgc2l6ZSoqLCB5b3Ugd291bGQgYmUgY2FsY3VsYXRpbmcgdGhpczoNCg0KJCRPUl97Y2FzZS1jb250cm9sfSA9IFxmcmFje1xmcmFje1xmcmFje1AoWSlQKFh8WSl9e1AoWCl9fXtcZnJhY3tQKFkpUChcbmVne31YfFkpfXtQKFxuZWd7fVgpfX19e1xmcmFje1xmcmFje1AoXG5lZ3t9WSlQKFh8XG5lZ3t9WSl9e1AoWCl9fXtcZnJhY3tQKFxuZWd7fVkpUChcbmVne31YfFxuZWd7fVkpfXtQKFxuZWd7fVgpfX19ID0gXGZyYWN7XGZyYWN7XGZyYWN7MS5QKFh8WSl9ezF9fXtcZnJhY3sxLlAoXG5lZ3t9WHxZKX17MX19fXtcZnJhY3tcZnJhY3sxLlAoWHxcbmVne31ZKX17MX19e1xmcmFjezEuUChcbmVne31YfFxuZWd7fVkpfXsxfX19ID0gXGZyYWN7XGZyYWN7UChYfFkpfXtQKFxuZWd7fVh8WSl9fXtcZnJhY3tQKFh8XG5lZ3t9WSl9e1AoXG5lZ3t9WHxcbmVne31ZKX19ID0gT1Jfe3BvcH0kJA0KDQoNCkkgd29uJ3Qgd3JpdGUgaGVyZSB0aGUgZXF1YXRpb24gZm9yIHRoZSBPZGRzIFJhdGlvIGluIGEgY2FzZS1jb250cm9sIHN0dWR5LCBiZWNhdXNlIGl0IHdvdWxkIGJlIGV4YWN0bHkgdGhlIHNhbWUgYXMgdGhlIHBvcHVsYXRpb24gb2RkcyByYXRpbywgdGhlcmVmb3JlIHRoZXkgYXJlIHRoZSBzYW1lLg0KDQojIyBXaGVuIE9SIH4gUlINCg0KV2hlbmV2ZXIgdGhlIHBvcHVsYXRpb24gcmlzayBvZiBhIGNlcnRhaW4gZGlzZWFzZSBpcyBjbG9zZSB0byB6ZXJvIChlLmcuIG9uZSBpbiBhIG1pbGxpb24pLCB3ZSBjYW4gYXNzdW1lIHRoYXQ6DQoNCmBgYHtyfQ0KcGxvdCh4ID0gYygxOjEwKSwgeSA9IGMoMToxMCksIGNvbCA9ICJ3aGl0ZSIsIHlsYWIgPSAiIix4bGFiID0gIiIsIGF4ZXM9RikNCmFibGluZShoID0gYyg1LCAxLCA5KSwgdiA9IGMoNi41LDMsMTApKQ0KdGV4dCh4PWMoNC41LCA4LCAyLCAyKSwgeT1jKDEwLCAxMCwgNywgMyksIGMoIm91dGNvbWUiLCAibm8gb3V0Y29tZSIsICJleHBvc3VyZSIsICJubyBleHBvc3VyZSIpKQ0KdGV4dCh4PWMoNC41LCA4LCA0LjUsIDgpLCB5PWMoNywgNywgMywgMyksIGMoImEiLCAiYiIsICJjIiwgImQiKSkNCmBgYA0KDQoNCiQkXGxpbVxsaW1pdHNfe2EsYyBcdG8gMH1SUj1cZnJhY3tcZnJhY3thfXthK2J9fXtcZnJhY3tjfXtjK2R9fVxhcHByb3hcZnJhY3thL2J9e2MvZH1cYXBwcm94IE9SJCQNCg0KVGhlcmVmb3JlLCBnaXZlbiB0aGUgKipyYXJlIGRpc2Vhc2UgYXNzdW1wdGlvbioqLCBPUiBpcyBhIGdvb2QgYW5kIHNpbXBsaWZpZWQgYXBwcm94aW1hdGlvbiBvZiBSUi4NCg0KDQoNCiMgQ29uY2x1c2lvbg0KDQpIZXJlIEkgdHJpZWQgdG8gZXhwbGFpbiBpbiBhIHZpc3VhbCBhbmQgYSB0aGVvcmV0aWNhbCB3YXkgd2h5IHRoZSBPZGRzIFJhdGlvIGlzIGFuIGVmZmVjdCBzaXplIG1lYXN1cmVtZW50IHRoYXQgY2FuIGJlIGNhbGN1bGF0ZWQgaW4gZWl0aGVyIGEgKipjb2hvcnQqKiBvciBhICoqY2FzZS1jb250cm9sKiogc3R1ZHksIGJlY2F1c2UgdGhleSBhcmUgbWF0aGVtYXRpY2FsbHkgdGhlIHNhbWUuIEhvd2V2ZXIsIHRoZSAqKnJpc2sgcmF0aW8qKiBjYW4gb25seSBiZSBjYWxjdWxhdGVkIHVzaW5nIGEgY29ob3J0IHN0dWR5IGRlc2lnbiwgd2hpbGUgYSBjYXNlLWNvbnRyb2wgd2lsbCBvbmx5IGJlIGFibGUgdG8gb2ZmZXIgYW4gKipvZGRzIHJhdGlvKiosIGFuZCB0aGF0IGlzIG1hdGhlbWF0aWNhbGx5IHRydWUuDQoNCkFsc28sIEkgZXhwbGFpbmVkIHdoeSBhbiBvZGRzIHJhdGlvIGlzIGEgZ29vZCBhcHByb3hpbWF0aW9uIG9mIHRoZSByaXNrIHJhdGlvIGluIHBvcHVsYXRpb25zIHdoZXJlIHRoZSBvdXRjb21lIGlzIHZlcnkgcmFyZSwgYmVjYXVzZSB3aGVuIHRoZSBwcm9iYWJpbGl0eSBvZiBhbiBvdXRjb21lIGlzIG5lYXIgemVybywgdGhlIG9kZHMgcmF0aW8gKmJlY29tZXMqIHRoZSByaXNrIHJhdGlvLg==