Section 1 - Understanding the Data

1.1

Before applying analytics tools on the training set, we first need to understand the data at hand. Load “FluTrain.csv” into a data frame called FluTrain. Looking at the time period 2004-2011, which week corresponds to the highest percentage of ILI-related physician visits? Select the day of the month corresponding to the start of this week.

FluTrain = read.csv("data/FluTrain.csv")
names(FluTrain)
[1] "Week"    "ILI"     "Queries"
FluTrain$Week[which.max(FluTrain$ILI)]
[1] 2009-10-18 - 2009-10-24
417 Levels: 2004-01-04 - 2004-01-10 ... 2011-12-25 - 2011-12-31

Which week corresponds to the highest percentage of ILI-related query fraction?

FluTrain$Week[which.max(FluTrain$Queries)]
[1] 2009-10-18 - 2009-10-24
417 Levels: 2004-01-04 - 2004-01-10 ... 2011-12-25 - 2011-12-31

1.2

Let us now understand the data at an aggregate level. Plot the histogram of the dependent variable, ILI. What best describes the distribution of values of ILI?

hist(FluTrain$ILI)

#Most of the ILI values are small, with a relatively small number of much larger values (in statistics, this sort of data is called "skew right").

1.3

Plot the natural logarithm of ILI versus Queries. What does the plot suggest?.

plot(FluTrain$Queries , log(FluTrain$ILI))

Section 2 - Linear Regression Model

2.1

Based on the plot we just made, it seems that a linear regression model could be a good modeling choice. Based on our understanding of the data from the previous subproblem, which model best describes our estimation problem?

#log(ILI) = intercept + coefficient x Queries, where the coefficient is positive

2.2

Let’s call the regression model from the previous problem (Problem 2.1) FluTrend1 and run it in R. Hint: to take the logarithm of a variable Var in a regression equation, you simply use log(Var) when specifying the formula to the lm() function.

What is the training set R-squared value for FluTrend1 model (the “Multiple R-squared”)?

FluTrend1 = lm(log(ILI)~Queries, data=FluTrain)
summary(FluTrend1)

Call:
lm(formula = log(ILI) ~ Queries, data = FluTrain)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.76003 -0.19696 -0.01657  0.18685  1.06450 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.49934    0.03041  -16.42   <2e-16 ***
Queries      2.96129    0.09312   31.80   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2995 on 415 degrees of freedom
Multiple R-squared:  0.709, Adjusted R-squared:  0.7083 
F-statistic:  1011 on 1 and 415 DF,  p-value: < 2.2e-16
#0.709

2.3

For a single variable linear regression model, there is a direct relationship between the R-squared and the correlation between the independent and the dependent variables. What is the relationship we infer from our problem? (Don’t forget that you can use the cor function to compute the correlation between two variables.)

#R-squared = Correlation^2

Section 3 - Performance on the Test Set

3.1

What is our estimate for the percentage of ILI-related physician visits for the week of March 11, 2012? (HINT: You can either just output FluTest$Week to find which element corresponds to March 11, 2012, or you can use the “which” function in R. To learn more about the which function, type ?which in your R console.)

FluTest = read.csv("data/FluTest.csv")
PredTest1 = predict(FluTrend1, newdata=FluTest)
PredTest1 = exp(predict(FluTrend1, newdata=FluTest))
which(FluTest$Week == "2012-03-11 - 2012-03-17")
[1] 11
PredTest1[11]
      11 
2.187378 

3.2

What is the relative error betweeen the estimate (our prediction) and the observed value for the week of March 11, 2012? Note that the relative error is calculated as

(Observed ILI - Estimated ILI)/Observed ILI

(FluTest$ILI[11]-PredTest1[11])/FluTest$ILI[11]
        11 
0.04623827 

3.3

What is the Root Mean Square Error (RMSE) between our estimates and the actual observations for the percentage of ILI-related physician visits, on the test set?

RMSE
[1] 0.7490645

Section 4 - Training a Time Series Model

4.1

How many values are missing in the new ILILag2 variable?

install.packages("zoo")
Error in install.packages : Updating loaded packages
library(zoo)
ILILag2 = lag(zoo(FluTrain$ILI), -2, na.pad=TRUE)
FluTrain$ILILag2 = coredata(ILILag2)
sum(is.na(ILILag2))
[1] 2

