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

Assignment 3

Question 1.

Response variable Y = alumni_giving_rate, X1 = percent_of_classes_under_20, X2 = student_faculty_racio.

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(here)

a) What is the final estimated 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\).

alumni_fit <- lm(alumni_giving_rate ~ percent_of_classes_under_20 + student_faculty_ratio, data = alumni)
coef(alumni_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\).

b) What is the predicted alumni_giving_rate for an observation with percent_of_classes_under_20 = 50 and student_faculty_ratio = 10?

X1 <- 50
X2 <- 10
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 30.9429105"

The giving rate is 30.94%.

c) Test the statistical significance of the regression coefficient using t-tests; use α=0.05. Obtain the t-statistics and p-values, interpret the results, make a conclusion (i.e. reject or not reject), and explain why.

summary(alumni_fit)

Call:
lm(formula = alumni_giving_rate ~ percent_of_classes_under_20 + 
    student_faculty_ratio, data = alumni)

Residuals:
   Min     1Q Median     3Q    Max 
-15.00  -6.57  -1.95   4.42  24.56 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)                  39.6556    13.5076   2.936 0.005225 ** 
percent_of_classes_under_20   0.1662     0.1626   1.022 0.312128    
student_faculty_ratio        -1.7021     0.4421  -3.850 0.000371 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.098 on 45 degrees of freedom
Multiple R-squared:  0.5613,    Adjusted R-squared:  0.5418 
F-statistic: 28.79 on 2 and 45 DF,  p-value: 8.869e-09

To test the statistical significance using T test, we will use the marginal test to complete this. From the above summary statistics we can see that the t statistics are 1.022 for \(\beta_1\) and -3.850 for \(\beta_2\). We will set the null hypothesis \(H_0 : \beta_j = 0\) to be there is no significant linear relationship between response and predictors, and the alternative hypothesis \(H_1 : \beta_j \neq 0\) is that there is statistical significance between responses and predictors. We will take a look at the p values for each predictor.

Based on the p value for percent_of_classes_under_20, which is 0.312 and is greater than the threshold \(\alpha = 0.05\), in this case, we failed to reject the null hypothesis for \(\beta_1\) - that there is no significant linear relation between alumni_giving_rate and percent_of_classes_under_20 when controlling student_faculty_ratio; and based on the p value for student_faculty_ratio, the p value is 0.00037 and is less than the 0.05 threshold, so we will reject the null hypothesis for \(\beta_2\) - there is a significant linear relationship between alumni_giving_rate and student_faculty_ratio.

d) d. What is the F statistic? Is it significant? Clearly write out the null hypothesis, F-statistic, and p-value and interpret the test results.

summary(alumni_fit)

Call:
lm(formula = alumni_giving_rate ~ percent_of_classes_under_20 + 
    student_faculty_ratio, data = alumni)

Residuals:
   Min     1Q Median     3Q    Max 
-15.00  -6.57  -1.95   4.42  24.56 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)                  39.6556    13.5076   2.936 0.005225 ** 
percent_of_classes_under_20   0.1662     0.1626   1.022 0.312128    
student_faculty_ratio        -1.7021     0.4421  -3.850 0.000371 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9.098 on 45 degrees of freedom
Multiple R-squared:  0.5613,    Adjusted R-squared:  0.5418 
F-statistic: 28.79 on 2 and 45 DF,  p-value: 8.869e-09
#manually construct F-test
alumni_fit_reduced <- lm(alumni_giving_rate ~ 1, data = alumni)
anova(alumni_fit_reduced, alumni_fit)
Analysis of Variance Table

Model 1: alumni_giving_rate ~ 1
Model 2: alumni_giving_rate ~ percent_of_classes_under_20 + student_faculty_ratio
  Res.Df    RSS Df Sum of Sq      F    Pr(>F)    
1     47 8491.5                                  
2     45 3724.9  2    4766.6 28.793 8.869e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

To test the statistical significance using F test, we will set the null hypothesis \(H_0 : \beta_1 = \beta_2 = 0\) - there is no statistic significance between response and predictors; and the alternative hypothesis to be \(H_1 : \beta_j \neq 0\) for at least one \(j \in {1,2}\), meaning either \(\beta_1\) or \(\beta_2\) not equal to zero - there is statistical significance between response and predictors.

From the above summary statistics and the manual F-test results, we can see that the coefficients of two predictors do not equal to zero: \(\beta_1 = 0.1662\) and \(\beta_2 = -1.7021\). The F statistic value is 28.793, and the p value is \(8.869e^-9\), which is smaller than the 0.05 threshold. Therefore, we are going to reject the null hypothesis - there is a significant linear relationship between the response alumni_giving_rate and the predictors.

It suggests that all else held constant, for every one percent increase in the percent_of_classes_under_20, the alumni_giving_rate is expected to increase by approximately 0.166, and when all else held constant, for every one unit increase in student_faculty_ratio, the alumni_giving_rate is expected to decrease by 1.702.

e) What is the value of the coefficient of determination? Please interpret.

summary(alumni_fit)$adj.r.squared
[1] 0.5418446

From the summary statistics, we can see there there are two R Squared values. \(R^2\) will increase as more terms are added to the model, so I decide to choose the adjusted R-squared value to report. So the \(R^2 = 0.5418\). This means that 54.18% of the variance can be explained by the model.

f) What is the correlation coefficient \(r_1\) between percent_of_classes_under_20 and alumni_giving_rate and the correlation coefficient \(r_2\) between student_faculty_ratio and alumni_giving_rate? Do you see any relationship between \(r_1\), \(r_2\), and \(R^2\)?

R2 <- summary(alumni_fit)$adj.r.squared
r1 <- cor(alumni$percent_of_classes_under_20, alumni$alumni_giving_rate)
r2 <- cor(alumni$student_faculty_ratio, alumni$alumni_giving_rate)
print(paste("The correlation coefficient r_1 = ", r1))
[1] "The correlation coefficient r_1 =  0.645650419081598"
print(paste("The correlation coefficient r_2 = ", r2))
[1] "The correlation coefficient r_2 =  -0.742397463273406"
print(paste("The coefficient of determination R^2 = ", R2))
[1] "The coefficient of determination R^2 =  0.541844592524699"

We learned from simple linear regression that \(r^2 = R^2\), however, in multiple linear regression, looks like the \(R^2\) is a combined value of both predictors, so the value of \(r_1^2\) and \(r_2^2\) does not necessarily add up, hence the relationship between r and R breaks down in multiple linear regression.

There is still some pattern between those values. We see that \(r_1\) is positive and relatively strong, which suggests that as the percentage of classes with fewer than 20 increases, the giving rate will also tend to increase. On the other hand, \(r_2\) is negative and stronger than \(r_1\), it indicates that when the student to faculty ratio increase, the giving rate will decrease. The \(R^2\) value is moderate and indicates that 54% of the variance can be explained by the model.

Question 2 Simulation Study.

a) Generate N = 1000 observations from the model \(Y \sim 5X_1 - 2X_2 + \epsilon\), where \(X_1 \sim N(\mu = 2, \sigma = 0.1), X_2 \sim N(\mu = 0, \sigma = 0.4), and \epsilon \sim N(\mu = 0, \sigma = 0.5).\)

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

b) Fit a multiple linear regression to the simulated data from part a. What is the estimated prediction equation? Report the estimated coefficients and their standard errors. Are they significant? Clearly write out the null and alternative hypotheses, observed t-statistic(s), p-value(s), and interpret the estimates and test results. What is fitted model’s MSE?

mdata_fit <- lm(y ~ x1 + x2, data = mdata)
summary(mdata_fit)

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

Residuals:
     Min       1Q   Median       3Q      Max 
-1.57953 -0.34033 -0.00096  0.31540  1.63513 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 10.26397    0.30604   33.54   <2e-16 ***
x1           4.87776    0.15252   31.98   <2e-16 ***
x2          -2.03892    0.03836  -53.16   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4843 on 997 degrees of freedom
Multiple R-squared:  0.7913,    Adjusted R-squared:  0.7909 
F-statistic:  1890 on 2 and 997 DF,  p-value: < 2.2e-16
mse <- mean(mdata_fit$residuals^2)
print(paste("MSE:", mse))
[1] "MSE: 0.233881211623243"

I used the lm()function to fit my multiple linear regression. From the summary statistics, we can see that the coefficient values are listed as \(\beta_1 = 4.878\) and \(\beta_2 = -2.039\). Based on the full model: \(\hat{y}= \hat\beta_0 + \hat\beta_1X_1 + \hat\beta_2X_2 + \epsilon\), I can estimate the prediction equation to be \(\hat{y} = 10.26 + 4.878X_1 - 2.039X_2\).

The estimated coefficients and standard errors are : 4.878 and 0.153 for x1, -2.039 and 0.038 for x2.

Since we have multiple predictors in the linear regression model, we can use hypotheses of interest like \(H_0 : \beta_j = 0\) - there is no significant linear relationship between response and the predictors, and \(H_1: \beta_j \neq 0\) - there is a significant linear relationship between Y and any of the features. To conduct a marginal test, we will be able to see t value and p value for each predictor.

