This post will illustrate how to conduct statistical analysis on count data.

What is Count Data

When discussing the modeling of count data, it’s important to clarify exactly what is meant by a count. The word “count” is typically used as a verb meaning to enumerate units, items, or events. We might count the number of road kills observed on a stretch of highway, how many patients died at a particular hospital within 48 hours of having a myocardial infarction.

The datset that will be explored is a forest fire dataset. In this dataset it contains the following:

cases: number of forest fire cases reported in each of the 253 areas between June and September, 2017;
size: the size of each area (in km2);
windspeed: the average wind speed (in mph) of each area over the observation period;
temperature: the average temperature (in oC) of each area over the observation period;
wui: a quantity measuring the woodland-urban interface, the proportion of each area where houses are in or near wildland vegetation;
terrain: a variable describing the main topographical feature of each area.

What is the problem that needs to be solved?

A local authoriy is looking at using the data from past forest fires to drive policy decision on what polidices would best prevent a protect from local forest fires from breaking out.

In this example the data is bounded at zero, with forest fire cases being the dependent variable then it is not possible to obtain negative counts. Consequently, it would not be suitable to use standard linear regression in this case, since the assumptions that Y (the dependent variable) follows a normal distribution is violated, as it assumes normal errors around the mean, and hence equally weights them. This means that the likelihood of a count of one is just as likely as negative one, which is not the case for this data here.

#Histogram of forest fire cases
hist(forestfire$cases,breaks = c(0,0.9999,1.9999,2.9999,3.9999,4.9999,5.9999),
     freq = TRUE,xlab='Cases',main = 'Histogram of number of forest fires')
the AREAS in the plot are wrong -- rather use 'freq = FALSE'

The above histogram shows how the distribution of the data does not follow a normal distribution and is thus unsuitable for linear regression.

Initial Exploritary Data Analysis

#Plot of the data
plot(forestfire)

In the above pair plot it is evident that there is no liner correlation between any of the variables. This further illustrates how a linear regression model is not suitable. An alternative is to use a Poisson regression model or one of its variants. These models have a number of advantages over an ordinary linear regression model, including a skew, discrete distribution, and the restriction of predicted values to non-negative numbers. A Poisson model is similar to an ordinary linear regression, with two exceptions. First, it assumes that the errors follow a Poisson, not a normal, distribution. Second, rather than modeling Y as a linear function of the regression coefficients, it models the natural log of the response variable, ln(Y), as a linear function of the coefficients.

The Poisson Model

Each count can be modeled within a Poisson distribution with a mean value of
\[\textrm{Pr}(Y=y|\lambda)=\frac{e^{-\lambda}\lambda^{y}}{y!} \quad (y=0,1,2,...). \] In the above equation the distribution is specified using a single parameter lambda. The parameter lambda is the mean incidence count. Exposure may be time, space, distance, area, volume, or population size.

The parameter lambda may be interpreted as the risk of a new occurrence of the event during a specified exposure period, t. The probability of y events is then given by

\[\Pr(Y = y | \lambda,t) = \frac{e^{-\lambda t}(\lambda t)^y}{y!} \quad (y=0,1,2,...).\] When employing a rate parameter over time, area or volume to a Poisson model, then it is entered as the natural log of t as an offset into the estimating algorithm. The offset with the fitted value is expressed as
\[\lambda = e^{(x\beta + \log(t))},\] and can be rewritten as
\[e^{x\beta} = \frac{\lambda}{t}, \quad \lambda = t e^{x\beta},\] log(t) is entered into the estimating algorithm as a constant (Hilbe, 2014).

#Number of data points
length(forestfire$cases)
[1] 253
summary(forestfire)
     cases            size         windspeed       temperature         wui               terrain   
 Min.   :0.000   Min.   : 60.8   Min.   : 1.984   Min.   :20.00   Min.   :0.05015   forest   : 38  
 1st Qu.:0.000   1st Qu.:106.3   1st Qu.: 6.705   1st Qu.:22.23   1st Qu.:0.16471   hillyArea: 51  
 Median :1.000   Median :117.7   Median : 7.950   Median :24.32   Median :0.20477   plain    :117  
 Mean   :1.115   Mean   :119.1   Mean   : 8.051   Mean   :24.28   Mean   :0.20087   swamp    : 47  
 3rd Qu.:2.000   3rd Qu.:130.8   3rd Qu.: 9.479   3rd Qu.:26.02   3rd Qu.:0.23695                  
 Max.   :5.000   Max.   :168.5   Max.   :15.621   Max.   :31.03   Max.   :0.35279                  

Having established that linear regression is unsuited to model this count data, a Poisson regression can be used as an appropriate model to use in this case, provided it satisfies the basic requirements of a Poisson model. The general formula for the Poisson regres- sion model is:

\[Y_i = \lambda_i = \exp^{x_{i}\beta},\] where Y is the predicted count, lambda is the predicted event rate for ith sample, and e are the regressors.

The basic Poisson assumptions are:
1. The distribution is discrete with a single parameter, the mean. It is the expected number of times that an item or event occurs per unit of time, area or volume.
2. The response terms are non negative integers.
3. Observations are independent of one another.
4. The mean and variance of the model are almost the same.

One condition that the Poisson regression must satisfy is to ensure that the data is not significantly over or under dispersed. This means that the mean should be approximately the same as the variance (Hilbe, 2014).

Testing for over dispersion

