The R code is hidden by default. Please click on Show to view all codes. Thank you.

Assignment 4

Question 1. Alumni Donation Data

Import Data and load libraries from URL: https://bgreenwell.github.io/uc-bana7052/data/alumni.csv

url <- "https://bgreenwell.github.io/uc-bana7052/data/alumni.csv"
alumni <- read.csv(url)
str(alumni)
attach(alumni)
library(tidyverse)
library(investr)
library(car)
library(lmtest)
library(gridExtra)

1) Does the assumption of error normality appear to be violated?

To see if the error normality is violated or not, I am going to use a QQ plot to diagnose it. First I am going to fit the data to a linear regression model.

# fit the model
fit <- lm(alumni_giving_rate ~ percent_of_classes_under_20 + student_faculty_ratio)

# residual diagnostics
qqnorm(residuals(fit), main = "Right-skewed Distribution")
qqline(residuals(fit), col = "blue")

From the QQ plot we can see that the majority of the points are on the straight line while some of the of points are above the line. This tells us that it’s right-skewed.

We can also use the Shapiro-Wilk test to exam the p value:

shapiro.test(residuals(fit))

    Shapiro-Wilk normality test

data:  residuals(fit)
W = 0.94577, p-value = 0.02721

The P value from the Shapiro-Wilk normality test is 0.027, which is less than the threshold value of 0.05, so it indicates the non-normality.

2) Does the assumption of constant error variance appear to be violated?

To diagnose that, I am going to compare the Residuals VS Fitted Values plot. I will be getting the studentized residual and fitted values.

# studentized residual
r.stu <- rstandard(fit)
# fitted value
f.val <- fitted(fit)
plot(f.val, y = r.stu, xlab = "Fitted Value", ylab = "Studentized Residual")
abline(h = c(-2, 0,2), lty = 2, col = 2)

From the Residual vs Fitted value plot, we can see that most points are scattered around the 0 reference line and within the -2 to +2 range. It suggests the assumtpion of constant variance may hold.

We can also use Breush-Pagan test to see if there is non-constant variance.

bptest(fit)

    studentized Breusch-Pagan test

data:  fit
BP = 0.2723, df = 2, p-value = 0.8727

We can see that the P value is 0.8727 which is larger than the 0.05 threshold, this suggests that there is no strong evidence of heteroscedasticity, so we can say that the constant variance is not violated.

3) Does there appear to be any Y or X outliers or influential points?

To detect if there are outliers or influential points, I am going to use the Cook’s distance and leverage plots.

h <- hatvalues(fit)
out <- which(h > 2 * mean(h))
plot(h, type = "h", ylim = extendrange(h, f = 0.15), main = "High Leverage Points")
abline(h = 2 * mean(h), col = 2)
text(out, y = h[out], labels = out, pos = 3, col = 3)

influencePlot(fit)

We can see from the High Leverage Points plot that there are three values that are greater than \(2\bar{h}\), which can be considered as outliers with respect to the predictor values. Also from the influence measure, We can see there are two more values that can be considered influential and maybe outliers.

4) Is there any concern about multicollinearity?

To access the multicollinearity, I will use the vaiance inflation factors (VIFs) to detect. VIF quantifies how much the variance of a regression coefficient is inflated due to multicollinearity with other predictors.

car::vif(fit)
percent_of_classes_under_20       student_faculty_ratio 
                   2.611671                    2.611671 

From the result we can see that the VIF values for both predictors are around 2.61, which is not large enough (normal 10) to be a major concern. Therefore, we can say that there is not much of a concern about multicollinearity.

e) What is the predicted alumni giving rate for an observation with (𝑋1 = 40, 𝑋2 = 5)? Is there any concern about this prediction? Please explain.

To find the predicted alumni giving rate, we are going to first estimate the model.

MLR model with normal errors is given – \(Y_i = \beta_0 + \sum_{j=1}^{p-1} \beta_j X_{ij} + \epsilon_i, i = 1,2, ..., n\).

coef(fit)
                (Intercept) percent_of_classes_under_20       student_faculty_ratio 
                 39.6555835                   0.1661686                  -1.7021103 

From the coefficients result above, we can estimate that the final model is \(\hat{Y} = 39.66 + 0.166 X_1 - 1.702 X_2\).

To find the predicted alumni giving rate:

X1 <- 40
X2 <- 5
Y <- 39.6555835 + 0.1661686 * X1 - 1.7021103 * X2
print(paste("The predicted alumni giving rate is",Y))
[1] "The predicted alumni giving rate is 37.791776"
boxplot(alumni$percent_of_classes_under_20, main = "Boxplot of percent of classes under 20", xlab = "percent of calsses under 20", ylab = "percentage")

boxplot(alumni$student_faculty_ratio, main = "Boxplot of student faculty ratio", xlab = "student faculty ratio", ylab = "ratio")

To determine if there is a concern about the prediction, I am going to see it from two different aspects.

  1. From the boxplot we can see the mean and the 1st and 3rd quartiles of each predictors, which we can see that X1 = 40 and X2 equals to 5 is not within that range. If those are outliers of the observed dataset, then the prediction may not be most reliable.

  2. We have diagnosed that the residuals do not seem to have normality. The model assumptions are linearity, normality of residuals and constant variance. Since we have a violation against normality, the prediction may not be reliable.

Question 2, Simulation Study. Assume mean function \(E(Y|X = 10 + 5X - 2X^2)\).

a) Generate data with \(X_1 \sim N(\mu = 3, \sigma = 0.5)\), sample size \(n = 100\), and error term \(\epsilon \sim N(\mu = 0, \sigma = 0.5)\)

set.seed(7052)
x1 <- rnorm(100, mean = 3, sd = 0.5)
error <- rnorm(100, mean = 0, sd = 0.5)
y <- 10 + 5 * x1 - 2 * x1^2 + error
data <- data.frame(x1, y)
head(mdata, n=3)

b) Fit a SLR using just X. What is the estimated regression equation? Please conduct model estimation, inference, and residual diagnostics. What do you conclude?

To fit the simple linear regression model \(Y = \beta_0 + \beta_1 X +\epsilon\), I will first use the lm() function to fit the model and run a summary statistic on it to get the coefficient.

model.fit <- lm(y ~ x1, data = data)
summary(model.fit)