From the results, we can see that the t value for x1 is 31.98 and the p value is less than \(2e^-16\) which is smaller than the 0.05 threshold, so we can reject the null hypothesis on x1, that there is a significant linear relationship between response y and predictor x1. Same, we see the t value for x2 is -53.16 and p value is also less than \(2e^-16\), so we reject the null hypothesis on x2 as well, there is a significant linear relationship between response y and predictor x2. Taking a look at the F-statistic, it indicates that the F value is 1890 with p value less than \(2e^-16\), so overall, we can also reject the null hypothesis, that there is statistical significance between response y and both predictors.

x1 has a positive linear relationship to response y, when x1 increase, y value will also increase; on the other than, x2 has a negative linear relationship to response y, meaning when x2 increase, y will decrease.

The MSE value is around 0.234, which indicating a reasonable fit of the model to the data.

c) Repeat part b), but re-simulate the data and change the error term to ϵ∼N(μ=0,σ=1) (i.e., standard normal).

set.seed(7052)
x1 <- rnorm(1000, mean = 2, sd = 0.1)
x2 <- rnorm(1000, mean = 0, sd = 0.4)
error <- rnorm(1000, mean = 0, sd = 1)
y <- 10 + 5 * x1 - 2 * x2 + error
mdata2 <- data.frame(x1, x2, y)
head(mdata2, n=3)
mdata_fit2 <- lm(y ~ x1 + x2, data = mdata2)
summary(mdata_fit2)

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

Residuals:
    Min      1Q  Median      3Q     Max 
-3.1591 -0.6807 -0.0019  0.6308  3.2703 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 10.52794    0.61207   17.20   <2e-16 ***
x1           4.75551    0.30504   15.59   <2e-16 ***
x2          -2.07784    0.07671  -27.09   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9687 on 997 degrees of freedom
Multiple R-squared:  0.4904,    Adjusted R-squared:  0.4894 
F-statistic: 479.8 on 2 and 997 DF,  p-value: < 2.2e-16
mse2 <- mean(mdata_fit2$residuals^2)
print(paste("MSE for mdata_fit2 is :", mse2))
[1] "MSE for mdata_fit2 is : 0.935524846492974"

By using the same function with the previous data frame, we can see that the coefficient values are listed as \(\beta_1 = 4.756\) and \(\beta_2 = -2.078\). Based on the full model: \(\hat{y}= \hat\beta_0 + \hat\beta_1X_1 + \hat\beta_2X_2 + \epsilon\), I can estimate the prediction equation to be \(\hat{y} = 10.53 + 4.756X_1 - 2.078X_2\).

The estimated coefficients and standard errors are : 4.756 and 0.305 for x1, -2.078 and 0.077 for x2. We can see that with the error variance increased, the standard error for each predictor also increased (doubled).

The hypotheses of interest: to set \(H_0 : \beta_j = 0\) - there is no significant linear relationship between response and the predictors, and \(H_1: \beta_j \neq 0\) - there is a significant linear relationship between Y and any of the features. To conduct a marginal test, we will be able to see t value and p value for each predictor.

From the results, we can see that the t value for x1 is 15.59 and the p value is less than \(2e^-16\) which is smaller than the 0.05 threshold, so we can reject the null hypothesis on x1, that there is a significant linear relationship between response y and predictor x1. Same, we see the t value for x2 is -27.09 and p value is also less than \(2e^-16\), so we reject the null hypothesis on x2 as well, there is a significant linear relationship between response y and predictor x2. Taking a look at the F-statistic, it indicates that the F value is 479.8 with p value less than \(2e^-16\), so overall, we can also reject the null hypothesis, that there is statistical significance between response Y and both predictors.

Same as the previous statistics, x1 has a positive linear relationship to response y, when x1 increase, y value will also increase; on the other than, x2 has a negative linear relationship to response y, meaning when x2 increase, y will decrease.

The MSE value is around 0.936, which has increased quite a bit compared to the previous fitted model statistics, indicating this may be a worse fit compare to the previous one.

d) Repeat parts a)–c) using N=400. What do you conclude? What is the effect to the model parameter estimates when the error variance gets smaller? What is the effect when the sample size gets bigger?

I’ll name the data with N=400, error variance = 0.5 to mdata3 and N=400, error variance = 1 to mdata4

set.seed(7052)
x1 <- rnorm(400, mean = 2, sd = 0.1)
x2 <- rnorm(400, mean = 0, sd = 0.4)
error <- rnorm(400, mean = 0, sd = 0.5)
y <- 10 + 5 * x1 - 2 * x2 + error
mdata3 <- data.frame(x1, x2, y)
head(mdata3, n=3)
set.seed(7052)
x1 <- rnorm(400, mean = 2, sd = 0.1)
x2 <- rnorm(400, mean = 0, sd = 0.4)
error <- rnorm(400, mean = 0, sd = 1)
y <- 10 + 5 * x1 - 2 * x2 + error
mdata4 <- data.frame(x1, x2, y)
head(mdata4, n=3)

Perform the linear regression model for mdata3 and mdata4

mdata_fit3 <- lm(y ~ x1 + x2, data = mdata3)
summary(mdata_fit3)

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

Residuals:
     Min       1Q   Median       3Q      Max 
-1.85547 -0.36374  0.00169  0.32801  1.31769 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 10.69826    0.52106   20.53   <2e-16 ***
x1           4.66233    0.25869   18.02   <2e-16 ***
x2          -1.95779    0.06508  -30.08   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.5076 on 397 degrees of freedom
Multiple R-squared:  0.7521,    Adjusted R-squared:  0.7509 
F-statistic: 602.3 on 2 and 397 DF,  p-value: < 2.2e-16
mse3 <- mean(mdata_fit3$residuals^2)
print(paste("MSE of mdata_fit3:", mse3))
[1] "MSE of mdata_fit3: 0.255756735784694"
mdata_fit4 <- lm(y ~ x1 + x2, data = mdata4)
summary(mdata_fit4)

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

Residuals:
    Min      1Q  Median      3Q     Max 
-3.7109 -0.7275  0.0034  0.6560  2.6354 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  11.3965     1.0421  10.936  < 2e-16 ***
x1            4.3247     0.5174   8.359 1.08e-15 ***
x2           -1.9156     0.1302 -14.716  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.015 on 397 degrees of freedom
Multiple R-squared:  0.4142,    Adjusted R-squared:  0.4113 
F-statistic: 140.4 on 2 and 397 DF,  p-value: < 2.2e-16
mse4 <- mean(mdata_fit4$residuals^2)
print(paste("MSE of mdata_fit4:", mse4))
[1] "MSE of mdata_fit4: 1.02302694313878"

From the above summary statistics for mdata3 and mdata4, we can learn:

For mdata3, given the intercept 10.70 and slope for both predictors are 4.662 and -1.958, we can write the estimated prediction equation to be \(\hat{y} = 10.7 + 4.662X_1 - 1.958X_2\). For mdata4, given the intercept 11.40 and slope for both predictors are 4.325 and -1.916, we can write the estimated prediction equation to be \(\hat{y} = 11.4 + 4.325X_1 - 1.916X_2\).

The estimated coefficients and standard errors for mdata3 are : 4.662 and 0.259 for x1, -1.958 and 0.065 for x2; for mdata4: 4.325 and 0.517 for x1, -1.916 and 0.13 for x2. We can see that with the error variance increased, the standard error for each predictor also increased (doubled).

The hypothesis testing for both fitted models mdata3 and mdata4 is the same. The null hypothesis \(H_0\) is that there is no linear relationship between response y and predictors, \(H_0 : \beta_j = 0\). The alternative hypothesis \(H_1\) is that there is a linear relationship between response y and any of the predictors, \(H_1: \beta_j \neq 0\).

For mdata3, the t value for x1 is 18.02 and the p value is less than \(2e^-16\) which is smaller than the 0.05 threshold, so we can reject the null hypothesis on x1, that there is a significant linear relationship between response Y and predictor x1. Same, we see the t value for x2 is -30.08 and p value is also less than \(2e^-16\), so we reject the null hypothesis on x2 as well, there is a significant linear relationship between response Y and predictor x2. Taking a look at the F-statistic, it indicates that the F value is 602.3 with p value less than \(2.2e^-16\), so overall, we can also reject the null hypothesis, that there is statistical significance between response Y and both predictors. Same with mdata4, t value for x1 is 8.359, p value is \(1.08^-15\), t value for x2 is -14.716, p value is less than \(2e^-16\). Both p value shows that we should reject the null hypothesis, there is a statistical significance between response Y and predictors X1 and X2. We can also learn that from the F-statistic, F value is 140.4 and p value is less than \(2.2e^-16\).

Same as the previous statistics, x1 has a positive linear relationship to response y, when x1 increase, y value will also increase; on the other than, x2 has a negative linear relationship to response y, meaning when x2 increase, y will decrease.

Also, from this simulation, we can see some patterns when the sample size and error term variance are changed. See the image below:

Table Caption: Table of the summary statistics from different parameters
Table Caption: Table of the summary statistics from different parameters

