1 Exploring market risk-factor data

https://www.qrmtutorial.org/

1.1 Introduction

1.1.1 Exploring risk-factor time series: equity indexes

In this exercise, you will look at an equity index and plot it for a particular range of dates. The data used in this exercise and in the rest of the course are contained in the package qrmdata. You also need the package xts to manipulate time series.

When the qrmdata library is attached, as it will be throughout the course, you can load a dataset with the data() command. For example, the command data(“FTSE”) loads the UK FTSE (Financial Times Stock Exchange) index, which you can then refer to as object FTSE.

If you want to extract the data from a certain date range, for example from April 1 to June 30, 2000, you can create a new object using the command ftse00 <- FTSE[“2000-04-01/2000-06-30”].

library(zoo)
package 㤼㸱zoo㤼㸲 was built under R version 4.0.3
Attaching package: 㤼㸱zoo㤼㸲

The following object is masked from 㤼㸱package:timeSeries㤼㸲:

    time<-

The following objects are masked from 㤼㸱package:base㤼㸲:

    as.Date, as.Date.numeric

Warning messages:
1: package ‘timeSeries’ was built under R version 4.0.3 
2: package ‘timeDate’ was built under R version 4.0.3 
library(xts)
package 㤼㸱xts㤼㸲 was built under R version 4.0.3
library(qrmdata)
package 㤼㸱qrmdata㤼㸲 was built under R version 4.0.3
# Load DJ index
data("DJ")

# Show head() and tail() of DJ index
head(DJ)
              ^DJI
1985-01-29 1292.62
1985-01-30 1287.88
1985-01-31 1286.77
1985-02-01 1277.72
1985-02-04 1290.08
1985-02-05 1285.23
tail(DJ)
               ^DJI
2015-12-23 17602.61
2015-12-24 17552.17
2015-12-28 17528.27
2015-12-29 17720.98
2015-12-30 17603.87
2015-12-31 17425.03
# Plot DJ index
plot(DJ)


# Extract 2008-2009 and assign to dj0809
dj0809 <- DJ["2008-01-01/2009-12-31"]

# Plot dj0809
plot(dj0809)

Take a good look at how it behaves and note how far the index fell in the 2008-2009 financial crisis.

1.1.2 Exploring risk-factor time series: individual equities

For some risk management applications, it is sufficient to model equity risk by looking at indexes. If you want a more detailed model of the risk in a portfolio of equities, you can drill down to the level of individual share prices.

In the previous chapter, you used DJ[“2008/2009”] to extract the Dow Jones data from certain rows of an xts object by specifying a date range index. To also extract data from particular columns, you can add a column identifier, like a string name or numeric index, in the brackets following a comma. To select multiple columns, include these column identifiers in a vector. This [rows, columns] format is consistent with indexing most other two dimensional objects in R.

data[index, colname]
data[index, c(col1index, col2index)]

The qrmdata package also includes data for certain constituents, or the stocks or companies part of a larger index. The Dow Jones constituents data are contained in “DJ_const”. In this exercise, you will view the names of all its stocks, select the Apple and Goldman Sachs share prices, and plot them using the command plot.zoo() to display multiple time series.

# Load DJ constituents data
data("DJ_const")

# Apply names() and head() to DJ_const
names(DJ_const)
 [1] "AAPL" "AXP"  "BA"   "CAT"  "CSCO" "CVX"  "DD"   "DIS"  "GE"   "GS"   "HD"   "IBM"  "INTC" "JNJ" 
[15] "JPM"  "KO"   "MCD"  "MMM"  "MRK"  "MSFT" "NKE"  "PFE"  "PG"   "TRV"  "UNH"  "UTX"  "V"    "VZ"  
[29] "WMT"  "XOM" 
head(DJ_const)
           AAPL AXP       BA      CAT CSCO CVX       DD      DIS       GE GS HD      IBM INTC JNJ JPM
1962-01-02   NA  NA 0.212905 0.593184   NA  NA 1.227958 0.061014 0.145967 NA NA 2.346625   NA  NA  NA
1962-01-03   NA  NA 0.217163 0.598964   NA  NA 1.229230 0.061832 0.144501 NA NA 2.367136   NA  NA  NA
1962-01-04   NA  NA 0.215034 0.614372   NA  NA 1.220331 0.061832 0.142794 NA NA 2.343548   NA  NA  NA
1962-01-05   NA  NA 0.210773 0.620152   NA  NA 1.187280 0.062039 0.139132 NA NA 2.297395   NA  NA  NA
1962-01-08   NA  NA 0.211306 0.624001   NA  NA 1.169484 0.061832 0.138889 NA NA 2.254319   NA  NA  NA
1962-01-09   NA  NA 0.211839 0.629777   NA  NA 1.173297 0.063060 0.139620 NA NA 2.280983   NA  NA  NA
                 KO MCD MMM MRK MSFT NKE PFE PG TRV UNH UTX  V VZ WMT XOM
1962-01-02 0.031031  NA  NA  NA   NA  NA  NA NA  NA  NA  NA NA NA  NA  NA
1962-01-03 0.030339  NA  NA  NA   NA  NA  NA NA  NA  NA  NA NA NA  NA  NA
1962-01-04 0.030571  NA  NA  NA   NA  NA  NA NA  NA  NA  NA NA NA  NA  NA
1962-01-05 0.029879  NA  NA  NA   NA  NA  NA NA  NA  NA  NA NA NA  NA  NA
1962-01-08 0.029570  NA  NA  NA   NA  NA  NA NA  NA  NA  NA NA NA  NA  NA
1962-01-09 0.030110  NA  NA  NA   NA  NA  NA NA  NA  NA  NA NA NA  NA  NA
# Extract AAPL and GS in 2008-09 and assign to stocks
stocks <- DJ_const["2008/2009", c("AAPL", "GS")]

# Plot stocks with plot.zoo()
plot.zoo(stocks)

1.1.3 Exploring risk-factor data: exchange rates

For a portfolio with risk exposure in different countries, it is necessary to consider the risk coming from foreign exchange (FX) rates. The qrmdata package includes FX rate data for many currencies, ranging from Swiss Francs to Japanese Yen, with respect to the USD (United States dollar) and GBP (Great Britain pound).

In this exercise, you will look at the datasets “EUR_USD” and “GBP_USD”, which contain the Euro and British pound exchange rates against the US dollar. Then, you will merge these time series and plot them together for the period 2010-2015.

# Load exchange rate data
data("GBP_USD")
data("EUR_USD")

# Plot the two exchange rates
plot(GBP_USD)

plot(EUR_USD)


# Plot a USD_GBP exchange rate
plot(1/GBP_USD)


# Merge the two exchange rates GBP_USD and EUR_USD
fx <- merge(GBP_USD, EUR_USD, all = TRUE)

# Extract 2010-15 data from fx and assign to fx0015
fx0015 <- fx["2010/2015"]

# Plot the exchange rates in fx0015
plot.zoo(fx0015)

Note that merging the EUR_USD and GBP_USD data, in that order, would have produced a different object from fx.

1.2 Risk-factor returns

1.2.1 Exploring return series

To analyze risk, the key task is to model the fluctuations in prices and rates over different time periods; these fluctuations are known as returns. To calculate the log-returns of the FTSE stock index and assign to ftse_x, apply the log() and diff() functions in succession:

ftse_x <- diff(log(FTSE))

differencing in this way will always give a NA in the first position of the time series, which can then be removed with diff(log(FTSE))[-1]. However, you will not need to do this in the course unless it is specified in the instructions.

In this exercise, you will calculate and plot log-return series for the equity and FX risk factors that you have previously encountered.

# Compute the log-returns of dj0809 and assign to dj0809_x
dj0809_x <- diff(log(dj0809))

# Plot the log-returns
plot(dj0809_x)


# Compute the log-returns of djstocks and assign to djstocks_x
djstocks <- DJ_const["2008/2009", c("AAPL", "GS")]
djstocks_x <- diff(log(djstocks))

# Plot the two share returns
plot.zoo(djstocks_x)


# Compute the log-returns of GBP_USD and assign to erate_x
erate_x <- diff(log(GBP_USD))

# Plot the log-returns
plot(erate_x)

The return series often just look like noise with some periods of larger fluctuations. You’ll discover later that they typically have a lot of interesting structure.

1.2.2 Different ways of plotting risk-factor and return series

You already know that you can use plot.zoo() to plot multiple time series. For a four-dimensional time series data, the call plot.zoo(data) creates four separate plots by default, unless you include the parameter plot.type = “single” to plot all four series in one plot. You can also add even more parameters such as col to specify different colors and type = “h” to get vertical bars instead of joining points, which can sometimes be a better way of displaying returns.

plot.zoo(x, plot.type, col = 1, type = "l", ...)

In this exercise, you will explore the plot.zoo() function to plot equity risk-factor data and the corresponding returns in different ways.

djstocks <- DJ_const["2008/2009", c("AAPL", "AXP", "BA", "CAT")]
# Plot djstocks in four separate plots
plot.zoo(djstocks)


# Plot djstocks in one plot and add legend
plot.zoo(djstocks, plot.type = "single", col = c(1:4))
legend(julian(x = as.Date("2009-01-01")), y = 70, legend = names(DJ_const)[1:4], fill = 1:4)


# Compute log-returns and assign to djstocks_x
djstocks_x <- diff(log(djstocks))

# Plot djstocks_x in four separate plots
plot.zoo(djstocks_x)


# Plot djstocks_x with vertical bars
plot.zoo(djstocks_x, type = "h")

Note how in late 2008 there were large returns for all series. That was the height of the financial crisis.

1.3 Aggregating log-returns

1.3.1 Aggregating log-return series

In statistics, aggregate data are data combined from several measurements. You just learned that you can compute compute weekly, monthly and quarterly log-returns by summing daily log-returns with the corresponding apply.weekly(), apply.monthly() and apply.quarterly() functions.

For example, you can use the following code to form the quarterly returns for a univariate time series data and multivariate time series mv_data:

# apply.quarterly(x, FUN, ...)
data_q = apply.quarterly(data, sum)
mv_data_q = apply.quarterly(mv_data, colSums)

In this exercise, you will practice aggregating time series data using these functions and plotting the results. The data DJ and DJ_const are available in your workspace, as are the objects djx, which contains daily log-returns of the Dow Jones index from 2000-2015, and djreturns, which contains the daily log-returns for the first four DJ_const stocks from 2000-2015. Use plot for univariate time series and plot.zoo for multivariate time series.

dj <- DJ["2000/2015"]
djx <- diff(log(dj))
djstocks <- DJ_const["2000/2015",c("AAPL", "AXP", "BA", "CAT")]
djreturns <- diff(log(djstocks))
# Plot djx
plot(djx)


# Plot weekly log-returns of djx
plot(apply.weekly(djx, sum), type = "h")


# Plot monthly log-returns of djx
plot(apply.monthly(djx, sum), type = "h")


# Plot djreturns
plot.zoo(djreturns)


# Plot monthly log-returns of djreturns
plot.zoo(apply.monthly(djreturns, colSums), type = "h")

These aggregation functions are extremely useful as for analyzing risk over longer time horizons.

Data scientists often use the aggregations that you have learned so far in combination with summary statistics to extract even more insights from data. Functions that calculate summary statistics include mean(), median(), and var(). The object sp contains daily log-returns for the S&P 500 index for the period 1960-2015; it is loaded in your workspace. To three decimal places, what is the average quarterly log-return for the S&P 500 from 1990-2010?

data("SP500")
sp <- SP500["1990/2010"]
sp <- diff(log(sp))[-1]
mean(apply.quarterly(sp, sum))
[1] 0.01490178

1.4 Exploring other kinds of risk factors

1.4.1 Commodities data

The plotting function pairs() creates a pairwise scatterplot of the components of a multivariate time series with two or more dimensions. It is used on a zoo object rather than an xts object.

A roughly circular shape of a scatterplot indicates a low correlation between the log-returns of two different commodities. Generally speaking, low correlation is good in a portfolio as it implies that the assets are diversified. High correlation, on the other hand, represents a risk that must be properly modelled.

In this exercise, you will look at gold and oil prices over a 25 year period, calculate their daily and monthly log-returns, and plot them. The data gold and oil, containing the daily prices from 1990-2015 of gold and Brent crude oil.

data("OIL_Brent")
oil <- OIL_Brent["1990/2015"]
data("GOLD")
gold <- GOLD["1990/2015"]

# Plot gold and oil prices
plot(gold)

plot(oil)


# Calculate daily log-returns
goldx <- diff(log(gold))
oilx <- diff(log(oil))

# Calculate monthly log-returns
goldx_m <- apply.monthly(goldx, sum)
oilx_m <- apply.monthly(oilx, sum)

# Merge goldx_m and oilx_m into coms
coms <- merge(goldx_m, oilx_m)

# Plot coms with vertical bars
plot.zoo(coms, type = "h")


# Make a pairwise scatterplot of coms
pairs(as.zoo(coms))

As you can see, gold and oil are well diversified commodities.

1.5 Interest-rate data

The object zcb contains daily values of Canadian zero-coupon-bond yields, expressed as percentages, for the period 2006-2015. Yields are the key risk-factor when it comes to analysing the interest-rate risk in a portfolio of bonds or other fixed-income products.

It is not so clear what is the best way of calculating risk-factor changes for yields. It is possible to compute log-returns, provided yields are not negative, and it is also possible to calculate simple returns. To compute the simple returns of a series, use only diff() instead of diff() and log().

In this exercise, you will plot time series of yields for fixed times to maturity, and plot risk-factor changes for these yields. You will also plot the whole yield curve on particular dates. The zcb data has been loaded into your workspace. A vector yield_cols containing the names of the columns corresponding to maturities of 1, 5 and 10 years has been created. A numerical vector maturity containing all the maturities in years has also been created.

data("ZCB_CAD")
zcb <- ZCB_CAD["2006/2015"]
maturity <- c(0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 
3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6, 6.25, 
6.5, 6.75, 7, 7.25, 7.5, 7.75, 8, 8.25, 8.5, 8.75, 9, 9.25, 9.5, 
9.75, 10, 10.25, 10.5, 10.75, 11, 11.25, 11.5, 11.75, 12, 12.25, 
12.5, 12.75, 13, 13.25, 13.5, 13.75, 14, 14.25, 14.5, 14.75, 
15, 15.25, 15.5, 15.75, 16, 16.25, 16.5, 16.75, 17, 17.25, 17.5, 
17.75, 18, 18.25, 18.5, 18.75, 19, 19.25, 19.5, 19.75, 20, 20.25, 
20.5, 20.75, 21, 21.25, 21.5, 21.75, 22, 22.25, 22.5, 22.75, 
23, 23.25, 23.5, 23.75, 24, 24.25, 24.5, 24.75, 25, 25.25, 25.5, 
25.75, 26, 26.25, 26.5, 26.75, 27, 27.25, 27.5, 27.75, 28, 28.25, 
28.5, 28.75, 29, 29.25, 29.5, 29.75, 30)
yield_cols <- c("1.00y", "5.00y", "10.00y")
# Compute log-returns as zcb_x and simple returns as zcb_x2
zcb_x <- diff(log(zcb))
zcb_x2 <- diff(zcb)

# Plot zcb_x for 1, 5 and 10-year maturities
plot.zoo(zcb_x[, yield_cols])


# Plot zcb_x2 for 1, 5 and 10-year maturities
plot.zoo(zcb_x2[, yield_cols])


# Plot the yield curve for the first day of zcb
plot(maturity, zcb[1,], ylim = range(zcb), type = "l", ylab = "yield (%)", col = "red")

# Add a line for the last day of zcb
lines(maturity, zcb[nrow(zcb), ])

Yields can seem a little tricky to work with at first but they are fundamental for analyzing bond portfolios and many other financial products that depend on interest rates.

2 Real world returns are riskier than normal

2.1 The normal distribution

2.1.1 Graphical methods for assessing normality

To create a histogram with 20 buckets that represents the probability density of the FTSE data, as well as how to add a normal distribution to the existing plot as a red line:

hist(ftse, nclass = 20, probability = TRUE)
lines(ftse, dnorm(ftse, mean = mu, sd = sigma), col = "red")

As you can see, dnorm(x, mean, sd) calculates the probability density function (PDF) of the data x with the calculated sample mean and standard deviation; this is known as the method-of-moments.

Finally, to calculate an estimate of the density of data x, use density(x). This creates a so-called kernel-density estimate (KDE) using a non-parametric method that makes no assumptions about the underlying distribution.

The various plots suggest that the data are heavier tailed than normal, although you will learn about better graphical and numerical tests in future exercises.

In this exercise, you will fit a normal distribution to the log-returns of the Dow Jones index for 2008-2009 and compare the data with the fitted distribution using a histogram and a density plot. The object djx containing Dow Jones data is loaded into your workspace.

djx <- DJ["2008/2009"]
djx <- diff(log(djx))
djx <- as.numeric(djx)[-1]
djx <- sort(djx)
# Calculate average and standard deviation of djx
mu <- mean(djx)
sigma <- sd(djx)

# Plot histogram of djx
hist(djx, nclass = 20, probability = TRUE)

# Add the normal density as a red line to histogram
lines(djx, dnorm(djx, mean = mu, sd = sigma), col = "red")


# Plot non-parametric KDE of djx
plot(density(djx))

# Add the normal density as red line to KDE
lines(djx, dnorm(djx, mean = mu, sd = sigma), col = "red")

mu <- mean(djx)
sigma <- sd(djx)
te <- dnorm(djx, mean = mu, sd = sigma)
ord <- sort(djx)
head(ord)
[1] -0.08200514 -0.08014005 -0.07615925 -0.07234497 -0.05863401 -0.05725062
tail(ord)
[1] 0.05633869 0.06337643 0.06458521 0.06611575 0.10325919 0.10508346
te <- dnorm(ord, mean = mu, sd = sigma)
head(te)
[1] 0.004951580 0.007206443 0.015594272 0.031482814 0.291488669 0.355490098

The data don’t look very normal. Compare in particular the center and the tails of the histogram and density plot with the red normal curve.

2.2 Testing for normality

2.2.1 Q-Q plots for assessing normality

The quantile-quantile plot (Q-Q plot) is a better graphical method for revealing non-normality. In general, a Q-Q plot compares the quantiles of the data with the quantiles of a reference distribution; if the data are from a distribution of the same type (up to scaling and location), a reasonably straight line should be observed. You should know that the degrees of freedom (df) refer to the number of values or observations that can affect the system you are working with.

To generate 1000 normal data points with the rnorm() function, as well as how to use qqnorm() to create the Q-Q plot, and qqline() to add a straight line for reference:

data <- rnorm(1000, mean = 3, sd = 2)
qqnorm(data)
qqline(data)

You will create a Q-Q plot of the Dow Jones log-returns in djx against the normal reference distribution, which you will add as a visual guide. You will then compare the plot with simulated datasets from normal, Student t and uniform distributions generated with the rnorm(), rt() and runif() functions. Y

If the data are from a normal distribution the dots should be close to the red line (although there may be some deviation at the very end).

# Make a Q-Q plot of djx and add a red line
qqnorm(djx)
qqline(djx, col = "red")


# Calculate the length of djx as n
n <- length(djx)

# Generate n standard normal variables, make a Q-Q plot, add a red line
x1 <- rnorm(n)
qqnorm(x1)
qqline(x1, col = "red")


# Generate n Student t variables, make a Q-Q plot, add a red line
x2 <- rt(n, df = 4)
qqnorm(x2)
qqline(x2, col = "red")


# Generate n standard uniform variables, make a Q-Q plot, add red line
x3 <- runif(n)
qqnorm(x3)
qqline(x3, col = "red")

The Q-Q plot is a very effective tool that is widely used in applied statistical and econometric work.

2.3 Skewness, kurtosis and the Jarque-Bera test

2.3.1 Numerical tests of normality

The moments package contains functions for computing the kurtosis and skewness of data and well as for implementing the Jarque-Bera test, which is a test of normality based on these higher-order moments. In one command, it compares the skewness and kurtosis of the data with the theoretical values for the normal distribution, which are 0 and 3, respectively.

jarque.test(x)
skewness(x, na.rm = FALSE)
kurtosis(x, na.rm = FALSE)

In this exercise, you will calculate the skewness and kurtosis for the djx, the Dow Jones index from 2008-2011, and apply the Jarque-Bera test of normality. You will then apply the same methods to djreturns, which contains 29 of the Dow Jones stocks for the same period.

Recall that you can use apply(X, MARGIN, FUN, …) to apply functions over array margins. The MARGIN parameter is a vector indicating where the function will be applied; in this instance, you will use 2 to specify that the function FUN should be applied to the columns in matrix X.

dj <- DJ["2008/2011"]
djx <- diff(log(dj))
djx <- as.numeric(djx)[-1]
djx <- sort(djx)

djstocks <- DJ_const["2008/2011"]
djreturns <- diff(log(djstocks))[-1]
library(moments)
package 㤼㸱moments㤼㸲 was built under R version 4.0.3
Attaching package: 㤼㸱moments㤼㸲

The following objects are masked from 㤼㸱package:timeDate㤼㸲:

    kurtosis, skewness
# Calculate skewness and kurtosis of djx
skewness(djx)
[1] 0.001913285
kurtosis(djx)
[1] 9.058875
# Carry out a Jarque-Bera test for djx
jarque.test(djx)

    Jarque-Bera Normality Test

data:  djx
JB = 1541.8, p-value < 2.2e-16
alternative hypothesis: greater
# Calculate skewness and kurtosis of djreturns 
s <- apply(djreturns, 2, skewness)
k <- apply(djreturns, 2, kurtosis)

# Plot k against s and add text labels to identify stocks
plot(s, k, type = "n")
text(s, k, names(s), cex = 0.6)


# Carry out Jarque-Bera tests for each constituent in djreturns
apply(djreturns, 2, jarque.test)
$AAPL

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1819.5, p-value < 2.2e-16
alternative hypothesis: greater


$AXP

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1066.1, p-value < 2.2e-16
alternative hypothesis: greater


$BA

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 347.08, p-value < 2.2e-16
alternative hypothesis: greater


$CAT

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 304.64, p-value < 2.2e-16
alternative hypothesis: greater


$CSCO

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 2758.9, p-value < 2.2e-16
alternative hypothesis: greater


$CVX

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 5268.2, p-value < 2.2e-16
alternative hypothesis: greater


$DD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 459.61, p-value < 2.2e-16
alternative hypothesis: greater


$DIS

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1053.4, p-value < 2.2e-16
alternative hypothesis: greater


$GE

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1176.9, p-value < 2.2e-16
alternative hypothesis: greater


$GS

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 3513.6, p-value < 2.2e-16
alternative hypothesis: greater


$HD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 470.66, p-value < 2.2e-16
alternative hypothesis: greater


$IBM

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 660.46, p-value < 2.2e-16
alternative hypothesis: greater


$INTC

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 510.51, p-value < 2.2e-16
alternative hypothesis: greater


$JNJ

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 5987.3, p-value < 2.2e-16
alternative hypothesis: greater


$JPM

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1906.3, p-value < 2.2e-16
alternative hypothesis: greater


$KO

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 4310.6, p-value < 2.2e-16
alternative hypothesis: greater


$MCD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 809.57, p-value < 2.2e-16
alternative hypothesis: greater


$MMM

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 379.55, p-value < 2.2e-16
alternative hypothesis: greater


$MRK

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 2647.7, p-value < 2.2e-16
alternative hypothesis: greater


$MSFT

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 2280.7, p-value < 2.2e-16
alternative hypothesis: greater


$NKE

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 944.42, p-value < 2.2e-16
alternative hypothesis: greater


$PFE

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 717.42, p-value < 2.2e-16
alternative hypothesis: greater


$PG

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1690.9, p-value < 2.2e-16
alternative hypothesis: greater


$TRV

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 8039.2, p-value < 2.2e-16
alternative hypothesis: greater


$UNH

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 10514, p-value < 2.2e-16
alternative hypothesis: greater


$UTX

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1044, p-value < 2.2e-16
alternative hypothesis: greater


$V

    Jarque-Bera Normality Test

data:  newX[, i]
JB = NA, p-value = NA
alternative hypothesis: greater


$VZ

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1969.1, p-value < 2.2e-16
alternative hypothesis: greater


$WMT

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 2350.8, p-value < 2.2e-16
alternative hypothesis: greater


$XOM

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 5812.4, p-value < 2.2e-16
alternative hypothesis: greater

The return distributions of the Dow Jones stocks all have high kurtosis and some of them are quite skewed.

2.3.2 Testing normality for longer time horizons

As returns are added together over longer time periods, a central limit effect takes place and returns tend to become more normal.

In this exercise, you will use aggregation functions that you learned in the first chapter to aggregate the data in djx_d, containing the daily log-returns for 29 of the Dow Jones stocks for the period 2000-2015.

djstocks <- DJ_const["2000/2015"]
djreturns <- diff(log(djstocks))[-1]
djx_d <- djreturns
# Calculate weekly and monthly log-returns from djx_d
djx_w <- apply.weekly(djx_d, colSums)
djx_m <- apply.monthly(djx_d, colSums)

# Calculate the p-value for each series in djx_d
apply(djx_d, 2, function(v){jarque.test(v)$p.value})
AAPL  AXP   BA  CAT CSCO  CVX   DD  DIS   GE   GS   HD  IBM INTC  JNJ  JPM   KO  MCD  MMM  MRK MSFT  NKE 
   0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0 
 PFE   PG  TRV  UNH  UTX    V   VZ  WMT  XOM 
   0    0    0    0    0   NA    0    0    0 
# Calculate the p-value for each series in djx_w
apply(djx_w, 2, function(v){jarque.test(v)$p.value})
AAPL  AXP   BA  CAT CSCO  CVX   DD  DIS   GE   GS   HD  IBM INTC  JNJ  JPM   KO  MCD  MMM  MRK MSFT  NKE 
   0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0 
 PFE   PG  TRV  UNH  UTX    V   VZ  WMT  XOM 
   0    0    0    0    0   NA    0    0    0 
# Calculate the p-value for each series in djx_m
apply(djx_m, 2, function(v){jarque.test(v)$p.value})
        AAPL          AXP           BA          CAT         CSCO          CVX           DD          DIS 
0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 1.110223e-16 1.677566e-01 5.059611e-03 4.043754e-11 
          GE           GS           HD          IBM         INTC          JNJ          JPM           KO 
3.086420e-13 3.259324e-02 5.493080e-02 0.000000e+00 0.000000e+00 5.472560e-08 1.982609e-06 5.641173e-07 
         MCD          MMM          MRK         MSFT          NKE          PFE           PG          TRV 
0.000000e+00 9.341348e-02 1.524618e-07 0.000000e+00 0.000000e+00 3.076613e-01 0.000000e+00 0.000000e+00 
         UNH          UTX            V           VZ          WMT          XOM 
0.000000e+00 0.000000e+00           NA 0.000000e+00 7.281104e-04 1.100037e-02 

Although the p-values get larger, all monthly returns other than for Chevron (CVX), 3M (MMM), and Pfizer (PFE) still fail the normality test.

2.3.3 Overlapping returns

When you aggregate series by summing daily log-returns into longer intervals, you analyze a smaller amount of observations. To preserve the quantity of data, you can calculate overlapping returns with the rollapplyr() function; this also creates strong correlations between observations.

There are 5 trading days in the average calendar week. By computing the 5-day moving sums of the log-returns of daily index data, you obtain approximate overlapping weekly returns ending on each calendar week. Similarly, calculating 21-day moving sums gives approximate overlapping monthly returns, and calculating 63-day moving sums gives approximate overlapping quarterly returns. Let’s look at an example with the Dow Jones daily return data in djx. Because 5 values are used to calculate each moving sum, the first 4 values in the result are NA. In this instance, we will use indexing to remove them:

dj <- DJ["2008/2011"]
djx <- diff(log(dj))[-1]
djx5 <- rollapplyr(djx, width = 5, FUN = sum)
head(djx5)
                  ^DJI
2008-01-03          NA
2008-01-04          NA
2008-01-07          NA
2008-01-08          NA
2008-01-09 -0.02394677
2008-01-10 -0.01571869
djx5 <- djx5[-(1:4)]

n this exercise, you will calculate moving sums of different intervals from djx, which is loaded in your workspace. You will then find the skewness and kurtosis of the resulting data and conduct the Jarque-Bera test just as you have in previous exercises. Do the overlapping returns appear more normal?

# Calculate a 21-day moving sum of djx
djx21 <- rollapplyr(djx, width = 21, FUN = sum)[-(1:20)]

# Calculate a 63-day moving sum of djx
djx63 <- rollapplyr(djx, width = 63, FUN = sum)[-(1:62)]

# Merge the three series and plot
djx2 <- merge(djx, djx21, djx63, all = FALSE)
plot.zoo(djx2)


# Compute the skewness and kurtosis for each series in djx2
apply(djx2, 2, skewness)
      X.DJI     X.DJI.1     X.DJI.2 
-0.01276806 -1.16018080 -0.87509434 
apply(djx2, 2, kurtosis)
   X.DJI  X.DJI.1  X.DJI.2 
9.264838 5.845321 3.845090 
# Conduct the Jarque-Bera test to each series in djx2
apply(djx2, 2, jarque.test)
$X.DJI

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 1547.1, p-value < 2.2e-16
alternative hypothesis: greater


$X.DJI.1

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 531.33, p-value < 2.2e-16
alternative hypothesis: greater


$X.DJI.2

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 148.89, p-value < 2.2e-16
alternative hypothesis: greater

These overlapping returns are highly correlated and even more difficult to interpret.

2.4 The Student t distribution

2.4.1 Fitting t distribution to data

A Student t distribution is generally a much better fit to daily, weekly, and monthly returns than a normal distribution.

You can create one by using the fit.st() function in the QRM package. The resulting fitted model has a parameter estimates component par.ests which can be assigned to a list tpars in order to store its values of nu, mu, and sigma for later use:

tfit <- fit.st(ftse)
tpars <- tfit$par.ests
tpars

You will fit a Student t distribution to the daily log-returns of the Dow Jones index from 2008-2011 contained in djx. Then, you will plot a histogram of the data and superimpose a red line to the plot showing the fitted t density.

library(QRM)
djx <- as.numeric(djx)
djx <- sort(djx)
# Fit a Student t distribution to djx
tfit <- fit.st(djx)

# Define tpars, nu, mu, and sigma
tpars <- tfit$par.ests
nu <- tpars[1]
mu <- tpars[2]
sigma <- tpars[3]

# Plot a histogram of djx
hist(djx, nclass = 20, probability = TRUE, ylim = range(0, 40))

# Compute the fitted t density at the values djx
yvals <- dt((djx - mu)/sigma, df = nu)/sigma

# Superimpose a red line to show the fitted t density
lines(djx, yvals, col = "red")

The fitted Student t distribution looks a lot better than the normal did.

2.4.2 Testing FX returns for normality

So far, the exercises in this chapter have examined the normality of equity index returns and individual equity returns.

