For predicting whether the agricultural epidemic of powdery mildew in mango will erupt in a certain year in the state of Uttar Pradesh in India, Misra et al. (2004) used annual outbreak 9 A. K. Misra, O. M. Prakash, and V. Ramasubramanian. Forewarning powdery mildew caused by Oidium mangiferae in mango (Mangifera indica) using logistic regression models. Indian Journal of Agricultural Science, 74(2):84-87, 2004 records during 1987-2000. The epidemic typically occurs in the third and fourth week of March, and hence outbreak status is known by the end of March of a given year. The authors used a logistic regression model with two weather predictors (maximum temperature and relative humidity) to forecast an outbreak. The data is shown in the table below and are available in PowderyMildewEpidemic.xls.

The historical data is shown below. The relative humidity and max temp for most years between 1987-2000 are given along with whether there was a mildew outbreak early in the corresponding year.

library(pander)
library(knitr)
library(forecast)
library(caret)
library(dplyr)
setwd("/Users/Chris Iyer/Documents/")
mildew <- read.csv("PowderyMildewEpidemic.csv")
mildew <- mildew %>% mutate(Outbreak1 = ifelse(Outbreak == "Yes", 1,0))
kable(mildew)
Year Outbreak MaxTemp RelHumidity Outbreak1
1987 Yes 30.14 82.86 1
1988 No 30.66 79.57 0
1989 No 26.31 89.14 0
1990 Yes 28.43 91.00 1
1991 No 29.57 80.57 0
1992 Yes 31.25 67.82 1
1993 No 30.35 61.76 0
1994 Yes 30.71 81.14 1
1995 No 30.71 61.57 0
1996 Yes 33.07 59.76 1
1997 No 31.50 68.29 0
2000 No 29.50 79.14 0

Is the mildew following a trend?

I plotted the data in a couple of different ways to visualize trends and the relationships between the variables and the mildew’s growth.

In the side by side plots below, I show each predictor variable seperately over time, highlightng the outbreak years with red points.

library(ggplot2)
tempPlot <- ggplot(data=mildew, aes(x=Year, y=MaxTemp)) +
  geom_line() +
    annotate("point", x = c(1987, 1990, 1992, 1994, 1996), y = c(30.14, 28.43, 31.25, 30.71,33.07),colour = "red", size = 2.5)
humidityPlot <- ggplot(data=mildew, aes(x=Year, y=RelHumidity)) +
  geom_line() +
    annotate("point", x = c(1987, 1990, 1992, 1994, 1996), y = c(82.86, 91.00, 67.82, 81.14,59.76),colour = "red", size = 2.5)
library(gridExtra)
grid.arrange(tempPlot, humidityPlot, ncol=2)

Since I can’t find any obvious explanation for mildew outbreaks, I tried to plot the two predictor variables on a single plot, standardizing them with their z-scores. They are plotted below; the 5 vertical lines represent years where there was a mildew outbreak.

mildewZ <- mildew %>% mutate(RelHumZ= scale(RelHumidity, center = TRUE, scale = TRUE), MaxTempZ = scale(MaxTemp, center = TRUE, scale = TRUE))
mildewZ
bothPlot <-ggplot(mildewZ, aes(Year)) + 
  geom_line(aes(y = RelHumZ, color = RelHumZ), size =     1, colour = "red") + 
  geom_line(aes(y = MaxTempZ, color = MaxTempZ), size =   1, colour = "red") +
  geom_vline(xintercept=c(1987, 1990, 1992, 1994, 1996),   size = 1.5) + 
  annotate("text", x = 1998, y = -0.9352666, label = "Relative \nHumidity") + 
  annotate("text", x = 1998, y = 0.83512904, label = "Temp") + 
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black")) + 
  scale_x_discrete(name ="Dose (mg)", 
                    limits=c(1987, 1990, 1992, 1994, 1996, 2000))
  bothPlot

  1. In order for the model to serve as a forewarning system for farmers, what requirements must be satisfied regarding data availability?

