Abstract

In this workshop we will learn the basics of simple regression models in the context of Finance. We will learn how to run a regression model for the Market Model and a regression model to estimate the Capital Asset Pricing Model (CAPM).

Q Simple regression model

In a simple regression model is used to understand the linear relationship between two variables assuming that one variable, the independent variable (IV), can be used as a predictor of the other variable, the dependent variable (DV). In this part we illustrate a simple regression model with the Market Model.

The Market Model states that the expected return of a stock is given by its alpha coefficient (b0) plus its market beta coefficient (b1) multiplied times the market return. In mathematical terms:

E[Ri]=α+β(RM)

We can express the same equation using BO as alpha, and B1 as market beta:

E[Ri]=β0+β1(RM)

We can estimate the alpha and market beta coefficient by running a simple linear regression model specifying that the market return is the independent variable and the stock return is the dependent variable. It is strongly recommended to use continuously compounded returns instead of simple returns to estimate the market regression model. The market regression model can be expressed as:

r(i,t)=β0+β1∗r(M,t)+εt

Where:

εt is the error at time t. Thanks to the Central Limit Theorem, this error behaves like a Normal distributed random variable ∼ N(0, σε); the error term is expected to have mean=0 and a specific standard deviation (also called volatility).

r(i,t) is the return of the stock i at time t.

r(M,t) is the market return at time t

β0 and β1 are coefficients or constants

Data download

Now it’s time to use real data to better understand this model. Download monthly prices for Alfa (ALFAA.MX) and the IPCyC (^MXX) from Yahoo from January 2015 to Dec 2019. You must use ALSEA and the IPCyC to construct your own market model). You have to:

library(quantmod)
getSymbols(c("ALFAA.MX", "^MXX"), from="2015-01-01", to= "2019-12-31", periodicity="monthly", src="yahoo")
r_ALFAA <- na.omit(diff(log(ALFAA.MX$ALFAA.MX.Adjusted)))
r_MXX <- na.omit(diff(log(MXX$MXX.Adjusted)))
all_rets <- merge(r_ALFAA, r_MXX)
colnames(all_rets) <- c("ALFAA", "MXX")

Q Visualize the relationship

Do a scatter plot putting the IPCyC returns as the independent variable (X) and the stock return as the dependent variable (Y). We also add a line that better represents the relationship between the stock returns and the market returns. Type:

plot.default(x=all_rets$MXX,y=all_rets$ALFAA)
abline(lm(all_rets$ALFAA ~ all_rets$MXX),col='blue')

Sometimes graphs can be deceiving. In this case, the range of X axis and Y axis are different, so it is better to do a graph where we can make both X and Y ranges with equal distance. We also add a line that better represents the relationship between the stock returns and the market returns. Type:

plot.default(x=all_rets$MXX,y=all_rets$ALFAA, xlim=c(-0.30,0.30) )
abline(lm(all_rets$ALFAA ~ all_rets$MXX),col='blue')

WHAT DOES THE PLOT TELL YOU? BRIEFLY EXPLAIN THE REGRESSION LINE IS WHAT REPRESENTS THE POSITIVE RELATIONSHIP BETWEEN THE RETURNS IN THE MARKET AND THE STOCKS. WHEN THE MARKET RETURNS INCREASE, SO DO THE ALFA’S IN ALMOST A 1 TO 1 RELATIONSHIP.

Q Running the market regression model

Using the lm() function, run a simple regression model to see how the monthly returns of the stock are related with the market return. The first parameter of the function is the DEPENDENT VARIABLE (in this case, the stock return), and the second parameter must be the INDEPENDENT VARIABLE, also named the EXPLANATORY VARIABLE (in this case, the market return).

What you will get is called The Market Regression Model. You are trying to examine how the market returns can explain stock returns from Jan 2015 to Aug 2020.

Assign your market model to an object named “reg”.

reg <- lm(r_ALFAA ~ r_MXX)
sumreg<- summary(reg)
sumreg

We can calculate the main sums of squares of a regression model. In the Note “Basics of Linear Regression Models” you can remember what are these sums of squares.

For the sum of squares of total deviations from the mean of Y (SST), you can do the following:

Calculate a variable for the mean of the dependent variable Y (in this case, the stock return):

meanY = mean(r_ALFAA)

Calculate a variable with the squared deviations of each value of Y (stock returns) from its mean, and get the sum of these values:

squared_deviations_1 <- (r_ALFAA - meanY)^2
SST = sum(squared_deviations_1)
SST
[1] 0.2491152

For the sum of squares of the regression model (SSRM) you have to use the predicted values of the regression model, also called the fitted values of the model. These values are stored in the regression object reg we created with the lm function:

The fitted (predicted) values of the regression model are stored in the fitted.values attribute of the regression object:

fittedY = reg$fitted.values

Now you can get the SSRM with a similar process we followed to get the SST. Remember that you have to get the sum of squared deviations of each fitted value from the mean of Y.

squared_deviations_2 = (fittedY-meanY)^2
SSRM = sum(squared_deviations_2)
SSRM
[1] 0.1008404

In a similar process, you can get the sum of squares for the errors (SSE). To get the SSE you have to get the sum of squares of the difference between the real values of Y (stock return) and the predicted values (fittedY).

You can compare if your calculations of sum of squares are correct by running the ANOVA function as follows:

anova(reg)

In the column Sum Sq you can see the SSRM and the SSE.

RESPOND TO THE FOLLOWING QUESTIONS:

  1. What are the standard errors of the beta coefficients? (b0 and b1) What are they for? b0 IS -0.0102618, THE STANDARD ERROR IS 0.0066429. b1 IS 1.1688907, AND THE STANDARD ERROR IS 0.1877383.THE STANDARD ERROR OF A COEFFICIENT IS WHAT ONE CAN EXPECT AS THE STANDARD DEVIATION OF THE -COEFFICIENT-. REGRESSION COEFFICIENTS ARE CONSTANTLY CHANGING, SO THE STANDARD ERROR OF A COEFFICIENT GIVES US INFORMATION ABOUT THE RATE OF CHANGE OF A COEFFICIENT FROM ITS MEAN VALUE. THESE COEFFICIENTS HELP US CALCULATE THE STANDARD ERROR AND FROM THAT DERIVE TO THE CONFIDENCE INTERVAL.

  2. What is the total sum of squares (SST) ? (provide the result, and explain the formula) THE SST IS THE SUM OF SQUARES TOTAL OF THE REGRESSION MODEL.

THE TOTAL SUM OF SQUARES (SST) IS EQUAL TO SSRM + SSE.

sumsquares <- anova(reg)
sumsquares
Analysis of Variance Table

Response: r_ALFAA
          Df  Sum Sq  Mean Sq F value    Pr(>F)    
r_MXX      1 0.10084 0.100840  38.765 6.113e-08 ***
Residuals 57 0.14827 0.002601                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

SSE: 0.1482748 SSRM: 0.1008404 SST: 0.2491151

  1. What is the sum of squared errors (SSE) ? (provide the result, and explain the formula)
SSE <- SST - SSRM
SSE
[1] 0.1482748

AS WE DID IN THE EXERCISE ABOVE, SSE IS EQUAL TO .01482748

  1. What is the sum of squared regression differences (SSR) ? (provide the result and explain the formula)

AS WE DID IN THE EXERCISE ABOVE, SSR IS EQUAL TO 0.1008404 :/

  1. What is the coefficient of determination of the regression (the R-squared)? (provide the result and explain the formula) WE CAN OBTAIN R-SQUARED DIRECTLY FROM THE REGRESSION MODEL.
summary(reg)

Call:
lm(formula = r_ALFAA ~ r_MXX)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.097701 -0.036862 -0.004467  0.030768  0.146265 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.010262   0.006643  -1.545    0.128    
r_MXX        1.168891   0.187738   6.226 6.11e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.051 on 57 degrees of freedom
Multiple R-squared:  0.4048,    Adjusted R-squared:  0.3944 
F-statistic: 38.77 on 1 and 57 DF,  p-value: 6.113e-08

HERE WE CAN TELL THAT THE MULTIPLE R-SQUARED ARE EQUIVALENT TO 0.4048.

  1. Interpret the results of the beta coefficients (b0 and b1) and their corresponding t-values and p-values with your own words.

BETA ONE IS EQUAL TO 1.1688907, WHICH MEANS IT HAS A POSITIVE RELATIONSHIP TO THE MARKET RETURNS. ONE CAN SEE THAT ALFA IS RISKIER THAN THE MARKET SINCE THE BETA ONE COEFFICIENT IS HIGHER THAN 1, AND THE RELATIONSHIP IS DIRECTLY PROPORTIONAL ON A 1 TO 1.17% RATIO. THE P-VALUE IS 0.000000028, MAKING AN ERROR WHEN WE CONCLUDE TO REJECT THE NULL HYPOTHESIS IS ALMOST 0.

  1. Estimate an approximate 95% confidence interval for b0 and b1 and interpret them

