Background:
For 30 Galapagos Islands, the data consist of the number of plant species found on each island and the number that are endemic to that island. We also have five geographic variables for each island. The data was presented by Johnson and Raven (1973) and also appear in Weisberg (2005).
While the dataset contains seven variables, we are interested only in the following six:
Species: the number of plant species found on the island Area: the area of the island (km^2) Elevation: the highest elevation of the island (m) Nearest: the distance from the nearest island (km) Scruz: the distance from Santa Cruz island (km) Adjacent: the area of the adjacent island (km^2)
Please install the package faraway, load the dataset gala, and drop the unnecessary second column that is Endemics:
require(faraway)
data(gala)
mydata <- gala
df <- mydata[-2]
exp(0.0057094)
[1] 1.005726
Question 1: Fitting the Model
Fit a poisson regression model using the number of species as the response variable and all other variables as predictors. Call it model1.
- Display the summary of model1. What are the model parameters and estimates?
ans: Elevation: 0.0035406 | Area: -0.0005799 | Nearest: 0.0088256 | Scruz: -0.0057094 | Adjacent: -0.0006630
- Write down the equation for the estimated number of species given the predicting variables.
ans: \(Log(Species) = 3.155 - (0.0005799 \times Area) + (0.0035406\times Elevation) + (0.0088256\times Nearest) - (0.0057094\times Scruz) - (0.0006630\times Adjacent)\)
- Provide meaningful interpretations for the coefficients of Elevation and Scruz.
ans: Holding all else constant, for each meter increase in the elevation of an island, the number of species goes up by a factor of \(1.0035\) (=exp(0.0035406)
). It can also be said that the ratio between [expected count of plant species per island for one meter increase in elevation] to [expected count of species on island for no increase in elevation] is \(1.0035\).
Holding all else constant for each kilometer increase in distance to santa cruz, the number of plant species goes down by a factor of \(1.0057\) (=exp(0.0057094)
). Similarly, the ratio between [expected count of plant species per island for one km increase in distance to Santa Cruz] to [expected count of species on island for no increase in distance to Santa Cruz] is \(1.0057\).
#q2
#a
confint(model1, level=.9)
#b
pc1 <- 3510.7-716.85
pc2 <-29-24
1-pchisq(pc1,pc2)
Question 2: Inference
Using model1, find a 90% confidence interval for the coefficient for Nearest. ans: With \(90 \%\) confidence, the true value of the coefficient for Nearest lies within the range \((0.0058097477, 0.0118020143)\)
Is model1 significant overall? How do you come to your conclusion?
ans: Yes it is significant; I used the pchisq function (subtracting residual from null values) to find the p-value associated with the chi square test for this model. The value was so small that it is reported as equivalent to zero, meaning the null hypothesis can be rejected.
- Which variables are significantly nonzero at the 0.01 significance level? Which are significantly positive? Why?
ans: Elevation and Nearest are significantly positive because their p-value is less than 0.005, which is the p-value of 0.01 divided by two, and their coefficient is a positive number. All predictors (Nearest, Area, Elevation, Scruz, Adjacent) are significantly nonzero at the 0.01 significance level because their p-values are all less than 0.01.
#q3#
#library(vcd)
#library(car)
#library(ggplot2)
#a
## Test for GOF: Using deviance residuals
deviances2 = residuals(model1,type="deviance")
dev.tvalue = sum(deviances2^2)
c(dev.tvalue, 1-pchisq(dev.tvalue,24))
[1] 716.8458 0.0000
## Test for GOF: Using Person residuals
pearres2 = residuals(model1,type="pearson")
pearson.tvalue = sum(pearres2^2)
c(pearson.tvalue, 1-pchisq(pearson.tvalue,24))
[1] 761.9792 0.0000
#b
#res vs fitted
plot(model1, which=1)

#fit to distribution
distplot(df$Species,type="poisson")

#qq
res <- residuals(model1,type="deviance")
qqnorm(res)
qqline(res)

#hist
hist(res,breaks=8,density=15,col="salmon",xlab="Standard residuals", main="Frequency of Residuals Model1")

#pred vs resid
for (i in 2:6) {
plot(df[,i], res, ylab = "Deviance",xlab = names(df[i]))
abline(0,0,col="salmon",lwd=2)
}





#log sepc vs pred
for (i in 2:6) {
plot(log(df$Species), df[,i], ylab = "log(Species)",xlab = names(df[i]))
}