4.2

Use the plot() function to plot the log of ILILag2 against the log of ILI. Which best describes the relationship between these two variables?

plot(log(FluTrain$ILI),log(ILILag2))

#There is a strong positive relationship between log(ILILag2) and log(ILI).

4.3

Train a linear regression model on the FluTrain dataset to predict the log of the ILI variable using the Queries variable as well as the log of the ILILag2 variable. Call this model FluTrend2.

Which coefficients are significant at the p=0.05 level in this regression model? (Select all that apply.)

FluTrend2 = lm(log(ILI) ~ Queries + log(ILILag2),FluTrain)
summary(FluTrend2)

Call:
lm(formula = log(ILI) ~ Queries + log(ILILag2), data = FluTrain)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.52209 -0.11082 -0.01819  0.08143  0.76785 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -0.24064    0.01953  -12.32   <2e-16 ***
Queries       1.25578    0.07910   15.88   <2e-16 ***
log(ILILag2)  0.65569    0.02251   29.14   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.1703 on 412 degrees of freedom
  (2 observations deleted due to missingness)
Multiple R-squared:  0.9063,    Adjusted R-squared:  0.9059 
F-statistic:  1993 on 2 and 412 DF,  p-value: < 2.2e-16
#0.9063

4.4

On the basis of R-squared value and significance of coefficients, which statement is the most accurate?

summary(FluTrend1)

Call:
lm(formula = log(ILI) ~ Queries, data = FluTrain)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.76003 -0.19696 -0.01657  0.18685  1.06450 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.49934    0.03041  -16.42   <2e-16 ***
Queries      2.96129    0.09312   31.80   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2995 on 415 degrees of freedom
Multiple R-squared:  0.709, Adjusted R-squared:  0.7083 
F-statistic:  1011 on 1 and 415 DF,  p-value: < 2.2e-16
#FluTrend2 is a stronger model than FluTrend1 on the training set.

Section 5 - Evaluating the Time Series Model in the Test Set

5.1

Modify the code from the previous subproblem to add an ILILag2 variable to the FluTest data frame. How many missing values are there in this new variable?

ILILag2 = lag(zoo(FluTest$ILI), -2, na.pad=TRUE)
FluTest$ILILag2 = coredata(ILILag2)
sum(is.na(FluTest$ILILag2))
[1] 2

5.2

In this problem, the training and testing sets are split sequentially – the training set contains all observations from 2004-2011 and the testing set contains all observations from 2012. There is no time gap between the two datasets, meaning the first observation in FluTest was recorded one week after the last observation in FluTrain. From this, we can identify how to fill in the missing values for the ILILag2 variable in FluTest.

# The ILI value of the last observation in the FluTrain data frame.

5.3

Fill in the missing values for ILILag2 in FluTest. In terms of syntax, you could set the value of ILILag2 in row “x” of the FluTest data frame to the value of ILI in row “y” of the FluTrain data frame with “FluTest\(ILILag2[x] = FluTrain\)ILI[y]”. Use the answer to the previous questions to determine the appropriate values of “x” and “y”. It may be helpful to check the total number of rows in FluTrain using str(FluTrain) or nrow(FluTrain).

What is the new value of the ILILag2 variable in the first row of FluTest?

FluTest$ILILag2[1] = FluTrain$ILI[416]
#1.852736

What is the new value of the ILILag2 variable in the second row of FluTest?

FluTrain$ILI[417]
[1] 2.12413

5.4

Obtain test set predictions of the ILI variable from the FluTrend2 model, again remembering to call the exp() function on the result of the predict() function to obtain predictions for ILI instead of log(ILI).

What is the test-set RMSE of the FluTrend2 model?

RMSE
[1] 0.2942029

5.5

Which model obtained the best test-set RMSE?