To reinforce these ideas, you will apply similar ideas to exchange-rate log-returns. The dataset fx_d contains daily log-returns of the EUR/USD, GBP/USD and JPY/USD exchange rates for the period 2001-2015, and the dataset fx_m contains the corresponding monthly log-returns. Which of the monthly log-return series appears the most normal?

data("EUR_USD")
data("GBP_USD")
data("JPY_USD")
fx1 <- EUR_USD["2001/2015"]
fx2 <- GBP_USD["2001/2015"]
fx3 <- JPY_USD["2001/2015"]
fx <- merge(fx1, fx2, fx3)
fx_d <- apply(log(fx), 2, diff)
fx_m <- apply.monthly(fx_d, colSums)
# Plot the daily log-return series in fx_d
plot.zoo(fx_d, type = "h")


# Apply the Jarque-Bera test to each of the series in fx_d
apply(fx_d, 2, jarque.test)
$EUR.USD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 2791.1, p-value < 2.2e-16
alternative hypothesis: greater


$GBP.USD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 10962, p-value < 2.2e-16
alternative hypothesis: greater


$JPY.USD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 5039.7, p-value < 2.2e-16
alternative hypothesis: greater
# Plot the monthly log-return series in fx_m
plot.zoo(fx_m, type = "h")


# Apply the Jarque-Bera test to each of the series in fx_m
apply(fx_m, 2, jarque.test)
$EUR.USD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 22.717, p-value = 1.167e-05
alternative hypothesis: greater


$GBP.USD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 40.814, p-value = 1.372e-09
alternative hypothesis: greater


$JPY.USD

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 3.6561, p-value = 0.1607
alternative hypothesis: greater
# Fit a Student t distribution to each of the series in fx_m
apply(fx_m, 2, function(v){fit.st(v)$par.ests})
         EUR.USD      GBP.USD      JPY.USD
nu    4.91304346 6.0621630186 1.840870e+01
mu    0.00194676 0.0008555348 1.118179e-04
sigma 0.02376514 0.0204503515 2.553159e-02

JPY/USD exchange rate log-returns appear to be the most normal.

2.4.3 Testing interest-rate returns for normality

The object zcbx_m contains monthly log-return series for the 1-year, 5-year and 10-year Canadian zero-coupon bond yields. The object zcbx2_m contains the corresponding simple returns. Both are multivariate; they are loaded into your workspace.

In this exercise, you will plot these interest rate return series and then examine their normality with Q-Q plots and Jarque-Bera tests.

The log-returns show clearer evidence of non-normality than the simple returns in this case.

data("ZCB_CAD")
zcb <- ZCB_CAD[,c("1.00y", "5.00y", "10.00y")]
zcbx <- diff(log(zcb))
zcbx2 <- diff(zcb)
zcbx_m <- apply.monthly(zcbx, colSums)["2006/2015"]
zcbx2_m<- apply.monthly(zcbx2, colSums)["2006/2015"]
# Plot the interest-rate return series zcbx_m and zcbx2_m
plot.zoo(zcbx_m, type = "h")

plot.zoo(zcbx2_m, type = "h")


# Make Q-Q plots of the 3rd component series of zcbx_m and zcbx2_m
qqnorm(zcbx_m[,3])

qqnorm(zcbx2_m[,3])


# Compute the kurtosis of each series in zcbx_m and zcbx2_m
apply(zcbx_m, 2, kurtosis)
    1.00y     5.00y    10.00y 
 8.597937 13.899820  7.990000 
apply(zcbx2_m, 2, kurtosis)
   1.00y    5.00y   10.00y 
6.105796 3.737785 3.510665 
# Conduct the Jarque-Bera test on each series in zcbx_m and zcbx2_m
apply(zcbx_m, 2, jarque.test)
$`1.00y`

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 164.94, p-value < 2.2e-16
alternative hypothesis: greater


$`5.00y`

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 645.07, p-value < 2.2e-16
alternative hypothesis: greater


$`10.00y`

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 142.19, p-value < 2.2e-16
alternative hypothesis: greater
apply(zcbx2_m, 2, jarque.test)
$`1.00y`

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 77.413, p-value < 2.2e-16
alternative hypothesis: greater


$`5.00y`

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 5.7791, p-value = 0.0556
alternative hypothesis: greater


$`10.00y`

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 4.0851, p-value = 0.1297
alternative hypothesis: greater

Note how the simple monthly returns for the 5 and 10 year yields did not fail the normality test.

2.4.4 Testing gold price returns for normality

The object goldx_q contains quarterly log-returns of the gold price from the beginning of 1990 to the end of 2015.

Test the data for normality using the Jarque-Bera test, then fit a Student t distribution and find the estimated degree of freedom ν^ to the nearest integer.

data("GOLD")
gold <- GOLD["1990/2015"]
goldx <- diff(log(gold))[-1]
goldx_q <- as.numeric(apply.quarterly(goldx, sum)[,1])
jarque.test(goldx_q)

    Jarque-Bera Normality Test

data:  goldx_q
JB = 35.01, p-value = 2.498e-08
alternative hypothesis: greater
tfit <- fit.st(goldx_q)

tpars <- tfit$par.ests

tpars[1]
      nu 
9.917565 

The data fail a test of normality and \(\hat{\nu}=10\)

3 Real world returns are volatile and correlated

3.1 Characteristics of volatile return series

In this exercise you will plot the Dow Jones log-returns for 2008-2011 alongside independent and identically distributed (iid) normal data and iid Student t data.

The xts object djx contains the Dow Jones index and the objects npars and tpars contain the parameter estimates that are obtained when a normal distribution and a t distribution are fitted to djx. you will generate a normal sample from the fitted model by generating standard normal data, scaling them with the second component npars[2] and shifting them with the first component npars[1]. For the Student t sample you will do something similar but note that this time the first component tpars[1] contains the degree of freedom parameter and tpars[2] and tpars[3] contain the location and scale parameters.

After making the plots, you should compare the behavior of the real returns with that of the iid returns, particularly around the 2008 financial crisis.

djx <- DJ["2007-12-31/2011-12-31"]
djx <- diff(log(djx))[-1]
npars <- c(mu = mean(djx), sigma = sd(djx))
tfit <- fit.st(djx)
tpars <- tfit$par.ests
set.seed(123)
# Compute the length n of djx 
n <- length(djx)

#  Generate a normal sample of size n with parameters given by npars
ndata <- rnorm(n)*npars[2] + npars[1]

# Generate a t-distributed sample of size n with paramaters given by tpars
tdata <- rt(n, df = tpars[1])*tpars[3] + tpars[2]

# Make ndata and tdata into xts objects
ndatax <- xts(ndata, time(djx))
tdatax <- xts(tdata, time(djx))

# Merge djx, ndatax, and tdatax and plot
alldata <- merge(djx, ndatax, tdatax)
plot.zoo(alldata, type = "h", ylim = range(alldata))

Note how the real returns look more volatile than the iid returns. There was clearly a period of large movements around the 2008 financial crisis followed by a quieter period in 2010.

3.2 Estimating serial correlations

3.2.1 Using acf plots to reveal volatility

This exercise follows on from the previous R exercise where we looked for visible signs of volatility in a financial time series. For the Dow Jones returns from 2008-11 in djx and the simulated normal and t-distributed data in ndata and tdata, respectively, you will calculate and plot the sample autocorrelation functions (acf) using the command acf().

While very little evidence of serial correlation is found in these plots, the picture changes dramatically when we look at absolute or squared return data. The real returns in the Dow Jones return series djx behave very differently to the simulated data. The serial correlation in absolute or squared returns is a consequence of volatility, which causes large returns to be followed by further large returns, although not necessarily of the same sign.

# Set up a plot region to show 3 plots at a time
par(mfrow = c(3, 1))

# Plot the acfs of djx, ndata and tdata
acf(djx)
acf(ndata)
acf(tdata)


# Plot the acfs of the absolute values
acf(abs(djx))
acf(abs(ndata))
acf(abs(tdata))


# Plot the acfs of the squares of the values
acf(djx^2)
acf(ndata^2)
acf(tdata^2)

It is very common to see strong serial correlation in absolute and squared return series.

3.3 The Ljung-Box test

3.3.1 Applying Ljung-Box tests to return data

This code applies the Ljung-Box test to the ftse data with a lag of 10:

Box.test(ftse, lag = 10, type = "Ljung")

You will carry out a Ljung-Box test for serial correlation on the time series djx which contains the Dow Jones daily index returns for 2008-2011, as well as on all the individual equity return series in djall which contains the Dow Jones data for 2006-2015. You will implement this test on both the raw return series and the absolute values of the series, which you can calculate with abs().

You should notice that while the hypothesis of no serial correlation is rejected for many of the raw return series, it is rejected overwhelmingly for all of the absolute value series.

djall <- DJ_const["2006-12-31/2015-12-31"]
djall <- diff(log(djall))[-1]
# Apply the Ljung-Box test to djx
Box.test(djx, lag = 10, type = "Ljung")

    Box-Ljung test

data:  djx
X-squared = 34.228, df = 10, p-value = 0.000169
# Apply the Ljung-Box test to absolute values of djx
Box.test(abs(djx), lag = 10, type = "Ljung")

    Box-Ljung test

data:  abs(djx)
X-squared = 1083.9, df = 10, p-value < 2.2e-16
# Apply the Ljung-Box test to all return series in djall
apply(djall, 2, Box.test, lag = 10, type = "Ljung")
$AAPL

    Box-Ljung test

data:  newX[, i]
X-squared = 15.063, df = 10, p-value = 0.1298


$AXP

    Box-Ljung test

data:  newX[, i]
X-squared = 45.453, df = 10, p-value = 1.802e-06


$BA

    Box-Ljung test

data:  newX[, i]
X-squared = 19.929, df = 10, p-value = 0.02993


$CAT

    Box-Ljung test

data:  newX[, i]
X-squared = 16.596, df = 10, p-value = 0.08379


$CSCO

    Box-Ljung test

data:  newX[, i]
X-squared = 15.694, df = 10, p-value = 0.1087


$CVX

    Box-Ljung test

data:  newX[, i]
X-squared = 63.987, df = 10, p-value = 6.331e-10


$DD

    Box-Ljung test

data:  newX[, i]
X-squared = 28.199, df = 10, p-value = 0.001677


$DIS

    Box-Ljung test

data:  newX[, i]
X-squared = 31.457, df = 10, p-value = 0.0004929


$GE

    Box-Ljung test

data:  newX[, i]
X-squared = 39.402, df = 10, p-value = 2.159e-05


$GS

    Box-Ljung test

data:  newX[, i]
X-squared = 35.037, df = 10, p-value = 0.0001231


$HD

    Box-Ljung test

data:  newX[, i]
X-squared = 12.51, df = 10, p-value = 0.2524


$IBM

    Box-Ljung test

data:  newX[, i]
X-squared = 27.601, df = 10, p-value = 0.002091


$INTC

    Box-Ljung test

data:  newX[, i]
X-squared = 56.863, df = 10, p-value = 1.414e-08


$JNJ

    Box-Ljung test

data:  newX[, i]
X-squared = 56.638, df = 10, p-value = 1.559e-08


$JPM

    Box-Ljung test

data:  newX[, i]
X-squared = 50.188, df = 10, p-value = 2.465e-07


$KO

    Box-Ljung test

data:  newX[, i]
X-squared = 37.219, df = 10, p-value = 5.186e-05


$MCD

    Box-Ljung test

data:  newX[, i]
X-squared = 40.098, df = 10, p-value = 1.628e-05


$MMM

    Box-Ljung test

data:  newX[, i]
X-squared = 28.234, df = 10, p-value = 0.001656


$MRK

    Box-Ljung test

data:  newX[, i]
X-squared = 19.687, df = 10, p-value = 0.03235


$MSFT

    Box-Ljung test

data:  newX[, i]
X-squared = 40.66, df = 10, p-value = 1.296e-05


$NKE

    Box-Ljung test

data:  newX[, i]
X-squared = 34.322, df = 10, p-value = 0.0001629


$PFE

    Box-Ljung test

data:  newX[, i]
X-squared = 49.19, df = 10, p-value = 3.759e-07


$PG

    Box-Ljung test

data:  newX[, i]
X-squared = 48.028, df = 10, p-value = 6.133e-07


$TRV

    Box-Ljung test

data:  newX[, i]
X-squared = 131.74, df = 10, p-value < 2.2e-16


$UNH

    Box-Ljung test

data:  newX[, i]
X-squared = 47.264, df = 10, p-value = 8.455e-07


$UTX

    Box-Ljung test

data:  newX[, i]
X-squared = 37.93, df = 10, p-value = 3.903e-05


$V

    Box-Ljung test

data:  newX[, i]
X-squared = 35.988, df = 10, p-value = 8.457e-05


$VZ

    Box-Ljung test

data:  newX[, i]
X-squared = 37.096, df = 10, p-value = 5.448e-05


$WMT

    Box-Ljung test

data:  newX[, i]
X-squared = 44.655, df = 10, p-value = 2.51e-06


$XOM

    Box-Ljung test

data:  newX[, i]
X-squared = 117.54, df = 10, p-value < 2.2e-16
# Apply the Ljung-Box test to absolute values of all returns in djall
apply(abs(djall), 2, Box.test, lag = 10, type = "Ljung")
$AAPL

    Box-Ljung test

data:  newX[, i]
X-squared = 910.73, df = 10, p-value < 2.2e-16


$AXP

    Box-Ljung test

data:  newX[, i]
X-squared = 3111.9, df = 10, p-value < 2.2e-16


$BA

    Box-Ljung test

data:  newX[, i]
X-squared = 1077, df = 10, p-value < 2.2e-16


$CAT

    Box-Ljung test

data:  newX[, i]
X-squared = 1567.6, df = 10, p-value < 2.2e-16


$CSCO

    Box-Ljung test

data:  newX[, i]
X-squared = 646.52, df = 10, p-value < 2.2e-16


$CVX

    Box-Ljung test

data:  newX[, i]
X-squared = 2203.8, df = 10, p-value < 2.2e-16


$DD

    Box-Ljung test

data:  newX[, i]
X-squared = 1432.9, df = 10, p-value < 2.2e-16


$DIS

    Box-Ljung test

data:  newX[, i]
X-squared = 1820.8, df = 10, p-value < 2.2e-16


$GE

    Box-Ljung test

data:  newX[, i]
X-squared = 2336.6, df = 10, p-value < 2.2e-16


$GS

    Box-Ljung test

data:  newX[, i]
X-squared = 2078.9, df = 10, p-value < 2.2e-16


$HD

    Box-Ljung test

data:  newX[, i]
X-squared = 1843.2, df = 10, p-value < 2.2e-16


$IBM

    Box-Ljung test

data:  newX[, i]
X-squared = 1025, df = 10, p-value < 2.2e-16


$INTC

    Box-Ljung test

data:  newX[, i]
X-squared = 1063.8, df = 10, p-value < 2.2e-16


$JNJ

    Box-Ljung test

data:  newX[, i]
X-squared = 1496.1, df = 10, p-value < 2.2e-16


$JPM

    Box-Ljung test

data:  newX[, i]
X-squared = 3038.8, df = 10, p-value < 2.2e-16


$KO

    Box-Ljung test

data:  newX[, i]
X-squared = 1526, df = 10, p-value < 2.2e-16


$MCD

    Box-Ljung test

data:  newX[, i]
X-squared = 1197.3, df = 10, p-value < 2.2e-16


$MMM

    Box-Ljung test

data:  newX[, i]
X-squared = 1272.8, df = 10, p-value < 2.2e-16


$MRK

    Box-Ljung test

data:  newX[, i]
X-squared = 1402.9, df = 10, p-value < 2.2e-16


$MSFT

    Box-Ljung test

data:  newX[, i]
X-squared = 824.11, df = 10, p-value < 2.2e-16


$NKE

    Box-Ljung test

data:  newX[, i]
X-squared = 1174.9, df = 10, p-value < 2.2e-16


$PFE

    Box-Ljung test

data:  newX[, i]
X-squared = 1187.9, df = 10, p-value < 2.2e-16


$PG

    Box-Ljung test

data:  newX[, i]
X-squared = 1115.4, df = 10, p-value < 2.2e-16


$TRV

    Box-Ljung test

data:  newX[, i]
X-squared = 2873.8, df = 10, p-value < 2.2e-16


$UNH

    Box-Ljung test

data:  newX[, i]
X-squared = 1407.5, df = 10, p-value < 2.2e-16


$UTX

    Box-Ljung test

data:  newX[, i]
X-squared = 1462.8, df = 10, p-value < 2.2e-16


$V

    Box-Ljung test

data:  newX[, i]
X-squared = 1165.2, df = 10, p-value < 2.2e-16


$VZ

    Box-Ljung test

data:  newX[, i]
X-squared = 1916.2, df = 10, p-value < 2.2e-16


$WMT

    Box-Ljung test

data:  newX[, i]
X-squared = 685.86, df = 10, p-value < 2.2e-16


$XOM

    Box-Ljung test

data:  newX[, i]
X-squared = 1918.2, df = 10, p-value < 2.2e-16

Note that the Ljung-Box test did not reject the null hypothesis when applied to the raw returns for AAPL, CAT, CSCO and HD.

3.3.2 Applying Ljung-Box tests to longer-interval returns

What happens when you apply the same analyses as in the previous exercise to the monthly returns rather than the daily returns? Does the amount of serial dependence in the data appear to increase or decrease?

# Create monthly log-returns from djx
djx_m <- apply.monthly(djx, sum)

# Apply Ljung-Box tests to raw and absolute values of djx_m
Box.test(djx_m, lag = 10, type = "Ljung")

    Box-Ljung test

data:  djx_m
X-squared = 21.099, df = 10, p-value = 0.02041
Box.test(abs(djx_m), lag = 10, type = "Ljung")

    Box-Ljung test

data:  abs(djx_m)
X-squared = 12.78, df = 10, p-value = 0.2362
# Create monthly log-returns from djall
djall_m <- apply.monthly(djall, colSums)

# Apply Ljung-Box tests to raw and absolute values of djall_m
apply(djall_m, 2, Box.test, lag = 10, type = "Ljung")
$AAPL

    Box-Ljung test

data:  newX[, i]
X-squared = 8.7875, df = 10, p-value = 0.5524


$AXP

    Box-Ljung test

data:  newX[, i]
X-squared = 24.336, df = 10, p-value = 0.006756


$BA

    Box-Ljung test

data:  newX[, i]
X-squared = 15.021, df = 10, p-value = 0.1313


$CAT

    Box-Ljung test

data:  newX[, i]
X-squared = 24.815, df = 10, p-value = 0.005707


$CSCO

    Box-Ljung test

data:  newX[, i]
X-squared = 11.565, df = 10, p-value = 0.3152


$CVX

    Box-Ljung test

data:  newX[, i]
X-squared = 8.576, df = 10, p-value = 0.5728


$DD

    Box-Ljung test

data:  newX[, i]
X-squared = 16.261, df = 10, p-value = 0.0924


$DIS

    Box-Ljung test

data:  newX[, i]
X-squared = 25.73, df = 10, p-value = 0.004122


$GE

    Box-Ljung test

data:  newX[, i]
X-squared = 13.919, df = 10, p-value = 0.1767


$GS

    Box-Ljung test

data:  newX[, i]
X-squared = 8.2406, df = 10, p-value = 0.6053


$HD

    Box-Ljung test

data:  newX[, i]
X-squared = 15.412, df = 10, p-value = 0.1178


$IBM

    Box-Ljung test

data:  newX[, i]
X-squared = 7.6343, df = 10, p-value = 0.6645


$INTC

    Box-Ljung test

data:  newX[, i]
X-squared = 7.7879, df = 10, p-value = 0.6495


$JNJ

    Box-Ljung test

data:  newX[, i]
X-squared = 12.386, df = 10, p-value = 0.2601


$JPM

    Box-Ljung test

data:  newX[, i]
X-squared = 8.1258, df = 10, p-value = 0.6165


$KO

    Box-Ljung test

data:  newX[, i]
X-squared = 23.391, df = 10, p-value = 0.00939


$MCD

    Box-Ljung test

data:  newX[, i]
X-squared = 15.718, df = 10, p-value = 0.108


$MMM

    Box-Ljung test

data:  newX[, i]
X-squared = 10.849, df = 10, p-value = 0.3694


$MRK

    Box-Ljung test

data:  newX[, i]
X-squared = 9.9017, df = 10, p-value = 0.4492


$MSFT

    Box-Ljung test

data:  newX[, i]
X-squared = 6.1226, df = 10, p-value = 0.8049


$NKE

    Box-Ljung test

data:  newX[, i]
X-squared = 6.1524, df = 10, p-value = 0.8023


$PFE

    Box-Ljung test

data:  newX[, i]
X-squared = 11.468, df = 10, p-value = 0.3222


$PG

    Box-Ljung test

data:  newX[, i]
X-squared = 6.427, df = 10, p-value = 0.7782


$TRV

    Box-Ljung test

data:  newX[, i]
X-squared = 11.718, df = 10, p-value = 0.3044


$UNH

    Box-Ljung test

data:  newX[, i]
X-squared = 19.614, df = 10, p-value = 0.03312


$UTX

    Box-Ljung test

data:  newX[, i]
X-squared = 20.689, df = 10, p-value = 0.02337


$V

    Box-Ljung test

data:  newX[, i]
X-squared = 10.395, df = 10, p-value = 0.4066


$VZ

    Box-Ljung test

data:  newX[, i]
X-squared = 15.69, df = 10, p-value = 0.1089


$WMT

    Box-Ljung test

data:  newX[, i]
X-squared = 6.0142, df = 10, p-value = 0.8141


$XOM

    Box-Ljung test

data:  newX[, i]
X-squared = 8.3262, df = 10, p-value = 0.597
apply(abs(djall_m), 2, Box.test, lag = 10, type = "Ljung")
$AAPL

    Box-Ljung test

data:  newX[, i]
X-squared = 25.433, df = 10, p-value = 0.004582


$AXP

    Box-Ljung test

data:  newX[, i]
X-squared = 63.524, df = 10, p-value = 7.759e-10


$BA

    Box-Ljung test

data:  newX[, i]
X-squared = 30.285, df = 10, p-value = 0.0007693


$CAT

    Box-Ljung test

data:  newX[, i]
X-squared = 40.407, df = 10, p-value = 1.436e-05


$CSCO

    Box-Ljung test

data:  newX[, i]
X-squared = 14.867, df = 10, p-value = 0.137


$CVX

    Box-Ljung test

data:  newX[, i]
X-squared = 12.093, df = 10, p-value = 0.2789


$DD

    Box-Ljung test

data:  newX[, i]
X-squared = 21.997, df = 10, p-value = 0.01512


$DIS

    Box-Ljung test

data:  newX[, i]
X-squared = 19.021, df = 10, p-value = 0.03999


$GE

    Box-Ljung test

data:  newX[, i]
X-squared = 93.633, df = 10, p-value = 9.992e-16


$GS

    Box-Ljung test

data:  newX[, i]
X-squared = 27.807, df = 10, p-value = 0.001938


$HD

    Box-Ljung test

data:  newX[, i]
X-squared = 10.328, df = 10, p-value = 0.4122


$IBM

    Box-Ljung test

data:  newX[, i]
X-squared = 7.8389, df = 10, p-value = 0.6446


$INTC

    Box-Ljung test

data:  newX[, i]
X-squared = 4.981, df = 10, p-value = 0.8924


$JNJ

    Box-Ljung test

data:  newX[, i]
X-squared = 12.031, df = 10, p-value = 0.283


$JPM

    Box-Ljung test

data:  newX[, i]
X-squared = 50.321, df = 10, p-value = 2.329e-07


$KO

    Box-Ljung test

data:  newX[, i]
X-squared = 12.959, df = 10, p-value = 0.2259


$MCD

    Box-Ljung test

data:  newX[, i]
X-squared = 8.647, df = 10, p-value = 0.5659


$MMM

    Box-Ljung test

data:  newX[, i]
X-squared = 9.2386, df = 10, p-value = 0.5096


$MRK

    Box-Ljung test

data:  newX[, i]
X-squared = 22.105, df = 10, p-value = 0.01458


$MSFT

    Box-Ljung test

data:  newX[, i]
X-squared = 4.8293, df = 10, p-value = 0.9023


$NKE

    Box-Ljung test

data:  newX[, i]
X-squared = 6.8513, df = 10, p-value = 0.7394


$PFE

    Box-Ljung test

data:  newX[, i]
X-squared = 17.793, df = 10, p-value = 0.05855


$PG

    Box-Ljung test

data:  newX[, i]
X-squared = 19.134, df = 10, p-value = 0.03859


$TRV

    Box-Ljung test

data:  newX[, i]
X-squared = 6.0277, df = 10, p-value = 0.8129


$UNH

    Box-Ljung test

data:  newX[, i]
X-squared = 58.968, df = 10, p-value = 5.679e-09


$UTX

    Box-Ljung test

data:  newX[, i]
X-squared = 16.905, df = 10, p-value = 0.0765


$V

    Box-Ljung test

data:  newX[, i]
X-squared = 14.577, df = 10, p-value = 0.1483


$VZ

    Box-Ljung test

data:  newX[, i]
X-squared = 10.138, df = 10, p-value = 0.4285


$WMT

    Box-Ljung test

data:  newX[, i]
X-squared = 4.7833, df = 10, p-value = 0.9052


$XOM

    Box-Ljung test

data:  newX[, i]
X-squared = 10.339, df = 10, p-value = 0.4113

The amount of serial dependence appears to decrease when we move from daily to monthly returns.

3.4 Looking at the extremes in volatile return series

3.4.1 Extreme values in volatile time series

When you take a long series of iid data, such as several thousand observations, and select a small subset of the most extreme observations, like less than 100, then these extremes appear at random and the spaces or gaps between the extremes follow a distribution that is very close to exponential. When we carry out the same exercise for a volatile financial log-return series then the extremes appear in clusters during periods of high volatility. This is another feature of real log-return data that we need to take account of when building models.

You will investigate the irregular time series djx_extremes which contains the 100 most extreme negative log-returns of the Dow Jones index between 1985 and 2015. You will compare it with iid_extremes which contains the 100 most extreme values in an iid series of the same length as djx_extremes. To do this, you will use the object exp_quantiles, which contains 100 theoretical quantiles of the standard exponential distribution. These can be used to construct a Q-Q plot of each dataset against the exponential reference distribution.

set.seed(123)

#load data and get log returns
djreturns <- diff(log(DJ))[-1]

#get mean and sigma to generate normal distribution
npars <- c(mu = mean(djreturns), sigma = sd(djreturns))
n <- length(djreturns)

#calculate extreme losses
dj_losses <- -djreturns
djx_extremes <- dj_losses[dj_losses>0.0274]

#calculate extreme losses on iid dist
iid <- rnorm(n)*npars[2] + npars[1]
iid <- as.xts(iid, order.by = index(djreturns))
iid_losses <- -iid
iid_extremes <- iid_losses[iid_losses>0.02459]

#get 100 theroical quantiles of the standar exponential distribution
exp_quantiles <- qexp(ppoints(100))
# Partition plotting area into 3 pieces
par(mfrow = c(1, 3))

# Plot djx_extremes
plot(djx_extremes, type = "h")

# Compute the spaces between the times of the extremes
djx_spaces <- diff(time(djx_extremes))

# Make a histogram of these spaces
hist(as.numeric(djx_spaces))

# Make a Q-Q plot of djx_spaces against exp_quantiles
qqplot(exp_quantiles, djx_spaces)


# Carry out the previous 4 steps for iid_extremes
plot(iid_extremes, type = "h")
iid_spaces <- diff(time(iid_extremes))
hist(as.numeric(iid_spaces))
qqplot(exp_quantiles, iid_spaces)

Note how strongly clustered the extreme returns are compared with the extremes in the iid series.

3.4.2 Cross correlations between risk-factor return series

Many risk-factor returns are correlated with each other in the same time period. However, in the same way that there tends to be only weak serial correlation within series, there tends to be only weak cross correlation between series in different time periods.

The picture changes dramatically when we look at the absolute values, which are often strongly correlated both within and between series.

In this exercise, you will investigate cross correlations between the daily log-returns of the Dow Jones, FTSE100 and SMI equity indexes. When the function acf() is applied to a multivariate time series, we obtain a matrix of plots with the usual sample acf plots on the diagonal, and plots of the correlations between different series at different lags off the diagonal.

One thing to note here is that the US and European series are slightly out of step. The European markets tend to follow the US, so we see some evidence of cross correlation between US returns on one day and European returns on the next.

data("SMI")
data("FTSE")
smix <- diff(log(SMI))[-1]["2005/2015"]
ftsex <- diff(log(FTSE))[-1]["2005/2015"]
djx <- diff(log(DJ))[-1]["2005/2015"]
indexes <- merge(djx, ftsex, smix, all = TRUE)
indexes <- na.omit(indexes) 
# Make a time series plot of indexes with plot.zoo and a pairwise scatterplot with pairs
plot.zoo(indexes)

pairs(as.zoo(indexes))


# Calculate the sample correlation matrix of indexes
cor(indexes)
           X.DJI    X.FTSE    X.SSMI
X.DJI  1.0000000 0.5903534 0.5408565
X.FTSE 0.5903534 1.0000000 0.8226086
X.SSMI 0.5408565 0.8226086 1.0000000
# Plot the sample acfs and cross-correlation functions for the returns in indexes
acf(indexes)


# Plot the sample acfs and cross-correlations functions for the absolute values of indexes
acf(abs(indexes))

Do you see the evidence that the US market leads the European markets in the third of the four plots?

3.5 The stylized facts of return series

3.5.1 Volatility and correlation of FX returns

You will discover evidence of volatility and serial dependence in daily and weekly exchange-rate log-returns. The dataset fx contains daily log-returns for the “EUR_USD”, “GBP_USD”, “JPY_USD” and “CHF_USD” exchange rates while fx_w contains the corresponding weekly log-returns. Both are in your workspace.

Note that foreign exchange trading takes place every day of the week although the lower volume of trading at weekends leads to an unusual weekly correlation cycle which will be evident in one of the pictures you create.

data("CHF_USD")
fx1 <- diff(log(EUR_USD))[-1]["2011/2016"]
fx2 <- diff(log(GBP_USD))[-1]["2011/2016"]
fx3 <- diff(log(JPY_USD))[-1]["2011/2016"]
fx4 <- diff(log(CHF_USD))[-1]["2011/2016"]
fx <- merge(fx1, fx2, fx3, fx4, all = TRUE)
fx_w<- apply.weekly(fx, colSums)
# Plot fx and fx_w
plot.zoo(fx, type = "h")

plot.zoo(fx_w, type = "h")


# Make acf plots of fx and the absolute values of fx
acf(fx)

acf(abs(fx))



# Apply the Ljung-Box test to the components of fx and their absolute values
apply(fx, 2, Box.test, lag = 10, type = "Ljung")
$EUR.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 195.33, df = 10, p-value < 2.2e-16


$GBP.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 206.44, df = 10, p-value < 2.2e-16