#might make prettier plots in ggplot if have free time
#ggplot(df, aes(x = Species, y = res, color = Area)) +
# geom_point(pch = 20, size = 3) +
# labs(x = "")
#c
disp <- dev.tvalue/(30-5-1)
disp
[1] 29.86857
Question 3: Goodness of fit
- Perform goodness of fit hypothesis tests using both deviance and Pearson residuals. What do you conclude? Explain the differences, if any, between these findings and what you found in Question 2b.
ans: Using both deviance and Pearson residuals to assess Goodness of fit yielded p-values equivalent to zero, indicating that the null hypothesis can be rejected. The alternative hypothesis tells us that this model is not a good fit of the data. Alternatively, the test conducted in 2b supports that this is a good model
- Perform visual analytics for checking goodness of fit for this model and write your observations. Be sure to address the model assumptions. Only deviance residuals are required for this question.
ans: While they data do fit a poisson distribution, the model itself shows a poor fit when looking at residuals vs fitted values. This plot also reveals some of the islands being outliers, perhaps skewing the data and making it more difficult to create an accurate model. The histogram showing binned residual frequencies does not appear normally distributed. There may be a right tail. One of the islands has an extremely higher area size than all of the other islands, possibly causing skewness. It appears that a small number of islands are very far away from the others, possibly influencing parameters of proximity. If properly fitting a good model proves challenging, it may be that the data itself requires more cleaning, or the data is not even useful for this purpose of making predictions.
- Calculate the dispersion parameter for this model. Is this an overdispersed model?
ans: Overdispersion takes place when the variability of the rate estimates is larger than would be implied by a Poisson model. Overdispersion parameter is calculated by dividing the deviance, or the sum of squared deviance residuals, by the degrees of freedom, n-p-1. The dispersion value calculated here is \(29.86857\), which is much higher than 2, indicating overdispersion of the model
exp(0.0001568) #1.000157
[1] 1.000157
Question 4: Fitting a Count per Area Model
Let’s create a rate based poisson regression model for the same dataset. Now the response will be density of species (number of species/km^2). So the exposure in this case will be Area. Call this model2. Fit the model and display the summary of the model.
- Write down the equation for the estimated number of species per square kilometer given the predicting variables.
ans:\(log(Species/Area) = 2.155 -0.0029656\times Elevation - 0.0167442\times Nearest - 0.0010783\times Scruz + 0.0001568\times Adjacent\)
- Provide a meaningful interpretation for the coefficient of Adjacent.
ans: Holding all else constant, for each \(km^2\) increase in the area of the adjacent island, the number of species goes up by a factor of \(1.000\) (=exp(0.0001568)
). It can also be said that the ratio between [expected count of plant species per island for one meter increase in elevation] to [expected count of species on island for no increase in elevation] is \(1.000\).. _ (c) Is information about the nearby island significant given the other variables? Compare model2 with a model containing only Elevation and Scruz.
ans: The wald.test()
function was used to compare model two to one only containing Elevation and Scruz parameters. The test gave a chi-square value of 183.4, and a small p-value reported as equal to zero. Because the p-value is low, we reject the null hypothesis
- Has your goodness of fit been affected? Repeat the tests, plots, and dispersion parameter calculation you performed in Question 3 with model2.
ans: This second model does not fit as well as the first. While both appear to have a poor goodness of fit, visual diagnostics seem to indicate that model2 does a worse job of capturing and appropriately modeling the data for making a prediction.
- Overall, would you say model2 is a good-fitting model? If so, why? If not, what would you suggest to improve the fit and why? Note, we are not asking you to spend hours finding the best possible model but to offer plausible suggestions along with your reasoning.
ans: Model2 is not a good fitting model. Goodness of fits tests and multiple instances of outliers indicate that the model is not fit well, and the data itself coming in may be of low quality. I created four alternative models below, with modified predictors and offsets. I compared AIC among the four models. The first two, model3 and model4, have more or less the same AIC value (about 900), and both offset the model by Elevation of the island. The other two models have much higher AIC values (>1700)and also both offset the response with Area of the island. Perhaps using Area in this way makes the model fit more poorly to the data.
#q4e
model3 <- glm(data=df,Species~Area+Nearest+Scruz+Adjacent+offset(log(Elevation)),poisson)
model4 <- glm(data=df,Species~Area+Scruz + Adjacent + offset(log(Elevation)),poisson)
model5 <- glm(data=df,Species~Elevation + Scruz + offset(log(Area)),poisson)
model6 <- glm(data=df,Species~Elevation + Nearest + Adjacent + offset(log(Area)),poisson)
cat("AIC values for alternative models:\n")
AIC values for alternative models:
model3$aic;model4$aic;model5$aic;model6$aic
[1] 898.1268
[1] 904.7802
[1] 1923.005
[1] 1736.024
#q5
newdata <- data.frame("Scruz"=110,"Area"=25,"Elevation"=100,"Nearest"=21.1, "Adjacent"=.57)
q5a <- predict(model1, newdata = newdata, type="response")
q5b <- predict(model2, newdata = newdata, type="response")
q5a;q5b
Question 5: Prediction
Suppose you’ve found a new island 110 km from Santa Cruz with an area of 25 km^2 and an elevation of 100 m. Its nearest island is 21.1 km away with an area of 0.57 km^2.
- Predict the number of plant species on this new island using model1.
a: Using model 1, there are predicted to be \(21.16\) plant species on this new island.
- Predict the number of plant species using model2.
a: using model 2, there are predicted to be \(100.06\) plant species on this new island.
- Comment on how your predictions compare.
a: Model1 predicts about 21 species on the new island, while model2 predicts nearly five times that value at about 100 species present on the new island. This is a very large disparity, and appears to be caused by offsetting the response variable by area of island. It is worth noting that this data set only has an \(n\) of \(30\), which is a considerably low sample size for performing poisson regression. This makes for a greater challenge in fitting an appropriate and meaningful model for predicting plant species on islands.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgQmFja2dyb3VuZDogIyMjDQoNCkZvciAzMCBHYWxhcGFnb3MgSXNsYW5kcywgdGhlIGRhdGEgY29uc2lzdCBvZiB0aGUgbnVtYmVyIG9mIHBsYW50IHNwZWNpZXMgZm91bmQgb24gZWFjaCBpc2xhbmQgYW5kIHRoZSBudW1iZXIgdGhhdCBhcmUgZW5kZW1pYyB0byB0aGF0IGlzbGFuZC4gV2UgYWxzbyBoYXZlIGZpdmUgZ2VvZ3JhcGhpYyB2YXJpYWJsZXMgZm9yIGVhY2ggaXNsYW5kLiBUaGUgZGF0YSB3YXMgcHJlc2VudGVkIGJ5IEpvaG5zb24gYW5kIFJhdmVuICgxOTczKSBhbmQgYWxzbyBhcHBlYXIgaW4gV2Vpc2JlcmcgKDIwMDUpLg0KDQpXaGlsZSB0aGUgZGF0YXNldCBjb250YWlucyBzZXZlbiB2YXJpYWJsZXMsIHdlIGFyZSBpbnRlcmVzdGVkIG9ubHkgaW4gIHRoZSBmb2xsb3dpbmcgc2l4Og0KDQpTcGVjaWVzOiB0aGUgbnVtYmVyIG9mIHBsYW50IHNwZWNpZXMgZm91bmQgb24gdGhlIGlzbGFuZA0KQXJlYTogdGhlIGFyZWEgb2YgdGhlIGlzbGFuZCAoa21eMikNCkVsZXZhdGlvbjogdGhlIGhpZ2hlc3QgZWxldmF0aW9uIG9mIHRoZSBpc2xhbmQgKG0pDQpOZWFyZXN0OiB0aGUgZGlzdGFuY2UgZnJvbSB0aGUgbmVhcmVzdCBpc2xhbmQgKGttKQ0KU2NydXo6IHRoZSBkaXN0YW5jZSBmcm9tIFNhbnRhIENydXogaXNsYW5kIChrbSkNCkFkamFjZW50OiB0aGUgYXJlYSBvZiB0aGUgYWRqYWNlbnQgaXNsYW5kIChrbV4yKQ0KDQpQbGVhc2UgaW5zdGFsbCB0aGUgcGFja2FnZSBmYXJhd2F5LCBsb2FkIHRoZSBkYXRhc2V0IGdhbGEsIGFuZCBkcm9wIHRoZSB1bm5lY2Vzc2FyeSBzZWNvbmQgY29sdW1uIHRoYXQgaXMgRW5kZW1pY3M6DQpgYGB7ciwgY29tbWVudD1OQSwgcmVzdWx0cz0iaG9sZCJ9DQpyZXF1aXJlKGZhcmF3YXkpDQpkYXRhKGdhbGEpDQpteWRhdGEgPC0gZ2FsYQ0KZGYgPC0gbXlkYXRhWy0yXQ0KYGBgDQoNCmBgYHtyLCBjb21tZW50PU5BLCByZXN1bHRzPSJob2xkIn0NCiNxMSMNCmxpYnJhcnkoanRvb2xzKQ0KDQptb2RlbDEgPC0gZ2xtKGRhdGE9ZGYsU3BlY2llc34uLCBmYW1pbHk9InBvaXNzb24iLCkNCnN1bW1hcnkobW9kZWwxKQ0KDQpleHAoMC4wMDM1NDA2KSANCmV4cCgwLjAwNTcwOTQpIA0KDQptb2RlbDENCmBgYA0KIyMjIyBRdWVzdGlvbiAxOiBGaXR0aW5nIHRoZSBNb2RlbCAjIyMjDQoNCkZpdCBhIHBvaXNzb24gcmVncmVzc2lvbiBtb2RlbCB1c2luZyB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgYXMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGFuZCBhbGwgb3RoZXIgdmFyaWFibGVzIGFzIHByZWRpY3RvcnMuIENhbGwgaXQgbW9kZWwxLg0KDQooYSkgRGlzcGxheSB0aGUgc3VtbWFyeSBvZiBtb2RlbDEuIFdoYXQgYXJlIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGFuZCBlc3RpbWF0ZXM/DQoNCl9hbnM6IEVsZXZhdGlvbjogMC4wMDM1NDA2IHwgQXJlYTogLTAuMDAwNTc5OSB8IE5lYXJlc3Q6IDAuMDA4ODI1NiB8IFNjcnV6OiAtMC4wMDU3MDk0IHwgQWRqYWNlbnQ6IC0wLjAwMDY2MzBfICANCg0KKGIpIFdyaXRlIGRvd24gdGhlIGVxdWF0aW9uIGZvciB0aGUgZXN0aW1hdGVkIG51bWJlciBvZiBzcGVjaWVzIGdpdmVuIHRoZSBwcmVkaWN0aW5nIHZhcmlhYmxlcy4NCg0KX2FuczpfICRMb2coU3BlY2llcykgPSAzLjE1NSAtICgwLjAwMDU3OTkgXHRpbWVzIEFyZWEpICsgKDAuMDAzNTQwNlx0aW1lcyBFbGV2YXRpb24pICsgKDAuMDA4ODI1Nlx0aW1lcyBOZWFyZXN0KSAtICgwLjAwNTcwOTRcdGltZXMgU2NydXopIC0gKDAuMDAwNjYzMFx0aW1lcyBBZGphY2VudCkkDQoNCihjKSBQcm92aWRlIG1lYW5pbmdmdWwgaW50ZXJwcmV0YXRpb25zIGZvciB0aGUgY29lZmZpY2llbnRzIG9mIEVsZXZhdGlvbiBhbmQgU2NydXouDQoNCl9hbnM6IEhvbGRpbmcgYWxsIGVsc2UgY29uc3RhbnQsIGZvciBlYWNoIG1ldGVyIGluY3JlYXNlIGluIHRoZSBlbGV2YXRpb24gb2YgYW4gaXNsYW5kLCB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgZ29lcyB1cCBieSBhIGZhY3RvciBvZiAkMS4wMDM1JCAoPWBleHAoMC4wMDM1NDA2KWApLiBJdCBjYW4gYWxzbyBiZSBzYWlkIHRoYXQgdGhlIHJhdGlvIGJldHdlZW4gW2V4cGVjdGVkIGNvdW50IG9mIHBsYW50IHNwZWNpZXMgcGVyIGlzbGFuZCBmb3Igb25lIG1ldGVyIGluY3JlYXNlIGluIGVsZXZhdGlvbl0gdG8gW2V4cGVjdGVkIGNvdW50IG9mIHNwZWNpZXMgb24gaXNsYW5kIGZvciBubyBpbmNyZWFzZSBpbiBlbGV2YXRpb25dIGlzICQxLjAwMzUkLl8gDQoNCl9Ib2xkaW5nIGFsbCBlbHNlIGNvbnN0YW50IGZvciBlYWNoIGtpbG9tZXRlciBpbmNyZWFzZSBpbiBkaXN0YW5jZSB0byBzYW50YSBjcnV6LCB0aGUgbnVtYmVyIG9mIHBsYW50IHNwZWNpZXMgZ29lcyBkb3duIGJ5IGEgZmFjdG9yIG9mICQxLjAwNTckICg9YGV4cCgwLjAwNTcwOTQpYCkuIFNpbWlsYXJseSwgdGhlIHJhdGlvIGJldHdlZW4gW2V4cGVjdGVkIGNvdW50IG9mIHBsYW50IHNwZWNpZXMgcGVyIGlzbGFuZCBmb3Igb25lIGttIGluY3JlYXNlIGluIGRpc3RhbmNlIHRvIFNhbnRhIENydXpdIHRvIFtleHBlY3RlZCBjb3VudCBvZiBzcGVjaWVzIG9uIGlzbGFuZCBmb3Igbm8gaW5jcmVhc2UgaW4gZGlzdGFuY2UgdG8gU2FudGEgQ3J1el0gaXMgJDEuMDA1NyQuXyANCiANCg0KYGBge3IsIGNvbW1lbnQ9TkEsIHJlc3VsdHM9ImhvbGQifQ0KI3EyDQojYQ0KY29uZmludChtb2RlbDEsIGxldmVsPS45KQ0KDQojYg0KcGMxIDwtIDM1MTAuNy03MTYuODUNCnBjMiA8LTI5LTI0DQoxLXBjaGlzcShwYzEscGMyKQ0KYGBgDQojIyMjIFF1ZXN0aW9uIDI6IEluZmVyZW5jZSAjIyMjDQoNCihhKSBVc2luZyBtb2RlbDEsIGZpbmQgYSA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIGNvZWZmaWNpZW50IGZvciBOZWFyZXN0Lg0KX2FuczogV2l0aCAkOTAgXCUkIGNvbmZpZGVuY2UsIHRoZSB0cnVlIHZhbHVlIG9mIHRoZSBjb2VmZmljaWVudCBmb3IgTmVhcmVzdCBsaWVzIHdpdGhpbiB0aGUgcmFuZ2UgJCgwLjAwNTgwOTc0NzcsIDAuMDExODAyMDE0MykkXw0KDQooYikgSXMgbW9kZWwxIHNpZ25pZmljYW50IG92ZXJhbGw/IEhvdyBkbyB5b3UgY29tZSB0byB5b3VyIGNvbmNsdXNpb24/DQoNCl9hbnM6IFllcyBpdCBpcyBzaWduaWZpY2FudDsgSSB1c2VkIHRoZSBwY2hpc3EgZnVuY3Rpb24gKHN1YnRyYWN0aW5nIHJlc2lkdWFsIGZyb20gbnVsbCB2YWx1ZXMpIHRvIGZpbmQgdGhlIHAtdmFsdWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBjaGkgc3F1YXJlIHRlc3QgZm9yIHRoaXMgbW9kZWwuIFRoZSB2YWx1ZSB3YXMgc28gc21hbGwgdGhhdCBpdCBpcyByZXBvcnRlZCBhcyBlcXVpdmFsZW50IHRvIHplcm8sIG1lYW5pbmcgdGhlIG51bGwgaHlwb3RoZXNpcyBjYW4gYmUgcmVqZWN0ZWQuXw0KDQooYykgV2hpY2ggdmFyaWFibGVzIGFyZSBzaWduaWZpY2FudGx5IG5vbnplcm8gYXQgdGhlIDAuMDEgc2lnbmlmaWNhbmNlIGxldmVsPyBXaGljaCBhcmUgc2lnbmlmaWNhbnRseSBwb3NpdGl2ZT8gV2h5Pw0KDQpfYW5zOiBFbGV2YXRpb24gYW5kIE5lYXJlc3QgYXJlIHNpZ25pZmljYW50bHkgcG9zaXRpdmUgYmVjYXVzZSB0aGVpciBwLXZhbHVlIGlzIGxlc3MgdGhhbiAwLjAwNSwgd2hpY2ggaXMgdGhlIHAtdmFsdWUgb2YgMC4wMSBkaXZpZGVkIGJ5IHR3bywgYW5kIHRoZWlyIGNvZWZmaWNpZW50IGlzIGEgcG9zaXRpdmUgbnVtYmVyLiBBbGwgcHJlZGljdG9ycyAoTmVhcmVzdCwgQXJlYSwgRWxldmF0aW9uLCBTY3J1eiwgQWRqYWNlbnQpIGFyZSBzaWduaWZpY2FudGx5IG5vbnplcm8gYXQgdGhlIDAuMDEgc2lnbmlmaWNhbmNlIGxldmVsIGJlY2F1c2UgdGhlaXIgcC12YWx1ZXMgYXJlIGFsbCBsZXNzIHRoYW4gMC4wMS5fDQoNCmBgYHtyLCBjb21tZW50PU5BLCByZXN1bHRzPSJob2xkIn0NCiNxMyMNCiNsaWJyYXJ5KHZjZCkNCiNsaWJyYXJ5KGNhcikNCiNsaWJyYXJ5KGdncGxvdDIpDQoNCiNhDQojIyBUZXN0IGZvciBHT0Y6IFVzaW5nIGRldmlhbmNlIHJlc2lkdWFscw0KZGV2aWFuY2VzMiA9IHJlc2lkdWFscyhtb2RlbDEsdHlwZT0iZGV2aWFuY2UiKQ0KZGV2LnR2YWx1ZSA9IHN1bShkZXZpYW5jZXMyXjIpDQpjKGRldi50dmFsdWUsIDEtcGNoaXNxKGRldi50dmFsdWUsMjQpKQ0KDQojIyBUZXN0IGZvciBHT0Y6IFVzaW5nIFBlcnNvbiByZXNpZHVhbHMNCnBlYXJyZXMyID0gcmVzaWR1YWxzKG1vZGVsMSx0eXBlPSJwZWFyc29uIikNCnBlYXJzb24udHZhbHVlID0gc3VtKHBlYXJyZXMyXjIpDQpjKHBlYXJzb24udHZhbHVlLCAxLXBjaGlzcShwZWFyc29uLnR2YWx1ZSwyNCkpDQoNCiNiDQoNCiNyZXMgdnMgZml0dGVkDQpwbG90KG1vZGVsMSwgd2hpY2g9MSkNCg0KI2ZpdCB0byBkaXN0cmlidXRpb24NCmRpc3RwbG90KGRmJFNwZWNpZXMsdHlwZT0icG9pc3NvbiIpDQoNCiNxcQ0KcmVzIDwtIHJlc2lkdWFscyhtb2RlbDEsdHlwZT0iZGV2aWFuY2UiKQ0KcXFub3JtKHJlcykNCnFxbGluZShyZXMpDQoNCiNoaXN0DQpoaXN0KHJlcyxicmVha3M9OCxkZW5zaXR5PTE1LGNvbD0ic2FsbW9uIix4bGFiPSJTdGFuZGFyZCByZXNpZHVhbHMiLCBtYWluPSJGcmVxdWVuY3kgb2YgUmVzaWR1YWxzIE1vZGVsMSIpDQoNCiNwcmVkIHZzIHJlc2lkDQpmb3IgKGkgaW4gMjo2KSB7DQogIHBsb3QoZGZbLGldLCByZXMsIHlsYWIgPSAiRGV2aWFuY2UiLHhsYWIgPSBuYW1lcyhkZltpXSkpDQogIGFibGluZSgwLDAsY29sPSJzYWxtb24iLGx3ZD0yKQ0KfQ0KDQojbG9nIHNlcGMgdnMgcHJlZA0KZm9yIChpIGluIDI6Nikgew0KICBwbG90KGxvZyhkZiRTcGVjaWVzKSwgZGZbLGldLCB5bGFiID0gImxvZyhTcGVjaWVzKSIseGxhYiA9IG5hbWVzKGRmW2ldKSkNCn0NCg0KI21pZ2h0IG1ha2UgcHJldHRpZXIgcGxvdHMgaW4gZ2dwbG90IGlmIGhhdmUgZnJlZSB0aW1lDQojZ2dwbG90KGRmLCBhZXMoeCA9IFNwZWNpZXMsIHkgPSByZXMsIGNvbG9yID0gQXJlYSkpICsNCiMgICAgZ2VvbV9wb2ludChwY2ggPSAyMCwgc2l6ZSA9IDMpICsNCiMgICAgbGFicyh4ID0gIiIpIA0KDQojYw0KZGlzcCA8LSBkZXYudHZhbHVlLygzMC01LTEpDQpkaXNwDQpgYGANCiMjIyMgUXVlc3Rpb24gMzogR29vZG5lc3Mgb2YgZml0ICMjIyMNCg0KKGEpIFBlcmZvcm0gZ29vZG5lc3Mgb2YgZml0IGh5cG90aGVzaXMgdGVzdHMgdXNpbmcgYm90aCBkZXZpYW5jZSBhbmQgUGVhcnNvbiByZXNpZHVhbHMuIFdoYXQgZG8geW91IGNvbmNsdWRlPyBFeHBsYWluIHRoZSBkaWZmZXJlbmNlcywgaWYgYW55LCBiZXR3ZWVuIHRoZXNlIGZpbmRpbmdzIGFuZCB3aGF0IHlvdSBmb3VuZCBpbiBRdWVzdGlvbiAyYi4NCg0KX2FuczogVXNpbmcgYm90aCBkZXZpYW5jZSBhbmQgUGVhcnNvbiByZXNpZHVhbHMgdG8gYXNzZXNzIEdvb2RuZXNzIG9mIGZpdCB5aWVsZGVkIHAtdmFsdWVzIGVxdWl2YWxlbnQgdG8gemVybywgaW5kaWNhdGluZyB0aGF0IHRoZSBudWxsIGh5cG90aGVzaXMgY2FuIGJlIHJlamVjdGVkLiBUaGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyB0ZWxscyB1cyB0aGF0IHRoaXMgbW9kZWwgaXMgbm90IGEgZ29vZCBmaXQgb2YgdGhlIGRhdGEuIEFsdGVybmF0aXZlbHksIHRoZSB0ZXN0IGNvbmR1Y3RlZCBpbiAyYiBzdXBwb3J0cyB0aGF0IHRoaXMgaXMgYSBnb29kIG1vZGVsXyANCg0KKGIpIFBlcmZvcm0gdmlzdWFsIGFuYWx5dGljcyBmb3IgY2hlY2tpbmcgZ29vZG5lc3Mgb2YgZml0IGZvciB0aGlzIG1vZGVsIGFuZCB3cml0ZSB5b3VyIG9ic2VydmF0aW9ucy4gQmUgc3VyZSB0byBhZGRyZXNzIHRoZSBtb2RlbCBhc3N1bXB0aW9ucy4gT25seSBkZXZpYW5jZSByZXNpZHVhbHMgYXJlIHJlcXVpcmVkIGZvciB0aGlzIHF1ZXN0aW9uLg0KDQpfYW5zOiBXaGlsZSB0aGV5IGRhdGEgZG8gZml0IGEgcG9pc3NvbiBkaXN0cmlidXRpb24sIHRoZSBtb2RlbCBpdHNlbGYgc2hvd3MgYSBwb29yIGZpdCB3aGVuIGxvb2tpbmcgYXQgcmVzaWR1YWxzIHZzIGZpdHRlZCB2YWx1ZXMuIFRoaXMgcGxvdCBhbHNvIHJldmVhbHMgc29tZSBvZiB0aGUgaXNsYW5kcyBiZWluZyBvdXRsaWVycywgcGVyaGFwcyBza2V3aW5nIHRoZSBkYXRhIGFuZCBtYWtpbmcgaXQgbW9yZSBkaWZmaWN1bHQgdG8gY3JlYXRlIGFuIGFjY3VyYXRlIG1vZGVsLiBUaGUgaGlzdG9ncmFtIHNob3dpbmcgYmlubmVkIHJlc2lkdWFsIGZyZXF1ZW5jaWVzIGRvZXMgbm90IGFwcGVhciBub3JtYWxseSBkaXN0cmlidXRlZC4gVGhlcmUgbWF5IGJlIGEgcmlnaHQgdGFpbC4gT25lIG9mIHRoZSBpc2xhbmRzIGhhcyBhbiBleHRyZW1lbHkgaGlnaGVyIGFyZWEgc2l6ZSB0aGFuIGFsbCBvZiB0aGUgb3RoZXIgaXNsYW5kcywgcG9zc2libHkgY2F1c2luZyBza2V3bmVzcy4gSXQgYXBwZWFycyB0aGF0IGEgc21hbGwgbnVtYmVyIG9mIGlzbGFuZHMgYXJlIHZlcnkgZmFyIGF3YXkgZnJvbSB0aGUgb3RoZXJzLCBwb3NzaWJseSBpbmZsdWVuY2luZyBwYXJhbWV0ZXJzIG9mIHByb3hpbWl0eS4gSWYgcHJvcGVybHkgZml0dGluZyBhIGdvb2QgbW9kZWwgcHJvdmVzIGNoYWxsZW5naW5nLCBpdCBtYXkgYmUgdGhhdCB0aGUgZGF0YSBpdHNlbGYgcmVxdWlyZXMgbW9yZSBjbGVhbmluZywgb3IgdGhlIGRhdGEgaXMgbm90IGV2ZW4gdXNlZnVsIGZvciB0aGlzIHB1cnBvc2Ugb2YgbWFraW5nIHByZWRpY3Rpb25zLl8gDQoNCihjKSBDYWxjdWxhdGUgdGhlIGRpc3BlcnNpb24gcGFyYW1ldGVyIGZvciB0aGlzIG1vZGVsLiBJcyB0aGlzIGFuIG92ZXJkaXNwZXJzZWQgbW9kZWw/DQoNCl9hbnM6IE92ZXJkaXNwZXJzaW9uIHRha2VzIHBsYWNlIHdoZW4gdGhlIHZhcmlhYmlsaXR5IG9mIHRoZSByYXRlIGVzdGltYXRlcyBpcyBsYXJnZXIgdGhhbiB3b3VsZCBiZSBpbXBsaWVkIGJ5IGEgUG9pc3NvbiBtb2RlbC4gT3ZlcmRpc3BlcnNpb24gcGFyYW1ldGVyIGlzIGNhbGN1bGF0ZWQgYnkgZGl2aWRpbmcgdGhlIGRldmlhbmNlLCBvciB0aGUgc3VtIG9mIHNxdWFyZWQgZGV2aWFuY2UgcmVzaWR1YWxzLCBieSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tLCBuLXAtMS4gVGhlIGRpc3BlcnNpb24gdmFsdWUgY2FsY3VsYXRlZCBoZXJlIGlzICQyOS44Njg1NyQsIHdoaWNoIGlzIG11Y2ggaGlnaGVyIHRoYW4gMiwgaW5kaWNhdGluZyBvdmVyZGlzcGVyc2lvbiBvZiB0aGUgbW9kZWxfIA0KDQpgYGB7cn0NCiNxNA0KI2xpYnJhcnkoYW9kKQ0KI2F0dGFjaChkZikNCm1vZGVsMiA8LSBnbG0oZGF0YT1kZixTcGVjaWVzfkVsZXZhdGlvbitOZWFyZXN0K1NjcnV6K0FkamFjZW50KyBvZmZzZXQobG9nKEFyZWEpKSxwb2lzc29uKQ0Kc3VtbWFyeShtb2RlbDIpDQoNCmV4cCgwLjAwMDE1NjgpICMxLjAwMDE1Nw0KDQojYw0Kd2FsZC50ZXN0KGI9Y29lZihtb2RlbDIpLCBTaWdtYT12Y292KG1vZGVsMiksIFRlcm1zPTM6NCkNCg0KI2QNCiMjIFRlc3QgZm9yIEdPRjogVXNpbmcgZGV2aWFuY2UgcmVzaWR1YWxzDQpkZXZpYW5jZXMyID0gcmVzaWR1YWxzKG1vZGVsMix0eXBlPSJkZXZpYW5jZSIpDQpkZXYudHZhbHVlID0gc3VtKGRldmlhbmNlczJeMikNCmMoZGV2LnR2YWx1ZSwgMS1wY2hpc3EoZGV2LnR2YWx1ZSwyNSkpDQoNCiMjIFRlc3QgZm9yIEdPRjogVXNpbmcgUGVhcnNvbiByZXNpZHVhbHMNCnBlYXJyZXMyID0gcmVzaWR1YWxzKG1vZGVsMix0eXBlPSJwZWFyc29uIikNCnBlYXJzb24udHZhbHVlID0gc3VtKHBlYXJyZXMyXjIpDQpjKHBlYXJzb24udHZhbHVlLCAxLXBjaGlzcShwZWFyc29uLnR2YWx1ZSwyNSkpDQoNCiNyZXMgdnMgZml0dGVkDQpwbG90KG1vZGVsMiwgd2hpY2g9MSkNCiNxcQ0KcmVzIDwtIHJlc2lkdWFscyhtb2RlbDIsdHlwZT0iZGV2aWFuY2UiKQ0KcXFub3JtKHJlcykNCnFxbGluZShyZXMpDQojaGlzdA0KaGlzdChyZXMsYnJlYWtzPTgsZGVuc2l0eT0xNSxjb2w9ImNhZGV0Ymx1ZTMiLHhsYWI9IlN0YW5kYXJkIHJlc2lkdWFscyIsIG1haW49IkZyZXF1ZW5jeSBvZiBSZXNpZHVhbHMgTW9kZWwyIikNCg0KDQojcHJlZCB2cyByZXNpZA0KZm9yIChpIGluIDI6Nikgew0KICBwbG90KGRmWyxpXSwgcmVzLCB5bGFiID0gIkRldmlhbmNlIix4bGFiID0gbmFtZXMoZGZbaV0pKQ0KICBhYmxpbmUoMCwwLGNvbD0iY2FkZXRibHVlMiIsbHdkPTIpDQp9DQojbG9nIHNlcGMgdnMgcHJlZA0KZm9yIChpIGluIDI6Nikgew0KICBwbG90KGxvZyhkZiRTcGVjaWVzKSwgZGZbLGldLCB5bGFiID0gImxvZyhTcGVjaWVzKSIseGxhYiA9IG5hbWVzKGRmW2ldKSkNCn0NCg0KI2Rpc3BlcnNpb24NCmRpc3AgPC0gZGV2LnR2YWx1ZS8oMzAtNC0xKQ0KZGlzcA0KYGBgDQojIyMjIFF1ZXN0aW9uIDQ6IEZpdHRpbmcgYSBDb3VudCBwZXIgQXJlYSBNb2RlbCAjIyMjDQoNCkxldCdzIGNyZWF0ZSBhIHJhdGUgYmFzZWQgcG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsIGZvciB0aGUgc2FtZSBkYXRhc2V0LiBOb3cgdGhlIHJlc3BvbnNlIHdpbGwgYmUgZGVuc2l0eSBvZiBzcGVjaWVzIChudW1iZXIgb2Ygc3BlY2llcy9rbV4yKS4gU28gdGhlIGV4cG9zdXJlIGluIHRoaXMgY2FzZSB3aWxsIGJlIEFyZWEuIENhbGwgdGhpcyBtb2RlbDIuIEZpdCB0aGUgbW9kZWwgYW5kIGRpc3BsYXkgdGhlIHN1bW1hcnkgb2YgdGhlIG1vZGVsLg0KDQooYSkgV3JpdGUgZG93biB0aGUgZXF1YXRpb24gZm9yIHRoZSBlc3RpbWF0ZWQgbnVtYmVyIG9mIHNwZWNpZXMgcGVyIHNxdWFyZSBraWxvbWV0ZXIgZ2l2ZW4gdGhlIHByZWRpY3RpbmcgdmFyaWFibGVzLg0KDQpfYW5zOl8kbG9nKFNwZWNpZXMvQXJlYSkgPSAyLjE1NSAtMC4wMDI5NjU2XHRpbWVzIEVsZXZhdGlvbiAtIDAuMDE2NzQ0Mlx0aW1lcyBOZWFyZXN0IC0gMC4wMDEwNzgzXHRpbWVzIFNjcnV6ICsgMC4wMDAxNTY4XHRpbWVzIEFkamFjZW50JA0KDQooYikgUHJvdmlkZSBhIG1lYW5pbmdmdWwgaW50ZXJwcmV0YXRpb24gZm9yIHRoZSBjb2VmZmljaWVudCBvZiBBZGphY2VudC4NCg0KX2FuczogSG9sZGluZyBhbGwgZWxzZSBjb25zdGFudCwgZm9yIGVhY2ggJGttXjIkIGluY3JlYXNlIGluIHRoZSBhcmVhIG9mIHRoZSBhZGphY2VudCBpc2xhbmQsIHRoZSBudW1iZXIgb2Ygc3BlY2llcyBnb2VzIHVwIGJ5IGEgZmFjdG9yIG9mICQxLjAwMCQgKD1gZXhwKDAuMDAwMTU2OClgKS4gSXQgY2FuIGFsc28gYmUgc2FpZCB0aGF0IHRoZSByYXRpbyBiZXR3ZWVuIFtleHBlY3RlZCBjb3VudCBvZiBwbGFudCBzcGVjaWVzIHBlciBpc2xhbmQgZm9yIG9uZSBtZXRlciBpbmNyZWFzZSBpbiBlbGV2YXRpb25dIHRvIFtleHBlY3RlZCBjb3VudCBvZiBzcGVjaWVzIG9uIGlzbGFuZCBmb3Igbm8gaW5jcmVhc2UgaW4gZWxldmF0aW9uXSBpcyAkMS4wMDAkLi5fIA0KXw0KKGMpIElzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBuZWFyYnkgaXNsYW5kIHNpZ25pZmljYW50IGdpdmVuIHRoZSBvdGhlciB2YXJpYWJsZXM/IENvbXBhcmUgbW9kZWwyIHdpdGggYSBtb2RlbCBjb250YWluaW5nIG9ubHkgRWxldmF0aW9uIGFuZCBTY3J1ei4NCg0KX2FuczogVGhlIGB3YWxkLnRlc3QoKWAgZnVuY3Rpb24gd2FzIHVzZWQgdG8gY29tcGFyZSBtb2RlbCB0d28gdG8gb25lIG9ubHkgY29udGFpbmluZyBFbGV2YXRpb24gYW5kIFNjcnV6IHBhcmFtZXRlcnMuIFRoZSB0ZXN0IGdhdmUgYSBjaGktc3F1YXJlIHZhbHVlIG9mIDE4My40LCBhbmQgYSBzbWFsbCBwLXZhbHVlIHJlcG9ydGVkIGFzIGVxdWFsIHRvIHplcm8uIEJlY2F1c2UgdGhlIHAtdmFsdWUgaXMgbG93LCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpc18NCg0KKGQpIEhhcyB5b3VyIGdvb2RuZXNzIG9mIGZpdCBiZWVuIGFmZmVjdGVkPyBSZXBlYXQgdGhlIHRlc3RzLCBwbG90cywgYW5kIGRpc3BlcnNpb24gcGFyYW1ldGVyIGNhbGN1bGF0aW9uIHlvdSBwZXJmb3JtZWQgaW4gUXVlc3Rpb24gMyB3aXRoIG1vZGVsMi4NCg0KX2FuczogVGhpcyBzZWNvbmQgbW9kZWwgZG9lcyBub3QgZml0IGFzIHdlbGwgYXMgdGhlIGZpcnN0LiBXaGlsZSBib3RoIGFwcGVhciB0byBoYXZlIGEgcG9vciBnb29kbmVzcyBvZiBmaXQsIHZpc3VhbCBkaWFnbm9zdGljcyBzZWVtIHRvIGluZGljYXRlIHRoYXQgbW9kZWwyIGRvZXMgYSB3b3JzZSBqb2Igb2YgY2FwdHVyaW5nIGFuZCBhcHByb3ByaWF0ZWx5IG1vZGVsaW5nIHRoZSBkYXRhIGZvciBtYWtpbmcgYSBwcmVkaWN0aW9uLl8gDQoNCihlKSBPdmVyYWxsLCB3b3VsZCB5b3Ugc2F5IG1vZGVsMiBpcyBhIGdvb2QtZml0dGluZyBtb2RlbD8gSWYgc28sIHdoeT8gSWYgbm90LCB3aGF0IHdvdWxkIHlvdSBzdWdnZXN0IHRvIGltcHJvdmUgdGhlIGZpdCBhbmQgd2h5PyBOb3RlLCB3ZSBhcmUgbm90IGFza2luZyB5b3UgdG8gc3BlbmQgaG91cnMgZmluZGluZyB0aGUgYmVzdCBwb3NzaWJsZSBtb2RlbCBidXQgdG8gb2ZmZXIgcGxhdXNpYmxlIHN1Z2dlc3Rpb25zIGFsb25nIHdpdGggeW91ciByZWFzb25pbmcuDQoNCl9hbnM6IE1vZGVsMiBpcyBub3QgYSBnb29kIGZpdHRpbmcgbW9kZWwuIEdvb2RuZXNzIG9mIGZpdHMgdGVzdHMgYW5kIG11bHRpcGxlIGluc3RhbmNlcyBvZiBvdXRsaWVycyBpbmRpY2F0ZSB0aGF0IHRoZSBtb2RlbCBpcyBub3QgZml0IHdlbGwsIGFuZCB0aGUgZGF0YSBpdHNlbGYgY29taW5nIGluIG1heSBiZSBvZiBsb3cgcXVhbGl0eS4gSSBjcmVhdGVkIGZvdXIgYWx0ZXJuYXRpdmUgbW9kZWxzIGJlbG93LCB3aXRoIG1vZGlmaWVkIHByZWRpY3RvcnMgYW5kIG9mZnNldHMuIEkgY29tcGFyZWQgQUlDIGFtb25nIHRoZSBmb3VyIG1vZGVscy4gVGhlIGZpcnN0IHR3bywgbW9kZWwzIGFuZCBtb2RlbDQsIGhhdmUgbW9yZSBvciBsZXNzIHRoZSBzYW1lIEFJQyB2YWx1ZSAoYWJvdXQgOTAwKSwgYW5kIGJvdGggb2Zmc2V0IHRoZSBtb2RlbCBieSBFbGV2YXRpb24gb2YgdGhlIGlzbGFuZC4gVGhlIG90aGVyIHR3byBtb2RlbHMgaGF2ZSBtdWNoIGhpZ2hlciBBSUMgdmFsdWVzICg+MTcwMClhbmQgYWxzbyBib3RoIG9mZnNldCB0aGUgcmVzcG9uc2Ugd2l0aCBBcmVhIG9mIHRoZSBpc2xhbmQuIFBlcmhhcHMgdXNpbmcgQXJlYSBpbiB0aGlzIHdheSBtYWtlcyB0aGUgbW9kZWwgZml0IG1vcmUgcG9vcmx5IHRvIHRoZSBkYXRhLl8NCg0KYGBge3IsIHJlc3VsdHM9J2hvbGQnfQ0KI3E0ZQ0KbW9kZWwzIDwtIGdsbShkYXRhPWRmLFNwZWNpZXN+QXJlYStOZWFyZXN0K1NjcnV6K0FkamFjZW50K29mZnNldChsb2coRWxldmF0aW9uKSkscG9pc3NvbikNCm1vZGVsNCA8LSBnbG0oZGF0YT1kZixTcGVjaWVzfkFyZWErU2NydXogKyBBZGphY2VudCArIG9mZnNldChsb2coRWxldmF0aW9uKSkscG9pc3NvbikNCm1vZGVsNSA8LSBnbG0oZGF0YT1kZixTcGVjaWVzfkVsZXZhdGlvbiArIFNjcnV6ICsgb2Zmc2V0KGxvZyhBcmVhKSkscG9pc3NvbikNCm1vZGVsNiA8LSBnbG0oZGF0YT1kZixTcGVjaWVzfkVsZXZhdGlvbiArIE5lYXJlc3QgKyBBZGphY2VudCArIG9mZnNldChsb2coQXJlYSkpLHBvaXNzb24pDQoNCmNhdCgiQUlDIHZhbHVlcyBmb3IgYWx0ZXJuYXRpdmUgbW9kZWxzOlxuIikNCm1vZGVsMyRhaWM7bW9kZWw0JGFpYzttb2RlbDUkYWljO21vZGVsNiRhaWMNCmBgYA0KDQoNCg0KDQpgYGB7ciwgY29tbWVudD1OQSwgcmVzdWx0cz0iaG9sZCJ9DQojcTUNCm5ld2RhdGEgPC0gZGF0YS5mcmFtZSgiU2NydXoiPTExMCwiQXJlYSI9MjUsIkVsZXZhdGlvbiI9MTAwLCJOZWFyZXN0Ij0yMS4xLCAiQWRqYWNlbnQiPS41NykNCnE1YSA8LSBwcmVkaWN0KG1vZGVsMSwgbmV3ZGF0YSA9IG5ld2RhdGEsIHR5cGU9InJlc3BvbnNlIikNCnE1YiA8LSBwcmVkaWN0KG1vZGVsMiwgbmV3ZGF0YSA9IG5ld2RhdGEsIHR5cGU9InJlc3BvbnNlIikNCnE1YTtxNWINCmBgYA0KDQojIyMjIFF1ZXN0aW9uIDU6IFByZWRpY3Rpb24gIyMjIw0KDQpTdXBwb3NlIHlvdSd2ZSBmb3VuZCBhIG5ldyBpc2xhbmQgMTEwIGttIGZyb20gU2FudGEgQ3J1eiB3aXRoIGFuIGFyZWEgb2YgMjUga21eMiBhbmQgYW4gZWxldmF0aW9uIG9mIDEwMCBtLiBJdHMgbmVhcmVzdCBpc2xhbmQgaXMgMjEuMSBrbSBhd2F5IHdpdGggYW4gYXJlYSBvZiAwLjU3IGttXjIuDQoNCihhKSBQcmVkaWN0IHRoZSBudW1iZXIgb2YgcGxhbnQgc3BlY2llcyBvbiB0aGlzIG5ldyBpc2xhbmQgdXNpbmcgbW9kZWwxLg0KDQpfYTogVXNpbmcgbW9kZWwgMSwgdGhlcmUgYXJlIHByZWRpY3RlZCB0byBiZSAkMjEuMTYkIHBsYW50IHNwZWNpZXMgb24gdGhpcyBuZXcgaXNsYW5kLl8NCg0KKGIpIFByZWRpY3QgdGhlIG51bWJlciBvZiBwbGFudCBzcGVjaWVzIHVzaW5nIG1vZGVsMi4NCg0KX2E6IHVzaW5nIG1vZGVsIDIsIHRoZXJlIGFyZSBwcmVkaWN0ZWQgdG8gYmUgJDEwMC4wNiQgcGxhbnQgc3BlY2llcyBvbiB0aGlzIG5ldyBpc2xhbmQuXw0KDQooYykgQ29tbWVudCBvbiBob3cgeW91ciBwcmVkaWN0aW9ucyBjb21wYXJlLg0KDQpfYTogTW9kZWwxIHByZWRpY3RzIGFib3V0IDIxIHNwZWNpZXMgb24gdGhlIG5ldyBpc2xhbmQsIHdoaWxlIG1vZGVsMiBwcmVkaWN0cyBuZWFybHkgZml2ZSB0aW1lcyB0aGF0IHZhbHVlIGF0IGFib3V0IDEwMCBzcGVjaWVzIHByZXNlbnQgb24gdGhlIG5ldyBpc2xhbmQuIFRoaXMgaXMgYSB2ZXJ5IGxhcmdlIGRpc3Bhcml0eSwgYW5kIGFwcGVhcnMgdG8gYmUgY2F1c2VkIGJ5IG9mZnNldHRpbmcgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGJ5IGFyZWEgb2YgaXNsYW5kLiBJdCBpcyB3b3J0aCBub3RpbmcgdGhhdCB0aGlzIGRhdGEgc2V0IG9ubHkgaGFzIGFuICRuJCBvZiAkMzAkLCB3aGljaCBpcyBhIGNvbnNpZGVyYWJseSBsb3cgc2FtcGxlIHNpemUgZm9yIHBlcmZvcm1pbmcgcG9pc3NvbiByZWdyZXNzaW9uLiBUaGlzIG1ha2VzIGZvciBhIGdyZWF0ZXIgY2hhbGxlbmdlIGluIGZpdHRpbmcgYW4gYXBwcm9wcmlhdGUgYW5kIG1lYW5pbmdmdWwgbW9kZWwgZm9yIHByZWRpY3RpbmcgcGxhbnQgc3BlY2llcyBvbiBpc2xhbmRzLl8gDQoNCg0K