FluTrend2
LS0tDQp0aXRsZTogIkFTMi0zIERldGVjdGluZyBGbHUgRXBpZGVtaWNzIHZpYSBTZWFyY2ggRW5naW5lIFF1ZXJ5IERhdGEiDQphdXRob3I6ICI8546L5qyjPiA8TTA2NDExMTAzOT4iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgU2VjdGlvbiAxIC0gVW5kZXJzdGFuZGluZyB0aGUgRGF0YQ0KDQojIyMjIDEuMQ0KQmVmb3JlIGFwcGx5aW5nIGFuYWx5dGljcyB0b29scyBvbiB0aGUgdHJhaW5pbmcgc2V0LCB3ZSBmaXJzdCBuZWVkIHRvIHVuZGVyc3RhbmQgdGhlIGRhdGEgYXQgaGFuZC4gTG9hZCAiRmx1VHJhaW4uY3N2IiBpbnRvIGEgZGF0YSBmcmFtZSBjYWxsZWQgRmx1VHJhaW4uIExvb2tpbmcgYXQgdGhlIHRpbWUgcGVyaW9kIDIwMDQtMjAxMSwgd2hpY2ggd2VlayBjb3JyZXNwb25kcyB0byB0aGUgaGlnaGVzdCBwZXJjZW50YWdlIG9mIElMSS1yZWxhdGVkIHBoeXNpY2lhbiB2aXNpdHM/IFNlbGVjdCB0aGUgZGF5IG9mIHRoZSBtb250aCBjb3JyZXNwb25kaW5nIHRvIHRoZSBzdGFydCBvZiB0aGlzIHdlZWsuDQpgYGB7cn0NCkZsdVRyYWluID0gcmVhZC5jc3YoImRhdGEvRmx1VHJhaW4uY3N2IikNCm5hbWVzKEZsdVRyYWluKQ0KRmx1VHJhaW4kV2Vla1t3aGljaC5tYXgoRmx1VHJhaW4kSUxJKV0NCmBgYA0KDQpXaGljaCB3ZWVrIGNvcnJlc3BvbmRzIHRvIHRoZSBoaWdoZXN0IHBlcmNlbnRhZ2Ugb2YgSUxJLXJlbGF0ZWQgcXVlcnkgZnJhY3Rpb24/DQpgYGB7cn0NCkZsdVRyYWluJFdlZWtbd2hpY2gubWF4KEZsdVRyYWluJFF1ZXJpZXMpXQ0KYGBgDQoNCiMjIyMgMS4yDQpMZXQgdXMgbm93IHVuZGVyc3RhbmQgdGhlIGRhdGEgYXQgYW4gYWdncmVnYXRlIGxldmVsLiBQbG90IHRoZSBoaXN0b2dyYW0gb2YgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgSUxJLiBXaGF0IGJlc3QgZGVzY3JpYmVzIHRoZSBkaXN0cmlidXRpb24gb2YgdmFsdWVzIG9mIElMST8NCmBgYHtyfQ0KaGlzdChGbHVUcmFpbiRJTEkpDQojTW9zdCBvZiB0aGUgSUxJIHZhbHVlcyBhcmUgc21hbGwsIHdpdGggYSByZWxhdGl2ZWx5IHNtYWxsIG51bWJlciBvZiBtdWNoIGxhcmdlciB2YWx1ZXMgKGluIHN0YXRpc3RpY3MsIHRoaXMgc29ydCBvZiBkYXRhIGlzIGNhbGxlZCAic2tldyByaWdodCIpLg0KYGBgDQojIyMjIDEuMw0KUGxvdCB0aGUgbmF0dXJhbCBsb2dhcml0aG0gb2YgSUxJIHZlcnN1cyBRdWVyaWVzLiBXaGF0IGRvZXMgdGhlIHBsb3Qgc3VnZ2VzdD8uDQpgYGB7cn0NCnBsb3QoRmx1VHJhaW4kUXVlcmllcyAsIGxvZyhGbHVUcmFpbiRJTEkpKQ0KYGBgDQoNCiMjIyBTZWN0aW9uIDIgLSBMaW5lYXIgUmVncmVzc2lvbiBNb2RlbA0KDQojIyMjIDIuMQ0KQmFzZWQgb24gdGhlIHBsb3Qgd2UganVzdCBtYWRlLCBpdCBzZWVtcyB0aGF0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgY291bGQgYmUgYSBnb29kIG1vZGVsaW5nIGNob2ljZS4gQmFzZWQgb24gb3VyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGRhdGEgZnJvbSB0aGUgcHJldmlvdXMgc3VicHJvYmxlbSwgd2hpY2ggbW9kZWwgYmVzdCBkZXNjcmliZXMgb3VyIGVzdGltYXRpb24gcHJvYmxlbT8NCmBgYHtyfQ0KI2xvZyhJTEkpID0gaW50ZXJjZXB0ICsgY29lZmZpY2llbnQgeCBRdWVyaWVzLCB3aGVyZSB0aGUgY29lZmZpY2llbnQgaXMgcG9zaXRpdmUNCmBgYA0KDQojIyMjIDIuMg0KTGV0J3MgY2FsbCB0aGUgcmVncmVzc2lvbiBtb2RlbCBmcm9tIHRoZSBwcmV2aW91cyBwcm9ibGVtIChQcm9ibGVtIDIuMSkgRmx1VHJlbmQxIGFuZCBydW4gaXQgaW4gUi4gSGludDogdG8gdGFrZSB0aGUgbG9nYXJpdGhtIG9mIGEgdmFyaWFibGUgVmFyIGluIGEgcmVncmVzc2lvbiBlcXVhdGlvbiwgeW91IHNpbXBseSB1c2UgbG9nKFZhcikgd2hlbiBzcGVjaWZ5aW5nIHRoZSBmb3JtdWxhIHRvIHRoZSBsbSgpIGZ1bmN0aW9uLg0KDQpXaGF0IGlzIHRoZSB0cmFpbmluZyBzZXQgUi1zcXVhcmVkIHZhbHVlIGZvciBGbHVUcmVuZDEgbW9kZWwgKHRoZSAiTXVsdGlwbGUgUi1zcXVhcmVkIik/DQpgYGB7cn0NCkZsdVRyZW5kMSA9IGxtKGxvZyhJTEkpflF1ZXJpZXMsIGRhdGE9Rmx1VHJhaW4pDQpzdW1tYXJ5KEZsdVRyZW5kMSkNCiMwLjcwOQ0KYGBgDQoNCiMjIyMgMi4zDQpGb3IgYSBzaW5nbGUgdmFyaWFibGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIHRoZXJlIGlzIGEgZGlyZWN0IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBSLXNxdWFyZWQgYW5kIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBpbmRlcGVuZGVudCBhbmQgdGhlIGRlcGVuZGVudCB2YXJpYWJsZXMuIFdoYXQgaXMgdGhlIHJlbGF0aW9uc2hpcCB3ZSBpbmZlciBmcm9tIG91ciBwcm9ibGVtPyAoRG9uJ3QgZm9yZ2V0IHRoYXQgeW91IGNhbiB1c2UgdGhlIGNvciBmdW5jdGlvbiB0byBjb21wdXRlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHR3byB2YXJpYWJsZXMuKQ0KYGBge3J9DQojUi1zcXVhcmVkID0gQ29ycmVsYXRpb25eMg0KYGBgDQoNCiMjIyBTZWN0aW9uIDMgLSBQZXJmb3JtYW5jZSBvbiB0aGUgVGVzdCBTZXQNCg0KIyMjIyAzLjENCldoYXQgaXMgb3VyIGVzdGltYXRlIGZvciB0aGUgcGVyY2VudGFnZSBvZiBJTEktcmVsYXRlZCBwaHlzaWNpYW4gdmlzaXRzIGZvciB0aGUgd2VlayBvZiBNYXJjaCAxMSwgMjAxMj8gKEhJTlQ6IFlvdSBjYW4gZWl0aGVyIGp1c3Qgb3V0cHV0IEZsdVRlc3QkV2VlayB0byBmaW5kIHdoaWNoIGVsZW1lbnQgY29ycmVzcG9uZHMgdG8gTWFyY2ggMTEsIDIwMTIsIG9yIHlvdSBjYW4gdXNlIHRoZSAid2hpY2giIGZ1bmN0aW9uIGluIFIuIFRvIGxlYXJuIG1vcmUgYWJvdXQgdGhlIHdoaWNoIGZ1bmN0aW9uLCB0eXBlID93aGljaCBpbiB5b3VyIFIgY29uc29sZS4pDQoNCmBgYHtyfQ0KRmx1VGVzdCA9IHJlYWQuY3N2KCJkYXRhL0ZsdVRlc3QuY3N2IikNClByZWRUZXN0MSA9IHByZWRpY3QoRmx1VHJlbmQxLCBuZXdkYXRhPUZsdVRlc3QpDQpQcmVkVGVzdDEgPSBleHAocHJlZGljdChGbHVUcmVuZDEsIG5ld2RhdGE9Rmx1VGVzdCkpDQp3aGljaChGbHVUZXN0JFdlZWsgPT0gIjIwMTItMDMtMTEgLSAyMDEyLTAzLTE3IikNClByZWRUZXN0MVsxMV0NCmBgYA0KDQojIyMjIDMuMg0KV2hhdCBpcyB0aGUgcmVsYXRpdmUgZXJyb3IgYmV0d2VlZW4gdGhlIGVzdGltYXRlIChvdXIgcHJlZGljdGlvbikgYW5kIHRoZSBvYnNlcnZlZCB2YWx1ZSBmb3IgdGhlIHdlZWsgb2YgTWFyY2ggMTEsIDIwMTI/IE5vdGUgdGhhdCB0aGUgcmVsYXRpdmUgZXJyb3IgaXMgY2FsY3VsYXRlZCBhcw0KDQooT2JzZXJ2ZWQgSUxJIC0gRXN0aW1hdGVkIElMSSkvT2JzZXJ2ZWQgSUxJDQoNCmBgYHtyfQ0KKEZsdVRlc3QkSUxJWzExXS1QcmVkVGVzdDFbMTFdKS9GbHVUZXN0JElMSVsxMV0NCmBgYA0KIyMjIyAzLjMNCldoYXQgaXMgdGhlIFJvb3QgTWVhbiBTcXVhcmUgRXJyb3IgKFJNU0UpIGJldHdlZW4gb3VyIGVzdGltYXRlcyBhbmQgdGhlIGFjdHVhbCBvYnNlcnZhdGlvbnMgZm9yIHRoZSBwZXJjZW50YWdlIG9mIElMSS1yZWxhdGVkIHBoeXNpY2lhbiB2aXNpdHMsIG9uIHRoZSB0ZXN0IHNldD8NCmBgYHtyfQ0KU1NFID0gc3VtKChGbHVUZXN0JElMSS1QcmVkVGVzdDEpXjIpDQpSTVNFID0gc3FydChTU0UvbnJvdyhGbHVUZXN0KSkNCmBgYA0KDQojIyMgU2VjdGlvbiA0IC0gVHJhaW5pbmcgYSBUaW1lIFNlcmllcyBNb2RlbA0KDQojIyMjIDQuMQ0KSG93IG1hbnkgdmFsdWVzIGFyZSBtaXNzaW5nIGluIHRoZSBuZXcgSUxJTGFnMiB2YXJpYWJsZT8NCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJ6b28iKQ0KbGlicmFyeSh6b28pDQpJTElMYWcyID0gbGFnKHpvbyhGbHVUcmFpbiRJTEkpLCAtMiwgbmEucGFkPVRSVUUpDQpGbHVUcmFpbiRJTElMYWcyID0gY29yZWRhdGEoSUxJTGFnMikNCnN1bShpcy5uYShJTElMYWcyKSkNCmBgYA0KIyMjIyA0LjINClVzZSB0aGUgcGxvdCgpIGZ1bmN0aW9uIHRvIHBsb3QgdGhlIGxvZyBvZiBJTElMYWcyIGFnYWluc3QgdGhlIGxvZyBvZiBJTEkuIFdoaWNoIGJlc3QgZGVzY3JpYmVzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGVzZSB0d28gdmFyaWFibGVzPw0KDQpgYGB7cn0NCnBsb3QobG9nKEZsdVRyYWluJElMSSksbG9nKElMSUxhZzIpKQ0KI1RoZXJlIGlzIGEgc3Ryb25nIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxvZyhJTElMYWcyKSBhbmQgbG9nKElMSSkuDQpgYGANCg0KIyMjIyA0LjMNClRyYWluIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgb24gdGhlIEZsdVRyYWluIGRhdGFzZXQgdG8gcHJlZGljdCB0aGUgbG9nIG9mIHRoZSBJTEkgdmFyaWFibGUgdXNpbmcgdGhlIFF1ZXJpZXMgdmFyaWFibGUgYXMgd2VsbCBhcyB0aGUgbG9nIG9mIHRoZSBJTElMYWcyIHZhcmlhYmxlLiBDYWxsIHRoaXMgbW9kZWwgRmx1VHJlbmQyLg0KDQpXaGljaCBjb2VmZmljaWVudHMgYXJlIHNpZ25pZmljYW50IGF0IHRoZSBwPTAuMDUgbGV2ZWwgaW4gdGhpcyByZWdyZXNzaW9uIG1vZGVsPyAoU2VsZWN0IGFsbCB0aGF0IGFwcGx5LikNCg0KYGBge3J9DQpGbHVUcmVuZDIgPSBsbShsb2coSUxJKSB+IFF1ZXJpZXMgKyBsb2coSUxJTGFnMiksRmx1VHJhaW4pDQpzdW1tYXJ5KEZsdVRyZW5kMikNCiMwLjkwNjMNCmBgYA0KDQojIyMjIDQuNA0KT24gdGhlIGJhc2lzIG9mIFItc3F1YXJlZCB2YWx1ZSBhbmQgc2lnbmlmaWNhbmNlIG9mIGNvZWZmaWNpZW50cywgd2hpY2ggc3RhdGVtZW50IGlzIHRoZSBtb3N0IGFjY3VyYXRlPw0KYGBge3J9DQpzdW1tYXJ5KEZsdVRyZW5kMSkNCiNGbHVUcmVuZDIgaXMgYSBzdHJvbmdlciBtb2RlbCB0aGFuIEZsdVRyZW5kMSBvbiB0aGUgdHJhaW5pbmcgc2V0Lg0KYGBgDQoNCiMjIyBTZWN0aW9uIDUgLSBFdmFsdWF0aW5nIHRoZSBUaW1lIFNlcmllcyBNb2RlbCBpbiB0aGUgVGVzdCBTZXQNCg0KIyMjIyA1LjENCk1vZGlmeSB0aGUgY29kZSBmcm9tIHRoZSBwcmV2aW91cyBzdWJwcm9ibGVtIHRvIGFkZCBhbiBJTElMYWcyIHZhcmlhYmxlIHRvIHRoZSBGbHVUZXN0IGRhdGEgZnJhbWUuIEhvdyBtYW55IG1pc3NpbmcgdmFsdWVzIGFyZSB0aGVyZSBpbiB0aGlzIG5ldyB2YXJpYWJsZT8NCmBgYHtyfQ0KSUxJTGFnMiA9IGxhZyh6b28oRmx1VGVzdCRJTEkpLCAtMiwgbmEucGFkPVRSVUUpDQpGbHVUZXN0JElMSUxhZzIgPSBjb3JlZGF0YShJTElMYWcyKQ0Kc3VtKGlzLm5hKEZsdVRlc3QkSUxJTGFnMikpDQpgYGANCiMjIyMgNS4yDQpJbiB0aGlzIHByb2JsZW0sIHRoZSB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzIGFyZSBzcGxpdCBzZXF1ZW50aWFsbHkgLS0gdGhlIHRyYWluaW5nIHNldCBjb250YWlucyBhbGwgb2JzZXJ2YXRpb25zIGZyb20gMjAwNC0yMDExIGFuZCB0aGUgdGVzdGluZyBzZXQgY29udGFpbnMgYWxsIG9ic2VydmF0aW9ucyBmcm9tIDIwMTIuIFRoZXJlIGlzIG5vIHRpbWUgZ2FwIGJldHdlZW4gdGhlIHR3byBkYXRhc2V0cywgbWVhbmluZyB0aGUgZmlyc3Qgb2JzZXJ2YXRpb24gaW4gRmx1VGVzdCB3YXMgcmVjb3JkZWQgb25lIHdlZWsgYWZ0ZXIgdGhlIGxhc3Qgb2JzZXJ2YXRpb24gaW4gRmx1VHJhaW4uIEZyb20gdGhpcywgd2UgY2FuIGlkZW50aWZ5IGhvdyB0byBmaWxsIGluIHRoZSBtaXNzaW5nIHZhbHVlcyBmb3IgdGhlIElMSUxhZzIgdmFyaWFibGUgaW4gRmx1VGVzdC4NCmBgYHtyfQ0KIyBUaGUgSUxJIHZhbHVlIG9mIHRoZSBsYXN0IG9ic2VydmF0aW9uIGluIHRoZSBGbHVUcmFpbiBkYXRhIGZyYW1lLg0KYGBgDQoNCiMjIyMgNS4zDQpGaWxsIGluIHRoZSBtaXNzaW5nIHZhbHVlcyBmb3IgSUxJTGFnMiBpbiBGbHVUZXN0LiBJbiB0ZXJtcyBvZiBzeW50YXgsIHlvdSBjb3VsZCBzZXQgdGhlIHZhbHVlIG9mIElMSUxhZzIgaW4gcm93ICJ4IiBvZiB0aGUgRmx1VGVzdCBkYXRhIGZyYW1lIHRvIHRoZSB2YWx1ZSBvZiBJTEkgaW4gcm93ICJ5IiBvZiB0aGUgRmx1VHJhaW4gZGF0YSBmcmFtZSB3aXRoICJGbHVUZXN0JElMSUxhZzJbeF0gPSBGbHVUcmFpbiRJTElbeV0iLiBVc2UgdGhlIGFuc3dlciB0byB0aGUgcHJldmlvdXMgcXVlc3Rpb25zIHRvIGRldGVybWluZSB0aGUgYXBwcm9wcmlhdGUgdmFsdWVzIG9mICJ4IiBhbmQgInkiLiBJdCBtYXkgYmUgaGVscGZ1bCB0byBjaGVjayB0aGUgdG90YWwgbnVtYmVyIG9mIHJvd3MgaW4gRmx1VHJhaW4gdXNpbmcgc3RyKEZsdVRyYWluKSBvciBucm93KEZsdVRyYWluKS4NCg0KV2hhdCBpcyB0aGUgbmV3IHZhbHVlIG9mIHRoZSBJTElMYWcyIHZhcmlhYmxlIGluIHRoZSBmaXJzdCByb3cgb2YgRmx1VGVzdD8NCmBgYHtyfQ0KRmx1VGVzdCRJTElMYWcyWzFdID0gRmx1VHJhaW4kSUxJWzQxNl0NCiMxLjg1MjczNg0KYGBgDQoNCldoYXQgaXMgdGhlIG5ldyB2YWx1ZSBvZiB0aGUgSUxJTGFnMiB2YXJpYWJsZSBpbiB0aGUgc2Vjb25kIHJvdyBvZiBGbHVUZXN0Pw0KYGBge3J9DQpGbHVUZXN0JElMSUxhZzJbMl0gPSBGbHVUcmFpbiRJTElbNDE3XQ0KIzIuMTI0MTMNCmBgYA0KIyMjIyA1LjQNCk9idGFpbiB0ZXN0IHNldCBwcmVkaWN0aW9ucyBvZiB0aGUgSUxJIHZhcmlhYmxlIGZyb20gdGhlIEZsdVRyZW5kMiBtb2RlbCwgYWdhaW4gcmVtZW1iZXJpbmcgdG8gY2FsbCB0aGUgZXhwKCkgZnVuY3Rpb24gb24gdGhlIHJlc3VsdCBvZiB0aGUgcHJlZGljdCgpIGZ1bmN0aW9uIHRvIG9idGFpbiBwcmVkaWN0aW9ucyBmb3IgSUxJIGluc3RlYWQgb2YgbG9nKElMSSkuDQoNCldoYXQgaXMgdGhlIHRlc3Qtc2V0IFJNU0Ugb2YgdGhlIEZsdVRyZW5kMiBtb2RlbD8NCmBgYHtyfQ0KUHJlZGljdFRlc3QyID0gZXhwKHByZWRpY3QoRmx1VHJlbmQyLEZsdVRlc3QpKQ0KU1NFID0gc3VtKChGbHVUZXN0JElMSSAtIFByZWRpY3RUZXN0MileMikNCnN1bShpcy5uYShGbHVUZXN0JElMSSkpDQpzdW0oaXMubmEoUHJlZGljdFRlc3QyKSkNClJNU0UgPSBzcXJ0KFNTRS9ucm93KEZsdVRlc3QpKQ0KYGBgDQojIyMjIDUuNQ0KV2hpY2ggbW9kZWwgb2J0YWluZWQgdGhlIGJlc3QgdGVzdC1zZXQgUk1TRT8NCmBgYHtyfQ0KRmx1VHJlbmQyDQpgYGANCg0K