This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

library("fBasics")
载入需要的程辑包:timeDate
载入需要的程辑包:timeSeries
  1. Consider the daily stock returns of American Express (AXP), Caterpillar (CAT), and Starbucks (SBUX) from January 1999 to December 2008. The data are simple returns given in the file d- 3stocks9908.txt (date, axp, cat, sbux).
df = data.table::fread('/Users/aisling/Documents/daydayup/nus_mqf/Financial Time Series/homework/Homework/HW 1/d-3stocks9908.txt',index = 'date')
head(df)
NA
  1. Compute the sample mean, standard deviation, skewness, excess kurtosis, minimum, and maximum of each simple return series. (Hint: use the R command basicStats of fBasics)
basicStats(df)
  1. Transform the simple returns to log returns. Compute the sample mean, standard deviation, skewness, excess kurtosis, minimum, and maximum of each log return series.
logR = (log(df+1))
basicStats(logR)
NA
  1. Test the null hypothesis that the mean of the log returns of AXP is zero. (Hint: use the R command t.test)
axp_pvalue = t.test(logR$axp)$p.value
sprintf('the p-value is %s, so we should not reject the null hypothesis that the mean of the log returns of AXP is zero.',axp_pvalue)
[1] "the p-value is 0.752367158391223, so we should not reject the null hypothesis that the mean of the log returns of AXP is zero."
  1. Obtain the histogram (with nclass=40) and sample density plot of the daily log returns of AXP stock.
require(ggplot2)
ggplot(data = logR, aes(logR$axp)) +
  geom_histogram(bins = 40) +
  labs(title="sample density plot of the daily log returns of AXP stock") +
  labs(x=" log return ", y="Freq")

  1. Test if log return of AXP follows normal distribution by using at least two methods. (Need to give explanation)
# 1.The Jarque-Bera Test,a type of Lagrange multiplier test, is a test for normality. It is usually used for large data sets, because other normality tests are not reliable when n is large (for example, Shapiro-Wilk isn’t reliable with n more than 2,000).A normal distribution has a skew of zero (i.e. it’s perfectly symmetrical around the mean) and a kurtosis of three; In general, a large J-B value indicates that errors are not normally distributed.

# 2. Shapiro-Wilk test is a way to tell if a random sample comes from a normal distribution. The test gives us a W value; small values indicate the sample is not normally distributed (you can reject the null hypothesis that your population is normally distributed if your values are under a certain threshold). 

axp_jb_test = normalTest(logR$axp,method="jb")
axp_jb_pvalue = axp_jb_test@test$p.value
sprintf("P Value is %s, hence %s null hypothesis of normality", axp_jb_pvalue ,ifelse(pvalue <= 0.05, "Reject","Do not reject"))
[1] "P Value is 0, hence Do not reject null hypothesis of normality"
 
axp_sw_test = normalTest(logR$axp,method="sw")
axp_sw_pvalue = axp_sw_test@test$p.value
sprintf("P Value is %s, hence %s null hypothesis of normality", axp_sw_pvalue ,ifelse(pvalue <= 0.05, "Reject","Do not reject") )
[1] "P Value is 7.78170086263107e-33, hence Do not reject null hypothesis of normality"
  1. Answer the same questions as Problem 1 but using monthly returns for General Motors (GM), CRSP value-weighted index (VW), CRSP equal-weighted index (EW) and S&P composite index from January 1975 to December 2008. The returns of the indexes include dividend distributions. Data file is m-gm3dx7508.txt (date, gm, vw, ew, sp).
df_2 = data.table::fread('/Users/aisling/Documents/daydayup/nus_mqf/Financial Time Series/homework/Homework/HW 1/m-gm3dx7508.txt',index = 'date')
head(df_2)
basicStats(df_2)
NA
logR2 = (log(df_2+1))
basicStats(logR2)
# Test the null hypothesis that the mean of the log returns of stock is zero

for (col_name in colnames(logR2)[-1]){
  axp_pvalue2 = t.test(logR2[,col_name,with = F])$p.value
  res <- ifelse(axp_pvalue2 < 0.05 ,'reject','accept')
  print(sprintf('the p-value is %s, so we should %s the null hypothesis that the mean of the log returns of %s is zero.',axp_pvalue2,res,col_name))
  
  }
[1] "the p-value is 0.816604171543212, so we should accept the null hypothesis that the mean of the log returns of gm is zero."
[1] "the p-value is 7.33172261828164e-05, so we should reject the null hypothesis that the mean of the log returns of vw is zero."
[1] "the p-value is 3.42511340170795e-05, so we should reject the null hypothesis that the mean of the log returns of ew is zero."
[1] "the p-value is 0.00393916498183515, so we should reject the null hypothesis that the mean of the log returns of sp is zero."
# Obtain the histogram (with nclass=40) and sample density plot of the daily log returns of the stock.
for (col_name in colnames(logR2)[-1]){
  
  print( ggplot(data = logR2, aes(logR2[[col_name]])) +
           geom_histogram(bins = 40) +
           labs(title= cat(" density plot ")) +
           labs(x=paste0("log return of  ", col_name), y="Freq"))
  
  }
 density plot  density plot  density plot  density plot 

NA
# Test if log return of the stock follows normal distribution by using at least two methods. (Need to give explanation)

# 1.The Jarque-Bera Test,a type of Lagrange multiplier test, is a test for normality. It is usually used for large data sets, because other normality tests are not reliable when n is large (for example, Shapiro-Wilk isn’t reliable with n more than 2,000).A normal distribution has a skew of zero (i.e. it’s perfectly symmetrical around the mean) and a kurtosis of three; In general, a large J-B value indicates that errors are not normally distributed.

# 2. Shapiro-Wilk test is a way to tell if a random sample comes from a normal distribution. The test gives us a W value; small values indicate the sample is not normally distributed (you can reject the null hypothesis that your population is normally distributed if your values are under a certain threshold). 