#Compare Mean and Variance the number of cases
mean(forestfire$cases)
[1] 1.114625
var(forestfire$cases)
[1] 1.165381
mean(forestfire$size)
[1] 119.0527
var(forestfire$size)
[1] 366.4492
mean(forestfire$cases)/mean(forestfire$size)
[1] 0.00936245
var(forestfire$cases)/var(forestfire$size)
[1] 0.003180196
#Difference in rate mean and rate variance 
mean(forestfire$cases)/mean(forestfire$size)-var(forestfire$cases)/var(forestfire$size)
[1] 0.006182253

Subsequently, the difference between the rate mean and rate variance are almost identical (a difference of 0.006) suggesting there is no substantial over or under dispersion here.

Fitting a regression model

The general Poisson model using the size of each area as the offset term gives the following regression formula: \[\log(\lambda_i) = \log(\textrm{size}) + \beta_0 + \beta_1\textrm{Windspeed} + \beta_2\textrm{Temprature} +\beta_3 \textrm{WUI}\\ + \beta_4\textrm{Terrain}X_1\textrm{HillyArea}+\beta_4\textrm{Terrain}X_2\textrm{Plain}+\beta_4\textrm{Terrain}X_3\textrm{Swamp}.\]

#Fitting a poisson model
FullPoissonModel <- glm(forestfire$cases ~ forestfire$windspeed + 
                          forestfire$temperature + forestfire$wui
                        + forestfire$terrain + offset(log(forestfire$size)),poisson)
summary(FullPoissonModel)

Call:
glm(formula = forestfire$cases ~ forestfire$windspeed + forestfire$temperature + 
    forestfire$wui + forestfire$terrain + offset(log(forestfire$size)), 
    family = poisson)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-2.14120  -1.29547  -0.06082   0.46339   2.62288  

Coefficients:
                             Estimate Std. Error z value Pr(>|z|)    
(Intercept)                 -6.439233   0.687780  -9.362  < 2e-16 ***
forestfire$windspeed         0.024764   0.028430   0.871  0.38374    
forestfire$temperature       0.067991   0.023652   2.875  0.00405 ** 
forestfire$wui               0.549923   1.117609   0.492  0.62268    
forestfire$terrainhillyArea -0.276622   0.196199  -1.410  0.15857    
forestfire$terrainplain     -0.353247   0.166549  -2.121  0.03392 *  
forestfire$terrainswamp     -0.006726   0.186626  -0.036  0.97125    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 299.85  on 252  degrees of freedom
Residual deviance: 284.72  on 246  degrees of freedom
AIC: 696.14

Number of Fisher Scoring iterations: 5

The P-value for temprature is less than 0.05 so this is sgnificant. Although the P-value for the terrain plain is close to 0.05 and is only slightly larger. Subsequntly, the next step is to fit a model with the temprature only.

#fit the model with temprature only
TempPoissonModel <- glm(forestfire$cases ~ forestfire$temperature + 
                          offset(log(forestfire$size)),poisson)
summary(TempPoissonModel)

Call:
glm(formula = forestfire$cases ~ forestfire$temperature + offset(log(forestfire$size)), 
    family = poisson)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-1.96352  -1.35488  -0.08503   0.53047   2.73585  

Coefficients:
                       Estimate Std. Error z value Pr(>|z|)    
(Intercept)            -6.20382    0.58385 -10.626   <2e-16 ***
forestfire$temperature  0.06258    0.02352   2.661   0.0078 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 299.85  on 252  degrees of freedom
Residual deviance: 292.80  on 251  degrees of freedom
AIC: 694.21

Number of Fisher Scoring iterations: 5

The next step is to compare the two models and decide which one would ultimatly be best to use as a final model.

#Compare the full model with the reduced model
library(lmtest)
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric
lrtest(FullPoissonModel,TempPoissonModel)
Likelihood ratio test

Model 1: forestfire$cases ~ forestfire$windspeed + forestfire$temperature + 
    forestfire$wui + forestfire$terrain + offset(log(forestfire$size))
Model 2: forestfire$cases ~ forestfire$temperature + offset(log(forestfire$size))
  #Df  LogLik Df Chisq Pr(>Chisq)
1   7 -341.07                    
2   2 -345.11 -5 8.079     0.1519

H0: Smaller model is best H1: Larger model is better

Here P > 0.05 so we retain H0 and the full model is worse. We go for the simpler model. However, model 1 does have a slightly lower LogLiklihood.

The regression model is consequently: \[ \log(\lambda_i) = \log(\textrm{size}) + \beta_0 + \beta_1\textrm{Temprature}\] \[ \log(\lambda_i) = -5.90696+ 0.05267*\textrm{Temprature}\]

Model Diagnostics

Goodness of fit

anova(TempPoissonModel,test = "Chisq")
Analysis of Deviance Table

Model: poisson, link: log

Response: forestfire$cases

Terms added sequentially (first to last)

                       Df Deviance Resid. Df Resid. Dev Pr(>Chi)   
NULL                                     252     299.85            
forestfire$temperature  1   7.0473       251     292.80 0.007939 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

H0: Null Modell is best.
H1: Full model fits better.

Here P-val < 0.05 so reject H0, and the Temp Model is a good fit.

Check for over/underdispersion

library(AER)
deviance(TempPoissonModel)/TempPoissonModel$df.residual
[1] 1.166541
dispersiontest(TempPoissonModel)

    Overdispersion test

data:  TempPoissonModel
z = 0.079021, p-value = 0.4685
alternative hypothesis: true dispersion is greater than 1
sample estimates:
dispersion 
  1.007029 

Here P-val > 0.05 so retain null hypothesis, and true dispersion is not significantly greater than one and the data is not overdispersed.

Check for influential and leverage points

library(car)
influencePlot(TempPoissonModel)