Answer: In order to generate a forecast using logistic regression, the measurement of the object of interest can either be numerical or binary, however since the forecast is binary, if the object of interest is numerical, the forecaster has to create a derived variable. In the case of predicting whether the powdery mildew will occur in Uttar Pradesh, India, we are given a dataset with the measurements of two predictor variables and a binary yes/no for the outbreak outcome. The outbreak variable has to be converted to a 0,1 for no/yes outcomes. The 0,1 is the derived variable.

Most importantly, the predictor variables must be available at the time of the prediction of the event.

  1. Write an equation for the model fitted by the researchers in the form of equation (8.1). Use predictor names instead of x notation.

\(log(odds(Mildew)_t=\beta_0 + \beta_{mildew_{t-1}} + \beta_{humidity_{t-1}} + \beta_{maxTemp_{t-1}}\)

  1. Create a scatter plot of the two predictors, using different hue for epidemic and non-epidemic markers. Does there appear to be a relationship between epidemic status and the two predictors?
plot(mildew$MaxTemp ~ mildew$RelHumidity, xlab = "Relative Humidity", ylab = "Max Temp (degrees Celsius)", col = mildew$Outbreak1 + 1, bty = "l", pch = 15)
legend(60, 29, c("No Outbreak", "Outbreak"), col = 1:2, pch = 15, bty = "l")

This is the same plot with the axes reversed.

plot(mildew$RelHumidity ~ mildew$MaxTemp, ylab = "Relative Humidity", xlab = "Max Temp (degrees Celsius)", col = mildew$Outbreak1 + 1, bty = "l", pch = 15)
legend(26.5,72, c("No Outbreak", "Outbreak"), col = 1:2, pch = 15, bty = "l")

  1. Compute naive forecasts of epidemic status for years 1995- 1997 using next-year forecasts (Ft+1 = Ft). What is the naive forecast for year 2000? Summarize the results for these four years in a classification matrix. Use a roll forward naive forecast.

Based on the naive model, the forecast for 2000, is for no mildew outbreak.

naiveForecasts <- mildew$Outbreak1[(length(mildew$Outbreak1)-1-3) : (length(mildew$Outbreak1)-1)]
Year <- c(1995, 1996, 1997, 2000)
MildewYear <- cbind(Year, naiveForecasts)
kable(MildewYear)
Year naiveForecasts
1995 1
1996 0
1997 1
2000 0

Confusion Matrix

Based on the matrix below, the accuracy of the naive method is 25%, less reliable than the flip of a coin. This is not the best forecasting model.

confusionMatrix(naiveForecasts, mildew$Outbreak1[(length(mildew$Outbreak1)-3): length(mildew$Outbreak1)], positive = c("1"))
Confusion Matrix and Statistics

          Reference
Prediction 0 1
         0 1 1
         1 2 0
                                          
               Accuracy : 0.25            
                 95% CI : (0.0063, 0.8059)
    No Information Rate : 0.75            
    P-Value [Acc > NIR] : 0.9961          
                                          
                  Kappa : -0.5            
 Mcnemar's Test P-Value : 1.0000          
                                          
            Sensitivity : 0.0000          
            Specificity : 0.3333          
         Pos Pred Value : 0.0000          
         Neg Pred Value : 0.5000          
             Prevalence : 0.2500          
         Detection Rate : 0.0000          
   Detection Prevalence : 0.5000          
      Balanced Accuracy : 0.1667          
                                          
       'Positive' Class : 1               
                                          
  1. Partition the data into training and validation periods, so that years 1987-1994 are the training period. Fit a logistic regression to the training period using the two predictors, and report the outbreak probability as well as a forecast for year 1995 (use a threshold of 0.5).

Training period

trainOutMildew <- mildew[1:8,]
kable(trainOutMildew)
Year Outbreak MaxTemp RelHumidity Outbreak1
1987 Yes 30.14 82.86 1
1988 No 30.66 79.57 0
1989 No 26.31 89.14 0
1990 Yes 28.43 91.00 1
1991 No 29.57 80.57 0
1992 Yes 31.25 67.82 1
1993 No 30.35 61.76 0
1994 Yes 30.71 81.14 1

Fit a Logistic Regression Model

outLogRegMildew <- glm(Outbreak1 ~ MaxTemp + RelHumidity, data = trainOutMildew, family = "binomial")
summary(outLogRegMildew)

Call:
glm(formula = Outbreak1 ~ MaxTemp + RelHumidity, family = "binomial", 
    data = trainOutMildew)

Deviance Residuals: 
      1        2        3        4        5  
 0.7466  -1.7276  -0.3132   1.0552  -1.1419  
      6        7        8  
 1.2419  -0.3908   0.6060  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)