for (col_name in colnames(logR2)[-1]){
  
  print(sprintf('============================ %s ====================================',col_name))


  jb_test = normalTest(logR2[[col_name]],method="jb")
  jb_pvalue = jb_test@test$p.value
  res_jb2 <- ifelse(axp_pvalue2 < 0.05 ,'reject','do not reject')
  print(sprintf("Jarque Bera Test: P Value is %s, hence %s null hypothesis of normality", jb_pvalue ,res_jb2))
  
  
  sw_test = normalTest(logR2[[col_name]],method="sw")
  sw_pvalue = sw_test@test$p.value
  res_sw2 <- ifelse(axp_pvalue2 < 0.05 ,'reject','do not reject')
  print(sprintf("Shapiro-Wilk test : P Value is %s, hence %s null hypothesis of normality", sw_pvalue ,res_sw2 ))
  
}
[1] "============================ gm ===================================="
[1] "Jarque Bera Test: P Value is 0, hence reject null hypothesis of normality"
[1] "Shapiro-Wilk test : P Value is 6.01277515227384e-12, hence reject null hypothesis of normality"
[1] "============================ vw ===================================="
[1] "Jarque Bera Test: P Value is 0, hence reject null hypothesis of normality"
[1] "Shapiro-Wilk test : P Value is 8.10694896883752e-11, hence reject null hypothesis of normality"
[1] "============================ ew ===================================="
[1] "Jarque Bera Test: P Value is 0, hence reject null hypothesis of normality"
[1] "Shapiro-Wilk test : P Value is 1.04817251126734e-12, hence reject null hypothesis of normality"
[1] "============================ sp ===================================="
[1] "Jarque Bera Test: P Value is 0, hence reject null hypothesis of normality"
[1] "Shapiro-Wilk test : P Value is 4.14264029673579e-09, hence reject null hypothesis of normality"
  1. Consider the monthly stock returns of value-weighted index (VW) from January 1975 to December 2008 in Problem 2. Perform the tests and draw conclusions using the 5% significance level.
  1. Test H0: μ = 0 versus Ha : μ ≠ 0,where μ denotes the mean return.
pvalue = t.test(logR2[['vw']] ) $p.value
sprintf("The p-value is %s, hence we %s the null hypothesis that the mean is 0",  pvalue , ifelse(pvalue <= 0.05, "Reject","Do not reject") )
[1] "The p-value is 7.33172261828164e-05, hence we Reject the null hypothesis that the mean is 0"
  1. Test H0: m3 = 0 versus Ha : m3 ≠ 0, where m3 denotes the skewness.
library(moments)
# agostino.test(x)  # 峰度检验

pvalue = agostino.test(logR2[['vw']] )$p.value
sprintf("The p-value is %s, hence we %s the null hypothesis that skewness is 0", pvalue , ifelse(pvalue <= 0.05, "Reject","Do not reject") )
[1] "The p-value is 1.28785870856518e-13, hence we Reject the null hypothesis that skewness is 0"
  1. Test H0: K = 3 versus Ha : K ≠ 3, where K denotes the kurtosis.
# anscombe.test(x)  # 偏度检验
pvalue = anscombe.test(logR2[['vw']] )$p.value
sprintf("The p-value is %s, hence we %s the null hypothesis that the kurtosis is 3",  pvalue ,ifelse(pvalue <= 0.05, "Reject","Do not reject") )
[1] "The p-value is 3.91860472957707e-11, hence we Reject the null hypothesis that the kurtosis is 3"
  1. Consider the daily log returns of AXP stock from January 1999 to December 2008 as in Problem 1. Perform the following tests:
  1. Test the null hypothesis that the skewness measure of the returns is zero;

pvalue = agostino.test(logR[['axp']] )$p.value
sprintf("The p-value is %s, hence we %s the null hypothesis that skewness is 0", pvalue , ifelse(pvalue <= 0.05, "Reject","Do not reject") )
[1] "The p-value is 1.67548197538281e-11, hence we Reject the null hypothesis that skewness is 0"
  1. Test the null hypothesis that the excess kurtosis of the returns is zero.
 
pvalue = anscombe.test(logR[['axp']] )$p.value
sprintf("The p-value is %s, hence we %s the null hypothesis that the kurtosis is 3",  pvalue , ifelse(pvalue <= 0.05, "Reject","Do not reject") )
[1] "The p-value is 1.57492483442182e-76, hence we Reject the null hypothesis that the kurtosis is 3"
  1. Daily foreign exchange rates (spot rates) can be obtained from the Federal Reserve Bank in St Louis (FRED). The data are the noon buying rates in New York City certified by the Federal Reserve Bank of New York. Consider the exchange rates between the U.S. dollar and the Euro from January 4, 1999 to March 8, 2013. See the file d-exuseu.txt.
  1. Compute the daily log return of the exchange rate.
df_5 = data.table::fread('/Users/aisling/Documents/daydayup/nus_mqf/Financial Time Series/homework/Homework/HW 1/d-exuseu.txt')
head(df_5)
logR5 = diff(log(df_5$VALUE))
head(logR5)
[1] -0.004412021 -0.010600202  0.003089071 -0.010161114 -0.001732502  0.001213067
  1. Compute the sample mean, standard deviation, skewness, excess kurtosis, minimum, and maximum of the log returns of the exchange rate.
basicStats(logR5)
  1. Obtain a density plot of the daily long returns of Dollar-Euro exchange rate.
plot(density(logR5))

  1. Test H0: μ = 0 versus Ha : μ ≠ 0, where μ denotes the mean of the daily log return of Dollar- Euro exchange rate.

pvalue = t.test(logR5)$p.value
sprintf("The p-value is %s, hence we %s the null hypothesis that the mean of Dollar Euro Exchange Return is 0", pvalue , ifelse(pvalue <= 0.05, "Reject","Do not reject"))
[1] "The p-value is 0.806554013958007, hence we Do not reject the null hypothesis that the mean of Dollar Euro Exchange Return is 0"
  1. Consider SP500 and IBM data (in file ‘SP.csv’ and ‘IBM.csv’ respectively):