Call:
lm(formula = y ~ x1, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.2342 -0.2929  0.1358  0.5694  1.9273 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  27.5188     0.4870   56.51   <2e-16 ***
x1           -6.9848     0.1588  -43.99   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8617 on 98 degrees of freedom
Multiple R-squared:  0.9518,    Adjusted R-squared:  0.9513 
F-statistic:  1935 on 1 and 98 DF,  p-value: < 2.2e-16

The intercept \(\beta_0 = 27.52\) and slope value is \(\beta_1 = -6.98\), so we can say the estimated model is \(\hat{y} = 27.52 -6.98x_1\).

From the summary statistics, we can also see that the p-value for both intercept and x1 are very small, both are less than \(2e^-16\), which is less than the 0.05 threshold, so it is statistically significant, there is a negative linear relationship between the response and the predictor.

par(mfrow = c(2,2))
plot(model.fit)

From the residual diagnostic plots, we can see that:

  1. There is a violation to the normality. From the QQ plot, we can see points below the trend line, which indicats a left-skewed distribution.

  2. There is a violation of constant variance. While the fitted value between 5-10 has consistent small residuals, there are also quite a lot points that below the reference line and drop out of the standardized residual threshold \(r_i^{(stan)} < 3\).

  3. From the Residuals vs Leverage plot we can see that there are presence of outliers and influential points. Such as 14, 85, 68 labed in the plot.

c) Update the model from part b by adding a quadratic term. Conduct model estimation, inference, and residual diagnostics. What do you conclude? Does this model seem to fit the data better?

To fit the quadratic model, we can say \(\hat{y} = \beta_0 + \beta_1 x_1 + \beta_2 x^2 + \epsilon\). I am going to assign x_squared to be \(x_1^2\).

data2 <- mutate(data, x_squared = x1^2)
head(data2, n=3)
fit2 <- lm(y ~ x1 + x_squared, data = data2)
summary(fit2)

Call:
lm(formula = y ~ x1 + x_squared, data = data2)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.19046 -0.30582  0.03546  0.31477  1.38463 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  10.7438     1.0707  10.034  < 2e-16 ***
x1            4.4770     0.7154   6.258 1.06e-08 ***
x_squared    -1.8949     0.1175 -16.131  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4513 on 97 degrees of freedom
Multiple R-squared:  0.9869,    Adjusted R-squared:  0.9866 
F-statistic:  3656 on 2 and 97 DF,  p-value: < 2.2e-16

After refitting the linear model and run the summary statistics, we can estimate based on the \(\beta_0, \beta_1, and \beta_2\) value. \(\beta_0 = 10.74, \beta_1 = 4.48, \beta_2 = -1.89\), therefore, the estimated model is \(\hat{y} = 10.74 + 4.48x_1 - 1.89x_1^2\).

The p value of three coefficients are very small, indicates statistical significance. We can also look at the \(R^2\) value, the \(R^2\) value from the single linear regression model is 0.95 and this model’s \(R^2\) value is increased to 0.99, which increased quite a bit. When \(R^2\) value increase, it indicates a better fit of the model.

par(mfrow = c(2,2))
plot(fit2)

From the residual diagnostic plots, we can also see that:

  1. The QQ plot is behaving better, most of the points are right on the line, indicates a normal distribution, there is one value slightly outside of the line, but there is not big influence for that one.

  2. The fitted value vs standardized residual also seems to be better, most of the values are within the -1.5 - +1.5 range, which indicates a constant variance.

  3. For cook’s distance and leverages, we can see there are still a couple of outliers but it’s also behaving better than the previous model. Most of the points are on the lefts ide which has a lower score. We could do something to the outliers to make the data more accurate, but these outliers may not be as significant.

From all the reasons above, the 2nd model fit is a better fit of the data.

d) What is the variance inflation factor (VIF) for the quadratic model? Any concern of multicollinearity?

car::vif(fit2)
       x1 x_squared 
 73.97863  73.97863 

By using the vif() function, we can see that the VIF value for both \(x_1\) and \(x_1^2\) are very high, the values are almost 74, which is way pass the normal value of 10. It strongly suggests that there are multicollinearity, which could affect codfficient stability.

e) Now enter the X variable and compare the VIF from d. What did you find? Which VIF is smaller? Please brifly explain the reason.

#method 1:
fit3 <- lm(y ~ x1 + I(x1^2), data = data2)
fit_centered1 <- lm(y ~ I(x1 - mean(x1)) + I((x1 - mean(x1))^2), data = data2)
# Method 2: center x in the training data
data2$x1_centered <- data2$x1 - mean(data2$x1)
fit_centered2 <- lm(y ~ x1_centered + I(x1_centered^2), data = data2)

car::vif(fit_centered1)
    I(x1 - mean(x1)) I((x1 - mean(x1))^2) 
            1.000295             1.000295 
car::vif(fit_centered2)
     x1_centered I(x1_centered^2) 
        1.000295         1.000295 

After center the X variable, the VIF scores dropped tremendously. I used both methods to calculate the VIF and the results are almost equal to 1, which is small enough to say that there is now no multicollinearity, becuase the quadratic term is less correlated with the centered X.

Question 3.

a) What are the assumptions of the normal linear regression model?

The typical assumptions are:

  1. Independence: The observation are independent of each other.

  2. Constant variance: the variance of the error term is constant across all levels of the predictors. Therefore the residuals should be roughly the same at all fitted values.

  3. Normally distributed error. The error term are normally distributed, particularly for inference purposes. When we do t test and obtain confidence intervals, we normally assume that the error is normally distributed.

  4. We assume that we have the correct model or at least a useful one.

  5. Other assumptions like linearity, meaning the response variable is linearly related to the predictors; and no multicollinearity, meaning predictor variables are not highly correlated with each other are also some common assumptions.

b) Are the residuals from linear regression uncorrelated in general? Please explain. What is the distribution of residuals?

Yes, in a correctly specified linear regression model, the residuals are assumed to be uncorrelated with each other and the assumption of independence holds. When we assume the observations are independent, we imply that the errors should be uncorrelated across observations. The residuals don’t necessarily be normally distributed, but if the error terms are normally distributed, then the residuals will approximate a normal distribution. Residuals should ideally have a mean of zero and unit variance.

c) Why do we plot the residuals against the fitted value rather than against the observed response value?

  1. We can spot the pattern in a residuals vs fitted value plot, it can indicate non-linearity or non-constant variance in the data. If residuals are plotted against observed values, it’s harder to detect htese issues related to model fit.

  2. Fitted values are the best estimates provided by the model for y. Checking how the residuals behave relative to these values helps assess whether the model’s linear fit is appropriate.

  3. The plot can also help spot outliers. The points are deviate significantly from the test of the residuals at high or low fitted values may have a large impact on the model.

d) What is multicollinearity? Computationally, what kind of problems can multicollinearity cause when using ordinary lease squares?

Multicollinearity happens when predictor variables are correlated among themselves. When the correlation is high, there is a significant multicollinearity. Although, multicollinearity does not always prevent us from obtaining a good fit, it could cause some issues:

  1. It can cause some of the estimated coefficients to become unstable, like high standard errors. The estimates may become highly sensitive to small changes in the data. It could also increase the variance of the estimated regression coefficients which can make them unstable and sensitive to minor changes in the model.

  2. It can complicate the interpretation of the estimated coefficients, because a change in one predictor will almost always correspond with a change in another. It becomes hard to detect the true effect of predictors because their p value become less reliable.