cooks <- cooks.distance(TempPoissonModel)
leverage <- hatvalues(TempPoissonModel)
forestfire[cooks>0.018, ] #2p/n p=2 n=220 
forestfire[leverage>0.018, ]

Check for zero inflation

library(pscl)
zerocheck <- zeroinfl(forestfire$cases ~ forestfire$temperature+
                        offset(log(forestfire$size)), dist='poisson')
AIC(TempPoissonModel,zerocheck)

The Temp Poisson Model has a lower AIC and suggesting it is a better fit than a zero inflated model. This suggests that the data is not zero inflated.

Half normal probability plot.

library(faraway)
halfnorm(residuals(TempPoissonModel))

Half-Normal plots are obtained by plotting the ordered absolute values of a model diagnostic versus the expected order statistic of a half-normal distribution.

Conclusion

From the final regression model above it is clear that temperature is of key importance when it comes to pre- vention of forest fires. With a positive coefficient value of approximately 0.05 meaning there is a positive correlation with the number of fires and the temperature. Additionally, what the model has shown is that since the other factors are not statistically significant at the 5% level then there is no significant greater chance of forest fires occurring for different terrains. Furthermore, the wind-speed and proportion of woodland urban interface (WUI) does not have any significant added reason in a greater number of counts of forest fires occurring.

Actionable policy decisions

A policy maker would perhaps take greater precautions against forest fires in areas that have higher temperatures, to have a notable impact on reducing and preventing forest fires. Furthermore, the greatest drive in policy decsions should be focused around temprature. For example, allocating more resources when tempratures rise across all different terrains.