When sample size increases, the estimates of the coefficients get more precise, and the standard errors are smaller for both predictors. T value will get larger and p value will get lower. Higher t value means that the coefficients are more likely to be statistically significant, and lower p-value makes us likely to reject the null hypothesis. On the other hand, when the error term variance increases, the variability in the response variable increases, and we see higher standard errors for both predictors, almost doubled. The t value will decrease and p value will increase, which means the coefficient will be less likely significant.

e) What about the MSE from each model?

From the table above, we can see that:

When sample size increases, the MSE does not change much while the error variance is the same. However, when the error variance increases, the MSE will also increase, which makes the residuals larger. So with error variance increase, we may see a worse fit of the data.

Question 3 Multiple Linear Regression in Matrix Notation

a) Write out the multiple linear regression model with normal errors in matrix form.

The regression model can be expressed as \(Y = X\beta + \epsilon\), where Y is an n * 1 vector of responses, \(\mathbf{Y} = \begin{bmatrix} Y_1 & Y_2 & \cdots & Y_n \end{bmatrix}\), \(\beta\) is an p * 1 vector of coefficients, \(\mathbf{\beta} = \begin{bmatrix} \beta_1 & \beta_2 & \cdots & \beta_{p-1} \end{bmatrix}\), \(\epsilon\) is the normal error, and X is an n * p model matrix. \(\mathbf{X} = \begin{bmatrix} 1 & X_{11} & X_{12} & \cdot & X_{1,p-1} \\ 1 & X_{21} & X_{22} & \cdot & X_{2,p-1} \\ \vdots & \vdots & \ddots & \vdots \\ 1 & X_{n1} & X_{n2} & \cdot & X_{n,p-1} \end{bmatrix}\).

b) State the model assumptions from part a).

The usual assumption is that the \(\epsilon\) error term is normally distributed \(\epsilon \sim N (0_n, \sigma^2I_n)\). I is the n * n identity matrix. All errors are independent.

c) Write out the model matrix X for the model in part a.

X is an n * p model matrix. \(\mathbf{X} = \begin{bmatrix} 1 & X_{11} & X_{12} & \cdot & X_{1,p-1} \\ 1 & X_{21} & X_{22} & \cdot & X_{2,p-1} \\ \vdots & \vdots & \ddots & \vdots \\ 1 & X_{n1} & X_{n2} & \cdot & X_{n,p-1} \end{bmatrix}\).

d) What is the least squares estimate of β in part a)?

To find the value of \(\beta\) that minimizes SSE, differentiate SSE w.r.t. \(\beta\) and equating to zero, we have equation \(2X^\intercal Y + 2X^\intercal X \beta = 0_p\), so \(\hat\beta = (X^\intercal X) ^{-1} X^\intercal Y\). X has to be full rank in order for \(X^\intercal X\) to be invertible.

e) What does it mean for the estimate in part d) to be unbiased?

As one of the properties of \(\hat\beta\), unbiased means the expected value of \(\hat{\beta}\) equals the true value of \(\beta\).