AROUND 95% OF THE TIME, B1 CAN MOVE FROM 0.7934141 TO 1.5443674. ALFA RETURNS ARE RISKIER THAN THE MARKET SINCE BETA 1 CAN MOVE FROM LESS THAN ONE TO OVER ONE, BUT, WE DO NOT HAVE ENOUGH INDICATORS THAT ALFA RETURNS ARE RISKIER THAN THE MARKET RETURNS. T VALUE OF THE TEST IS LESS THAN 2, THUS WE CANNOT REJECT THE NULL HYPOTHESIS THAT SATES THAT BETA 1 EQUALS 1.

AROUND 95% OF THE TIME, BETA 0 WILL MOVE BETWEEN -0.023 TO 0.003, THUS BETA 0 ISN’T SIGNIFICANTLY LESS THAN 0. HOWEVER, MOST OF THE TIME BETA 0 WILL MOVE IN NEGATIVE VALUES. THE P-VALUE OF BETA 0, 0.127, 87% OF THE TIME WILL MOVE IN NEGATIVE VALUES. IF WE REJECT THE NULL HYPOTHSIS THE PROBABILITY THAT THE CONCLUSION WILL BE WRONG IS EQUIVALENT TO 0.127.

Q Estimating the CAPM model for a stock

The CAPM model

The Capital Asset Pricing Model states that the expected return of a stock is given by the risk-free rate plus its beta coefficient multiplied by the market premium return. In mathematical terms:

E[Ri]=Rf+β1(RM−Rf)

We can express the same equation as:

(E[Ri]−Rf)=β1(RM−Rf)

Then, we are saying that the expected value of the premium return of a stock is equal to the premium market return multiplied by its market beta coefficient. You can estimate the beta coefficient of the CAPM using a regression model and using continuously compounded returns instead of simple returns. However, you must include the intercept b0 in the regression equation:

(ri−rf)=β0+β1(rM−rf)+ε

Where ε ∼ N(0, σε); the error is a random shock with an expected mean=0 and a specific standard deviation or volatility. This error represents the result of all factors that influence stock returns, and cannot be explained by the model (by the market).

In the market model, the dependent variable was the stock return and the independent variable was the market return. Unlike the market model, here the dependent variable is the difference between the stock return minus the risk-free rate (the stock premium return), and the independent variable is the premium return, which is equal to the market return minus the risk-free rate. Let’s run this model in r with a couple of stocks.

Data collection

options(scipen=999)
library(quantmod)

Download stock data

Download monthly stock data for Apple, Tesla and the S&P500 from 2014 to Dec, 2020 from Yahoo Finance using the getSymbols function and obtain continuously compounded returns for each.

getSymbols(c("AAPL", "^GSPC", "TSLA"), from="2014-01-01", 
           to="2020-12-01", periodicity="monthly", src="yahoo")
[1] "AAPL"  "^GSPC" "TSLA" 
prices <- merge(AAPL$AAPL.Adjusted,GSPC$GSPC.Adjusted, TSLA$TSLA.Adjusted)
prices <- merge(Ad(AAPL), Ad(GSPC), Ad(TSLA))
APPL_r <- na.omit(diff(log(prices$AAPL.Adjusted)))
GSPC_r <- na.omit(diff(log(prices$GSPC.Adjusted)))
TSLA_r <- na.omit(diff(log(prices$TSLA.Adjusted)))

Download risk-free data from the FED

Download the risk-free monthly rate for the US (6-month treasury bills), which is the TB6MS ticker:

getSymbols("TB3MS", src = "FRED")
[1] "TB3MS"

This return is given in percentage and in annual rate. I divide it by 100 and 12 to get a monthly simple rate since I am using monthly rates for the stocks:

rfrate<-TB3MS/100/12

This return is given in percentage and in annual rate. I divide it by 100 and 12 to get a monthly simple rate since I am using monthly rates for the stocks:

rfrate <- log(1+rfrate)

I used the formula to get cc reteurns from simple returns, which is applying the natural log of the growth factor (1+rfrate)

Subsetting the risk-free dataset

Unfortunately, when getSymbols brings data from the FED, it brings all historical values of the series, even though the end date is specified.

Then, I do a sub-setting of the risk-free rate dataset to keep only those months that are equal to the months I brought for the stocks:

rfrate <- rfrate["2014-02-01/2020-12-01"]

Estimating the premium returns

Now you have to generate new variables (columns) for the premium returns for the stocks and the S&P 500. The premium returns will be equal to the returns minus the risk-free rat:

TSLA_Premr <- TSLA_r - rfrate
APPL_Premr <- APPL_r - rfrate
GSPC_Premr <- GSPC_r - rfrate

Q Visualize the relationship

Do a scatter plot putting the S&P500 premium returns as the independent variable (X) and Tesla premium return as the dependent variable (Y). We also add a line that better represents the relationship between the stock returns and the market returns:

plot.default(x=GSPC_Premr, y=TSLA_Premr)
abline(lm(TSLA_Premr ~ GSPC_Premr),col='blue')

Sometimes graphs can be deceiving. In this case, the range of X axis and Y axis are different, so it is better to do a graph where we can make both X and Y ranges with equal distance. We also add a line that better represents the relationship between the stock returns and the market returns. Type:

plot.default(x=GSPC_Premr, y=TSLA_Premr, ylim=c(-0.5,0.5),xlim=c(-0.6,0.6))
abline(lm(TSLA_Premr ~ GSPC_Premr),col='blue')

WHAT DOES THE PLOT TELL YOU? BRIEFLY EXPLAIN THE PLOT HAS A DIRECTLY PROPORTIONAL POSITIVE RELATIONSHIP, WHERE INCREMENTS IN THE MARKET RETURNS IMPACT THE STOCK RETURNS AND VICEVERSA. IF THE MARKET RETURNS DECREASE, SO DOES THE STOCK RETURNS. THE SLOPE OF THE PLOT APPEARS LARGER THAN 1 DUE TO THE ANGE BEING GREATER THAN 45 DEGREES. THEN, THE RELATIONSHIP IS EXPECTED TO BE 1 TO 1.

Q Estimating the CAPM model for a stock

Use the premium returns to run the CAPM regression model for each stock.

We start with Tesla:

Tesla_CAPM <-lm(TSLA_Premr ~ GSPC_Premr, na.action=na.omit)
Tesla_s <-summary(Tesla_CAPM)
Tesla_s

To do a rough estimate of the 95% confidence interval for B0:

minB0 <- Tesla_s$coefficients[1,1]  - (2* Tesla_s$coefficients[1,2] )
maxBO <-  Tesla_s$coefficients[1,1]  + (2* Tesla_s$coefficients[1,2] )

cat("The approx. B0 confidence interval goes from", minB0, "to", maxBO)
The approx. B0 confidence interval goes from -0.01294225 to 0.05062803
t_critical_value = qt(0.025,Tesla_CAPM$df.residual)
# I get the absolute value:
t_critical_value = abs(t_critical_value)
t_critical_value
[1] 1.990063

To estimate the 95% confidence interval for B1:

minB1 <- Tesla_s$coefficients[2,1]  - (2* Tesla_s$coefficients[2,2] )
maxB1 <-  Tesla_s$coefficients[2,1]  + (2* Tesla_s$coefficients[2,2] )
cat("The approx. B1 confidence interval goes from", minB1, "to", maxB1)
The approx. B1 confidence interval goes from 0.9959955 to 2.525798
minB1 <- Tesla_s$coefficients[2,1]  - (t_critical_value* Tesla_s$coefficients[2,2] )
maxB1 <-  Tesla_s$coefficients[2,1]  + (t_critical_value* Tesla_s$coefficients[2,2] )

cat("The B1 confidence interval goes from", minB1, "to", maxB1)
The B1 confidence interval goes from 0.9997957 to 2.521998
APPL_CAPM <-lm(APPL_Premr ~ GSPC_Premr, na.action=na.omit)
APPL_s <-summary(APPL_CAPM)
APPL_s

Call:
lm(formula = APPL_Premr ~ GSPC_Premr, na.action = na.omit)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.238842 -0.029580 -0.001329  0.039277  0.128609 

Coefficients:
            Estimate Std. Error t value       Pr(>|t|)    
(Intercept) 0.013915   0.006834   2.036          0.045 *  
GSPC_Premr  1.242986   0.164456   7.558 0.000000000059 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06074 on 80 degrees of freedom
Multiple R-squared:  0.4166,    Adjusted R-squared:  0.4093 
F-statistic: 57.13 on 1 and 80 DF,  p-value: 0.00000000005901
  1. INTERPRET THE RESULTS OF THE COEFFICIENTS (b0 and b1), THEIR STANDARD ERRORS, P-VALUES AND 95% CONFIDENCE INTERVALS.