$JPY.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 141.56, df = 10, p-value < 2.2e-16


$CHF.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 310.46, df = 10, p-value < 2.2e-16
apply(abs(fx), 2, Box.test, lag = 10, type = "Ljung")
$EUR.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 307.05, df = 10, p-value < 2.2e-16


$GBP.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 235.89, df = 10, p-value < 2.2e-16


$JPY.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 264.54, df = 10, p-value < 2.2e-16


$CHF.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 376.51, df = 10, p-value < 2.2e-16
# Make acf plots of fx_w and the absolute values of fx_w
acf(fx_w)

acf(abs(fx_w))



# Apply the Ljung-Box test to the components of fx_w and their absolute values
apply(fx_w, 2, Box.test, lag = 10, type = "Ljung")
$EUR.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 10.364, df = 10, p-value = 0.4091


$GBP.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 8.8896, df = 10, p-value = 0.5426


$JPY.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 7.7924, df = 10, p-value = 0.6491


$CHF.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 10.961, df = 10, p-value = 0.3605
apply(abs(fx_w), 2, Box.test, lag = 10, type = "Ljung")
$EUR.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 29.168, df = 10, p-value = 0.00117


$GBP.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 47.097, df = 10, p-value = 9.066e-07


$JPY.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 46.153, df = 10, p-value = 1.345e-06


$CHF.USD

    Box-Ljung test

data:  newX[, i]
X-squared = 34.449, df = 10, p-value = 0.000155

There is strong evidence of serial dependence in the absolute values of the weekly log-returns.

3.5.2 Volatility and correlation of interest-rate data

You will explore whether volatility and serial dependence is also a feature of daily and monthly interest-rate log-returns. The dataset zcb_x contains daily log-returns for the 1-year, 5-year and 10-year Canadian zero-coupon bond yields while zcbx_m contains the corresponding monthly log-returns.

# Make acf plots of zcb_x and the absolute values of zcb_x
acf(zcbx[-1])

acf(abs(zcbx[-1]))


# Apply the Ljung-Box test to the components of zcb_x and their absolute values
apply(zcbx, 2, Box.test, lag = 10, type = "Ljung")
$`1.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 34.333, df = 10, p-value = 0.0001622


$`5.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 17.186, df = 10, p-value = 0.07036


$`10.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 26.048, df = 10, p-value = 0.003676
apply(abs(zcbx), 2, Box.test, lag = 10, type = "Ljung")
$`1.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 2988.9, df = 10, p-value < 2.2e-16


$`5.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 5839.9, df = 10, p-value < 2.2e-16


$`10.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 3281.4, df = 10, p-value < 2.2e-16
# Make acf plots of zcbx_m and the absolute values of zcbx_m
acf(zcbx_m)

acf(abs(zcbx_m))



# Apply the Ljung-Box test to the components of zcbx_m and their absolute values
apply(zcbx_m, 2, Box.test, lag = 10, type = "Ljung")
$`1.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 8.3928, df = 10, p-value = 0.5905


$`5.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 5.4943, df = 10, p-value = 0.8558


$`10.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 4.246, df = 10, p-value = 0.9356
apply(abs(zcbx_m), 2, Box.test, lag = 10, type = "Ljung")
$`1.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 41.993, df = 10, p-value = 7.52e-06