(Intercept) -56.1543    44.4573  -1.263    0.207
MaxTemp       1.3849     1.1406   1.214    0.225
RelHumidity   0.1877     0.1578   1.189    0.234

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 11.0904  on 7  degrees of freedom
Residual deviance:  8.1198  on 5  degrees of freedom
AIC: 14.12

Number of Fisher Scoring iterations: 5

Forecast for 1995

predictionsMildew <- predict(outLogRegMildew, mildew[9:12,],type = "response")
logRegForecast <- cbind(Year, predictionsMildew)
kable(logRegForecast, row.names = FALSE)
Year predictionsMildew
1995 0.1119407
1996 0.7021411
1997 0.5705413
2000 0.3894790

Confusion Matrix for the Forecast

Cutoff value = 0.5

confusionMatrix(ifelse(predictionsMildew > 0.5, 1,0), mildew[9:12,]$Outbreak1, positive = c("1"))
Confusion Matrix and Statistics

          Reference
Prediction 0 1
         0 2 0
         1 1 1
                                          
               Accuracy : 0.75            
                 95% CI : (0.1941, 0.9937)
    No Information Rate : 0.75            
    P-Value [Acc > NIR] : 0.7383          
                                          
                  Kappa : 0.5             
 Mcnemar's Test P-Value : 1.0000          
                                          
            Sensitivity : 1.0000          
            Specificity : 0.6667          
         Pos Pred Value : 0.5000          
         Neg Pred Value : 1.0000          
             Prevalence : 0.2500          
         Detection Rate : 0.2500          
   Detection Prevalence : 0.5000          
      Balanced Accuracy : 0.8333          
                                          
       'Positive' Class : 1               
                                          