df_sp=  data.table::fread('/Users/aisling/Documents/daydayup/nus_mqf/Financial Time Series/homework/Homework/HW 1/SP.CSV',index = 'V1')
df_ibm = data.table::fread('/Users/aisling/Documents/daydayup/nus_mqf/Financial Time Series/homework/Homework/HW 1/IBM.CSV',index = 'V1')

head(df_sp)
head(df_ibm)
NA
  1. Find the log return of SP and IBM by using ‘Adjusted Price’
logR_sp = diff(log(df_sp[["SP.Adjusted"]]))
logR_ibm = diff(log(df_ibm[["IBM.Adjusted"]]))

head(logR_sp)
[1] -0.052185651 -0.026072347  0.023969244  0.018511805 -0.016934050 -0.008178439
head(logR_ibm)
[1]  0.010635805 -0.009094314  0.015077732  0.011760352 -0.011861601 -0.002429755
  1. Merge the above two return series into a new dataset (hint: using ‘data.frame’) and plot them (y is IBM, x is SP)
df_new = data.frame(y = logR_ibm , x = logR_sp)
qplot(df_new$y, df_new$y)

  1. Find the best linear model by using AIC as criterion (need to show all your models)
m1 <- lm(y ~ x, df_new)
summary(m1)

Call:
lm(formula = y ~ x, data = df_new)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.086931 -0.006241  0.000360  0.006798  0.093286 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 0.0001795  0.0002345   0.766    0.444    
x           0.2314457  0.0109979  21.045   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01308 on 3111 degrees of freedom
Multiple R-squared:  0.1246,    Adjusted R-squared:  0.1243 
F-statistic: 442.9 on 1 and 3111 DF,  p-value: < 2.2e-16
sprintf('fit the model y ~ x ,AIC = %s ',AIC(m1))
[1] "fit the model y ~ x ,AIC = -18160.9543106046 "
confint(m1)
                    2.5 %       97.5 %
(Intercept) -0.0002802095 0.0006392583
x            0.2098817677 0.2530095436
# generate some other variables : 
idx = which(df_new$x <= 0)
nsp <- rep(0,length(df_new$x))
nsp[idx] = df_new$x[idx]
c1 <- rep(0,length(df_new$x))
c1[idx] = 1
 
df_new2 <- data.frame(y = df_new$y, x = df_new$x, c1, nsp)   
m2 <- lm(y ~ x + c1 , df_new2) 
summary(m2)

Call:
lm(formula = y ~ x + c1, data = df_new2)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.086854 -0.006247  0.000366  0.006818  0.093189 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 9.841e-05  4.065e-04   0.242    0.809    
x           2.341e-01  1.550e-02  15.107   <2e-16 ***
c1          1.614e-04  6.608e-04   0.244    0.807    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01308 on 3110 degrees of freedom
Multiple R-squared:  0.1246,    Adjusted R-squared:  0.1241 
F-statistic: 221.4 on 2 and 3110 DF,  p-value: < 2.2e-16
m3 <- lm(y ~ x + nsp, df_new2) 
summary(m3)

Call:
lm(formula = y ~ x + nsp, data = df_new2)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.086771 -0.006218  0.000382  0.006816  0.092673 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  2.566e-06  3.303e-04   0.008    0.994    
x            2.432e-01  1.900e-02  12.803   <2e-16 ***
nsp         -2.357e-02  3.099e-02  -0.760    0.447    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01308 on 3110 degrees of freedom
Multiple R-squared:  0.1248,    Adjusted R-squared:  0.1242 
F-statistic: 221.7 on 2 and 3110 DF,  p-value: < 2.2e-16
m4 <- lm(y ~ x + c1 + nsp, df_new2)
summary(m4)

Call:
lm(formula = y ~ x + c1 + nsp, data = df_new2)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.086690 -0.006189  0.000400  0.006812  0.092568 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -8.292e-05  4.707e-04  -0.176    0.860    
x            2.461e-01  2.202e-02  11.173   <2e-16 ***
c1           1.685e-04  6.609e-04   0.255    0.799    
nsp         -2.368e-02  3.100e-02  -0.764    0.445    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01308 on 3109 degrees of freedom
Multiple R-squared:  0.1248,    Adjusted R-squared:  0.124 
F-statistic: 147.8 on 3 and 3109 DF,  p-value: < 2.2e-16
library(MASS)
m5 <- stepAIC(m4) 
Start:  AIC=-26993.91
y ~ x + c1 + nsp

       Df Sum of Sq     RSS    AIC
- c1    1 0.0000111 0.53230 -26996
- nsp   1 0.0000999 0.53238 -26995
<none>              0.53228 -26994
- x     1 0.0213730 0.55366 -26873

Step:  AIC=-26995.84
y ~ x + nsp

       Df Sum of Sq     RSS    AIC
- nsp   1  0.000099 0.53239 -26997
<none>              0.53230 -26996
- x     1  0.028054 0.56035 -26838

Step:  AIC=-26997.27
y ~ x

       Df Sum of Sq     RSS    AIC
<none>              0.53239 -26997
- x     1   0.07579 0.60818 -26585
summary(m5)

