Workshop 9, Financial Econometrics II
Alberto Dorantes, Ph.D. Apr 27, 2022
Consideration
Estimados estudiantes: En estos días getSymbols de la librería
quantmod NO está funcionando (marca un error al bajar datos). Para
arreglar el error, tienen que re-instalar la librería quantmod. Pueden
hacerlo desde Packages en la ventana inferior derecha de RStudio, ó
también escribir en la consola:
install.packages("quantmod")
Error in install.packages : Updating loaded packages
library(quantmod)
Abstract
In this workshop we will learn about Value at Risk (VaR) and Expected
Shortfall (ES) and how to apply it to a real-world market index. We will
also use a GARCH(1,1) model to forecast volatility and VaR.
Introduction to Value at Risk (VaR)
Value at Risk (VaR) is a measure of risk that focuses on potential
losses of an investment in a short period of time. Investment firms and
banks constantly monitor VaR of their portfolios in order to be prepared
in case a bad scenario. VaR is usually estimated daily using a small
probability such as 5%, 1%, or 0.1%. Very bad scenarios in the short
term have a certain probability p to happen in one day. For example, if
the probability of losing 10% or MORE of an investment in one single day
is 5%, then we say that the 5% Value at Risk (5%VaR) is equal to 10%. We
can also calculate VaR in money if we know the initial investment. For
example, using the same example, if my initial investment is $1’000,000,
then the 5%VaR = 10%, which is equal to $100,000.00. VaR can be reported
as a positive or negative amount; this is just a matter of preference.
But we have to be aware that VaR is a measure of potential loss in % or
in $ with a certain probability. p%VaR is the MINIMUM % loss of an
investment with a probability of p. In other words, there is a
probability p that I can lose %VaR or MORE. Another way to define p%VaR
is the following. p%VaR is the MAXIMUM %loss of an investment with a
probatility (1-p). In other words, there is a probability (1-p) that I
can have a return of %VaR or HIGHER. Then, we can say that p%VaR is the
best scenario that can happen after a very bad scenario that can happen
with probability p. Also, we can say that p%VaR is the worse scenario
that can happen when the scenario is not the bad one, so when there is a
probability of (1-p)%. Let’s illustrate VaR using real data from the US
index S&P500 daily returns from January 2019 to April 26, 2022.
library(quantmod)
getSymbols("^GSPC", from="2019-01-01",
to="2022-04-27")
[1] "^GSPC"
# I get the adjusted column:
SPindex = Ad(GSPC)
# I calculate daily returns of the index:
SPreturn<- na.omit(diff(log(SPindex)))
names(SPreturn)<-c("return")
We plot the daily index over time:
plot(SPindex)

We see strong decline in March 2020, another important decline in
early 2022.
Now we do a histogram of the return of this index
hist(SPreturn, breaks=40)