The probability of a mildew outbreak in 1995 is 11.2% using a cutoff of 0.5. The accuracty of the model is 75%, much better than that of the naive model. Forecasting the probability that the mildew will grow with a logistic regression model is preferible than forecasting with a naive model in this case given the data set.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpGb3IgcHJlZGljdGluZyB3aGV0aGVyIHRoZSBhZ3JpY3VsdHVyYWwgZXBpZGVtaWMgb2YgcG93ZGVyeSBtaWxkZXcgaW4gbWFuZ28gd2lsbCBlcnVwdCBpbiBhIGNlcnRhaW4geWVhciBpbiB0aGUgc3RhdGUgb2YgVXR0YXIgUHJhZGVzaCBpbiBJbmRpYSwgTWlzcmEgZXQgYWwuICgyMDA0KSB1c2VkIGFubnVhbCBvdXRicmVhayA5IEEuIEsuIE1pc3JhLCBPLiBNLiBQcmFrYXNoLCBhbmQgVi4gUmFtYXN1YnJhbWFuaWFuLiBGb3Jld2FybmluZyBwb3dkZXJ5IG1pbGRldyBjYXVzZWQgYnkgT2lkaXVtIG1hbmdpZmVyYWUgaW4gbWFuZ28gKE1hbmdpZmVyYSBpbmRpY2EpIHVzaW5nIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzLiBJbmRpYW4gSm91cm5hbCBvZiBBZ3JpY3VsdHVyYWwgU2NpZW5jZSwgNzQoMik6ODQtODcsIDIwMDQgcmVjb3JkcyBkdXJpbmcgMTk4Ny0yMDAwLiBUaGUgZXBpZGVtaWMgdHlwaWNhbGx5IG9jY3VycyBpbiB0aGUgdGhpcmQgYW5kIGZvdXJ0aCB3ZWVrIG9mIE1hcmNoLCBhbmQgaGVuY2Ugb3V0YnJlYWsgc3RhdHVzIGlzIGtub3duIGJ5IHRoZSBlbmQgb2YgTWFyY2ggb2YgYSBnaXZlbiB5ZWFyLiBUaGUgYXV0aG9ycyB1c2VkIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIHR3byB3ZWF0aGVyIHByZWRpY3RvcnMgKG1heGltdW0gdGVtcGVyYXR1cmUgYW5kIHJlbGF0aXZlIGh1bWlkaXR5KSB0byBmb3JlY2FzdCBhbiBvdXRicmVhay4gVGhlIGRhdGEgaXMgc2hvd24gaW4gdGhlIHRhYmxlIGJlbG93IGFuZCBhcmUgYXZhaWxhYmxlIGluIFBvd2RlcnlNaWxkZXdFcGlkZW1pYy54bHMuDQoNClRoZSBoaXN0b3JpY2FsIGRhdGEgaXMgc2hvd24gYmVsb3cuIFRoZSByZWxhdGl2ZSBodW1pZGl0eSBhbmQgbWF4IHRlbXAgZm9yIG1vc3QgeWVhcnMgYmV0d2VlbiAxOTg3LTIwMDAgYXJlIGdpdmVuIGFsb25nIHdpdGggd2hldGhlciB0aGVyZSB3YXMgYSBtaWxkZXcgb3V0YnJlYWsgZWFybHkgaW4gdGhlIGNvcnJlc3BvbmRpbmcgeWVhci4gDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShwYW5kZXIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGRwbHlyKQ0Kc2V0d2QoIi9Vc2Vycy9DaHJpcyBJeWVyL0RvY3VtZW50cy8iKQ0KbWlsZGV3IDwtIHJlYWQuY3N2KCJQb3dkZXJ5TWlsZGV3RXBpZGVtaWMuY3N2IikNCm1pbGRldyA8LSBtaWxkZXcgJT4lIG11dGF0ZShPdXRicmVhazEgPSBpZmVsc2UoT3V0YnJlYWsgPT0gIlllcyIsIDEsMCkpDQprYWJsZShtaWxkZXcpDQpgYGANCg0KDQoNCklzIHRoZSBtaWxkZXcgZm9sbG93aW5nIGEgdHJlbmQ/DQoNCkkgcGxvdHRlZCB0aGUgZGF0YSBpbiBhIGNvdXBsZSBvZiBkaWZmZXJlbnQgd2F5cyB0byB2aXN1YWxpemUgdHJlbmRzIGFuZCB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgYW5kIHRoZSBtaWxkZXcncyBncm93dGguIA0KDQpJbiB0aGUgc2lkZSBieSBzaWRlIHBsb3RzIGJlbG93LCBJIHNob3cgZWFjaCBwcmVkaWN0b3IgdmFyaWFibGUgc2VwZXJhdGVseSBvdmVyIHRpbWUsIGhpZ2hsaWdodG5nIHRoZSBvdXRicmVhayB5ZWFycyB3aXRoIHJlZCBwb2ludHMuIA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCnRlbXBQbG90IDwtIGdncGxvdChkYXRhPW1pbGRldywgYWVzKHg9WWVhciwgeT1NYXhUZW1wKSkgKw0KICBnZW9tX2xpbmUoKSArDQogICAgYW5ub3RhdGUoInBvaW50IiwgeCA9IGMoMTk4NywgMTk5MCwgMTk5MiwgMTk5NCwgMTk5NiksIHkgPSBjKDMwLjE0LCAyOC40MywgMzEuMjUsIDMwLjcxLDMzLjA3KSxjb2xvdXIgPSAicmVkIiwgc2l6ZSA9IDIuNSkNCmh1bWlkaXR5UGxvdCA8LSBnZ3Bsb3QoZGF0YT1taWxkZXcsIGFlcyh4PVllYXIsIHk9UmVsSHVtaWRpdHkpKSArDQogIGdlb21fbGluZSgpICsNCiAgICBhbm5vdGF0ZSgicG9pbnQiLCB4ID0gYygxOTg3LCAxOTkwLCAxOTkyLCAxOTk0LCAxOTk2KSwgeSA9IGMoODIuODYsIDkxLjAwLCA2Ny44MiwgODEuMTQsNTkuNzYpLGNvbG91ciA9ICJyZWQiLCBzaXplID0gMi41KQ0KbGlicmFyeShncmlkRXh0cmEpDQpncmlkLmFycmFuZ2UodGVtcFBsb3QsIGh1bWlkaXR5UGxvdCwgbmNvbD0yKQ0KYGBgDQpTaW5jZSBJIGNhbid0IGZpbmQgYW55IG9idmlvdXMgZXhwbGFuYXRpb24gZm9yIG1pbGRldyBvdXRicmVha3MsIEkgdHJpZWQgdG8gcGxvdCB0aGUgdHdvIHByZWRpY3RvciB2YXJpYWJsZXMgb24gYSBzaW5nbGUgcGxvdCwgc3RhbmRhcmRpemluZyB0aGVtIHdpdGggdGhlaXIgei1zY29yZXMuIFRoZXkgYXJlIHBsb3R0ZWQgYmVsb3c7IHRoZSA1IHZlcnRpY2FsIGxpbmVzIHJlcHJlc2VudCB5ZWFycyB3aGVyZSB0aGVyZSB3YXMgYSBtaWxkZXcgb3V0YnJlYWsuIA0KDQpgYGB7cn0NCm1pbGRld1ogPC0gbWlsZGV3ICU+JSBtdXRhdGUoUmVsSHVtWj0gc2NhbGUoUmVsSHVtaWRpdHksIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSksIE1heFRlbXBaID0gc2NhbGUoTWF4VGVtcCwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKSkNCm1pbGRld1oNCg0KYm90aFBsb3QgPC1nZ3Bsb3QobWlsZGV3WiwgYWVzKFllYXIpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBSZWxIdW1aLCBjb2xvciA9IFJlbEh1bVopLCBzaXplID0gICAgIDEsIGNvbG91ciA9ICJyZWQiKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBNYXhUZW1wWiwgY29sb3IgPSBNYXhUZW1wWiksIHNpemUgPSAgIDEsIGNvbG91ciA9ICJyZWQiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKDE5ODcsIDE5OTAsIDE5OTIsIDE5OTQsIDE5OTYpLCAgIHNpemUgPSAxLjUpICsgDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE5OTgsIHkgPSAtMC45MzUyNjY2LCBsYWJlbCA9ICJSZWxhdGl2ZSBcbkh1bWlkaXR5IikgKyANCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMTk5OCwgeSA9IDAuODM1MTI5MDQsIGxhYmVsID0gIlRlbXAiKSArIA0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpKSArIA0KICBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSJEb3NlIChtZykiLCANCiAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoMTk4NywgMTk5MCwgMTk5MiwgMTk5NCwgMTk5NiwgMjAwMCkpDQogIGJvdGhQbG90DQpgYGANCg0KDQoxLiBJbiBvcmRlciBmb3IgdGhlIG1vZGVsIHRvIHNlcnZlIGFzIGEgZm9yZXdhcm5pbmcgc3lzdGVtIGZvciBmYXJtZXJzLCB3aGF0IHJlcXVpcmVtZW50cyBtdXN0IGJlIHNhdGlzZmllZCByZWdhcmRpbmcgZGF0YSBhdmFpbGFiaWxpdHk/DQoNCkFuc3dlcjogSW4gb3JkZXIgdG8gZ2VuZXJhdGUgYSBmb3JlY2FzdCB1c2luZyBsb2dpc3RpYyByZWdyZXNzaW9uLCB0aGUgbWVhc3VyZW1lbnQgb2YgdGhlIG9iamVjdCBvZiBpbnRlcmVzdCBjYW4gZWl0aGVyIGJlIG51bWVyaWNhbCBvciBiaW5hcnksIGhvd2V2ZXIgc2luY2UgdGhlIGZvcmVjYXN0IGlzIGJpbmFyeSwgaWYgdGhlIG9iamVjdCBvZiBpbnRlcmVzdCBpcyBudW1lcmljYWwsIHRoZSBmb3JlY2FzdGVyIGhhcyB0byBjcmVhdGUgYSBkZXJpdmVkIHZhcmlhYmxlLiBJbiB0aGUgY2FzZSBvZiBwcmVkaWN0aW5nIHdoZXRoZXIgdGhlIHBvd2RlcnkgbWlsZGV3IHdpbGwgb2NjdXIgaW4gVXR0YXIgUHJhZGVzaCwgSW5kaWEsIHdlIGFyZSBnaXZlbiBhIGRhdGFzZXQgd2l0aCB0aGUgbWVhc3VyZW1lbnRzIG9mIHR3byBwcmVkaWN0b3IgdmFyaWFibGVzIGFuZCBhIGJpbmFyeSB5ZXMvbm8gZm9yIHRoZSBvdXRicmVhayBvdXRjb21lLiBUaGUgb3V0YnJlYWsgdmFyaWFibGUgaGFzIHRvIGJlIGNvbnZlcnRlZCB0byBhIDAsMSBmb3Igbm8veWVzIG91dGNvbWVzLiBUaGUgMCwxIGlzIHRoZSBkZXJpdmVkIHZhcmlhYmxlLg0KDQpNb3N0IGltcG9ydGFudGx5LCB0aGUgcHJlZGljdG9yIHZhcmlhYmxlcyBtdXN0IGJlIGF2YWlsYWJsZSBhdCB0aGUgdGltZSBvZiB0aGUgcHJlZGljdGlvbiBvZiB0aGUgZXZlbnQuIA0KDQoyLiBXcml0ZSBhbiBlcXVhdGlvbiBmb3IgdGhlIG1vZGVsIGZpdHRlZCBieSB0aGUgcmVzZWFyY2hlcnMgaW4gdGhlIGZvcm0gb2YgZXF1YXRpb24gKDguMSkuIFVzZSBwcmVkaWN0b3IgbmFtZXMgaW5zdGVhZCBvZiB4IG5vdGF0aW9uLiANCg0KJGxvZyhvZGRzKE1pbGRldylfdD1cYmV0YV8wICsgXGJldGFfe21pbGRld197dC0xfX0gKyBcYmV0YV97aHVtaWRpdHlfe3QtMX19ICsgIFxiZXRhX3ttYXhUZW1wX3t0LTF9fSQNCg0KMy4gQ3JlYXRlIGEgc2NhdHRlciBwbG90IG9mIHRoZSB0d28gcHJlZGljdG9ycywgdXNpbmcgZGlmZmVyZW50IGh1ZSBmb3IgZXBpZGVtaWMgYW5kIG5vbi1lcGlkZW1pYyBtYXJrZXJzLiBEb2VzIHRoZXJlIGFwcGVhciB0byBiZSBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVwaWRlbWljIHN0YXR1cyBhbmQgdGhlIHR3byBwcmVkaWN0b3JzPyANCg0KYGBge3J9DQpwbG90KG1pbGRldyRNYXhUZW1wIH4gbWlsZGV3JFJlbEh1bWlkaXR5LCB4bGFiID0gIlJlbGF0aXZlIEh1bWlkaXR5IiwgeWxhYiA9ICJNYXggVGVtcCAoZGVncmVlcyBDZWxzaXVzKSIsIGNvbCA9IG1pbGRldyRPdXRicmVhazEgKyAxLCBidHkgPSAibCIsIHBjaCA9IDE1KQ0KbGVnZW5kKDYwLCAyOSwgYygiTm8gT3V0YnJlYWsiLCAiT3V0YnJlYWsiKSwgY29sID0gMToyLCBwY2ggPSAxNSwgYnR5ID0gImwiKQ0KYGBgDQoNClRoaXMgaXMgdGhlIHNhbWUgcGxvdCB3aXRoIHRoZSBheGVzIHJldmVyc2VkLiANCg0KYGBge3J9DQpwbG90KG1pbGRldyRSZWxIdW1pZGl0eSB+IG1pbGRldyRNYXhUZW1wLCB5bGFiID0gIlJlbGF0aXZlIEh1bWlkaXR5IiwgeGxhYiA9ICJNYXggVGVtcCAoZGVncmVlcyBDZWxzaXVzKSIsIGNvbCA9IG1pbGRldyRPdXRicmVhazEgKyAxLCBidHkgPSAibCIsIHBjaCA9IDE1KQ0KbGVnZW5kKDI2LjUsNzIsIGMoIk5vIE91dGJyZWFrIiwgIk91dGJyZWFrIiksIGNvbCA9IDE6MiwgcGNoID0gMTUsIGJ0eSA9ICJsIikNCmBgYA0KDQo0LiBDb21wdXRlIG5haXZlIGZvcmVjYXN0cyBvZiBlcGlkZW1pYyBzdGF0dXMgZm9yIHllYXJzIDE5OTUtIDE5OTcgdXNpbmcgbmV4dC15ZWFyIGZvcmVjYXN0cyAoRnQrMSA9IEZ0KS4gV2hhdCBpcyB0aGUgbmFpdmUgZm9yZWNhc3QgZm9yIHllYXIgMjAwMD8gU3VtbWFyaXplIHRoZSByZXN1bHRzIGZvciB0aGVzZSBmb3VyIHllYXJzIGluIGEgY2xhc3NpZmljYXRpb24gbWF0cml4LiBVc2UgYSByb2xsIGZvcndhcmQgbmFpdmUgZm9yZWNhc3QuICANCg0KDQpCYXNlZCBvbiB0aGUgbmFpdmUgbW9kZWwsIHRoZSBmb3JlY2FzdCBmb3IgMjAwMCwgaXMgZm9yIG5vIG1pbGRldyBvdXRicmVhay4gDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpuYWl2ZUZvcmVjYXN0cyA8LSBtaWxkZXckT3V0YnJlYWsxWyhsZW5ndGgobWlsZGV3JE91dGJyZWFrMSktMS0zKSA6IChsZW5ndGgobWlsZGV3JE91dGJyZWFrMSktMSldDQpZZWFyIDwtIGMoMTk5NSwgMTk5NiwgMTk5NywgMjAwMCkNCk1pbGRld1llYXIgPC0gY2JpbmQoWWVhciwgbmFpdmVGb3JlY2FzdHMpDQprYWJsZShNaWxkZXdZZWFyKQ0KDQpgYGANCg0KQ29uZnVzaW9uIE1hdHJpeA0KDQpCYXNlZCBvbiB0aGUgbWF0cml4IGJlbG93LCB0aGUgYWNjdXJhY3kgb2YgdGhlIG5haXZlIG1ldGhvZCBpcyAyNSUsIGxlc3MgcmVsaWFibGUgdGhhbiB0aGUgZmxpcCBvZiBhIGNvaW4uIFRoaXMgaXMgbm90IHRoZSBiZXN0IGZvcmVjYXN0aW5nIG1vZGVsLiANCg0KYGBge3J9DQpjb25mdXNpb25NYXRyaXgobmFpdmVGb3JlY2FzdHMsIG1pbGRldyRPdXRicmVhazFbKGxlbmd0aChtaWxkZXckT3V0YnJlYWsxKS0zKTogbGVuZ3RoKG1pbGRldyRPdXRicmVhazEpXSwgcG9zaXRpdmUgPSBjKCIxIikpDQpgYGANCg0KNS4gUGFydGl0aW9uIHRoZSBkYXRhIGludG8gdHJhaW5pbmcgYW5kIHZhbGlkYXRpb24gcGVyaW9kcywgc28gdGhhdCB5ZWFycyAxOTg3LTE5OTQgYXJlIHRoZSB0cmFpbmluZyBwZXJpb2QuIEZpdCBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gdG8gdGhlIHRyYWluaW5nIHBlcmlvZCB1c2luZyB0aGUgdHdvIHByZWRpY3RvcnMsIGFuZCByZXBvcnQgdGhlIG91dGJyZWFrIHByb2JhYmlsaXR5IGFzIHdlbGwgYXMgYSBmb3JlY2FzdCBmb3IgeWVhciAxOTk1ICh1c2UgYSB0aHJlc2hvbGQgb2YgMC41KS4NCg0KIyMjVHJhaW5pbmcgcGVyaW9kDQoNCmBgYHtyfQ0KdHJhaW5PdXRNaWxkZXcgPC0gbWlsZGV3WzE6OCxdDQprYWJsZSh0cmFpbk91dE1pbGRldykNCmBgYA0KDQojIyNGaXQgYSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsDQoNCmBgYHtyfQ0Kb3V0TG9nUmVnTWlsZGV3IDwtIGdsbShPdXRicmVhazEgfiBNYXhUZW1wICsgUmVsSHVtaWRpdHksIGRhdGEgPSB0cmFpbk91dE1pbGRldywgZmFtaWx5ID0gImJpbm9taWFsIikNCnN1bW1hcnkob3V0TG9nUmVnTWlsZGV3KQ0KYGBgDQogDQojIyNGb3JlY2FzdCBmb3IgMTk5NQ0KDQpgYGB7cn0NCnByZWRpY3Rpb25zTWlsZGV3IDwtIHByZWRpY3Qob3V0TG9nUmVnTWlsZGV3LCBtaWxkZXdbOToxMixdLHR5cGUgPSAicmVzcG9uc2UiKQ0KbG9nUmVnRm9yZWNhc3QgPC0gY2JpbmQoWWVhciwgcHJlZGljdGlvbnNNaWxkZXcpDQprYWJsZShsb2dSZWdGb3JlY2FzdCwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyMjQ29uZnVzaW9uIE1hdHJpeCBmb3IgdGhlIEZvcmVjYXN0DQpDdXRvZmYgdmFsdWUgPSAwLjUNCg0KYGBge3J9DQpjb25mdXNpb25NYXRyaXgoaWZlbHNlKHByZWRpY3Rpb25zTWlsZGV3ID4gMC41LCAxLDApLCBtaWxkZXdbOToxMixdJE91dGJyZWFrMSwgcG9zaXRpdmUgPSBjKCIxIikpDQpgYGANCg0KVGhlIHByb2JhYmlsaXR5IG9mIGEgbWlsZGV3IG91dGJyZWFrIGluIDE5OTUgaXMgMTEuMiUgdXNpbmcgYSBjdXRvZmYgb2YgMC41LiBUaGUgYWNjdXJhY3R5IG9mIHRoZSBtb2RlbCBpcyA3NSUsIG11Y2ggYmV0dGVyIHRoYW4gdGhhdCBvZiB0aGUgbmFpdmUgbW9kZWwuIEZvcmVjYXN0aW5nIHRoZSBwcm9iYWJpbGl0eSB0aGF0IHRoZSBtaWxkZXcgd2lsbCBncm93IHdpdGggYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIGlzIHByZWZlcmlibGUgdGhhbiBmb3JlY2FzdGluZyB3aXRoIGEgbmFpdmUgbW9kZWwgaW4gdGhpcyBjYXNlIGdpdmVuIHRoZSBkYXRhIHNldC4g