LS0tCnRpdGxlOiAiQkFOQSA3MDUyIEFzc2lnbm1lbnQgMyAtIFJGaXNjaGVyIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgoqKlRoZSBSIGNvZGUgaXMgaGlkZGVuIGJ5IGRlZmF1bHQuIFBsZWFzZSBjbGljayBvbiBTaG93IHRvIHZpZXcgYWxsIGNvZGVzLiBUaGFuayB5b3UuKioKCiMjIyBBc3NpZ25tZW50IDMKCiMjIyMgUXVlc3Rpb24gMS4KUmVzcG9uc2UgdmFyaWFibGUgWSA9IGBhbHVtbmlfZ2l2aW5nX3JhdGVgLCBYMSA9IGBwZXJjZW50X29mX2NsYXNzZXNfdW5kZXJfMjBgLCBYMiA9IGBzdHVkZW50X2ZhY3VsdHlfcmFjaW9gLgoKSW1wb3J0IERhdGEgYW5kIGxvYWQgbGlicmFyaWVzIGZyb20gVVJMOiBodHRwczovL2JncmVlbndlbGwuZ2l0aHViLmlvL3VjLWJhbmE3MDUyL2RhdGEvYWx1bW5pLmNzdgpgYGB7ciBJbXBvcnQgRGF0YSBBbHVtbml9CnVybCA8LSAiaHR0cHM6Ly9iZ3JlZW53ZWxsLmdpdGh1Yi5pby91Yy1iYW5hNzA1Mi9kYXRhL2FsdW1uaS5jc3YiCmFsdW1uaSA8LSByZWFkLmNzdih1cmwpCnN0cihhbHVtbmkpCmF0dGFjaChhbHVtbmkpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGludmVzdHIpCmxpYnJhcnkoaGVyZSkKYGBgCgoqKmEpIFdoYXQgaXMgdGhlIGZpbmFsIGVzdGltYXRlZCBtb2RlbD8qKgoKTUxSIG1vZGVsIHdpdGggbm9ybWFsIGVycm9ycyBpcyBnaXZlbiAtLSAkWV9pID0gXGJldGFfMCArIFxzdW1fe2o9MX1ee3AtMX0gXGJldGFfaiBYX3tpan0gKyBcZXBzaWxvbl9pLCBpID0gMSwyLCAuLi4sIG4kLgoKYGBge3IgZml0IE1MUn0KYWx1bW5pX2ZpdCA8LSBsbShhbHVtbmlfZ2l2aW5nX3JhdGUgfiBwZXJjZW50X29mX2NsYXNzZXNfdW5kZXJfMjAgKyBzdHVkZW50X2ZhY3VsdHlfcmF0aW8sIGRhdGEgPSBhbHVtbmkpCmNvZWYoYWx1bW5pX2ZpdCkKYGBgCgpGcm9tIHRoZSBjb2VmZmljaWVudHMgcmVzdWx0IGFib3ZlLCB3ZSBjYW4gZXN0aW1hdGUgdGhhdCB0aGUgZmluYWwgbW9kZWwgaXMgJFxoYXR7WX0gPSAzOS42NiArIDAuMTY2IFhfMSAtIDEuNzAyIFhfMiQuCgoqKmIpIFdoYXQgaXMgdGhlIHByZWRpY3RlZCBgYWx1bW5pX2dpdmluZ19yYXRlYCBmb3IgYW4gb2JzZXJ2YXRpb24gd2l0aCBgcGVyY2VudF9vZl9jbGFzc2VzX3VuZGVyXzIwYCA9IDUwIGFuZCBgc3R1ZGVudF9mYWN1bHR5X3JhdGlvYCA9IDEwPyoqCgpgYGB7ciBhbHVtbmkgZ2l2aW5nIHJhdGUgdmFsdWV9ClgxIDwtIDUwClgyIDwtIDEwClkgPC0gMzkuNjU1NTgzNSArIDAuMTY2MTY4NiAqIFgxIC0gMS43MDIxMTAzICogWDIKcHJpbnQocGFzdGUoIlRoZSBwcmVkaWN0ZWQgYWx1bW5pIGdpdmluZyByYXRlIGlzIixZKSkKYGBgCgpUaGUgZ2l2aW5nIHJhdGUgaXMgMzAuOTQlLgoKKipjKSBUZXN0IHRoZSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2Ugb2YgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQgdXNpbmcgdC10ZXN0czsgdXNlIM6xPTAuMDUuIE9idGFpbiB0aGUgdC1zdGF0aXN0aWNzIGFuZCBwLXZhbHVlcywgaW50ZXJwcmV0IHRoZSByZXN1bHRzLCBtYWtlIGEgY29uY2x1c2lvbiAoaS5lLiByZWplY3Qgb3Igbm90IHJlamVjdCksIGFuZCBleHBsYWluIHdoeS4qKgoKYGBge3IgVCB0ZXN0fQpzdW1tYXJ5KGFsdW1uaV9maXQpCmBgYAoKVG8gdGVzdCB0aGUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIHVzaW5nIFQgdGVzdCwgd2Ugd2lsbCB1c2UgdGhlIG1hcmdpbmFsIHRlc3QgdG8gY29tcGxldGUgdGhpcy4gRnJvbSB0aGUgYWJvdmUgc3VtbWFyeSBzdGF0aXN0aWNzIHdlIGNhbiBzZWUgdGhhdCB0aGUgdCBzdGF0aXN0aWNzIGFyZSAxLjAyMiBmb3IgJFxiZXRhXzEkIGFuZCAtMy44NTAgZm9yICRcYmV0YV8yJC4gV2Ugd2lsbCBzZXQgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wIDogXGJldGFfaiA9IDAkIHRvIGJlIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNwb25zZSBhbmQgcHJlZGljdG9ycywgYW5kIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICRIXzEgOiBcYmV0YV9qIFxuZXEgMCQgaXMgdGhhdCB0aGVyZSBpcyBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYmV0d2VlbiByZXNwb25zZXMgYW5kIHByZWRpY3RvcnMuIFdlIHdpbGwgdGFrZSBhIGxvb2sgYXQgdGhlIHAgdmFsdWVzIGZvciBlYWNoIHByZWRpY3Rvci4gCgpCYXNlZCBvbiB0aGUgcCB2YWx1ZSBmb3IgYHBlcmNlbnRfb2ZfY2xhc3Nlc191bmRlcl8yMGAsIHdoaWNoIGlzIDAuMzEyIGFuZCBpcyBncmVhdGVyIHRoYW4gdGhlIHRocmVzaG9sZCAkXGFscGhhID0gMC4wNSQsIGluIHRoaXMgY2FzZSwgd2UgZmFpbGVkIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGZvciAkXGJldGFfMSQgLSB0aGF0IHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbiBiZXR3ZWVuIGBhbHVtbmlfZ2l2aW5nX3JhdGVgIGFuZCBgcGVyY2VudF9vZl9jbGFzc2VzX3VuZGVyXzIwYCB3aGVuIGNvbnRyb2xsaW5nIGBzdHVkZW50X2ZhY3VsdHlfcmF0aW9gOyBhbmQgYmFzZWQgb24gdGhlIHAgdmFsdWUgZm9yIGBzdHVkZW50X2ZhY3VsdHlfcmF0aW9gLCB0aGUgcCB2YWx1ZSBpcyAwLjAwMDM3IGFuZCBpcyBsZXNzIHRoYW4gdGhlIDAuMDUgdGhyZXNob2xkLCBzbyB3ZSB3aWxsIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGZvciAkXGJldGFfMiQgLSB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBgYWx1bW5pX2dpdmluZ19yYXRlYCBhbmQgYHN0dWRlbnRfZmFjdWx0eV9yYXRpb2AuIAoKKipkKSBkLglXaGF0IGlzIHRoZSBGIHN0YXRpc3RpYz8gSXMgaXQgc2lnbmlmaWNhbnQ/IENsZWFybHkgd3JpdGUgb3V0IHRoZSBudWxsIGh5cG90aGVzaXMsIEYtc3RhdGlzdGljLCBhbmQgcC12YWx1ZSBhbmQgaW50ZXJwcmV0IHRoZSB0ZXN0IHJlc3VsdHMuKioKCmBgYHtyIEYgdGVzdH0Kc3VtbWFyeShhbHVtbmlfZml0KQoKI21hbnVhbGx5IGNvbnN0cnVjdCBGLXRlc3QKYWx1bW5pX2ZpdF9yZWR1Y2VkIDwtIGxtKGFsdW1uaV9naXZpbmdfcmF0ZSB+IDEsIGRhdGEgPSBhbHVtbmkpCmFub3ZhKGFsdW1uaV9maXRfcmVkdWNlZCwgYWx1bW5pX2ZpdCkKYGBgCgoKVG8gdGVzdCB0aGUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIHVzaW5nIEYgdGVzdCwgd2Ugd2lsbCBzZXQgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wIDogXGJldGFfMSA9IFxiZXRhXzIgPSAwJCAtIHRoZXJlIGlzIG5vIHN0YXRpc3RpYyBzaWduaWZpY2FuY2UgYmV0d2VlbiByZXNwb25zZSBhbmQgcHJlZGljdG9yczsgYW5kIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIHRvIGJlICRIXzEgOiBcYmV0YV9qIFxuZXEgMCQgZm9yIGF0IGxlYXN0IG9uZSAkaiBcaW4gezEsMn0kLCBtZWFuaW5nIGVpdGhlciAkXGJldGFfMSQgb3IgJFxiZXRhXzIkIG5vdCBlcXVhbCB0byB6ZXJvIC0gdGhlcmUgaXMgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIGJldHdlZW4gcmVzcG9uc2UgYW5kIHByZWRpY3RvcnMuIAoKRnJvbSB0aGUgYWJvdmUgc3VtbWFyeSBzdGF0aXN0aWNzIGFuZCB0aGUgbWFudWFsIEYtdGVzdCByZXN1bHRzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGNvZWZmaWNpZW50cyBvZiB0d28gcHJlZGljdG9ycyBkbyBub3QgZXF1YWwgdG8gemVybzogJFxiZXRhXzEgPSAwLjE2NjIkIGFuZCAkXGJldGFfMiA9IC0xLjcwMjEkLiBUaGUgRiBzdGF0aXN0aWMgdmFsdWUgaXMgMjguNzkzLCBhbmQgdGhlIHAgdmFsdWUgaXMgJDguODY5ZV4tOSQsIHdoaWNoIGlzIHNtYWxsZXIgdGhhbiB0aGUgMC4wNSB0aHJlc2hvbGQuIFRoZXJlZm9yZSwgd2UgYXJlIGdvaW5nIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIC0gdGhlcmUgaXMgYSBzaWduaWZpY2FudCBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHJlc3BvbnNlIGBhbHVtbmlfZ2l2aW5nX3JhdGVgIGFuZCB0aGUgcHJlZGljdG9ycy4KCkl0IHN1Z2dlc3RzIHRoYXQgYWxsIGVsc2UgaGVsZCBjb25zdGFudCwgZm9yIGV2ZXJ5IG9uZSBwZXJjZW50IGluY3JlYXNlIGluIHRoZSBgcGVyY2VudF9vZl9jbGFzc2VzX3VuZGVyXzIwYCwgdGhlIGBhbHVtbmlfZ2l2aW5nX3JhdGVgIGlzIGV4cGVjdGVkIHRvICoqaW5jcmVhc2UqKiBieSBhcHByb3hpbWF0ZWx5IDAuMTY2LCBhbmQgd2hlbiBhbGwgZWxzZSBoZWxkIGNvbnN0YW50LCBmb3IgZXZlcnkgb25lIHVuaXQgaW5jcmVhc2UgaW4gYHN0dWRlbnRfZmFjdWx0eV9yYXRpb2AsIHRoZSBgYWx1bW5pX2dpdmluZ19yYXRlYCBpcyBleHBlY3RlZCB0byAqKmRlY3JlYXNlKiogYnkgMS43MDIuCgoqKmUpIFdoYXQgaXMgdGhlIHZhbHVlIG9mIHRoZSBjb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uPyBQbGVhc2UgaW50ZXJwcmV0LioqCgpgYGB7ciBSMn0Kc3VtbWFyeShhbHVtbmlfZml0KSRhZGouci5zcXVhcmVkCmBgYAoKRnJvbSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzLCB3ZSBjYW4gc2VlIHRoZXJlIHRoZXJlIGFyZSB0d28gUiBTcXVhcmVkIHZhbHVlcy4gJFJeMiQgd2lsbCBpbmNyZWFzZSBhcyBtb3JlIHRlcm1zIGFyZSBhZGRlZCB0byB0aGUgbW9kZWwsIHNvIEkgZGVjaWRlIHRvIGNob29zZSB0aGUgYWRqdXN0ZWQgUi1zcXVhcmVkIHZhbHVlIHRvIHJlcG9ydC4gU28gdGhlICRSXjIgPSAwLjU0MTgkLiBUaGlzIG1lYW5zIHRoYXQgNTQuMTglIG9mIHRoZSB2YXJpYW5jZSBjYW4gYmUgZXhwbGFpbmVkIGJ5IHRoZSBtb2RlbC4KCioqZikgCVdoYXQgaXMgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ICRyXzEkIGJldHdlZW4gYHBlcmNlbnRfb2ZfY2xhc3Nlc191bmRlcl8yMGAgYW5kIGBhbHVtbmlfZ2l2aW5nX3JhdGVgIGFuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgJHJfMiQgYmV0d2VlbiBgc3R1ZGVudF9mYWN1bHR5X3JhdGlvYCBhbmQgYGFsdW1uaV9naXZpbmdfcmF0ZWA/IERvIHlvdSBzZWUgYW55IHJlbGF0aW9uc2hpcCBiZXR3ZWVuICRyXzEkLCAkcl8yJCwgYW5kICRSXjIkPyoqCgpgYGB7ciBjb3JyZWxhdGlvbiBjb2VmZmljaWVudH0KUjIgPC0gc3VtbWFyeShhbHVtbmlfZml0KSRhZGouci5zcXVhcmVkCnIxIDwtIGNvcihhbHVtbmkkcGVyY2VudF9vZl9jbGFzc2VzX3VuZGVyXzIwLCBhbHVtbmkkYWx1bW5pX2dpdmluZ19yYXRlKQpyMiA8LSBjb3IoYWx1bW5pJHN0dWRlbnRfZmFjdWx0eV9yYXRpbywgYWx1bW5pJGFsdW1uaV9naXZpbmdfcmF0ZSkKcHJpbnQocGFzdGUoIlRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCByXzEgPSAiLCByMSkpCnByaW50KHBhc3RlKCJUaGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgcl8yID0gIiwgcjIpKQpwcmludChwYXN0ZSgiVGhlIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24gUl4yID0gIiwgUjIpKQpgYGAKCldlIGxlYXJuZWQgZnJvbSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gdGhhdCAkcl4yID0gUl4yJCwgaG93ZXZlciwgaW4gbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24sIGxvb2tzIGxpa2UgdGhlICRSXjIkIGlzIGEgY29tYmluZWQgdmFsdWUgb2YgYm90aCBwcmVkaWN0b3JzLCBzbyB0aGUgdmFsdWUgb2YgJHJfMV4yJCBhbmQgJHJfMl4yJCBkb2VzIG5vdCBuZWNlc3NhcmlseSBhZGQgdXAsIGhlbmNlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiByIGFuZCBSIGJyZWFrcyBkb3duIGluIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uLgoKVGhlcmUgaXMgc3RpbGwgc29tZSBwYXR0ZXJuIGJldHdlZW4gdGhvc2UgdmFsdWVzLiBXZSBzZWUgdGhhdCAkcl8xJCBpcyBwb3NpdGl2ZSBhbmQgcmVsYXRpdmVseSBzdHJvbmcsIHdoaWNoIHN1Z2dlc3RzIHRoYXQgYXMgdGhlIHBlcmNlbnRhZ2Ugb2YgY2xhc3NlcyB3aXRoIGZld2VyIHRoYW4gMjAgaW5jcmVhc2VzLCB0aGUgZ2l2aW5nIHJhdGUgd2lsbCBhbHNvIHRlbmQgdG8gaW5jcmVhc2UuIE9uIHRoZSBvdGhlciBoYW5kLCAkcl8yJCBpcyBuZWdhdGl2ZSBhbmQgc3Ryb25nZXIgdGhhbiAkcl8xJCwgaXQgaW5kaWNhdGVzIHRoYXQgd2hlbiB0aGUgc3R1ZGVudCB0byBmYWN1bHR5IHJhdGlvIGluY3JlYXNlLCB0aGUgZ2l2aW5nIHJhdGUgd2lsbCBkZWNyZWFzZS4gVGhlICRSXjIkIHZhbHVlIGlzIG1vZGVyYXRlIGFuZCBpbmRpY2F0ZXMgdGhhdCA1NCUgb2YgdGhlIHZhcmlhbmNlIGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIG1vZGVsLiAKCiMjIyMgUXVlc3Rpb24gMiBTaW11bGF0aW9uIFN0dWR5LiAKCioqYSkgR2VuZXJhdGUgTiA9IDEwMDAgb2JzZXJ2YXRpb25zIGZyb20gdGhlIG1vZGVsICRZIFxzaW0gNVhfMSAtIDJYXzIgKyBcZXBzaWxvbiQsIHdoZXJlICRYXzEgXHNpbSBOKFxtdSA9IDIsIFxzaWdtYSA9IDAuMSksIFhfMiBcc2ltIE4oXG11ID0gMCwgXHNpZ21hID0gMC40KSwgYW5kIFxlcHNpbG9uIFxzaW0gTihcbXUgPSAwLCBcc2lnbWEgPSAwLjUpLiQqKgoKYGBge3Igc2FtcGxlfQpzZXQuc2VlZCg3MDUyKQp4MSA8LSBybm9ybSgxMDAwLCBtZWFuID0gMiwgc2QgPSAwLjEpCngyIDwtIHJub3JtKDEwMDAsIG1lYW4gPSAwLCBzZCA9IDAuNCkKZXJyb3IgPC0gcm5vcm0oMTAwMCwgbWVhbiA9IDAsIHNkID0gMC41KQp5IDwtIDEwICsgNSAqIHgxIC0gMiAqIHgyICsgZXJyb3IKbWRhdGEgPC0gZGF0YS5mcmFtZSh4MSwgeDIsIHkpCmhlYWQobWRhdGEsIG49MykKYGBgCgoqKmIpIEZpdCBhIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIHRvIHRoZSBzaW11bGF0ZWQgZGF0YSBmcm9tIHBhcnQgYS4gV2hhdCBpcyB0aGUgZXN0aW1hdGVkIHByZWRpY3Rpb24gZXF1YXRpb24/IFJlcG9ydCB0aGUgZXN0aW1hdGVkIGNvZWZmaWNpZW50cyBhbmQgdGhlaXIgc3RhbmRhcmQgZXJyb3JzLiBBcmUgdGhleSBzaWduaWZpY2FudD8gQ2xlYXJseSB3cml0ZSBvdXQgdGhlIG51bGwgYW5kIGFsdGVybmF0aXZlIGh5cG90aGVzZXMsIG9ic2VydmVkIHQtc3RhdGlzdGljKHMpLCBwLXZhbHVlKHMpLCBhbmQgaW50ZXJwcmV0IHRoZSBlc3RpbWF0ZXMgYW5kIHRlc3QgcmVzdWx0cy4gV2hhdCBpcyBmaXR0ZWQgbW9kZWzigJlzIE1TRT8qKgoKYGBge3IgTUxSIG1kYXRhfQptZGF0YV9maXQgPC0gbG0oeSB+IHgxICsgeDIsIGRhdGEgPSBtZGF0YSkKc3VtbWFyeShtZGF0YV9maXQpCm1zZSA8LSBtZWFuKG1kYXRhX2ZpdCRyZXNpZHVhbHNeMikKcHJpbnQocGFzdGUoIk1TRToiLCBtc2UpKQpgYGAKCkkgdXNlZCB0aGUgYGxtKClgZnVuY3Rpb24gdG8gZml0IG15IG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uLiBGcm9tIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MsIHdlIGNhbiBzZWUgdGhhdCB0aGUgY29lZmZpY2llbnQgdmFsdWVzIGFyZSBsaXN0ZWQgYXMgJFxiZXRhXzEgPSA0Ljg3OCQgYW5kICRcYmV0YV8yID0gLTIuMDM5JC4gQmFzZWQgb24gdGhlIGZ1bGwgbW9kZWw6ICRcaGF0e3l9PSBcaGF0XGJldGFfMCArIFxoYXRcYmV0YV8xWF8xICsgXGhhdFxiZXRhXzJYXzIgKyBcZXBzaWxvbiQsIEkgY2FuIGVzdGltYXRlIHRoZSBwcmVkaWN0aW9uIGVxdWF0aW9uIHRvIGJlICRcaGF0e3l9ID0gMTAuMjYgKyA0Ljg3OFhfMSAtIDIuMDM5WF8yJC4KClRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzIGFuZCBzdGFuZGFyZCBlcnJvcnMgYXJlIDogNC44NzggYW5kIDAuMTUzIGZvciB4MSwgLTIuMDM5IGFuZCAwLjAzOCBmb3IgeDIuIAoKU2luY2Ugd2UgaGF2ZSBtdWx0aXBsZSBwcmVkaWN0b3JzIGluIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCwgd2UgY2FuIHVzZSBoeXBvdGhlc2VzIG9mIGludGVyZXN0IGxpa2UgJEhfMCA6IFxiZXRhX2ogPSAwJCAtIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNwb25zZSBhbmQgdGhlIHByZWRpY3RvcnMsIGFuZCAkSF8xOiBcYmV0YV9qIFxuZXEgMCQgLSB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBZIGFuZCBhbnkgb2YgdGhlIGZlYXR1cmVzLiBUbyBjb25kdWN0IGEgbWFyZ2luYWwgdGVzdCwgd2Ugd2lsbCBiZSBhYmxlIHRvIHNlZSB0IHZhbHVlIGFuZCBwIHZhbHVlIGZvciBlYWNoIHByZWRpY3Rvci4KCkZyb20gdGhlIHJlc3VsdHMsIHdlIGNhbiBzZWUgdGhhdCB0aGUgdCB2YWx1ZSBmb3IgeDEgaXMgMzEuOTggYW5kIHRoZSBwIHZhbHVlIGlzIGxlc3MgdGhhbiAkMmVeLTE2JCB3aGljaCBpcyBzbWFsbGVyIHRoYW4gdGhlIDAuMDUgdGhyZXNob2xkLCBzbyB3ZSBjYW4gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgb24geDEsIHRoYXQgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcmVzcG9uc2UgeSBhbmQgcHJlZGljdG9yIHgxLiBTYW1lLCB3ZSBzZWUgdGhlIHQgdmFsdWUgZm9yIHgyIGlzIC01My4xNiBhbmQgcCB2YWx1ZSBpcyBhbHNvIGxlc3MgdGhhbiAkMmVeLTE2JCwgc28gd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgb24geDIgYXMgd2VsbCwgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcmVzcG9uc2UgeSBhbmQgcHJlZGljdG9yIHgyLiBUYWtpbmcgYSBsb29rIGF0IHRoZSBGLXN0YXRpc3RpYywgaXQgaW5kaWNhdGVzIHRoYXQgdGhlIEYgdmFsdWUgaXMgMTg5MCB3aXRoIHAgdmFsdWUgbGVzcyB0aGFuICQyZV4tMTYkLCBzbyBvdmVyYWxsLCB3ZSBjYW4gYWxzbyByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgdGhhdCB0aGVyZSBpcyBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYmV0d2VlbiByZXNwb25zZSB5IGFuZCBib3RoIHByZWRpY3RvcnMuCgp4MSBoYXMgYSBwb3NpdGl2ZSBsaW5lYXIgcmVsYXRpb25zaGlwIHRvIHJlc3BvbnNlIHksIHdoZW4geDEgaW5jcmVhc2UsIHkgdmFsdWUgd2lsbCBhbHNvIGluY3JlYXNlOyBvbiB0aGUgb3RoZXIgdGhhbiwgeDIgaGFzIGEgbmVnYXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcCB0byByZXNwb25zZSB5LCBtZWFuaW5nIHdoZW4geDIgaW5jcmVhc2UsIHkgd2lsbCBkZWNyZWFzZS4KClRoZSBNU0UgdmFsdWUgaXMgYXJvdW5kIDAuMjM0LCB3aGljaCBpbmRpY2F0aW5nIGEgcmVhc29uYWJsZSBmaXQgb2YgdGhlIG1vZGVsIHRvIHRoZSBkYXRhLgoKKipjKSAJUmVwZWF0IHBhcnQgYiksIGJ1dCByZS1zaW11bGF0ZSB0aGUgZGF0YSBhbmQgY2hhbmdlIHRoZSBlcnJvciB0ZXJtIHRvIM+14oi8TijOvD0wLM+DPTEpIChpLmUuLCBzdGFuZGFyZCBub3JtYWwpLioqCgpgYGB7ciBoaWdoZXIgcmVzaWR1YWx9CnNldC5zZWVkKDcwNTIpCngxIDwtIHJub3JtKDEwMDAsIG1lYW4gPSAyLCBzZCA9IDAuMSkKeDIgPC0gcm5vcm0oMTAwMCwgbWVhbiA9IDAsIHNkID0gMC40KQplcnJvciA8LSBybm9ybSgxMDAwLCBtZWFuID0gMCwgc2QgPSAxKQp5IDwtIDEwICsgNSAqIHgxIC0gMiAqIHgyICsgZXJyb3IKbWRhdGEyIDwtIGRhdGEuZnJhbWUoeDEsIHgyLCB5KQpoZWFkKG1kYXRhMiwgbj0zKQpgYGAKCmBgYHtyIGZpdCBtZGF0YTJ9Cm1kYXRhX2ZpdDIgPC0gbG0oeSB+IHgxICsgeDIsIGRhdGEgPSBtZGF0YTIpCnN1bW1hcnkobWRhdGFfZml0MikKbXNlMiA8LSBtZWFuKG1kYXRhX2ZpdDIkcmVzaWR1YWxzXjIpCnByaW50KHBhc3RlKCJNU0UgZm9yIG1kYXRhX2ZpdDIgaXMgOiIsIG1zZTIpKQpgYGAKCkJ5IHVzaW5nIHRoZSBzYW1lIGZ1bmN0aW9uIHdpdGggdGhlIHByZXZpb3VzIGRhdGEgZnJhbWUsIHdlIGNhbiBzZWUgdGhhdCB0aGUgY29lZmZpY2llbnQgdmFsdWVzIGFyZSBsaXN0ZWQgYXMgJFxiZXRhXzEgPSA0Ljc1NiQgYW5kICRcYmV0YV8yID0gLTIuMDc4JC4gQmFzZWQgb24gdGhlIGZ1bGwgbW9kZWw6ICRcaGF0e3l9PSBcaGF0XGJldGFfMCArIFxoYXRcYmV0YV8xWF8xICsgXGhhdFxiZXRhXzJYXzIgKyBcZXBzaWxvbiQsIEkgY2FuIGVzdGltYXRlIHRoZSBwcmVkaWN0aW9uIGVxdWF0aW9uIHRvIGJlICRcaGF0e3l9ID0gMTAuNTMgKyA0Ljc1NlhfMSAtIDIuMDc4WF8yJC4KClRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzIGFuZCBzdGFuZGFyZCBlcnJvcnMgYXJlIDogNC43NTYgYW5kIDAuMzA1IGZvciB4MSwgLTIuMDc4IGFuZCAwLjA3NyBmb3IgeDIuIFdlIGNhbiBzZWUgdGhhdCB3aXRoIHRoZSBlcnJvciB2YXJpYW5jZSBpbmNyZWFzZWQsIHRoZSBzdGFuZGFyZCBlcnJvciBmb3IgZWFjaCBwcmVkaWN0b3IgYWxzbyBpbmNyZWFzZWQgKGRvdWJsZWQpLgoKVGhlIGh5cG90aGVzZXMgb2YgaW50ZXJlc3Q6IHRvIHNldCAkSF8wIDogXGJldGFfaiA9IDAkIC0gdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHJlc3BvbnNlIGFuZCB0aGUgcHJlZGljdG9ycywgYW5kICRIXzE6IFxiZXRhX2ogXG5lcSAwJCAtIHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFkgYW5kIGFueSBvZiB0aGUgZmVhdHVyZXMuIFRvIGNvbmR1Y3QgYSBtYXJnaW5hbCB0ZXN0LCB3ZSB3aWxsIGJlIGFibGUgdG8gc2VlIHQgdmFsdWUgYW5kIHAgdmFsdWUgZm9yIGVhY2ggcHJlZGljdG9yLgoKRnJvbSB0aGUgcmVzdWx0cywgd2UgY2FuIHNlZSB0aGF0IHRoZSB0IHZhbHVlIGZvciB4MSBpcyAxNS41OSBhbmQgdGhlIHAgdmFsdWUgaXMgbGVzcyB0aGFuICQyZV4tMTYkIHdoaWNoIGlzIHNtYWxsZXIgdGhhbiB0aGUgMC4wNSB0aHJlc2hvbGQsIHNvIHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvbiB4MSwgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNwb25zZSB5IGFuZCBwcmVkaWN0b3IgeDEuIFNhbWUsIHdlIHNlZSB0aGUgdCB2YWx1ZSBmb3IgeDIgaXMgLTI3LjA5IGFuZCBwIHZhbHVlIGlzIGFsc28gbGVzcyB0aGFuICQyZV4tMTYkLCBzbyB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvbiB4MiBhcyB3ZWxsLCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNwb25zZSB5IGFuZCBwcmVkaWN0b3IgeDIuIFRha2luZyBhIGxvb2sgYXQgdGhlIEYtc3RhdGlzdGljLCBpdCBpbmRpY2F0ZXMgdGhhdCB0aGUgRiB2YWx1ZSBpcyA0NzkuOCB3aXRoIHAgdmFsdWUgbGVzcyB0aGFuICQyZV4tMTYkLCBzbyBvdmVyYWxsLCB3ZSBjYW4gYWxzbyByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgdGhhdCB0aGVyZSBpcyBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYmV0d2VlbiByZXNwb25zZSBZIGFuZCBib3RoIHByZWRpY3RvcnMuCgpTYW1lIGFzIHRoZSBwcmV2aW91cyBzdGF0aXN0aWNzLCB4MSBoYXMgYSBwb3NpdGl2ZSBsaW5lYXIgcmVsYXRpb25zaGlwIHRvIHJlc3BvbnNlIHksIHdoZW4geDEgaW5jcmVhc2UsIHkgdmFsdWUgd2lsbCBhbHNvIGluY3JlYXNlOyBvbiB0aGUgb3RoZXIgdGhhbiwgeDIgaGFzIGEgbmVnYXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcCB0byByZXNwb25zZSB5LCBtZWFuaW5nIHdoZW4geDIgaW5jcmVhc2UsIHkgd2lsbCBkZWNyZWFzZS4KClRoZSBNU0UgdmFsdWUgaXMgYXJvdW5kIDAuOTM2LCB3aGljaCBoYXMgaW5jcmVhc2VkIHF1aXRlIGEgYml0IGNvbXBhcmVkIHRvIHRoZSBwcmV2aW91cyBmaXR0ZWQgbW9kZWwgc3RhdGlzdGljcywgaW5kaWNhdGluZyB0aGlzIG1heSBiZSBhIHdvcnNlIGZpdCBjb21wYXJlIHRvIHRoZSBwcmV2aW91cyBvbmUuCgoqKmQpIAlSZXBlYXQgcGFydHMgYSnigJNjKSB1c2luZyBOPTQwMC4gV2hhdCBkbyB5b3UgY29uY2x1ZGU/IFdoYXQgaXMgdGhlIGVmZmVjdCB0byB0aGUgbW9kZWwgcGFyYW1ldGVyIGVzdGltYXRlcyB3aGVuIHRoZSBlcnJvciB2YXJpYW5jZSBnZXRzIHNtYWxsZXI/IFdoYXQgaXMgdGhlIGVmZmVjdCB3aGVuIHRoZSBzYW1wbGUgc2l6ZSBnZXRzIGJpZ2dlcj8qKgoKSSdsbCBuYW1lIHRoZSBkYXRhIHdpdGggTj00MDAsIGVycm9yIHZhcmlhbmNlID0gMC41IHRvIGBtZGF0YTNgIGFuZCBOPTQwMCwgZXJyb3IgdmFyaWFuY2UgPSAxIHRvIGBtZGF0YTRgCgpgYGB7ciBzbWFsbGVyIHNhbXBsZSBzaXplIDAuNSBlcnJvciB2YXJpYW5jZX0Kc2V0LnNlZWQoNzA1MikKeDEgPC0gcm5vcm0oNDAwLCBtZWFuID0gMiwgc2QgPSAwLjEpCngyIDwtIHJub3JtKDQwMCwgbWVhbiA9IDAsIHNkID0gMC40KQplcnJvciA8LSBybm9ybSg0MDAsIG1lYW4gPSAwLCBzZCA9IDAuNSkKeSA8LSAxMCArIDUgKiB4MSAtIDIgKiB4MiArIGVycm9yCm1kYXRhMyA8LSBkYXRhLmZyYW1lKHgxLCB4MiwgeSkKaGVhZChtZGF0YTMsIG49MykKYGBgCgpgYGB7ciBzbWFsbGVyIHNhbXBsZSBzaXplLCAxIGVycm9yIHZhcmlhbmNlfQpzZXQuc2VlZCg3MDUyKQp4MSA8LSBybm9ybSg0MDAsIG1lYW4gPSAyLCBzZCA9IDAuMSkKeDIgPC0gcm5vcm0oNDAwLCBtZWFuID0gMCwgc2QgPSAwLjQpCmVycm9yIDwtIHJub3JtKDQwMCwgbWVhbiA9IDAsIHNkID0gMSkKeSA8LSAxMCArIDUgKiB4MSAtIDIgKiB4MiArIGVycm9yCm1kYXRhNCA8LSBkYXRhLmZyYW1lKHgxLCB4MiwgeSkKaGVhZChtZGF0YTQsIG49MykKYGBgCgpQZXJmb3JtIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBmb3IgbWRhdGEzIGFuZCBtZGF0YTQKCmBgYHtyIGRhdGFzZXQgMyBhbmQgNH0KbWRhdGFfZml0MyA8LSBsbSh5IH4geDEgKyB4MiwgZGF0YSA9IG1kYXRhMykKc3VtbWFyeShtZGF0YV9maXQzKQptc2UzIDwtIG1lYW4obWRhdGFfZml0MyRyZXNpZHVhbHNeMikKcHJpbnQocGFzdGUoIk1TRSBvZiBtZGF0YV9maXQzOiIsIG1zZTMpKQptZGF0YV9maXQ0IDwtIGxtKHkgfiB4MSArIHgyLCBkYXRhID0gbWRhdGE0KQpzdW1tYXJ5KG1kYXRhX2ZpdDQpCm1zZTQgPC0gbWVhbihtZGF0YV9maXQ0JHJlc2lkdWFsc14yKQpwcmludChwYXN0ZSgiTVNFIG9mIG1kYXRhX2ZpdDQ6IiwgbXNlNCkpCmBgYAoKRnJvbSB0aGUgYWJvdmUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciBgbWRhdGEzYCBhbmQgYG1kYXRhNGAsIHdlIGNhbiBsZWFybjoKCkZvciBgbWRhdGEzYCwgZ2l2ZW4gdGhlIGludGVyY2VwdCAxMC43MCBhbmQgc2xvcGUgZm9yIGJvdGggcHJlZGljdG9ycyBhcmUgNC42NjIgYW5kIC0xLjk1OCwgd2UgY2FuIHdyaXRlIHRoZSBlc3RpbWF0ZWQgcHJlZGljdGlvbiBlcXVhdGlvbiB0byBiZSAkXGhhdHt5fSA9IDEwLjcgKyA0LjY2MlhfMSAtIDEuOTU4WF8yJC4gRm9yIGBtZGF0YTRgLCBnaXZlbiB0aGUgaW50ZXJjZXB0IDExLjQwIGFuZCBzbG9wZSBmb3IgYm90aCBwcmVkaWN0b3JzIGFyZSA0LjMyNSBhbmQgLTEuOTE2LCB3ZSBjYW4gd3JpdGUgdGhlIGVzdGltYXRlZCBwcmVkaWN0aW9uIGVxdWF0aW9uIHRvIGJlICRcaGF0e3l9ID0gMTEuNCArIDQuMzI1WF8xIC0gMS45MTZYXzIkLgoKVGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMgYW5kIHN0YW5kYXJkIGVycm9ycyBmb3IgYG1kYXRhM2AgYXJlIDogNC42NjIgYW5kIDAuMjU5IGZvciB4MSwgLTEuOTU4IGFuZCAwLjA2NSBmb3IgeDI7IGZvciBgbWRhdGE0YDogNC4zMjUgYW5kIDAuNTE3IGZvciB4MSwgLTEuOTE2IGFuZCAwLjEzIGZvciB4Mi4gV2UgY2FuIHNlZSB0aGF0IHdpdGggdGhlIGVycm9yIHZhcmlhbmNlIGluY3JlYXNlZCwgdGhlIHN0YW5kYXJkIGVycm9yIGZvciBlYWNoIHByZWRpY3RvciBhbHNvIGluY3JlYXNlZCAoZG91YmxlZCkuCgpUaGUgaHlwb3RoZXNpcyB0ZXN0aW5nIGZvciBib3RoIGZpdHRlZCBtb2RlbHMgYG1kYXRhM2AgYW5kIGBtZGF0YTRgIGlzIHRoZSBzYW1lLiBUaGUgbnVsbCBoeXBvdGhlc2lzICRIXzAkIGlzIHRoYXQgdGhlcmUgaXMgbm8gbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHJlc3BvbnNlIHkgYW5kIHByZWRpY3RvcnMsICRIXzAgOiBcYmV0YV9qID0gMCQuIFRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICRIXzEkIGlzIHRoYXQgdGhlcmUgaXMgYSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gcmVzcG9uc2UgeSBhbmQgYW55IG9mIHRoZSBwcmVkaWN0b3JzLCAkSF8xOiBcYmV0YV9qIFxuZXEgMCQuCgpGb3IgYG1kYXRhM2AsIHRoZSB0IHZhbHVlIGZvciB4MSBpcyAxOC4wMiBhbmQgdGhlIHAgdmFsdWUgaXMgbGVzcyB0aGFuICQyZV4tMTYkIHdoaWNoIGlzIHNtYWxsZXIgdGhhbiB0aGUgMC4wNSB0aHJlc2hvbGQsIHNvIHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvbiB4MSwgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNwb25zZSBZIGFuZCBwcmVkaWN0b3IgeDEuIFNhbWUsIHdlIHNlZSB0aGUgdCB2YWx1ZSBmb3IgeDIgaXMgLTMwLjA4IGFuZCBwIHZhbHVlIGlzIGFsc28gbGVzcyB0aGFuICQyZV4tMTYkLCBzbyB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvbiB4MiBhcyB3ZWxsLCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiByZXNwb25zZSBZIGFuZCBwcmVkaWN0b3IgeDIuIFRha2luZyBhIGxvb2sgYXQgdGhlIEYtc3RhdGlzdGljLCBpdCBpbmRpY2F0ZXMgdGhhdCB0aGUgRiB2YWx1ZSBpcyA2MDIuMyB3aXRoIHAgdmFsdWUgbGVzcyB0aGFuICQyLjJlXi0xNiQsIHNvIG92ZXJhbGwsIHdlIGNhbiBhbHNvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLCB0aGF0IHRoZXJlIGlzIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBiZXR3ZWVuIHJlc3BvbnNlIFkgYW5kIGJvdGggcHJlZGljdG9ycy4gU2FtZSB3aXRoIGBtZGF0YTRgLCB0IHZhbHVlIGZvciB4MSBpcyA4LjM1OSwgcCB2YWx1ZSBpcyAkMS4wOF4tMTUkLCB0IHZhbHVlIGZvciB4MiBpcyAtMTQuNzE2LCBwIHZhbHVlIGlzIGxlc3MgdGhhbiAkMmVeLTE2JC4gQm90aCBwIHZhbHVlIHNob3dzIHRoYXQgd2Ugc2hvdWxkIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLCB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBiZXR3ZWVuIHJlc3BvbnNlIFkgYW5kIHByZWRpY3RvcnMgWDEgYW5kIFgyLiBXZSBjYW4gYWxzbyBsZWFybiB0aGF0IGZyb20gdGhlIEYtc3RhdGlzdGljLCBGIHZhbHVlIGlzIDE0MC40IGFuZCBwIHZhbHVlIGlzIGxlc3MgdGhhbiAkMi4yZV4tMTYkLiAKClNhbWUgYXMgdGhlIHByZXZpb3VzIHN0YXRpc3RpY3MsIHgxIGhhcyBhIHBvc2l0aXZlIGxpbmVhciByZWxhdGlvbnNoaXAgdG8gcmVzcG9uc2UgeSwgd2hlbiB4MSBpbmNyZWFzZSwgeSB2YWx1ZSB3aWxsIGFsc28gaW5jcmVhc2U7IG9uIHRoZSBvdGhlciB0aGFuLCB4MiBoYXMgYSBuZWdhdGl2ZSBsaW5lYXIgcmVsYXRpb25zaGlwIHRvIHJlc3BvbnNlIHksIG1lYW5pbmcgd2hlbiB4MiBpbmNyZWFzZSwgeSB3aWxsIGRlY3JlYXNlLgoKQWxzbywgZnJvbSB0aGlzIHNpbXVsYXRpb24sIHdlIGNhbiBzZWUgc29tZSBwYXR0ZXJucyB3aGVuIHRoZSBzYW1wbGUgc2l6ZSBhbmQgZXJyb3IgdGVybSB2YXJpYW5jZSBhcmUgY2hhbmdlZC4gU2VlIHRoZSBpbWFnZSBiZWxvdzoKCiFbKipUYWJsZSBDYXB0aW9uOiBUYWJsZSBvZiB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZyb20gZGlmZmVyZW50IHBhcmFtZXRlcnMqKl0oVEFCTEUyLkpQRykgIAoKV2hlbiBzYW1wbGUgc2l6ZSBpbmNyZWFzZXMsIHRoZSBlc3RpbWF0ZXMgb2YgdGhlIGNvZWZmaWNpZW50cyBnZXQgbW9yZSBwcmVjaXNlLCBhbmQgdGhlIHN0YW5kYXJkIGVycm9ycyBhcmUgc21hbGxlciBmb3IgYm90aCBwcmVkaWN0b3JzLiBUIHZhbHVlIHdpbGwgZ2V0IGxhcmdlciBhbmQgcCB2YWx1ZSB3aWxsIGdldCBsb3dlci4gSGlnaGVyIHQgdmFsdWUgbWVhbnMgdGhhdCB0aGUgY29lZmZpY2llbnRzIGFyZSBtb3JlIGxpa2VseSB0byBiZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBhbmQgbG93ZXIgcC12YWx1ZSBtYWtlcyB1cyBsaWtlbHkgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuIE9uIHRoZSBvdGhlciBoYW5kLCB3aGVuIHRoZSBlcnJvciB0ZXJtIHZhcmlhbmNlIGluY3JlYXNlcywgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSByZXNwb25zZSB2YXJpYWJsZSBpbmNyZWFzZXMsIGFuZCB3ZSBzZWUgaGlnaGVyIHN0YW5kYXJkIGVycm9ycyBmb3IgYm90aCBwcmVkaWN0b3JzLCBhbG1vc3QgZG91YmxlZC4gVGhlIHQgdmFsdWUgd2lsbCBkZWNyZWFzZSBhbmQgcCB2YWx1ZSB3aWxsIGluY3JlYXNlLCB3aGljaCBtZWFucyB0aGUgY29lZmZpY2llbnQgd2lsbCBiZSBsZXNzIGxpa2VseSBzaWduaWZpY2FudC4KCioqZSkgV2hhdCBhYm91dCB0aGUgTVNFIGZyb20gZWFjaCBtb2RlbD8qKgoKRnJvbSB0aGUgdGFibGUgYWJvdmUsIHdlIGNhbiBzZWUgdGhhdDoKCldoZW4gc2FtcGxlIHNpemUgaW5jcmVhc2VzLCB0aGUgTVNFIGRvZXMgbm90IGNoYW5nZSBtdWNoIHdoaWxlIHRoZSBlcnJvciB2YXJpYW5jZSBpcyB0aGUgc2FtZS4gSG93ZXZlciwgd2hlbiB0aGUgZXJyb3IgdmFyaWFuY2UgaW5jcmVhc2VzLCB0aGUgTVNFIHdpbGwgYWxzbyBpbmNyZWFzZSwgd2hpY2ggbWFrZXMgdGhlIHJlc2lkdWFscyBsYXJnZXIuIFNvIHdpdGggZXJyb3IgdmFyaWFuY2UgaW5jcmVhc2UsIHdlIG1heSBzZWUgYSB3b3JzZSBmaXQgb2YgdGhlIGRhdGEuCgojIyMjIFF1ZXN0aW9uIDMgTXVsdGlwbGUgTGluZWFyIFJlZ3Jlc3Npb24gaW4gTWF0cml4IE5vdGF0aW9uCgoqKmEpIFdyaXRlIG91dCB0aGUgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBub3JtYWwgZXJyb3JzIGluIG1hdHJpeCBmb3JtLioqCgpUaGUgcmVncmVzc2lvbiBtb2RlbCBjYW4gYmUgZXhwcmVzc2VkIGFzICRZID0gWFxiZXRhICsgXGVwc2lsb24kLCB3aGVyZSBZIGlzIGFuIG4gKiAxIHZlY3RvciBvZiByZXNwb25zZXMsICRcbWF0aGJme1l9ID0gXGJlZ2lue2JtYXRyaXh9IFlfMSAmIFlfMiAmIFxjZG90cyAmIFlfbiBcZW5ke2JtYXRyaXh9JCwgJFxiZXRhJCBpcyBhbiBwICogMSB2ZWN0b3Igb2YgY29lZmZpY2llbnRzLCAkXG1hdGhiZntcYmV0YX0gPSBcYmVnaW57Ym1hdHJpeH0gXGJldGFfMSAmIFxiZXRhXzIgJiBcY2RvdHMgJiBcYmV0YV97cC0xfSBcZW5ke2JtYXRyaXh9JCwgJFxlcHNpbG9uJCBpcyB0aGUgbm9ybWFsIGVycm9yLCBhbmQgWCBpcyBhbiBuICogcCBtb2RlbCBtYXRyaXguIAokXG1hdGhiZntYfSA9IFxiZWdpbntibWF0cml4fSAxICYgWF97MTF9ICYgWF97MTJ9ICYgXGNkb3QgJiBYX3sxLHAtMX0gXFwgMSAmIFhfezIxfSAmIFhfezIyfSAmIFxjZG90ICYgWF97MixwLTF9IFxcIFx2ZG90cyAmIFx2ZG90cyAmIFxkZG90cyAmIFx2ZG90cyBcXCAxICYgWF97bjF9ICYgWF97bjJ9ICYgXGNkb3QgJiBYX3tuLHAtMX0gXGVuZHtibWF0cml4fSQuCgoqKmIpIFN0YXRlIHRoZSBtb2RlbCBhc3N1bXB0aW9ucyBmcm9tIHBhcnQgYSkuKioKClRoZSB1c3VhbCBhc3N1bXB0aW9uIGlzIHRoYXQgdGhlICRcZXBzaWxvbiQgZXJyb3IgdGVybSBpcyBub3JtYWxseSBkaXN0cmlidXRlZCAkXGVwc2lsb24gXHNpbSBOICgwX24sIFxzaWdtYV4ySV9uKSQuIEkgaXMgdGhlIG4gKiBuIGlkZW50aXR5IG1hdHJpeC4gQWxsIGVycm9ycyBhcmUgaW5kZXBlbmRlbnQuCgoqKmMpIFdyaXRlIG91dCB0aGUgbW9kZWwgbWF0cml4IFggZm9yIHRoZSBtb2RlbCBpbiBwYXJ0IGEuKioKClggaXMgYW4gbiAqIHAgbW9kZWwgbWF0cml4LiAKJFxtYXRoYmZ7WH0gPSBcYmVnaW57Ym1hdHJpeH0gMSAmIFhfezExfSAmIFhfezEyfSAmIFxjZG90ICYgWF97MSxwLTF9IFxcIDEgJiBYX3syMX0gJiBYX3syMn0gJiBcY2RvdCAmIFhfezIscC0xfSBcXCBcdmRvdHMgJiBcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgXFwgMSAmIFhfe24xfSAmIFhfe24yfSAmIFxjZG90ICYgWF97bixwLTF9IFxlbmR7Ym1hdHJpeH0kLgoKKipkKSBXaGF0IGlzIHRoZSBsZWFzdCBzcXVhcmVzIGVzdGltYXRlIG9mIM6yIGluIHBhcnQgYSk/KioKClRvIGZpbmQgdGhlIHZhbHVlIG9mICRcYmV0YSQgdGhhdCBtaW5pbWl6ZXMgU1NFLCBkaWZmZXJlbnRpYXRlIFNTRSB3LnIudC4gJFxiZXRhJCBhbmQgZXF1YXRpbmcgdG8gemVybywgd2UgaGF2ZSBlcXVhdGlvbiAkMlheXGludGVyY2FsIFkgKyAyWF5caW50ZXJjYWwgWCBcYmV0YSA9IDBfcCQsIHNvICRcaGF0XGJldGEgPSAoWF5caW50ZXJjYWwgWCkgXnstMX0gWF5caW50ZXJjYWwgWSQuIFggaGFzIHRvIGJlIGZ1bGwgcmFuayBpbiBvcmRlciBmb3IgJFheXGludGVyY2FsIFgkIHRvIGJlIGludmVydGlibGUuCgoqKmUpIFdoYXQgZG9lcyBpdCBtZWFuIGZvciB0aGUgZXN0aW1hdGUgaW4gcGFydCBkKSB0byBiZSB1bmJpYXNlZD8qKgoKQXMgb25lIG9mIHRoZSBwcm9wZXJ0aWVzIG9mICRcaGF0XGJldGEkLCB1bmJpYXNlZCBtZWFucyB0aGUgZXhwZWN0ZWQgdmFsdWUgb2YgJFxoYXR7XGJldGF9JCBlcXVhbHMgdGhlIHRydWUgdmFsdWUgb2YgJFxiZXRhJC4KCg==