The height of each bar represents the frequency in number of days
that a specific daily return range has happened.
If the daily returns behaves like a normal-distributed variable, then
about 2.5% of the days the S&P500 returns would be less than the its
mean minus 2 times its standard deviation. Remember that for a
normal-distributed variable, in the range plus/minus 2 standard
deviations from its mean, we will find about 95% of the values.
We downloaded 835 days of return, so we would expect that about
20.875 will be the # of days that the SP&500 would offer returns
less than -2 times its standard deviation from its mean:
# Number of days for the S&P returns:
N=nrow(SPreturn)
N
[1] 835
# The 2.5% of these # of days is about:
n25=0.025*nrow(SPreturn)
n25
[1] 20.875
Now we can look the real data and see how many days the S&P500
has offered returns less than 2 times its standard deviation from its
mean. We can calculate the mean and standard deviation (volatility) of
daily returns, and then identify how many days the S&P500 has
offered extreme returns less than the mean minus 2 times its
volatility:
# We calculate the mean and standard deviation of returns:
mean_return=mean(SPreturn$return)
mean_return
[1] 0.0006094223
volatility = sd(SPreturn$return)
volatility
[1] 0.01417127
# We calculate the expected minimum return of the 95% confidence interval (C.I.)
# assuming normality (the 2.5 percentile)
min95ci_returns = mean_return-2*volatility
min95ci_returns
[1] -0.02773312
# We select the days with returns less than the minimum of the 95% C.I.
extremes<- SPreturn[SPreturn$return<min95ci_returns,]
extremes
return
2019-08-05 -0.03023018
2019-08-14 -0.02973035
2020-02-24 -0.03408808
2020-02-25 -0.03074790
2020-02-27 -0.04516814
2020-03-03 -0.02851048
2020-03-05 -0.03451078
2020-03-09 -0.07901041
2020-03-11 -0.05010289
2020-03-12 -0.09994485
2020-03-16 -0.12765220
2020-03-18 -0.05322227
2020-03-20 -0.04432762
2020-03-23 -0.02973150
2020-03-27 -0.03426785
2020-04-01 -0.04514636
2020-04-21 -0.03115512
2020-05-01 -0.02846021
2020-06-11 -0.06075269
2020-09-03 -0.03575759
2020-09-08 -0.02814883
2020-10-28 -0.03592554
2022-03-07 -0.02996259
2022-04-22 -0.02813208
2022-04-26 -0.02855001
nextremes = nrow(extremes)
# Number of extreme returns:
nextremes
[1] 25
percextremes = nextremes / N * 100
percextremes
[1] 2.994012
In this case, we have 25 extreme days with returns less than the
minimum of the 95% C.I. of daily returns. Then, it seems that we have
had more extreme returns than expected. This represents about 2.994012%
of the total # of days, which is greater than the expected 2.5%.
Then, 2.994012% of the time, the S&P500 has experience a loss of
-2.7733123% or MORE. If we believe that in the future the S&P500
will behave in a similar manner, then we can say that there is a
probability of 2.994012% that I can lose -2.7733123% or MORE in only ONE
DAY.
We can also say that there is a probability of 97.005988% (100% -
2.994012%) that the MAXIMUM loss I can experience in ONE DAY is
-2.7733123%. Then, the 2.994012%VaR of the daily S&P500 returns is
-2.7733123%
VaR1 = min95ci_returns*100
VaR1
[1] -2.773312
For turbulence periods in financial markets it is likely that a bad
scenario with probability p can happen. Once this scenario happens, then
p%VaR is the best scenario, but in reality this the p%VaR is not too
realistic. We need to be more conservative and estimate which might be
the expected loss once the probability p of the bad scenario happens.
This conservative estimate is given by the Expected Shortfall. We will
review the concept of ES in the following section.
Expected Shortfall (ES)
Expected Shortfall with a probability p refers to the expected
average loss of an investment in ONE period (in this case, in one day)
once the probability p of a bad scenario happens. Then, the absolute
value of p%ES will always be greater (more negative) than the p%VaR.
Let’s calculate the ES using the previous example of the S&P500 500
daily returns.
To estimate the ES at the 2.994012% probability, we just calculate
the average of the days when the S&P500 returns have been less than
-2.7733123%.We can do this as follows
extremes
return
2019-08-05 -0.03023018
2019-08-14 -0.02973035
2020-02-24 -0.03408808
2020-02-25 -0.03074790
2020-02-27 -0.04516814
2020-03-03 -0.02851048
2020-03-05 -0.03451078
2020-03-09 -0.07901041
2020-03-11 -0.05010289
2020-03-12 -0.09994485
2020-03-16 -0.12765220
2020-03-18 -0.05322227
2020-03-20 -0.04432762
2020-03-23 -0.02973150
2020-03-27 -0.03426785
2020-04-01 -0.04514636
2020-04-21 -0.03115512
2020-05-01 -0.02846021
2020-06-11 -0.06075269
2020-09-03 -0.03575759
2020-09-08 -0.02814883
2020-10-28 -0.03592554
2022-03-07 -0.02996259
2022-04-22 -0.02813208
2022-04-26 -0.02855001
ES=mean(extremes$return) * 100
ES
[1] -4.412946
The Expected Shortfall at the 2.994012% probability is the average of
these extreme return, which is -4.4129462%. As expected, the 2.994012%
ES is more negative than the 2.994012%VaR (-4.4129462% vs
-2.7733123%).
There are more than one method to estimate VaR and ES. Read the my
Note “Introduction to Value at Risk” to learn different methods to
estimate VaR and Expected Shortfall.
The most popular methods are 1) Percentile method using real
distribution, 2) assuming normal distribution of returns, and 3)
assuming a fat-tailed distribution of returns using the t-Student
probability distribution.
Another not popular method (but more accurate) is using a volatility
model like an GARCH(1,1) model to estimate and forecast daily
volatility, and use this volatility to estimate Value at Risk.
Kurtosis and fat-tail distribution
Skewness and Kurtosis are statistical measures of a random variable.
Here is a quick summary of Skewness and Kurtosis:
Skewness is a measure for asymmetry of the distribution. A normal
distribution has about the same values that are less than then mean
compared with the values that are higher than the mean. A normal
distribution has a skewness close to zero. A negative skewness means
that the tail to the left has more values (skewed to the left). A
positive skewness means that the tail to the right has more values
(skewed to the right).
Kurtosis can be used to examine know whether a variable has a
distribution with much more extreme values compared to the normal
distribution. According to the value of Kurtosis, we can identify
whether we have a significant number of extreme values in a
variable:
If Kurtosis=3 then, the variable behaves close to normal
distribution
If Kurtosis>3, then this means that there are extreme values in
the variable that makes the distribution to be a fat-tailed
distribution.
Here is a quick review of moments in statistics, which are the base
to understand Variance, Skewness and Kurtosis:
Moments in Statistics:
A Moment in Statistis is a specific measure about a probability
distribution of a random variable.
The expected value of a random variable X can be calculated as the
mean of X using historical values:
Mean(X)=X⎯⎯⎯⎯=E[X]=1N∑(Xi)=X1+X2+…XNN
The 4 Moments in Statistics are:
1st moment: E[X−X⎯⎯⎯⎯]=0
2nd moment: E[X−X⎯⎯⎯⎯]2=1N∑(Xi−X⎯⎯⎯⎯)2=VAR(X) = Variance(X);
The Standard Deviation of X is the square root of the Variance(X):
SD(X)=VAR(X)‾‾‾‾‾‾‾‾√
3rd moment: E[X−X⎯⎯⎯⎯]3=1N∑(Xi−X⎯⎯⎯⎯)3 The 3rd moment is used to
estimate Skewness(X) as:
Skewness(X)=E[X−X⎯⎯⎯⎯]3SD(X)3
4rd moment: E[X−X⎯⎯⎯⎯]4=1N∑(Xi−X⎯⎯⎯⎯)4 The 4rd moment is used to
estimate Kurtosis(X) as:
Kurtosis(X)=E[X−X⎯⎯⎯⎯]4SD(X)4
Calculate Kurtosis of S&P500 daily returns. Do you see a sign of
fat-tail distribution of returns
The moments library has functions for Kurtosis and Skewness. Install
this library
library(moments)
kurtosis = as.numeric(kurtosis(SPreturn))
kurtosis
[1] 20.0883
Since kurtosis is much higher than 3, this is a sign of fat-tailed
distribution.
Estimating VaR assuming fat-tail distribution
Considering that the distribution of real returns is more a fat-tail
distribution (more-than-normal extreme values), it is better to use the
t distribution rather than the normal distribution. Research indicates
that there is a relationship between the kurtosis and the degrees of
freedom of the t distribution to model fat-tail distributions. A
t-distribution with low degrees of freedom shows fatter tails compared
with a t distribution with higher degrees of freedom (or compared to a
normal distribution). The way to estimate the degrees of freedom of a t
distribution to model a fat-tail distribution, we use the kurtosis of
the distribution as follows: Degrees of freedom (df)= 6/Kurtosis + 4 You
have to estimate the degrees of freedom and then use the t distribution
to estimate the 1% VaR of $1million for the next future day of the
sample. Compare both estimations of VaR, the one calculated assuming
normal distribution and this one. Briefly reports this comparison. Hint:
the function qt(0.01,df) gives you the t value, which represents the #
of standard deviations you need to go from the mean to the left to
arrive to the 1% percentile. I calculate the degrees of freedom I use to
simulate a fat-tailed distribution using the t-Student distribution:
# I calculate the degrees of freedom for the t distribution:
df = 6/kurtosis + 4
df
[1] 4.298681
# I calculate the t critical value according to the probability of 1% and the df:
t1 = qt(0.01,df)
t1
[1] -3.607109
Now I get the 1%VaR assuming fat-tail distribution:
meansp = mean(SPreturn)
volatilitysp = sd(SPreturn)
VaR2 = meansp + t1 * volatilitysp
VaR2
[1] -0.05050791
Interpretation of this 1%VaR:
Assuming fat-tail distribution of daily returns of the S&P500, I
can lose in one day -5.0507905% or more with a probability of 1%.
Compared to the first 1%VaR=-277.331227% (assuming normal
distribution), this 1%VaR=-5.0507905% assuming fat-tail distribution is
more conservative, and more realistic.
To calculate the Expected Shortfall assuming fat-tail distribution,
we can calculate the average return of the bad days that have had
returns less than the 1%VaR assuming fat-tail distribution:
baddays2 <- SPreturn[SPreturn$return<=VaR2,]
baddays2
return
2020-03-09 -0.07901041
2020-03-12 -0.09994485
2020-03-16 -0.12765220
2020-03-18 -0.05322227
2020-06-11 -0.06075269
Now we can get the average of these very bad days:
ES3 = mean(baddays2$return)
ES3
[1] -0.08411649
This would be the more conservative estimation of 1% Expected
Shortfall of the S&P500. Then, assuming fat-tail distribution of
daily returns of the S&P500, and using real historical daily
returns, ON AVERAGE, I can lose in one day -8.4116486% with a
probability of 1%.
Forecasting VaR with GARCH(1,1) Model
Work with the same dataset (daily S&P500 returns).
1.- Run a GARCH(1,1) model. INTERPRET the model and briefly explain
your results.
library(rugarch)
Especgarch1=ugarchspec(variance.model= list(model= "sGARCH", garchOrder= c(1, 1),
submodel= NULL, variance.targeting= FALSE),
mean.model= list(armaOrder= c(0, 0), include.mean= TRUE, archm= FALSE,
archpow= 0, arfima= FALSE, external.regressors= NULL, archex= FALSE),
distribution.model= "norm", start.pars= list(), fixed.pars= list())
#Estimación del GARCH(1,1)
garch1<- ugarchfit(spec=Especgarch1, data=SPreturn$return)
garch1
*---------------------------------*
* GARCH Model Fit *
*---------------------------------*
Conditional Variance Dynamics
-----------------------------------
GARCH Model : sGARCH(1,1)
Mean Model : ARFIMA(0,0,0)
Distribution : norm
Optimal Parameters
------------------------------------
Estimate Std. Error t value Pr(>|t|)
mu 0.001047 0.000270 3.8804 0.000104
omega 0.000006 0.000003 2.3265 0.019993
alpha1 0.253622 0.036941 6.8656 0.000000
beta1 0.721067 0.011207 64.3398 0.000000
Robust Standard Errors:
Estimate Std. Error t value Pr(>|t|)
mu 0.001047 0.000260 4.02889 0.000056
omega 0.000006 0.000007 0.84433 0.398487
alpha1 0.253622 0.051157 4.95770 0.000001
beta1 0.721067 0.094270 7.64894 0.000000
LogLikelihood : 2677.884
Information Criteria
------------------------------------
Akaike -6.4045
Bayes -6.3819
Shibata -6.4046
Hannan-Quinn -6.3958
Weighted Ljung-Box Test on Standardized Residuals
------------------------------------
statistic p-value
Lag[1] 0.7817 0.3766
Lag[2*(p+q)+(p+q)-1][2] 0.9404 0.5180
Lag[4*(p+q)+(p+q)-1][5] 1.3737 0.7709
d.o.f=0
H0 : No serial correlation
Weighted Ljung-Box Test on Standardized Squared Residuals
------------------------------------
statistic p-value
Lag[1] 0.4232 0.5153
Lag[2*(p+q)+(p+q)-1][5] 1.1354 0.8283
Lag[4*(p+q)+(p+q)-1][9] 1.7665 0.9310
d.o.f=2
Weighted ARCH LM Tests
------------------------------------
Statistic Shape Scale P-Value
ARCH Lag[3] 0.01123 0.500 2.000 0.9156
ARCH Lag[5] 0.92434 1.440 1.667 0.7555
ARCH Lag[7] 1.06257 2.315 1.543 0.9032
Nyblom stability test
------------------------------------
Joint Statistic: 2.5098
Individual Statistics:
mu 0.2157
omega 0.2498
alpha1 0.1074
beta1 0.2079
Asymptotic Critical Values (10% 5% 1%)
Joint Statistic: 1.07 1.24 1.6
Individual Statistic: 0.35 0.47 0.75
Sign Bias Test
------------------------------------
Adjusted Pearson Goodness-of-Fit Test:
------------------------------------
group statistic p-value(g-1)
1 20 43.06 0.0012721
2 30 60.44 0.0005448
3 40 80.40 0.0001071
4 50 77.28 0.0061301
Elapsed time : 0.07194638
*INTERPRETATION the model output**
What does each coefficient mean?
THE beta1 COEFFICIENT IS 0.7210678, AND IT IS SIGNIFICANTLY DIFFERENT
THAN ZERO. THIS MEANS THAT ABOUT 72.1067762% OF THE RETURN VARIANCE OF
YESTERDAY IS PASSED TO THE RETURN VARIANCE OF TODAY, BESIDES THE IMPACT
OF THE YESTERDAY’S SQUARED ERROR. SINCE THIS COEFFICIENT IS GREATER THAN
0.7, THIS IS A SIGN OF CLUSTERING OF VOLATILITY.
CONSIDERING THE VARIANCE OF YESTERDAY, THE SQUARED ERROR OF YESTERDAY
IMPACTS THE RETURN VARIANCE OF TODAY IN A POSITIVE AND SIGNIFICANT WAY,
BUT ONLY ABOUT 25.3621103% OF THE SQUARED ERROR OF YESTERDAY IS PASSED
TO THE VARIANCE OF TODAY.
2.- With this GARCH(1,1) model, forecast both volatility and 1% VaR
of $1 million for 1 future day (tomorrow).
garch1.prediction <- ugarchforecast(garch1,n.ahead= 1)
garch1.prediction will be a very special R class: an uGARCHforecast
class. This is special R class object that stores information about the
GARCH prediction.
For this type of R class objects, we use the @ character to get
access to the content of each element stored in this object.
The forecast for the daily return is stored in
garch1.prediction@forecast$seriesFor
2022-04-26
T+1 0.001047319
The forecast for the standard deviation of returns (volatility) is
stored in:
garch1.prediction@forecast$sigmaFor
2022-04-26
T+1 0.02016522
Now using this predicted volatility, I calculate a new 1%VaR for
tomorrow. I will assume fat-tail distribution, so I will use the
t-Student distribution with the degrees of freedom I calculated
above:
VaR1_G = meansp + t1 * garch1.prediction@forecast$sigmaFor[1]
VaR1_G
[1] -0.07212872
*The 1%VaR using the predicted volatility from the GARCH(1,1) model
is -7.2128673%.
Extend the dataset 10 days in the future. Do a within-sample forecast
and an out-of-sample forecast for all days of the year (before and after
TODAY) for daily volatility and 1%VaR for 1 day.
we do a forecast for 10 days
garch1.prediction <- ugarchforecast(garch1,n.ahead= 10)
We can plot the historic and future volatility:
plot(garch1.prediction,which = 3)