LS0tCnRpdGxlOiAiQkFOQSA3MDUyIEFzc2lnbm1lbnQgNCAtIFJGaXNjaGVyIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgoqKlRoZSBSIGNvZGUgaXMgaGlkZGVuIGJ5IGRlZmF1bHQuIFBsZWFzZSBjbGljayBvbiBTaG93IHRvIHZpZXcgYWxsIGNvZGVzLiBUaGFuayB5b3UuKioKCiMjIyBBc3NpZ25tZW50IDQKCiMjIyMgUXVlc3Rpb24gMS4gQWx1bW5pIERvbmF0aW9uIERhdGEKCkltcG9ydCBEYXRhIGFuZCBsb2FkIGxpYnJhcmllcyBmcm9tIFVSTDogaHR0cHM6Ly9iZ3JlZW53ZWxsLmdpdGh1Yi5pby91Yy1iYW5hNzA1Mi9kYXRhL2FsdW1uaS5jc3YKYGBge3IgSW1wb3J0IERhdGEgQWx1bW5pfQp1cmwgPC0gImh0dHBzOi8vYmdyZWVud2VsbC5naXRodWIuaW8vdWMtYmFuYTcwNTIvZGF0YS9hbHVtbmkuY3N2IgphbHVtbmkgPC0gcmVhZC5jc3YodXJsKQpzdHIoYWx1bW5pKQphdHRhY2goYWx1bW5pKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShpbnZlc3RyKQpsaWJyYXJ5KGNhcikKbGlicmFyeShsbXRlc3QpCmxpYnJhcnkoZ3JpZEV4dHJhKQpgYGAKCioqMSkgRG9lcyB0aGUgYXNzdW1wdGlvbiBvZiBlcnJvciBub3JtYWxpdHkgYXBwZWFyIHRvIGJlIHZpb2xhdGVkPyoqCgpUbyBzZWUgaWYgdGhlIGVycm9yIG5vcm1hbGl0eSBpcyB2aW9sYXRlZCBvciBub3QsIEkgYW0gZ29pbmcgdG8gdXNlIGEgUVEgcGxvdCB0byBkaWFnbm9zZSBpdC4gRmlyc3QgSSBhbSBnb2luZyB0byBmaXQgdGhlIGRhdGEgdG8gYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbC4KCmBgYHtyfQojIGZpdCB0aGUgbW9kZWwKZml0IDwtIGxtKGFsdW1uaV9naXZpbmdfcmF0ZSB+IHBlcmNlbnRfb2ZfY2xhc3Nlc191bmRlcl8yMCArIHN0dWRlbnRfZmFjdWx0eV9yYXRpbykKCiMgcmVzaWR1YWwgZGlhZ25vc3RpY3MKcXFub3JtKHJlc2lkdWFscyhmaXQpLCBtYWluID0gIlJpZ2h0LXNrZXdlZCBEaXN0cmlidXRpb24iKQpxcWxpbmUocmVzaWR1YWxzKGZpdCksIGNvbCA9ICJibHVlIikKYGBgCgpGcm9tIHRoZSBRUSBwbG90IHdlIGNhbiBzZWUgdGhhdCB0aGUgbWFqb3JpdHkgb2YgdGhlIHBvaW50cyBhcmUgb24gdGhlIHN0cmFpZ2h0IGxpbmUgd2hpbGUgc29tZSBvZiB0aGUgb2YgcG9pbnRzIGFyZSBhYm92ZSB0aGUgbGluZS4gVGhpcyB0ZWxscyB1cyB0aGF0IGl0J3MgcmlnaHQtc2tld2VkLiAKCldlIGNhbiBhbHNvIHVzZSB0aGUgU2hhcGlyby1XaWxrIHRlc3QgdG8gZXhhbSB0aGUgcCB2YWx1ZToKCmBgYHtyIHNoYXBpcm8gdGVzdH0Kc2hhcGlyby50ZXN0KHJlc2lkdWFscyhmaXQpKQpgYGAKClRoZSBQIHZhbHVlIGZyb20gdGhlIFNoYXBpcm8tV2lsayBub3JtYWxpdHkgdGVzdCBpcyAwLjAyNywgd2hpY2ggaXMgbGVzcyB0aGFuIHRoZSB0aHJlc2hvbGQgdmFsdWUgb2YgMC4wNSwgc28gaXQgaW5kaWNhdGVzIHRoZSBub24tbm9ybWFsaXR5LgoKKioyKSBEb2VzIHRoZSBhc3N1bXB0aW9uIG9mIGNvbnN0YW50IGVycm9yIHZhcmlhbmNlIGFwcGVhciB0byBiZSB2aW9sYXRlZD8qKgoKVG8gZGlhZ25vc2UgdGhhdCwgSSBhbSBnb2luZyB0byBjb21wYXJlIHRoZSBSZXNpZHVhbHMgVlMgRml0dGVkIFZhbHVlcyBwbG90LiBJIHdpbGwgYmUgZ2V0dGluZyB0aGUgc3R1ZGVudGl6ZWQgcmVzaWR1YWwgYW5kIGZpdHRlZCB2YWx1ZXMuCgpgYGB7ciByZXNpZHVhbCB2cyBmaXR0ZWQgdmFsdWV9CiMgc3R1ZGVudGl6ZWQgcmVzaWR1YWwKci5vcmQgPC0gcnN0YW5kYXJkKGZpdCkKIyBmaXR0ZWQgdmFsdWUKZi52YWwgPC0gZml0dGVkKGZpdCkKcGxvdChmLnZhbCwgeSA9IHIuc3R1LCB4bGFiID0gIkZpdHRlZCBWYWx1ZSIsIHlsYWIgPSAiU3R1ZGVudGl6ZWQgUmVzaWR1YWwiLCBtYWluID0gIlJlc2lkdWFscyB2cyBGaXR0ZWQiKQphYmxpbmUoaCA9IGMoLTIsIDAsMiksIGx0eSA9IDIsIGNvbCA9IDIpCmBgYAoKRnJvbSB0aGUgUmVzaWR1YWwgdnMgRml0dGVkIHZhbHVlIHBsb3QsIHdlIGNhbiBzZWUgdGhhdCBtb3N0IHBvaW50cyBhcmUgc2NhdHRlcmVkIGFyb3VuZCB0aGUgMCByZWZlcmVuY2UgbGluZSBhbmQgd2l0aGluIHRoZSAtMiB0byArMiByYW5nZS4gSXQgc3VnZ2VzdHMgdGhlIGFzc3VtdHBpb24gb2YgY29uc3RhbnQgdmFyaWFuY2UgbWF5IGhvbGQuCgpXZSBjYW4gYWxzbyB1c2UgQnJldXNoLVBhZ2FuIHRlc3QgdG8gc2VlIGlmIHRoZXJlIGlzIG5vbi1jb25zdGFudCB2YXJpYW5jZS4KCmBgYHtyIGJwdGVzdH0KYnB0ZXN0KGZpdCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlIFAgdmFsdWUgaXMgMC44NzI3IHdoaWNoIGlzIGxhcmdlciB0aGFuIHRoZSAwLjA1IHRocmVzaG9sZCwgdGhpcyBzdWdnZXN0cyB0aGF0IHRoZXJlIGlzIG5vIHN0cm9uZyBldmlkZW5jZSBvZiBoZXRlcm9zY2VkYXN0aWNpdHksIHNvIHdlIGNhbiBzYXkgdGhhdCB0aGUgY29uc3RhbnQgdmFyaWFuY2UgaXMgbm90IHZpb2xhdGVkLgoKKiozKSBEb2VzIHRoZXJlIGFwcGVhciB0byBiZSBhbnkgWSBvciBYIG91dGxpZXJzIG9yIGluZmx1ZW50aWFsIHBvaW50cz8qKgoKVG8gZGV0ZWN0IGlmIHRoZXJlIGFyZSBvdXRsaWVycyBvciBpbmZsdWVudGlhbCBwb2ludHMsIEkgYW0gZ29pbmcgdG8gdXNlIHRoZSBDb29rJ3MgZGlzdGFuY2UgYW5kIGxldmVyYWdlIHBsb3RzLgoKYGBge3J9CmggPC0gaGF0dmFsdWVzKGZpdCkKb3V0IDwtIHdoaWNoKGggPiAyICogbWVhbihoKSkKcGxvdChoLCB0eXBlID0gImgiLCB5bGltID0gZXh0ZW5kcmFuZ2UoaCwgZiA9IDAuMTUpLCBtYWluID0gIkhpZ2ggTGV2ZXJhZ2UgUG9pbnRzIikKYWJsaW5lKGggPSAyICogbWVhbihoKSwgY29sID0gMikKdGV4dChvdXQsIHkgPSBoW291dF0sIGxhYmVscyA9IG91dCwgcG9zID0gMywgY29sID0gMykKYGBgCgpgYGB7cn0KaW5mbHVlbmNlUGxvdChmaXQpCmBgYAoKV2UgY2FuIHNlZSBmcm9tIHRoZSBIaWdoIExldmVyYWdlIFBvaW50cyBwbG90IHRoYXQgdGhlcmUgYXJlIHRocmVlIHZhbHVlcyB0aGF0IGFyZSBncmVhdGVyIHRoYW4gJDJcYmFye2h9JCwgd2hpY2ggY2FuIGJlIGNvbnNpZGVyZWQgYXMgb3V0bGllcnMgd2l0aCByZXNwZWN0IHRvIHRoZSBwcmVkaWN0b3IgdmFsdWVzLiBBbHNvIGZyb20gdGhlIGluZmx1ZW5jZSBtZWFzdXJlLCBXZSBjYW4gc2VlIHRoZXJlIGFyZSB0d28gbW9yZSB2YWx1ZXMgdGhhdCBjYW4gYmUgY29uc2lkZXJlZCBpbmZsdWVudGlhbCBhbmQgbWF5YmUgb3V0bGllcnMuCgoqKjQpIElzIHRoZXJlIGFueSBjb25jZXJuIGFib3V0IG11bHRpY29sbGluZWFyaXR5PyoqCgpUbyBhY2Nlc3MgdGhlIG11bHRpY29sbGluZWFyaXR5LCBJIHdpbGwgdXNlIHRoZSB2YWlhbmNlIGluZmxhdGlvbiBmYWN0b3JzIChWSUZzKSB0byBkZXRlY3QuIFZJRiBxdWFudGlmaWVzIGhvdyBtdWNoIHRoZSB2YXJpYW5jZSBvZiBhIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQgaXMgaW5mbGF0ZWQgZHVlIHRvIG11bHRpY29sbGluZWFyaXR5IHdpdGggb3RoZXIgcHJlZGljdG9ycy4gCgpgYGB7ciBtdWx0aWNvbGxpbmVhcml0eX0KY2FyOjp2aWYoZml0KQpgYGAKCkZyb20gdGhlIHJlc3VsdCB3ZSBjYW4gc2VlIHRoYXQgdGhlIFZJRiB2YWx1ZXMgZm9yIGJvdGggcHJlZGljdG9ycyBhcmUgYXJvdW5kIDIuNjEsIHdoaWNoIGlzIG5vdCBsYXJnZSBlbm91Z2ggKG5vcm1hbCAxMCkgdG8gYmUgYSBtYWpvciBjb25jZXJuLiBUaGVyZWZvcmUsIHdlIGNhbiBzYXkgdGhhdCB0aGVyZSBpcyBub3QgbXVjaCBvZiBhIGNvbmNlcm4gYWJvdXQgbXVsdGljb2xsaW5lYXJpdHkuCgoqKmUpIFdoYXQgaXMgdGhlIHByZWRpY3RlZCBhbHVtbmkgZ2l2aW5nIHJhdGUgZm9yIGFuIG9ic2VydmF0aW9uIHdpdGggKPCdkYsxID0gNDAsIPCdkYsyID0gNSk/IElzIHRoZXJlIGFueSBjb25jZXJuIGFib3V0IHRoaXMgcHJlZGljdGlvbj8gUGxlYXNlIGV4cGxhaW4uKioKClRvIGZpbmQgdGhlIHByZWRpY3RlZCBhbHVtbmkgZ2l2aW5nIHJhdGUsIHdlIGFyZSBnb2luZyB0byBmaXJzdCBlc3RpbWF0ZSB0aGUgbW9kZWwuCgpNTFIgbW9kZWwgd2l0aCBub3JtYWwgZXJyb3JzIGlzIGdpdmVuIC0tICRZX2kgPSBcYmV0YV8wICsgXHN1bV97aj0xfV57cC0xfSBcYmV0YV9qIFhfe2lqfSArIFxlcHNpbG9uX2ksIGkgPSAxLDIsIC4uLiwgbiQuCgpgYGB7ciBmaXQgTUxSfQpjb2VmKGZpdCkKYGBgCgpGcm9tIHRoZSBjb2VmZmljaWVudHMgcmVzdWx0IGFib3ZlLCB3ZSBjYW4gZXN0aW1hdGUgdGhhdCB0aGUgZmluYWwgbW9kZWwgaXMgJFxoYXR7WX0gPSAzOS42NiArIDAuMTY2IFhfMSAtIDEuNzAyIFhfMiQuCgpUbyBmaW5kIHRoZSBwcmVkaWN0ZWQgYWx1bW5pIGdpdmluZyByYXRlOgoKYGBge3J9ClgxIDwtIDQwClgyIDwtIDUKWSA8LSAzOS42NTU1ODM1ICsgMC4xNjYxNjg2ICogWDEgLSAxLjcwMjExMDMgKiBYMgpwcmludChwYXN0ZSgiVGhlIHByZWRpY3RlZCBhbHVtbmkgZ2l2aW5nIHJhdGUgaXMiLFkpKQpgYGAKCmBgYHtyfQpib3hwbG90KGFsdW1uaSRwZXJjZW50X29mX2NsYXNzZXNfdW5kZXJfMjAsIG1haW4gPSAiQm94cGxvdCBvZiBwZXJjZW50IG9mIGNsYXNzZXMgdW5kZXIgMjAiLCB4bGFiID0gInBlcmNlbnQgb2YgY2Fsc3NlcyB1bmRlciAyMCIsIHlsYWIgPSAicGVyY2VudGFnZSIpCmJveHBsb3QoYWx1bW5pJHN0dWRlbnRfZmFjdWx0eV9yYXRpbywgbWFpbiA9ICJCb3hwbG90IG9mIHN0dWRlbnQgZmFjdWx0eSByYXRpbyIsIHhsYWIgPSAic3R1ZGVudCBmYWN1bHR5IHJhdGlvIiwgeWxhYiA9ICJyYXRpbyIpCmBgYAoKVG8gZGV0ZXJtaW5lIGlmIHRoZXJlIGlzIGEgY29uY2VybiBhYm91dCB0aGUgcHJlZGljdGlvbiwgSSBhbSBnb2luZyB0byBzZWUgaXQgZnJvbSB0d28gZGlmZmVyZW50IGFzcGVjdHMuCgoxLiBGcm9tIHRoZSBib3hwbG90IHdlIGNhbiBzZWUgdGhlIG1lYW4gYW5kIHRoZSAxc3QgYW5kIDNyZCBxdWFydGlsZXMgb2YgZWFjaCBwcmVkaWN0b3JzLCB3aGljaCB3ZSBjYW4gc2VlIHRoYXQgWDEgPSA0MCBhbmQgWDIgZXF1YWxzIHRvIDUgaXMgbm90IHdpdGhpbiB0aGF0IHJhbmdlLiBJZiB0aG9zZSBhcmUgb3V0bGllcnMgb2YgdGhlIG9ic2VydmVkIGRhdGFzZXQsIHRoZW4gdGhlIHByZWRpY3Rpb24gbWF5IG5vdCBiZSBtb3N0IHJlbGlhYmxlLgoKMi4gV2UgaGF2ZSBkaWFnbm9zZWQgdGhhdCB0aGUgcmVzaWR1YWxzIGRvIG5vdCBzZWVtIHRvIGhhdmUgbm9ybWFsaXR5LiBUaGUgbW9kZWwgYXNzdW1wdGlvbnMgYXJlIGxpbmVhcml0eSwgbm9ybWFsaXR5IG9mIHJlc2lkdWFscyBhbmQgY29uc3RhbnQgdmFyaWFuY2UuIFNpbmNlIHdlIGhhdmUgYSB2aW9sYXRpb24gYWdhaW5zdCBub3JtYWxpdHksIHRoZSBwcmVkaWN0aW9uIG1heSBub3QgYmUgcmVsaWFibGUuCgojIyMjIFF1ZXN0aW9uIDIsIFNpbXVsYXRpb24gU3R1ZHkuIEFzc3VtZSBtZWFuIGZ1bmN0aW9uICRFKFl8WCA9IDEwICsgNVggLSAyWF4yKSQuCgoqKmEpIEdlbmVyYXRlIGRhdGEgd2l0aCAkWF8xIFxzaW0gTihcbXUgPSAzLCBcc2lnbWEgPSAwLjUpJCwgc2FtcGxlIHNpemUgJG4gPSAxMDAkLCBhbmQgZXJyb3IgdGVybSAkXGVwc2lsb24gXHNpbSBOKFxtdSA9IDAsIFxzaWdtYSA9IDAuNSkkKioKCmBgYHtyIHNhbXBsZX0Kc2V0LnNlZWQoNzA1MikKeDEgPC0gcm5vcm0oMTAwLCBtZWFuID0gMywgc2QgPSAwLjUpCmVycm9yIDwtIHJub3JtKDEwMCwgbWVhbiA9IDAsIHNkID0gMC41KQp5IDwtIDEwICsgNSAqIHgxIC0gMiAqIHgxXjIgKyBlcnJvcgpkYXRhIDwtIGRhdGEuZnJhbWUoeDEsIHkpCmhlYWQobWRhdGEsIG49MykKYGBgCgoqKmIpIEZpdCBhIFNMUiB1c2luZyBqdXN0IFguIFdoYXQgaXMgdGhlIGVzdGltYXRlZCByZWdyZXNzaW9uIGVxdWF0aW9uPyBQbGVhc2UgY29uZHVjdCBtb2RlbCBlc3RpbWF0aW9uLCBpbmZlcmVuY2UsIGFuZCByZXNpZHVhbCBkaWFnbm9zdGljcy4gV2hhdCBkbyB5b3UgY29uY2x1ZGU/KioKClRvIGZpdCB0aGUgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsICRZID0gXGJldGFfMCArIFxiZXRhXzEgWCArXGVwc2lsb24kLCBJIHdpbGwgZmlyc3QgdXNlIHRoZSBgbG0oKWAgZnVuY3Rpb24gdG8gZml0IHRoZSBtb2RlbCBhbmQgcnVuIGEgc3VtbWFyeSBzdGF0aXN0aWMgb24gaXQgdG8gZ2V0IHRoZSBjb2VmZmljaWVudC4KCmBgYHtyIGZpdCBtb2RlbH0KbW9kZWwuZml0IDwtIGxtKHkgfiB4MSwgZGF0YSA9IGRhdGEpCnN1bW1hcnkobW9kZWwuZml0KQpgYGAKClRoZSBpbnRlcmNlcHQgJFxiZXRhXzAgPSAyNy41MiQgYW5kIHNsb3BlIHZhbHVlIGlzICRcYmV0YV8xID0gLTYuOTgkLCBzbyB3ZSBjYW4gc2F5IHRoZSBlc3RpbWF0ZWQgbW9kZWwgaXMgJFxoYXR7eX0gPSAyNy41MiAtNi45OHhfMSQuIAoKRnJvbSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzLCB3ZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGUgcC12YWx1ZSBmb3IgYm90aCBpbnRlcmNlcHQgYW5kIHgxIGFyZSB2ZXJ5IHNtYWxsLCBib3RoIGFyZSBsZXNzIHRoYW4gJDJlXi0xNiQsIHdoaWNoIGlzIGxlc3MgdGhhbiB0aGUgMC4wNSB0aHJlc2hvbGQsIHNvIGl0IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHRoZXJlIGlzIGEgbmVnYXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSByZXNwb25zZSBhbmQgdGhlIHByZWRpY3Rvci4KCmBgYHtyIHJlc2lkdWFsIGRpYWd9CnBhcihtZnJvdyA9IGMoMiwyKSkKcGxvdChtb2RlbC5maXQpCmBgYAoKRnJvbSB0aGUgcmVzaWR1YWwgZGlhZ25vc3RpYyBwbG90cywgd2UgY2FuIHNlZSB0aGF0OiAKCjEuIFRoZXJlIGlzIGEgdmlvbGF0aW9uIHRvIHRoZSBub3JtYWxpdHkuIEZyb20gdGhlIFFRIHBsb3QsIHdlIGNhbiBzZWUgcG9pbnRzIGJlbG93IHRoZSB0cmVuZCBsaW5lLCB3aGljaCBpbmRpY2F0cyBhIGxlZnQtc2tld2VkIGRpc3RyaWJ1dGlvbi4KCjIuIFRoZXJlIGlzIGEgdmlvbGF0aW9uIG9mIGNvbnN0YW50IHZhcmlhbmNlLiBXaGlsZSB0aGUgZml0dGVkIHZhbHVlIGJldHdlZW4gNS0xMCBoYXMgY29uc2lzdGVudCBzbWFsbCByZXNpZHVhbHMsIHRoZXJlIGFyZSBhbHNvIHF1aXRlIGEgbG90IHBvaW50cyB0aGF0IGJlbG93IHRoZSByZWZlcmVuY2UgbGluZSBhbmQgZHJvcCBvdXQgb2YgdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbCB0aHJlc2hvbGQgJHJfaV57KHN0YW4pfSA8IDMkLgoKMy4gRnJvbSB0aGUgUmVzaWR1YWxzIHZzIExldmVyYWdlIHBsb3Qgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBwcmVzZW5jZSBvZiBvdXRsaWVycyBhbmQgaW5mbHVlbnRpYWwgcG9pbnRzLiBTdWNoIGFzIDE0LCA4NSwgNjggbGFiZWQgaW4gdGhlIHBsb3QuCgoqKmMpIFVwZGF0ZSB0aGUgbW9kZWwgZnJvbSBwYXJ0IGIgYnkgYWRkaW5nIGEgcXVhZHJhdGljIHRlcm0uIENvbmR1Y3QgbW9kZWwgZXN0aW1hdGlvbiwgaW5mZXJlbmNlLCBhbmQgcmVzaWR1YWwgZGlhZ25vc3RpY3MuIFdoYXQgZG8geW91IGNvbmNsdWRlPyBEb2VzIHRoaXMgbW9kZWwgc2VlbSB0byBmaXQgdGhlIGRhdGEgYmV0dGVyPyoqCgpUbyBmaXQgdGhlIHF1YWRyYXRpYyBtb2RlbCwgd2UgY2FuIHNheSAkXGhhdHt5fSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfMSArIFxiZXRhXzIgeF4yICsgXGVwc2lsb24kLiBJIGFtIGdvaW5nIHRvIGFzc2lnbiBgeF9zcXVhcmVkYCB0byBiZSAkeF8xXjIkLgoKYGBge3J9CmRhdGEyIDwtIG11dGF0ZShkYXRhLCB4X3NxdWFyZWQgPSB4MV4yKQpoZWFkKGRhdGEyLCBuPTMpCmBgYAoKYGBge3IgcmVmaXQgbW9kZWx9CmZpdDIgPC0gbG0oeSB+IHgxICsgeF9zcXVhcmVkLCBkYXRhID0gZGF0YTIpCnN1bW1hcnkoZml0MikKYGBgCgpBZnRlciByZWZpdHRpbmcgdGhlIGxpbmVhciBtb2RlbCBhbmQgcnVuIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MsIHdlIGNhbiBlc3RpbWF0ZSBiYXNlZCBvbiB0aGUgJFxiZXRhXzAsIFxiZXRhXzEsIGFuZCBcYmV0YV8yJCB2YWx1ZS4gJFxiZXRhXzAgPSAxMC43NCwgXGJldGFfMSA9IDQuNDgsIFxiZXRhXzIgPSAtMS44OSQsIHRoZXJlZm9yZSwgdGhlIGVzdGltYXRlZCBtb2RlbCBpcyAkXGhhdHt5fSA9IDEwLjc0ICsgNC40OHhfMSAtIDEuODl4XzFeMiQuCgpUaGUgcCB2YWx1ZSBvZiB0aHJlZSBjb2VmZmljaWVudHMgYXJlIHZlcnkgc21hbGwsIGluZGljYXRlcyBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UuIFdlIGNhbiBhbHNvIGxvb2sgYXQgdGhlICRSXjIkIHZhbHVlLCB0aGUgJFJeMiQgdmFsdWUgZnJvbSB0aGUgc2luZ2xlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGlzIDAuOTUgYW5kIHRoaXMgbW9kZWwncyAkUl4yJCB2YWx1ZSBpcyBpbmNyZWFzZWQgdG8gMC45OSwgd2hpY2ggaW5jcmVhc2VkIHF1aXRlIGEgYml0LiBXaGVuICRSXjIkIHZhbHVlIGluY3JlYXNlLCBpdCBpbmRpY2F0ZXMgYSBiZXR0ZXIgZml0IG9mIHRoZSBtb2RlbC4KCmBgYHtyIHJlc2lkdWFsIG9mIGZpdDJ9CnBhcihtZnJvdyA9IGMoMiwyKSkKcGxvdChmaXQyKQpgYGAKCkZyb20gdGhlIHJlc2lkdWFsIGRpYWdub3N0aWMgcGxvdHMsIHdlIGNhbiBhbHNvIHNlZSB0aGF0OgoKMS4gVGhlIFFRIHBsb3QgaXMgYmVoYXZpbmcgYmV0dGVyLCBtb3N0IG9mIHRoZSBwb2ludHMgYXJlIHJpZ2h0IG9uIHRoZSBsaW5lLCBpbmRpY2F0ZXMgYSBub3JtYWwgZGlzdHJpYnV0aW9uLCB0aGVyZSBpcyBvbmUgdmFsdWUgc2xpZ2h0bHkgb3V0c2lkZSBvZiB0aGUgbGluZSwgYnV0IHRoZXJlIGlzIG5vdCBiaWcgaW5mbHVlbmNlIGZvciB0aGF0IG9uZS4gCgoyLiBUaGUgZml0dGVkIHZhbHVlIHZzIHN0YW5kYXJkaXplZCByZXNpZHVhbCBhbHNvIHNlZW1zIHRvIGJlIGJldHRlciwgbW9zdCBvZiB0aGUgdmFsdWVzIGFyZSB3aXRoaW4gdGhlIC0xLjUgLSArMS41IHJhbmdlLCB3aGljaCBpbmRpY2F0ZXMgYSBjb25zdGFudCB2YXJpYW5jZS4KCjMuIEZvciBjb29rJ3MgZGlzdGFuY2UgYW5kIGxldmVyYWdlcywgd2UgY2FuIHNlZSB0aGVyZSBhcmUgc3RpbGwgYSBjb3VwbGUgb2Ygb3V0bGllcnMgYnV0IGl0J3MgYWxzbyBiZWhhdmluZyBiZXR0ZXIgdGhhbiB0aGUgcHJldmlvdXMgbW9kZWwuIE1vc3Qgb2YgdGhlIHBvaW50cyBhcmUgb24gdGhlIGxlZnRzIGlkZSB3aGljaCBoYXMgYSBsb3dlciBzY29yZS4gV2UgY291bGQgZG8gc29tZXRoaW5nIHRvIHRoZSBvdXRsaWVycyB0byBtYWtlIHRoZSBkYXRhIG1vcmUgYWNjdXJhdGUsIGJ1dCB0aGVzZSBvdXRsaWVycyBtYXkgbm90IGJlIGFzIHNpZ25pZmljYW50LgoKRnJvbSBhbGwgdGhlIHJlYXNvbnMgYWJvdmUsIHRoZSAybmQgbW9kZWwgZml0IGlzIGEgYmV0dGVyIGZpdCBvZiB0aGUgZGF0YS4KCioqZCkgV2hhdCBpcyB0aGUgdmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvciAoVklGKSBmb3IgdGhlIHF1YWRyYXRpYyBtb2RlbD8gQW55IGNvbmNlcm4gb2YgbXVsdGljb2xsaW5lYXJpdHk/KioKCmBgYHtyIFZJRiBmaXQyfQpjYXI6OnZpZihmaXQyKQpgYGAKCkJ5IHVzaW5nIHRoZSBgdmlmKClgIGZ1bmN0aW9uLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIFZJRiB2YWx1ZSBmb3IgYm90aCAkeF8xJCBhbmQgJHhfMV4yJCBhcmUgdmVyeSBoaWdoLCB0aGUgdmFsdWVzIGFyZSBhbG1vc3QgNzQsIHdoaWNoIGlzIHdheSBwYXNzIHRoZSBub3JtYWwgdmFsdWUgb2YgMTAuIEl0IHN0cm9uZ2x5IHN1Z2dlc3RzIHRoYXQgdGhlcmUgYXJlIG11bHRpY29sbGluZWFyaXR5LCB3aGljaCBjb3VsZCBhZmZlY3QgY29kZmZpY2llbnQgc3RhYmlsaXR5LgoKKiplKSBOb3cgZW50ZXIgdGhlIFggdmFyaWFibGUgYW5kIGNvbXBhcmUgdGhlIFZJRiBmcm9tIGQuIFdoYXQgZGlkIHlvdSBmaW5kPyBXaGljaCBWSUYgaXMgc21hbGxlcj8gUGxlYXNlIGJyaWZseSBleHBsYWluIHRoZSByZWFzb24uKioKCmBgYHtyfQojbWV0aG9kIDE6CmZpdDMgPC0gbG0oeSB+IHgxICsgSSh4MV4yKSwgZGF0YSA9IGRhdGEyKQpmaXRfY2VudGVyZWQxIDwtIGxtKHkgfiBJKHgxIC0gbWVhbih4MSkpICsgSSgoeDEgLSBtZWFuKHgxKSleMiksIGRhdGEgPSBkYXRhMikKIyBNZXRob2QgMjogY2VudGVyIHggaW4gdGhlIHRyYWluaW5nIGRhdGEKZGF0YTIkeDFfY2VudGVyZWQgPC0gZGF0YTIkeDEgLSBtZWFuKGRhdGEyJHgxKQpmaXRfY2VudGVyZWQyIDwtIGxtKHkgfiB4MV9jZW50ZXJlZCArIEkoeDFfY2VudGVyZWReMiksIGRhdGEgPSBkYXRhMikKCmNhcjo6dmlmKGZpdF9jZW50ZXJlZDEpCmNhcjo6dmlmKGZpdF9jZW50ZXJlZDIpCmBgYAoKQWZ0ZXIgY2VudGVyIHRoZSBYIHZhcmlhYmxlLCB0aGUgVklGIHNjb3JlcyBkcm9wcGVkIHRyZW1lbmRvdXNseS4gSSB1c2VkIGJvdGggbWV0aG9kcyB0byBjYWxjdWxhdGUgdGhlIFZJRiBhbmQgdGhlIHJlc3VsdHMgYXJlIGFsbW9zdCBlcXVhbCB0byAxLCB3aGljaCBpcyBzbWFsbCBlbm91Z2ggdG8gc2F5IHRoYXQgdGhlcmUgaXMgbm93IG5vIG11bHRpY29sbGluZWFyaXR5LCBiZWN1YXNlIHRoZSBxdWFkcmF0aWMgdGVybSBpcyBsZXNzIGNvcnJlbGF0ZWQgd2l0aCB0aGUgY2VudGVyZWQgWC4KCiMjIyMgUXVlc3Rpb24gMy4KCioqYSkgV2hhdCBhcmUgdGhlIGFzc3VtcHRpb25zIG9mIHRoZSBub3JtYWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWw/KioKClRoZSB0eXBpY2FsIGFzc3VtcHRpb25zIGFyZToKCjEuIEluZGVwZW5kZW5jZTogVGhlIG9ic2VydmF0aW9uIGFyZSBpbmRlcGVuZGVudCBvZiBlYWNoIG90aGVyLiAKCjIuIENvbnN0YW50IHZhcmlhbmNlOiB0aGUgdmFyaWFuY2Ugb2YgdGhlIGVycm9yIHRlcm0gaXMgY29uc3RhbnQgYWNyb3NzIGFsbCBsZXZlbHMgb2YgdGhlIHByZWRpY3RvcnMuIFRoZXJlZm9yZSB0aGUgcmVzaWR1YWxzIHNob3VsZCBiZSByb3VnaGx5IHRoZSBzYW1lIGF0IGFsbCBmaXR0ZWQgdmFsdWVzLgoKMy4gTm9ybWFsbHkgZGlzdHJpYnV0ZWQgZXJyb3IuIFRoZSBlcnJvciB0ZXJtIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZCwgcGFydGljdWxhcmx5IGZvciBpbmZlcmVuY2UgcHVycG9zZXMuIFdoZW4gd2UgZG8gdCB0ZXN0IGFuZCBvYnRhaW4gY29uZmlkZW5jZSBpbnRlcnZhbHMsIHdlIG5vcm1hbGx5IGFzc3VtZSB0aGF0IHRoZSBlcnJvciBpcyBub3JtYWxseSBkaXN0cmlidXRlZC4KCjQuIFdlIGFzc3VtZSB0aGF0IHdlIGhhdmUgdGhlIGNvcnJlY3QgbW9kZWwgb3IgYXQgbGVhc3QgYSB1c2VmdWwgb25lLgoKNS4gT3RoZXIgYXNzdW1wdGlvbnMgbGlrZSBsaW5lYXJpdHksIG1lYW5pbmcgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGlzIGxpbmVhcmx5IHJlbGF0ZWQgdG8gdGhlIHByZWRpY3RvcnM7IGFuZCBubyBtdWx0aWNvbGxpbmVhcml0eSwgbWVhbmluZyBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSBub3QgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyIGFyZSBhbHNvIHNvbWUgY29tbW9uIGFzc3VtcHRpb25zLgoKKipiKSBBcmUgdGhlIHJlc2lkdWFscyBmcm9tIGxpbmVhciByZWdyZXNzaW9uIHVuY29ycmVsYXRlZCBpbiBnZW5lcmFsPyBQbGVhc2UgZXhwbGFpbi4gV2hhdCBpcyB0aGUgZGlzdHJpYnV0aW9uIG9mIHJlc2lkdWFscz8qKgoKWWVzLCBpbiBhIGNvcnJlY3RseSBzcGVjaWZpZWQgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIHRoZSByZXNpZHVhbHMgYXJlIGFzc3VtZWQgdG8gYmUgdW5jb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlciBhbmQgdGhlIGFzc3VtcHRpb24gb2YgaW5kZXBlbmRlbmNlIGhvbGRzLiBXaGVuIHdlIGFzc3VtZSB0aGUgb2JzZXJ2YXRpb25zIGFyZSBpbmRlcGVuZGVudCwgd2UgaW1wbHkgdGhhdCB0aGUgZXJyb3JzIHNob3VsZCBiZSB1bmNvcnJlbGF0ZWQgYWNyb3NzIG9ic2VydmF0aW9ucy4gVGhlIHJlc2lkdWFscyBkb24ndCBuZWNlc3NhcmlseSBiZSBub3JtYWxseSBkaXN0cmlidXRlZCwgYnV0IGlmIHRoZSBlcnJvciB0ZXJtcyBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHRoZW4gdGhlIHJlc2lkdWFscyB3aWxsIGFwcHJveGltYXRlIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gUmVzaWR1YWxzIHNob3VsZCBpZGVhbGx5IGhhdmUgYSBtZWFuIG9mIHplcm8gYW5kIHVuaXQgdmFyaWFuY2UuCgoqKmMpIFdoeSBkbyB3ZSBwbG90IHRoZSByZXNpZHVhbHMgYWdhaW5zdCB0aGUgZml0dGVkIHZhbHVlIHJhdGhlciB0aGFuIGFnYWluc3QgdGhlIG9ic2VydmVkIHJlc3BvbnNlIHZhbHVlPyoqCgoxLiBXZSBjYW4gc3BvdCB0aGUgcGF0dGVybiBpbiBhIHJlc2lkdWFscyB2cyBmaXR0ZWQgdmFsdWUgcGxvdCwgaXQgY2FuIGluZGljYXRlIG5vbi1saW5lYXJpdHkgb3Igbm9uLWNvbnN0YW50IHZhcmlhbmNlIGluIHRoZSBkYXRhLiBJZiByZXNpZHVhbHMgYXJlIHBsb3R0ZWQgYWdhaW5zdCBvYnNlcnZlZCB2YWx1ZXMsIGl0J3MgaGFyZGVyIHRvIGRldGVjdCBodGVzZSBpc3N1ZXMgcmVsYXRlZCB0byBtb2RlbCBmaXQuCgoyLiBGaXR0ZWQgdmFsdWVzIGFyZSB0aGUgYmVzdCBlc3RpbWF0ZXMgcHJvdmlkZWQgYnkgdGhlIG1vZGVsIGZvciB5LiBDaGVja2luZyBob3cgdGhlIHJlc2lkdWFscyBiZWhhdmUgcmVsYXRpdmUgdG8gdGhlc2UgdmFsdWVzIGhlbHBzIGFzc2VzcyB3aGV0aGVyIHRoZSBtb2RlbCdzIGxpbmVhciBmaXQgaXMgYXBwcm9wcmlhdGUuCgozLiBUaGUgcGxvdCBjYW4gYWxzbyBoZWxwIHNwb3Qgb3V0bGllcnMuIFRoZSBwb2ludHMgYXJlIGRldmlhdGUgc2lnbmlmaWNhbnRseSBmcm9tIHRoZSB0ZXN0IG9mIHRoZSByZXNpZHVhbHMgYXQgaGlnaCBvciBsb3cgZml0dGVkIHZhbHVlcyBtYXkgaGF2ZSBhIGxhcmdlIGltcGFjdCBvbiB0aGUgbW9kZWwuCgoqKmQpIFdoYXQgaXMgbXVsdGljb2xsaW5lYXJpdHk/IENvbXB1dGF0aW9uYWxseSwgd2hhdCBraW5kIG9mIHByb2JsZW1zIGNhbiBtdWx0aWNvbGxpbmVhcml0eSBjYXVzZSB3aGVuIHVzaW5nIG9yZGluYXJ5IGxlYXNlIHNxdWFyZXM/KioKCk11bHRpY29sbGluZWFyaXR5IGhhcHBlbnMgd2hlbiBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSBjb3JyZWxhdGVkIGFtb25nIHRoZW1zZWx2ZXMuIFdoZW4gdGhlIGNvcnJlbGF0aW9uIGlzIGhpZ2gsIHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgbXVsdGljb2xsaW5lYXJpdHkuIEFsdGhvdWdoLCBtdWx0aWNvbGxpbmVhcml0eSBkb2VzIG5vdCBhbHdheXMgcHJldmVudCB1cyBmcm9tIG9idGFpbmluZyBhIGdvb2QgZml0LCBpdCBjb3VsZCBjYXVzZSBzb21lIGlzc3VlczoKCjEuIEl0IGNhbiBjYXVzZSBzb21lIG9mIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzIHRvIGJlY29tZSB1bnN0YWJsZSwgbGlrZSBoaWdoIHN0YW5kYXJkIGVycm9ycy4gVGhlIGVzdGltYXRlcyBtYXkgYmVjb21lIGhpZ2hseSBzZW5zaXRpdmUgdG8gc21hbGwgY2hhbmdlcyBpbiB0aGUgZGF0YS4gSXQgY291bGQgYWxzbyBpbmNyZWFzZSB0aGUgdmFyaWFuY2Ugb2YgdGhlIGVzdGltYXRlZCByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyB3aGljaCBjYW4gbWFrZSB0aGVtIHVuc3RhYmxlIGFuZCBzZW5zaXRpdmUgdG8gbWlub3IgY2hhbmdlcyBpbiB0aGUgbW9kZWwuIAoKMi4gSXQgY2FuIGNvbXBsaWNhdGUgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzLCBiZWNhdXNlIGEgY2hhbmdlIGluIG9uZSBwcmVkaWN0b3Igd2lsbCBhbG1vc3QgYWx3YXlzIGNvcnJlc3BvbmQgd2l0aCBhIGNoYW5nZSBpbiBhbm90aGVyLiBJdCBiZWNvbWVzIGhhcmQgdG8gZGV0ZWN0IHRoZSB0cnVlIGVmZmVjdCBvZiBwcmVkaWN0b3JzIGJlY2F1c2UgdGhlaXIgcCB2YWx1ZSBiZWNvbWUgbGVzcyByZWxpYWJsZS4KCgoKCgoKCgoKCgoKCgoKCg==