$`5.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 8.993, df = 10, p-value = 0.5328


$`10.00y`

    Box-Ljung test

data:  newX[, i]
X-squared = 11.912, df = 10, p-value = 0.291

The monthly log-returns for the 5 and 10 year yields don’t appear to show much serial dependence.

4 Estimating portfolio value-at-risk

4.1 Value-at-risk and expected shortfall

4.1.1 Computing VaR and ES for normal distribution

The standard function qnorm() calculates quantiles of a normal distribution from the probability p, the mean, and standard deviation, and thus can be used to calculate value-at-risk (VaR). The function ESnorm() from the QRM package calculates the expected shortfall (ES) for a normal distribution from the probability p, location parameter mu, and scale parameter sd: qnorm(p, mean = 0, sd = 1) ESnorm(p, mu = 0, sd = 1)

Common numeric values for p include 0.95 and 0.99 for confidence levels of 95% and 99%, respectively. you will compute and display VaR and ES for a normal distribution N(μ,σ2) with mean μ and standard deviation σ. In the process, you will use the new functions for sequence generation and adding straight lines to a plot. You can read about their arguments by typing in ?seq and ?abline to your console.

The variables mu and sigma contain the estimated mean and standard deviation of the Dow Jones index returns for 2008-2009 contained in djx.

djx <- diff(log(dj))[-1,]["2008/2009"]
sigma <- sd(djx)
mu <- mean(djx)
# Make a sequence of 100 x-values going from -4*sigma to 4*sigma
xvals <- seq(from = -4*sigma, to = 4*sigma, length.out = 100)

# Compute the density of a N(mu, sigma^2) distribution at xvals
ndens <- dnorm(xvals, mean = mu, sd = sigma)

# Plot ndens against xvals
plot(xvals, ndens, type = "l")

# Compute the 99% VaR and 99% ES of a N(mu, sigma^2) distribution
VaR99 <- qnorm(0.99, mean = mu, sd = sigma)
VaR99
[1] 0.04612495
ES99 <- ESnorm(0.99, mu = mu, sd = sigma)
ES99
[1] 0.05290841
# Draw vertical lines at VaR99 and ES99 in red and green
abline(v = VaR99, col = "red")
abline(v = ES99, col = "green")

– ES99 is only 14.7% bigger than VaR99. For heavy-tailed distributions, the difference can be much greater.

4.2 International equity portfolio

4.2.1 Examining risk factors for international equity portfolio

The UK investor in UK, US, and Swiss equities is exposed to 5 risk factors; the data is contained in riskfactors, a multivariate dataset.

In this exercise, you will recall some of the tests and techniques that you learned earlier for showing that these risk factors are heavier tailed than normal, highly volatile and subject to profound serial dependencies.

data("USD_GBP")
data("CHF_GBP")
X.FTSE <- FTSE["2000/2012"]
X.GSPC <- SP500["2000/2012"]
X.SSMI <- SMI["2000/2012"]
USD.GBP <- USD_GBP["2000/2012"]
CHF.GBP <- CHF_GBP["2000/2012"]
riskfactors <- merge(X.FTSE,  X.GSPC, X.SSMI, USD.GBP, CHF.GBP , all = TRUE)
riskfactors <- na.omit(riskfactors)
# Plot the risk-factor data
plot.zoo(riskfactors)


# Calculate the log-returns, assign to returns, and plot
returns <- diff(log(riskfactors))[-1, ]
plot.zoo(returns)


# Use apply() to carry out the Jarque-Bera test for all 5 series
apply(returns, 2, jarque.test)
$X.FTSE

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 4209.4, p-value < 2.2e-16
alternative hypothesis: greater


$X.GSPC

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 6961.6, p-value < 2.2e-16
alternative hypothesis: greater


$X.SSMI

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 5158.1, p-value < 2.2e-16
alternative hypothesis: greater


$USD.GBP

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 2586.4, p-value < 2.2e-16
alternative hypothesis: greater


$CHF.GBP

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 7759.2, p-value < 2.2e-16
alternative hypothesis: greater
# Make a Q-Q plot against normal for the 5th return series and add a reference line
qqnorm(returns[, 5])
qqline(returns[, 5])


# Make a picture of the sample acfs for returns and their absolute values
acf(returns)

acf(abs(returns))

All five risk factors are clearly non-normal and show strong serial and cross dependencies.

4.2.2 Historical simulation

Suppose that a UK investor has invested 30% of her wealth in the FTSE index, 40% in the S&P 500 index, and 30% in the SMI index.

For different vectors of log-returns for the 5 risk factors, the function lossop() computes the loss or gain incurred by the investor when her total wealth is 1. The function can also be applied to a 5-dimensional time series of log-returns to obtain a time series of historically-simulated losses and gains corresponding to each vector of log-returns in the time series.

The function lossop() is the so-called loss operator for the portfolio and has been specially written for this exercise. In general, for each new portfolio, a specific function has to be written to compute portfolio losses and gains.

In this exercise, you will form historically simulated losses and examine them. This is a necessary prelude to using these data to estimate VaR and ES.

lossop <- function (xseries, wts = c(0.3, 0.4, 0.3)){
    if (is.xts(xseries)) 
        x <- coredata(xseries)
    else if (is.matrix(xseries)) 
        x <- xseries
    else x <- matrix(xseries, nrow = 1)
    ll <- apply(x, 1, function(x, wts) {
        1 - (wts[1] * exp(x[1]) + wts[2] * exp(x[2] + x[4]) + 
            wts[3] * exp(x[3] + x[5]))
    }, wts = wts)
    if (is.xts(xseries)) 
        ll <- xts(ll, time(xseries))
    ll
}
# Calculate the loss from a log-return of -0.1 for all risk factors
lossop(rep(-0.1, 5))
[1] 0.1554372
# Apply lossop() to returns and plot hslosses
hslosses <- lossop(returns)
plot(hslosses)


# Form a Q-Q plot of hslosses against normal
qqnorm(hslosses)


# Plot the sample acf of hslosses and their absolute values
acf(hslosses)

acf(abs(hslosses))

Note how the features of the underlying risk-factor returns (heavy tails and serial dependence) are present in the historically simulated losses.

4.2.3 Estimating VaR and ES

Now you are ready to estimate VaR and ES for the international equity investor using the historically simulated losses and gains in hslosses.

You will do this by two methods. First, you will apply a simple non-parametric method using a sample quantile to estimate VaR and the average of values exceeding the sample quantile to estimate ES.

Then, you will compare these estimates with the values obtained when you assume that the hslosses have a normal distribution. Obviously, this is a very bad assumption and you should compare the two sets of estimates to see which are more conservative.

# Estimate the 99th sample percentile of the distribution of hslosses
quantile(hslosses, 0.99)
       99% 
0.03076173 
# Estimate the 99% ES
mean(hslosses[hslosses >= quantile(hslosses, 0.99)])
[1] 0.04184655
# Estimate the mean and standard deviation of hslosses
mu <- mean(hslosses)
sigma <- sd(hslosses)

# Compute the 99% quantile of a normal distribution
qnorm(0.99, mean = mu, sd = sigma)
[1] 0.02602973
# Compute the 99% ES of a normal distribution
ESnorm(0.99, mu = mu, sd = sigma)
[1] 0.02983979

This is what we expected. The estimates derived from a normal assumption are much less conservative than the estimates derived using the non-parametric method. That is not to say that the latter method is the best possible, but it is a reasonable first attempt to estimate the risk measures.

4.3 Option portfolio and Black Scholes

4.3.1 Compute Black-Scholes price of an option

The Black_Scholes() function in the package qrmtools can be used to price European call and put options using the standard Black-Scholes options pricing formula for a non-dividend-paying stock.

In this exercise you will price in succession: an out-of-the-money European call, an in-the-money European call, an in-the-money European put and an out-of-the-money European put. An option is in-the-money if immediate exercise would result in a positive payout and out-of-the-money if it would not.

The main point of the exercise is to understand the different risk factors that go into the price calculation: the current stock price, the current volatility and the current interest rate.

# Set the interest rate r to be 0.01, the volatility sigma to be 0.2 and the strike K to be 100
r <- 0.01
sigma <- 0.2
K <- 100


library(qrmtools)
package 㤼㸱qrmtools㤼㸲 was built under R version 4.0.3Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 

Attaching package: 㤼㸱qrmtools㤼㸲

The following objects are masked from 㤼㸱package:QRM㤼㸲:

    dGEV, dGPD, pGEV, pGPD, qGEV, qGPD, rGEV, rGPD

The following object is masked from 㤼㸱package:timeSeries㤼㸲:

    returns
# Look at the arguments of the Black_Scholes function
args(Black_Scholes)
function (t, S, r, sigma, K, T, type = c("call", "put")) 
NULL
# Price a European call option that matures in one year if the current stock price is 80
Black_Scholes(0, 80, r, sigma, K, 1, "call")
[1] 1.302245
# Price a European call option that matures in one year if the current stock price is 120
Black_Scholes(0, 120, r, sigma, K, 1, "call")
[1] 22.94188
# Price a European put option that matures in one year if the current stock price is 80
Black_Scholes(0, 80, r, sigma, K, 1,"put")
[1] 20.30723
# Price a European put option that matures in one year if the current stock price is 120
Black_Scholes(0, 120, r, sigma, K, 1,"put")
[1] 1.94686

Did you see how dramatically the option values changed as the stock price moved from out-of-the-money to in-the-money or vice versa?

4.3.2 Equity and implied volatility risk factors

To analyze the risk of a portfolio consisting of an option, it is necessary to consider changes in all three risk factors: stock price, volatility and interest rates. Here, you will focus on the first two of these risk factors and assume that interest rates do not change much over short time intervals. The daily risk-factor values for the period 1990-2010 are contained in riskfactors and the corresponding log-returns in returns; both multivariate datasets are loaded in your workspace.

Volatility is a new risk factor that hasn’t been considered so far in this course. It is represented by the VIX index which is constructed from the implied volatilities of a wide range of options on the S&P 500 index:

data("VIX")
X.GSPC <- SP500["1990/2010"]
X.VIX <- VIX["1990/2010"]
riskfactors <- merge(X.GSPC, X.VIX, all = TRUE)
riskfactors <- na.omit(riskfactors)
returns <- diff(log(riskfactors))[-1, ]
names(returns)
[1] "X.GSPC" "X.VIX" 

You will be able to verify whether the log-returns of volatility behave like other return data you have encountered, and to see how they vary with the log-returns of the S&P 500 index.

# Plot the risk factors and the log-returns
plot.zoo(riskfactors)

plot.zoo(returns)


# Make a scatterplot of the two return series
plot(as.matrix(returns))


# Apply the Jarque-Bera test to the returns and make a Q-Q plot of the volatility log-returns
apply(returns, 2, jarque.test)
$X.GSPC

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 17397, p-value < 2.2e-16
alternative hypothesis: greater


$X.VIX

    Jarque-Bera Normality Test

data:  newX[, i]
JB = 4412.6, p-value < 2.2e-16
alternative hypothesis: greater
qqnorm(returns[, 2])


# Create the sample acf of the returns and absolute returns
acf(returns)

acf(abs(returns))


# Calculate the correlation between the log-returns
cor(returns)
           X.GSPC      X.VIX
X.GSPC  1.0000000 -0.6978308
X.VIX  -0.6978308  1.0000000

It is clear that the log-returns of the VIX index show the same stylized facts as other returns that you have analyzed - non-normality, heavy tails, volatility, serial dependence in the absolute values but not the raw values. Moreover, they are negatively correlated with the log-returns of the SP500 index

4.4 Historical simulation for the option example

4.4.1 Historical simulation of losses for option portfolio

Suppose that an investor has invested one unit of wealth in a single European call option on the S&P 500 index. The function lossop() computes the loss or gain incurred by the investor over a one-day time horizon due to changes in the log stock price or changes in the log volatility. As before, this function has been written specially for the particular portfolio in this exercise: lossop(xseries, S, sigma) The first argument contains the log returns corresponding to the stock price and volatility risk factors, either in a series or in form c(stock_risk, volatility_risk), S is the current stock price, and sigma is the current volatility.

Changes in the interest rate over the time horizon will be neglected as being of lesser importance.

In this exercise, you will form the historically simulated losses for the option portfolio and examine their properties before estimating VaR and ES in the next exercise. The interest rate, strike price, and maturity have been set to r = 0.01, K = 100 and T = 1, respectively.

lossop <- function (xseries, r = 0.01, K = 100, T = 1, sigma = 0.2, S = 100){
    if (is.xts(xseries)) 
        x <- coredata(xseries)
    else if (is.matrix(xseries)) 
        x <- xseries
    else x <- matrix(xseries, nrow = 1)
    ll <- apply(x, 1, function(x, r, K, T, sigma, S) {
        deltat <- 1/250
        V_t0 <- Black_Scholes(0, S, r, sigma, K, T, "call")
        V_t1 = Black_Scholes(deltat, exp(log(S) + x[1]), r, exp(log(sigma) + 
            x[2]), K, T, "call")
        -(V_t1 - V_t0)/V_t0
    }, r = r, K = K, T = T, sigma = sigma, S = S)
    if (is.xts(xseries)) 
        ll <- xts(ll, time(xseries))
    ll
}
# Calculate the first loss
lossop(c(-0.1, -0.1), S = 80, sigma = 0.2)
[1] 0.8030928
# Calculate the second loss
lossop(c(-0.1, 0.1), S = 100, sigma = 0.2)
[1] 0.4380754
# Create and plot hslosses
hslosses <- lossop(returns, S = 100, sigma = 0.2)
plot(hslosses)


# Form a Q-Q plot of hslosses against normal
qqnorm(hslosses)


# Plot the sample acf of raw data and absolute values in hslosses
acf(hslosses)

acf(abs(hslosses))

4.4.2 Estimating VaR and ES for option portfolio

Now you are ready to estimate VaR and ES for the investor in the European call option using the historically simulated losses and gains in hslosses.

Once again, you will do this by two methods. First, you will apply a non-parametric method using a sample quantile to estimate VaR and calculate the average of values exceeding the same quantile to estimate ES.

Then, you will compare these estimates with the values obtained when you assume that the hslosses have a normal distribution. Like in the previous exercise, this is a bad assumption and you should compare the two sets of estimates to see which are more conservative.

# Estimate the 99.5% percentile of the distribution
quantile(hslosses, 0.995)
    99.5% 
0.1618376 
# Estimate the 99.5% ES
mean(hslosses[hslosses >= quantile(hslosses, 0.995)])
[1] 0.2211743
# Estimate the mean and standard deviation of hslosses
mu <- mean(hslosses)
sigma <- sd(hslosses)

# Compute the 99.5% quantile of a normal distribution
qnorm(0.995, mean = mu, sd = sigma)
[1] 0.1441452
# Compute the 99.5% ES of a normal distribution
ESnorm(0.995, mu = mu, sd = sigma)
[1] 0.1622111

It will be no surprise to you now that the normal distribution greatly underestimates these measures of risk.

4.4.3 Computing VaR for weekly losses

In this final exercise, you will test your understanding by computing an empirical estimate of VaR for weekly losses in the returns data. You will have to repeat the analysis of the previous exercise, but this time, you need to:

Find the weekly log-returns of returns using apply.weekly(). Use these weekly log-returns to simulate the losses of the two risk factors through lossop(). Note that the lossop() function has been adjusted in your workspace so that it correctly calculates the losses and gains of the option portfolio for a one-week time horizon. It still takes in arguments as follows:

lossop(xseries, S, sigma)

lossop <- function (xseries, r = 0.01, K = 100, T = 1, sigma = 0.2, S = 100){
    if (is.xts(xseries)) 
        x <- coredata(xseries)
    else if (is.matrix(xseries)) 
        x <- xseries
    else x <- matrix(xseries, nrow = 1)
    ll <- apply(x, 1, function(x, r, K, T, sigma, S) {
        deltat <- 5/250
        V_t0 <- Black_Scholes(0, S, r, sigma, K, T, "call")
        V_t1 = Black_Scholes(deltat, exp(log(S) + x[1]), r, exp(log(sigma) + 
            x[2]), K, T, "call")
        -(V_t1 - V_t0)/V_t0
    }, r = r, K = K, T = T, sigma = sigma, S = S)
    if (is.xts(xseries)) 
        ll <- xts(ll, time(xseries))
    ll
}

Your challenge is to compute the 99% VaR for weekly changes in value of the European call option in returns when the current stock price is S = 120 and the current volatility is sigma = 0.25.

return_w <- apply.weekly(returns, colSums)
hslosses <- lossop(return_w, S = 120, sigma = 0.25)
quantile(hslosses, 0.995)
    99.5% 
0.2402091 
LS0tDQp0aXRsZTogIlF1YW50aXRhdGl2ZSBSaXNrIE1hbmFnZW1lbnQgaW4gUiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIA0KdG9jX2RlcHRoOiAzDQotLS0NCiMgRXhwbG9yaW5nIG1hcmtldCByaXNrLWZhY3RvciBkYXRhDQoNCmh0dHBzOi8vd3d3LnFybXR1dG9yaWFsLm9yZy8NCg0KIyMgSW50cm9kdWN0aW9uDQoNCiMjIyBFeHBsb3Jpbmcgcmlzay1mYWN0b3IgdGltZSBzZXJpZXM6IGVxdWl0eSBpbmRleGVzDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGxvb2sgYXQgYW4gZXF1aXR5IGluZGV4IGFuZCBwbG90IGl0IGZvciBhIHBhcnRpY3VsYXIgcmFuZ2Ugb2YgZGF0ZXMuIFRoZSBkYXRhIHVzZWQgaW4gdGhpcyBleGVyY2lzZSBhbmQgaW4gdGhlIHJlc3Qgb2YgdGhlIGNvdXJzZSBhcmUgY29udGFpbmVkIGluIHRoZSBwYWNrYWdlIHFybWRhdGEuIFlvdSBhbHNvIG5lZWQgdGhlIHBhY2thZ2UgeHRzIHRvIG1hbmlwdWxhdGUgdGltZSBzZXJpZXMuDQoNCldoZW4gdGhlIHFybWRhdGEgbGlicmFyeSBpcyBhdHRhY2hlZCwgYXMgaXQgd2lsbCBiZSB0aHJvdWdob3V0IHRoZSBjb3Vyc2UsIHlvdSBjYW4gbG9hZCBhIGRhdGFzZXQgd2l0aCB0aGUgZGF0YSgpIGNvbW1hbmQuIEZvciBleGFtcGxlLCB0aGUgY29tbWFuZCBkYXRhKCJGVFNFIikgbG9hZHMgdGhlIFVLIEZUU0UgKEZpbmFuY2lhbCBUaW1lcyBTdG9jayBFeGNoYW5nZSkgaW5kZXgsIHdoaWNoIHlvdSBjYW4gdGhlbiByZWZlciB0byBhcyBvYmplY3QgRlRTRS4NCg0KSWYgeW91IHdhbnQgdG8gZXh0cmFjdCB0aGUgZGF0YSBmcm9tIGEgY2VydGFpbiBkYXRlIHJhbmdlLCBmb3IgZXhhbXBsZSBmcm9tIEFwcmlsIDEgdG8gSnVuZSAzMCwgMjAwMCwgeW91IGNhbiBjcmVhdGUgYSBuZXcgb2JqZWN0IHVzaW5nIHRoZSBjb21tYW5kIGZ0c2UwMCA8LSBGVFNFWyIyMDAwLTA0LTAxLzIwMDAtMDYtMzAiXS4NCmBgYHtyfQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KHh0cykNCmxpYnJhcnkocXJtZGF0YSkNCmBgYA0KYGBge3J9DQojIExvYWQgREogaW5kZXgNCmRhdGEoIkRKIikNCg0KIyBTaG93IGhlYWQoKSBhbmQgdGFpbCgpIG9mIERKIGluZGV4DQpoZWFkKERKKQ0KdGFpbChESikNCg0KIyBQbG90IERKIGluZGV4DQpwbG90KERKKQ0KDQojIEV4dHJhY3QgMjAwOC0yMDA5IGFuZCBhc3NpZ24gdG8gZGowODA5DQpkajA4MDkgPC0gREpbIjIwMDgtMDEtMDEvMjAwOS0xMi0zMSJdDQoNCiMgUGxvdCBkajA4MDkNCnBsb3QoZGowODA5KQ0KYGBgDQpUYWtlIGEgZ29vZCBsb29rIGF0IGhvdyBpdCBiZWhhdmVzIGFuZCBub3RlIGhvdyBmYXIgdGhlIGluZGV4IGZlbGwgaW4gdGhlIDIwMDgtMjAwOSBmaW5hbmNpYWwgY3Jpc2lzLg0KDQojIyMgRXhwbG9yaW5nIHJpc2stZmFjdG9yIHRpbWUgc2VyaWVzOiBpbmRpdmlkdWFsIGVxdWl0aWVzDQoNCkZvciBzb21lIHJpc2sgbWFuYWdlbWVudCBhcHBsaWNhdGlvbnMsIGl0IGlzIHN1ZmZpY2llbnQgdG8gbW9kZWwgZXF1aXR5IHJpc2sgYnkgbG9va2luZyBhdCBpbmRleGVzLiBJZiB5b3Ugd2FudCBhIG1vcmUgZGV0YWlsZWQgbW9kZWwgb2YgdGhlIHJpc2sgaW4gYSBwb3J0Zm9saW8gb2YgZXF1aXRpZXMsIHlvdSBjYW4gZHJpbGwgZG93biB0byB0aGUgbGV2ZWwgb2YgaW5kaXZpZHVhbCBzaGFyZSBwcmljZXMuDQoNCkluIHRoZSBwcmV2aW91cyBjaGFwdGVyLCB5b3UgdXNlZCBESlsiMjAwOC8yMDA5Il0gdG8gZXh0cmFjdCB0aGUgRG93IEpvbmVzIGRhdGEgZnJvbSBjZXJ0YWluIHJvd3Mgb2YgYW4geHRzIG9iamVjdCBieSBzcGVjaWZ5aW5nIGEgZGF0ZSByYW5nZSBpbmRleC4gVG8gYWxzbyBleHRyYWN0IGRhdGEgZnJvbSBwYXJ0aWN1bGFyIGNvbHVtbnMsIHlvdSBjYW4gYWRkIGEgY29sdW1uIGlkZW50aWZpZXIsIGxpa2UgYSBzdHJpbmcgbmFtZSBvciBudW1lcmljIGluZGV4LCBpbiB0aGUgYnJhY2tldHMgZm9sbG93aW5nIGEgY29tbWEuIFRvIHNlbGVjdCBtdWx0aXBsZSBjb2x1bW5zLCBpbmNsdWRlIHRoZXNlIGNvbHVtbiBpZGVudGlmaWVycyBpbiBhIHZlY3Rvci4gVGhpcyBbcm93cywgY29sdW1uc10gZm9ybWF0IGlzIGNvbnNpc3RlbnQgd2l0aCBpbmRleGluZyBtb3N0IG90aGVyIHR3byBkaW1lbnNpb25hbCBvYmplY3RzIGluIFIuDQoNCiAgICBkYXRhW2luZGV4LCBjb2xuYW1lXQ0KICAgIGRhdGFbaW5kZXgsIGMoY29sMWluZGV4LCBjb2wyaW5kZXgpXQ0KDQpUaGUgcXJtZGF0YSBwYWNrYWdlIGFsc28gaW5jbHVkZXMgZGF0YSBmb3IgY2VydGFpbiBjb25zdGl0dWVudHMsIG9yIHRoZSBzdG9ja3Mgb3IgY29tcGFuaWVzIHBhcnQgb2YgYSBsYXJnZXIgaW5kZXguIFRoZSBEb3cgSm9uZXMgY29uc3RpdHVlbnRzIGRhdGEgYXJlIGNvbnRhaW5lZCBpbiAiREpfY29uc3QiLiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCB2aWV3IHRoZSBuYW1lcyBvZiBhbGwgaXRzIHN0b2Nrcywgc2VsZWN0IHRoZSBBcHBsZSBhbmQgR29sZG1hbiBTYWNocyBzaGFyZSBwcmljZXMsIGFuZCBwbG90IHRoZW0gdXNpbmcgdGhlIGNvbW1hbmQgcGxvdC56b28oKSB0byBkaXNwbGF5IG11bHRpcGxlIHRpbWUgc2VyaWVzLg0KYGBge3J9DQojIExvYWQgREogY29uc3RpdHVlbnRzIGRhdGENCmRhdGEoIkRKX2NvbnN0IikNCg0KIyBBcHBseSBuYW1lcygpIGFuZCBoZWFkKCkgdG8gREpfY29uc3QNCm5hbWVzKERKX2NvbnN0KQ0KaGVhZChESl9jb25zdCkNCg0KIyBFeHRyYWN0IEFBUEwgYW5kIEdTIGluIDIwMDgtMDkgYW5kIGFzc2lnbiB0byBzdG9ja3MNCnN0b2NrcyA8LSBESl9jb25zdFsiMjAwOC8yMDA5IiwgYygiQUFQTCIsICJHUyIpXQ0KDQojIFBsb3Qgc3RvY2tzIHdpdGggcGxvdC56b28oKQ0KcGxvdC56b28oc3RvY2tzKQ0KYGBgDQojIyMgRXhwbG9yaW5nIHJpc2stZmFjdG9yIGRhdGE6IGV4Y2hhbmdlIHJhdGVzDQoNCkZvciBhIHBvcnRmb2xpbyB3aXRoIHJpc2sgZXhwb3N1cmUgaW4gZGlmZmVyZW50IGNvdW50cmllcywgaXQgaXMgbmVjZXNzYXJ5IHRvIGNvbnNpZGVyIHRoZSByaXNrIGNvbWluZyBmcm9tIGZvcmVpZ24gZXhjaGFuZ2UgKEZYKSByYXRlcy4gVGhlIHFybWRhdGEgcGFja2FnZSBpbmNsdWRlcyBGWCByYXRlIGRhdGEgZm9yIG1hbnkgY3VycmVuY2llcywgcmFuZ2luZyBmcm9tIFN3aXNzIEZyYW5jcyB0byBKYXBhbmVzZSBZZW4sIHdpdGggcmVzcGVjdCB0byB0aGUgVVNEIChVbml0ZWQgU3RhdGVzIGRvbGxhcikgYW5kIEdCUCAoR3JlYXQgQnJpdGFpbiBwb3VuZCkuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGxvb2sgYXQgdGhlIGRhdGFzZXRzICJFVVJfVVNEIiBhbmQgIkdCUF9VU0QiLCB3aGljaCBjb250YWluIHRoZSBFdXJvIGFuZCBCcml0aXNoIHBvdW5kIGV4Y2hhbmdlIHJhdGVzIGFnYWluc3QgdGhlIFVTIGRvbGxhci4gVGhlbiwgeW91IHdpbGwgbWVyZ2UgdGhlc2UgdGltZSBzZXJpZXMgYW5kIHBsb3QgdGhlbSB0b2dldGhlciBmb3IgdGhlIHBlcmlvZCAyMDEwLTIwMTUuDQpgYGB7cn0NCiMgTG9hZCBleGNoYW5nZSByYXRlIGRhdGENCmRhdGEoIkdCUF9VU0QiKQ0KZGF0YSgiRVVSX1VTRCIpDQoNCiMgUGxvdCB0aGUgdHdvIGV4Y2hhbmdlIHJhdGVzDQpwbG90KEdCUF9VU0QpDQpwbG90KEVVUl9VU0QpDQoNCiMgUGxvdCBhIFVTRF9HQlAgZXhjaGFuZ2UgcmF0ZQ0KcGxvdCgxL0dCUF9VU0QpDQoNCiMgTWVyZ2UgdGhlIHR3byBleGNoYW5nZSByYXRlcyBHQlBfVVNEIGFuZCBFVVJfVVNEDQpmeCA8LSBtZXJnZShHQlBfVVNELCBFVVJfVVNELCBhbGwgPSBUUlVFKQ0KDQojIEV4dHJhY3QgMjAxMC0xNSBkYXRhIGZyb20gZnggYW5kIGFzc2lnbiB0byBmeDAwMTUNCmZ4MDAxNSA8LSBmeFsiMjAxMC8yMDE1Il0NCg0KIyBQbG90IHRoZSBleGNoYW5nZSByYXRlcyBpbiBmeDAwMTUNCnBsb3Quem9vKGZ4MDAxNSkNCmBgYA0KTm90ZSB0aGF0IG1lcmdpbmcgdGhlIEVVUl9VU0QgYW5kIEdCUF9VU0QgZGF0YSwgaW4gdGhhdCBvcmRlciwgd291bGQgaGF2ZSBwcm9kdWNlZCBhIGRpZmZlcmVudCBvYmplY3QgZnJvbSBmeC4NCg0KIyMgUmlzay1mYWN0b3IgcmV0dXJucw0KDQojIyMgRXhwbG9yaW5nIHJldHVybiBzZXJpZXMNCg0KVG8gYW5hbHl6ZSByaXNrLCB0aGUga2V5IHRhc2sgaXMgdG8gbW9kZWwgdGhlIGZsdWN0dWF0aW9ucyBpbiBwcmljZXMgYW5kIHJhdGVzIG92ZXIgZGlmZmVyZW50IHRpbWUgcGVyaW9kczsgdGhlc2UgZmx1Y3R1YXRpb25zIGFyZSBrbm93biBhcyByZXR1cm5zLiBUbyBjYWxjdWxhdGUgdGhlIGxvZy1yZXR1cm5zIG9mIHRoZSBGVFNFIHN0b2NrIGluZGV4IGFuZCBhc3NpZ24gdG8gZnRzZV94LCBhcHBseSB0aGUgbG9nKCkgYW5kIGRpZmYoKSBmdW5jdGlvbnMgaW4gc3VjY2Vzc2lvbjoNCg0KICAgIGZ0c2VfeCA8LSBkaWZmKGxvZyhGVFNFKSkNCg0KZGlmZmVyZW5jaW5nIGluIHRoaXMgd2F5IHdpbGwgYWx3YXlzIGdpdmUgYSBOQSBpbiB0aGUgZmlyc3QgcG9zaXRpb24gb2YgdGhlIHRpbWUgc2VyaWVzLCB3aGljaCBjYW4gdGhlbiBiZSByZW1vdmVkIHdpdGggZGlmZihsb2coRlRTRSkpWy0xXS4gSG93ZXZlciwgeW91IHdpbGwgbm90IG5lZWQgdG8gZG8gdGhpcyBpbiB0aGUgY291cnNlIHVubGVzcyBpdCBpcyBzcGVjaWZpZWQgaW4gdGhlIGluc3RydWN0aW9ucy4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgY2FsY3VsYXRlIGFuZCBwbG90IGxvZy1yZXR1cm4gc2VyaWVzIGZvciB0aGUgZXF1aXR5IGFuZCBGWCByaXNrIGZhY3RvcnMgdGhhdCB5b3UgaGF2ZSBwcmV2aW91c2x5IGVuY291bnRlcmVkLg0KYGBge3J9DQojIENvbXB1dGUgdGhlIGxvZy1yZXR1cm5zIG9mIGRqMDgwOSBhbmQgYXNzaWduIHRvIGRqMDgwOV94DQpkajA4MDlfeCA8LSBkaWZmKGxvZyhkajA4MDkpKQ0KDQojIFBsb3QgdGhlIGxvZy1yZXR1cm5zDQpwbG90KGRqMDgwOV94KQ0KDQojIENvbXB1dGUgdGhlIGxvZy1yZXR1cm5zIG9mIGRqc3RvY2tzIGFuZCBhc3NpZ24gdG8gZGpzdG9ja3NfeA0KZGpzdG9ja3MgPC0gREpfY29uc3RbIjIwMDgvMjAwOSIsIGMoIkFBUEwiLCAiR1MiKV0NCmRqc3RvY2tzX3ggPC0gZGlmZihsb2coZGpzdG9ja3MpKQ0KDQojIFBsb3QgdGhlIHR3byBzaGFyZSByZXR1cm5zDQpwbG90LnpvbyhkanN0b2Nrc194KQ0KDQojIENvbXB1dGUgdGhlIGxvZy1yZXR1cm5zIG9mIEdCUF9VU0QgYW5kIGFzc2lnbiB0byBlcmF0ZV94DQplcmF0ZV94IDwtIGRpZmYobG9nKEdCUF9VU0QpKQ0KDQojIFBsb3QgdGhlIGxvZy1yZXR1cm5zDQpwbG90KGVyYXRlX3gpDQpgYGANClRoZSByZXR1cm4gc2VyaWVzIG9mdGVuIGp1c3QgbG9vayBsaWtlIG5vaXNlIHdpdGggc29tZSBwZXJpb2RzIG9mIGxhcmdlciBmbHVjdHVhdGlvbnMuIFlvdSdsbCBkaXNjb3ZlciBsYXRlciB0aGF0IHRoZXkgdHlwaWNhbGx5IGhhdmUgYSBsb3Qgb2YgaW50ZXJlc3Rpbmcgc3RydWN0dXJlLg0KDQojIyMgRGlmZmVyZW50IHdheXMgb2YgcGxvdHRpbmcgcmlzay1mYWN0b3IgYW5kIHJldHVybiBzZXJpZXMNCg0KWW91IGFscmVhZHkga25vdyB0aGF0IHlvdSBjYW4gdXNlIHBsb3Quem9vKCkgdG8gcGxvdCBtdWx0aXBsZSB0aW1lIHNlcmllcy4gRm9yIGEgZm91ci1kaW1lbnNpb25hbCB0aW1lIHNlcmllcyBkYXRhLCB0aGUgY2FsbCBwbG90LnpvbyhkYXRhKSBjcmVhdGVzIGZvdXIgc2VwYXJhdGUgcGxvdHMgYnkgZGVmYXVsdCwgdW5sZXNzIHlvdSBpbmNsdWRlIHRoZSBwYXJhbWV0ZXIgcGxvdC50eXBlID0gInNpbmdsZSIgdG8gcGxvdCBhbGwgZm91ciBzZXJpZXMgaW4gb25lIHBsb3QuIFlvdSBjYW4gYWxzbyBhZGQgZXZlbiBtb3JlIHBhcmFtZXRlcnMgc3VjaCBhcyBjb2wgdG8gc3BlY2lmeSBkaWZmZXJlbnQgY29sb3JzIGFuZCB0eXBlID0gImgiIHRvIGdldCB2ZXJ0aWNhbCBiYXJzIGluc3RlYWQgb2Ygam9pbmluZyBwb2ludHMsIHdoaWNoIGNhbiBzb21ldGltZXMgYmUgYSBiZXR0ZXIgd2F5IG9mIGRpc3BsYXlpbmcgcmV0dXJucy4NCg0KICAgIHBsb3Quem9vKHgsIHBsb3QudHlwZSwgY29sID0gMSwgdHlwZSA9ICJsIiwgLi4uKQ0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBleHBsb3JlIHRoZSBwbG90LnpvbygpIGZ1bmN0aW9uIHRvIHBsb3QgZXF1aXR5IHJpc2stZmFjdG9yIGRhdGEgYW5kIHRoZSBjb3JyZXNwb25kaW5nIHJldHVybnMgaW4gZGlmZmVyZW50IHdheXMuDQpgYGB7cn0NCmRqc3RvY2tzIDwtIERKX2NvbnN0WyIyMDA4LzIwMDkiLCBjKCJBQVBMIiwgIkFYUCIsICJCQSIsICJDQVQiKV0NCiMgUGxvdCBkanN0b2NrcyBpbiBmb3VyIHNlcGFyYXRlIHBsb3RzDQpwbG90LnpvbyhkanN0b2NrcykNCg0KIyBQbG90IGRqc3RvY2tzIGluIG9uZSBwbG90IGFuZCBhZGQgbGVnZW5kDQpwbG90LnpvbyhkanN0b2NrcywgcGxvdC50eXBlID0gInNpbmdsZSIsIGNvbCA9IGMoMTo0KSkNCmxlZ2VuZChqdWxpYW4oeCA9IGFzLkRhdGUoIjIwMDktMDEtMDEiKSksIHkgPSA3MCwgbGVnZW5kID0gbmFtZXMoREpfY29uc3QpWzE6NF0sIGZpbGwgPSAxOjQpDQoNCiMgQ29tcHV0ZSBsb2ctcmV0dXJucyBhbmQgYXNzaWduIHRvIGRqc3RvY2tzX3gNCmRqc3RvY2tzX3ggPC0gZGlmZihsb2coZGpzdG9ja3MpKQ0KDQojIFBsb3QgZGpzdG9ja3NfeCBpbiBmb3VyIHNlcGFyYXRlIHBsb3RzDQpwbG90LnpvbyhkanN0b2Nrc194KQ0KDQojIFBsb3QgZGpzdG9ja3NfeCB3aXRoIHZlcnRpY2FsIGJhcnMNCnBsb3Quem9vKGRqc3RvY2tzX3gsIHR5cGUgPSAiaCIpDQpgYGANCk5vdGUgaG93IGluIGxhdGUgMjAwOCB0aGVyZSB3ZXJlIGxhcmdlIHJldHVybnMgZm9yIGFsbCBzZXJpZXMuIFRoYXQgd2FzIHRoZSBoZWlnaHQgb2YgdGhlIGZpbmFuY2lhbCBjcmlzaXMuDQoNCiMjIEFnZ3JlZ2F0aW5nIGxvZy1yZXR1cm5zDQoNCiMjIyBBZ2dyZWdhdGluZyBsb2ctcmV0dXJuIHNlcmllcw0KDQpJbiBzdGF0aXN0aWNzLCBhZ2dyZWdhdGUgZGF0YSBhcmUgZGF0YSBjb21iaW5lZCBmcm9tIHNldmVyYWwgbWVhc3VyZW1lbnRzLiBZb3UganVzdCBsZWFybmVkIHRoYXQgeW91IGNhbiBjb21wdXRlIGNvbXB1dGUgd2Vla2x5LCBtb250aGx5IGFuZCBxdWFydGVybHkgbG9nLXJldHVybnMgYnkgc3VtbWluZyBkYWlseSBsb2ctcmV0dXJucyB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIGFwcGx5LndlZWtseSgpLCBhcHBseS5tb250aGx5KCkgYW5kIGFwcGx5LnF1YXJ0ZXJseSgpIGZ1bmN0aW9ucy4NCg0KRm9yIGV4YW1wbGUsIHlvdSBjYW4gdXNlIHRoZSBmb2xsb3dpbmcgY29kZSB0byBmb3JtIHRoZSBxdWFydGVybHkgcmV0dXJucyBmb3IgYSB1bml2YXJpYXRlIHRpbWUgc2VyaWVzIGRhdGEgYW5kIG11bHRpdmFyaWF0ZSB0aW1lIHNlcmllcyBtdl9kYXRhOg0KDQogICAgIyBhcHBseS5xdWFydGVybHkoeCwgRlVOLCAuLi4pDQogICAgZGF0YV9xID0gYXBwbHkucXVhcnRlcmx5KGRhdGEsIHN1bSkNCiAgICBtdl9kYXRhX3EgPSBhcHBseS5xdWFydGVybHkobXZfZGF0YSwgY29sU3VtcykNCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgcHJhY3RpY2UgYWdncmVnYXRpbmcgdGltZSBzZXJpZXMgZGF0YSB1c2luZyB0aGVzZSBmdW5jdGlvbnMgYW5kIHBsb3R0aW5nIHRoZSByZXN1bHRzLiBUaGUgZGF0YSBESiBhbmQgREpfY29uc3QgYXJlIGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZSwgYXMgYXJlIHRoZSBvYmplY3RzIGRqeCwgd2hpY2ggY29udGFpbnMgZGFpbHkgbG9nLXJldHVybnMgb2YgdGhlIERvdyBKb25lcyBpbmRleCBmcm9tIDIwMDAtMjAxNSwgYW5kIGRqcmV0dXJucywgd2hpY2ggY29udGFpbnMgdGhlIGRhaWx5IGxvZy1yZXR1cm5zIGZvciB0aGUgZmlyc3QgZm91ciBESl9jb25zdCBzdG9ja3MgZnJvbSAyMDAwLTIwMTUuIFVzZSBwbG90IGZvciB1bml2YXJpYXRlIHRpbWUgc2VyaWVzIGFuZCBwbG90LnpvbyBmb3IgbXVsdGl2YXJpYXRlIHRpbWUgc2VyaWVzLg0KYGBge3J9DQpkaiA8LSBESlsiMjAwMC8yMDE1Il0NCmRqeCA8LSBkaWZmKGxvZyhkaikpDQpkanN0b2NrcyA8LSBESl9jb25zdFsiMjAwMC8yMDE1IixjKCJBQVBMIiwgIkFYUCIsICJCQSIsICJDQVQiKV0NCmRqcmV0dXJucyA8LSBkaWZmKGxvZyhkanN0b2NrcykpDQpgYGANCmBgYHtyfQ0KIyBQbG90IGRqeA0KcGxvdChkangpDQoNCiMgUGxvdCB3ZWVrbHkgbG9nLXJldHVybnMgb2YgZGp4DQpwbG90KGFwcGx5LndlZWtseShkangsIHN1bSksIHR5cGUgPSAiaCIpDQoNCiMgUGxvdCBtb250aGx5IGxvZy1yZXR1cm5zIG9mIGRqeA0KcGxvdChhcHBseS5tb250aGx5KGRqeCwgc3VtKSwgdHlwZSA9ICJoIikNCg0KIyBQbG90IGRqcmV0dXJucw0KcGxvdC56b28oZGpyZXR1cm5zKQ0KDQojIFBsb3QgbW9udGhseSBsb2ctcmV0dXJucyBvZiBkanJldHVybnMNCnBsb3Quem9vKGFwcGx5Lm1vbnRobHkoZGpyZXR1cm5zLCBjb2xTdW1zKSwgdHlwZSA9ICJoIikNCg0KYGBgDQpUaGVzZSBhZ2dyZWdhdGlvbiBmdW5jdGlvbnMgYXJlIGV4dHJlbWVseSB1c2VmdWwgYXMgZm9yIGFuYWx5emluZyByaXNrIG92ZXIgbG9uZ2VyIHRpbWUgaG9yaXpvbnMuDQoNCkRhdGEgc2NpZW50aXN0cyBvZnRlbiB1c2UgdGhlIGFnZ3JlZ2F0aW9ucyB0aGF0IHlvdSBoYXZlIGxlYXJuZWQgc28gZmFyIGluIGNvbWJpbmF0aW9uIHdpdGggc3VtbWFyeSBzdGF0aXN0aWNzIHRvIGV4dHJhY3QgZXZlbiBtb3JlIGluc2lnaHRzIGZyb20gZGF0YS4gRnVuY3Rpb25zIHRoYXQgY2FsY3VsYXRlIHN1bW1hcnkgc3RhdGlzdGljcyBpbmNsdWRlIG1lYW4oKSwgbWVkaWFuKCksIGFuZCB2YXIoKS4NClRoZSBvYmplY3Qgc3AgY29udGFpbnMgZGFpbHkgbG9nLXJldHVybnMgZm9yIHRoZSBTJlAgNTAwIGluZGV4IGZvciB0aGUgcGVyaW9kIDE5NjAtMjAxNTsgaXQgaXMgbG9hZGVkIGluIHlvdXIgd29ya3NwYWNlLiBUbyB0aHJlZSBkZWNpbWFsIHBsYWNlcywgd2hhdCBpcyB0aGUgYXZlcmFnZSBxdWFydGVybHkgbG9nLXJldHVybiBmb3IgdGhlIFMmUCA1MDAgZnJvbSAxOTkwLTIwMTA/DQoNCmBgYHtyfQ0KZGF0YSgiU1A1MDAiKQ0Kc3AgPC0gU1A1MDBbIjE5OTAvMjAxMCJdDQpzcCA8LSBkaWZmKGxvZyhzcCkpWy0xXQ0KbWVhbihhcHBseS5xdWFydGVybHkoc3AsIHN1bSkpDQpgYGANCiMjIEV4cGxvcmluZyBvdGhlciBraW5kcyBvZiByaXNrIGZhY3RvcnMNCg0KIyMjIENvbW1vZGl0aWVzIGRhdGENCg0KVGhlIHBsb3R0aW5nIGZ1bmN0aW9uIHBhaXJzKCkgY3JlYXRlcyBhIHBhaXJ3aXNlIHNjYXR0ZXJwbG90IG9mIHRoZSBjb21wb25lbnRzIG9mIGEgbXVsdGl2YXJpYXRlIHRpbWUgc2VyaWVzIHdpdGggdHdvIG9yIG1vcmUgZGltZW5zaW9ucy4gSXQgaXMgdXNlZCBvbiBhIHpvbyBvYmplY3QgcmF0aGVyIHRoYW4gYW4geHRzIG9iamVjdC4NCg0KQSByb3VnaGx5IGNpcmN1bGFyIHNoYXBlIG9mIGEgc2NhdHRlcnBsb3QgaW5kaWNhdGVzIGEgbG93IGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGxvZy1yZXR1cm5zIG9mIHR3byBkaWZmZXJlbnQgY29tbW9kaXRpZXMuIEdlbmVyYWxseSBzcGVha2luZywgbG93IGNvcnJlbGF0aW9uIGlzIGdvb2QgaW4gYSBwb3J0Zm9saW8gYXMgaXQgaW1wbGllcyB0aGF0IHRoZSBhc3NldHMgYXJlIGRpdmVyc2lmaWVkLiBIaWdoIGNvcnJlbGF0aW9uLCBvbiB0aGUgb3RoZXIgaGFuZCwgcmVwcmVzZW50cyBhIHJpc2sgdGhhdCBtdXN0IGJlIHByb3Blcmx5IG1vZGVsbGVkLg0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBsb29rIGF0IGdvbGQgYW5kIG9pbCBwcmljZXMgb3ZlciBhIDI1IHllYXIgcGVyaW9kLCBjYWxjdWxhdGUgdGhlaXIgZGFpbHkgYW5kIG1vbnRobHkgbG9nLXJldHVybnMsIGFuZCBwbG90IHRoZW0uIFRoZSBkYXRhIGdvbGQgYW5kIG9pbCwgY29udGFpbmluZyB0aGUgZGFpbHkgcHJpY2VzIGZyb20gMTk5MC0yMDE1IG9mIGdvbGQgYW5kIEJyZW50IGNydWRlIG9pbC4NCmBgYHtyfQ0KZGF0YSgiT0lMX0JyZW50IikNCm9pbCA8LSBPSUxfQnJlbnRbIjE5OTAvMjAxNSJdDQpkYXRhKCJHT0xEIikNCmdvbGQgPC0gR09MRFsiMTk5MC8yMDE1Il0NCg0KIyBQbG90IGdvbGQgYW5kIG9pbCBwcmljZXMNCnBsb3QoZ29sZCkNCnBsb3Qob2lsKQ0KDQojIENhbGN1bGF0ZSBkYWlseSBsb2ctcmV0dXJucw0KZ29sZHggPC0gZGlmZihsb2coZ29sZCkpDQpvaWx4IDwtIGRpZmYobG9nKG9pbCkpDQoNCiMgQ2FsY3VsYXRlIG1vbnRobHkgbG9nLXJldHVybnMNCmdvbGR4X20gPC0gYXBwbHkubW9udGhseShnb2xkeCwgc3VtKQ0Kb2lseF9tIDwtIGFwcGx5Lm1vbnRobHkob2lseCwgc3VtKQ0KDQojIE1lcmdlIGdvbGR4X20gYW5kIG9pbHhfbSBpbnRvIGNvbXMNCmNvbXMgPC0gbWVyZ2UoZ29sZHhfbSwgb2lseF9tKQ0KDQojIFBsb3QgY29tcyB3aXRoIHZlcnRpY2FsIGJhcnMNCnBsb3Quem9vKGNvbXMsIHR5cGUgPSAiaCIpDQoNCiMgTWFrZSBhIHBhaXJ3aXNlIHNjYXR0ZXJwbG90IG9mIGNvbXMNCnBhaXJzKGFzLnpvbyhjb21zKSkNCmBgYA0KQXMgeW91IGNhbiBzZWUsIGdvbGQgYW5kIG9pbCBhcmUgd2VsbCBkaXZlcnNpZmllZCBjb21tb2RpdGllcy4NCg0KIyMgSW50ZXJlc3QtcmF0ZSBkYXRhDQoNClRoZSBvYmplY3QgemNiIGNvbnRhaW5zIGRhaWx5IHZhbHVlcyBvZiBDYW5hZGlhbiB6ZXJvLWNvdXBvbi1ib25kIHlpZWxkcywgZXhwcmVzc2VkIGFzIHBlcmNlbnRhZ2VzLCBmb3IgdGhlIHBlcmlvZCAyMDA2LTIwMTUuIFlpZWxkcyBhcmUgdGhlIGtleSByaXNrLWZhY3RvciB3aGVuIGl0IGNvbWVzIHRvIGFuYWx5c2luZyB0aGUgaW50ZXJlc3QtcmF0ZSByaXNrIGluIGEgcG9ydGZvbGlvIG9mIGJvbmRzIG9yIG90aGVyIGZpeGVkLWluY29tZSBwcm9kdWN0cy4NCg0KSXQgaXMgbm90IHNvIGNsZWFyIHdoYXQgaXMgdGhlIGJlc3Qgd2F5IG9mIGNhbGN1bGF0aW5nIHJpc2stZmFjdG9yIGNoYW5nZXMgZm9yIHlpZWxkcy4gSXQgaXMgcG9zc2libGUgdG8gY29tcHV0ZSBsb2ctcmV0dXJucywgcHJvdmlkZWQgeWllbGRzIGFyZSBub3QgbmVnYXRpdmUsIGFuZCBpdCBpcyBhbHNvIHBvc3NpYmxlIHRvIGNhbGN1bGF0ZSBzaW1wbGUgcmV0dXJucy4gVG8gY29tcHV0ZSB0aGUgc2ltcGxlIHJldHVybnMgb2YgYSBzZXJpZXMsIHVzZSBvbmx5IGRpZmYoKSBpbnN0ZWFkIG9mIGRpZmYoKSBhbmQgbG9nKCkuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIHBsb3QgdGltZSBzZXJpZXMgb2YgeWllbGRzIGZvciBmaXhlZCB0aW1lcyB0byBtYXR1cml0eSwgYW5kIHBsb3Qgcmlzay1mYWN0b3IgY2hhbmdlcyBmb3IgdGhlc2UgeWllbGRzLiBZb3Ugd2lsbCBhbHNvIHBsb3QgdGhlIHdob2xlIHlpZWxkIGN1cnZlIG9uIHBhcnRpY3VsYXIgZGF0ZXMuIFRoZSB6Y2IgZGF0YSBoYXMgYmVlbiBsb2FkZWQgaW50byB5b3VyIHdvcmtzcGFjZS4gQSB2ZWN0b3IgeWllbGRfY29scyBjb250YWluaW5nIHRoZSBuYW1lcyBvZiB0aGUgY29sdW1ucyBjb3JyZXNwb25kaW5nIHRvIG1hdHVyaXRpZXMgb2YgMSwgNSBhbmQgMTAgeWVhcnMgaGFzIGJlZW4gY3JlYXRlZC4gQSBudW1lcmljYWwgdmVjdG9yIG1hdHVyaXR5IGNvbnRhaW5pbmcgYWxsIHRoZSBtYXR1cml0aWVzIGluIHllYXJzIGhhcyBhbHNvIGJlZW4gY3JlYXRlZC4NCmBgYHtyfQ0KZGF0YSgiWkNCX0NBRCIpDQp6Y2IgPC0gWkNCX0NBRFsiMjAwNi8yMDE1Il0NCmBgYA0KYGBge3J9DQptYXR1cml0eSA8LSBjKDAuMjUsIDAuNSwgMC43NSwgMSwgMS4yNSwgMS41LCAxLjc1LCAyLCAyLjI1LCAyLjUsIDIuNzUsIDMsIA0KMy4yNSwgMy41LCAzLjc1LCA0LCA0LjI1LCA0LjUsIDQuNzUsIDUsIDUuMjUsIDUuNSwgNS43NSwgNiwgNi4yNSwgDQo2LjUsIDYuNzUsIDcsIDcuMjUsIDcuNSwgNy43NSwgOCwgOC4yNSwgOC41LCA4Ljc1LCA5LCA5LjI1LCA5LjUsIA0KOS43NSwgMTAsIDEwLjI1LCAxMC41LCAxMC43NSwgMTEsIDExLjI1LCAxMS41LCAxMS43NSwgMTIsIDEyLjI1LCANCjEyLjUsIDEyLjc1LCAxMywgMTMuMjUsIDEzLjUsIDEzLjc1LCAxNCwgMTQuMjUsIDE0LjUsIDE0Ljc1LCANCjE1LCAxNS4yNSwgMTUuNSwgMTUuNzUsIDE2LCAxNi4yNSwgMTYuNSwgMTYuNzUsIDE3LCAxNy4yNSwgMTcuNSwgDQoxNy43NSwgMTgsIDE4LjI1LCAxOC41LCAxOC43NSwgMTksIDE5LjI1LCAxOS41LCAxOS43NSwgMjAsIDIwLjI1LCANCjIwLjUsIDIwLjc1LCAyMSwgMjEuMjUsIDIxLjUsIDIxLjc1LCAyMiwgMjIuMjUsIDIyLjUsIDIyLjc1LCANCjIzLCAyMy4yNSwgMjMuNSwgMjMuNzUsIDI0LCAyNC4yNSwgMjQuNSwgMjQuNzUsIDI1LCAyNS4yNSwgMjUuNSwgDQoyNS43NSwgMjYsIDI2LjI1LCAyNi41LCAyNi43NSwgMjcsIDI3LjI1LCAyNy41LCAyNy43NSwgMjgsIDI4LjI1LCANCjI4LjUsIDI4Ljc1LCAyOSwgMjkuMjUsIDI5LjUsIDI5Ljc1LCAzMCkNCmBgYA0KDQpgYGB7cn0NCnlpZWxkX2NvbHMgPC0gYygiMS4wMHkiLCAiNS4wMHkiLCAiMTAuMDB5IikNCiMgQ29tcHV0ZSBsb2ctcmV0dXJucyBhcyB6Y2JfeCBhbmQgc2ltcGxlIHJldHVybnMgYXMgemNiX3gyDQp6Y2JfeCA8LSBkaWZmKGxvZyh6Y2IpKQ0KemNiX3gyIDwtIGRpZmYoemNiKQ0KDQojIFBsb3QgemNiX3ggZm9yIDEsIDUgYW5kIDEwLXllYXIgbWF0dXJpdGllcw0KcGxvdC56b28oemNiX3hbLCB5aWVsZF9jb2xzXSkNCg0KIyBQbG90IHpjYl94MiBmb3IgMSwgNSBhbmQgMTAteWVhciBtYXR1cml0aWVzDQpwbG90Lnpvbyh6Y2JfeDJbLCB5aWVsZF9jb2xzXSkNCg0KIyBQbG90IHRoZSB5aWVsZCBjdXJ2ZSBmb3IgdGhlIGZpcnN0IGRheSBvZiB6Y2INCnBsb3QobWF0dXJpdHksIHpjYlsxLF0sIHlsaW0gPSByYW5nZSh6Y2IpLCB0eXBlID0gImwiLCB5bGFiID0gInlpZWxkICglKSIsIGNvbCA9ICJyZWQiKQ0KDQojIEFkZCBhIGxpbmUgZm9yIHRoZSBsYXN0IGRheSBvZiB6Y2INCmxpbmVzKG1hdHVyaXR5LCB6Y2JbbnJvdyh6Y2IpLCBdKQ0KYGBgDQpZaWVsZHMgY2FuIHNlZW0gYSBsaXR0bGUgdHJpY2t5IHRvIHdvcmsgd2l0aCBhdCBmaXJzdCBidXQgdGhleSBhcmUgZnVuZGFtZW50YWwgZm9yIGFuYWx5emluZyBib25kIHBvcnRmb2xpb3MgYW5kIG1hbnkgb3RoZXIgZmluYW5jaWFsIHByb2R1Y3RzIHRoYXQgZGVwZW5kIG9uIGludGVyZXN0IHJhdGVzLg0KDQojIFJlYWwgd29ybGQgcmV0dXJucyBhcmUgcmlza2llciB0aGFuIG5vcm1hbA0KDQojIyBUaGUgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KDQojIyMgR3JhcGhpY2FsIG1ldGhvZHMgZm9yIGFzc2Vzc2luZyBub3JtYWxpdHkNCg0KVG8gY3JlYXRlIGEgaGlzdG9ncmFtIHdpdGggMjAgYnVja2V0cyB0aGF0IHJlcHJlc2VudHMgdGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgb2YgdGhlIEZUU0UgZGF0YSwgYXMgd2VsbCBhcyBob3cgdG8gYWRkIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB0byB0aGUgZXhpc3RpbmcgcGxvdCBhcyBhIHJlZCBsaW5lOg0KDQogICAgaGlzdChmdHNlLCBuY2xhc3MgPSAyMCwgcHJvYmFiaWxpdHkgPSBUUlVFKQ0KICAgIGxpbmVzKGZ0c2UsIGRub3JtKGZ0c2UsIG1lYW4gPSBtdSwgc2QgPSBzaWdtYSksIGNvbCA9ICJyZWQiKQ0KDQpBcyB5b3UgY2FuIHNlZSwgZG5vcm0oeCwgbWVhbiwgc2QpIGNhbGN1bGF0ZXMgdGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gKFBERikgb2YgdGhlIGRhdGEgeCB3aXRoIHRoZSBjYWxjdWxhdGVkIHNhbXBsZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb247IHRoaXMgaXMga25vd24gYXMgdGhlIG1ldGhvZC1vZi1tb21lbnRzLg0KDQpGaW5hbGx5LCB0byBjYWxjdWxhdGUgYW4gZXN0aW1hdGUgb2YgdGhlIGRlbnNpdHkgb2YgZGF0YSB4LCB1c2UgZGVuc2l0eSh4KS4gVGhpcyBjcmVhdGVzIGEgc28tY2FsbGVkIGtlcm5lbC1kZW5zaXR5IGVzdGltYXRlIChLREUpIHVzaW5nIGEgbm9uLXBhcmFtZXRyaWMgbWV0aG9kIHRoYXQgbWFrZXMgbm8gYXNzdW1wdGlvbnMgYWJvdXQgdGhlIHVuZGVybHlpbmcgZGlzdHJpYnV0aW9uLg0KDQpUaGUgdmFyaW91cyBwbG90cyBzdWdnZXN0IHRoYXQgdGhlIGRhdGEgYXJlIGhlYXZpZXIgdGFpbGVkIHRoYW4gbm9ybWFsLCBhbHRob3VnaCB5b3Ugd2lsbCBsZWFybiBhYm91dCBiZXR0ZXIgZ3JhcGhpY2FsIGFuZCBudW1lcmljYWwgdGVzdHMgaW4gZnV0dXJlIGV4ZXJjaXNlcy4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgZml0IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB0byB0aGUgbG9nLXJldHVybnMgb2YgdGhlIERvdyBKb25lcyBpbmRleCBmb3IgMjAwOC0yMDA5IGFuZCBjb21wYXJlIHRoZSBkYXRhIHdpdGggdGhlIGZpdHRlZCBkaXN0cmlidXRpb24gdXNpbmcgYSBoaXN0b2dyYW0gYW5kIGEgZGVuc2l0eSBwbG90LiBUaGUgb2JqZWN0IGRqeCBjb250YWluaW5nIERvdyBKb25lcyBkYXRhIGlzIGxvYWRlZCBpbnRvIHlvdXIgd29ya3NwYWNlLg0KYGBge3J9DQpkanggPC0gREpbIjIwMDgvMjAwOSJdDQpkanggPC0gZGlmZihsb2coZGp4KSkNCmRqeCA8LSBhcy5udW1lcmljKGRqeClbLTFdDQpkanggPC0gc29ydChkangpDQpgYGANCmBgYHtyfQ0KIyBDYWxjdWxhdGUgYXZlcmFnZSBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGRqeA0KbXUgPC0gbWVhbihkangpDQpzaWdtYSA8LSBzZChkangpDQoNCiMgUGxvdCBoaXN0b2dyYW0gb2YgZGp4DQpoaXN0KGRqeCwgbmNsYXNzID0gMjAsIHByb2JhYmlsaXR5ID0gVFJVRSkNCg0KIyBBZGQgdGhlIG5vcm1hbCBkZW5zaXR5IGFzIGEgcmVkIGxpbmUgdG8gaGlzdG9ncmFtDQpsaW5lcyhkangsIGRub3JtKGRqeCwgbWVhbiA9IG11LCBzZCA9IHNpZ21hKSwgY29sID0gInJlZCIpDQoNCiMgUGxvdCBub24tcGFyYW1ldHJpYyBLREUgb2YgZGp4DQpwbG90KGRlbnNpdHkoZGp4KSkNCg0KIyBBZGQgdGhlIG5vcm1hbCBkZW5zaXR5IGFzIHJlZCBsaW5lIHRvIEtERQ0KbGluZXMoZGp4LCBkbm9ybShkangsIG1lYW4gPSBtdSwgc2QgPSBzaWdtYSksIGNvbCA9ICJyZWQiKQ0KYGBgDQpgYGB7cn0NCm11IDwtIG1lYW4oZGp4KQ0Kc2lnbWEgPC0gc2QoZGp4KQ0KdGUgPC0gZG5vcm0oZGp4LCBtZWFuID0gbXUsIHNkID0gc2lnbWEpDQpvcmQgPC0gc29ydChkangpDQpoZWFkKG9yZCkNCnRhaWwob3JkKQ0KdGUgPC0gZG5vcm0ob3JkLCBtZWFuID0gbXUsIHNkID0gc2lnbWEpDQpoZWFkKHRlKQ0KYGBgDQpUaGUgZGF0YSBkb24ndCBsb29rIHZlcnkgbm9ybWFsLiBDb21wYXJlIGluIHBhcnRpY3VsYXIgdGhlIGNlbnRlciBhbmQgdGhlIHRhaWxzIG9mIHRoZSBoaXN0b2dyYW0gYW5kIGRlbnNpdHkgcGxvdCB3aXRoIHRoZSByZWQgbm9ybWFsIGN1cnZlLg0KDQojIyBUZXN0aW5nIGZvciBub3JtYWxpdHkNCg0KIyMjIFEtUSBwbG90cyBmb3IgYXNzZXNzaW5nIG5vcm1hbGl0eQ0KDQpUaGUgcXVhbnRpbGUtcXVhbnRpbGUgcGxvdCAoUS1RIHBsb3QpIGlzIGEgYmV0dGVyIGdyYXBoaWNhbCBtZXRob2QgZm9yIHJldmVhbGluZyBub24tbm9ybWFsaXR5LiBJbiBnZW5lcmFsLCBhIFEtUSBwbG90IGNvbXBhcmVzIHRoZSBxdWFudGlsZXMgb2YgdGhlIGRhdGEgd2l0aCB0aGUgcXVhbnRpbGVzIG9mIGEgcmVmZXJlbmNlIGRpc3RyaWJ1dGlvbjsgaWYgdGhlIGRhdGEgYXJlIGZyb20gYSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbWUgdHlwZSAodXAgdG8gc2NhbGluZyBhbmQgbG9jYXRpb24pLCBhIHJlYXNvbmFibHkgc3RyYWlnaHQgbGluZSBzaG91bGQgYmUgb2JzZXJ2ZWQuIFlvdSBzaG91bGQga25vdyB0aGF0IHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gKGRmKSByZWZlciB0byB0aGUgbnVtYmVyIG9mIHZhbHVlcyBvciBvYnNlcnZhdGlvbnMgdGhhdCBjYW4gYWZmZWN0IHRoZSBzeXN0ZW0geW91IGFyZSB3b3JraW5nIHdpdGguDQoNClRvIGdlbmVyYXRlIDEwMDAgbm9ybWFsIGRhdGEgcG9pbnRzIHdpdGggdGhlIHJub3JtKCkgZnVuY3Rpb24sIGFzIHdlbGwgYXMgaG93IHRvIHVzZSBxcW5vcm0oKSB0byBjcmVhdGUgdGhlIFEtUSBwbG90LCBhbmQgcXFsaW5lKCkgdG8gYWRkIGEgc3RyYWlnaHQgbGluZSBmb3IgcmVmZXJlbmNlOg0KDQpgYGB7cn0NCmRhdGEgPC0gcm5vcm0oMTAwMCwgbWVhbiA9IDMsIHNkID0gMikNCnFxbm9ybShkYXRhKQ0KcXFsaW5lKGRhdGEpDQpgYGANCllvdSB3aWxsIGNyZWF0ZSBhIFEtUSBwbG90IG9mIHRoZSBEb3cgSm9uZXMgbG9nLXJldHVybnMgaW4gZGp4IGFnYWluc3QgdGhlIG5vcm1hbCByZWZlcmVuY2UgZGlzdHJpYnV0aW9uLCB3aGljaCB5b3Ugd2lsbCBhZGQgYXMgYSB2aXN1YWwgZ3VpZGUuIFlvdSB3aWxsIHRoZW4gY29tcGFyZSB0aGUgcGxvdCB3aXRoIHNpbXVsYXRlZCBkYXRhc2V0cyBmcm9tIG5vcm1hbCwgU3R1ZGVudCB0IGFuZCB1bmlmb3JtIGRpc3RyaWJ1dGlvbnMgZ2VuZXJhdGVkIHdpdGggdGhlIHJub3JtKCksIHJ0KCkgYW5kIHJ1bmlmKCkgZnVuY3Rpb25zLiBZDQoNCklmIHRoZSBkYXRhIGFyZSBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB0aGUgZG90cyBzaG91bGQgYmUgY2xvc2UgdG8gdGhlIHJlZCBsaW5lIChhbHRob3VnaCB0aGVyZSBtYXkgYmUgc29tZSBkZXZpYXRpb24gYXQgdGhlIHZlcnkgZW5kKS4NCg0KYGBge3J9DQojIE1ha2UgYSBRLVEgcGxvdCBvZiBkanggYW5kIGFkZCBhIHJlZCBsaW5lDQpxcW5vcm0oZGp4KQ0KcXFsaW5lKGRqeCwgY29sID0gInJlZCIpDQoNCiMgQ2FsY3VsYXRlIHRoZSBsZW5ndGggb2YgZGp4IGFzIG4NCm4gPC0gbGVuZ3RoKGRqeCkNCg0KIyBHZW5lcmF0ZSBuIHN0YW5kYXJkIG5vcm1hbCB2YXJpYWJsZXMsIG1ha2UgYSBRLVEgcGxvdCwgYWRkIGEgcmVkIGxpbmUNCngxIDwtIHJub3JtKG4pDQpxcW5vcm0oeDEpDQpxcWxpbmUoeDEsIGNvbCA9ICJyZWQiKQ0KDQojIEdlbmVyYXRlIG4gU3R1ZGVudCB0IHZhcmlhYmxlcywgbWFrZSBhIFEtUSBwbG90LCBhZGQgYSByZWQgbGluZQ0KeDIgPC0gcnQobiwgZGYgPSA0KQ0KcXFub3JtKHgyKQ0KcXFsaW5lKHgyLCBjb2wgPSAicmVkIikNCg0KIyBHZW5lcmF0ZSBuIHN0YW5kYXJkIHVuaWZvcm0gdmFyaWFibGVzLCBtYWtlIGEgUS1RIHBsb3QsIGFkZCByZWQgbGluZQ0KeDMgPC0gcnVuaWYobikNCnFxbm9ybSh4MykNCnFxbGluZSh4MywgY29sID0gInJlZCIpDQpgYGANClRoZSBRLVEgcGxvdCBpcyBhIHZlcnkgZWZmZWN0aXZlIHRvb2wgdGhhdCBpcyB3aWRlbHkgdXNlZCBpbiBhcHBsaWVkIHN0YXRpc3RpY2FsIGFuZCBlY29ub21ldHJpYyB3b3JrLg0KDQojIyBTa2V3bmVzcywga3VydG9zaXMgYW5kIHRoZSBKYXJxdWUtQmVyYSB0ZXN0DQoNCiMjIyBOdW1lcmljYWwgdGVzdHMgb2Ygbm9ybWFsaXR5DQoNClRoZSBtb21lbnRzIHBhY2thZ2UgY29udGFpbnMgZnVuY3Rpb25zIGZvciBjb21wdXRpbmcgdGhlIGt1cnRvc2lzIGFuZCBza2V3bmVzcyBvZiBkYXRhIGFuZCB3ZWxsIGFzIGZvciBpbXBsZW1lbnRpbmcgdGhlIEphcnF1ZS1CZXJhIHRlc3QsIHdoaWNoIGlzIGEgdGVzdCBvZiBub3JtYWxpdHkgYmFzZWQgb24gdGhlc2UgaGlnaGVyLW9yZGVyIG1vbWVudHMuIEluIG9uZSBjb21tYW5kLCBpdCBjb21wYXJlcyB0aGUgc2tld25lc3MgYW5kIGt1cnRvc2lzIG9mIHRoZSBkYXRhIHdpdGggdGhlIHRoZW9yZXRpY2FsIHZhbHVlcyBmb3IgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24sIHdoaWNoIGFyZSAwIGFuZCAzLCByZXNwZWN0aXZlbHkuDQoNCiAgICBqYXJxdWUudGVzdCh4KQ0KICAgIHNrZXduZXNzKHgsIG5hLnJtID0gRkFMU0UpDQogICAga3VydG9zaXMoeCwgbmEucm0gPSBGQUxTRSkNCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgY2FsY3VsYXRlIHRoZSBza2V3bmVzcyBhbmQga3VydG9zaXMgZm9yIHRoZSBkangsIHRoZSBEb3cgSm9uZXMgaW5kZXggZnJvbSAyMDA4LTIwMTEsIGFuZCBhcHBseSB0aGUgSmFycXVlLUJlcmEgdGVzdCBvZiBub3JtYWxpdHkuIFlvdSB3aWxsIHRoZW4gYXBwbHkgdGhlIHNhbWUgbWV0aG9kcyB0byBkanJldHVybnMsIHdoaWNoIGNvbnRhaW5zIDI5IG9mIHRoZSBEb3cgSm9uZXMgc3RvY2tzIGZvciB0aGUgc2FtZSBwZXJpb2QuDQoNClJlY2FsbCB0aGF0IHlvdSBjYW4gdXNlIGFwcGx5KFgsIE1BUkdJTiwgRlVOLCDigKYpIHRvIGFwcGx5IGZ1bmN0aW9ucyBvdmVyIGFycmF5IG1hcmdpbnMuIFRoZSBNQVJHSU4gcGFyYW1ldGVyIGlzIGEgdmVjdG9yIGluZGljYXRpbmcgd2hlcmUgdGhlIGZ1bmN0aW9uIHdpbGwgYmUgYXBwbGllZDsgaW4gdGhpcyBpbnN0YW5jZSwgeW91IHdpbGwgdXNlIDIgdG8gc3BlY2lmeSB0aGF0IHRoZSBmdW5jdGlvbiBGVU4gc2hvdWxkIGJlIGFwcGxpZWQgdG8gdGhlIGNvbHVtbnMgaW4gbWF0cml4IFguDQpgYGB7cn0NCmRqIDwtIERKWyIyMDA4LzIwMTEiXQ0KZGp4IDwtIGRpZmYobG9nKGRqKSkNCmRqeCA8LSBhcy5udW1lcmljKGRqeClbLTFdDQpkanggPC0gc29ydChkangpDQoNCmRqc3RvY2tzIDwtIERKX2NvbnN0WyIyMDA4LzIwMTEiXQ0KZGpyZXR1cm5zIDwtIGRpZmYobG9nKGRqc3RvY2tzKSlbLTFdDQpgYGANCmBgYHtyfQ0KbGlicmFyeShtb21lbnRzKQ0KIyBDYWxjdWxhdGUgc2tld25lc3MgYW5kIGt1cnRvc2lzIG9mIGRqeA0Kc2tld25lc3MoZGp4KQ0Ka3VydG9zaXMoZGp4KQ0KDQojIENhcnJ5IG91dCBhIEphcnF1ZS1CZXJhIHRlc3QgZm9yIGRqeA0KamFycXVlLnRlc3QoZGp4KQ0KDQojIENhbGN1bGF0ZSBza2V3bmVzcyBhbmQga3VydG9zaXMgb2YgZGpyZXR1cm5zIA0KcyA8LSBhcHBseShkanJldHVybnMsIDIsIHNrZXduZXNzKQ0KayA8LSBhcHBseShkanJldHVybnMsIDIsIGt1cnRvc2lzKQ0KDQojIFBsb3QgayBhZ2FpbnN0IHMgYW5kIGFkZCB0ZXh0IGxhYmVscyB0byBpZGVudGlmeSBzdG9ja3MNCnBsb3QocywgaywgdHlwZSA9ICJuIikNCnRleHQocywgaywgbmFtZXMocyksIGNleCA9IDAuNikNCg0KIyBDYXJyeSBvdXQgSmFycXVlLUJlcmEgdGVzdHMgZm9yIGVhY2ggY29uc3RpdHVlbnQgaW4gZGpyZXR1cm5zDQphcHBseShkanJldHVybnMsIDIsIGphcnF1ZS50ZXN0KQ0KYGBgDQpUaGUgcmV0dXJuIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIERvdyBKb25lcyBzdG9ja3MgYWxsIGhhdmUgaGlnaCBrdXJ0b3NpcyBhbmQgc29tZSBvZiB0aGVtIGFyZSBxdWl0ZSBza2V3ZWQuDQoNCiMjIyBUZXN0aW5nIG5vcm1hbGl0eSBmb3IgbG9uZ2VyIHRpbWUgaG9yaXpvbnMNCg0KQXMgcmV0dXJucyBhcmUgYWRkZWQgdG9nZXRoZXIgb3ZlciBsb25nZXIgdGltZSBwZXJpb2RzLCBhIGNlbnRyYWwgbGltaXQgZWZmZWN0IHRha2VzIHBsYWNlIGFuZCByZXR1cm5zIHRlbmQgdG8gYmVjb21lIG1vcmUgbm9ybWFsLg0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCB1c2UgYWdncmVnYXRpb24gZnVuY3Rpb25zIHRoYXQgeW91IGxlYXJuZWQgaW4gdGhlIGZpcnN0IGNoYXB0ZXIgdG8gYWdncmVnYXRlIHRoZSBkYXRhIGluIGRqeF9kLCBjb250YWluaW5nIHRoZSBkYWlseSBsb2ctcmV0dXJucyBmb3IgMjkgb2YgdGhlIERvdyBKb25lcyBzdG9ja3MgZm9yIHRoZSBwZXJpb2QgMjAwMC0yMDE1LiANCg0KYGBge3J9DQpkanN0b2NrcyA8LSBESl9jb25zdFsiMjAwMC8yMDE1Il0NCmRqcmV0dXJucyA8LSBkaWZmKGxvZyhkanN0b2NrcykpWy0xXQ0KZGp4X2QgPC0gZGpyZXR1cm5zDQojIENhbGN1bGF0ZSB3ZWVrbHkgYW5kIG1vbnRobHkgbG9nLXJldHVybnMgZnJvbSBkanhfZA0KZGp4X3cgPC0gYXBwbHkud2Vla2x5KGRqeF9kLCBjb2xTdW1zKQ0KZGp4X20gPC0gYXBwbHkubW9udGhseShkanhfZCwgY29sU3VtcykNCg0KIyBDYWxjdWxhdGUgdGhlIHAtdmFsdWUgZm9yIGVhY2ggc2VyaWVzIGluIGRqeF9kDQphcHBseShkanhfZCwgMiwgZnVuY3Rpb24odil7amFycXVlLnRlc3QodikkcC52YWx1ZX0pDQoNCiMgQ2FsY3VsYXRlIHRoZSBwLXZhbHVlIGZvciBlYWNoIHNlcmllcyBpbiBkanhfdw0KYXBwbHkoZGp4X3csIDIsIGZ1bmN0aW9uKHYpe2phcnF1ZS50ZXN0KHYpJHAudmFsdWV9KQ0KDQojIENhbGN1bGF0ZSB0aGUgcC12YWx1ZSBmb3IgZWFjaCBzZXJpZXMgaW4gZGp4X20NCmFwcGx5KGRqeF9tLCAyLCBmdW5jdGlvbih2KXtqYXJxdWUudGVzdCh2KSRwLnZhbHVlfSkNCg0KYGBgDQpBbHRob3VnaCB0aGUgcC12YWx1ZXMgZ2V0IGxhcmdlciwgYWxsIG1vbnRobHkgcmV0dXJucyBvdGhlciB0aGFuIGZvciBDaGV2cm9uIChDVlgpLCAzTSAoTU1NKSwgYW5kIFBmaXplciAoUEZFKSBzdGlsbCBmYWlsIHRoZSBub3JtYWxpdHkgdGVzdC4NCg0KIyMjIE92ZXJsYXBwaW5nIHJldHVybnMNCldoZW4geW91IGFnZ3JlZ2F0ZSBzZXJpZXMgYnkgc3VtbWluZyBkYWlseSBsb2ctcmV0dXJucyBpbnRvIGxvbmdlciBpbnRlcnZhbHMsIHlvdSBhbmFseXplIGEgc21hbGxlciBhbW91bnQgb2Ygb2JzZXJ2YXRpb25zLiBUbyBwcmVzZXJ2ZSB0aGUgcXVhbnRpdHkgb2YgZGF0YSwgeW91IGNhbiBjYWxjdWxhdGUgb3ZlcmxhcHBpbmcgcmV0dXJucyB3aXRoIHRoZSByb2xsYXBwbHlyKCkgZnVuY3Rpb247IHRoaXMgYWxzbyBjcmVhdGVzIHN0cm9uZyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBvYnNlcnZhdGlvbnMuDQoNClRoZXJlIGFyZSA1IHRyYWRpbmcgZGF5cyBpbiB0aGUgYXZlcmFnZSBjYWxlbmRhciB3ZWVrLiBCeSBjb21wdXRpbmcgdGhlIDUtZGF5IG1vdmluZyBzdW1zIG9mIHRoZSBsb2ctcmV0dXJucyBvZiBkYWlseSBpbmRleCBkYXRhLCB5b3Ugb2J0YWluIGFwcHJveGltYXRlIG92ZXJsYXBwaW5nIHdlZWtseSByZXR1cm5zIGVuZGluZyBvbiBlYWNoIGNhbGVuZGFyIHdlZWsuIFNpbWlsYXJseSwgY2FsY3VsYXRpbmcgMjEtZGF5IG1vdmluZyBzdW1zIGdpdmVzIGFwcHJveGltYXRlIG92ZXJsYXBwaW5nIG1vbnRobHkgcmV0dXJucywgYW5kIGNhbGN1bGF0aW5nIDYzLWRheSBtb3Zpbmcgc3VtcyBnaXZlcyBhcHByb3hpbWF0ZSBvdmVybGFwcGluZyBxdWFydGVybHkgcmV0dXJucy4NCkxldCdzIGxvb2sgYXQgYW4gZXhhbXBsZSB3aXRoIHRoZSBEb3cgSm9uZXMgZGFpbHkgcmV0dXJuIGRhdGEgaW4gZGp4LiBCZWNhdXNlIDUgdmFsdWVzIGFyZSB1c2VkIHRvIGNhbGN1bGF0ZSBlYWNoIG1vdmluZyBzdW0sIHRoZSBmaXJzdCA0IHZhbHVlcyBpbiB0aGUgcmVzdWx0IGFyZSBOQS4gSW4gdGhpcyBpbnN0YW5jZSwgd2Ugd2lsbCB1c2UgaW5kZXhpbmcgdG8gcmVtb3ZlIHRoZW06DQpgYGB7cn0NCmRqIDwtIERKWyIyMDA4LzIwMTEiXQ0KZGp4IDwtIGRpZmYobG9nKGRqKSlbLTFdDQpkang1IDwtIHJvbGxhcHBseXIoZGp4LCB3aWR0aCA9IDUsIEZVTiA9IHN1bSkNCmhlYWQoZGp4NSkNCmRqeDUgPC0gZGp4NVstKDE6NCldDQpgYGANCm4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgY2FsY3VsYXRlIG1vdmluZyBzdW1zIG9mIGRpZmZlcmVudCBpbnRlcnZhbHMgZnJvbSBkangsIHdoaWNoIGlzIGxvYWRlZCBpbiB5b3VyIHdvcmtzcGFjZS4gWW91IHdpbGwgdGhlbiBmaW5kIHRoZSBza2V3bmVzcyBhbmQga3VydG9zaXMgb2YgdGhlIHJlc3VsdGluZyBkYXRhIGFuZCBjb25kdWN0IHRoZSBKYXJxdWUtQmVyYSB0ZXN0IGp1c3QgYXMgeW91IGhhdmUgaW4gcHJldmlvdXMgZXhlcmNpc2VzLiBEbyB0aGUgb3ZlcmxhcHBpbmcgcmV0dXJucyBhcHBlYXIgbW9yZSBub3JtYWw/DQpgYGB7cn0NCiMgQ2FsY3VsYXRlIGEgMjEtZGF5IG1vdmluZyBzdW0gb2YgZGp4DQpkangyMSA8LSByb2xsYXBwbHlyKGRqeCwgd2lkdGggPSAyMSwgRlVOID0gc3VtKVstKDE6MjApXQ0KDQojIENhbGN1bGF0ZSBhIDYzLWRheSBtb3Zpbmcgc3VtIG9mIGRqeA0KZGp4NjMgPC0gcm9sbGFwcGx5cihkangsIHdpZHRoID0gNjMsIEZVTiA9IHN1bSlbLSgxOjYyKV0NCg0KIyBNZXJnZSB0aGUgdGhyZWUgc2VyaWVzIGFuZCBwbG90DQpkangyIDwtIG1lcmdlKGRqeCwgZGp4MjEsIGRqeDYzLCBhbGwgPSBGQUxTRSkNCnBsb3Quem9vKGRqeDIpDQoNCiMgQ29tcHV0ZSB0aGUgc2tld25lc3MgYW5kIGt1cnRvc2lzIGZvciBlYWNoIHNlcmllcyBpbiBkangyDQphcHBseShkangyLCAyLCBza2V3bmVzcykNCmFwcGx5KGRqeDIsIDIsIGt1cnRvc2lzKQ0KDQojIENvbmR1Y3QgdGhlIEphcnF1ZS1CZXJhIHRlc3QgdG8gZWFjaCBzZXJpZXMgaW4gZGp4Mg0KYXBwbHkoZGp4MiwgMiwgamFycXVlLnRlc3QpDQpgYGANClRoZXNlIG92ZXJsYXBwaW5nIHJldHVybnMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIGFuZCBldmVuIG1vcmUgZGlmZmljdWx0IHRvIGludGVycHJldC4NCg0KIyMgVGhlIFN0dWRlbnQgdCBkaXN0cmlidXRpb24NCg0KIyMjIEZpdHRpbmcgdCBkaXN0cmlidXRpb24gdG8gZGF0YQ0KDQpBIFN0dWRlbnQgdCBkaXN0cmlidXRpb24gaXMgZ2VuZXJhbGx5IGEgbXVjaCBiZXR0ZXIgZml0IHRvIGRhaWx5LCB3ZWVrbHksIGFuZCBtb250aGx5IHJldHVybnMgdGhhbiBhIG5vcm1hbCBkaXN0cmlidXRpb24uDQoNCllvdSBjYW4gY3JlYXRlIG9uZSBieSB1c2luZyB0aGUgZml0LnN0KCkgZnVuY3Rpb24gaW4gdGhlIFFSTSBwYWNrYWdlLiBUaGUgcmVzdWx0aW5nIGZpdHRlZCBtb2RlbCBoYXMgYSBwYXJhbWV0ZXIgZXN0aW1hdGVzIGNvbXBvbmVudCBwYXIuZXN0cyB3aGljaCBjYW4gYmUgYXNzaWduZWQgdG8gYSBsaXN0IHRwYXJzIGluIG9yZGVyIHRvIHN0b3JlIGl0cyB2YWx1ZXMgb2YgbnUsIG11LCBhbmQgc2lnbWEgZm9yIGxhdGVyIHVzZToNCg0KICAgIHRmaXQgPC0gZml0LnN0KGZ0c2UpDQogICAgdHBhcnMgPC0gdGZpdCRwYXIuZXN0cw0KICAgIHRwYXJzDQoNCllvdSB3aWxsIGZpdCBhIFN0dWRlbnQgdCBkaXN0cmlidXRpb24gdG8gdGhlIGRhaWx5IGxvZy1yZXR1cm5zIG9mIHRoZSBEb3cgSm9uZXMgaW5kZXggZnJvbSAyMDA4LTIwMTEgY29udGFpbmVkIGluIGRqeC4gVGhlbiwgeW91IHdpbGwgcGxvdCBhIGhpc3RvZ3JhbSBvZiB0aGUgZGF0YSBhbmQgc3VwZXJpbXBvc2UgYSByZWQgbGluZSB0byB0aGUgcGxvdCBzaG93aW5nIHRoZSBmaXR0ZWQgdCBkZW5zaXR5Lg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShRUk0pDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGp4IDwtIGFzLm51bWVyaWMoZGp4KQ0KZGp4IDwtIHNvcnQoZGp4KQ0KIyBGaXQgYSBTdHVkZW50IHQgZGlzdHJpYnV0aW9uIHRvIGRqeA0KdGZpdCA8LSBmaXQuc3QoZGp4KQ0KDQojIERlZmluZSB0cGFycywgbnUsIG11LCBhbmQgc2lnbWENCnRwYXJzIDwtIHRmaXQkcGFyLmVzdHMNCm51IDwtIHRwYXJzWzFdDQptdSA8LSB0cGFyc1syXQ0Kc2lnbWEgPC0gdHBhcnNbM10NCg0KIyBQbG90IGEgaGlzdG9ncmFtIG9mIGRqeA0KaGlzdChkangsIG5jbGFzcyA9IDIwLCBwcm9iYWJpbGl0eSA9IFRSVUUsIHlsaW0gPSByYW5nZSgwLCA0MCkpDQoNCiMgQ29tcHV0ZSB0aGUgZml0dGVkIHQgZGVuc2l0eSBhdCB0aGUgdmFsdWVzIGRqeA0KeXZhbHMgPC0gZHQoKGRqeCAtIG11KS9zaWdtYSwgZGYgPSBudSkvc2lnbWENCg0KIyBTdXBlcmltcG9zZSBhIHJlZCBsaW5lIHRvIHNob3cgdGhlIGZpdHRlZCB0IGRlbnNpdHkNCmxpbmVzKGRqeCwgeXZhbHMsIGNvbCA9ICJyZWQiKQ0KYGBgDQpUaGUgZml0dGVkIFN0dWRlbnQgdCBkaXN0cmlidXRpb24gbG9va3MgYSBsb3QgYmV0dGVyIHRoYW4gdGhlIG5vcm1hbCBkaWQuDQoNCiMjIyBUZXN0aW5nIEZYIHJldHVybnMgZm9yIG5vcm1hbGl0eQ0KDQpTbyBmYXIsIHRoZSBleGVyY2lzZXMgaW4gdGhpcyBjaGFwdGVyIGhhdmUgZXhhbWluZWQgdGhlIG5vcm1hbGl0eSBvZiBlcXVpdHkgaW5kZXggcmV0dXJucyBhbmQgaW5kaXZpZHVhbCBlcXVpdHkgcmV0dXJucy4NCg0KVG8gcmVpbmZvcmNlIHRoZXNlIGlkZWFzLCB5b3Ugd2lsbCBhcHBseSBzaW1pbGFyIGlkZWFzIHRvIGV4Y2hhbmdlLXJhdGUgbG9nLXJldHVybnMuIFRoZSBkYXRhc2V0IGZ4X2QgY29udGFpbnMgZGFpbHkgbG9nLXJldHVybnMgb2YgdGhlIEVVUi9VU0QsIEdCUC9VU0QgYW5kIEpQWS9VU0QgZXhjaGFuZ2UgcmF0ZXMgZm9yIHRoZSBwZXJpb2QgMjAwMS0yMDE1LCBhbmQgdGhlIGRhdGFzZXQgZnhfbSBjb250YWlucyB0aGUgY29ycmVzcG9uZGluZyBtb250aGx5IGxvZy1yZXR1cm5zLg0KV2hpY2ggb2YgdGhlIG1vbnRobHkgbG9nLXJldHVybiBzZXJpZXMgYXBwZWFycyB0aGUgbW9zdCBub3JtYWw/DQpgYGB7cn0NCmRhdGEoIkVVUl9VU0QiKQ0KZGF0YSgiR0JQX1VTRCIpDQpkYXRhKCJKUFlfVVNEIikNCmZ4MSA8LSBFVVJfVVNEWyIyMDAxLzIwMTUiXQ0KZngyIDwtIEdCUF9VU0RbIjIwMDEvMjAxNSJdDQpmeDMgPC0gSlBZX1VTRFsiMjAwMS8yMDE1Il0NCmZ4IDwtIG1lcmdlKGZ4MSwgZngyLCBmeDMpDQpmeF9kIDwtIGFwcGx5KGxvZyhmeCksIDIsIGRpZmYpDQpmeF9tIDwtIGFwcGx5Lm1vbnRobHkoZnhfZCwgY29sU3VtcykNCmBgYA0KDQpgYGB7cn0NCiMgUGxvdCB0aGUgZGFpbHkgbG9nLXJldHVybiBzZXJpZXMgaW4gZnhfZA0KcGxvdC56b28oZnhfZCwgdHlwZSA9ICJoIikNCg0KIyBBcHBseSB0aGUgSmFycXVlLUJlcmEgdGVzdCB0byBlYWNoIG9mIHRoZSBzZXJpZXMgaW4gZnhfZA0KYXBwbHkoZnhfZCwgMiwgamFycXVlLnRlc3QpDQoNCiMgUGxvdCB0aGUgbW9udGhseSBsb2ctcmV0dXJuIHNlcmllcyBpbiBmeF9tDQpwbG90LnpvbyhmeF9tLCB0eXBlID0gImgiKQ0KDQojIEFwcGx5IHRoZSBKYXJxdWUtQmVyYSB0ZXN0IHRvIGVhY2ggb2YgdGhlIHNlcmllcyBpbiBmeF9tDQphcHBseShmeF9tLCAyLCBqYXJxdWUudGVzdCkNCg0KIyBGaXQgYSBTdHVkZW50IHQgZGlzdHJpYnV0aW9uIHRvIGVhY2ggb2YgdGhlIHNlcmllcyBpbiBmeF9tDQphcHBseShmeF9tLCAyLCBmdW5jdGlvbih2KXtmaXQuc3QodikkcGFyLmVzdHN9KQ0KYGBgDQpKUFkvVVNEIGV4Y2hhbmdlIHJhdGUgbG9nLXJldHVybnMgYXBwZWFyIHRvIGJlIHRoZSBtb3N0IG5vcm1hbC4NCg0KIyMjIFRlc3RpbmcgaW50ZXJlc3QtcmF0ZSByZXR1cm5zIGZvciBub3JtYWxpdHkNCg0KVGhlIG9iamVjdCB6Y2J4X20gY29udGFpbnMgbW9udGhseSBsb2ctcmV0dXJuIHNlcmllcyBmb3IgdGhlIDEteWVhciwgNS15ZWFyIGFuZCAxMC15ZWFyIENhbmFkaWFuIHplcm8tY291cG9uIGJvbmQgeWllbGRzLiBUaGUgb2JqZWN0IHpjYngyX20gY29udGFpbnMgdGhlIGNvcnJlc3BvbmRpbmcgc2ltcGxlIHJldHVybnMuIEJvdGggYXJlIG11bHRpdmFyaWF0ZTsgdGhleSBhcmUgbG9hZGVkIGludG8geW91ciB3b3Jrc3BhY2UuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIHBsb3QgdGhlc2UgaW50ZXJlc3QgcmF0ZSByZXR1cm4gc2VyaWVzIGFuZCB0aGVuIGV4YW1pbmUgdGhlaXIgbm9ybWFsaXR5IHdpdGggUS1RIHBsb3RzIGFuZCBKYXJxdWUtQmVyYSB0ZXN0cy4NCg0KVGhlIGxvZy1yZXR1cm5zIHNob3cgY2xlYXJlciBldmlkZW5jZSBvZiBub24tbm9ybWFsaXR5IHRoYW4gdGhlIHNpbXBsZSByZXR1cm5zIGluIHRoaXMgY2FzZS4NCg0KYGBge3J9DQpkYXRhKCJaQ0JfQ0FEIikNCnpjYiA8LSBaQ0JfQ0FEWyxjKCIxLjAweSIsICI1LjAweSIsICIxMC4wMHkiKV0NCnpjYnggPC0gZGlmZihsb2coemNiKSkNCnpjYngyIDwtIGRpZmYoemNiKQ0KemNieF9tIDwtIGFwcGx5Lm1vbnRobHkoemNieCwgY29sU3VtcylbIjIwMDYvMjAxNSJdDQp6Y2J4Ml9tPC0gYXBwbHkubW9udGhseSh6Y2J4MiwgY29sU3VtcylbIjIwMDYvMjAxNSJdDQpgYGANCg0KYGBge3J9DQojIFBsb3QgdGhlIGludGVyZXN0LXJhdGUgcmV0dXJuIHNlcmllcyB6Y2J4X20gYW5kIHpjYngyX20NCnBsb3Quem9vKHpjYnhfbSwgdHlwZSA9ICJoIikNCnBsb3Quem9vKHpjYngyX20sIHR5cGUgPSAiaCIpDQoNCiMgTWFrZSBRLVEgcGxvdHMgb2YgdGhlIDNyZCBjb21wb25lbnQgc2VyaWVzIG9mIHpjYnhfbSBhbmQgemNieDJfbQ0KcXFub3JtKHpjYnhfbVssM10pDQpxcW5vcm0oemNieDJfbVssM10pDQoNCiMgQ29tcHV0ZSB0aGUga3VydG9zaXMgb2YgZWFjaCBzZXJpZXMgaW4gemNieF9tIGFuZCB6Y2J4Ml9tDQphcHBseSh6Y2J4X20sIDIsIGt1cnRvc2lzKQ0KYXBwbHkoemNieDJfbSwgMiwga3VydG9zaXMpDQoNCiMgQ29uZHVjdCB0aGUgSmFycXVlLUJlcmEgdGVzdCBvbiBlYWNoIHNlcmllcyBpbiB6Y2J4X20gYW5kIHpjYngyX20NCmFwcGx5KHpjYnhfbSwgMiwgamFycXVlLnRlc3QpDQphcHBseSh6Y2J4Ml9tLCAyLCBqYXJxdWUudGVzdCkNCmBgYA0KTm90ZSBob3cgdGhlIHNpbXBsZSBtb250aGx5IHJldHVybnMgZm9yIHRoZSA1IGFuZCAxMCB5ZWFyIHlpZWxkcyBkaWQgbm90IGZhaWwgdGhlIG5vcm1hbGl0eSB0ZXN0Lg0KDQojIyMgVGVzdGluZyBnb2xkIHByaWNlIHJldHVybnMgZm9yIG5vcm1hbGl0eQ0KDQpUaGUgb2JqZWN0IGdvbGR4X3EgY29udGFpbnMgcXVhcnRlcmx5IGxvZy1yZXR1cm5zIG9mIHRoZSBnb2xkIHByaWNlIGZyb20gdGhlIGJlZ2lubmluZyBvZiAxOTkwIHRvIHRoZSBlbmQgb2YgMjAxNS4NCg0KVGVzdCB0aGUgZGF0YSBmb3Igbm9ybWFsaXR5IHVzaW5nIHRoZSBKYXJxdWUtQmVyYSB0ZXN0LCB0aGVuIGZpdCBhIFN0dWRlbnQgdCBkaXN0cmlidXRpb24gYW5kIGZpbmQgdGhlIGVzdGltYXRlZCBkZWdyZWUgb2YgZnJlZWRvbSDOvV4gdG8gdGhlIG5lYXJlc3QgaW50ZWdlci4NCg0KYGBge3J9DQpkYXRhKCJHT0xEIikNCmdvbGQgPC0gR09MRFsiMTk5MC8yMDE1Il0NCmdvbGR4IDwtIGRpZmYobG9nKGdvbGQpKVstMV0NCmdvbGR4X3EgPC0gYXMubnVtZXJpYyhhcHBseS5xdWFydGVybHkoZ29sZHgsIHN1bSlbLDFdKQ0KamFycXVlLnRlc3QoZ29sZHhfcSkNCg0KdGZpdCA8LSBmaXQuc3QoZ29sZHhfcSkNCg0KdHBhcnMgPC0gdGZpdCRwYXIuZXN0cw0KDQp0cGFyc1sxXQ0KYGBgDQpUaGUgZGF0YSBmYWlsIGEgdGVzdCBvZiBub3JtYWxpdHkgYW5kICRcaGF0e1xudX09MTAkDQoNCiMgUmVhbCB3b3JsZCByZXR1cm5zIGFyZSB2b2xhdGlsZSBhbmQgY29ycmVsYXRlZA0KDQojIyBDaGFyYWN0ZXJpc3RpY3Mgb2Ygdm9sYXRpbGUgcmV0dXJuIHNlcmllcw0KDQpJbiB0aGlzIGV4ZXJjaXNlIHlvdSB3aWxsIHBsb3QgdGhlIERvdyBKb25lcyBsb2ctcmV0dXJucyBmb3IgMjAwOC0yMDExIGFsb25nc2lkZSBpbmRlcGVuZGVudCBhbmQgaWRlbnRpY2FsbHkgZGlzdHJpYnV0ZWQgKGlpZCkgbm9ybWFsIGRhdGEgYW5kIGlpZCBTdHVkZW50IHQgZGF0YS4NCg0KVGhlIHh0cyBvYmplY3QgZGp4IGNvbnRhaW5zIHRoZSBEb3cgSm9uZXMgaW5kZXggYW5kIHRoZSBvYmplY3RzIG5wYXJzIGFuZCB0cGFycyBjb250YWluIHRoZSBwYXJhbWV0ZXIgZXN0aW1hdGVzIHRoYXQgYXJlIG9idGFpbmVkIHdoZW4gYSBub3JtYWwgZGlzdHJpYnV0aW9uIGFuZCBhIHQgZGlzdHJpYnV0aW9uIGFyZSBmaXR0ZWQgdG8gZGp4Lg0KeW91IHdpbGwgZ2VuZXJhdGUgYSBub3JtYWwgc2FtcGxlIGZyb20gdGhlIGZpdHRlZCBtb2RlbCBieSBnZW5lcmF0aW5nIHN0YW5kYXJkIG5vcm1hbCBkYXRhLCBzY2FsaW5nIHRoZW0gd2l0aCB0aGUgc2Vjb25kIGNvbXBvbmVudCBucGFyc1syXSBhbmQgc2hpZnRpbmcgdGhlbSB3aXRoIHRoZSBmaXJzdCBjb21wb25lbnQgbnBhcnNbMV0uIEZvciB0aGUgU3R1ZGVudCB0IHNhbXBsZSB5b3Ugd2lsbCBkbyBzb21ldGhpbmcgc2ltaWxhciBidXQgbm90ZSB0aGF0IHRoaXMgdGltZSB0aGUgZmlyc3QgY29tcG9uZW50IHRwYXJzWzFdIGNvbnRhaW5zIHRoZSBkZWdyZWUgb2YgZnJlZWRvbSBwYXJhbWV0ZXIgYW5kIHRwYXJzWzJdIGFuZCB0cGFyc1szXSBjb250YWluIHRoZSBsb2NhdGlvbiBhbmQgc2NhbGUgcGFyYW1ldGVycy4NCg0KQWZ0ZXIgbWFraW5nIHRoZSBwbG90cywgeW91IHNob3VsZCBjb21wYXJlIHRoZSBiZWhhdmlvciBvZiB0aGUgcmVhbCByZXR1cm5zIHdpdGggdGhhdCBvZiB0aGUgaWlkIHJldHVybnMsIHBhcnRpY3VsYXJseSBhcm91bmQgdGhlIDIwMDggZmluYW5jaWFsIGNyaXNpcy4NCmBgYHtyfQ0KZGp4IDwtIERKWyIyMDA3LTEyLTMxLzIwMTEtMTItMzEiXQ0KZGp4IDwtIGRpZmYobG9nKGRqeCkpWy0xXQ0KbnBhcnMgPC0gYyhtdSA9IG1lYW4oZGp4KSwgc2lnbWEgPSBzZChkangpKQ0KdGZpdCA8LSBmaXQuc3QoZGp4KQ0KdHBhcnMgPC0gdGZpdCRwYXIuZXN0cw0KYGBgDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCiMgQ29tcHV0ZSB0aGUgbGVuZ3RoIG4gb2YgZGp4IA0KbiA8LSBsZW5ndGgoZGp4KQ0KDQojICBHZW5lcmF0ZSBhIG5vcm1hbCBzYW1wbGUgb2Ygc2l6ZSBuIHdpdGggcGFyYW1ldGVycyBnaXZlbiBieSBucGFycw0KbmRhdGEgPC0gcm5vcm0obikqbnBhcnNbMl0gKyBucGFyc1sxXQ0KDQojIEdlbmVyYXRlIGEgdC1kaXN0cmlidXRlZCBzYW1wbGUgb2Ygc2l6ZSBuIHdpdGggcGFyYW1hdGVycyBnaXZlbiBieSB0cGFycw0KdGRhdGEgPC0gcnQobiwgZGYgPSB0cGFyc1sxXSkqdHBhcnNbM10gKyB0cGFyc1syXQ0KDQojIE1ha2UgbmRhdGEgYW5kIHRkYXRhIGludG8geHRzIG9iamVjdHMNCm5kYXRheCA8LSB4dHMobmRhdGEsIHRpbWUoZGp4KSkNCnRkYXRheCA8LSB4dHModGRhdGEsIHRpbWUoZGp4KSkNCg0KIyBNZXJnZSBkangsIG5kYXRheCwgYW5kIHRkYXRheCBhbmQgcGxvdA0KYWxsZGF0YSA8LSBtZXJnZShkangsIG5kYXRheCwgdGRhdGF4KQ0KcGxvdC56b28oYWxsZGF0YSwgdHlwZSA9ICJoIiwgeWxpbSA9IHJhbmdlKGFsbGRhdGEpKQ0KYGBgDQpOb3RlIGhvdyB0aGUgcmVhbCByZXR1cm5zIGxvb2sgbW9yZSB2b2xhdGlsZSB0aGFuIHRoZSBpaWQgcmV0dXJucy4gVGhlcmUgd2FzIGNsZWFybHkgYSBwZXJpb2Qgb2YgbGFyZ2UgbW92ZW1lbnRzIGFyb3VuZCB0aGUgMjAwOCBmaW5hbmNpYWwgY3Jpc2lzIGZvbGxvd2VkIGJ5IGEgcXVpZXRlciBwZXJpb2QgaW4gMjAxMC4NCg0KIyMgRXN0aW1hdGluZyBzZXJpYWwgY29ycmVsYXRpb25zDQoNCiMjIyBVc2luZyBhY2YgcGxvdHMgdG8gcmV2ZWFsIHZvbGF0aWxpdHkNCg0KVGhpcyBleGVyY2lzZSBmb2xsb3dzIG9uIGZyb20gdGhlIHByZXZpb3VzIFIgZXhlcmNpc2Ugd2hlcmUgd2UgbG9va2VkIGZvciB2aXNpYmxlIHNpZ25zIG9mIHZvbGF0aWxpdHkgaW4gYSBmaW5hbmNpYWwgdGltZSBzZXJpZXMuIEZvciB0aGUgRG93IEpvbmVzIHJldHVybnMgZnJvbSAyMDA4LTExIGluIGRqeCBhbmQgdGhlIHNpbXVsYXRlZCBub3JtYWwgYW5kIHQtZGlzdHJpYnV0ZWQgZGF0YSBpbiBuZGF0YSBhbmQgdGRhdGEsIHJlc3BlY3RpdmVseSwgeW91IHdpbGwgY2FsY3VsYXRlIGFuZCBwbG90IHRoZSBzYW1wbGUgYXV0b2NvcnJlbGF0aW9uIGZ1bmN0aW9ucyAoYWNmKSB1c2luZyB0aGUgY29tbWFuZCBhY2YoKS4NCg0KV2hpbGUgdmVyeSBsaXR0bGUgZXZpZGVuY2Ugb2Ygc2VyaWFsIGNvcnJlbGF0aW9uIGlzIGZvdW5kIGluIHRoZXNlIHBsb3RzLCB0aGUgcGljdHVyZSBjaGFuZ2VzIGRyYW1hdGljYWxseSB3aGVuIHdlIGxvb2sgYXQgYWJzb2x1dGUgb3Igc3F1YXJlZCByZXR1cm4gZGF0YS4gVGhlIHJlYWwgcmV0dXJucyBpbiB0aGUgRG93IEpvbmVzIHJldHVybiBzZXJpZXMgZGp4IGJlaGF2ZSB2ZXJ5IGRpZmZlcmVudGx5IHRvIHRoZSBzaW11bGF0ZWQgZGF0YS4gVGhlIHNlcmlhbCBjb3JyZWxhdGlvbiBpbiBhYnNvbHV0ZSBvciBzcXVhcmVkIHJldHVybnMgaXMgYSBjb25zZXF1ZW5jZSBvZiB2b2xhdGlsaXR5LCB3aGljaCBjYXVzZXMgbGFyZ2UgcmV0dXJucyB0byBiZSBmb2xsb3dlZCBieSBmdXJ0aGVyIGxhcmdlIHJldHVybnMsIGFsdGhvdWdoIG5vdCBuZWNlc3NhcmlseSBvZiB0aGUgc2FtZSBzaWduLg0KYGBge3J9DQojIFNldCB1cCBhIHBsb3QgcmVnaW9uIHRvIHNob3cgMyBwbG90cyBhdCBhIHRpbWUNCnBhcihtZnJvdyA9IGMoMywgMSkpDQoNCiMgUGxvdCB0aGUgYWNmcyBvZiBkangsIG5kYXRhIGFuZCB0ZGF0YQ0KYWNmKGRqeCkNCmFjZihuZGF0YSkNCmFjZih0ZGF0YSkNCg0KIyBQbG90IHRoZSBhY2ZzIG9mIHRoZSBhYnNvbHV0ZSB2YWx1ZXMNCmFjZihhYnMoZGp4KSkNCmFjZihhYnMobmRhdGEpKQ0KYWNmKGFicyh0ZGF0YSkpDQoNCiMgUGxvdCB0aGUgYWNmcyBvZiB0aGUgc3F1YXJlcyBvZiB0aGUgdmFsdWVzDQphY2YoZGp4XjIpDQphY2YobmRhdGFeMikNCmFjZih0ZGF0YV4yKQ0KYGBgDQpJdCBpcyB2ZXJ5IGNvbW1vbiB0byBzZWUgc3Ryb25nIHNlcmlhbCBjb3JyZWxhdGlvbiBpbiBhYnNvbHV0ZSBhbmQgc3F1YXJlZCByZXR1cm4gc2VyaWVzLg0KDQojIyBUaGUgTGp1bmctQm94IHRlc3QNCg0KIyMjIEFwcGx5aW5nIExqdW5nLUJveCB0ZXN0cyB0byByZXR1cm4gZGF0YQ0KDQpUaGlzIGNvZGUgYXBwbGllcyB0aGUgTGp1bmctQm94IHRlc3QgdG8gdGhlIGZ0c2UgZGF0YSB3aXRoIGEgbGFnIG9mIDEwOg0KDQogICAgQm94LnRlc3QoZnRzZSwgbGFnID0gMTAsIHR5cGUgPSAiTGp1bmciKQ0KICAgIA0KWW91IHdpbGwgY2Fycnkgb3V0IGEgTGp1bmctQm94IHRlc3QgZm9yIHNlcmlhbCBjb3JyZWxhdGlvbiBvbiB0aGUgdGltZSBzZXJpZXMgZGp4IHdoaWNoIGNvbnRhaW5zIHRoZSBEb3cgSm9uZXMgZGFpbHkgaW5kZXggcmV0dXJucyBmb3IgMjAwOC0yMDExLCBhcyB3ZWxsIGFzIG9uIGFsbCB0aGUgaW5kaXZpZHVhbCBlcXVpdHkgcmV0dXJuIHNlcmllcyBpbiBkamFsbCB3aGljaCBjb250YWlucyB0aGUgRG93IEpvbmVzIGRhdGEgZm9yIDIwMDYtMjAxNS4gWW91IHdpbGwgaW1wbGVtZW50IHRoaXMgdGVzdCBvbiBib3RoIHRoZSByYXcgcmV0dXJuIHNlcmllcyBhbmQgdGhlIGFic29sdXRlIHZhbHVlcyBvZiB0aGUgc2VyaWVzLCB3aGljaCB5b3UgY2FuIGNhbGN1bGF0ZSB3aXRoIGFicygpLg0KDQpZb3Ugc2hvdWxkIG5vdGljZSB0aGF0IHdoaWxlIHRoZSBoeXBvdGhlc2lzIG9mIG5vIHNlcmlhbCBjb3JyZWxhdGlvbiBpcyByZWplY3RlZCBmb3IgbWFueSBvZiB0aGUgcmF3IHJldHVybiBzZXJpZXMsIGl0IGlzIHJlamVjdGVkIG92ZXJ3aGVsbWluZ2x5IGZvciBhbGwgb2YgdGhlIGFic29sdXRlIHZhbHVlIHNlcmllcy4NCmBgYHtyfQ0KZGphbGwgPC0gREpfY29uc3RbIjIwMDYtMTItMzEvMjAxNS0xMi0zMSJdDQpkamFsbCA8LSBkaWZmKGxvZyhkamFsbCkpWy0xXQ0KYGBgDQoNCmBgYHtyfQ0KIyBBcHBseSB0aGUgTGp1bmctQm94IHRlc3QgdG8gZGp4DQpCb3gudGVzdChkangsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCg0KIyBBcHBseSB0aGUgTGp1bmctQm94IHRlc3QgdG8gYWJzb2x1dGUgdmFsdWVzIG9mIGRqeA0KQm94LnRlc3QoYWJzKGRqeCksIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCg0KIyBBcHBseSB0aGUgTGp1bmctQm94IHRlc3QgdG8gYWxsIHJldHVybiBzZXJpZXMgaW4gZGphbGwNCmFwcGx5KGRqYWxsLCAyLCBCb3gudGVzdCwgbGFnID0gMTAsIHR5cGUgPSAiTGp1bmciKQ0KDQojIEFwcGx5IHRoZSBManVuZy1Cb3ggdGVzdCB0byBhYnNvbHV0ZSB2YWx1ZXMgb2YgYWxsIHJldHVybnMgaW4gZGphbGwNCmFwcGx5KGFicyhkamFsbCksIDIsIEJveC50ZXN0LCBsYWcgPSAxMCwgdHlwZSA9ICJManVuZyIpDQpgYGANCk5vdGUgdGhhdCB0aGUgTGp1bmctQm94IHRlc3QgZGlkIG5vdCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB3aGVuIGFwcGxpZWQgdG8gdGhlIHJhdyByZXR1cm5zIGZvciBBQVBMLCBDQVQsIENTQ08gYW5kIEhELg0KDQojIyMgQXBwbHlpbmcgTGp1bmctQm94IHRlc3RzIHRvIGxvbmdlci1pbnRlcnZhbCByZXR1cm5zDQoNCldoYXQgaGFwcGVucyB3aGVuIHlvdSBhcHBseSB0aGUgc2FtZSBhbmFseXNlcyBhcyBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UgdG8gdGhlIG1vbnRobHkgcmV0dXJucyByYXRoZXIgdGhhbiB0aGUgZGFpbHkgcmV0dXJucz8gRG9lcyB0aGUgYW1vdW50IG9mIHNlcmlhbCBkZXBlbmRlbmNlIGluIHRoZSBkYXRhIGFwcGVhciB0byBpbmNyZWFzZSBvciBkZWNyZWFzZT8NCg0KYGBge3J9DQojIENyZWF0ZSBtb250aGx5IGxvZy1yZXR1cm5zIGZyb20gZGp4DQpkanhfbSA8LSBhcHBseS5tb250aGx5KGRqeCwgc3VtKQ0KDQojIEFwcGx5IExqdW5nLUJveCB0ZXN0cyB0byByYXcgYW5kIGFic29sdXRlIHZhbHVlcyBvZiBkanhfbQ0KQm94LnRlc3QoZGp4X20sIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCkJveC50ZXN0KGFicyhkanhfbSksIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCg0KIyBDcmVhdGUgbW9udGhseSBsb2ctcmV0dXJucyBmcm9tIGRqYWxsDQpkamFsbF9tIDwtIGFwcGx5Lm1vbnRobHkoZGphbGwsIGNvbFN1bXMpDQoNCiMgQXBwbHkgTGp1bmctQm94IHRlc3RzIHRvIHJhdyBhbmQgYWJzb2x1dGUgdmFsdWVzIG9mIGRqYWxsX20NCmFwcGx5KGRqYWxsX20sIDIsIEJveC50ZXN0LCBsYWcgPSAxMCwgdHlwZSA9ICJManVuZyIpDQphcHBseShhYnMoZGphbGxfbSksIDIsIEJveC50ZXN0LCBsYWcgPSAxMCwgdHlwZSA9ICJManVuZyIpDQpgYGANClRoZSBhbW91bnQgb2Ygc2VyaWFsIGRlcGVuZGVuY2UgYXBwZWFycyB0byBkZWNyZWFzZSB3aGVuIHdlIG1vdmUgZnJvbSBkYWlseSB0byBtb250aGx5IHJldHVybnMuDQoNCiMjIExvb2tpbmcgYXQgdGhlIGV4dHJlbWVzIGluIHZvbGF0aWxlIHJldHVybiBzZXJpZXMNCg0KIyMjIEV4dHJlbWUgdmFsdWVzIGluIHZvbGF0aWxlIHRpbWUgc2VyaWVzDQoNCldoZW4geW91IHRha2UgYSBsb25nIHNlcmllcyBvZiBpaWQgZGF0YSwgc3VjaCBhcyBzZXZlcmFsIHRob3VzYW5kIG9ic2VydmF0aW9ucywgYW5kIHNlbGVjdCBhIHNtYWxsIHN1YnNldCBvZiB0aGUgbW9zdCBleHRyZW1lIG9ic2VydmF0aW9ucywgbGlrZSBsZXNzIHRoYW4gMTAwLCB0aGVuIHRoZXNlIGV4dHJlbWVzIGFwcGVhciBhdCByYW5kb20gYW5kIHRoZSBzcGFjZXMgb3IgZ2FwcyBiZXR3ZWVuIHRoZSBleHRyZW1lcyBmb2xsb3cgYSBkaXN0cmlidXRpb24gdGhhdCBpcyB2ZXJ5IGNsb3NlIHRvIGV4cG9uZW50aWFsLiBXaGVuIHdlIGNhcnJ5IG91dCB0aGUgc2FtZSBleGVyY2lzZSBmb3IgYSB2b2xhdGlsZSBmaW5hbmNpYWwgbG9nLXJldHVybiBzZXJpZXMgdGhlbiB0aGUgZXh0cmVtZXMgYXBwZWFyIGluIGNsdXN0ZXJzIGR1cmluZyBwZXJpb2RzIG9mIGhpZ2ggdm9sYXRpbGl0eS4gVGhpcyBpcyBhbm90aGVyIGZlYXR1cmUgb2YgcmVhbCBsb2ctcmV0dXJuIGRhdGEgdGhhdCB3ZSBuZWVkIHRvIHRha2UgYWNjb3VudCBvZiB3aGVuIGJ1aWxkaW5nIG1vZGVscy4NCg0KWW91IHdpbGwgaW52ZXN0aWdhdGUgdGhlIGlycmVndWxhciB0aW1lIHNlcmllcyBkanhfZXh0cmVtZXMgd2hpY2ggY29udGFpbnMgdGhlIDEwMCBtb3N0IGV4dHJlbWUgbmVnYXRpdmUgbG9nLXJldHVybnMgb2YgdGhlIERvdyBKb25lcyBpbmRleCBiZXR3ZWVuIDE5ODUgYW5kIDIwMTUuIFlvdSB3aWxsIGNvbXBhcmUgaXQgd2l0aCBpaWRfZXh0cmVtZXMgd2hpY2ggY29udGFpbnMgdGhlIDEwMCBtb3N0IGV4dHJlbWUgdmFsdWVzIGluIGFuIGlpZCBzZXJpZXMgb2YgdGhlIHNhbWUgbGVuZ3RoIGFzIGRqeF9leHRyZW1lcy4gVG8gZG8gdGhpcywgeW91IHdpbGwgdXNlIHRoZSBvYmplY3QgZXhwX3F1YW50aWxlcywgd2hpY2ggY29udGFpbnMgMTAwIHRoZW9yZXRpY2FsIHF1YW50aWxlcyBvZiB0aGUgc3RhbmRhcmQgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLiBUaGVzZSBjYW4gYmUgdXNlZCB0byBjb25zdHJ1Y3QgYSBRLVEgcGxvdCBvZiBlYWNoIGRhdGFzZXQgYWdhaW5zdCB0aGUgZXhwb25lbnRpYWwgcmVmZXJlbmNlIGRpc3RyaWJ1dGlvbi4NCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KDQojbG9hZCBkYXRhIGFuZCBnZXQgbG9nIHJldHVybnMNCmRqcmV0dXJucyA8LSBkaWZmKGxvZyhESikpWy0xXQ0KDQojZ2V0IG1lYW4gYW5kIHNpZ21hIHRvIGdlbmVyYXRlIG5vcm1hbCBkaXN0cmlidXRpb24NCm5wYXJzIDwtIGMobXUgPSBtZWFuKGRqcmV0dXJucyksIHNpZ21hID0gc2QoZGpyZXR1cm5zKSkNCm4gPC0gbGVuZ3RoKGRqcmV0dXJucykNCg0KI2NhbGN1bGF0ZSBleHRyZW1lIGxvc3Nlcw0KZGpfbG9zc2VzIDwtIC1kanJldHVybnMNCmRqeF9leHRyZW1lcyA8LSBkal9sb3NzZXNbZGpfbG9zc2VzPjAuMDI3NF0NCg0KI2NhbGN1bGF0ZSBleHRyZW1lIGxvc3NlcyBvbiBpaWQgZGlzdA0KaWlkIDwtIHJub3JtKG4pKm5wYXJzWzJdICsgbnBhcnNbMV0NCmlpZCA8LSBhcy54dHMoaWlkLCBvcmRlci5ieSA9IGluZGV4KGRqcmV0dXJucykpDQppaWRfbG9zc2VzIDwtIC1paWQNCmlpZF9leHRyZW1lcyA8LSBpaWRfbG9zc2VzW2lpZF9sb3NzZXM+MC4wMjQ1OV0NCg0KI2dldCAxMDAgdGhlcm9pY2FsIHF1YW50aWxlcyBvZiB0aGUgc3RhbmRhciBleHBvbmVudGlhbCBkaXN0cmlidXRpb24NCmV4cF9xdWFudGlsZXMgPC0gcWV4cChwcG9pbnRzKDEwMCkpDQpgYGANCg0KDQpgYGB7cn0NCiMgUGFydGl0aW9uIHBsb3R0aW5nIGFyZWEgaW50byAzIHBpZWNlcw0KcGFyKG1mcm93ID0gYygxLCAzKSkNCg0KIyBQbG90IGRqeF9leHRyZW1lcw0KcGxvdChkanhfZXh0cmVtZXMsIHR5cGUgPSAiaCIpDQoNCiMgQ29tcHV0ZSB0aGUgc3BhY2VzIGJldHdlZW4gdGhlIHRpbWVzIG9mIHRoZSBleHRyZW1lcw0KZGp4X3NwYWNlcyA8LSBkaWZmKHRpbWUoZGp4X2V4dHJlbWVzKSkNCg0KIyBNYWtlIGEgaGlzdG9ncmFtIG9mIHRoZXNlIHNwYWNlcw0KaGlzdChhcy5udW1lcmljKGRqeF9zcGFjZXMpKQ0KDQojIE1ha2UgYSBRLVEgcGxvdCBvZiBkanhfc3BhY2VzIGFnYWluc3QgZXhwX3F1YW50aWxlcw0KcXFwbG90KGV4cF9xdWFudGlsZXMsIGRqeF9zcGFjZXMpDQoNCiMgQ2Fycnkgb3V0IHRoZSBwcmV2aW91cyA0IHN0ZXBzIGZvciBpaWRfZXh0cmVtZXMNCnBsb3QoaWlkX2V4dHJlbWVzLCB0eXBlID0gImgiKQ0KaWlkX3NwYWNlcyA8LSBkaWZmKHRpbWUoaWlkX2V4dHJlbWVzKSkNCmhpc3QoYXMubnVtZXJpYyhpaWRfc3BhY2VzKSkNCnFxcGxvdChleHBfcXVhbnRpbGVzLCBpaWRfc3BhY2VzKQ0KYGBgDQpOb3RlIGhvdyBzdHJvbmdseSBjbHVzdGVyZWQgdGhlIGV4dHJlbWUgcmV0dXJucyBhcmUgY29tcGFyZWQgd2l0aCB0aGUgZXh0cmVtZXMgaW4gdGhlIGlpZCBzZXJpZXMuDQoNCiMjIyBDcm9zcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiByaXNrLWZhY3RvciByZXR1cm4gc2VyaWVzDQoNCk1hbnkgcmlzay1mYWN0b3IgcmV0dXJucyBhcmUgY29ycmVsYXRlZCB3aXRoIGVhY2ggb3RoZXIgaW4gdGhlIHNhbWUgdGltZSBwZXJpb2QuIEhvd2V2ZXIsIGluIHRoZSBzYW1lIHdheSB0aGF0IHRoZXJlIHRlbmRzIHRvIGJlIG9ubHkgd2VhayBzZXJpYWwgY29ycmVsYXRpb24gd2l0aGluIHNlcmllcywgdGhlcmUgdGVuZHMgdG8gYmUgb25seSB3ZWFrIGNyb3NzIGNvcnJlbGF0aW9uIGJldHdlZW4gc2VyaWVzIGluIGRpZmZlcmVudCB0aW1lIHBlcmlvZHMuDQoNClRoZSBwaWN0dXJlIGNoYW5nZXMgZHJhbWF0aWNhbGx5IHdoZW4gd2UgbG9vayBhdCB0aGUgYWJzb2x1dGUgdmFsdWVzLCB3aGljaCBhcmUgb2Z0ZW4gc3Ryb25nbHkgY29ycmVsYXRlZCBib3RoIHdpdGhpbiBhbmQgYmV0d2VlbiBzZXJpZXMuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGludmVzdGlnYXRlIGNyb3NzIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBkYWlseSBsb2ctcmV0dXJucyBvZiB0aGUgRG93IEpvbmVzLCBGVFNFMTAwIGFuZCBTTUkgZXF1aXR5IGluZGV4ZXMuIFdoZW4gdGhlIGZ1bmN0aW9uIGFjZigpIGlzIGFwcGxpZWQgdG8gYSBtdWx0aXZhcmlhdGUgdGltZSBzZXJpZXMsIHdlIG9idGFpbiBhIG1hdHJpeCBvZiBwbG90cyB3aXRoIHRoZSB1c3VhbCBzYW1wbGUgYWNmIHBsb3RzIG9uIHRoZSBkaWFnb25hbCwgYW5kIHBsb3RzIG9mIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBkaWZmZXJlbnQgc2VyaWVzIGF0IGRpZmZlcmVudCBsYWdzIG9mZiB0aGUgZGlhZ29uYWwuDQoNCk9uZSB0aGluZyB0byBub3RlIGhlcmUgaXMgdGhhdCB0aGUgVVMgYW5kIEV1cm9wZWFuIHNlcmllcyBhcmUgc2xpZ2h0bHkgb3V0IG9mIHN0ZXAuIFRoZSBFdXJvcGVhbiBtYXJrZXRzIHRlbmQgdG8gZm9sbG93IHRoZSBVUywgc28gd2Ugc2VlIHNvbWUgZXZpZGVuY2Ugb2YgY3Jvc3MgY29ycmVsYXRpb24gYmV0d2VlbiBVUyByZXR1cm5zIG9uIG9uZSBkYXkgYW5kIEV1cm9wZWFuIHJldHVybnMgb24gdGhlIG5leHQuDQpgYGB7cn0NCmRhdGEoIlNNSSIpDQpkYXRhKCJGVFNFIikNCnNtaXggPC0gZGlmZihsb2coU01JKSlbLTFdWyIyMDA1LzIwMTUiXQ0KZnRzZXggPC0gZGlmZihsb2coRlRTRSkpWy0xXVsiMjAwNS8yMDE1Il0NCmRqeCA8LSBkaWZmKGxvZyhESikpWy0xXVsiMjAwNS8yMDE1Il0NCmluZGV4ZXMgPC0gbWVyZ2UoZGp4LCBmdHNleCwgc21peCwgYWxsID0gVFJVRSkNCmluZGV4ZXMgPC0gbmEub21pdChpbmRleGVzKSANCmBgYA0KDQpgYGB7cn0NCiMgTWFrZSBhIHRpbWUgc2VyaWVzIHBsb3Qgb2YgaW5kZXhlcyB3aXRoIHBsb3Quem9vIGFuZCBhIHBhaXJ3aXNlIHNjYXR0ZXJwbG90IHdpdGggcGFpcnMNCnBsb3Quem9vKGluZGV4ZXMpDQpwYWlycyhhcy56b28oaW5kZXhlcykpDQoNCiMgQ2FsY3VsYXRlIHRoZSBzYW1wbGUgY29ycmVsYXRpb24gbWF0cml4IG9mIGluZGV4ZXMNCmNvcihpbmRleGVzKQ0KDQojIFBsb3QgdGhlIHNhbXBsZSBhY2ZzIGFuZCBjcm9zcy1jb3JyZWxhdGlvbiBmdW5jdGlvbnMgZm9yIHRoZSByZXR1cm5zIGluIGluZGV4ZXMNCmFjZihpbmRleGVzKQ0KDQojIFBsb3QgdGhlIHNhbXBsZSBhY2ZzIGFuZCBjcm9zcy1jb3JyZWxhdGlvbnMgZnVuY3Rpb25zIGZvciB0aGUgYWJzb2x1dGUgdmFsdWVzIG9mIGluZGV4ZXMNCmFjZihhYnMoaW5kZXhlcykpDQpgYGANCkRvIHlvdSBzZWUgdGhlIGV2aWRlbmNlIHRoYXQgdGhlIFVTIG1hcmtldCBsZWFkcyB0aGUgRXVyb3BlYW4gbWFya2V0cyBpbiB0aGUgdGhpcmQgb2YgdGhlIGZvdXIgcGxvdHM/DQoNCiMjIFRoZSBzdHlsaXplZCBmYWN0cyBvZiByZXR1cm4gc2VyaWVzDQoNCiMjIyBWb2xhdGlsaXR5IGFuZCBjb3JyZWxhdGlvbiBvZiBGWCByZXR1cm5zDQoNCllvdSB3aWxsIGRpc2NvdmVyIGV2aWRlbmNlIG9mIHZvbGF0aWxpdHkgYW5kIHNlcmlhbCBkZXBlbmRlbmNlIGluIGRhaWx5IGFuZCB3ZWVrbHkgZXhjaGFuZ2UtcmF0ZSBsb2ctcmV0dXJucy4gVGhlIGRhdGFzZXQgZnggY29udGFpbnMgZGFpbHkgbG9nLXJldHVybnMgZm9yIHRoZSAiRVVSX1VTRCIsICJHQlBfVVNEIiwgIkpQWV9VU0QiIGFuZCAiQ0hGX1VTRCIgZXhjaGFuZ2UgcmF0ZXMgd2hpbGUgZnhfdyBjb250YWlucyB0aGUgY29ycmVzcG9uZGluZyB3ZWVrbHkgbG9nLXJldHVybnMuIEJvdGggYXJlIGluIHlvdXIgd29ya3NwYWNlLg0KDQpOb3RlIHRoYXQgZm9yZWlnbiBleGNoYW5nZSB0cmFkaW5nIHRha2VzIHBsYWNlIGV2ZXJ5IGRheSBvZiB0aGUgd2VlayBhbHRob3VnaCB0aGUgbG93ZXIgdm9sdW1lIG9mIHRyYWRpbmcgYXQgd2Vla2VuZHMgbGVhZHMgdG8gYW4gdW51c3VhbCB3ZWVrbHkgY29ycmVsYXRpb24gY3ljbGUgd2hpY2ggd2lsbCBiZSBldmlkZW50IGluIG9uZSBvZiB0aGUgcGljdHVyZXMgeW91IGNyZWF0ZS4NCmBgYHtyfQ0KZGF0YSgiQ0hGX1VTRCIpDQpmeDEgPC0gZGlmZihsb2coRVVSX1VTRCkpWy0xXVsiMjAxMS8yMDE2Il0NCmZ4MiA8LSBkaWZmKGxvZyhHQlBfVVNEKSlbLTFdWyIyMDExLzIwMTYiXQ0KZngzIDwtIGRpZmYobG9nKEpQWV9VU0QpKVstMV1bIjIwMTEvMjAxNiJdDQpmeDQgPC0gZGlmZihsb2coQ0hGX1VTRCkpWy0xXVsiMjAxMS8yMDE2Il0NCmZ4IDwtIG1lcmdlKGZ4MSwgZngyLCBmeDMsIGZ4NCwgYWxsID0gVFJVRSkNCmZ4X3c8LSBhcHBseS53ZWVrbHkoZngsIGNvbFN1bXMpDQpgYGANCg0KYGBge3J9DQojIFBsb3QgZnggYW5kIGZ4X3cNCnBsb3Quem9vKGZ4LCB0eXBlID0gImgiKQ0KcGxvdC56b28oZnhfdywgdHlwZSA9ICJoIikNCg0KIyBNYWtlIGFjZiBwbG90cyBvZiBmeCBhbmQgdGhlIGFic29sdXRlIHZhbHVlcyBvZiBmeA0KYWNmKGZ4KQ0KYWNmKGFicyhmeCkpDQoNCg0KIyBBcHBseSB0aGUgTGp1bmctQm94IHRlc3QgdG8gdGhlIGNvbXBvbmVudHMgb2YgZnggYW5kIHRoZWlyIGFic29sdXRlIHZhbHVlcw0KYXBwbHkoZngsIDIsIEJveC50ZXN0LCBsYWcgPSAxMCwgdHlwZSA9ICJManVuZyIpDQphcHBseShhYnMoZngpLCAyLCBCb3gudGVzdCwgbGFnID0gMTAsIHR5cGUgPSAiTGp1bmciKQ0KDQojIE1ha2UgYWNmIHBsb3RzIG9mIGZ4X3cgYW5kIHRoZSBhYnNvbHV0ZSB2YWx1ZXMgb2YgZnhfdw0KYWNmKGZ4X3cpDQphY2YoYWJzKGZ4X3cpKQ0KDQoNCiMgQXBwbHkgdGhlIExqdW5nLUJveCB0ZXN0IHRvIHRoZSBjb21wb25lbnRzIG9mIGZ4X3cgYW5kIHRoZWlyIGFic29sdXRlIHZhbHVlcw0KYXBwbHkoZnhfdywgMiwgQm94LnRlc3QsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCmFwcGx5KGFicyhmeF93KSwgMiwgQm94LnRlc3QsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCmBgYA0KDQpUaGVyZSBpcyBzdHJvbmcgZXZpZGVuY2Ugb2Ygc2VyaWFsIGRlcGVuZGVuY2UgaW4gdGhlIGFic29sdXRlIHZhbHVlcyBvZiB0aGUgd2Vla2x5IGxvZy1yZXR1cm5zLg0KDQojIyMgVm9sYXRpbGl0eSBhbmQgY29ycmVsYXRpb24gb2YgaW50ZXJlc3QtcmF0ZSBkYXRhDQoNCllvdSB3aWxsIGV4cGxvcmUgd2hldGhlciB2b2xhdGlsaXR5IGFuZCBzZXJpYWwgZGVwZW5kZW5jZSBpcyBhbHNvIGEgZmVhdHVyZSBvZiBkYWlseSBhbmQgbW9udGhseSBpbnRlcmVzdC1yYXRlIGxvZy1yZXR1cm5zLiBUaGUgZGF0YXNldCB6Y2JfeCBjb250YWlucyBkYWlseSBsb2ctcmV0dXJucyBmb3IgdGhlIDEteWVhciwgNS15ZWFyIGFuZCAxMC15ZWFyIENhbmFkaWFuIHplcm8tY291cG9uIGJvbmQgeWllbGRzIHdoaWxlIHpjYnhfbSBjb250YWlucyB0aGUgY29ycmVzcG9uZGluZyBtb250aGx5IGxvZy1yZXR1cm5zLg0KYGBge3J9DQojIE1ha2UgYWNmIHBsb3RzIG9mIHpjYl94IGFuZCB0aGUgYWJzb2x1dGUgdmFsdWVzIG9mIHpjYl94DQphY2YoemNieFstMV0pDQphY2YoYWJzKHpjYnhbLTFdKSkNCg0KIyBBcHBseSB0aGUgTGp1bmctQm94IHRlc3QgdG8gdGhlIGNvbXBvbmVudHMgb2YgemNiX3ggYW5kIHRoZWlyIGFic29sdXRlIHZhbHVlcw0KYXBwbHkoemNieCwgMiwgQm94LnRlc3QsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCmFwcGx5KGFicyh6Y2J4KSwgMiwgQm94LnRlc3QsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCg0KIyBNYWtlIGFjZiBwbG90cyBvZiB6Y2J4X20gYW5kIHRoZSBhYnNvbHV0ZSB2YWx1ZXMgb2YgemNieF9tDQphY2YoemNieF9tKQ0KYWNmKGFicyh6Y2J4X20pKQ0KDQoNCiMgQXBwbHkgdGhlIExqdW5nLUJveCB0ZXN0IHRvIHRoZSBjb21wb25lbnRzIG9mIHpjYnhfbSBhbmQgdGhlaXIgYWJzb2x1dGUgdmFsdWVzDQphcHBseSh6Y2J4X20sIDIsIEJveC50ZXN0LCBsYWcgPSAxMCwgdHlwZSA9ICJManVuZyIpDQphcHBseShhYnMoemNieF9tKSwgMiwgQm94LnRlc3QsIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nIikNCmBgYA0KVGhlIG1vbnRobHkgbG9nLXJldHVybnMgZm9yIHRoZSA1IGFuZCAxMCB5ZWFyIHlpZWxkcyBkb24ndCBhcHBlYXIgdG8gc2hvdyBtdWNoIHNlcmlhbCBkZXBlbmRlbmNlLg0KDQojIEVzdGltYXRpbmcgcG9ydGZvbGlvIHZhbHVlLWF0LXJpc2sNCg0KIyMgVmFsdWUtYXQtcmlzayBhbmQgZXhwZWN0ZWQgc2hvcnRmYWxsDQoNCiMjIyBDb21wdXRpbmcgVmFSIGFuZCBFUyBmb3Igbm9ybWFsIGRpc3RyaWJ1dGlvbg0KDQpUaGUgc3RhbmRhcmQgZnVuY3Rpb24gcW5vcm0oKSBjYWxjdWxhdGVzIHF1YW50aWxlcyBvZiBhIG5vcm1hbCBkaXN0cmlidXRpb24gZnJvbSB0aGUgcHJvYmFiaWxpdHkgcCwgdGhlIG1lYW4sIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24sIGFuZCB0aHVzIGNhbiBiZSB1c2VkIHRvIGNhbGN1bGF0ZSB2YWx1ZS1hdC1yaXNrIChWYVIpLiBUaGUgZnVuY3Rpb24gRVNub3JtKCkgZnJvbSB0aGUgUVJNIHBhY2thZ2UgY2FsY3VsYXRlcyB0aGUgZXhwZWN0ZWQgc2hvcnRmYWxsIChFUykgZm9yIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBmcm9tIHRoZSBwcm9iYWJpbGl0eSBwLCBsb2NhdGlvbiBwYXJhbWV0ZXIgbXUsIGFuZCBzY2FsZSBwYXJhbWV0ZXIgc2Q6DQpxbm9ybShwLCBtZWFuID0gMCwgc2QgPSAxKQ0KRVNub3JtKHAsIG11ID0gMCwgc2QgPSAxKQ0KDQpDb21tb24gbnVtZXJpYyB2YWx1ZXMgZm9yIHAgaW5jbHVkZSAwLjk1IGFuZCAwLjk5IGZvciBjb25maWRlbmNlIGxldmVscyBvZiA5NSUgYW5kIDk5JSwgcmVzcGVjdGl2ZWx5Lg0KeW91IHdpbGwgY29tcHV0ZSBhbmQgZGlzcGxheSBWYVIgYW5kIEVTIGZvciBhIG5vcm1hbCBkaXN0cmlidXRpb24gTijOvCzPgzIpIHdpdGggbWVhbiDOvCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIM+DLiBJbiB0aGUgcHJvY2VzcywgeW91IHdpbGwgdXNlIHRoZSBuZXcgZnVuY3Rpb25zIGZvciBzZXF1ZW5jZSBnZW5lcmF0aW9uIGFuZCBhZGRpbmcgc3RyYWlnaHQgbGluZXMgdG8gYSBwbG90LiBZb3UgY2FuIHJlYWQgYWJvdXQgdGhlaXIgYXJndW1lbnRzIGJ5IHR5cGluZyBpbiA/c2VxIGFuZCA/YWJsaW5lIHRvIHlvdXIgY29uc29sZS4NCg0KVGhlIHZhcmlhYmxlcyBtdSBhbmQgc2lnbWEgY29udGFpbiB0aGUgZXN0aW1hdGVkIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgRG93IEpvbmVzIGluZGV4IHJldHVybnMgZm9yIDIwMDgtMjAwOSBjb250YWluZWQgaW4gZGp4Lg0KYGBge3J9DQpkanggPC0gZGlmZihsb2coZGopKVstMSxdWyIyMDA4LzIwMDkiXQ0Kc2lnbWEgPC0gc2QoZGp4KQ0KbXUgPC0gbWVhbihkangpDQpgYGANCg0KYGBge3J9DQojIE1ha2UgYSBzZXF1ZW5jZSBvZiAxMDAgeC12YWx1ZXMgZ29pbmcgZnJvbSAtNCpzaWdtYSB0byA0KnNpZ21hDQp4dmFscyA8LSBzZXEoZnJvbSA9IC00KnNpZ21hLCB0byA9IDQqc2lnbWEsIGxlbmd0aC5vdXQgPSAxMDApDQoNCiMgQ29tcHV0ZSB0aGUgZGVuc2l0eSBvZiBhIE4obXUsIHNpZ21hXjIpIGRpc3RyaWJ1dGlvbiBhdCB4dmFscw0KbmRlbnMgPC0gZG5vcm0oeHZhbHMsIG1lYW4gPSBtdSwgc2QgPSBzaWdtYSkNCg0KIyBQbG90IG5kZW5zIGFnYWluc3QgeHZhbHMNCnBsb3QoeHZhbHMsIG5kZW5zLCB0eXBlID0gImwiKQ0KDQojIENvbXB1dGUgdGhlIDk5JSBWYVIgYW5kIDk5JSBFUyBvZiBhIE4obXUsIHNpZ21hXjIpIGRpc3RyaWJ1dGlvbg0KVmFSOTkgPC0gcW5vcm0oMC45OSwgbWVhbiA9IG11LCBzZCA9IHNpZ21hKQ0KVmFSOTkNCkVTOTkgPC0gRVNub3JtKDAuOTksIG11ID0gbXUsIHNkID0gc2lnbWEpDQpFUzk5DQoNCiMgRHJhdyB2ZXJ0aWNhbCBsaW5lcyBhdCBWYVI5OSBhbmQgRVM5OSBpbiByZWQgYW5kIGdyZWVuDQphYmxpbmUodiA9IFZhUjk5LCBjb2wgPSAicmVkIikNCmFibGluZSh2ID0gRVM5OSwgY29sID0gImdyZWVuIikNCmBgYA0KLS0NCkVTOTkgaXMgb25seSAxNC43JSBiaWdnZXIgdGhhbiBWYVI5OS4gRm9yIGhlYXZ5LXRhaWxlZCBkaXN0cmlidXRpb25zLCB0aGUgZGlmZmVyZW5jZSBjYW4gYmUgbXVjaCBncmVhdGVyLg0KDQojIyBJbnRlcm5hdGlvbmFsIGVxdWl0eSBwb3J0Zm9saW8NCg0KIyMjIEV4YW1pbmluZyByaXNrIGZhY3RvcnMgZm9yIGludGVybmF0aW9uYWwgZXF1aXR5IHBvcnRmb2xpbw0KDQpUaGUgVUsgaW52ZXN0b3IgaW4gVUssIFVTLCBhbmQgU3dpc3MgZXF1aXRpZXMgaXMgZXhwb3NlZCB0byA1IHJpc2sgZmFjdG9yczsgdGhlIGRhdGEgaXMgY29udGFpbmVkIGluIHJpc2tmYWN0b3JzLCBhIG11bHRpdmFyaWF0ZSBkYXRhc2V0Lg0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCByZWNhbGwgc29tZSBvZiB0aGUgdGVzdHMgYW5kIHRlY2huaXF1ZXMgdGhhdCB5b3UgbGVhcm5lZCBlYXJsaWVyIGZvciBzaG93aW5nIHRoYXQgdGhlc2UgcmlzayBmYWN0b3JzIGFyZSBoZWF2aWVyIHRhaWxlZCB0aGFuIG5vcm1hbCwgaGlnaGx5IHZvbGF0aWxlIGFuZCBzdWJqZWN0IHRvIHByb2ZvdW5kIHNlcmlhbCBkZXBlbmRlbmNpZXMuDQpgYGB7cn0NCmRhdGEoIlVTRF9HQlAiKQ0KZGF0YSgiQ0hGX0dCUCIpDQpYLkZUU0UgPC0gRlRTRVsiMjAwMC8yMDEyIl0NClguR1NQQyA8LSBTUDUwMFsiMjAwMC8yMDEyIl0NClguU1NNSSA8LSBTTUlbIjIwMDAvMjAxMiJdDQpVU0QuR0JQIDwtIFVTRF9HQlBbIjIwMDAvMjAxMiJdDQpDSEYuR0JQIDwtIENIRl9HQlBbIjIwMDAvMjAxMiJdDQpyaXNrZmFjdG9ycyA8LSBtZXJnZShYLkZUU0UsICBYLkdTUEMsIFguU1NNSSwgVVNELkdCUCwgQ0hGLkdCUCAsIGFsbCA9IFRSVUUpDQpyaXNrZmFjdG9ycyA8LSBuYS5vbWl0KHJpc2tmYWN0b3JzKQ0KYGBgDQpgYGB7cn0NCiMgUGxvdCB0aGUgcmlzay1mYWN0b3IgZGF0YQ0KcGxvdC56b28ocmlza2ZhY3RvcnMpDQoNCiMgQ2FsY3VsYXRlIHRoZSBsb2ctcmV0dXJucywgYXNzaWduIHRvIHJldHVybnMsIGFuZCBwbG90DQpyZXR1cm5zIDwtIGRpZmYobG9nKHJpc2tmYWN0b3JzKSlbLTEsIF0NCnBsb3Quem9vKHJldHVybnMpDQoNCiMgVXNlIGFwcGx5KCkgdG8gY2Fycnkgb3V0IHRoZSBKYXJxdWUtQmVyYSB0ZXN0IGZvciBhbGwgNSBzZXJpZXMNCmFwcGx5KHJldHVybnMsIDIsIGphcnF1ZS50ZXN0KQ0KDQojIE1ha2UgYSBRLVEgcGxvdCBhZ2FpbnN0IG5vcm1hbCBmb3IgdGhlIDV0aCByZXR1cm4gc2VyaWVzIGFuZCBhZGQgYSByZWZlcmVuY2UgbGluZQ0KcXFub3JtKHJldHVybnNbLCA1XSkNCnFxbGluZShyZXR1cm5zWywgNV0pDQoNCiMgTWFrZSBhIHBpY3R1cmUgb2YgdGhlIHNhbXBsZSBhY2ZzIGZvciByZXR1cm5zIGFuZCB0aGVpciBhYnNvbHV0ZSB2YWx1ZXMNCmFjZihyZXR1cm5zKQ0KYWNmKGFicyhyZXR1cm5zKSkNCmBgYA0KQWxsIGZpdmUgcmlzayBmYWN0b3JzIGFyZSBjbGVhcmx5IG5vbi1ub3JtYWwgYW5kIHNob3cgc3Ryb25nIHNlcmlhbCBhbmQgY3Jvc3MgZGVwZW5kZW5jaWVzLg0KDQojIyMgSGlzdG9yaWNhbCBzaW11bGF0aW9uDQoNClN1cHBvc2UgdGhhdCBhIFVLIGludmVzdG9yIGhhcyBpbnZlc3RlZCAzMCUgb2YgaGVyIHdlYWx0aCBpbiB0aGUgRlRTRSBpbmRleCwgNDAlIGluIHRoZSBTJlAgNTAwIGluZGV4LCBhbmQgMzAlIGluIHRoZSBTTUkgaW5kZXguDQoNCkZvciBkaWZmZXJlbnQgdmVjdG9ycyBvZiBsb2ctcmV0dXJucyBmb3IgdGhlIDUgcmlzayBmYWN0b3JzLCB0aGUgZnVuY3Rpb24gbG9zc29wKCkgY29tcHV0ZXMgdGhlIGxvc3Mgb3IgZ2FpbiBpbmN1cnJlZCBieSB0aGUgaW52ZXN0b3Igd2hlbiBoZXIgdG90YWwgd2VhbHRoIGlzIDEuIFRoZSBmdW5jdGlvbiBjYW4gYWxzbyBiZSBhcHBsaWVkIHRvIGEgNS1kaW1lbnNpb25hbCB0aW1lIHNlcmllcyBvZiBsb2ctcmV0dXJucyB0byBvYnRhaW4gYSB0aW1lIHNlcmllcyBvZiBoaXN0b3JpY2FsbHktc2ltdWxhdGVkIGxvc3NlcyBhbmQgZ2FpbnMgY29ycmVzcG9uZGluZyB0byBlYWNoIHZlY3RvciBvZiBsb2ctcmV0dXJucyBpbiB0aGUgdGltZSBzZXJpZXMuDQoNClRoZSBmdW5jdGlvbiBsb3Nzb3AoKSBpcyB0aGUgc28tY2FsbGVkIGxvc3Mgb3BlcmF0b3IgZm9yIHRoZSBwb3J0Zm9saW8gYW5kIGhhcyBiZWVuIHNwZWNpYWxseSB3cml0dGVuIGZvciB0aGlzIGV4ZXJjaXNlLiBJbiBnZW5lcmFsLCBmb3IgZWFjaCBuZXcgcG9ydGZvbGlvLCBhIHNwZWNpZmljIGZ1bmN0aW9uIGhhcyB0byBiZSB3cml0dGVuIHRvIGNvbXB1dGUgcG9ydGZvbGlvIGxvc3NlcyBhbmQgZ2FpbnMuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGZvcm0gaGlzdG9yaWNhbGx5IHNpbXVsYXRlZCBsb3NzZXMgYW5kIGV4YW1pbmUgdGhlbS4gVGhpcyBpcyBhIG5lY2Vzc2FyeSBwcmVsdWRlIHRvIHVzaW5nIHRoZXNlIGRhdGEgdG8gZXN0aW1hdGUgVmFSIGFuZCBFUy4NCmBgYHtyfQ0KbG9zc29wIDwtIGZ1bmN0aW9uICh4c2VyaWVzLCB3dHMgPSBjKDAuMywgMC40LCAwLjMpKXsNCiAgICBpZiAoaXMueHRzKHhzZXJpZXMpKSANCiAgICAgICAgeCA8LSBjb3JlZGF0YSh4c2VyaWVzKQ0KICAgIGVsc2UgaWYgKGlzLm1hdHJpeCh4c2VyaWVzKSkgDQogICAgICAgIHggPC0geHNlcmllcw0KICAgIGVsc2UgeCA8LSBtYXRyaXgoeHNlcmllcywgbnJvdyA9IDEpDQogICAgbGwgPC0gYXBwbHkoeCwgMSwgZnVuY3Rpb24oeCwgd3RzKSB7DQogICAgICAgIDEgLSAod3RzWzFdICogZXhwKHhbMV0pICsgd3RzWzJdICogZXhwKHhbMl0gKyB4WzRdKSArIA0KICAgICAgICAgICAgd3RzWzNdICogZXhwKHhbM10gKyB4WzVdKSkNCiAgICB9LCB3dHMgPSB3dHMpDQogICAgaWYgKGlzLnh0cyh4c2VyaWVzKSkgDQogICAgICAgIGxsIDwtIHh0cyhsbCwgdGltZSh4c2VyaWVzKSkNCiAgICBsbA0KfQ0KYGBgDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIGxvc3MgZnJvbSBhIGxvZy1yZXR1cm4gb2YgLTAuMSBmb3IgYWxsIHJpc2sgZmFjdG9ycw0KbG9zc29wKHJlcCgtMC4xLCA1KSkNCg0KIyBBcHBseSBsb3Nzb3AoKSB0byByZXR1cm5zIGFuZCBwbG90IGhzbG9zc2VzDQpoc2xvc3NlcyA8LSBsb3Nzb3AocmV0dXJucykNCnBsb3QoaHNsb3NzZXMpDQoNCiMgRm9ybSBhIFEtUSBwbG90IG9mIGhzbG9zc2VzIGFnYWluc3Qgbm9ybWFsDQpxcW5vcm0oaHNsb3NzZXMpDQoNCiMgUGxvdCB0aGUgc2FtcGxlIGFjZiBvZiBoc2xvc3NlcyBhbmQgdGhlaXIgYWJzb2x1dGUgdmFsdWVzDQphY2YoaHNsb3NzZXMpDQphY2YoYWJzKGhzbG9zc2VzKSkNCmBgYA0KTm90ZSBob3cgdGhlIGZlYXR1cmVzIG9mIHRoZSB1bmRlcmx5aW5nIHJpc2stZmFjdG9yIHJldHVybnMgKGhlYXZ5IHRhaWxzIGFuZCBzZXJpYWwgZGVwZW5kZW5jZSkgYXJlIHByZXNlbnQgaW4gdGhlIGhpc3RvcmljYWxseSBzaW11bGF0ZWQgbG9zc2VzLg0KDQojIyMgRXN0aW1hdGluZyBWYVIgYW5kIEVTDQoNCk5vdyB5b3UgYXJlIHJlYWR5IHRvIGVzdGltYXRlIFZhUiBhbmQgRVMgZm9yIHRoZSBpbnRlcm5hdGlvbmFsIGVxdWl0eSBpbnZlc3RvciB1c2luZyB0aGUgaGlzdG9yaWNhbGx5IHNpbXVsYXRlZCBsb3NzZXMgYW5kIGdhaW5zIGluIGhzbG9zc2VzLg0KDQpZb3Ugd2lsbCBkbyB0aGlzIGJ5IHR3byBtZXRob2RzLiBGaXJzdCwgeW91IHdpbGwgYXBwbHkgYSBzaW1wbGUgbm9uLXBhcmFtZXRyaWMgbWV0aG9kIHVzaW5nIGEgc2FtcGxlIHF1YW50aWxlIHRvIGVzdGltYXRlIFZhUiBhbmQgdGhlIGF2ZXJhZ2Ugb2YgdmFsdWVzIGV4Y2VlZGluZyB0aGUgc2FtcGxlIHF1YW50aWxlIHRvIGVzdGltYXRlIEVTLg0KDQpUaGVuLCB5b3Ugd2lsbCBjb21wYXJlIHRoZXNlIGVzdGltYXRlcyB3aXRoIHRoZSB2YWx1ZXMgb2J0YWluZWQgd2hlbiB5b3UgYXNzdW1lIHRoYXQgdGhlIGhzbG9zc2VzIGhhdmUgYSBub3JtYWwgZGlzdHJpYnV0aW9uLiBPYnZpb3VzbHksIHRoaXMgaXMgYSB2ZXJ5IGJhZCBhc3N1bXB0aW9uIGFuZCB5b3Ugc2hvdWxkIGNvbXBhcmUgdGhlIHR3byBzZXRzIG9mIGVzdGltYXRlcyB0byBzZWUgd2hpY2ggYXJlIG1vcmUgY29uc2VydmF0aXZlLg0KYGBge3J9DQojIEVzdGltYXRlIHRoZSA5OXRoIHNhbXBsZSBwZXJjZW50aWxlIG9mIHRoZSBkaXN0cmlidXRpb24gb2YgaHNsb3NzZXMNCnF1YW50aWxlKGhzbG9zc2VzLCAwLjk5KQ0KDQojIEVzdGltYXRlIHRoZSA5OSUgRVMNCm1lYW4oaHNsb3NzZXNbaHNsb3NzZXMgPj0gcXVhbnRpbGUoaHNsb3NzZXMsIDAuOTkpXSkNCg0KIyBFc3RpbWF0ZSB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGhzbG9zc2VzDQptdSA8LSBtZWFuKGhzbG9zc2VzKQ0Kc2lnbWEgPC0gc2QoaHNsb3NzZXMpDQoNCiMgQ29tcHV0ZSB0aGUgOTklIHF1YW50aWxlIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KcW5vcm0oMC45OSwgbWVhbiA9IG11LCBzZCA9IHNpZ21hKQ0KDQojIENvbXB1dGUgdGhlIDk5JSBFUyBvZiBhIG5vcm1hbCBkaXN0cmlidXRpb24NCkVTbm9ybSgwLjk5LCBtdSA9IG11LCBzZCA9IHNpZ21hKQ0KYGBgDQpUaGlzIGlzIHdoYXQgd2UgZXhwZWN0ZWQuIFRoZSBlc3RpbWF0ZXMgZGVyaXZlZCBmcm9tIGEgbm9ybWFsIGFzc3VtcHRpb24gYXJlIG11Y2ggbGVzcyBjb25zZXJ2YXRpdmUgdGhhbiB0aGUgZXN0aW1hdGVzIGRlcml2ZWQgdXNpbmcgdGhlIG5vbi1wYXJhbWV0cmljIG1ldGhvZC4gVGhhdCBpcyBub3QgdG8gc2F5IHRoYXQgdGhlIGxhdHRlciBtZXRob2QgaXMgdGhlIGJlc3QgcG9zc2libGUsIGJ1dCBpdCBpcyBhIHJlYXNvbmFibGUgZmlyc3QgYXR0ZW1wdCB0byBlc3RpbWF0ZSB0aGUgcmlzayBtZWFzdXJlcy4NCg0KIyMgT3B0aW9uIHBvcnRmb2xpbyBhbmQgQmxhY2sgU2Nob2xlcw0KDQojIyMgQ29tcHV0ZSBCbGFjay1TY2hvbGVzIHByaWNlIG9mIGFuIG9wdGlvbg0KDQpUaGUgQmxhY2tfU2Nob2xlcygpIGZ1bmN0aW9uIGluIHRoZSBwYWNrYWdlIHFybXRvb2xzIGNhbiBiZSB1c2VkIHRvIHByaWNlIEV1cm9wZWFuIGNhbGwgYW5kIHB1dCBvcHRpb25zIHVzaW5nIHRoZSBzdGFuZGFyZCBCbGFjay1TY2hvbGVzIG9wdGlvbnMgcHJpY2luZyBmb3JtdWxhIGZvciBhIG5vbi1kaXZpZGVuZC1wYXlpbmcgc3RvY2suDQoNCkluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgcHJpY2UgaW4gc3VjY2Vzc2lvbjogYW4gb3V0LW9mLXRoZS1tb25leSBFdXJvcGVhbiBjYWxsLCBhbiBpbi10aGUtbW9uZXkgRXVyb3BlYW4gY2FsbCwgYW4gaW4tdGhlLW1vbmV5IEV1cm9wZWFuIHB1dCBhbmQgYW4gb3V0LW9mLXRoZS1tb25leSBFdXJvcGVhbiBwdXQuIEFuIG9wdGlvbiBpcyBpbi10aGUtbW9uZXkgaWYgaW1tZWRpYXRlIGV4ZXJjaXNlIHdvdWxkIHJlc3VsdCBpbiBhIHBvc2l0aXZlIHBheW91dCBhbmQgb3V0LW9mLXRoZS1tb25leSBpZiBpdCB3b3VsZCBub3QuDQoNClRoZSBtYWluIHBvaW50IG9mIHRoZSBleGVyY2lzZSBpcyB0byB1bmRlcnN0YW5kIHRoZSBkaWZmZXJlbnQgcmlzayBmYWN0b3JzIHRoYXQgZ28gaW50byB0aGUgcHJpY2UgY2FsY3VsYXRpb246IHRoZSBjdXJyZW50IHN0b2NrIHByaWNlLCB0aGUgY3VycmVudCB2b2xhdGlsaXR5IGFuZCB0aGUgY3VycmVudCBpbnRlcmVzdCByYXRlLg0KYGBge3J9DQojIFNldCB0aGUgaW50ZXJlc3QgcmF0ZSByIHRvIGJlIDAuMDEsIHRoZSB2b2xhdGlsaXR5IHNpZ21hIHRvIGJlIDAuMiBhbmQgdGhlIHN0cmlrZSBLIHRvIGJlIDEwMA0KciA8LSAwLjAxDQpzaWdtYSA8LSAwLjINCksgPC0gMTAwDQoNCg0KbGlicmFyeShxcm10b29scykNCiMgTG9vayBhdCB0aGUgYXJndW1lbnRzIG9mIHRoZSBCbGFja19TY2hvbGVzIGZ1bmN0aW9uDQphcmdzKEJsYWNrX1NjaG9sZXMpDQoNCiMgUHJpY2UgYSBFdXJvcGVhbiBjYWxsIG9wdGlvbiB0aGF0IG1hdHVyZXMgaW4gb25lIHllYXIgaWYgdGhlIGN1cnJlbnQgc3RvY2sgcHJpY2UgaXMgODANCkJsYWNrX1NjaG9sZXMoMCwgODAsIHIsIHNpZ21hLCBLLCAxLCAiY2FsbCIpDQoNCiMgUHJpY2UgYSBFdXJvcGVhbiBjYWxsIG9wdGlvbiB0aGF0IG1hdHVyZXMgaW4gb25lIHllYXIgaWYgdGhlIGN1cnJlbnQgc3RvY2sgcHJpY2UgaXMgMTIwDQpCbGFja19TY2hvbGVzKDAsIDEyMCwgciwgc2lnbWEsIEssIDEsICJjYWxsIikNCg0KIyBQcmljZSBhIEV1cm9wZWFuIHB1dCBvcHRpb24gdGhhdCBtYXR1cmVzIGluIG9uZSB5ZWFyIGlmIHRoZSBjdXJyZW50IHN0b2NrIHByaWNlIGlzIDgwDQpCbGFja19TY2hvbGVzKDAsIDgwLCByLCBzaWdtYSwgSywgMSwicHV0IikNCg0KIyBQcmljZSBhIEV1cm9wZWFuIHB1dCBvcHRpb24gdGhhdCBtYXR1cmVzIGluIG9uZSB5ZWFyIGlmIHRoZSBjdXJyZW50IHN0b2NrIHByaWNlIGlzIDEyMA0KQmxhY2tfU2Nob2xlcygwLCAxMjAsIHIsIHNpZ21hLCBLLCAxLCJwdXQiKQ0KYGBgDQpEaWQgeW91IHNlZSBob3cgZHJhbWF0aWNhbGx5IHRoZSBvcHRpb24gdmFsdWVzIGNoYW5nZWQgYXMgdGhlIHN0b2NrIHByaWNlIG1vdmVkIGZyb20gb3V0LW9mLXRoZS1tb25leSB0byBpbi10aGUtbW9uZXkgb3IgdmljZSB2ZXJzYT8NCg0KIyMjIEVxdWl0eSBhbmQgaW1wbGllZCB2b2xhdGlsaXR5IHJpc2sgZmFjdG9ycw0KDQpUbyBhbmFseXplIHRoZSByaXNrIG9mIGEgcG9ydGZvbGlvIGNvbnNpc3Rpbmcgb2YgYW4gb3B0aW9uLCBpdCBpcyBuZWNlc3NhcnkgdG8gY29uc2lkZXIgY2hhbmdlcyBpbiBhbGwgdGhyZWUgcmlzayBmYWN0b3JzOiBzdG9jayBwcmljZSwgdm9sYXRpbGl0eSBhbmQgaW50ZXJlc3QgcmF0ZXMuIEhlcmUsIHlvdSB3aWxsIGZvY3VzIG9uIHRoZSBmaXJzdCB0d28gb2YgdGhlc2UgcmlzayBmYWN0b3JzIGFuZCBhc3N1bWUgdGhhdCBpbnRlcmVzdCByYXRlcyBkbyBub3QgY2hhbmdlIG11Y2ggb3ZlciBzaG9ydCB0aW1lIGludGVydmFscy4gVGhlIGRhaWx5IHJpc2stZmFjdG9yIHZhbHVlcyBmb3IgdGhlIHBlcmlvZCAxOTkwLTIwMTAgYXJlIGNvbnRhaW5lZCBpbiByaXNrZmFjdG9ycyBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgbG9nLXJldHVybnMgaW4gcmV0dXJuczsgYm90aCBtdWx0aXZhcmlhdGUgZGF0YXNldHMgYXJlIGxvYWRlZCBpbiB5b3VyIHdvcmtzcGFjZS4NCg0KVm9sYXRpbGl0eSBpcyBhIG5ldyByaXNrIGZhY3RvciB0aGF0IGhhc24ndCBiZWVuIGNvbnNpZGVyZWQgc28gZmFyIGluIHRoaXMgY291cnNlLiBJdCBpcyByZXByZXNlbnRlZCBieSB0aGUgVklYIGluZGV4IHdoaWNoIGlzIGNvbnN0cnVjdGVkIGZyb20gdGhlIGltcGxpZWQgdm9sYXRpbGl0aWVzIG9mIGEgd2lkZSByYW5nZSBvZiBvcHRpb25zIG9uIHRoZSBTJlAgNTAwIGluZGV4Og0KYGBge3J9DQpkYXRhKCJWSVgiKQ0KWC5HU1BDIDwtIFNQNTAwWyIxOTkwLzIwMTAiXQ0KWC5WSVggPC0gVklYWyIxOTkwLzIwMTAiXQ0Kcmlza2ZhY3RvcnMgPC0gbWVyZ2UoWC5HU1BDLCBYLlZJWCwgYWxsID0gVFJVRSkNCnJpc2tmYWN0b3JzIDwtIG5hLm9taXQocmlza2ZhY3RvcnMpDQpyZXR1cm5zIDwtIGRpZmYobG9nKHJpc2tmYWN0b3JzKSlbLTEsIF0NCmBgYA0KYGBge3J9DQpuYW1lcyhyZXR1cm5zKQ0KYGBgDQpZb3Ugd2lsbCBiZSBhYmxlIHRvIHZlcmlmeSB3aGV0aGVyIHRoZSBsb2ctcmV0dXJucyBvZiB2b2xhdGlsaXR5IGJlaGF2ZSBsaWtlIG90aGVyIHJldHVybiBkYXRhIHlvdSBoYXZlIGVuY291bnRlcmVkLCBhbmQgdG8gc2VlIGhvdyB0aGV5IHZhcnkgd2l0aCB0aGUgbG9nLXJldHVybnMgb2YgdGhlIFMmUCA1MDAgaW5kZXguDQpgYGB7cn0NCiMgUGxvdCB0aGUgcmlzayBmYWN0b3JzIGFuZCB0aGUgbG9nLXJldHVybnMNCnBsb3Quem9vKHJpc2tmYWN0b3JzKQ0KcGxvdC56b28ocmV0dXJucykNCg0KIyBNYWtlIGEgc2NhdHRlcnBsb3Qgb2YgdGhlIHR3byByZXR1cm4gc2VyaWVzDQpwbG90KGFzLm1hdHJpeChyZXR1cm5zKSkNCg0KIyBBcHBseSB0aGUgSmFycXVlLUJlcmEgdGVzdCB0byB0aGUgcmV0dXJucyBhbmQgbWFrZSBhIFEtUSBwbG90IG9mIHRoZSB2b2xhdGlsaXR5IGxvZy1yZXR1cm5zDQphcHBseShyZXR1cm5zLCAyLCBqYXJxdWUudGVzdCkNCnFxbm9ybShyZXR1cm5zWywgMl0pDQoNCiMgQ3JlYXRlIHRoZSBzYW1wbGUgYWNmIG9mIHRoZSByZXR1cm5zIGFuZCBhYnNvbHV0ZSByZXR1cm5zDQphY2YocmV0dXJucykNCmFjZihhYnMocmV0dXJucykpDQoNCiMgQ2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBsb2ctcmV0dXJucw0KY29yKHJldHVybnMpDQpgYGANCkl0IGlzIGNsZWFyIHRoYXQgdGhlIGxvZy1yZXR1cm5zIG9mIHRoZSBWSVggaW5kZXggc2hvdyB0aGUgc2FtZSBzdHlsaXplZCBmYWN0cyBhcyBvdGhlciByZXR1cm5zIHRoYXQgeW91IGhhdmUgYW5hbHl6ZWQgLSBub24tbm9ybWFsaXR5LCBoZWF2eSB0YWlscywgdm9sYXRpbGl0eSwgc2VyaWFsIGRlcGVuZGVuY2UgaW4gdGhlIGFic29sdXRlIHZhbHVlcyBidXQgbm90IHRoZSByYXcgdmFsdWVzLiBNb3Jlb3ZlciwgdGhleSBhcmUgbmVnYXRpdmVseSBjb3JyZWxhdGVkIHdpdGggdGhlIGxvZy1yZXR1cm5zIG9mIHRoZSBTUDUwMCBpbmRleA0KDQojIyBIaXN0b3JpY2FsIHNpbXVsYXRpb24gZm9yIHRoZSBvcHRpb24gZXhhbXBsZQ0KDQojIyMgSGlzdG9yaWNhbCBzaW11bGF0aW9uIG9mIGxvc3NlcyBmb3Igb3B0aW9uIHBvcnRmb2xpbw0KDQpTdXBwb3NlIHRoYXQgYW4gaW52ZXN0b3IgaGFzIGludmVzdGVkIG9uZSB1bml0IG9mIHdlYWx0aCBpbiBhIHNpbmdsZSBFdXJvcGVhbiBjYWxsIG9wdGlvbiBvbiB0aGUgUyZQIDUwMCBpbmRleC4gVGhlIGZ1bmN0aW9uIGxvc3NvcCgpIGNvbXB1dGVzIHRoZSBsb3NzIG9yIGdhaW4gaW5jdXJyZWQgYnkgdGhlIGludmVzdG9yIG92ZXIgYSBvbmUtZGF5IHRpbWUgaG9yaXpvbiBkdWUgdG8gY2hhbmdlcyBpbiB0aGUgbG9nIHN0b2NrIHByaWNlIG9yIGNoYW5nZXMgaW4gdGhlIGxvZyB2b2xhdGlsaXR5LiBBcyBiZWZvcmUsIHRoaXMgZnVuY3Rpb24gaGFzIGJlZW4gd3JpdHRlbiBzcGVjaWFsbHkgZm9yIHRoZSBwYXJ0aWN1bGFyIHBvcnRmb2xpbyBpbiB0aGlzIGV4ZXJjaXNlOg0KbG9zc29wKHhzZXJpZXMsIFMsIHNpZ21hKQ0KVGhlIGZpcnN0IGFyZ3VtZW50IGNvbnRhaW5zIHRoZSBsb2cgcmV0dXJucyBjb3JyZXNwb25kaW5nIHRvIHRoZSBzdG9jayBwcmljZSBhbmQgdm9sYXRpbGl0eSByaXNrIGZhY3RvcnMsIGVpdGhlciBpbiBhIHNlcmllcyBvciBpbiBmb3JtIGMoc3RvY2tfcmlzaywgdm9sYXRpbGl0eV9yaXNrKSwgUyBpcyB0aGUgY3VycmVudCBzdG9jayBwcmljZSwgYW5kIHNpZ21hIGlzIHRoZSBjdXJyZW50IHZvbGF0aWxpdHkuDQoNCkNoYW5nZXMgaW4gdGhlIGludGVyZXN0IHJhdGUgb3ZlciB0aGUgdGltZSBob3Jpem9uIHdpbGwgYmUgbmVnbGVjdGVkIGFzIGJlaW5nIG9mIGxlc3NlciBpbXBvcnRhbmNlLg0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBmb3JtIHRoZSBoaXN0b3JpY2FsbHkgc2ltdWxhdGVkIGxvc3NlcyBmb3IgdGhlIG9wdGlvbiBwb3J0Zm9saW8gYW5kIGV4YW1pbmUgdGhlaXIgcHJvcGVydGllcyBiZWZvcmUgZXN0aW1hdGluZyBWYVIgYW5kIEVTIGluIHRoZSBuZXh0IGV4ZXJjaXNlLiBUaGUgaW50ZXJlc3QgcmF0ZSwgc3RyaWtlIHByaWNlLCBhbmQgbWF0dXJpdHkgaGF2ZSBiZWVuIHNldCB0byByID0gMC4wMSwgSyA9IDEwMCBhbmQgVCA9IDEsIHJlc3BlY3RpdmVseS4NCmBgYHtyfQ0KbG9zc29wIDwtIGZ1bmN0aW9uICh4c2VyaWVzLCByID0gMC4wMSwgSyA9IDEwMCwgVCA9IDEsIHNpZ21hID0gMC4yLCBTID0gMTAwKXsNCiAgICBpZiAoaXMueHRzKHhzZXJpZXMpKSANCiAgICAgICAgeCA8LSBjb3JlZGF0YSh4c2VyaWVzKQ0KICAgIGVsc2UgaWYgKGlzLm1hdHJpeCh4c2VyaWVzKSkgDQogICAgICAgIHggPC0geHNlcmllcw0KICAgIGVsc2UgeCA8LSBtYXRyaXgoeHNlcmllcywgbnJvdyA9IDEpDQogICAgbGwgPC0gYXBwbHkoeCwgMSwgZnVuY3Rpb24oeCwgciwgSywgVCwgc2lnbWEsIFMpIHsNCiAgICAgICAgZGVsdGF0IDwtIDEvMjUwDQogICAgICAgIFZfdDAgPC0gQmxhY2tfU2Nob2xlcygwLCBTLCByLCBzaWdtYSwgSywgVCwgImNhbGwiKQ0KICAgICAgICBWX3QxID0gQmxhY2tfU2Nob2xlcyhkZWx0YXQsIGV4cChsb2coUykgKyB4WzFdKSwgciwgZXhwKGxvZyhzaWdtYSkgKyANCiAgICAgICAgICAgIHhbMl0pLCBLLCBULCAiY2FsbCIpDQogICAgICAgIC0oVl90MSAtIFZfdDApL1ZfdDANCiAgICB9LCByID0gciwgSyA9IEssIFQgPSBULCBzaWdtYSA9IHNpZ21hLCBTID0gUykNCiAgICBpZiAoaXMueHRzKHhzZXJpZXMpKSANCiAgICAgICAgbGwgPC0geHRzKGxsLCB0aW1lKHhzZXJpZXMpKQ0KICAgIGxsDQp9DQpgYGANCg0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHRoZSBmaXJzdCBsb3NzDQpsb3Nzb3AoYygtMC4xLCAtMC4xKSwgUyA9IDgwLCBzaWdtYSA9IDAuMikNCg0KIyBDYWxjdWxhdGUgdGhlIHNlY29uZCBsb3NzDQpsb3Nzb3AoYygtMC4xLCAwLjEpLCBTID0gMTAwLCBzaWdtYSA9IDAuMikNCg0KIyBDcmVhdGUgYW5kIHBsb3QgaHNsb3NzZXMNCmhzbG9zc2VzIDwtIGxvc3NvcChyZXR1cm5zLCBTID0gMTAwLCBzaWdtYSA9IDAuMikNCnBsb3QoaHNsb3NzZXMpDQoNCiMgRm9ybSBhIFEtUSBwbG90IG9mIGhzbG9zc2VzIGFnYWluc3Qgbm9ybWFsDQpxcW5vcm0oaHNsb3NzZXMpDQoNCiMgUGxvdCB0aGUgc2FtcGxlIGFjZiBvZiByYXcgZGF0YSBhbmQgYWJzb2x1dGUgdmFsdWVzIGluIGhzbG9zc2VzDQphY2YoaHNsb3NzZXMpDQphY2YoYWJzKGhzbG9zc2VzKSkNCmBgYA0KIyMjIEVzdGltYXRpbmcgVmFSIGFuZCBFUyBmb3Igb3B0aW9uIHBvcnRmb2xpbw0KDQpOb3cgeW91IGFyZSByZWFkeSB0byBlc3RpbWF0ZSBWYVIgYW5kIEVTIGZvciB0aGUgaW52ZXN0b3IgaW4gdGhlIEV1cm9wZWFuIGNhbGwgb3B0aW9uIHVzaW5nIHRoZSBoaXN0b3JpY2FsbHkgc2ltdWxhdGVkIGxvc3NlcyBhbmQgZ2FpbnMgaW4gaHNsb3NzZXMuDQoNCk9uY2UgYWdhaW4sIHlvdSB3aWxsIGRvIHRoaXMgYnkgdHdvIG1ldGhvZHMuIEZpcnN0LCB5b3Ugd2lsbCBhcHBseSBhIG5vbi1wYXJhbWV0cmljIG1ldGhvZCB1c2luZyBhIHNhbXBsZSBxdWFudGlsZSB0byBlc3RpbWF0ZSBWYVIgYW5kIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBvZiB2YWx1ZXMgZXhjZWVkaW5nIHRoZSBzYW1lIHF1YW50aWxlIHRvIGVzdGltYXRlIEVTLg0KDQpUaGVuLCB5b3Ugd2lsbCBjb21wYXJlIHRoZXNlIGVzdGltYXRlcyB3aXRoIHRoZSB2YWx1ZXMgb2J0YWluZWQgd2hlbiB5b3UgYXNzdW1lIHRoYXQgdGhlIGhzbG9zc2VzIGhhdmUgYSBub3JtYWwgZGlzdHJpYnV0aW9uLiBMaWtlIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZSwgdGhpcyBpcyBhIGJhZCBhc3N1bXB0aW9uIGFuZCB5b3Ugc2hvdWxkIGNvbXBhcmUgdGhlIHR3byBzZXRzIG9mIGVzdGltYXRlcyB0byBzZWUgd2hpY2ggYXJlIG1vcmUgY29uc2VydmF0aXZlLg0KYGBge3J9DQojIEVzdGltYXRlIHRoZSA5OS41JSBwZXJjZW50aWxlIG9mIHRoZSBkaXN0cmlidXRpb24NCnF1YW50aWxlKGhzbG9zc2VzLCAwLjk5NSkNCg0KIyBFc3RpbWF0ZSB0aGUgOTkuNSUgRVMNCm1lYW4oaHNsb3NzZXNbaHNsb3NzZXMgPj0gcXVhbnRpbGUoaHNsb3NzZXMsIDAuOTk1KV0pDQoNCiMgRXN0aW1hdGUgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBoc2xvc3Nlcw0KbXUgPC0gbWVhbihoc2xvc3NlcykNCnNpZ21hIDwtIHNkKGhzbG9zc2VzKQ0KDQojIENvbXB1dGUgdGhlIDk5LjUlIHF1YW50aWxlIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KcW5vcm0oMC45OTUsIG1lYW4gPSBtdSwgc2QgPSBzaWdtYSkNCg0KIyBDb21wdXRlIHRoZSA5OS41JSBFUyBvZiBhIG5vcm1hbCBkaXN0cmlidXRpb24NCkVTbm9ybSgwLjk5NSwgbXUgPSBtdSwgc2QgPSBzaWdtYSkNCmBgYA0KSXQgd2lsbCBiZSBubyBzdXJwcmlzZSB0byB5b3Ugbm93IHRoYXQgdGhlIG5vcm1hbCBkaXN0cmlidXRpb24gZ3JlYXRseSB1bmRlcmVzdGltYXRlcyB0aGVzZSBtZWFzdXJlcyBvZiByaXNrLg0KDQojIyMgQ29tcHV0aW5nIFZhUiBmb3Igd2Vla2x5IGxvc3Nlcw0KDQpJbiB0aGlzIGZpbmFsIGV4ZXJjaXNlLCB5b3Ugd2lsbCB0ZXN0IHlvdXIgdW5kZXJzdGFuZGluZyBieSBjb21wdXRpbmcgYW4gZW1waXJpY2FsIGVzdGltYXRlIG9mIFZhUiBmb3Igd2Vla2x5IGxvc3NlcyBpbiB0aGUgcmV0dXJucyBkYXRhLiBZb3Ugd2lsbCBoYXZlIHRvIHJlcGVhdCB0aGUgYW5hbHlzaXMgb2YgdGhlIHByZXZpb3VzIGV4ZXJjaXNlLCBidXQgdGhpcyB0aW1lLCB5b3UgbmVlZCB0bzoNCg0KRmluZCB0aGUgd2Vla2x5IGxvZy1yZXR1cm5zIG9mIHJldHVybnMgdXNpbmcgYXBwbHkud2Vla2x5KCkuDQpVc2UgdGhlc2Ugd2Vla2x5IGxvZy1yZXR1cm5zIHRvIHNpbXVsYXRlIHRoZSBsb3NzZXMgb2YgdGhlIHR3byByaXNrIGZhY3RvcnMgdGhyb3VnaCBsb3Nzb3AoKS4NCk5vdGUgdGhhdCB0aGUgbG9zc29wKCkgZnVuY3Rpb24gaGFzIGJlZW4gYWRqdXN0ZWQgaW4geW91ciB3b3Jrc3BhY2Ugc28gdGhhdCBpdCBjb3JyZWN0bHkgY2FsY3VsYXRlcyB0aGUgbG9zc2VzIGFuZCBnYWlucyBvZiB0aGUgb3B0aW9uIHBvcnRmb2xpbyBmb3IgYSBvbmUtd2VlayB0aW1lIGhvcml6b24uIEl0IHN0aWxsIHRha2VzIGluIGFyZ3VtZW50cyBhcyBmb2xsb3dzOg0KDQpsb3Nzb3AoeHNlcmllcywgUywgc2lnbWEpDQpgYGB7cn0NCmxvc3NvcCA8LSBmdW5jdGlvbiAoeHNlcmllcywgciA9IDAuMDEsIEsgPSAxMDAsIFQgPSAxLCBzaWdtYSA9IDAuMiwgUyA9IDEwMCl7DQogICAgaWYgKGlzLnh0cyh4c2VyaWVzKSkgDQogICAgICAgIHggPC0gY29yZWRhdGEoeHNlcmllcykNCiAgICBlbHNlIGlmIChpcy5tYXRyaXgoeHNlcmllcykpIA0KICAgICAgICB4IDwtIHhzZXJpZXMNCiAgICBlbHNlIHggPC0gbWF0cml4KHhzZXJpZXMsIG5yb3cgPSAxKQ0KICAgIGxsIDwtIGFwcGx5KHgsIDEsIGZ1bmN0aW9uKHgsIHIsIEssIFQsIHNpZ21hLCBTKSB7DQogICAgICAgIGRlbHRhdCA8LSA1LzI1MA0KICAgICAgICBWX3QwIDwtIEJsYWNrX1NjaG9sZXMoMCwgUywgciwgc2lnbWEsIEssIFQsICJjYWxsIikNCiAgICAgICAgVl90MSA9IEJsYWNrX1NjaG9sZXMoZGVsdGF0LCBleHAobG9nKFMpICsgeFsxXSksIHIsIGV4cChsb2coc2lnbWEpICsgDQogICAgICAgICAgICB4WzJdKSwgSywgVCwgImNhbGwiKQ0KICAgICAgICAtKFZfdDEgLSBWX3QwKS9WX3QwDQogICAgfSwgciA9IHIsIEsgPSBLLCBUID0gVCwgc2lnbWEgPSBzaWdtYSwgUyA9IFMpDQogICAgaWYgKGlzLnh0cyh4c2VyaWVzKSkgDQogICAgICAgIGxsIDwtIHh0cyhsbCwgdGltZSh4c2VyaWVzKSkNCiAgICBsbA0KfQ0KYGBgDQoNCllvdXIgY2hhbGxlbmdlIGlzIHRvIGNvbXB1dGUgdGhlIDk5JSBWYVIgZm9yIHdlZWtseSBjaGFuZ2VzIGluIHZhbHVlIG9mIHRoZSBFdXJvcGVhbiBjYWxsIG9wdGlvbiBpbiByZXR1cm5zIHdoZW4gdGhlIGN1cnJlbnQgc3RvY2sgcHJpY2UgaXMgUyA9IDEyMCBhbmQgdGhlIGN1cnJlbnQgdm9sYXRpbGl0eSBpcyBzaWdtYSA9IDAuMjUuDQpgYGB7cn0NCnJldHVybl93IDwtIGFwcGx5LndlZWtseShyZXR1cm5zLCBjb2xTdW1zKQ0KaHNsb3NzZXMgPC0gbG9zc29wKHJldHVybl93LCBTID0gMTIwLCBzaWdtYSA9IDAuMjUpDQpxdWFudGlsZShoc2xvc3NlcywgMC45OTUpDQpgYGANCg0K