Now I calculate the daily 1%VaR for these 10 future days:
VaR1_G = meansp + t1 * garch1.prediction@forecast$sigmaFor
VaR1_G
2022-04-26
T+1 -0.07212872
T+2 -0.07174397
T+3 -0.07136698
T+4 -0.07099762
T+5 -0.07063577
T+6 -0.07028130
T+7 -0.06993409
T+8 -0.06959401
T+9 -0.06926094
T+10 -0.06893478
# Now I calculate 1%VaR for a $1 million per day:
VaR1_G_1mill = VaR1_G * 1000000
VaR1_G_1mill
2022-04-26
T+1 -72128.72
T+2 -71743.97
T+3 -71366.98
T+4 -70997.62
T+5 -70635.77
T+6 -70281.30
T+7 -69934.09
T+8 -69594.01
T+9 -69260.94
T+10 -68934.78
4.- Do a plot of volatility and VaR for the whole year *The
GARCH(1,1) fit estimation for volatility (sigma) and for stock return in
the history is stored in the garch1 R object at:
garch1@fit$sigma
We can look at the last values of the volatility fitted values:
tail(garch1@fit$sigma)
[1] 0.01017608 0.01169814 0.01026554 0.01209087 0.01809301 0.01573200
We can use these fit sigma values and attach them in the SPreturn xts
dataset along with the daily returns:
SPreturn$gvol = garch1@fit$sigma
Now we add a column for the 1%VaR using these historical GARCH
volatilities. I will use the t-Student distribution assuming fat-tails (
I will use the t1 I estimated above):
SPreturn$gVaR = meansp + t1 * SPreturn$gvol
SPreturn$gVaR1mill = SPreturn$gVaR * 1000000
Now I plot daily historical returns, and historial GARCH(1,1) fitted
values for daily volatilities and 1%Value at Risk:
plot(SPreturn$gVaR1mill)

plot(SPreturn[,c(2,3)])