LS0tCnRpdGxlOiAiTW9kZWxsaW5nIENvdW50IERhdGEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgcG9zdCB3aWxsIGlsbHVzdHJhdGUgaG93IHRvIGNvbmR1Y3Qgc3RhdGlzdGljYWwgYW5hbHlzaXMgb24gY291bnQgZGF0YS4gIAoKIyMgV2hhdCBpcyBDb3VudCBEYXRhICAKCldoZW4gZGlzY3Vzc2luZyB0aGUgbW9kZWxpbmcgb2YgY291bnQgZGF0YSwgaXTigJlzIGltcG9ydGFudCB0byBjbGFyaWZ5IGV4YWN0bHkgd2hhdCBpcyBtZWFudCBieSBhIGNvdW50LiBUaGUgd29yZCDigJxjb3VudOKAnSBpcyB0eXBpY2FsbHkgdXNlZCBhcyBhIHZlcmIgbWVhbmluZyB0byBlbnVtZXJhdGUgdW5pdHMsIGl0ZW1zLCBvciBldmVudHMuIFdlIG1pZ2h0IGNvdW50IHRoZSBudW1iZXIgb2Ygcm9hZCBraWxscyBvYnNlcnZlZCBvbiBhIHN0cmV0Y2ggb2YgaGlnaHdheSwgaG93IG1hbnkgcGF0aWVudHMgZGllZCBhdCBhIHBhcnRpY3VsYXIgaG9zcGl0YWwgd2l0aGluIDQ4IGhvdXJzIG9mIGhhdmluZyBhIG15b2NhcmRpYWwgaW5mYXJjdGlvbi4gIAoKVGhlIGRhdHNldCB0aGF0IHdpbGwgYmUgZXhwbG9yZWQgaXMgYSBmb3Jlc3QgZmlyZSBkYXRhc2V0LiBJbiB0aGlzIGRhdGFzZXQgaXQgY29udGFpbnMgdGhlIGZvbGxvd2luZzoKCmNhc2VzOiBudW1iZXIgb2YgZm9yZXN0IGZpcmUgY2FzZXMgcmVwb3J0ZWQgaW4gZWFjaCBvZiB0aGUgMjUzIGFyZWFzIGJldHdlZW4gSnVuZSBhbmQgU2VwdGVtYmVyLCAyMDE3OyAgCnNpemU6IHRoZSBzaXplIG9mIGVhY2ggYXJlYSAoaW4ga20yKTsgIAp3aW5kc3BlZWQ6IHRoZSBhdmVyYWdlIHdpbmQgc3BlZWQgKGluIG1waCkgb2YgZWFjaCBhcmVhIG92ZXIgdGhlIG9ic2VydmF0aW9uIHBlcmlvZDsgICAKdGVtcGVyYXR1cmU6IHRoZSBhdmVyYWdlIHRlbXBlcmF0dXJlIChpbiBvQykgb2YgZWFjaCBhcmVhIG92ZXIgdGhlIG9ic2VydmF0aW9uIHBlcmlvZDsgICAKd3VpOiBhIHF1YW50aXR5IG1lYXN1cmluZyB0aGUgd29vZGxhbmQtdXJiYW4gaW50ZXJmYWNlLCB0aGUgcHJvcG9ydGlvbiBvZiBlYWNoIGFyZWEgd2hlcmUgaG91c2VzIGFyZSBpbiBvciBuZWFyIHdpbGRsYW5kIHZlZ2V0YXRpb247ICAKdGVycmFpbjogYSB2YXJpYWJsZSBkZXNjcmliaW5nIHRoZSBtYWluIHRvcG9ncmFwaGljYWwgZmVhdHVyZSBvZiBlYWNoIGFyZWEuICAKCiMjIFdoYXQgaXMgdGhlIHByb2JsZW0gdGhhdCBuZWVkcyB0byBiZSBzb2x2ZWQ/ICAKCkEgbG9jYWwgYXV0aG9yaXkgaXMgbG9va2luZyBhdCB1c2luZyB0aGUgZGF0YSBmcm9tIHBhc3QgZm9yZXN0IGZpcmVzIHRvIGRyaXZlIHBvbGljeSBkZWNpc2lvbiBvbiB3aGF0IHBvbGlkaWNlcyB3b3VsZCBiZXN0IHByZXZlbnQgYSBwcm90ZWN0IGZyb20gbG9jYWwgZm9yZXN0IGZpcmVzIGZyb20gYnJlYWtpbmcgb3V0LiAgCgpJbiB0aGlzIGV4YW1wbGUgdGhlIGRhdGEgaXMgYm91bmRlZCBhdCB6ZXJvLCB3aXRoIGZvcmVzdCBmaXJlIGNhc2VzIGJlaW5nIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgdGhlbiBpdCBpcyBub3QgcG9zc2libGUgdG8gb2J0YWluIG5lZ2F0aXZlIGNvdW50cy4gQ29uc2VxdWVudGx5LCBpdCB3b3VsZCBub3QgYmUgc3VpdGFibGUgdG8gdXNlIHN0YW5kYXJkIGxpbmVhciByZWdyZXNzaW9uIGluIHRoaXMgY2FzZSwgc2luY2UgdGhlIGFzc3VtcHRpb25zIHRoYXQgWSAodGhlIGRlcGVuZGVudCB2YXJpYWJsZSkgZm9sbG93cyBhIG5vcm1hbCBkaXN0cmlidXRpb24gaXMgdmlvbGF0ZWQsIGFzIGl0IGFzc3VtZXMgbm9ybWFsIGVycm9ycyBhcm91bmQgdGhlIG1lYW4sIGFuZCBoZW5jZSBlcXVhbGx5IHdlaWdodHMgdGhlbS4gVGhpcyBtZWFucyB0aGF0IHRoZSBsaWtlbGlob29kIG9mIGEgY291bnQgb2Ygb25lIGlzIGp1c3QgYXMgbGlrZWx5IGFzIG5lZ2F0aXZlIG9uZSwgd2hpY2ggaXMgbm90IHRoZSBjYXNlIGZvciB0aGlzIGRhdGEgaGVyZS4gIAoKYGBge3J9CiNIaXN0b2dyYW0gb2YgZm9yZXN0IGZpcmUgY2FzZXMKaGlzdChmb3Jlc3RmaXJlJGNhc2VzLGJyZWFrcyA9IGMoMCwwLjk5OTksMS45OTk5LDIuOTk5OSwzLjk5OTksNC45OTk5LDUuOTk5OSksCiAgICAgZnJlcSA9IFRSVUUseGxhYj0nQ2FzZXMnLG1haW4gPSAnSGlzdG9ncmFtIG9mIG51bWJlciBvZiBmb3Jlc3QgZmlyZXMnKQpgYGAKClRoZSBhYm92ZSBoaXN0b2dyYW0gc2hvd3MgaG93IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEgZG9lcyBub3QgZm9sbG93IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhbmQgaXMgdGh1cyB1bnN1aXRhYmxlIGZvciBsaW5lYXIgcmVncmVzc2lvbi4gIAoKIyMjIEluaXRpYWwgRXhwbG9yaXRhcnkgRGF0YSBBbmFseXNpcyAgCgpgYGB7cn0KI1Bsb3Qgb2YgdGhlIGRhdGEKcGxvdChmb3Jlc3RmaXJlKQpgYGAKCkluIHRoZSBhYm92ZSBwYWlyIHBsb3QgaXQgaXMgZXZpZGVudCB0aGF0IHRoZXJlIGlzIG5vIGxpbmVyIGNvcnJlbGF0aW9uIGJldHdlZW4gYW55IG9mIHRoZSB2YXJpYWJsZXMuIFRoaXMgZnVydGhlciBpbGx1c3RyYXRlcyBob3cgYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBpcyBub3Qgc3VpdGFibGUuIEFuIGFsdGVybmF0aXZlIGlzIHRvIHVzZSBhIFBvaXNzb24gcmVncmVzc2lvbiBtb2RlbCBvciBvbmUgb2YgaXRzIHZhcmlhbnRzLiBUaGVzZSBtb2RlbHMgaGF2ZSBhIG51bWJlciBvZiBhZHZhbnRhZ2VzIG92ZXIgYW4gb3JkaW5hcnkgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIGluY2x1ZGluZyBhIHNrZXcsIGRpc2NyZXRlIGRpc3RyaWJ1dGlvbiwgYW5kIHRoZSByZXN0cmljdGlvbiBvZiBwcmVkaWN0ZWQgdmFsdWVzIHRvIG5vbi1uZWdhdGl2ZSBudW1iZXJzLiBBIFBvaXNzb24gbW9kZWwgaXMgc2ltaWxhciB0byBhbiBvcmRpbmFyeSBsaW5lYXIgcmVncmVzc2lvbiwgd2l0aCB0d28gZXhjZXB0aW9ucy4gRmlyc3QsIGl0IGFzc3VtZXMgdGhhdCB0aGUgZXJyb3JzIGZvbGxvdyBhIFBvaXNzb24sIG5vdCBhIG5vcm1hbCwgZGlzdHJpYnV0aW9uLiBTZWNvbmQsIHJhdGhlciB0aGFuIG1vZGVsaW5nIFkgYXMgYSBsaW5lYXIgZnVuY3Rpb24gb2YgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLCBpdCBtb2RlbHMgdGhlIG5hdHVyYWwgbG9nIG9mIHRoZSByZXNwb25zZSB2YXJpYWJsZSwgbG4oWSksIGFzIGEgbGluZWFyIGZ1bmN0aW9uIG9mIHRoZSBjb2VmZmljaWVudHMuICAKCiMjIyBUaGUgUG9pc3NvbiBNb2RlbCAgCgpFYWNoIGNvdW50IGNhbiBiZSBtb2RlbGVkIHdpdGhpbiBhIFBvaXNzb24gZGlzdHJpYnV0aW9uIHdpdGggYSBtZWFuIHZhbHVlIG9mICAKJCRcdGV4dHJte1ByfShZPXl8XGxhbWJkYSk9XGZyYWN7ZV57LVxsYW1iZGF9XGxhbWJkYV57eX19e3khfSBccXVhZCAoeT0wLDEsMiwuLi4pLiAkJApJbiB0aGUgYWJvdmUgZXF1YXRpb24gdGhlIGRpc3RyaWJ1dGlvbiBpcyBzcGVjaWZpZWQgdXNpbmcgYSBzaW5nbGUgcGFyYW1ldGVyIGxhbWJkYS4gVGhlIHBhcmFtZXRlciBsYW1iZGEgaXMgdGhlIG1lYW4gaW5jaWRlbmNlIGNvdW50LiBFeHBvc3VyZSBtYXkgYmUgdGltZSwgc3BhY2UsIGRpc3RhbmNlLCBhcmVhLCB2b2x1bWUsIG9yIHBvcHVsYXRpb24gc2l6ZS4gIAoKVGhlIHBhcmFtZXRlciBsYW1iZGEgbWF5IGJlIGludGVycHJldGVkIGFzIHRoZSByaXNrIG9mIGEgbmV3IG9jY3VycmVuY2Ugb2YgdGhlIGV2ZW50IGR1cmluZyBhIHNwZWNpZmllZCBleHBvc3VyZQpwZXJpb2QsIHQuIFRoZSBwcm9iYWJpbGl0eSBvZiB5IGV2ZW50cyBpcyB0aGVuIGdpdmVuIGJ5ICAKCiQkXFByKFkgPSB5IHwgXGxhbWJkYSx0KSA9IFxmcmFje2Veey1cbGFtYmRhIHR9KFxsYW1iZGEgdCleeX17eSF9IFxxdWFkICh5PTAsMSwyLC4uLikuJCQKV2hlbiBlbXBsb3lpbmcgYSByYXRlIHBhcmFtZXRlciBvdmVyIHRpbWUsIGFyZWEgb3Igdm9sdW1lIHRvIGEgUG9pc3NvbiBtb2RlbCwgdGhlbiBpdCBpcyBlbnRlcmVkIGFzIHRoZSBuYXR1cmFsIGxvZyBvZiB0IGFzIGFuIG9mZnNldCBpbnRvIHRoZSBlc3RpbWF0aW5nIGFsZ29yaXRobS4gVGhlIG9mZnNldCAgd2l0aCB0aGUgZml0dGVkIHZhbHVlIGlzIGV4cHJlc3NlZCBhcyAgCiQkXGxhbWJkYSA9IGVeeyh4XGJldGEgKyBcbG9nKHQpKX0sJCQKYW5kIGNhbiBiZSByZXdyaXR0ZW4gYXMgIAokJGVee3hcYmV0YX0gPSBcZnJhY3tcbGFtYmRhfXt0fSwgXHF1YWQgXGxhbWJkYSA9IHQgZV57eFxiZXRhfSwkJApsb2codCkgaXMgZW50ZXJlZCBpbnRvIHRoZSBlc3RpbWF0aW5nIGFsZ29yaXRobSBhcyBhIGNvbnN0YW50IChIaWxiZSwgMjAxNCkuICAKCmBgYHtyfQojTnVtYmVyIG9mIGRhdGEgcG9pbnRzCmxlbmd0aChmb3Jlc3RmaXJlJGNhc2VzKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGZvcmVzdGZpcmUpCmBgYAoKSGF2aW5nIGVzdGFibGlzaGVkIHRoYXQgbGluZWFyIHJlZ3Jlc3Npb24gaXMgdW5zdWl0ZWQgdG8gbW9kZWwgdGhpcyBjb3VudCBkYXRhLCBhIFBvaXNzb24gcmVncmVzc2lvbiBjYW4gYmUgdXNlZCBhcyBhbiBhcHByb3ByaWF0ZSBtb2RlbCB0byB1c2UgaW4gdGhpcyBjYXNlLCBwcm92aWRlZCBpdCBzYXRpc2ZpZXMgdGhlIGJhc2ljIHJlcXVpcmVtZW50cyBvZiBhIFBvaXNzb24gbW9kZWwuIFRoZSBnZW5lcmFsIGZvcm11bGEgZm9yIHRoZSBQb2lzc29uIHJlZ3Jlcy0gc2lvbiBtb2RlbCBpczoKCiQkWV9pID0gXGxhbWJkYV9pID0gXGV4cF57eF97aX1cYmV0YX0sJCQKd2hlcmUgWSBpcyB0aGUgcHJlZGljdGVkIGNvdW50LCBsYW1iZGEgaXMgdGhlIHByZWRpY3RlZCBldmVudCByYXRlIGZvciBpdGggc2FtcGxlLCBhbmQgZSBhcmUgdGhlIHJlZ3Jlc3NvcnMuICAKClRoZSBiYXNpYyBQb2lzc29uIGFzc3VtcHRpb25zIGFyZTogIAoxLiBUaGUgZGlzdHJpYnV0aW9uIGlzIGRpc2NyZXRlIHdpdGggYSBzaW5nbGUgcGFyYW1ldGVyLCB0aGUgbWVhbi4gSXQgaXMgdGhlIGV4cGVjdGVkIG51bWJlciBvZiB0aW1lcyB0aGF0IGFuIGl0ZW0gb3IgZXZlbnQgb2NjdXJzIHBlciB1bml0IG9mIHRpbWUsIGFyZWEgb3Igdm9sdW1lLiAgCjIuIFRoZSByZXNwb25zZSB0ZXJtcyBhcmUgbm9uIG5lZ2F0aXZlIGludGVnZXJzLiAgCjMuIE9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbnQgb2Ygb25lIGFub3RoZXIuICAKNC4gVGhlIG1lYW4gYW5kIHZhcmlhbmNlIG9mIHRoZSBtb2RlbCBhcmUgYWxtb3N0IHRoZSBzYW1lLiAgCgpPbmUgY29uZGl0aW9uIHRoYXQgdGhlIFBvaXNzb24gcmVncmVzc2lvbiBtdXN0IHNhdGlzZnkgaXMgdG8gZW5zdXJlIHRoYXQgdGhlIGRhdGEgaXMgbm90IHNpZ25pZmljYW50bHkgb3ZlciBvciB1bmRlciBkaXNwZXJzZWQuIFRoaXMgbWVhbnMgdGhhdCB0aGUgbWVhbiBzaG91bGQgYmUgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhcyB0aGUgdmFyaWFuY2UgKEhpbGJlLCAyMDE0KS4gIAoKIyMjIFRlc3RpbmcgZm9yIG92ZXIgZGlzcGVyc2lvbiAgCgpgYGB7cn0KI0NvbXBhcmUgTWVhbiBhbmQgVmFyaWFuY2UgdGhlIG51bWJlciBvZiBjYXNlcwptZWFuKGZvcmVzdGZpcmUkY2FzZXMpCnZhcihmb3Jlc3RmaXJlJGNhc2VzKQpgYGAKCmBgYHtyfQptZWFuKGZvcmVzdGZpcmUkc2l6ZSkKdmFyKGZvcmVzdGZpcmUkc2l6ZSkKYGBgCgpgYGB7cn0KbWVhbihmb3Jlc3RmaXJlJGNhc2VzKS9tZWFuKGZvcmVzdGZpcmUkc2l6ZSkKdmFyKGZvcmVzdGZpcmUkY2FzZXMpL3Zhcihmb3Jlc3RmaXJlJHNpemUpCmBgYAoKYGBge3J9CiNEaWZmZXJlbmNlIGluIHJhdGUgbWVhbiBhbmQgcmF0ZSB2YXJpYW5jZSAKbWVhbihmb3Jlc3RmaXJlJGNhc2VzKS9tZWFuKGZvcmVzdGZpcmUkc2l6ZSktdmFyKGZvcmVzdGZpcmUkY2FzZXMpL3Zhcihmb3Jlc3RmaXJlJHNpemUpCmBgYAoKU3Vic2VxdWVudGx5LCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSByYXRlIG1lYW4gYW5kIHJhdGUgdmFyaWFuY2UgYXJlIGFsbW9zdCBpZGVudGljYWwgKGEgZGlmZmVyZW5jZSBvZiAwLjAwNikgc3VnZ2VzdGluZyB0aGVyZSBpcyBubyBzdWJzdGFudGlhbCBvdmVyIG9yIHVuZGVyIGRpc3BlcnNpb24gaGVyZS4gIAoKIyMjIEZpdHRpbmcgYSByZWdyZXNzaW9uIG1vZGVsCgpUaGUgZ2VuZXJhbCBQb2lzc29uIG1vZGVsIHVzaW5nIHRoZSBzaXplIG9mIGVhY2ggYXJlYSBhcyB0aGUgb2Zmc2V0IHRlcm0gZ2l2ZXMgdGhlIGZvbGxvd2luZyByZWdyZXNzaW9uIGZvcm11bGE6CiQkXGxvZyhcbGFtYmRhX2kpID0gIFxsb2coXHRleHRybXtzaXplfSkgKyBcYmV0YV8wICsgXGJldGFfMVx0ZXh0cm17V2luZHNwZWVkfSArIFxiZXRhXzJcdGV4dHJte1RlbXByYXR1cmV9ICtcYmV0YV8zIFx0ZXh0cm17V1VJfVxcICsgXGJldGFfNFx0ZXh0cm17VGVycmFpbn1YXzFcdGV4dHJte0hpbGx5QXJlYX0rXGJldGFfNFx0ZXh0cm17VGVycmFpbn1YXzJcdGV4dHJte1BsYWlufStcYmV0YV80XHRleHRybXtUZXJyYWlufVhfM1x0ZXh0cm17U3dhbXB9LiQkCgpgYGB7cn0KI0ZpdHRpbmcgYSBwb2lzc29uIG1vZGVsCkZ1bGxQb2lzc29uTW9kZWwgPC0gZ2xtKGZvcmVzdGZpcmUkY2FzZXMgfiBmb3Jlc3RmaXJlJHdpbmRzcGVlZCArIAogICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmVzdGZpcmUkdGVtcGVyYXR1cmUgKyBmb3Jlc3RmaXJlJHd1aQogICAgICAgICAgICAgICAgICAgICAgICArIGZvcmVzdGZpcmUkdGVycmFpbiArIG9mZnNldChsb2coZm9yZXN0ZmlyZSRzaXplKSkscG9pc3NvbikKc3VtbWFyeShGdWxsUG9pc3Nvbk1vZGVsKQpgYGAKVGhlIFAtdmFsdWUgZm9yIHRlbXByYXR1cmUgaXMgbGVzcyB0aGFuIDAuMDUgc28gdGhpcyBpcyBzZ25pZmljYW50LiBBbHRob3VnaCB0aGUgUC12YWx1ZSBmb3IgdGhlIHRlcnJhaW4gcGxhaW4gaXMgY2xvc2UgdG8gMC4wNSBhbmQgaXMgb25seSBzbGlnaHRseSBsYXJnZXIuIFN1YnNlcXVudGx5LCB0aGUgbmV4dCBzdGVwIGlzIHRvIGZpdCBhIG1vZGVsIHdpdGggdGhlIHRlbXByYXR1cmUgb25seS4gIAoKYGBge3J9CiNmaXQgdGhlIG1vZGVsIHdpdGggdGVtcHJhdHVyZSBvbmx5ClRlbXBQb2lzc29uTW9kZWwgPC0gZ2xtKGZvcmVzdGZpcmUkY2FzZXMgfiBmb3Jlc3RmaXJlJHRlbXBlcmF0dXJlICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0KGxvZyhmb3Jlc3RmaXJlJHNpemUpKSxwb2lzc29uKQpzdW1tYXJ5KFRlbXBQb2lzc29uTW9kZWwpCmBgYAoKVGhlIG5leHQgc3RlcCBpcyB0byBjb21wYXJlIHRoZSB0d28gbW9kZWxzIGFuZCBkZWNpZGUgd2hpY2ggb25lIHdvdWxkIHVsdGltYXRseSBiZSBiZXN0IHRvIHVzZSBhcyBhIGZpbmFsIG1vZGVsLiAgCgpgYGB7cn0KI0NvbXBhcmUgdGhlIGZ1bGwgbW9kZWwgd2l0aCB0aGUgcmVkdWNlZCBtb2RlbApsaWJyYXJ5KGxtdGVzdCkKbHJ0ZXN0KEZ1bGxQb2lzc29uTW9kZWwsVGVtcFBvaXNzb25Nb2RlbCkKYGBgCgpIMDogU21hbGxlciBtb2RlbCBpcyBiZXN0CkgxOiBMYXJnZXIgbW9kZWwgaXMgYmV0dGVyCgpIZXJlIFAgPiAwLjA1IHNvIHdlIHJldGFpbiBIMCBhbmQgdGhlIGZ1bGwgbW9kZWwgaXMgd29yc2UuIFdlIGdvIGZvciB0aGUgc2ltcGxlciBtb2RlbC4gSG93ZXZlciwgbW9kZWwgMSBkb2VzIGhhdmUgYSBzbGlnaHRseSBsb3dlciBMb2dMaWtsaWhvb2QuICAKClRoZSByZWdyZXNzaW9uIG1vZGVsIGlzIGNvbnNlcXVlbnRseToKJCQgICAgXGxvZyhcbGFtYmRhX2kpID0gIFxsb2coXHRleHRybXtzaXplfSkgKyBcYmV0YV8wICsgXGJldGFfMVx0ZXh0cm17VGVtcHJhdHVyZX0kJAogICAkJCBcbG9nKFxsYW1iZGFfaSkgPSAgLTUuOTA2OTYrIDAuMDUyNjcqXHRleHRybXtUZW1wcmF0dXJlfSQkCgojIyMgTW9kZWwgRGlhZ25vc3RpY3MgIAoKR29vZG5lc3Mgb2YgZml0ICAKYGBge3J9CmFub3ZhKFRlbXBQb2lzc29uTW9kZWwsdGVzdCA9ICJDaGlzcSIpCmBgYAoKSDA6IE51bGwgTW9kZWxsIGlzIGJlc3QuICAKSDE6IEZ1bGwgbW9kZWwgZml0cyBiZXR0ZXIuICAKCkhlcmUgUC12YWwgPCAwLjA1IHNvIHJlamVjdCBIMCwgYW5kIHRoZSBUZW1wIE1vZGVsIGlzIGEgZ29vZCBmaXQuICAKCkNoZWNrIGZvciBvdmVyL3VuZGVyZGlzcGVyc2lvbgpgYGB7cn0KbGlicmFyeShBRVIpCmRldmlhbmNlKFRlbXBQb2lzc29uTW9kZWwpL1RlbXBQb2lzc29uTW9kZWwkZGYucmVzaWR1YWwKZGlzcGVyc2lvbnRlc3QoVGVtcFBvaXNzb25Nb2RlbCkKYGBgCkhlcmUgUC12YWwgPiAwLjA1IHNvIHJldGFpbiBudWxsIGh5cG90aGVzaXMsIGFuZCB0cnVlIGRpc3BlcnNpb24gaXMgbm90IHNpZ25pZmljYW50bHkgZ3JlYXRlciB0aGFuIG9uZSBhbmQgdGhlIGRhdGEgaXMgbm90IG92ZXJkaXNwZXJzZWQuICAKCkNoZWNrIGZvciBpbmZsdWVudGlhbCBhbmQgbGV2ZXJhZ2UgcG9pbnRzICAKYGBge3J9CmxpYnJhcnkoY2FyKQppbmZsdWVuY2VQbG90KFRlbXBQb2lzc29uTW9kZWwpCmBgYAoKYGBge3J9CmNvb2tzIDwtIGNvb2tzLmRpc3RhbmNlKFRlbXBQb2lzc29uTW9kZWwpCmxldmVyYWdlIDwtIGhhdHZhbHVlcyhUZW1wUG9pc3Nvbk1vZGVsKQpmb3Jlc3RmaXJlW2Nvb2tzPjAuMDE4LCBdICMycC9uIHA9MiBuPTIyMCAKZm9yZXN0ZmlyZVtsZXZlcmFnZT4wLjAxOCwgXQpgYGAKCkNoZWNrIGZvciB6ZXJvIGluZmxhdGlvbgpgYGB7cn0KbGlicmFyeShwc2NsKQp6ZXJvY2hlY2sgPC0gemVyb2luZmwoZm9yZXN0ZmlyZSRjYXNlcyB+IGZvcmVzdGZpcmUkdGVtcGVyYXR1cmUrCiAgICAgICAgICAgICAgICAgICAgICAgIG9mZnNldChsb2coZm9yZXN0ZmlyZSRzaXplKSksIGRpc3Q9J3BvaXNzb24nKQpBSUMoVGVtcFBvaXNzb25Nb2RlbCx6ZXJvY2hlY2spCmBgYAoKVGhlIFRlbXAgUG9pc3NvbiBNb2RlbCBoYXMgYSBsb3dlciBBSUMgYW5kIHN1Z2dlc3RpbmcgaXQgaXMgYSBiZXR0ZXIgZml0IHRoYW4gYSB6ZXJvIGluZmxhdGVkIG1vZGVsLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIGRhdGEgaXMgbm90IHplcm8gaW5mbGF0ZWQuICAKCkhhbGYgbm9ybWFsIHByb2JhYmlsaXR5IHBsb3QuICAKYGBge3J9CmxpYnJhcnkoZmFyYXdheSkKaGFsZm5vcm0ocmVzaWR1YWxzKFRlbXBQb2lzc29uTW9kZWwpKQpgYGAKCkhhbGYtTm9ybWFsIHBsb3RzIGFyZSBvYnRhaW5lZCBieSBwbG90dGluZyB0aGUgb3JkZXJlZCBhYnNvbHV0ZSB2YWx1ZXMgb2YgYSBtb2RlbCBkaWFnbm9zdGljIHZlcnN1cyB0aGUgZXhwZWN0ZWQgb3JkZXIgc3RhdGlzdGljIG9mIGEgaGFsZi1ub3JtYWwgZGlzdHJpYnV0aW9uLiAKCgojIyBDb25jbHVzaW9uIAoKRnJvbSB0aGUgZmluYWwgcmVncmVzc2lvbiBtb2RlbCBhYm92ZSBpdCBpcyBjbGVhciB0aGF0IHRlbXBlcmF0dXJlIGlzIG9mIGtleSBpbXBvcnRhbmNlIHdoZW4gaXQgY29tZXMgdG8gcHJlLSB2ZW50aW9uIG9mIGZvcmVzdCBmaXJlcy4gV2l0aCBhIHBvc2l0aXZlIGNvZWZmaWNpZW50IHZhbHVlIG9mIGFwcHJveGltYXRlbHkgMC4wNSBtZWFuaW5nIHRoZXJlIGlzIGEgcG9zaXRpdmUgY29ycmVsYXRpb24gd2l0aCB0aGUgbnVtYmVyIG9mIGZpcmVzIGFuZCB0aGUgdGVtcGVyYXR1cmUuIEFkZGl0aW9uYWxseSwgd2hhdCB0aGUgbW9kZWwgaGFzIHNob3duIGlzIHRoYXQgc2luY2UgdGhlIG90aGVyIGZhY3RvcnMgYXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGF0IHRoZSA1JSBsZXZlbCB0aGVuIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGdyZWF0ZXIgY2hhbmNlIG9mIGZvcmVzdCBmaXJlcyBvY2N1cnJpbmcgZm9yIGRpZmZlcmVudCB0ZXJyYWlucy4gRnVydGhlcm1vcmUsIHRoZSB3aW5kLXNwZWVkIGFuZCBwcm9wb3J0aW9uIG9mIHdvb2RsYW5kIHVyYmFuIGludGVyZmFjZSAoV1VJKSBkb2VzIG5vdCBoYXZlIGFueSBzaWduaWZpY2FudCBhZGRlZCByZWFzb24gaW4gYSBncmVhdGVyIG51bWJlciBvZiBjb3VudHMgb2YgZm9yZXN0IGZpcmVzIG9jY3VycmluZy4gICAgCgojIyBBY3Rpb25hYmxlIHBvbGljeSBkZWNpc2lvbnMgICAgCkEgcG9saWN5IG1ha2VyIHdvdWxkIHBlcmhhcHMgdGFrZSBncmVhdGVyIHByZWNhdXRpb25zIGFnYWluc3QgZm9yZXN0IGZpcmVzIGluIGFyZWFzIHRoYXQgaGF2ZSBoaWdoZXIgdGVtcGVyYXR1cmVzLCB0byBoYXZlIGEgbm90YWJsZSBpbXBhY3Qgb24gcmVkdWNpbmcgYW5kIHByZXZlbnRpbmcgZm9yZXN0IGZpcmVzLiBGdXJ0aGVybW9yZSwgdGhlIGdyZWF0ZXN0IGRyaXZlIGluIHBvbGljeSBkZWNzaW9ucyBzaG91bGQgYmUgZm9jdXNlZCBhcm91bmQgdGVtcHJhdHVyZS4gRm9yIGV4YW1wbGUsIGFsbG9jYXRpbmcgbW9yZSByZXNvdXJjZXMgd2hlbiB0ZW1wcmF0dXJlcyByaXNlIGFjcm9zcyBhbGwgZGlmZmVyZW50IHRlcnJhaW5zLiAg