AROUND 95% OF THE TIME, BETA 0 WILL MOVE BETWEEN -0.023 TO 0.003, THUS BETA 0 ISN’T SIGNIFICANTLY LESS THAN 0. HOWEVER, MOST OF THE TIME BETA 0 WILL MOVE IN NEGATIVE VALUES. THE P-VALUE OF BETA 0, 0.127, 87% OF THE TIME WILL MOVE IN NEGATIVE VALUES. IF WE REJECT THE NULL HYPOTHSIS THE PROBABILITY THAT THE CONCLUSION WILL BE WRONG IS EQUIVALENT TO 0.127. AROUND 95% OF THE TIME, B1 CAN MOVE FROM 0.7934141 TO 1.5443674. ALFA RETURNS ARE RISKIER THAN THE MARKET SINCE BETA 1 CAN MOVE FROM LESS THAN ONE TO OVER ONE, BUT, WE DO NOT HAVE ENOUGH INDICATORS THAT ALFA RETURNS ARE RISKIER THAN THE MARKET RETURNS. T VALUE OF THE TEST IS LESS THAN 2, THUS WE CANNOT REJECT THE NULL HYPOTHESIS THAT SATES THAT BETA 1 EQUALS 1.

  1. DO A QUICK RESEARCH ABOUT THE EFFICIENT MARKET HYPOTHESIS. BRIEFLY DESCRIBE WHAT THIS HYPOTHESIS SAYS.

ACCORDING TO RAJEEV DHIR, "THE EFFICIENT MARKET HYPOTHESIS (EMH) MAINTAINS THAT ALL STOCKS ARE PERFECTLY PRICED ACCORDING TO THEIR INHERENT INVESTMENT PROPERTIES, THE KNOWLEDGE OF WHICH ALL MARKET PARTICIPANTS POSSESS EQUALLY. - (INVESTOPEDIA, 06.30.21)

  1. ACCORDING TO THE EFFICIENT MARKET HYPOTHESIS, WHAT IS THE EXPECTED VALUE OF b0 in the CAPM REGRESSION MODEL? I COULDNT FIND INFORMATION REGARDING THIS QUESTION, BUT I WOULD GO FOR 0.

  2. ACCORDING TO YOUR RESULTS, IS TESLA SIGNIFICANTLY RISKIER THAN THE MARKET ? WHAT IS THE t-test YOU NEED TO DO TO RESPOND THIS QUESTION? Do the test and provide your interpretation. (Hint: Here you have to change the null hypothesis for b1: H0: b1=1; Ha=b1<>1)

THE BETA 1 COEFFICIENT FOR TESLA IS 1.760, TESLA PREMIUM RETURNS ARE RISKIER THAN THE MARKET PREMIUM RETURNS, ALTHOUGH ARGUABLY WELL HAVE TO TEST THIS.

Tesla_t <- (Tesla_s$coefficients[2,1]-1)/Tesla_s$coefficients[2,2]
Tesla_t
[1] 1.989529
pvalue<- 2*pt(Tesla_t, Tesla_CAPM$df.residual, lower.tail=FALSE)
pvalue
[1] 0.05006007
pvalue1tailed = pvalue / 2
pvalue1tailed
[1] 0.02503003

THE STATISTICAL EVIDENCE POINTS TOWARDS AT THE 95% CONFINDENCE INTERVAL TO SAY THAT TESLA PREMIUM RETURNS ARE SIGNIFICANTLY RISKIER THAN THOSE OF THE MARKET.