The green line is the GARCH(1,1) 1% Value at Risk; the red line is
the GARCH(1,1) fitted volatility, and the black line is the daily return
series.
I recommend you to read the article GARCH 101: The use of [http://www.cmat.edu.uy/~mordecki/hk/engle.pdf||ARCH/GARCH
Models in Applied Econometrics] written by Robert Engle to better
understand how you can apply ARCH model to forecast volatility and
VaR
LS0tCnRpdGxlOiAiV29ya3Nob3AgOSwgRmluYW5jaWFsIEVjb25vbWV0cmljcyBJSSIKYXV0aG9yOiBTdGVmYW4gU2Nod2VpdHplcgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiMjIFdvcmtzaG9wIDksIEZpbmFuY2lhbCBFY29ub21ldHJpY3MgSUkKIyBBbGJlcnRvIERvcmFudGVzLCBQaC5ELiBBcHIgMjcsIDIwMjIKICAKIyBDb25zaWRlcmF0aW9uCkVzdGltYWRvcyBlc3R1ZGlhbnRlczoKRW4gZXN0b3MgZMOtYXMgZ2V0U3ltYm9scyBkZSBsYSBsaWJyZXLDrWEgcXVhbnRtb2QgTk8gZXN0w6EgZnVuY2lvbmFuZG8gKG1hcmNhIHVuIGVycm9yIGFsIGJhamFyIGRhdG9zKS4KUGFyYSBhcnJlZ2xhciBlbCBlcnJvciwgdGllbmVuIHF1ZSByZS1pbnN0YWxhciBsYSBsaWJyZXLDrWEgcXVhbnRtb2QuIFB1ZWRlbiBoYWNlcmxvIGRlc2RlIFBhY2thZ2VzIGVuIGxhIHZlbnRhbmEgaW5mZXJpb3IgZGVyZWNoYSBkZSBSU3R1ZGlvLCDDsyB0YW1iacOpbiBlc2NyaWJpciBlbiBsYSBjb25zb2xhOgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikKYGBgCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpgYGAKCiMgQWJzdHJhY3QKSW4gdGhpcyB3b3Jrc2hvcCB3ZSB3aWxsIGxlYXJuIGFib3V0IFZhbHVlIGF0IFJpc2sgKFZhUikgYW5kIEV4cGVjdGVkIFNob3J0ZmFsbCAoRVMpIGFuZCBob3cgdG8gYXBwbHkgaXQgdG8gYSByZWFsLXdvcmxkIG1hcmtldCBpbmRleC4gV2Ugd2lsbCBhbHNvIHVzZSBhIEdBUkNIKDEsMSkgbW9kZWwgdG8gZm9yZWNhc3Qgdm9sYXRpbGl0eSBhbmQgVmFSLgoKIyBJbnRyb2R1Y3Rpb24gdG8gVmFsdWUgYXQgUmlzayAoVmFSKQpWYWx1ZSBhdCBSaXNrIChWYVIpIGlzIGEgbWVhc3VyZSBvZiByaXNrIHRoYXQgZm9jdXNlcyBvbiBwb3RlbnRpYWwgbG9zc2VzIG9mIGFuIGludmVzdG1lbnQgaW4gYSBzaG9ydCBwZXJpb2Qgb2YgdGltZS4KSW52ZXN0bWVudCBmaXJtcyBhbmQgYmFua3MgY29uc3RhbnRseSBtb25pdG9yIFZhUiBvZiB0aGVpciBwb3J0Zm9saW9zIGluIG9yZGVyIHRvIGJlIHByZXBhcmVkIGluIGNhc2UgYSBiYWQgc2NlbmFyaW8uIFZhUiBpcyB1c3VhbGx5IGVzdGltYXRlZCBkYWlseSB1c2luZyBhIHNtYWxsIHByb2JhYmlsaXR5IHN1Y2ggYXMgNSUsIDElLCBvciAwLjElLgpWZXJ5IGJhZCBzY2VuYXJpb3MgaW4gdGhlIHNob3J0IHRlcm0gaGF2ZSBhIGNlcnRhaW4gcHJvYmFiaWxpdHkgcCB0byBoYXBwZW4gaW4gb25lIGRheS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBwcm9iYWJpbGl0eSBvZiBsb3NpbmcgMTAlIG9yIE1PUkUgb2YgYW4gaW52ZXN0bWVudCBpbiBvbmUgc2luZ2xlIGRheSBpcyA1JSwgdGhlbiB3ZSBzYXkgdGhhdCB0aGUgNSUgVmFsdWUgYXQgUmlzayAoNSVWYVIpIGlzIGVxdWFsIHRvIDEwJS4KV2UgY2FuIGFsc28gY2FsY3VsYXRlIFZhUiBpbiBtb25leSBpZiB3ZSBrbm93IHRoZSBpbml0aWFsIGludmVzdG1lbnQuIEZvciBleGFtcGxlLCB1c2luZyB0aGUgc2FtZSBleGFtcGxlLCBpZiBteSBpbml0aWFsIGludmVzdG1lbnQgaXMgJDHigJkwMDAsMDAwLCB0aGVuIHRoZSA1JVZhUiA9IDEwJSwgd2hpY2ggaXMgZXF1YWwgdG8gJDEwMCwwMDAuMDAuIFZhUiBjYW4gYmUgcmVwb3J0ZWQgYXMgYSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSBhbW91bnQ7IHRoaXMgaXMganVzdCBhIG1hdHRlciBvZiBwcmVmZXJlbmNlLiBCdXQgd2UgaGF2ZSB0byBiZSBhd2FyZSB0aGF0IFZhUiBpcyBhIG1lYXN1cmUgb2YgcG90ZW50aWFsIGxvc3MgaW4gJSBvciBpbiAkIHdpdGggYSBjZXJ0YWluIHByb2JhYmlsaXR5LgpwJVZhUiBpcyB0aGUgTUlOSU1VTSAlIGxvc3Mgb2YgYW4gaW52ZXN0bWVudCB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgcC4gSW4gb3RoZXIgd29yZHMsIHRoZXJlIGlzIGEgcHJvYmFiaWxpdHkgcCB0aGF0IEkgY2FuIGxvc2UgJVZhUiBvciBNT1JFLiBBbm90aGVyIHdheSB0byBkZWZpbmUgcCVWYVIgaXMgdGhlIGZvbGxvd2luZy4gcCVWYVIgaXMgdGhlIE1BWElNVU0gJWxvc3Mgb2YgYW4gaW52ZXN0bWVudCB3aXRoIGEgcHJvYmF0aWxpdHkgKDEtcCkuIEluIG90aGVyIHdvcmRzLCB0aGVyZSBpcyBhIHByb2JhYmlsaXR5ICgxLXApIHRoYXQgSSBjYW4gaGF2ZSBhIHJldHVybiBvZiAlVmFSIG9yIEhJR0hFUi4KVGhlbiwgd2UgY2FuIHNheSB0aGF0IHAlVmFSIGlzIHRoZSBiZXN0IHNjZW5hcmlvIHRoYXQgY2FuIGhhcHBlbiBhZnRlciBhIHZlcnkgYmFkIHNjZW5hcmlvIHRoYXQgY2FuIGhhcHBlbiB3aXRoIHByb2JhYmlsaXR5IHAuIEFsc28sIHdlIGNhbiBzYXkgdGhhdCBwJVZhUiBpcyB0aGUgd29yc2Ugc2NlbmFyaW8gdGhhdCBjYW4gaGFwcGVuIHdoZW4gdGhlIHNjZW5hcmlvIGlzIG5vdCB0aGUgYmFkIG9uZSwgc28gd2hlbiB0aGVyZSBpcyBhIHByb2JhYmlsaXR5IG9mICgxLXApJS4KTGV04oCZcyBpbGx1c3RyYXRlIFZhUiB1c2luZyByZWFsIGRhdGEgZnJvbSB0aGUgVVMgaW5kZXggUyZQNTAwIGRhaWx5IHJldHVybnMgZnJvbSBKYW51YXJ5IDIwMTkgdG8gQXByaWwgMjYsIDIwMjIuCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKZ2V0U3ltYm9scygiXkdTUEMiLCBmcm9tPSIyMDE5LTAxLTAxIiwKICAgICAgICAgICAgICAgICAgICB0bz0iMjAyMi0wNC0yNyIpCmBgYAoKYGBge3J9CiMgSSBnZXQgdGhlIGFkanVzdGVkIGNvbHVtbjoKU1BpbmRleCA9IEFkKEdTUEMpCiMgSSBjYWxjdWxhdGUgZGFpbHkgcmV0dXJucyBvZiB0aGUgaW5kZXg6ClNQcmV0dXJuPC0gbmEub21pdChkaWZmKGxvZyhTUGluZGV4KSkpCm5hbWVzKFNQcmV0dXJuKTwtYygicmV0dXJuIikKYGBgCgpXZSBwbG90IHRoZSBkYWlseSBpbmRleCBvdmVyIHRpbWU6CmBgYHtyfQpwbG90KFNQaW5kZXgpCmBgYApXZSBzZWUgc3Ryb25nIGRlY2xpbmUgaW4gTWFyY2ggMjAyMCwgYW5vdGhlciBpbXBvcnRhbnQgZGVjbGluZSBpbiBlYXJseSAyMDIyLgoKTm93IHdlIGRvIGEgaGlzdG9ncmFtIG9mIHRoZSByZXR1cm4gb2YgdGhpcyBpbmRleAoKYGBge3J9Cmhpc3QoU1ByZXR1cm4sIGJyZWFrcz00MCkKYGBgClRoZSBoZWlnaHQgb2YgZWFjaCBiYXIgcmVwcmVzZW50cyB0aGUgZnJlcXVlbmN5IGluIG51bWJlciBvZiBkYXlzIHRoYXQgYSBzcGVjaWZpYyBkYWlseSByZXR1cm4gcmFuZ2UgaGFzIGhhcHBlbmVkLgoKSWYgdGhlIGRhaWx5IHJldHVybnMgYmVoYXZlcyBsaWtlIGEgbm9ybWFsLWRpc3RyaWJ1dGVkIHZhcmlhYmxlLCB0aGVuIGFib3V0IDIuNSUgb2YgdGhlIGRheXMgdGhlIFMmUDUwMCByZXR1cm5zIHdvdWxkIGJlIGxlc3MgdGhhbiB0aGUgaXRzIG1lYW4gbWludXMgMiB0aW1lcyBpdHMgc3RhbmRhcmQgZGV2aWF0aW9uLiBSZW1lbWJlciB0aGF0IGZvciBhIG5vcm1hbC1kaXN0cmlidXRlZCB2YXJpYWJsZSwgaW4gdGhlIHJhbmdlIHBsdXMvbWludXMgMiBzdGFuZGFyZCBkZXZpYXRpb25zIGZyb20gaXRzIG1lYW4sIHdlIHdpbGwgZmluZCBhYm91dCA5NSUgb2YgdGhlIHZhbHVlcy4KCldlIGRvd25sb2FkZWQgODM1IGRheXMgb2YgcmV0dXJuLCBzbyB3ZSB3b3VsZCBleHBlY3QgdGhhdCBhYm91dCAyMC44NzUgd2lsbCBiZSB0aGUgIyBvZiBkYXlzIHRoYXQgdGhlIFNQJjUwMCB3b3VsZCBvZmZlciByZXR1cm5zIGxlc3MgdGhhbiAtMiB0aW1lcyBpdHMgc3RhbmRhcmQgZGV2aWF0aW9uIGZyb20gaXRzIG1lYW46CgpgYGB7cn0KIyBOdW1iZXIgb2YgZGF5cyBmb3IgdGhlIFMmUCByZXR1cm5zOgpOPW5yb3coU1ByZXR1cm4pCk4KYGBgCgpgYGB7cn0KIyBUaGUgMi41JSBvZiB0aGVzZSAjIG9mIGRheXMgaXMgYWJvdXQ6Cm4yNT0wLjAyNSpucm93KFNQcmV0dXJuKQpuMjUKYGBgCgpOb3cgd2UgY2FuIGxvb2sgdGhlIHJlYWwgZGF0YSBhbmQgc2VlIGhvdyBtYW55IGRheXMgdGhlIFMmUDUwMCBoYXMgb2ZmZXJlZCByZXR1cm5zIGxlc3MgdGhhbiAyIHRpbWVzIGl0cyBzdGFuZGFyZCBkZXZpYXRpb24gZnJvbSBpdHMgbWVhbi4gV2UgY2FuIGNhbGN1bGF0ZSB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uICh2b2xhdGlsaXR5KSBvZiBkYWlseSByZXR1cm5zLCBhbmQgdGhlbiBpZGVudGlmeSBob3cgbWFueSBkYXlzIHRoZSBTJlA1MDAgaGFzIG9mZmVyZWQgZXh0cmVtZSByZXR1cm5zIGxlc3MgdGhhbiB0aGUgbWVhbiBtaW51cyAyIHRpbWVzIGl0cyB2b2xhdGlsaXR5OgoKYGBge3J9CiMgV2UgY2FsY3VsYXRlIHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgcmV0dXJuczoKbWVhbl9yZXR1cm49bWVhbihTUHJldHVybiRyZXR1cm4pCm1lYW5fcmV0dXJuCmBgYAoKYGBge3J9CnZvbGF0aWxpdHkgPSBzZChTUHJldHVybiRyZXR1cm4pCnZvbGF0aWxpdHkKYGBgCgpgYGB7cn0KIyBXZSBjYWxjdWxhdGUgdGhlIGV4cGVjdGVkIG1pbmltdW0gcmV0dXJuIG9mIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCAoQy5JLikgCiMgICBhc3N1bWluZyBub3JtYWxpdHkgKHRoZSAyLjUgcGVyY2VudGlsZSkKbWluOTVjaV9yZXR1cm5zID0gbWVhbl9yZXR1cm4tMip2b2xhdGlsaXR5Cm1pbjk1Y2lfcmV0dXJucwpgYGAKCmBgYHtyfQojIFdlIHNlbGVjdCB0aGUgZGF5cyB3aXRoIHJldHVybnMgbGVzcyB0aGFuIHRoZSBtaW5pbXVtIG9mIHRoZSA5NSUgQy5JLgpleHRyZW1lczwtIFNQcmV0dXJuW1NQcmV0dXJuJHJldHVybjxtaW45NWNpX3JldHVybnMsXQpleHRyZW1lcwpgYGAKCmBgYHtyfQpuZXh0cmVtZXMgPSBucm93KGV4dHJlbWVzKQojIE51bWJlciBvZiBleHRyZW1lIHJldHVybnM6Cm5leHRyZW1lcwpgYGAKCmBgYHtyfQpwZXJjZXh0cmVtZXMgPSBuZXh0cmVtZXMgLyBOICogMTAwCnBlcmNleHRyZW1lcwpgYGAKCkluIHRoaXMgY2FzZSwgd2UgaGF2ZSAyNSBleHRyZW1lIGRheXMgd2l0aCByZXR1cm5zIGxlc3MgdGhhbiB0aGUgbWluaW11bSBvZiB0aGUgOTUlIEMuSS4gb2YgZGFpbHkgcmV0dXJucy4gVGhlbiwgaXQgc2VlbXMgdGhhdCB3ZSBoYXZlIGhhZCBtb3JlIGV4dHJlbWUgcmV0dXJucyB0aGFuIGV4cGVjdGVkLiBUaGlzIHJlcHJlc2VudHMgYWJvdXQgMi45OTQwMTIlIG9mIHRoZSB0b3RhbCAjIG9mIGRheXMsIHdoaWNoIGlzIGdyZWF0ZXIgdGhhbiB0aGUgZXhwZWN0ZWQgMi41JS4KClRoZW4sIDIuOTk0MDEyJSBvZiB0aGUgdGltZSwgdGhlIFMmUDUwMCBoYXMgZXhwZXJpZW5jZSBhIGxvc3Mgb2YgLTIuNzczMzEyMyUgb3IgTU9SRS4gSWYgd2UgYmVsaWV2ZSB0aGF0IGluIHRoZSBmdXR1cmUgdGhlIFMmUDUwMCB3aWxsIGJlaGF2ZSBpbiBhIHNpbWlsYXIgbWFubmVyLCB0aGVuIHdlIGNhbiBzYXkgdGhhdCB0aGVyZSBpcyBhIHByb2JhYmlsaXR5IG9mIDIuOTk0MDEyJSB0aGF0IEkgY2FuIGxvc2UgLTIuNzczMzEyMyUgb3IgTU9SRSBpbiBvbmx5IE9ORSBEQVkuCgpXZSBjYW4gYWxzbyBzYXkgdGhhdCB0aGVyZSBpcyBhIHByb2JhYmlsaXR5IG9mIDk3LjAwNTk4OCUgKDEwMCUgLSAyLjk5NDAxMiUpIHRoYXQgdGhlIE1BWElNVU0gbG9zcyBJIGNhbiBleHBlcmllbmNlIGluIE9ORSBEQVkgaXMgLTIuNzczMzEyMyUuIFRoZW4sIHRoZSAyLjk5NDAxMiVWYVIgb2YgdGhlIGRhaWx5IFMmUDUwMCByZXR1cm5zIGlzIC0yLjc3MzMxMjMlCgpgYGB7cn0KVmFSMSA9IG1pbjk1Y2lfcmV0dXJucyoxMDAKVmFSMQpgYGAKRm9yIHR1cmJ1bGVuY2UgcGVyaW9kcyBpbiBmaW5hbmNpYWwgbWFya2V0cyBpdCBpcyBsaWtlbHkgdGhhdCBhIGJhZCBzY2VuYXJpbyB3aXRoIHByb2JhYmlsaXR5IHAgY2FuIGhhcHBlbi4gT25jZSB0aGlzIHNjZW5hcmlvIGhhcHBlbnMsIHRoZW4gcCVWYVIgaXMgdGhlIGJlc3Qgc2NlbmFyaW8sIGJ1dCBpbiByZWFsaXR5IHRoaXMgdGhlIHAlVmFSIGlzIG5vdCB0b28gcmVhbGlzdGljLiBXZSBuZWVkIHRvIGJlIG1vcmUgY29uc2VydmF0aXZlIGFuZCBlc3RpbWF0ZSB3aGljaCBtaWdodCBiZSB0aGUgZXhwZWN0ZWQgbG9zcyBvbmNlIHRoZSBwcm9iYWJpbGl0eSBwIG9mIHRoZSBiYWQgc2NlbmFyaW8gaGFwcGVucy4gVGhpcyBjb25zZXJ2YXRpdmUgZXN0aW1hdGUgaXMgZ2l2ZW4gYnkgdGhlIEV4cGVjdGVkIFNob3J0ZmFsbC4gV2Ugd2lsbCByZXZpZXcgdGhlIGNvbmNlcHQgb2YgRVMgaW4gdGhlIGZvbGxvd2luZyBzZWN0aW9uLgoKIyBFeHBlY3RlZCBTaG9ydGZhbGwgKEVTKQoKRXhwZWN0ZWQgU2hvcnRmYWxsIHdpdGggYSBwcm9iYWJpbGl0eSBwIHJlZmVycyB0byB0aGUgZXhwZWN0ZWQgYXZlcmFnZSBsb3NzIG9mIGFuIGludmVzdG1lbnQgaW4gT05FIHBlcmlvZCAoaW4gdGhpcyBjYXNlLCBpbiBvbmUgZGF5KSBvbmNlIHRoZSBwcm9iYWJpbGl0eSBwIG9mIGEgYmFkIHNjZW5hcmlvIGhhcHBlbnMuIFRoZW4sIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiBwJUVTIHdpbGwgYWx3YXlzIGJlIGdyZWF0ZXIgKG1vcmUgbmVnYXRpdmUpIHRoYW4gdGhlIHAlVmFSLiBMZXTigJlzIGNhbGN1bGF0ZSB0aGUgRVMgdXNpbmcgdGhlIHByZXZpb3VzIGV4YW1wbGUgb2YgdGhlIFMmUDUwMCA1MDAgZGFpbHkgcmV0dXJucy4KClRvIGVzdGltYXRlIHRoZSBFUyBhdCB0aGUgMi45OTQwMTIlIHByb2JhYmlsaXR5LCB3ZSBqdXN0IGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBvZiB0aGUgZGF5cyB3aGVuIHRoZSBTJlA1MDAgcmV0dXJucyBoYXZlIGJlZW4gbGVzcyB0aGFuIC0yLjc3MzMxMjMlLldlIGNhbiBkbyB0aGlzIGFzIGZvbGxvd3MKCmBgYHtyfQpleHRyZW1lcwpgYGAKYGBge3J9CkVTPW1lYW4oZXh0cmVtZXMkcmV0dXJuKSAqIDEwMApFUwpgYGAKVGhlIEV4cGVjdGVkIFNob3J0ZmFsbCBhdCB0aGUgMi45OTQwMTIlIHByb2JhYmlsaXR5IGlzIHRoZSBhdmVyYWdlIG9mIHRoZXNlIGV4dHJlbWUgcmV0dXJuLCB3aGljaCBpcyAtNC40MTI5NDYyJS4gQXMgZXhwZWN0ZWQsIHRoZSAyLjk5NDAxMiUgRVMgaXMgbW9yZSBuZWdhdGl2ZSB0aGFuIHRoZSAyLjk5NDAxMiVWYVIgKC00LjQxMjk0NjIlIHZzIC0yLjc3MzMxMjMlKS4KClRoZXJlIGFyZSBtb3JlIHRoYW4gb25lIG1ldGhvZCB0byBlc3RpbWF0ZSBWYVIgYW5kIEVTLiBSZWFkIHRoZSBteSBOb3RlIOKAnEludHJvZHVjdGlvbiB0byBWYWx1ZSBhdCBSaXNr4oCdIHRvIGxlYXJuIGRpZmZlcmVudCBtZXRob2RzIHRvIGVzdGltYXRlIFZhUiBhbmQgRXhwZWN0ZWQgU2hvcnRmYWxsLgoKVGhlIG1vc3QgcG9wdWxhciBtZXRob2RzIGFyZSAxKSBQZXJjZW50aWxlIG1ldGhvZCB1c2luZyByZWFsIGRpc3RyaWJ1dGlvbiwgMikgYXNzdW1pbmcgbm9ybWFsIGRpc3RyaWJ1dGlvbiBvZiByZXR1cm5zLCBhbmQgMykgYXNzdW1pbmcgYSBmYXQtdGFpbGVkIGRpc3RyaWJ1dGlvbiBvZiByZXR1cm5zIHVzaW5nIHRoZSB0LVN0dWRlbnQgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLgoKQW5vdGhlciBub3QgcG9wdWxhciBtZXRob2QgKGJ1dCBtb3JlIGFjY3VyYXRlKSBpcyB1c2luZyBhIHZvbGF0aWxpdHkgbW9kZWwgbGlrZSBhbiBHQVJDSCgxLDEpIG1vZGVsIHRvIGVzdGltYXRlIGFuZCBmb3JlY2FzdCBkYWlseSB2b2xhdGlsaXR5LCBhbmQgdXNlIHRoaXMgdm9sYXRpbGl0eSB0byBlc3RpbWF0ZSBWYWx1ZSBhdCBSaXNrLgoKIyBLdXJ0b3NpcyBhbmQgZmF0LXRhaWwgZGlzdHJpYnV0aW9uCgpTa2V3bmVzcyBhbmQgS3VydG9zaXMgYXJlIHN0YXRpc3RpY2FsIG1lYXN1cmVzIG9mIGEgcmFuZG9tIHZhcmlhYmxlLiBIZXJlIGlzIGEgcXVpY2sgc3VtbWFyeSBvZiBTa2V3bmVzcyBhbmQgS3VydG9zaXM6CgpTa2V3bmVzcyBpcyBhIG1lYXN1cmUgZm9yIGFzeW1tZXRyeSBvZiB0aGUgZGlzdHJpYnV0aW9uLiBBIG5vcm1hbCBkaXN0cmlidXRpb24gaGFzIGFib3V0IHRoZSBzYW1lIHZhbHVlcyB0aGF0IGFyZSBsZXNzIHRoYW4gdGhlbiBtZWFuIGNvbXBhcmVkIHdpdGggdGhlIHZhbHVlcyB0aGF0IGFyZSBoaWdoZXIgdGhhbiB0aGUgbWVhbi4gQSBub3JtYWwgZGlzdHJpYnV0aW9uIGhhcyBhIHNrZXduZXNzIGNsb3NlIHRvIHplcm8uIEEgbmVnYXRpdmUgc2tld25lc3MgbWVhbnMgdGhhdCB0aGUgdGFpbCB0byB0aGUgbGVmdCBoYXMgbW9yZSB2YWx1ZXMgKHNrZXdlZCB0byB0aGUgbGVmdCkuIEEgcG9zaXRpdmUgc2tld25lc3MgbWVhbnMgdGhhdCB0aGUgdGFpbCB0byB0aGUgcmlnaHQgaGFzIG1vcmUgdmFsdWVzIChza2V3ZWQgdG8gdGhlIHJpZ2h0KS4KCkt1cnRvc2lzIGNhbiBiZSB1c2VkIHRvIGV4YW1pbmUga25vdyB3aGV0aGVyIGEgdmFyaWFibGUgaGFzIGEgZGlzdHJpYnV0aW9uIHdpdGggbXVjaCBtb3JlIGV4dHJlbWUgdmFsdWVzIGNvbXBhcmVkIHRvIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLiBBY2NvcmRpbmcgdG8gdGhlIHZhbHVlIG9mIEt1cnRvc2lzLCB3ZSBjYW4gaWRlbnRpZnkgd2hldGhlciB3ZSBoYXZlIGEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIGV4dHJlbWUgdmFsdWVzIGluIGEgdmFyaWFibGU6CgpJZiBLdXJ0b3Npcz0zIHRoZW4sIHRoZSB2YXJpYWJsZSBiZWhhdmVzIGNsb3NlIHRvIG5vcm1hbCBkaXN0cmlidXRpb24KCklmIEt1cnRvc2lzPjMsIHRoZW4gdGhpcyBtZWFucyB0aGF0IHRoZXJlIGFyZSBleHRyZW1lIHZhbHVlcyBpbiB0aGUgdmFyaWFibGUgdGhhdCBtYWtlcyB0aGUgZGlzdHJpYnV0aW9uIHRvIGJlIGEgZmF0LXRhaWxlZCBkaXN0cmlidXRpb24uCgpIZXJlIGlzIGEgcXVpY2sgcmV2aWV3IG9mIG1vbWVudHMgaW4gc3RhdGlzdGljcywgd2hpY2ggYXJlIHRoZSBiYXNlIHRvIHVuZGVyc3RhbmQgVmFyaWFuY2UsIFNrZXduZXNzIGFuZCBLdXJ0b3NpczoKCk1vbWVudHMgaW4gU3RhdGlzdGljczoKCkEgTW9tZW50IGluIFN0YXRpc3RpcyBpcyBhIHNwZWNpZmljIG1lYXN1cmUgYWJvdXQgYSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gb2YgYSByYW5kb20gdmFyaWFibGUuCgpUaGUgZXhwZWN0ZWQgdmFsdWUgb2YgYSByYW5kb20gdmFyaWFibGUgWCBjYW4gYmUgY2FsY3VsYXRlZCBhcyB0aGUgbWVhbiBvZiBYIHVzaW5nIGhpc3RvcmljYWwgdmFsdWVzOgoKTWVhbihYKT1Y4o6v4o6v4o6v4o6vPUVbWF09MU7iiJEoWGkpPVgxK1gyKy4uLlhOTgoKVGhlIDQgTW9tZW50cyBpbiBTdGF0aXN0aWNzIGFyZToKCjFzdCBtb21lbnQ6IEVbWOKIkljijq/ijq/ijq/ijq9dPTAKCjJuZCBtb21lbnQ6IEVbWOKIkljijq/ijq/ijq/ijq9dMj0xTuKIkShYaeKIkljijq/ijq/ijq/ijq8pMj1WQVIoWCkKID0gVmFyaWFuY2UoWCk7CgpUaGUgU3RhbmRhcmQgRGV2aWF0aW9uIG9mIFggaXMgdGhlIHNxdWFyZSByb290IG9mIHRoZSBWYXJpYW5jZShYKToKU0QoWCk9VkFSKFgp4oC+4oC+4oC+4oC+4oC+4oC+4oC+4oC+4oiaCgozcmQgbW9tZW50OiBFW1jiiJJY4o6v4o6v4o6v4o6vXTM9MU7iiJEoWGniiJJY4o6v4o6v4o6v4o6vKTMKVGhlIDNyZCBtb21lbnQgaXMgdXNlZCB0byBlc3RpbWF0ZSBTa2V3bmVzcyhYKSBhczoKClNrZXduZXNzKFgpPUVbWOKIkljijq/ijq/ijq/ijq9dM1NEKFgpMwoKNHJkIG1vbWVudDogRVtY4oiSWOKOr+KOr+KOr+KOr100PTFO4oiRKFhp4oiSWOKOr+KOr+KOr+KOryk0ClRoZSA0cmQgbW9tZW50IGlzIHVzZWQgdG8gZXN0aW1hdGUgS3VydG9zaXMoWCkgYXM6CgpLdXJ0b3NpcyhYKT1FW1jiiJJY4o6v4o6v4o6v4o6vXTRTRChYKTQKCkNhbGN1bGF0ZSBLdXJ0b3NpcyBvZiBTJlA1MDAgZGFpbHkgcmV0dXJucy4gRG8geW91IHNlZSBhIHNpZ24gb2YgZmF0LXRhaWwgZGlzdHJpYnV0aW9uIG9mIHJldHVybnMKClRoZSBtb21lbnRzIGxpYnJhcnkgaGFzIGZ1bmN0aW9ucyBmb3IgS3VydG9zaXMgYW5kIFNrZXduZXNzLiBJbnN0YWxsIHRoaXMgbGlicmFyeQoKYGBge3J9CmxpYnJhcnkobW9tZW50cykKa3VydG9zaXMgPSBhcy5udW1lcmljKGt1cnRvc2lzKFNQcmV0dXJuKSkKa3VydG9zaXMKYGBgCgpTaW5jZSBrdXJ0b3NpcyBpcyBtdWNoIGhpZ2hlciB0aGFuIDMsIHRoaXMgaXMgYSBzaWduIG9mIGZhdC10YWlsZWQgZGlzdHJpYnV0aW9uLgoKIyBFc3RpbWF0aW5nIFZhUiBhc3N1bWluZyBmYXQtdGFpbCBkaXN0cmlidXRpb24KQ29uc2lkZXJpbmcgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHJlYWwgcmV0dXJucyBpcyBtb3JlIGEgZmF0LXRhaWwgZGlzdHJpYnV0aW9uIChtb3JlLXRoYW4tbm9ybWFsIGV4dHJlbWUgdmFsdWVzKSwgaXQgaXMgYmV0dGVyIHRvIHVzZSB0aGUgdCBkaXN0cmlidXRpb24gcmF0aGVyIHRoYW4gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24uIFJlc2VhcmNoIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGt1cnRvc2lzIGFuZCB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIG9mIHRoZSB0IGRpc3RyaWJ1dGlvbiB0byBtb2RlbCBmYXQtdGFpbCBkaXN0cmlidXRpb25zLgpBIHQtZGlzdHJpYnV0aW9uIHdpdGggbG93IGRlZ3JlZXMgb2YgZnJlZWRvbSBzaG93cyBmYXR0ZXIgdGFpbHMgY29tcGFyZWQgd2l0aCBhIHQgZGlzdHJpYnV0aW9uIHdpdGggaGlnaGVyIGRlZ3JlZXMgb2YgZnJlZWRvbSAob3IgY29tcGFyZWQgdG8gYSBub3JtYWwgZGlzdHJpYnV0aW9uKS4KVGhlIHdheSB0byBlc3RpbWF0ZSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIG9mIGEgdCBkaXN0cmlidXRpb24gdG8gbW9kZWwgYSBmYXQtdGFpbCBkaXN0cmlidXRpb24sIHdlIHVzZSB0aGUga3VydG9zaXMgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhcyBmb2xsb3dzOgpEZWdyZWVzIG9mIGZyZWVkb20gKGRmKT0gNi9LdXJ0b3NpcyArIDQKWW91IGhhdmUgdG8gZXN0aW1hdGUgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbmQgdGhlbiB1c2UgdGhlIHQgZGlzdHJpYnV0aW9uIHRvIGVzdGltYXRlIHRoZSAxJSBWYVIgb2YgJDFtaWxsaW9uIGZvciB0aGUgbmV4dCBmdXR1cmUgZGF5IG9mIHRoZSBzYW1wbGUuIENvbXBhcmUgYm90aCBlc3RpbWF0aW9ucyBvZiBWYVIsIHRoZSBvbmUgY2FsY3VsYXRlZCBhc3N1bWluZyBub3JtYWwgZGlzdHJpYnV0aW9uIGFuZCB0aGlzIG9uZS4gQnJpZWZseSByZXBvcnRzIHRoaXMgY29tcGFyaXNvbi4KSGludDogdGhlIGZ1bmN0aW9uIHF0KDAuMDEsZGYpIGdpdmVzIHlvdSB0aGUgdCB2YWx1ZSwgd2hpY2ggcmVwcmVzZW50cyB0aGUgIyBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIHlvdSBuZWVkIHRvIGdvIGZyb20gdGhlIG1lYW4gdG8gdGhlIGxlZnQgdG8gYXJyaXZlIHRvIHRoZSAxJSBwZXJjZW50aWxlLgpJIGNhbGN1bGF0ZSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIEkgdXNlIHRvIHNpbXVsYXRlIGEgZmF0LXRhaWxlZCBkaXN0cmlidXRpb24gdXNpbmcgdGhlIHQtU3R1ZGVudCBkaXN0cmlidXRpb246CgpgYGB7cn0KIyBJIGNhbGN1bGF0ZSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIGZvciB0aGUgdCBkaXN0cmlidXRpb246CmRmID0gNi9rdXJ0b3NpcyArIDQKZGYKYGBgCgpgYGB7cn0KIyBJIGNhbGN1bGF0ZSB0aGUgdCBjcml0aWNhbCB2YWx1ZSBhY2NvcmRpbmcgdG8gdGhlIHByb2JhYmlsaXR5IG9mIDElIGFuZCB0aGUgZGY6CnQxID0gcXQoMC4wMSxkZikKdDEKYGBgCgpOb3cgSSBnZXQgdGhlIDElVmFSIGFzc3VtaW5nIGZhdC10YWlsIGRpc3RyaWJ1dGlvbjoKCmBgYHtyfQptZWFuc3AgPSBtZWFuKFNQcmV0dXJuKQp2b2xhdGlsaXR5c3AgPSBzZChTUHJldHVybikKVmFSMiA9IG1lYW5zcCArIHQxICogdm9sYXRpbGl0eXNwClZhUjIKYGBgCkludGVycHJldGF0aW9uIG9mIHRoaXMgMSVWYVI6CgpBc3N1bWluZyBmYXQtdGFpbCBkaXN0cmlidXRpb24gb2YgZGFpbHkgcmV0dXJucyBvZiB0aGUgUyZQNTAwLCBJIGNhbiBsb3NlIGluIG9uZSBkYXkgLTUuMDUwNzkwNSUgb3IgbW9yZSB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgMSUuCgpDb21wYXJlZCB0byB0aGUgZmlyc3QgMSVWYVI9LTI3Ny4zMzEyMjclIChhc3N1bWluZyBub3JtYWwgZGlzdHJpYnV0aW9uKSwgdGhpcyAxJVZhUj0tNS4wNTA3OTA1JSBhc3N1bWluZyBmYXQtdGFpbCBkaXN0cmlidXRpb24gaXMgbW9yZSBjb25zZXJ2YXRpdmUsIGFuZCBtb3JlIHJlYWxpc3RpYy4KClRvIGNhbGN1bGF0ZSB0aGUgRXhwZWN0ZWQgU2hvcnRmYWxsIGFzc3VtaW5nIGZhdC10YWlsIGRpc3RyaWJ1dGlvbiwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSByZXR1cm4gb2YgdGhlIGJhZCBkYXlzIHRoYXQgaGF2ZSBoYWQgcmV0dXJucyBsZXNzIHRoYW4gdGhlIDElVmFSIGFzc3VtaW5nIGZhdC10YWlsIGRpc3RyaWJ1dGlvbjoKCmBgYHtyfQpiYWRkYXlzMiA8LSBTUHJldHVybltTUHJldHVybiRyZXR1cm48PVZhUjIsXQpiYWRkYXlzMgpgYGAKCk5vdyB3ZSBjYW4gZ2V0IHRoZSBhdmVyYWdlIG9mIHRoZXNlIHZlcnkgYmFkIGRheXM6CgpgYGB7cn0KRVMzID0gbWVhbihiYWRkYXlzMiRyZXR1cm4pCkVTMwpgYGAKClRoaXMgd291bGQgYmUgdGhlIG1vcmUgY29uc2VydmF0aXZlIGVzdGltYXRpb24gb2YgMSUgRXhwZWN0ZWQgU2hvcnRmYWxsIG9mIHRoZSBTJlA1MDAuIFRoZW4sIGFzc3VtaW5nIGZhdC10YWlsIGRpc3RyaWJ1dGlvbiBvZiBkYWlseSByZXR1cm5zIG9mIHRoZSBTJlA1MDAsIGFuZCB1c2luZyByZWFsIGhpc3RvcmljYWwgZGFpbHkgcmV0dXJucywgT04gQVZFUkFHRSwgSSBjYW4gbG9zZSBpbiBvbmUgZGF5IC04LjQxMTY0ODYlIHdpdGggYSBwcm9iYWJpbGl0eSBvZiAxJS4KCiMgRm9yZWNhc3RpbmcgVmFSIHdpdGggR0FSQ0goMSwxKSBNb2RlbAoKV29yayB3aXRoIHRoZSBzYW1lIGRhdGFzZXQgKGRhaWx5IFMmUDUwMCByZXR1cm5zKS4KCjEuLSBSdW4gYSBHQVJDSCgxLDEpIG1vZGVsLiBJTlRFUlBSRVQgdGhlIG1vZGVsIGFuZCBicmllZmx5IGV4cGxhaW4geW91ciByZXN1bHRzLgoKYGBge3J9CmxpYnJhcnkocnVnYXJjaCkKRXNwZWNnYXJjaDE9dWdhcmNoc3BlYyh2YXJpYW5jZS5tb2RlbD0gbGlzdChtb2RlbD0gInNHQVJDSCIsIGdhcmNoT3JkZXI9IGMoMSwgMSksIApzdWJtb2RlbD0gTlVMTCwgIHZhcmlhbmNlLnRhcmdldGluZz0gRkFMU0UpLCAKbWVhbi5tb2RlbD0gbGlzdChhcm1hT3JkZXI9IGMoMCwgMCksIGluY2x1ZGUubWVhbj0gVFJVRSwgYXJjaG09IEZBTFNFLCAKYXJjaHBvdz0gMCwgYXJmaW1hPSBGQUxTRSwgIGV4dGVybmFsLnJlZ3Jlc3NvcnM9IE5VTEwsIGFyY2hleD0gRkFMU0UpLCAKZGlzdHJpYnV0aW9uLm1vZGVsPSAibm9ybSIsIHN0YXJ0LnBhcnM9IGxpc3QoKSwgZml4ZWQucGFycz0gbGlzdCgpKQoKI0VzdGltYWNpw7NuIGRlbCBHQVJDSCgxLDEpCgpnYXJjaDE8LSB1Z2FyY2hmaXQoc3BlYz1Fc3BlY2dhcmNoMSwgZGF0YT1TUHJldHVybiRyZXR1cm4pCmdhcmNoMQpgYGAKKklOVEVSUFJFVEFUSU9OIHRoZSBtb2RlbCBvdXRwdXQqKgoKV2hhdCBkb2VzIGVhY2ggY29lZmZpY2llbnQgbWVhbj8KClRIRSBiZXRhMSBDT0VGRklDSUVOVCBJUyAwLjcyMTA2NzgsIEFORCBJVCBJUyBTSUdOSUZJQ0FOVExZIERJRkZFUkVOVCBUSEFOIFpFUk8uIFRISVMgTUVBTlMgVEhBVCBBQk9VVCA3Mi4xMDY3NzYyJSBPRiBUSEUgUkVUVVJOIFZBUklBTkNFIE9GIFlFU1RFUkRBWSBJUyBQQVNTRUQgVE8gVEhFIFJFVFVSTiBWQVJJQU5DRSBPRiBUT0RBWSwgQkVTSURFUyBUSEUgSU1QQUNUIE9GIFRIRSBZRVNURVJEQVnigJlTIFNRVUFSRUQgRVJST1IuIFNJTkNFIFRISVMgQ09FRkZJQ0lFTlQgSVMgR1JFQVRFUiBUSEFOIDAuNywgVEhJUyBJUyBBIFNJR04gT0YgQ0xVU1RFUklORyBPRiBWT0xBVElMSVRZLgoKQ09OU0lERVJJTkcgVEhFIFZBUklBTkNFIE9GIFlFU1RFUkRBWSwgVEhFIFNRVUFSRUQgRVJST1IgT0YgWUVTVEVSREFZIElNUEFDVFMgVEhFIFJFVFVSTiBWQVJJQU5DRSBPRiBUT0RBWSBJTiBBIFBPU0lUSVZFIEFORCBTSUdOSUZJQ0FOVCBXQVksIEJVVCBPTkxZIEFCT1VUIDI1LjM2MjExMDMlIE9GIFRIRSBTUVVBUkVEIEVSUk9SIE9GIFlFU1RFUkRBWSBJUyBQQVNTRUQgVE8gVEhFIFZBUklBTkNFIE9GIFRPREFZLgoKMi4tIFdpdGggdGhpcyBHQVJDSCgxLDEpIG1vZGVsLCBmb3JlY2FzdCBib3RoIHZvbGF0aWxpdHkgYW5kIDElIFZhUiBvZiAkMSBtaWxsaW9uIGZvciAxIGZ1dHVyZSBkYXkgKHRvbW9ycm93KS4KCmBgYHtyfQpnYXJjaDEucHJlZGljdGlvbiA8LSB1Z2FyY2hmb3JlY2FzdChnYXJjaDEsbi5haGVhZD0gMSkKYGBgCmdhcmNoMS5wcmVkaWN0aW9uIHdpbGwgYmUgYSB2ZXJ5IHNwZWNpYWwgUiBjbGFzczogYW4gdUdBUkNIZm9yZWNhc3QgY2xhc3MuIFRoaXMgaXMgc3BlY2lhbCBSIGNsYXNzIG9iamVjdCB0aGF0IHN0b3JlcyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgR0FSQ0ggcHJlZGljdGlvbi4KCkZvciB0aGlzIHR5cGUgb2YgUiBjbGFzcyBvYmplY3RzLCB3ZSB1c2UgdGhlIEAgY2hhcmFjdGVyIHRvIGdldCBhY2Nlc3MgdG8gdGhlIGNvbnRlbnQgb2YgZWFjaCBlbGVtZW50IHN0b3JlZCBpbiB0aGlzIG9iamVjdC4KClRoZSBmb3JlY2FzdCBmb3IgdGhlIGRhaWx5IHJldHVybiBpcyBzdG9yZWQgaW4KYGBge3J9CmdhcmNoMS5wcmVkaWN0aW9uQGZvcmVjYXN0JHNlcmllc0ZvcgpgYGAKClRoZSBmb3JlY2FzdCBmb3IgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiByZXR1cm5zICh2b2xhdGlsaXR5KSBpcyBzdG9yZWQgaW46CgpgYGB7cn0KZ2FyY2gxLnByZWRpY3Rpb25AZm9yZWNhc3Qkc2lnbWFGb3IKYGBgCgpOb3cgdXNpbmcgdGhpcyBwcmVkaWN0ZWQgdm9sYXRpbGl0eSwgSSBjYWxjdWxhdGUgYSBuZXcgMSVWYVIgZm9yIHRvbW9ycm93LiBJIHdpbGwgYXNzdW1lIGZhdC10YWlsIGRpc3RyaWJ1dGlvbiwgc28gSSB3aWxsIHVzZSB0aGUgdC1TdHVkZW50IGRpc3RyaWJ1dGlvbiB3aXRoIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gSSBjYWxjdWxhdGVkIGFib3ZlOgoKYGBge3J9ClZhUjFfRyA9IG1lYW5zcCArIHQxICogZ2FyY2gxLnByZWRpY3Rpb25AZm9yZWNhc3Qkc2lnbWFGb3JbMV0KVmFSMV9HCmBgYAoKKlRoZSAxJVZhUiB1c2luZyB0aGUgcHJlZGljdGVkIHZvbGF0aWxpdHkgZnJvbSB0aGUgR0FSQ0goMSwxKSBtb2RlbCBpcyAtNy4yMTI4NjczJS4KCkV4dGVuZCB0aGUgZGF0YXNldCAxMCBkYXlzIGluIHRoZSBmdXR1cmUuIERvIGEgd2l0aGluLXNhbXBsZSBmb3JlY2FzdCBhbmQgYW4gb3V0LW9mLXNhbXBsZSBmb3JlY2FzdCBmb3IgYWxsIGRheXMgb2YgdGhlIHllYXIgKGJlZm9yZSBhbmQgYWZ0ZXIgVE9EQVkpIGZvciBkYWlseSB2b2xhdGlsaXR5IGFuZCAxJVZhUiBmb3IgMSBkYXkuCgp3ZSBkbyBhIGZvcmVjYXN0IGZvciAxMCBkYXlzCmBgYHtyfQpnYXJjaDEucHJlZGljdGlvbiA8LSB1Z2FyY2hmb3JlY2FzdChnYXJjaDEsbi5haGVhZD0gMTApCmBgYApXZSBjYW4gcGxvdCB0aGUgaGlzdG9yaWMgYW5kIGZ1dHVyZSB2b2xhdGlsaXR5OgpgYGB7cn0KcGxvdChnYXJjaDEucHJlZGljdGlvbix3aGljaCA9IDMpCmBgYApOb3cgSSBjYWxjdWxhdGUgdGhlIGRhaWx5IDElVmFSIGZvciB0aGVzZSAxMCBmdXR1cmUgZGF5czoKYGBge3J9ClZhUjFfRyA9IG1lYW5zcCArIHQxICogZ2FyY2gxLnByZWRpY3Rpb25AZm9yZWNhc3Qkc2lnbWFGb3IKVmFSMV9HCmBgYApgYGB7cn0KIyBOb3cgSSBjYWxjdWxhdGUgMSVWYVIgZm9yIGEgJDEgbWlsbGlvbiBwZXIgZGF5OgpWYVIxX0dfMW1pbGwgPSBWYVIxX0cgKiAxMDAwMDAwClZhUjFfR18xbWlsbApgYGAKCjQuLSBEbyBhIHBsb3Qgb2Ygdm9sYXRpbGl0eSBhbmQgVmFSIGZvciB0aGUgd2hvbGUgeWVhcgoqVGhlIEdBUkNIKDEsMSkgZml0IGVzdGltYXRpb24gZm9yIHZvbGF0aWxpdHkgKHNpZ21hKSBhbmQgZm9yIHN0b2NrIHJldHVybiBpbiB0aGUgaGlzdG9yeSBpcyBzdG9yZWQgaW4gdGhlIGdhcmNoMSBSIG9iamVjdCBhdDoKCmdhcmNoMUBmaXQkc2lnbWEKCldlIGNhbiBsb29rIGF0IHRoZSBsYXN0IHZhbHVlcyBvZiB0aGUgdm9sYXRpbGl0eSBmaXR0ZWQgdmFsdWVzOgoKYGBge3J9CnRhaWwoZ2FyY2gxQGZpdCRzaWdtYSkKYGBgCgpXZSBjYW4gdXNlIHRoZXNlIGZpdCBzaWdtYSB2YWx1ZXMgYW5kIGF0dGFjaCB0aGVtIGluIHRoZSBTUHJldHVybiB4dHMgZGF0YXNldCBhbG9uZyB3aXRoIHRoZSBkYWlseSByZXR1cm5zOgoKYGBge3J9ClNQcmV0dXJuJGd2b2wgPSBnYXJjaDFAZml0JHNpZ21hCmBgYAoKTm93IHdlIGFkZCBhIGNvbHVtbiBmb3IgdGhlIDElVmFSIHVzaW5nIHRoZXNlIGhpc3RvcmljYWwgR0FSQ0ggdm9sYXRpbGl0aWVzLiBJIHdpbGwgdXNlIHRoZSB0LVN0dWRlbnQgZGlzdHJpYnV0aW9uIGFzc3VtaW5nIGZhdC10YWlscyAoIEkgd2lsbCB1c2UgdGhlIHQxIEkgZXN0aW1hdGVkIGFib3ZlKToKCmBgYHtyfQpTUHJldHVybiRnVmFSID0gbWVhbnNwICsgdDEgKiBTUHJldHVybiRndm9sClNQcmV0dXJuJGdWYVIxbWlsbCA9IFNQcmV0dXJuJGdWYVIgKiAxMDAwMDAwCmBgYApOb3cgSSBwbG90IGRhaWx5IGhpc3RvcmljYWwgcmV0dXJucywgYW5kIGhpc3RvcmlhbCBHQVJDSCgxLDEpIGZpdHRlZCB2YWx1ZXMgZm9yIGRhaWx5IHZvbGF0aWxpdGllcyBhbmQgMSVWYWx1ZSBhdCBSaXNrOgpgYGB7cn0KcGxvdChTUHJldHVybiRnVmFSMW1pbGwpCmBgYApgYGB7cn0KcGxvdChTUHJldHVyblssYygyLDMpXSkKYGBgClRoZSBncmVlbiBsaW5lIGlzIHRoZSBHQVJDSCgxLDEpIDElIFZhbHVlIGF0IFJpc2s7IHRoZSByZWQgbGluZSBpcyB0aGUgR0FSQ0goMSwxKSBmaXR0ZWQgdm9sYXRpbGl0eSwgYW5kIHRoZSBibGFjayBsaW5lIGlzIHRoZSBkYWlseSByZXR1cm4gc2VyaWVzLgoKSSByZWNvbW1lbmQgeW91IHRvIHJlYWQgdGhlIGFydGljbGUgR0FSQ0ggMTAxOiBUaGUgdXNlIG9mIFtodHRwOi8vd3d3LmNtYXQuZWR1LnV5L35tb3JkZWNraS9oay9lbmdsZS5wZGZ8fEFSQ0gvR0FSQ0ggTW9kZWxzIGluIEFwcGxpZWQgRWNvbm9tZXRyaWNzXSB3cml0dGVuIGJ5IFJvYmVydCBFbmdsZSB0byBiZXR0ZXIgdW5kZXJzdGFuZCBob3cgeW91IGNhbiBhcHBseSBBUkNIIG1vZGVsIHRvIGZvcmVjYXN0IHZvbGF0aWxpdHkgYW5kIFZhUgoK