Call:
lm(formula = y ~ x, data = df_new2)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.086931 -0.006241  0.000360  0.006798  0.093286 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 0.0001795  0.0002345   0.766    0.444    
x           0.2314457  0.0109979  21.045   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01308 on 3111 degrees of freedom
Multiple R-squared:  0.1246,    Adjusted R-squared:  0.1243 
F-statistic: 442.9 on 1 and 3111 DF,  p-value: < 2.2e-16
sprintf('fit the model y ~ x + c1 ,AIC = %s ',AIC(m2))
[1] "fit the model y ~ x + c1 ,AIC = -18159.0140536929 "
sprintf('fit the model y ~ x + nsp ,AIC = %s ',AIC(m3))
[1] "fit the model y ~ x + nsp ,AIC = -18159.5331433622 "
sprintf('fit the model y ~ x + c1 + nsp ,AIC = %s ',AIC(m4))
[1] "fit the model y ~ x + c1 + nsp ,AIC = -18157.5982207751 "
sprintf('fit the model y ~ x + c1 + nsp ,remove nonsignificant variables one at a time while minimising AIC, AIC = %s ',AIC(m5))
[1] "fit the model y ~ x + c1 + nsp ,remove nonsignificant variables one at a time while minimising AIC, AIC = -18160.9543106046 "

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tCnRpdGxlOiAiSG9tZXdvcmsiCmF1dGhvcjogInlhcWlhbmhlIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiAKClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLiAKCmBgYHtyfQpsaWJyYXJ5KCJmQmFzaWNzIikKYGBgCjEuIENvbnNpZGVyIHRoZSBkYWlseSBzdG9jayByZXR1cm5zIG9mIEFtZXJpY2FuIEV4cHJlc3MgKEFYUCksIENhdGVycGlsbGFyIChDQVQpLCBhbmQgU3RhcmJ1Y2tzIChTQlVYKSBmcm9tIEphbnVhcnkgMTk5OSB0byBEZWNlbWJlciAyMDA4LiBUaGUgZGF0YSBhcmUgc2ltcGxlIHJldHVybnMgZ2l2ZW4gaW4gdGhlIGZpbGUgZC0gM3N0b2Nrczk5MDgudHh0IChkYXRlLCBheHAsIGNhdCwgc2J1eCkuCgpgYGB7cn0KZGYgPSBkYXRhLnRhYmxlOjpmcmVhZCgnL1VzZXJzL2Fpc2xpbmcvRG9jdW1lbnRzL2RheWRheXVwL251c19tcWYvRmluYW5jaWFsIFRpbWUgU2VyaWVzL2hvbWV3b3JrL0hvbWV3b3JrL0hXIDEvZC0zc3RvY2tzOTkwOC50eHQnLGluZGV4ID0gJ2RhdGUnKQpoZWFkKGRmKQpgYGAKCihhKSBDb21wdXRlIHRoZSBzYW1wbGUgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uLCBza2V3bmVzcywgZXhjZXNzIGt1cnRvc2lzLCBtaW5pbXVtLCBhbmQgbWF4aW11bSBvZiBlYWNoIHNpbXBsZSByZXR1cm4gc2VyaWVzLiAoSGludDogdXNlIHRoZSBSIGNvbW1hbmQgYmFzaWNTdGF0cyBvZiBmQmFzaWNzKQoKYGBge3J9CmJhc2ljU3RhdHMoZGYpCmBgYAooYikgVHJhbnNmb3JtIHRoZSBzaW1wbGUgcmV0dXJucyB0byBsb2cgcmV0dXJucy4gQ29tcHV0ZSB0aGUgc2FtcGxlIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgc2tld25lc3MsIGV4Y2VzcyBrdXJ0b3NpcywgbWluaW11bSwgYW5kIG1heGltdW0gb2YgZWFjaCBsb2cgcmV0dXJuIHNlcmllcy4KCmBgYHtyfQpsb2dSID0gKGxvZyhkZisxKSkKYmFzaWNTdGF0cyhsb2dSKQpgYGAKCihjKSBUZXN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgbWVhbiBvZiB0aGUgbG9nIHJldHVybnMgb2YgQVhQIGlzIHplcm8uIChIaW50OiB1c2UgdGhlIFIgY29tbWFuZCB0LnRlc3QpCgpgYGB7cn0KYXhwX3B2YWx1ZSA9IHQudGVzdChsb2dSJGF4cCkkcC52YWx1ZQpzcHJpbnRmKCd0aGUgcC12YWx1ZSBpcyAlcywgc28gd2Ugc2hvdWxkIG5vdCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSBtZWFuIG9mIHRoZSBsb2cgcmV0dXJucyBvZiBBWFAgaXMgemVyby4nLGF4cF9wdmFsdWUpCmBgYAoKKGQpIE9idGFpbiB0aGUgaGlzdG9ncmFtICh3aXRoIG5jbGFzcz00MCkgYW5kIHNhbXBsZSBkZW5zaXR5IHBsb3Qgb2YgdGhlIGRhaWx5IGxvZyByZXR1cm5zIG9mIEFYUCBzdG9jay4KCmBgYHtyfQpyZXF1aXJlKGdncGxvdDIpCmdncGxvdChkYXRhID0gbG9nUiwgYWVzKGxvZ1IkYXhwKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA0MCkgKwogIGxhYnModGl0bGU9InNhbXBsZSBkZW5zaXR5IHBsb3Qgb2YgdGhlIGRhaWx5IGxvZyByZXR1cm5zIG9mIEFYUCBzdG9jayIpICsKICBsYWJzKHg9IiBsb2cgcmV0dXJuICIsIHk9IkZyZXEiKQpgYGAKKGUpIFRlc3QgaWYgbG9nIHJldHVybiBvZiBBWFAgZm9sbG93cyBub3JtYWwgZGlzdHJpYnV0aW9uIGJ5IHVzaW5nIGF0IGxlYXN0IHR3byBtZXRob2RzLiAoTmVlZCB0byBnaXZlIGV4cGxhbmF0aW9uKQoKYGBge3J9CiMgMS5UaGUgSmFycXVlLUJlcmEgVGVzdCxhIHR5cGUgb2YgTGFncmFuZ2UgbXVsdGlwbGllciB0ZXN0LCBpcyBhIHRlc3QgZm9yIG5vcm1hbGl0eS4gSXQgaXMgdXN1YWxseSB1c2VkIGZvciBsYXJnZSBkYXRhIHNldHMsIGJlY2F1c2Ugb3RoZXIgbm9ybWFsaXR5IHRlc3RzIGFyZSBub3QgcmVsaWFibGUgd2hlbiBuIGlzIGxhcmdlIChmb3IgZXhhbXBsZSwgU2hhcGlyby1XaWxrIGlzbuKAmXQgcmVsaWFibGUgd2l0aCBuIG1vcmUgdGhhbiAyLDAwMCkuQSBub3JtYWwgZGlzdHJpYnV0aW9uIGhhcyBhIHNrZXcgb2YgemVybyAoaS5lLiBpdOKAmXMgcGVyZmVjdGx5IHN5bW1ldHJpY2FsIGFyb3VuZCB0aGUgbWVhbikgYW5kIGEga3VydG9zaXMgb2YgdGhyZWU7IEluIGdlbmVyYWwsIGEgbGFyZ2UgSi1CIHZhbHVlIGluZGljYXRlcyB0aGF0IGVycm9ycyBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyAyLiBTaGFwaXJvLVdpbGsgdGVzdCBpcyBhIHdheSB0byB0ZWxsIGlmIGEgcmFuZG9tIHNhbXBsZSBjb21lcyBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVGhlIHRlc3QgZ2l2ZXMgdXMgYSBXIHZhbHVlOyBzbWFsbCB2YWx1ZXMgaW5kaWNhdGUgdGhlIHNhbXBsZSBpcyBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgKHlvdSBjYW4gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB5b3VyIHBvcHVsYXRpb24gaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgaWYgeW91ciB2YWx1ZXMgYXJlIHVuZGVyIGEgY2VydGFpbiB0aHJlc2hvbGQpLiAKCmF4cF9qYl90ZXN0ID0gbm9ybWFsVGVzdChsb2dSJGF4cCxtZXRob2Q9ImpiIikKYXhwX2piX3B2YWx1ZSA9IGF4cF9qYl90ZXN0QHRlc3QkcC52YWx1ZQpzcHJpbnRmKCJQIFZhbHVlIGlzICVzLCBoZW5jZSAlcyBudWxsIGh5cG90aGVzaXMgb2Ygbm9ybWFsaXR5IiwgYXhwX2piX3B2YWx1ZSAsaWZlbHNlKHB2YWx1ZSA8PSAwLjA1LCAiUmVqZWN0IiwiRG8gbm90IHJlamVjdCIpKQogCmF4cF9zd190ZXN0ID0gbm9ybWFsVGVzdChsb2dSJGF4cCxtZXRob2Q9InN3IikKYXhwX3N3X3B2YWx1ZSA9IGF4cF9zd190ZXN0QHRlc3QkcC52YWx1ZQpzcHJpbnRmKCJQIFZhbHVlIGlzICVzLCBoZW5jZSAlcyBudWxsIGh5cG90aGVzaXMgb2Ygbm9ybWFsaXR5IiwgYXhwX3N3X3B2YWx1ZSAsaWZlbHNlKHB2YWx1ZSA8PSAwLjA1LCAiUmVqZWN0IiwiRG8gbm90IHJlamVjdCIpICkKYGBgCjIuIEFuc3dlciB0aGUgc2FtZSBxdWVzdGlvbnMgYXMgUHJvYmxlbSAxIGJ1dCB1c2luZyBtb250aGx5IHJldHVybnMgZm9yIEdlbmVyYWwgTW90b3JzIChHTSksIENSU1AgdmFsdWUtd2VpZ2h0ZWQgaW5kZXggKFZXKSwgQ1JTUCBlcXVhbC13ZWlnaHRlZCBpbmRleCAoRVcpIGFuZCBTJlAgY29tcG9zaXRlIGluZGV4IGZyb20gSmFudWFyeSAxOTc1IHRvIERlY2VtYmVyIDIwMDguIFRoZSByZXR1cm5zIG9mIHRoZSBpbmRleGVzIGluY2x1ZGUgZGl2aWRlbmQgZGlzdHJpYnV0aW9ucy4gRGF0YSBmaWxlIGlzIG0tZ20zZHg3NTA4LnR4dCAoZGF0ZSwgZ20sIHZ3LCBldywgc3ApLgoKYGBge3J9CmRmXzIgPSBkYXRhLnRhYmxlOjpmcmVhZCgnL1VzZXJzL2Fpc2xpbmcvRG9jdW1lbnRzL2RheWRheXVwL251c19tcWYvRmluYW5jaWFsIFRpbWUgU2VyaWVzL2hvbWV3b3JrL0hvbWV3b3JrL0hXIDEvbS1nbTNkeDc1MDgudHh0JyxpbmRleCA9ICdkYXRlJykKaGVhZChkZl8yKQpgYGAKCmBgYHtyfQpiYXNpY1N0YXRzKGRmXzIpCmBgYAoKYGBge3J9CmxvZ1IyID0gKGxvZyhkZl8yKzEpKQpiYXNpY1N0YXRzKGxvZ1IyKQpgYGAKCmBgYHtyfQojIFRlc3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSBtZWFuIG9mIHRoZSBsb2cgcmV0dXJucyBvZiBzdG9jayBpcyB6ZXJvCgpmb3IgKGNvbF9uYW1lIGluIGNvbG5hbWVzKGxvZ1IyKVstMV0pewogIGF4cF9wdmFsdWUyID0gdC50ZXN0KGxvZ1IyWyxjb2xfbmFtZSx3aXRoID0gRl0pJHAudmFsdWUKICByZXMgPC0gaWZlbHNlKGF4cF9wdmFsdWUyIDwgMC4wNSAsJ3JlamVjdCcsJ2FjY2VwdCcpCiAgcHJpbnQoc3ByaW50ZigndGhlIHAtdmFsdWUgaXMgJXMsIHNvIHdlIHNob3VsZCAlcyB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIG1lYW4gb2YgdGhlIGxvZyByZXR1cm5zIG9mICVzIGlzIHplcm8uJyxheHBfcHZhbHVlMixyZXMsY29sX25hbWUpKQogIAogIH0KYGBgCgpgYGB7cn0KIyBPYnRhaW4gdGhlIGhpc3RvZ3JhbSAod2l0aCBuY2xhc3M9NDApIGFuZCBzYW1wbGUgZGVuc2l0eSBwbG90IG9mIHRoZSBkYWlseSBsb2cgcmV0dXJucyBvZiB0aGUgc3RvY2suCmZvciAoY29sX25hbWUgaW4gY29sbmFtZXMobG9nUjIpWy0xXSl7CiAgCiAgcHJpbnQoIGdncGxvdChkYXRhID0gbG9nUjIsIGFlcyhsb2dSMltbY29sX25hbWVdXSkpICsKICAgICAgICAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNDApICsKICAgICAgICAgICBsYWJzKHRpdGxlPSBjYXQoIiBkZW5zaXR5IHBsb3QgIikpICsKICAgICAgICAgICBsYWJzKHg9cGFzdGUwKCJsb2cgcmV0dXJuIG9mICAiLCBjb2xfbmFtZSksIHk9IkZyZXEiKSkKICAKICB9CiAgCmBgYAoKYGBge3J9CiMgVGVzdCBpZiBsb2cgcmV0dXJuIG9mIHRoZSBzdG9jayBmb2xsb3dzIG5vcm1hbCBkaXN0cmlidXRpb24gYnkgdXNpbmcgYXQgbGVhc3QgdHdvIG1ldGhvZHMuIChOZWVkIHRvIGdpdmUgZXhwbGFuYXRpb24pCgoKCgpmb3IgKGNvbF9uYW1lIGluIGNvbG5hbWVzKGxvZ1IyKVstMV0pewogIAogIHByaW50KHNwcmludGYoJz09PT09PT09PT09PT09PT09PT09PT09PT09PT0gJXMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Jyxjb2xfbmFtZSkpCgoKICBqYl90ZXN0ID0gbm9ybWFsVGVzdChsb2dSMltbY29sX25hbWVdXSxtZXRob2Q9ImpiIikKICBqYl9wdmFsdWUgPSBqYl90ZXN0QHRlc3QkcC52YWx1ZQogIHJlc19qYjIgPC0gaWZlbHNlKGF4cF9wdmFsdWUyIDwgMC4wNSAsJ3JlamVjdCcsJ2RvIG5vdCByZWplY3QnKQogIHByaW50KHNwcmludGYoIkphcnF1ZSBCZXJhIFRlc3Q6IFAgVmFsdWUgaXMgJXMsIGhlbmNlICVzIG51bGwgaHlwb3RoZXNpcyBvZiBub3JtYWxpdHkiLCBqYl9wdmFsdWUgLHJlc19qYjIpKQogIAogIAogIHN3X3Rlc3QgPSBub3JtYWxUZXN0KGxvZ1IyW1tjb2xfbmFtZV1dLG1ldGhvZD0ic3ciKQogIHN3X3B2YWx1ZSA9IHN3X3Rlc3RAdGVzdCRwLnZhbHVlCiAgcmVzX3N3MiA8LSBpZmVsc2UoYXhwX3B2YWx1ZTIgPCAwLjA1ICwncmVqZWN0JywnZG8gbm90IHJlamVjdCcpCiAgcHJpbnQoc3ByaW50ZigiU2hhcGlyby1XaWxrIHRlc3QgOiBQIFZhbHVlIGlzICVzLCBoZW5jZSAlcyBudWxsIGh5cG90aGVzaXMgb2Ygbm9ybWFsaXR5Iiwgc3dfcHZhbHVlICxyZXNfc3cyICkpCiAgCn0KYGBgCgozLiBDb25zaWRlciB0aGUgbW9udGhseSBzdG9jayByZXR1cm5zIG9mIHZhbHVlLXdlaWdodGVkIGluZGV4IChWVykgZnJvbSBKYW51YXJ5IDE5NzUgdG8gRGVjZW1iZXIgMjAwOCBpbiBQcm9ibGVtIDIuIFBlcmZvcm0gdGhlIHRlc3RzIGFuZCBkcmF3IGNvbmNsdXNpb25zIHVzaW5nIHRoZSA1JSBzaWduaWZpY2FuY2UgbGV2ZWwuCgooYSkgVGVzdCBIMDogzrwgPSAwIHZlcnN1cyBIYSA6IM68ID3MuCAwLHdoZXJlIM68IGRlbm90ZXMgdGhlIG1lYW4gcmV0dXJuLgoKYGBge3J9CnB2YWx1ZSA9IHQudGVzdChsb2dSMltbJ3Z3J11dICkgJHAudmFsdWUKc3ByaW50ZigiVGhlIHAtdmFsdWUgaXMgJXMsIGhlbmNlIHdlICVzIHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgbWVhbiBpcyAwIiwgIHB2YWx1ZSAsIGlmZWxzZShwdmFsdWUgPD0gMC4wNSwgIlJlamVjdCIsIkRvIG5vdCByZWplY3QiKSApCgpgYGAKCgooYikgVGVzdCBIMDogbTMgPSAwIHZlcnN1cyBIYSA6IG0zID3MuCAwLCB3aGVyZSBtMyBkZW5vdGVzIHRoZSBza2V3bmVzcy4KCmBgYHtyfQpsaWJyYXJ5KG1vbWVudHMpCiMgYWdvc3Rpbm8udGVzdCh4KSAgIyDls7Dluqbmo4DpqowKCnB2YWx1ZSA9IGFnb3N0aW5vLnRlc3QobG9nUjJbWyd2dyddXSApJHAudmFsdWUKc3ByaW50ZigiVGhlIHAtdmFsdWUgaXMgJXMsIGhlbmNlIHdlICVzIHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCBza2V3bmVzcyBpcyAwIiwgcHZhbHVlICwgaWZlbHNlKHB2YWx1ZSA8PSAwLjA1LCAiUmVqZWN0IiwiRG8gbm90IHJlamVjdCIpICkKCmBgYAoKKGMpIFRlc3QgSDA6IEsgPSAzIHZlcnN1cyBIYSA6IEsgPcy4IDMsIHdoZXJlIEsgZGVub3RlcyB0aGUga3VydG9zaXMuCgpgYGB7cn0KIyBhbnNjb21iZS50ZXN0KHgpICAjIOWBj+W6puajgOmqjApwdmFsdWUgPSBhbnNjb21iZS50ZXN0KGxvZ1IyW1sndncnXV0gKSRwLnZhbHVlCnNwcmludGYoIlRoZSBwLXZhbHVlIGlzICVzLCBoZW5jZSB3ZSAlcyB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIGt1cnRvc2lzIGlzIDMiLCAgcHZhbHVlICxpZmVsc2UocHZhbHVlIDw9IDAuMDUsICJSZWplY3QiLCJEbyBub3QgcmVqZWN0IikgKQoKYGBgCgo0LiBDb25zaWRlciB0aGUgZGFpbHkgbG9nIHJldHVybnMgb2YgQVhQIHN0b2NrIGZyb20gSmFudWFyeSAxOTk5IHRvIERlY2VtYmVyIDIwMDggYXMgaW4gUHJvYmxlbSAxLiBQZXJmb3JtIHRoZSBmb2xsb3dpbmcgdGVzdHM6CihhKSBUZXN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgc2tld25lc3MgbWVhc3VyZSBvZiB0aGUgcmV0dXJucyBpcyB6ZXJvOyAKYGBge3J9CgpwdmFsdWUgPSBhZ29zdGluby50ZXN0KGxvZ1JbWydheHAnXV0gKSRwLnZhbHVlCnNwcmludGYoIlRoZSBwLXZhbHVlIGlzICVzLCBoZW5jZSB3ZSAlcyB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgc2tld25lc3MgaXMgMCIsIHB2YWx1ZSAsIGlmZWxzZShwdmFsdWUgPD0gMC4wNSwgIlJlamVjdCIsIkRvIG5vdCByZWplY3QiKSApCgpgYGAKCihiKSBUZXN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgZXhjZXNzIGt1cnRvc2lzIG9mIHRoZSByZXR1cm5zIGlzIHplcm8uCmBgYHtyfQogCnB2YWx1ZSA9IGFuc2NvbWJlLnRlc3QobG9nUltbJ2F4cCddXSApJHAudmFsdWUKc3ByaW50ZigiVGhlIHAtdmFsdWUgaXMgJXMsIGhlbmNlIHdlICVzIHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUga3VydG9zaXMgaXMgMyIsICBwdmFsdWUgLCBpZmVsc2UocHZhbHVlIDw9IDAuMDUsICJSZWplY3QiLCJEbyBub3QgcmVqZWN0IikgKQpgYGAKCgo1LiBEYWlseSBmb3JlaWduIGV4Y2hhbmdlIHJhdGVzIChzcG90IHJhdGVzKSBjYW4gYmUgb2J0YWluZWQgZnJvbSB0aGUgRmVkZXJhbCBSZXNlcnZlIEJhbmsgaW4gU3QgTG91aXMgKEZSRUQpLiBUaGUgZGF0YSBhcmUgdGhlIG5vb24gYnV5aW5nIHJhdGVzIGluIE5ldyBZb3JrIENpdHkgY2VydGlmaWVkIGJ5IHRoZSBGZWRlcmFsIFJlc2VydmUgQmFuayBvZiBOZXcgWW9yay4gQ29uc2lkZXIgdGhlIGV4Y2hhbmdlIHJhdGVzIGJldHdlZW4gdGhlIFUuUy4gZG9sbGFyIGFuZCB0aGUgRXVybyBmcm9tIEphbnVhcnkgNCwgMTk5OSB0byBNYXJjaCA4LCAyMDEzLiBTZWUgdGhlIGZpbGUgZC1leHVzZXUudHh0LgoKKGEpIENvbXB1dGUgdGhlIGRhaWx5IGxvZyByZXR1cm4gb2YgdGhlIGV4Y2hhbmdlIHJhdGUuCgpgYGB7cn0KZGZfNSA9IGRhdGEudGFibGU6OmZyZWFkKCcvVXNlcnMvYWlzbGluZy9Eb2N1bWVudHMvZGF5ZGF5dXAvbnVzX21xZi9GaW5hbmNpYWwgVGltZSBTZXJpZXMvaG9tZXdvcmsvSG9tZXdvcmsvSFcgMS9kLWV4dXNldS50eHQnKQpoZWFkKGRmXzUpCmxvZ1I1ID0gZGlmZihsb2coZGZfNSRWQUxVRSkpCmhlYWQobG9nUjUpCmBgYAoKKGIpIENvbXB1dGUgdGhlIHNhbXBsZSBtZWFuLCBzdGFuZGFyZCBkZXZpYXRpb24sIHNrZXduZXNzLCBleGNlc3Mga3VydG9zaXMsIG1pbmltdW0sIGFuZCBtYXhpbXVtIG9mIHRoZSBsb2cgcmV0dXJucyBvZiB0aGUgZXhjaGFuZ2UgcmF0ZS4KCmBgYHtyfQpiYXNpY1N0YXRzKGxvZ1I1KQpgYGAKCihjKSBPYnRhaW4gYSBkZW5zaXR5IHBsb3Qgb2YgdGhlIGRhaWx5IGxvbmcgcmV0dXJucyBvZiBEb2xsYXItRXVybyBleGNoYW5nZSByYXRlLgoKYGBge3J9CnBsb3QoZGVuc2l0eShsb2dSNSkpCgpgYGAKCihkKSBUZXN0IEgwOiDOvCA9IDAgdmVyc3VzIEhhIDogzrwgPcy4IDAsIHdoZXJlIM68IGRlbm90ZXMgdGhlIG1lYW4gb2YgdGhlIGRhaWx5IGxvZyByZXR1cm4gb2YgRG9sbGFyLSBFdXJvIGV4Y2hhbmdlIHJhdGUuCmBgYHtyfQoKcHZhbHVlID0gdC50ZXN0KGxvZ1I1KSRwLnZhbHVlCnNwcmludGYoIlRoZSBwLXZhbHVlIGlzICVzLCBoZW5jZSB3ZSAlcyB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIG1lYW4gb2YgRG9sbGFyIEV1cm8gRXhjaGFuZ2UgUmV0dXJuIGlzIDAiLCBwdmFsdWUgLCBpZmVsc2UocHZhbHVlIDw9IDAuMDUsICJSZWplY3QiLCJEbyBub3QgcmVqZWN0IikpCgoKYGBgCgoKNi4gQ29uc2lkZXIgU1A1MDAgYW5kIElCTSBkYXRhIChpbiBmaWxlIOKAmFNQLmNzduKAmSBhbmQg4oCYSUJNLmNzduKAmSByZXNwZWN0aXZlbHkpOgoKYGBge3J9CmRmX3NwPSAgZGF0YS50YWJsZTo6ZnJlYWQoJy9Vc2Vycy9haXNsaW5nL0RvY3VtZW50cy9kYXlkYXl1cC9udXNfbXFmL0ZpbmFuY2lhbCBUaW1lIFNlcmllcy9ob21ld29yay9Ib21ld29yay9IVyAxL1NQLkNTVicsaW5kZXggPSAnVjEnKQpkZl9pYm0gPSBkYXRhLnRhYmxlOjpmcmVhZCgnL1VzZXJzL2Fpc2xpbmcvRG9jdW1lbnRzL2RheWRheXVwL251c19tcWYvRmluYW5jaWFsIFRpbWUgU2VyaWVzL2hvbWV3b3JrL0hvbWV3b3JrL0hXIDEvSUJNLkNTVicsaW5kZXggPSAnVjEnKQoKaGVhZChkZl9zcCkKaGVhZChkZl9pYm0pCgpgYGAKCihhKSBGaW5kIHRoZSBsb2cgcmV0dXJuIG9mIFNQIGFuZCBJQk0gYnkgdXNpbmcg4oCYQWRqdXN0ZWQgUHJpY2XigJkKYGBge3J9CmxvZ1Jfc3AgPSBkaWZmKGxvZyhkZl9zcFtbIlNQLkFkanVzdGVkIl1dKSkKbG9nUl9pYm0gPSBkaWZmKGxvZyhkZl9pYm1bWyJJQk0uQWRqdXN0ZWQiXV0pKQoKaGVhZChsb2dSX3NwKQpoZWFkKGxvZ1JfaWJtKQoKYGBgCgoKKGIpIE1lcmdlIHRoZSBhYm92ZSB0d28gcmV0dXJuIHNlcmllcyBpbnRvIGEgbmV3IGRhdGFzZXQgKGhpbnQ6IHVzaW5nIOKAmGRhdGEuZnJhbWXigJkpIGFuZCBwbG90IHRoZW0gKHkgaXMgSUJNLCB4IGlzIFNQKQoKYGBge3J9CmRmX25ldyA9IGRhdGEuZnJhbWUoeSA9IGxvZ1JfaWJtICwgeCA9IGxvZ1Jfc3ApCnFwbG90KGRmX25ldyR5LCBkZl9uZXckeSkKYGBgCgooYykgRmluZCB0aGUgYmVzdCBsaW5lYXIgbW9kZWwgYnkgdXNpbmcgQUlDIGFzIGNyaXRlcmlvbiAobmVlZCB0byBzaG93IGFsbCB5b3VyIG1vZGVscykKCmBgYHtyfQptMSA8LSBsbSh5IH4geCwgZGZfbmV3KQpzdW1tYXJ5KG0xKQpzcHJpbnRmKCdmaXQgdGhlIG1vZGVsIHkgfiB4ICxBSUMgPSAlcyAnLEFJQyhtMSkpCmNvbmZpbnQobTEpCmBgYApgYGB7cn0KIyBnZW5lcmF0ZSBzb21lIG90aGVyIHZhcmlhYmxlcyA6IAppZHggPSB3aGljaChkZl9uZXckeCA8PSAwKQpuc3AgPC0gcmVwKDAsbGVuZ3RoKGRmX25ldyR4KSkKbnNwW2lkeF0gPSBkZl9uZXckeFtpZHhdCmMxIDwtIHJlcCgwLGxlbmd0aChkZl9uZXckeCkpCmMxW2lkeF0gPSAxCiAKZGZfbmV3MiA8LSBkYXRhLmZyYW1lKHkgPSBkZl9uZXckeSwgeCA9IGRmX25ldyR4LCBjMSwgbnNwKSAgIApgYGAKCmBgYHtyfQptMiA8LSBsbSh5IH4geCArIGMxICwgZGZfbmV3MikgCnN1bW1hcnkobTIpCgptMyA8LSBsbSh5IH4geCArIG5zcCwgZGZfbmV3MikgCnN1bW1hcnkobTMpCgptNCA8LSBsbSh5IH4geCArIGMxICsgbnNwLCBkZl9uZXcyKQpzdW1tYXJ5KG00KQoKbGlicmFyeShNQVNTKQptNSA8LSBzdGVwQUlDKG00KSAKc3VtbWFyeShtNSkKCnNwcmludGYoJ2ZpdCB0aGUgbW9kZWwgeSB+IHggKyBjMSAsQUlDID0gJXMgJyxBSUMobTIpKQpzcHJpbnRmKCdmaXQgdGhlIG1vZGVsIHkgfiB4ICsgbnNwICxBSUMgPSAlcyAnLEFJQyhtMykpCnNwcmludGYoJ2ZpdCB0aGUgbW9kZWwgeSB+IHggKyBjMSArIG5zcCAsQUlDID0gJXMgJyxBSUMobTQpKQpzcHJpbnRmKCdmaXQgdGhlIG1vZGVsIHkgfiB4ICsgYzEgKyBuc3AgLHJlbW92ZSBub25zaWduaWZpY2FudCB2YXJpYWJsZXMgb25lIGF0IGEgdGltZSB3aGlsZSBtaW5pbWlzaW5nIEFJQywgQUlDID0gJXMgJyxBSUMobTUpKQoKYGBgCgoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLiAKClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4KCg==