LS0tCnRpdGxlOiAiRmluYW5jaWFsIEVjb25vbWV0cmljcyAxLCBXb3Jrc2hvcCA0IgphdXRob3I6IFN0ZWZhbiBTY2h3ZWl0emVyIEEwMTIwOTc1NQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKIyMgQWJzdHJhY3QKCkluIHRoaXMgd29ya3Nob3Agd2Ugd2lsbCBsZWFybiB0aGUgYmFzaWNzIG9mIHNpbXBsZSByZWdyZXNzaW9uIG1vZGVscyBpbiB0aGUgY29udGV4dCBvZiBGaW5hbmNlLiBXZSB3aWxsIGxlYXJuIGhvdyB0byBydW4gYSByZWdyZXNzaW9uIG1vZGVsIGZvciB0aGUgTWFya2V0IE1vZGVsIGFuZCBhIHJlZ3Jlc3Npb24gbW9kZWwgdG8gZXN0aW1hdGUgdGhlIENhcGl0YWwgQXNzZXQgUHJpY2luZyBNb2RlbCAoQ0FQTSkuCgoKIyMgUSBTaW1wbGUgcmVncmVzc2lvbiBtb2RlbAoKSW4gYSBzaW1wbGUgcmVncmVzc2lvbiBtb2RlbCBpcyB1c2VkIHRvIHVuZGVyc3RhbmQgdGhlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gdmFyaWFibGVzIGFzc3VtaW5nIHRoYXQgb25lIHZhcmlhYmxlLCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgKElWKSwgY2FuIGJlIHVzZWQgYXMgYSBwcmVkaWN0b3Igb2YgdGhlIG90aGVyIHZhcmlhYmxlLCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIChEVikuIEluIHRoaXMgcGFydCB3ZSBpbGx1c3RyYXRlIGEgc2ltcGxlIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCB0aGUgTWFya2V0IE1vZGVsLgoKVGhlIE1hcmtldCBNb2RlbCBzdGF0ZXMgdGhhdCB0aGUgZXhwZWN0ZWQgcmV0dXJuIG9mIGEgc3RvY2sgaXMgZ2l2ZW4gYnkgaXRzIGFscGhhIGNvZWZmaWNpZW50IChiMCkgcGx1cyBpdHMgbWFya2V0IGJldGEgY29lZmZpY2llbnQgKGIxKSBtdWx0aXBsaWVkIHRpbWVzIHRoZSBtYXJrZXQgcmV0dXJuLiBJbiBtYXRoZW1hdGljYWwgdGVybXM6CgpFW1JpXT3OsSvOsihSTSkKCldlIGNhbiBleHByZXNzIHRoZSBzYW1lIGVxdWF0aW9uIHVzaW5nIEJPIGFzIGFscGhhLCBhbmQgQjEgYXMgbWFya2V0IGJldGE6CgpFW1JpXT3OsjArzrIxKFJNKQoKV2UgY2FuIGVzdGltYXRlIHRoZSBhbHBoYSBhbmQgbWFya2V0IGJldGEgY29lZmZpY2llbnQgYnkgcnVubmluZyBhIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBzcGVjaWZ5aW5nIHRoYXQgdGhlIG1hcmtldCByZXR1cm4gaXMgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlIGFuZCB0aGUgc3RvY2sgcmV0dXJuIGlzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUuIEl0IGlzIHN0cm9uZ2x5IHJlY29tbWVuZGVkIHRvIHVzZSBjb250aW51b3VzbHkgY29tcG91bmRlZCByZXR1cm5zIGluc3RlYWQgb2Ygc2ltcGxlIHJldHVybnMgdG8gZXN0aW1hdGUgdGhlIG1hcmtldCByZWdyZXNzaW9uIG1vZGVsLiBUaGUgbWFya2V0IHJlZ3Jlc3Npb24gbW9kZWwgY2FuIGJlIGV4cHJlc3NlZCBhczoKCnIoaSx0KT3OsjArzrIx4oiXcihNLHQpK861dAoKV2hlcmU6CgrOtXQgaXMgdGhlIGVycm9yIGF0IHRpbWUgdC4gVGhhbmtzIHRvIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0sIHRoaXMgZXJyb3IgYmVoYXZlcyBsaWtlIGEgTm9ybWFsIGRpc3RyaWJ1dGVkIHJhbmRvbSB2YXJpYWJsZSDiiLwgTigwLCDPg861KTsgdGhlIGVycm9yIHRlcm0gaXMgZXhwZWN0ZWQgdG8gaGF2ZSBtZWFuPTAgYW5kIGEgc3BlY2lmaWMgc3RhbmRhcmQgZGV2aWF0aW9uIChhbHNvIGNhbGxlZCB2b2xhdGlsaXR5KS4KCnIoaSx0KSBpcyB0aGUgcmV0dXJuIG9mIHRoZSBzdG9jayBpIGF0IHRpbWUgdC4KCnIoTSx0KSBpcyB0aGUgbWFya2V0IHJldHVybiBhdCB0aW1lIHQKCs6yMCBhbmQgzrIxIGFyZSBjb2VmZmljaWVudHMgb3IgY29uc3RhbnRzCgojIyBEYXRhIGRvd25sb2FkCgpOb3cgaXTigJlzIHRpbWUgdG8gdXNlIHJlYWwgZGF0YSB0byBiZXR0ZXIgdW5kZXJzdGFuZCB0aGlzIG1vZGVsLiBEb3dubG9hZCBtb250aGx5IHByaWNlcyBmb3IgQWxmYSAoQUxGQUEuTVgpIGFuZCB0aGUgSVBDeUMgKF5NWFgpIGZyb20gWWFob28gZnJvbSBKYW51YXJ5IDIwMTUgdG8gRGVjIDIwMTkuIFlvdSBtdXN0IHVzZSBBTFNFQSBhbmQgdGhlIElQQ3lDIHRvIGNvbnN0cnVjdCB5b3VyIG93biBtYXJrZXQgbW9kZWwpLiBZb3UgaGF2ZSB0bzoKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCmBgYAoKYGBge3J9CmdldFN5bWJvbHMoYygiQUxGQUEuTVgiLCAiXk1YWCIpLCBmcm9tPSIyMDE1LTAxLTAxIiwgdG89ICIyMDE5LTEyLTMxIiwgcGVyaW9kaWNpdHk9Im1vbnRobHkiLCBzcmM9InlhaG9vIikKYGBgCgpgYGB7cn0Kcl9BTEZBQSA8LSBuYS5vbWl0KGRpZmYobG9nKEFMRkFBLk1YJEFMRkFBLk1YLkFkanVzdGVkKSkpCmBgYAoKYGBge3J9CnJfTVhYIDwtIG5hLm9taXQoZGlmZihsb2coTVhYJE1YWC5BZGp1c3RlZCkpKQpgYGAKCmBgYHtyfQphbGxfcmV0cyA8LSBtZXJnZShyX0FMRkFBLCByX01YWCkKYGBgCgpgYGB7cn0KY29sbmFtZXMoYWxsX3JldHMpIDwtIGMoIkFMRkFBIiwgIk1YWCIpCmBgYAoKIyMgUSBWaXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcAoKRG8gYSBzY2F0dGVyIHBsb3QgcHV0dGluZyB0aGUgSVBDeUMgcmV0dXJucyBhcyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgKFgpIGFuZCB0aGUgc3RvY2sgcmV0dXJuIGFzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKFkpLiBXZSBhbHNvIGFkZCBhIGxpbmUgdGhhdCBiZXR0ZXIgcmVwcmVzZW50cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN0b2NrIHJldHVybnMgYW5kIHRoZSBtYXJrZXQgcmV0dXJucy4gVHlwZToKCmBgYHtyfQpwbG90LmRlZmF1bHQoeD1hbGxfcmV0cyRNWFgseT1hbGxfcmV0cyRBTEZBQSkKYWJsaW5lKGxtKGFsbF9yZXRzJEFMRkFBIH4gYWxsX3JldHMkTVhYKSxjb2w9J2JsdWUnKQpgYGAKClNvbWV0aW1lcyBncmFwaHMgY2FuIGJlIGRlY2VpdmluZy4gSW4gdGhpcyBjYXNlLCB0aGUgcmFuZ2Ugb2YgWCBheGlzIGFuZCBZIGF4aXMgYXJlIGRpZmZlcmVudCwgc28gaXQgaXMgYmV0dGVyIHRvIGRvIGEgZ3JhcGggd2hlcmUgd2UgY2FuIG1ha2UgYm90aCBYIGFuZCBZIHJhbmdlcyB3aXRoIGVxdWFsIGRpc3RhbmNlLiBXZSBhbHNvIGFkZCBhIGxpbmUgdGhhdCBiZXR0ZXIgcmVwcmVzZW50cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN0b2NrIHJldHVybnMgYW5kIHRoZSBtYXJrZXQgcmV0dXJucy4gVHlwZToKCmBgYHtyfQpwbG90LmRlZmF1bHQoeD1hbGxfcmV0cyRNWFgseT1hbGxfcmV0cyRBTEZBQSwgeGxpbT1jKC0wLjMwLDAuMzApICkKYWJsaW5lKGxtKGFsbF9yZXRzJEFMRkFBIH4gYWxsX3JldHMkTVhYKSxjb2w9J2JsdWUnKQpgYGAKCldIQVQgRE9FUyBUSEUgUExPVCBURUxMIFlPVT8gQlJJRUZMWSBFWFBMQUlOClRIRSBSRUdSRVNTSU9OIExJTkUgSVMgV0hBVCBSRVBSRVNFTlRTIFRIRSBQT1NJVElWRSBSRUxBVElPTlNISVAgQkVUV0VFTiBUSEUgUkVUVVJOUyBJTiBUSEUgTUFSS0VUIEFORCBUSEUgU1RPQ0tTLiBXSEVOIFRIRSBNQVJLRVQgUkVUVVJOUyBJTkNSRUFTRSwgU08gRE8gVEhFIEFMRkEnUyBJTiBBTE1PU1QgQSAxIFRPIDEgUkVMQVRJT05TSElQLgoKIyMgUSBSdW5uaW5nIHRoZSBtYXJrZXQgcmVncmVzc2lvbiBtb2RlbAoKVXNpbmcgdGhlIGxtKCkgZnVuY3Rpb24sIHJ1biBhIHNpbXBsZSByZWdyZXNzaW9uIG1vZGVsIHRvIHNlZSBob3cgdGhlIG1vbnRobHkgcmV0dXJucyBvZiB0aGUgc3RvY2sgYXJlIHJlbGF0ZWQgd2l0aCB0aGUgbWFya2V0IHJldHVybi4gVGhlIGZpcnN0IHBhcmFtZXRlciBvZiB0aGUgZnVuY3Rpb24gaXMgdGhlIERFUEVOREVOVCBWQVJJQUJMRSAoaW4gdGhpcyBjYXNlLCB0aGUgc3RvY2sgcmV0dXJuKSwgYW5kIHRoZSBzZWNvbmQgcGFyYW1ldGVyIG11c3QgYmUgdGhlIElOREVQRU5ERU5UIFZBUklBQkxFLCBhbHNvIG5hbWVkIHRoZSBFWFBMQU5BVE9SWSBWQVJJQUJMRSAoaW4gdGhpcyBjYXNlLCB0aGUgbWFya2V0IHJldHVybikuCgpXaGF0IHlvdSB3aWxsIGdldCBpcyBjYWxsZWQgVGhlIE1hcmtldCBSZWdyZXNzaW9uIE1vZGVsLiBZb3UgYXJlIHRyeWluZyB0byBleGFtaW5lIGhvdyB0aGUgbWFya2V0IHJldHVybnMgY2FuIGV4cGxhaW4gc3RvY2sgcmV0dXJucyBmcm9tIEphbiAyMDE1IHRvIEF1ZyAyMDIwLgoKQXNzaWduIHlvdXIgbWFya2V0IG1vZGVsIHRvIGFuIG9iamVjdCBuYW1lZCDigJxyZWfigJ0uCgpgYGB7cn0KcmVnIDwtIGxtKHJfQUxGQUEgfiByX01YWCkKYGBgCgpgYGB7cn0Kc3VtcmVnPC0gc3VtbWFyeShyZWcpCmBgYAoKYGBge3J9CnN1bXJlZwpgYGAKCldlIGNhbiBjYWxjdWxhdGUgdGhlIG1haW4gc3VtcyBvZiBzcXVhcmVzIG9mIGEgcmVncmVzc2lvbiBtb2RlbC4gSW4gdGhlIE5vdGUg4oCcQmFzaWNzIG9mIExpbmVhciBSZWdyZXNzaW9uIE1vZGVsc+KAnSB5b3UgY2FuIHJlbWVtYmVyIHdoYXQgYXJlIHRoZXNlIHN1bXMgb2Ygc3F1YXJlcy4KCkZvciB0aGUgc3VtIG9mIHNxdWFyZXMgb2YgdG90YWwgZGV2aWF0aW9ucyBmcm9tIHRoZSBtZWFuIG9mIFkgKFNTVCksIHlvdSBjYW4gZG8gdGhlIGZvbGxvd2luZzoKCkNhbGN1bGF0ZSBhIHZhcmlhYmxlIGZvciB0aGUgbWVhbiBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIFkgKGluIHRoaXMgY2FzZSwgdGhlIHN0b2NrIHJldHVybik6CgpgYGB7cn0KbWVhblkgPSBtZWFuKHJfQUxGQUEpCmBgYAoKQ2FsY3VsYXRlIGEgdmFyaWFibGUgd2l0aCB0aGUgc3F1YXJlZCBkZXZpYXRpb25zIG9mIGVhY2ggdmFsdWUgb2YgWSAoc3RvY2sgcmV0dXJucykgZnJvbSBpdHMgbWVhbiwgYW5kIGdldCB0aGUgc3VtIG9mIHRoZXNlIHZhbHVlczoKCmBgYHtyfQpzcXVhcmVkX2RldmlhdGlvbnNfMSA8LSAocl9BTEZBQSAtIG1lYW5ZKV4yClNTVCA9IHN1bShzcXVhcmVkX2RldmlhdGlvbnNfMSkKU1NUCmBgYApGb3IgdGhlIHN1bSBvZiBzcXVhcmVzIG9mIHRoZSByZWdyZXNzaW9uIG1vZGVsIChTU1JNKSB5b3UgaGF2ZSB0byB1c2UgdGhlIHByZWRpY3RlZCB2YWx1ZXMgb2YgdGhlIHJlZ3Jlc3Npb24gbW9kZWwsIGFsc28gY2FsbGVkIHRoZSBmaXR0ZWQgdmFsdWVzIG9mIHRoZSBtb2RlbC4gVGhlc2UgdmFsdWVzIGFyZSBzdG9yZWQgaW4gdGhlIHJlZ3Jlc3Npb24gb2JqZWN0IHJlZyB3ZSBjcmVhdGVkIHdpdGggdGhlIGxtIGZ1bmN0aW9uOgoKVGhlIGZpdHRlZCAocHJlZGljdGVkKSB2YWx1ZXMgb2YgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgYXJlIHN0b3JlZCBpbiB0aGUgZml0dGVkLnZhbHVlcyBhdHRyaWJ1dGUgb2YgdGhlIHJlZ3Jlc3Npb24gb2JqZWN0OgoKYGBge3J9CmZpdHRlZFkgPSByZWckZml0dGVkLnZhbHVlcwpgYGAKCk5vdyB5b3UgY2FuIGdldCB0aGUgU1NSTSB3aXRoIGEgc2ltaWxhciBwcm9jZXNzIHdlIGZvbGxvd2VkIHRvIGdldCB0aGUgU1NULiBSZW1lbWJlciB0aGF0IHlvdSBoYXZlIHRvIGdldCB0aGUgc3VtIG9mIHNxdWFyZWQgZGV2aWF0aW9ucyBvZiBlYWNoIGZpdHRlZCB2YWx1ZSBmcm9tIHRoZSBtZWFuIG9mIFkuCgpgYGB7cn0Kc3F1YXJlZF9kZXZpYXRpb25zXzIgPSAoZml0dGVkWS1tZWFuWSleMgpgYGAKCmBgYHtyfQpTU1JNID0gc3VtKHNxdWFyZWRfZGV2aWF0aW9uc18yKQpTU1JNCmBgYAoKSW4gYSBzaW1pbGFyIHByb2Nlc3MsIHlvdSBjYW4gZ2V0IHRoZSBzdW0gb2Ygc3F1YXJlcyBmb3IgdGhlIGVycm9ycyAoU1NFKS4gVG8gZ2V0IHRoZSBTU0UgeW91IGhhdmUgdG8gZ2V0IHRoZSBzdW0gb2Ygc3F1YXJlcyBvZiB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSByZWFsIHZhbHVlcyBvZiBZIChzdG9jayByZXR1cm4pIGFuZCB0aGUgcHJlZGljdGVkIHZhbHVlcyAoZml0dGVkWSkuCgpZb3UgY2FuIGNvbXBhcmUgaWYgeW91ciBjYWxjdWxhdGlvbnMgb2Ygc3VtIG9mIHNxdWFyZXMgYXJlIGNvcnJlY3QgYnkgcnVubmluZyB0aGUgQU5PVkEgZnVuY3Rpb24gYXMgZm9sbG93czoKCmBgYHtyfQphbm92YShyZWcpCmBgYAoKSW4gdGhlIGNvbHVtbiBTdW0gU3EgeW91IGNhbiBzZWUgdGhlIFNTUk0gYW5kIHRoZSBTU0UuCgojIyBSRVNQT05EIFRPIFRIRSBGT0xMT1dJTkcgUVVFU1RJT05TOgoKMS4gV2hhdCBhcmUgdGhlIHN0YW5kYXJkIGVycm9ycyBvZiB0aGUgYmV0YSBjb2VmZmljaWVudHM/IChiMCBhbmQgYjEpIFdoYXQgYXJlIHRoZXkgZm9yPwpiMCBJUyAtMC4wMTAyNjE4LCBUSEUgU1RBTkRBUkQgRVJST1IgSVMgMC4wMDY2NDI5LgpiMSBJUyAxLjE2ODg5MDcsIEFORCBUSEUgU1RBTkRBUkQgRVJST1IgSVMgMC4xODc3MzgzLlRIRSBTVEFOREFSRCBFUlJPUiBPRiBBIENPRUZGSUNJRU5UIElTIFdIQVQgT05FIENBTiBFWFBFQ1QgQVMgVEhFIFNUQU5EQVJEIERFVklBVElPTiBPRiBUSEUgLUNPRUZGSUNJRU5ULS4gUkVHUkVTU0lPTiBDT0VGRklDSUVOVFMgQVJFIENPTlNUQU5UTFkgQ0hBTkdJTkcsIFNPIFRIRSBTVEFOREFSRCBFUlJPUiBPRiBBIENPRUZGSUNJRU5UIEdJVkVTIFVTIElORk9STUFUSU9OIEFCT1VUIFRIRSBSQVRFIE9GIENIQU5HRSBPRiBBIENPRUZGSUNJRU5UIEZST00gSVRTIE1FQU4gVkFMVUUuIFRIRVNFIENPRUZGSUNJRU5UUyBIRUxQIFVTIENBTENVTEFURSBUSEUgU1RBTkRBUkQgRVJST1IgQU5EIEZST00gVEhBVCBERVJJVkUgVE8gVEhFIENPTkZJREVOQ0UgSU5URVJWQUwuCgoyLiBXaGF0IGlzIHRoZSB0b3RhbCBzdW0gb2Ygc3F1YXJlcyAoU1NUKSA/IChwcm92aWRlIHRoZSByZXN1bHQsIGFuZCBleHBsYWluIHRoZSBmb3JtdWxhKSBUSEUgU1NUIElTIFRIRSBTVU0gT0YgU1FVQVJFUyBUT1RBTCBPRiBUSEUgUkVHUkVTU0lPTiBNT0RFTC4KClRIRSBUT1RBTCBTVU0gT0YgU1FVQVJFUyAoU1NUKSBJUyBFUVVBTCBUTyBTU1JNICsgU1NFLiAKYGBge3J9CnN1bXNxdWFyZXMgPC0gYW5vdmEocmVnKQpzdW1zcXVhcmVzCmBgYApTU0U6IDAuMTQ4Mjc0OApTU1JNOiAwLjEwMDg0MDQKU1NUOiAwLjI0OTExNTEKCjMuIFdoYXQgaXMgdGhlIHN1bSBvZiBzcXVhcmVkIGVycm9ycyAoU1NFKSA/IChwcm92aWRlIHRoZSByZXN1bHQsIGFuZCBleHBsYWluIHRoZSBmb3JtdWxhKQpgYGB7cn0KU1NFIDwtIFNTVCAtIFNTUk0KU1NFCmBgYApBUyBXRSBESUQgSU4gVEhFIEVYRVJDSVNFIEFCT1ZFLCBTU0UgSVMgRVFVQUwgVE8gLjAxNDgyNzQ4Cgo0LiBXaGF0IGlzIHRoZSBzdW0gb2Ygc3F1YXJlZCByZWdyZXNzaW9uIGRpZmZlcmVuY2VzIChTU1IpID8gKHByb3ZpZGUgdGhlIHJlc3VsdCBhbmQgZXhwbGFpbiB0aGUgZm9ybXVsYSkKCkFTIFdFIERJRCBJTiBUSEUgRVhFUkNJU0UgQUJPVkUsIFNTUiBJUyBFUVVBTCBUTyAwLjEwMDg0MDQgOi8KCjUuIFdoYXQgaXMgdGhlIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24gb2YgdGhlIHJlZ3Jlc3Npb24gKHRoZSBSLXNxdWFyZWQpPyAocHJvdmlkZSB0aGUgcmVzdWx0IGFuZCBleHBsYWluIHRoZSBmb3JtdWxhKQpXRSBDQU4gT0JUQUlOIFItU1FVQVJFRCBESVJFQ1RMWSBGUk9NIFRIRSBSRUdSRVNTSU9OIE1PREVMLgpgYGB7cn0Kc3VtbWFyeShyZWcpCmBgYApIRVJFIFdFIENBTiBURUxMIFRIQVQgVEhFIE1VTFRJUExFIFItU1FVQVJFRCBBUkUgRVFVSVZBTEVOVCBUTyAwLjQwNDguCgo2LiBJbnRlcnByZXQgdGhlIHJlc3VsdHMgb2YgdGhlIGJldGEgY29lZmZpY2llbnRzIChiMCBhbmQgYjEpIGFuZCB0aGVpciBjb3JyZXNwb25kaW5nIHQtdmFsdWVzIGFuZCBwLXZhbHVlcyB3aXRoIHlvdXIgb3duIHdvcmRzLgoKQkVUQSBPTkUgSVMgRVFVQUwgVE8gMS4xNjg4OTA3LCBXSElDSCBNRUFOUyBJVCBIQVMgQSBQT1NJVElWRSBSRUxBVElPTlNISVAgVE8gVEhFIE1BUktFVCBSRVRVUk5TLiBPTkUgQ0FOIFNFRSBUSEFUIEFMRkEgSVMgUklTS0lFUiBUSEFOIFRIRSBNQVJLRVQgU0lOQ0UgVEhFIEJFVEEgT05FIENPRUZGSUNJRU5UIElTIEhJR0hFUiBUSEFOIDEsIEFORCBUSEUgUkVMQVRJT05TSElQIElTIERJUkVDVExZIFBST1BPUlRJT05BTCBPTiBBIDEgVE8gMS4xNyUgUkFUSU8uClRIRSBQLVZBTFVFIElTIDAuMDAwMDAwMDI4LCBNQUtJTkcgQU4gRVJST1IgV0hFTiBXRSBDT05DTFVERSBUTyBSRUpFQ1QgVEhFIE5VTEwgSFlQT1RIRVNJUyBJUyBBTE1PU1QgMC4KCjcuIEVzdGltYXRlIGFuIGFwcHJveGltYXRlIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciBiMCBhbmQgYjEgYW5kIGludGVycHJldCB0aGVtCgpBUk9VTkQgOTUlIE9GIFRIRSBUSU1FLCBCMSBDQU4gTU9WRSBGUk9NIDAuNzkzNDE0MSBUTyAxLjU0NDM2NzQuIEFMRkEgUkVUVVJOUyBBUkUgUklTS0lFUiBUSEFOIFRIRSBNQVJLRVQgU0lOQ0UgQkVUQSAxIENBTiBNT1ZFIEZST00gTEVTUyBUSEFOIE9ORSBUTyBPVkVSIE9ORSwgQlVULCBXRSBETyBOT1QgSEFWRSBFTk9VR0ggSU5ESUNBVE9SUyBUSEFUIEFMRkEgUkVUVVJOUyBBUkUgUklTS0lFUiBUSEFOIFRIRSBNQVJLRVQgUkVUVVJOUy4gVCBWQUxVRSBPRiBUSEUgVEVTVCBJUyBMRVNTIFRIQU4gMiwgVEhVUyBXRSBDQU5OT1QgUkVKRUNUIFRIRSBOVUxMIEhZUE9USEVTSVMgVEhBVCBTQVRFUyBUSEFUIEJFVEEgMSBFUVVBTFMgMS4KCkFST1VORCA5NSUgT0YgVEhFIFRJTUUsIEJFVEEgMCBXSUxMIE1PVkUgQkVUV0VFTiAtMC4wMjMgVE8gMC4wMDMsIFRIVVMgQkVUQSAwIElTTidUIFNJR05JRklDQU5UTFkgTEVTUyBUSEFOIDAuIEhPV0VWRVIsIE1PU1QgT0YgVEhFIFRJTUUgQkVUQSAwIFdJTEwgTU9WRSBJTiBORUdBVElWRSBWQUxVRVMuIFRIRSBQLVZBTFVFIE9GIEJFVEEgMCwgMC4xMjcsIDg3JSBPRiBUSEUgVElNRSBXSUxMIE1PVkUgSU4gTkVHQVRJVkUgVkFMVUVTLiBJRiBXRSBSRUpFQ1QgVEhFIE5VTEwgSFlQT1RIU0lTIFRIRSBQUk9CQUJJTElUWSBUSEFUIFRIRSBDT05DTFVTSU9OIFdJTEwgQkUgV1JPTkcgSVMgRVFVSVZBTEVOVCBUTyAwLjEyNy4gCgojIyBRIEVzdGltYXRpbmcgdGhlIENBUE0gbW9kZWwgZm9yIGEgc3RvY2sKIyMgVGhlIENBUE0gbW9kZWwKClRoZSBDYXBpdGFsIEFzc2V0IFByaWNpbmcgTW9kZWwgc3RhdGVzIHRoYXQgdGhlIGV4cGVjdGVkIHJldHVybiBvZiBhIHN0b2NrIGlzIGdpdmVuIGJ5IHRoZSByaXNrLWZyZWUgcmF0ZSBwbHVzIGl0cyBiZXRhIGNvZWZmaWNpZW50IG11bHRpcGxpZWQgYnkgdGhlIG1hcmtldCBwcmVtaXVtIHJldHVybi4gSW4gbWF0aGVtYXRpY2FsIHRlcm1zOgoKRVtSaV09UmYrzrIxKFJN4oiSUmYpCgpXZSBjYW4gZXhwcmVzcyB0aGUgc2FtZSBlcXVhdGlvbiBhczoKCihFW1JpXeKIklJmKT3OsjEoUk3iiJJSZikKClRoZW4sIHdlIGFyZSBzYXlpbmcgdGhhdCB0aGUgZXhwZWN0ZWQgdmFsdWUgb2YgdGhlIHByZW1pdW0gcmV0dXJuIG9mIGEgc3RvY2sgaXMgZXF1YWwgdG8gdGhlIHByZW1pdW0gbWFya2V0IHJldHVybiBtdWx0aXBsaWVkIGJ5IGl0cyBtYXJrZXQgYmV0YSBjb2VmZmljaWVudC4gWW91IGNhbiBlc3RpbWF0ZSB0aGUgYmV0YSBjb2VmZmljaWVudCBvZiB0aGUgQ0FQTSB1c2luZyBhIHJlZ3Jlc3Npb24gbW9kZWwgYW5kIHVzaW5nIGNvbnRpbnVvdXNseSBjb21wb3VuZGVkIHJldHVybnMgaW5zdGVhZCBvZiBzaW1wbGUgcmV0dXJucy4gSG93ZXZlciwgeW91IG11c3QgaW5jbHVkZSB0aGUgaW50ZXJjZXB0IGIwIGluIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uOgoKKHJp4oiScmYpPc6yMCvOsjEock3iiJJyZikrzrUKCldoZXJlIM61IOKIvCBOKDAsIM+DzrUpOyB0aGUgZXJyb3IgaXMgYSByYW5kb20gc2hvY2sgd2l0aCBhbiBleHBlY3RlZCBtZWFuPTAgYW5kIGEgc3BlY2lmaWMgc3RhbmRhcmQgZGV2aWF0aW9uIG9yIHZvbGF0aWxpdHkuIFRoaXMgZXJyb3IgcmVwcmVzZW50cyB0aGUgcmVzdWx0IG9mIGFsbCBmYWN0b3JzIHRoYXQgaW5mbHVlbmNlIHN0b2NrIHJldHVybnMsIGFuZCBjYW5ub3QgYmUgZXhwbGFpbmVkIGJ5IHRoZSBtb2RlbCAoYnkgdGhlIG1hcmtldCkuCgpJbiB0aGUgbWFya2V0IG1vZGVsLCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIHdhcyB0aGUgc3RvY2sgcmV0dXJuIGFuZCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgd2FzIHRoZSBtYXJrZXQgcmV0dXJuLiBVbmxpa2UgdGhlIG1hcmtldCBtb2RlbCwgaGVyZSB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHN0b2NrIHJldHVybiBtaW51cyB0aGUgcmlzay1mcmVlIHJhdGUgKHRoZSBzdG9jayBwcmVtaXVtIHJldHVybiksIGFuZCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgaXMgdGhlIHByZW1pdW0gcmV0dXJuLCB3aGljaCBpcyBlcXVhbCB0byB0aGUgbWFya2V0IHJldHVybiBtaW51cyB0aGUgcmlzay1mcmVlIHJhdGUuIExldOKAmXMgcnVuIHRoaXMgbW9kZWwgaW4gciB3aXRoIGEgY291cGxlIG9mIHN0b2Nrcy4KCiMjIERhdGEgY29sbGVjdGlvbgpgYGB7cn0Kb3B0aW9ucyhzY2lwZW49OTk5KQpsaWJyYXJ5KHF1YW50bW9kKQpgYGAKCiMjIERvd25sb2FkIHN0b2NrIGRhdGEKCkRvd25sb2FkIG1vbnRobHkgc3RvY2sgZGF0YSBmb3IgQXBwbGUsIFRlc2xhIGFuZCB0aGUgUyZQNTAwIGZyb20gMjAxNCB0byBEZWMsIDIwMjAgZnJvbSBZYWhvbyBGaW5hbmNlIHVzaW5nIHRoZSBnZXRTeW1ib2xzIGZ1bmN0aW9uIGFuZCBvYnRhaW4gY29udGludW91c2x5IGNvbXBvdW5kZWQgcmV0dXJucyBmb3IgZWFjaC4KYGBge3J9CmdldFN5bWJvbHMoYygiQUFQTCIsICJeR1NQQyIsICJUU0xBIiksIGZyb209IjIwMTQtMDEtMDEiLCAKICAgICAgICAgICB0bz0iMjAyMC0xMi0wMSIsIHBlcmlvZGljaXR5PSJtb250aGx5Iiwgc3JjPSJ5YWhvbyIpCmBgYAoKCmBgYHtyfQpwcmljZXMgPC0gbWVyZ2UoQUFQTCRBQVBMLkFkanVzdGVkLEdTUEMkR1NQQy5BZGp1c3RlZCwgVFNMQSRUU0xBLkFkanVzdGVkKQpgYGAKCmBgYHtyfQpwcmljZXMgPC0gbWVyZ2UoQWQoQUFQTCksIEFkKEdTUEMpLCBBZChUU0xBKSkKYGBgCgpgYGB7cn0KQVBQTF9yIDwtIG5hLm9taXQoZGlmZihsb2cocHJpY2VzJEFBUEwuQWRqdXN0ZWQpKSkKR1NQQ19yIDwtIG5hLm9taXQoZGlmZihsb2cocHJpY2VzJEdTUEMuQWRqdXN0ZWQpKSkKVFNMQV9yIDwtIG5hLm9taXQoZGlmZihsb2cocHJpY2VzJFRTTEEuQWRqdXN0ZWQpKSkKYGBgCgojIyBEb3dubG9hZCByaXNrLWZyZWUgZGF0YSBmcm9tIHRoZSBGRUQKCkRvd25sb2FkIHRoZSByaXNrLWZyZWUgbW9udGhseSByYXRlIGZvciB0aGUgVVMgKDYtbW9udGggdHJlYXN1cnkgYmlsbHMpLCB3aGljaCBpcyB0aGUgVEI2TVMgdGlja2VyOgpgYGB7cn0KZ2V0U3ltYm9scygiVEIzTVMiLCBzcmMgPSAiRlJFRCIpCmBgYApUaGlzIHJldHVybiBpcyBnaXZlbiBpbiBwZXJjZW50YWdlIGFuZCBpbiBhbm51YWwgcmF0ZS4gSSBkaXZpZGUgaXQgYnkgMTAwIGFuZCAxMiB0byBnZXQgYSBtb250aGx5IHNpbXBsZSByYXRlIHNpbmNlIEkgYW0gdXNpbmcgbW9udGhseSByYXRlcyBmb3IgdGhlIHN0b2NrczoKYGBge3J9CnJmcmF0ZTwtVEIzTVMvMTAwLzEyCmBgYApUaGlzIHJldHVybiBpcyBnaXZlbiBpbiBwZXJjZW50YWdlIGFuZCBpbiBhbm51YWwgcmF0ZS4gSSBkaXZpZGUgaXQgYnkgMTAwIGFuZCAxMiB0byBnZXQgYSBtb250aGx5IHNpbXBsZSByYXRlIHNpbmNlIEkgYW0gdXNpbmcgbW9udGhseSByYXRlcyBmb3IgdGhlIHN0b2NrczoKYGBge3J9CnJmcmF0ZSA8LSBsb2coMStyZnJhdGUpCmBgYApJIHVzZWQgdGhlIGZvcm11bGEgdG8gZ2V0IGNjIHJldGV1cm5zIGZyb20gc2ltcGxlIHJldHVybnMsIHdoaWNoIGlzIGFwcGx5aW5nIHRoZSBuYXR1cmFsIGxvZyBvZiB0aGUgZ3Jvd3RoIGZhY3RvciAoMStyZnJhdGUpCgojIyBTdWJzZXR0aW5nIHRoZSByaXNrLWZyZWUgZGF0YXNldAoKVW5mb3J0dW5hdGVseSwgd2hlbiBnZXRTeW1ib2xzIGJyaW5ncyBkYXRhIGZyb20gdGhlIEZFRCwgaXQgYnJpbmdzIGFsbCBoaXN0b3JpY2FsIHZhbHVlcyBvZiB0aGUgc2VyaWVzLCBldmVuIHRob3VnaCB0aGUgZW5kIGRhdGUgaXMgc3BlY2lmaWVkLgoKVGhlbiwgSSBkbyBhIHN1Yi1zZXR0aW5nIG9mIHRoZSByaXNrLWZyZWUgcmF0ZSBkYXRhc2V0IHRvIGtlZXAgb25seSB0aG9zZSBtb250aHMgdGhhdCBhcmUgZXF1YWwgdG8gdGhlIG1vbnRocyBJIGJyb3VnaHQgZm9yIHRoZSBzdG9ja3M6CmBgYHtyfQpyZnJhdGUgPC0gcmZyYXRlWyIyMDE0LTAyLTAxLzIwMjAtMTItMDEiXQpgYGAKCiMjIEVzdGltYXRpbmcgdGhlIHByZW1pdW0gcmV0dXJucwoKTm93IHlvdSBoYXZlIHRvIGdlbmVyYXRlIG5ldyB2YXJpYWJsZXMgKGNvbHVtbnMpIGZvciB0aGUgcHJlbWl1bSByZXR1cm5zIGZvciB0aGUgc3RvY2tzIGFuZCB0aGUgUyZQIDUwMC4gVGhlIHByZW1pdW0gcmV0dXJucyB3aWxsIGJlIGVxdWFsIHRvIHRoZSByZXR1cm5zIG1pbnVzIHRoZSByaXNrLWZyZWUgcmF0OgoKYGBge3J9ClRTTEFfUHJlbXIgPC0gVFNMQV9yIC0gcmZyYXRlCkFQUExfUHJlbXIgPC0gQVBQTF9yIC0gcmZyYXRlCkdTUENfUHJlbXIgPC0gR1NQQ19yIC0gcmZyYXRlCmBgYAoKIyMgUSBWaXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcAoKRG8gYSBzY2F0dGVyIHBsb3QgcHV0dGluZyB0aGUgUyZQNTAwIHByZW1pdW0gcmV0dXJucyBhcyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgKFgpIGFuZCBUZXNsYSBwcmVtaXVtIHJldHVybiBhcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIChZKS4gV2UgYWxzbyBhZGQgYSBsaW5lIHRoYXQgYmV0dGVyIHJlcHJlc2VudHMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBzdG9jayByZXR1cm5zIGFuZCB0aGUgbWFya2V0IHJldHVybnM6CgpgYGB7cn0KcGxvdC5kZWZhdWx0KHg9R1NQQ19QcmVtciwgeT1UU0xBX1ByZW1yKQphYmxpbmUobG0oVFNMQV9QcmVtciB+IEdTUENfUHJlbXIpLGNvbD0nYmx1ZScpCmBgYAoKU29tZXRpbWVzIGdyYXBocyBjYW4gYmUgZGVjZWl2aW5nLiBJbiB0aGlzIGNhc2UsIHRoZSByYW5nZSBvZiBYIGF4aXMgYW5kIFkgYXhpcyBhcmUgZGlmZmVyZW50LCBzbyBpdCBpcyBiZXR0ZXIgdG8gZG8gYSBncmFwaCB3aGVyZSB3ZSBjYW4gbWFrZSBib3RoIFggYW5kIFkgcmFuZ2VzIHdpdGggZXF1YWwgZGlzdGFuY2UuIFdlIGFsc28gYWRkIGEgbGluZSB0aGF0IGJldHRlciByZXByZXNlbnRzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgc3RvY2sgcmV0dXJucyBhbmQgdGhlIG1hcmtldCByZXR1cm5zLiBUeXBlOgoKYGBge3J9CnBsb3QuZGVmYXVsdCh4PUdTUENfUHJlbXIsIHk9VFNMQV9QcmVtciwgeWxpbT1jKC0wLjUsMC41KSx4bGltPWMoLTAuNiwwLjYpKQphYmxpbmUobG0oVFNMQV9QcmVtciB+IEdTUENfUHJlbXIpLGNvbD0nYmx1ZScpCmBgYApXSEFUIERPRVMgVEhFIFBMT1QgVEVMTCBZT1U/IEJSSUVGTFkgRVhQTEFJTgpUSEUgUExPVCBIQVMgQSBESVJFQ1RMWSBQUk9QT1JUSU9OQUwgUE9TSVRJVkUgUkVMQVRJT05TSElQLCBXSEVSRSBJTkNSRU1FTlRTIElOIFRIRSBNQVJLRVQgUkVUVVJOUyBJTVBBQ1QgVEhFIFNUT0NLIFJFVFVSTlMgQU5EIFZJQ0VWRVJTQS4gSUYgVEhFIE1BUktFVCBSRVRVUk5TIERFQ1JFQVNFLCBTTyBET0VTIFRIRSBTVE9DSyBSRVRVUk5TLiBUSEUgU0xPUEUgT0YgVEhFIFBMT1QgQVBQRUFSUyBMQVJHRVIgVEhBTiAxIERVRSBUTyBUSEUgQU5HRSBCRUlORyBHUkVBVEVSIFRIQU4gNDUgREVHUkVFUy4gVEhFTiwgVEhFIFJFTEFUSU9OU0hJUCBJUyBFWFBFQ1RFRCBUTyBCRSAxIFRPIDEuCgojIyBRIEVzdGltYXRpbmcgdGhlIENBUE0gbW9kZWwgZm9yIGEgc3RvY2sKClVzZSB0aGUgcHJlbWl1bSByZXR1cm5zIHRvIHJ1biB0aGUgQ0FQTSByZWdyZXNzaW9uIG1vZGVsIGZvciBlYWNoIHN0b2NrLgoKV2Ugc3RhcnQgd2l0aCBUZXNsYToKCmBgYHtyfQpUZXNsYV9DQVBNIDwtbG0oVFNMQV9QcmVtciB+IEdTUENfUHJlbXIsIG5hLmFjdGlvbj1uYS5vbWl0KQpUZXNsYV9zIDwtc3VtbWFyeShUZXNsYV9DQVBNKQpUZXNsYV9zCmBgYAoKVG8gZG8gYSByb3VnaCBlc3RpbWF0ZSBvZiB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIEIwOgoKYGBge3J9Cm1pbkIwIDwtIFRlc2xhX3MkY29lZmZpY2llbnRzWzEsMV0gIC0gKDIqIFRlc2xhX3MkY29lZmZpY2llbnRzWzEsMl0gKQptYXhCTyA8LSAgVGVzbGFfcyRjb2VmZmljaWVudHNbMSwxXSAgKyAoMiogVGVzbGFfcyRjb2VmZmljaWVudHNbMSwyXSApCgpjYXQoIlRoZSBhcHByb3guIEIwIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZ29lcyBmcm9tIiwgbWluQjAsICJ0byIsIG1heEJPKQpgYGAKYGBge3J9CnRfY3JpdGljYWxfdmFsdWUgPSBxdCgwLjAyNSxUZXNsYV9DQVBNJGRmLnJlc2lkdWFsKQojIEkgZ2V0IHRoZSBhYnNvbHV0ZSB2YWx1ZToKdF9jcml0aWNhbF92YWx1ZSA9IGFicyh0X2NyaXRpY2FsX3ZhbHVlKQp0X2NyaXRpY2FsX3ZhbHVlCmBgYAoKClRvIGVzdGltYXRlIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgQjE6CgpgYGB7cn0KbWluQjEgPC0gVGVzbGFfcyRjb2VmZmljaWVudHNbMiwxXSAgLSAoMiogVGVzbGFfcyRjb2VmZmljaWVudHNbMiwyXSApCm1heEIxIDwtICBUZXNsYV9zJGNvZWZmaWNpZW50c1syLDFdICArICgyKiBUZXNsYV9zJGNvZWZmaWNpZW50c1syLDJdICkKY2F0KCJUaGUgYXBwcm94LiBCMSBjb25maWRlbmNlIGludGVydmFsIGdvZXMgZnJvbSIsIG1pbkIxLCAidG8iLCBtYXhCMSkKYGBgCmBgYHtyfQptaW5CMSA8LSBUZXNsYV9zJGNvZWZmaWNpZW50c1syLDFdICAtICh0X2NyaXRpY2FsX3ZhbHVlKiBUZXNsYV9zJGNvZWZmaWNpZW50c1syLDJdICkKbWF4QjEgPC0gIFRlc2xhX3MkY29lZmZpY2llbnRzWzIsMV0gICsgKHRfY3JpdGljYWxfdmFsdWUqIFRlc2xhX3MkY29lZmZpY2llbnRzWzIsMl0gKQoKY2F0KCJUaGUgQjEgY29uZmlkZW5jZSBpbnRlcnZhbCBnb2VzIGZyb20iLCBtaW5CMSwgInRvIiwgbWF4QjEpCmBgYApgYGB7cn0KQVBQTF9DQVBNIDwtbG0oQVBQTF9QcmVtciB+IEdTUENfUHJlbXIsIG5hLmFjdGlvbj1uYS5vbWl0KQpBUFBMX3MgPC1zdW1tYXJ5KEFQUExfQ0FQTSkKQVBQTF9zCmBgYAooYSkgSU5URVJQUkVUIFRIRSBSRVNVTFRTIE9GIFRIRSBDT0VGRklDSUVOVFMgKGIwIGFuZCBiMSksIFRIRUlSIFNUQU5EQVJEIEVSUk9SUywgUC1WQUxVRVMgQU5EIDk1JSBDT05GSURFTkNFIElOVEVSVkFMUy4KCkFST1VORCA5NSUgT0YgVEhFIFRJTUUsIEJFVEEgMCBXSUxMIE1PVkUgQkVUV0VFTiAtMC4wMjMgVE8gMC4wMDMsIFRIVVMgQkVUQSAwIElTTidUIFNJR05JRklDQU5UTFkgTEVTUyBUSEFOIDAuIEhPV0VWRVIsIE1PU1QgT0YgVEhFIFRJTUUgQkVUQSAwIFdJTEwgTU9WRSBJTiBORUdBVElWRSBWQUxVRVMuIFRIRSBQLVZBTFVFIE9GIEJFVEEgMCwgMC4xMjcsIDg3JSBPRiBUSEUgVElNRSBXSUxMIE1PVkUgSU4gTkVHQVRJVkUgVkFMVUVTLiBJRiBXRSBSRUpFQ1QgVEhFIE5VTEwgSFlQT1RIU0lTIFRIRSBQUk9CQUJJTElUWSBUSEFUIFRIRSBDT05DTFVTSU9OIFdJTEwgQkUgV1JPTkcgSVMgRVFVSVZBTEVOVCBUTyAwLjEyNy4gCkFST1VORCA5NSUgT0YgVEhFIFRJTUUsIEIxIENBTiBNT1ZFIEZST00gMC43OTM0MTQxIFRPIDEuNTQ0MzY3NC4gQUxGQSBSRVRVUk5TIEFSRSBSSVNLSUVSIFRIQU4gVEhFIE1BUktFVCBTSU5DRSBCRVRBIDEgQ0FOIE1PVkUgRlJPTSBMRVNTIFRIQU4gT05FIFRPIE9WRVIgT05FLCBCVVQsIFdFIERPIE5PVCBIQVZFIEVOT1VHSCBJTkRJQ0FUT1JTIFRIQVQgQUxGQSBSRVRVUk5TIEFSRSBSSVNLSUVSIFRIQU4gVEhFIE1BUktFVCBSRVRVUk5TLiBUIFZBTFVFIE9GIFRIRSBURVNUIElTIExFU1MgVEhBTiAyLCBUSFVTIFdFIENBTk5PVCBSRUpFQ1QgVEhFIE5VTEwgSFlQT1RIRVNJUyBUSEFUIFNBVEVTIFRIQVQgQkVUQSAxIEVRVUFMUyAxLgoKKGIpIERPIEEgUVVJQ0sgUkVTRUFSQ0ggQUJPVVQgVEhFIEVGRklDSUVOVCBNQVJLRVQgSFlQT1RIRVNJUy4gQlJJRUZMWSBERVNDUklCRSBXSEFUIFRISVMgSFlQT1RIRVNJUyBTQVlTLgoKQUNDT1JESU5HIFRPIFJBSkVFViBESElSLCAiVEhFIEVGRklDSUVOVCBNQVJLRVQgSFlQT1RIRVNJUyAoRU1IKSBNQUlOVEFJTlMgVEhBVCBBTEwgU1RPQ0tTIEFSRSBQRVJGRUNUTFkgUFJJQ0VEIEFDQ09SRElORyBUTyBUSEVJUiBJTkhFUkVOVCBJTlZFU1RNRU5UIFBST1BFUlRJRVMsIFRIRSBLTk9XTEVER0UgT0YgV0hJQ0ggQUxMIE1BUktFVCBQQVJUSUNJUEFOVFMgUE9TU0VTUyBFUVVBTExZLiAtIChJTlZFU1RPUEVESUEsIDA2LjMwLjIxKQoKKGMpIEFDQ09SRElORyBUTyBUSEUgRUZGSUNJRU5UIE1BUktFVCBIWVBPVEhFU0lTLCBXSEFUIElTIFRIRSBFWFBFQ1RFRCBWQUxVRSBPRiBiMCBpbiB0aGUgQ0FQTSBSRUdSRVNTSU9OIE1PREVMPwpJIENPVUxETlQgRklORCBJTkZPUk1BVElPTiBSRUdBUkRJTkcgVEhJUyBRVUVTVElPTiwgQlVUIEkgV09VTEQgR08gRk9SIDAuCgooZCkgQUNDT1JESU5HIFRPIFlPVVIgUkVTVUxUUywgSVMgVEVTTEEgU0lHTklGSUNBTlRMWSBSSVNLSUVSIFRIQU4gVEhFIE1BUktFVCA/IFdIQVQgSVMgVEhFIHQtdGVzdCBZT1UgTkVFRCBUTyBETyBUTyBSRVNQT05EIFRISVMgUVVFU1RJT04/IERvIHRoZSB0ZXN0IGFuZCBwcm92aWRlIHlvdXIgaW50ZXJwcmV0YXRpb24uIChIaW50OiBIZXJlIHlvdSBoYXZlIHRvIGNoYW5nZSB0aGUgbnVsbCBoeXBvdGhlc2lzIGZvciBiMTogSDA6IGIxPTE7IEhhPWIxPD4xKQoKVEhFIEJFVEEgMSBDT0VGRklDSUVOVCBGT1IgVEVTTEEgSVMgMS43NjAsIFRFU0xBIFBSRU1JVU0gUkVUVVJOUyBBUkUgUklTS0lFUiBUSEFOIFRIRSBNQVJLRVQgUFJFTUlVTSBSRVRVUk5TLCBBTFRIT1VHSCBBUkdVQUJMWSBXRUxMIEhBVkUgVE8gVEVTVCBUSElTLgoKYGBge3J9ClRlc2xhX3QgPC0gKFRlc2xhX3MkY29lZmZpY2llbnRzWzIsMV0tMSkvVGVzbGFfcyRjb2VmZmljaWVudHNbMiwyXQpUZXNsYV90CmBgYApgYGB7cn0KcHZhbHVlPC0gMipwdChUZXNsYV90LCBUZXNsYV9DQVBNJGRmLnJlc2lkdWFsLCBsb3dlci50YWlsPUZBTFNFKQpwdmFsdWUKYGBgCmBgYHtyfQpwdmFsdWUxdGFpbGVkID0gcHZhbHVlIC8gMgpwdmFsdWUxdGFpbGVkCmBgYApUSEUgU1RBVElTVElDQUwgRVZJREVOQ0UgUE9JTlRTIFRPV0FSRFMgQVQgVEhFIDk1JSBDT05GSU5ERU5DRSBJTlRFUlZBTCBUTyBTQVkgVEhBVCBURVNMQSBQUkVNSVVNIFJFVFVSTlMgQVJFIFNJR05JRklDQU5UTFkgUklTS0lFUiBUSEFOIFRIT1NFIE9GIFRIRSBNQVJLRVQuCg==