0.1 Introduction / Materials

The data shows color and phenolic measurements from three diffrent types of red wine Tempranillo, Graciano, and Cabernet Sauvignon and from times 1.5 to 26 months. In the description of the data it is not mentioned exactly how the data was collected but is from M. MOnagas, P.J. Martin-Alvarez, B. Bartolome, C. Gomez-Cordoves (2006). “Statistical Interpretaion of the Color Parameters of Red Wines in Function of their Phenolic Composition During Aging in Bottle,” European Food Research Technology, Vol/ 222, pp. 702-209.

WineType (categorical): Type of wine (1 = Tempranillo, 2 = Graciano, 3 = Cabernet Sauvignon). Months (continuous): Time points in months (1.5, 3, 7, 9, 12, 19.5, 26).

Colorimetric Indices (continuous): CI_abs: Color Intensity. PctYellow: Percentage of yellow color. PctRed: Percentage of red color. PctBlue: Percentage of blue color. PctdA: Percentage of pure red. Tint: Measure of hue.

CIELAB Variables (continuous): L: Lightness. C: Chroma. h: Hue angle. a: Red/green component. b*: Yellow/blue component.

Phenolic Concentrations (mg/L) (continuous): GLU: Glucosides. AC: Acetyl-Glucoside. CIN: Cinnamolyl Glucosides. PYRUVILICS: Piruvylics. VINYLICS: Vinylics. FLAVANOLS: Flavanols. FLAVONOLS: Flavonols. CINNAMICS: Cinnamics. BENZOICS: Benzoics.

One question we can answer from this dataset are How does the color of each wine change over time?

0.2 Methodology and Analysis

wine = read.csv("https://raw.githubusercontent.com/TylerBattaglini/STA-321/main/redwine_phenolics_color.csv")
pander(head(wine))
Table continues below
WineType Months CI_abs PctYellow PctRed PctBlue PctdA Tint
1 1.5 0.54 39.63 47.3 13.08 44.28 0.84
1 3 0.53 40.11 47.6 12.29 44.95 0.84
1 7 0.59 41.14 45.87 13 40.98 0.9
1 9 0.61 42.41 43.55 14.03 35.19 0.97
1 12 0.58 43.12 43.17 13.71 34.18 1
1 19.5 0.65 43.53 42.53 13.91 32.43 1.02
Table continues below
L_star C_star h_star a_star b_star GLU AC CIN
70.85 26.76 8.42 26.47 3.92 294 25 41.41
71.3 27.39 9.3 27.03 4.43 291.2 24.82 39.52
69.13 27.74 14.71 26.84 7.05 241.7 18.05 31.77
68.9 25.68 19.17 24.26 8.43 200.8 18.94 28.93
70.15 25.03 22.18 23.18 9.45 195.8 17.05 26.49
67.6 26.69 25.09 24.16 11.32 172.1 12.33 23.31
PYRUVILICS VINYLICS FLAVANOLS FLAVONOLS CINNAMICS BENZOICS
3.54 0.85 40.4 10.16 0.73 20.54
3.44 0.84 36.43 11.2 1.06 20.54
3.09 0.85 28.98 10.08 1.46 20.46
2.51 0.85 26.03 10.02 1.56 19.69
2.31 0.9 23.78 8.29 1.59 17.94
1.98 0.99 25.54 8.99 2.07 16.47
cor(wine[, c("PctYellow" , "PctRed" , "PctBlue" , "PctdA" , "Tint" , "L_star" , "C_star" , "h_star" , "a_star" , "b_star")])
           PctYellow     PctRed    PctBlue      PctdA       Tint     L_star
PctYellow  1.0000000 -0.9967832  0.9470656 -0.9971463  0.9971792  0.8891158
PctRed    -0.9967832  1.0000000 -0.9697443  0.9954049 -0.9925643 -0.8636488
PctBlue    0.9470656 -0.9697443  1.0000000 -0.9499914  0.9385418  0.7521327
PctdA     -0.9971463  0.9954049 -0.9499914  1.0000000 -0.9991542 -0.8777421
Tint       0.9971792 -0.9925643  0.9385418 -0.9991542  1.0000000  0.8895708
L_star     0.8891158 -0.8636488  0.7521327 -0.8777421  0.8895708  1.0000000
C_star    -0.9663385  0.9556817 -0.8854307  0.9578633 -0.9624469 -0.9713457
h_star     0.9202595 -0.9124449  0.8511498 -0.9369638  0.9369379  0.7443927
a_star    -0.9742234  0.9635554 -0.8928374  0.9675497 -0.9718639 -0.9661964
b_star     0.7636888 -0.7742779  0.7747803 -0.7779744  0.7680176  0.4480203
              C_star     h_star     a_star     b_star
PctYellow -0.9663385  0.9202595 -0.9742234  0.7636888
PctRed     0.9556817 -0.9124449  0.9635554 -0.7742779
PctBlue   -0.8854307  0.8511498 -0.8928374  0.7747803
PctdA      0.9578633 -0.9369638  0.9675497 -0.7779744
Tint      -0.9624469  0.9369379 -0.9718639  0.7680176
L_star    -0.9713457  0.7443927 -0.9661964  0.4480203
C_star     1.0000000 -0.8294239  0.9991101 -0.5982883
h_star    -0.8294239  1.0000000 -0.8519375  0.9019515
a_star     0.9991101 -0.8519375  1.0000000 -0.6274512
b_star    -0.5982883  0.9019515 -0.6274512  1.0000000
cor(wine[, c("GLU", "AC", "CIN", "PYRUVILICS", "VINYLICS", "FLAVANOLS", "FLAVONOLS", "CINNAMICS", "BENZOICS")])
                    GLU          AC         CIN   PYRUVILICS   VINYLICS
GLU         1.000000000  0.06646864  0.98425506 -0.006723363  0.4140117
AC          0.066468642  1.00000000 -0.05598275  0.933226840 -0.4080035
CIN         0.984255058 -0.05598275  1.00000000 -0.132460744  0.4483935
PYRUVILICS -0.006723363  0.93322684 -0.13246074  1.000000000 -0.4566231
VINYLICS    0.414011714 -0.40800350  0.44839346 -0.456623104  1.0000000
FLAVANOLS   0.114840758  0.36881975  0.10232394  0.391422113 -0.7746567
FLAVONOLS  -0.276634829  0.09139609 -0.26011469  0.158195327 -0.8936213
CINNAMICS  -0.197715491 -0.34981902 -0.15028912 -0.445395098  0.6741770
BENZOICS   -0.184364479 -0.25095925 -0.15279299 -0.103557707 -0.6970817
            FLAVANOLS   FLAVONOLS  CINNAMICS   BENZOICS
GLU         0.1148408 -0.27663483 -0.1977155 -0.1843645
AC          0.3688197  0.09139609 -0.3498190 -0.2509593
CIN         0.1023239 -0.26011469 -0.1502891 -0.1527930
PYRUVILICS  0.3914221  0.15819533 -0.4453951 -0.1035577
VINYLICS   -0.7746567 -0.89362126  0.6741770 -0.6970817
FLAVANOLS   1.0000000  0.85777860 -0.7266122  0.6674665
FLAVONOLS   0.8577786  1.00000000 -0.6295157  0.8783409
CINNAMICS  -0.7266122 -0.62951570  1.0000000 -0.6054222
BENZOICS    0.6674665  0.87834089 -0.6054222  1.0000000

We look at the correlation between varibales and see lots of correlation which could lead to multicollinearity. We should section these variables and group them.

wine_filtered <- wine %>%
  filter(WineType != 1) %>%
  select(-PctYellow, -PctRed, -PctBlue, -PctdA, -L_star, -C_star, -h_star, -a_star, -b_star, -Tint, -WineType) %>%
  mutate(Phenolics_Concentration = (GLU + AC + CIN + PYRUVILICS + VINYLICS + FLAVANOLS + FLAVONOLS + CINNAMICS + BENZOICS) / 9) %>%
  select(-GLU, -AC, -CIN, -PYRUVILICS, -VINYLICS, -FLAVANOLS, -FLAVONOLS, -CINNAMICS, -BENZOICS)
str(wine_filtered)
'data.frame':   14 obs. of  3 variables:
 $ Months                 : num  1.5 3 7 9 12 19.5 26 1.5 3 7 ...
 $ CI_abs                 : num  1.13 1.12 1.1 1.07 1.03 1.03 0.96 1.06 1.01 1.01 ...
 $ Phenolics_Concentration: num  52 48.9 41.8 30.7 28.2 ...

We filter out Wine 1 because we only want to look at Red Wine and not other colors which was included. We also delete the color variables because they are telling the same story as Ci_abs. We group the Phenolic analysis togethor because they are correlated and again tell the same story.

plot(wine_filtered$Months, wine_filtered$CI_abs, main = "Color vs Time", xlab = "Time", ylab = "Color Intensity")

We see here that there is some correlation between time of how long the wine aged and the Color Intensity.

full.model = lm(CI_abs~ ., data = wine_filtered)
kable(summary(full.model)$coef, caption ="Statistics of Regression Coefficients")
Statistics of Regression Coefficients
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.1377981 0.1201053 9.4733359 0.0000013
Months -0.0051872 0.0035208 -1.4733070 0.1686988
Phenolics_Concentration -0.0008608 0.0024276 -0.3545693 0.7296163
table(wine_filtered$WineType)
< table of extent 0 >
cor(wine_filtered)
                            Months     CI_abs Phenolics_Concentration
Months                   1.0000000 -0.6490598              -0.9148849
CI_abs                  -0.6490598  1.0000000               0.5611678
Phenolics_Concentration -0.9148849  0.5611678               1.0000000

We begin our serach for the final model by looking at a model that includes all the predictor values.

par(mfrow=c(2,2))
plot(full.model)

We see her that our residuals are all over ther place, most likely because our lack of variables. Our looks slighlty normal with someoutliers but we cannot assume normality. We also see unequal variance.

vif(full.model)
                 Months Phenolics_Concentration 
               6.135513                6.135513 

Our VIF values are a little big but we can continue our analysis.

par(pty = "s", mfrow = c(2, 2), oma=c(.1,.1,.1,.1), mar=c(4, 0, 2, 0))

boxcox(CI_abs ~ Phenolics_Concentration +  log(Months)  
       , data = wine_filtered, lambda = seq(0, 1, length = 10), 
       xlab=expression(paste(lambda, ": log months")))

boxcox(CI_abs ~ Phenolics_Concentration + Months, data = wine_filtered, lambda = seq(-0.5, 1, length = 10), 
       xlab=expression(paste(lambda, ": months")))

boxcox(CI_abs ~ log(1+Phenolics_Concentration) + Months, data = wine_filtered, lambda = seq(-0.5, 1, length = 10), 
       xlab=expression(paste(lambda, ": log phenolics")))
##
boxcox(CI_abs ~ log(1+Months) +  log(Phenolics_Concentration) 
      , data = wine_filtered, lambda = seq(-0.5, 1, length = 10), 
      xlab=expression(paste(lambda, ": log-months, log.phenolics")))

We do a Box-Cox transformation to try and fix our non normal QQ plot and unequal variance.

sqrt.CI = lm((CI_abs)^0.5 ~ Months + Phenolics_Concentration, data = wine_filtered)
kable(summary(sqrt.CI)$coef, caption = "log-transformed model")
log-transformed model
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.0694735 0.0586378 18.2386389 0.0000000
Months -0.0026035 0.0017189 -1.5146053 0.1580653
Phenolics_Concentration -0.0004623 0.0011852 -0.3900359 0.7039565
par(mfrow = c(2,2))
plot(sqrt.CI)

Firstly we do a Square-root transformation. We can see that we still have non-constant variance and a non-normal QQ plot.

log.CI = lm(log(CI_abs) ~ Months + Phenolics_Concentration, data = wine_filtered)
kable(summary(log.CI)$coef, caption = "log-transformed model")
log-transformed model
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.1400287 0.1145686 1.2222259 0.2471659
Months -0.0052261 0.0033585 -1.5560876 0.1479720
Phenolics_Concentration -0.0009855 0.0023157 -0.4255795 0.6786214
par(mfrow = c(2,2))
plot(log.CI)

We then do a log transformation of the Color Intensity based off the Box Cox transformation and build a linear regressionbased on log CI. Again these plots do not help our non constant variance and non-normal QQ plot.

par(pty = "s", mfrow = c(1, 3))
qqnorm(full.model$residuals, main = "Full-Model")
qqline(full.model$residuals)
qqnorm(log.CI$residuals, main = "Log-CI")
qqline(log.CI$residuals)
qqnorm(sqrt.CI$residuals, main = "sqrt CI")
qqline(sqrt.CI$residuals)

select=function(m){ 
 e = m$resid                           
 n0 = length(e)                        
 SSE=(m$df)*(summary(m)$sigma)^2       
 R.sq=summary(m)$r.squared             
 R.adj=summary(m)$adj.r               
 MSE=(summary(m)$sigma)^2             
 Cp=(SSE/MSE)-(n0-2*(n0-m$df))         
 AIC=n0*log(SSE)-n0*log(n0)+2*(n0-m$df)          
 SBC=n0*log(SSE)-n0*log(n0)+(log(n0))*(n0-m$df)  
 X=model.matrix(m)                     
 H=X%*%solve(t(X)%*%X)%*%t(X)          
 d=e/(1-diag(H))                       
 PRESS=t(d)%*%d   
 tbl = as.data.frame(cbind(SSE=SSE, R.sq=R.sq, R.adj = R.adj, Cp = Cp, AIC = AIC, SBC = SBC, PRD = PRESS))
 names(tbl)=c("SSE", "R.sq", "R.adj", "Cp", "AIC", "SBC", "PRESS")
 tbl
}

We then do some goodness of fit measures for each of the three models

output.sum = rbind(select(full.model), select(sqrt.CI), select(log.CI))
row.names(output.sum) = c("full.model", "sqrt.CI", "log.CI")
kable(output.sum, caption = "Goodness-of-fit Measures of Candidate Models")
Goodness-of-fit Measures of Candidate Models
SSE R.sq R.adj Cp AIC SBC PRESS
full.model 0.0209950 0.4278182 0.3237851 3 -85.03541 -83.11823 0.0324937
sqrt.CI 0.0050043 0.4322969 0.3290781 3 -105.11112 -103.19394 0.0077449
log.CI 0.0191039 0.4368550 0.3344651 3 -86.35687 -84.43970 0.0295675

We see that our third model is the best out of the three models based on R R squared

kable(summary(log.CI)$coef, caption = "Inferential Statistics of Final Model")
Inferential Statistics of Final Model
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.1400287 0.1145686 1.2222259 0.2471659
Months -0.0052261 0.0033585 -1.5560876 0.1479720
Phenolics_Concentration -0.0009855 0.0023157 -0.4255795 0.6786214

In our final model we see that our p-values are not significant and we would need to do some type of variable selection.

0.3 Results

Since we have a non-normal and unequal variance we really have no statistical findings we can take away. We have a very small sample because of the deletion of many variables and combination of others. For later projects we should combine the colors instead of deleting them so hopefully we can assume normatlity and constant variance.

0.4 Discussion

We performed a Box Cox transformation to serch for a final model for our data. We have a lot of violations so again we cannot make any inferences about the data.

LS0tDQp0aXRsZTogIkZhY3RvcnMgSW5mbHVlbmNlIFdpbmUgUXVhbGl0eSINCmF1dGhvcjogJ1R5bGVyIEJhdHRhZ2xpbmknDQpkYXRlOiAiMjAyNC0wOS0xOSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGZpZ193aWR0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KYWx3YXlzX2FsbG93X2h0bWw6IHRydWUNCi0tLQ0KDQpgYGB7PWh0bWx9DQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCi8qIENhc2NhZGluZyBTdHlsZSBTaGVldHMgKENTUykgaXMgYSBzdHlsZXNoZWV0IGxhbmd1YWdlIHVzZWQgdG8gZGVzY3JpYmUgdGhlIHByZXNlbnRhdGlvbiBvZiBhIGRvY3VtZW50IHdyaXR0ZW4gaW4gSFRNTCBvciBYTUwuIGl0IGlzIGEgc2ltcGxlIG1lY2hhbmlzbSBmb3IgYWRkaW5nIHN0eWxlIChlLmcuLCBmb250cywgY29sb3JzLCBzcGFjaW5nKSB0byBXZWIgZG9jdW1lbnRzLiAqLw0KDQpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLw0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGF1dGhvcnMgICovDQogIGZvbnQtc2l6ZTogMjBweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpoMiB7IC8qIEhlYWRlciAyIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMiBzZWN0aW9uIHRpdGxlICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQo8L3N0eWxlPg0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBEZXRlY3QsIGluc3RhbGwgYW5kIGxvYWQgcGFja2FnZXMgaWYgbmVlZGVkLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJNQVNTIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIk1BU1MiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KaWYgKCFyZXF1aXJlKCJubGVxc2x2IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIm5sZXFzbHYiKQ0KICAgbGlicmFyeShubGVxc2x2KQ0KfQ0KIw0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBzeWNoIikpIHsgICANCiAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICAgbGlicmFyeShwc3ljaCkNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoIk1BU1MiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsgICANCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoIkdHYWxseSIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpDQogICBsaWJyYXJ5KEdHYWxseSkNCn0NCmlmICghcmVxdWlyZSgiY2FyIikpIHsgICANCiAgaW5zdGFsbC5wYWNrYWdlcygiY2FyIikNCiAgIGxpYnJhcnkoY2FyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJkcGx5ciIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCiAgIGxpYnJhcnkoZHBseXIpDQp9DQoNCiMgc3BlY2lmaWNhdGlvbnMgb2Ygb3V0cHV0cyBvZiBjb2RlIGluIGNvZGUgY2h1bmtzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZ3MgPSBGQUxTRSwgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2VzID0gRkFMU0UsICAjDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BICAgICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICApICAgDQpgYGANCg0KIyMgSW50cm9kdWN0aW9uIC8gTWF0ZXJpYWxzDQoNClRoZSBkYXRhIHNob3dzIGNvbG9yIGFuZCBwaGVub2xpYyBtZWFzdXJlbWVudHMgZnJvbSB0aHJlZSBkaWZmcmVudCB0eXBlcyBvZiByZWQgd2luZSBUZW1wcmFuaWxsbywgR3JhY2lhbm8sIGFuZCBDYWJlcm5ldCBTYXV2aWdub24gYW5kIGZyb20gdGltZXMgMS41IHRvIDI2IG1vbnRocy4gSW4gdGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBkYXRhIGl0IGlzIG5vdCBtZW50aW9uZWQgZXhhY3RseSBob3cgdGhlIGRhdGEgd2FzIGNvbGxlY3RlZCBidXQgaXMgZnJvbSBNLiBNT25hZ2FzLCBQLkouIE1hcnRpbi1BbHZhcmV6LCBCLiBCYXJ0b2xvbWUsIEMuIEdvbWV6LUNvcmRvdmVzICgyMDA2KS4NCiJTdGF0aXN0aWNhbCBJbnRlcnByZXRhaW9uIG9mIHRoZSBDb2xvciBQYXJhbWV0ZXJzIG9mIFJlZCBXaW5lcyBpbiBGdW5jdGlvbg0Kb2YgdGhlaXIgUGhlbm9saWMgQ29tcG9zaXRpb24gRHVyaW5nIEFnaW5nIGluIEJvdHRsZSwiIEV1cm9wZWFuIEZvb2QgUmVzZWFyY2gNClRlY2hub2xvZ3ksIFZvbC8gMjIyLCBwcC4gNzAyLTIwOS4NCg0KDQpXaW5lVHlwZSAoY2F0ZWdvcmljYWwpOiBUeXBlIG9mIHdpbmUgKDEgPSBUZW1wcmFuaWxsbywgMiA9IEdyYWNpYW5vLCAzID0gQ2FiZXJuZXQgU2F1dmlnbm9uKS4NCk1vbnRocyAoY29udGludW91cyk6IFRpbWUgcG9pbnRzIGluIG1vbnRocyAoMS41LCAzLCA3LCA5LCAxMiwgMTkuNSwgMjYpLg0KDQpDb2xvcmltZXRyaWMgSW5kaWNlcyAoY29udGludW91cyk6DQpDSV9hYnM6IENvbG9yIEludGVuc2l0eS4NClBjdFllbGxvdzogUGVyY2VudGFnZSBvZiB5ZWxsb3cgY29sb3IuDQpQY3RSZWQ6IFBlcmNlbnRhZ2Ugb2YgcmVkIGNvbG9yLg0KUGN0Qmx1ZTogUGVyY2VudGFnZSBvZiBibHVlIGNvbG9yLg0KUGN0ZEE6IFBlcmNlbnRhZ2Ugb2YgcHVyZSByZWQuDQpUaW50OiBNZWFzdXJlIG9mIGh1ZS4NCg0KQ0lFTEFCIFZhcmlhYmxlcyAoY29udGludW91cyk6DQpMKjogTGlnaHRuZXNzLg0KQyo6IENocm9tYS4NCmgqOiBIdWUgYW5nbGUuDQphKjogUmVkL2dyZWVuIGNvbXBvbmVudC4NCmIqOiBZZWxsb3cvYmx1ZSBjb21wb25lbnQuDQoNClBoZW5vbGljIENvbmNlbnRyYXRpb25zIChtZy9MKSAoY29udGludW91cyk6DQpHTFU6IEdsdWNvc2lkZXMuDQpBQzogQWNldHlsLUdsdWNvc2lkZS4NCkNJTjogQ2lubmFtb2x5bCBHbHVjb3NpZGVzLg0KUFlSVVZJTElDUzogUGlydXZ5bGljcy4NClZJTllMSUNTOiBWaW55bGljcy4NCkZMQVZBTk9MUzogRmxhdmFub2xzLg0KRkxBVk9OT0xTOiBGbGF2b25vbHMuDQpDSU5OQU1JQ1M6IENpbm5hbWljcy4NCkJFTlpPSUNTOiBCZW56b2ljcy4NCg0KT25lIHF1ZXN0aW9uIHdlIGNhbiBhbnN3ZXIgZnJvbSB0aGlzIGRhdGFzZXQgYXJlIEhvdyBkb2VzIHRoZSBjb2xvciBvZiBlYWNoIHdpbmUgY2hhbmdlIG92ZXIgdGltZT8NCg0KIyMgTWV0aG9kb2xvZ3kgYW5kIEFuYWx5c2lzDQoNCmBgYHtyfQ0Kd2luZSA9IHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vVHlsZXJCYXR0YWdsaW5pL1NUQS0zMjEvbWFpbi9yZWR3aW5lX3BoZW5vbGljc19jb2xvci5jc3YiKQ0KcGFuZGVyKGhlYWQod2luZSkpDQpgYGANCg0KYGBge3J9DQpjb3Iod2luZVssIGMoIlBjdFllbGxvdyIgLCAiUGN0UmVkIiAsICJQY3RCbHVlIiAsICJQY3RkQSIgLCAiVGludCIgLCAiTF9zdGFyIiAsICJDX3N0YXIiICwgImhfc3RhciIgLCAiYV9zdGFyIiAsICJiX3N0YXIiKV0pDQoNCmBgYA0KDQpgYGB7cn0NCmNvcih3aW5lWywgYygiR0xVIiwgIkFDIiwgIkNJTiIsICJQWVJVVklMSUNTIiwgIlZJTllMSUNTIiwgIkZMQVZBTk9MUyIsICJGTEFWT05PTFMiLCAiQ0lOTkFNSUNTIiwgIkJFTlpPSUNTIildKQ0KDQpgYGANCldlIGxvb2sgYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdmFyaWJhbGVzIGFuZCBzZWUgbG90cyBvZiBjb3JyZWxhdGlvbiB3aGljaCBjb3VsZCBsZWFkIHRvIG11bHRpY29sbGluZWFyaXR5LiBXZSBzaG91bGQgc2VjdGlvbiB0aGVzZSB2YXJpYWJsZXMgYW5kIGdyb3VwIHRoZW0uDQoNCmBgYHtyfQ0Kd2luZV9maWx0ZXJlZCA8LSB3aW5lICU+JQ0KICBmaWx0ZXIoV2luZVR5cGUgIT0gMSkgJT4lDQogIHNlbGVjdCgtUGN0WWVsbG93LCAtUGN0UmVkLCAtUGN0Qmx1ZSwgLVBjdGRBLCAtTF9zdGFyLCAtQ19zdGFyLCAtaF9zdGFyLCAtYV9zdGFyLCAtYl9zdGFyLCAtVGludCwgLVdpbmVUeXBlKSAlPiUNCiAgbXV0YXRlKFBoZW5vbGljc19Db25jZW50cmF0aW9uID0gKEdMVSArIEFDICsgQ0lOICsgUFlSVVZJTElDUyArIFZJTllMSUNTICsgRkxBVkFOT0xTICsgRkxBVk9OT0xTICsgQ0lOTkFNSUNTICsgQkVOWk9JQ1MpIC8gOSkgJT4lDQogIHNlbGVjdCgtR0xVLCAtQUMsIC1DSU4sIC1QWVJVVklMSUNTLCAtVklOWUxJQ1MsIC1GTEFWQU5PTFMsIC1GTEFWT05PTFMsIC1DSU5OQU1JQ1MsIC1CRU5aT0lDUykNCnN0cih3aW5lX2ZpbHRlcmVkKQ0KYGBgDQpXZSBmaWx0ZXIgb3V0IFdpbmUgMSBiZWNhdXNlIHdlIG9ubHkgd2FudCB0byBsb29rIGF0IFJlZCBXaW5lIGFuZCBub3Qgb3RoZXIgY29sb3JzIHdoaWNoIHdhcyBpbmNsdWRlZC4gV2UgYWxzbyBkZWxldGUgdGhlIGNvbG9yIHZhcmlhYmxlcyBiZWNhdXNlIHRoZXkgYXJlIHRlbGxpbmcgdGhlIHNhbWUgc3RvcnkgYXMgQ2lfYWJzLiBXZSBncm91cCB0aGUgUGhlbm9saWMgYW5hbHlzaXMgdG9nZXRob3IgYmVjYXVzZSB0aGV5IGFyZSBjb3JyZWxhdGVkIGFuZCBhZ2FpbiB0ZWxsIHRoZSBzYW1lIHN0b3J5Lg0KDQpgYGB7cn0NCg0KcGxvdCh3aW5lX2ZpbHRlcmVkJE1vbnRocywgd2luZV9maWx0ZXJlZCRDSV9hYnMsIG1haW4gPSAiQ29sb3IgdnMgVGltZSIsIHhsYWIgPSAiVGltZSIsIHlsYWIgPSAiQ29sb3IgSW50ZW5zaXR5IikNCg0KYGBgDQpXZSBzZWUgaGVyZSB0aGF0IHRoZXJlIGlzIHNvbWUgY29ycmVsYXRpb24gYmV0d2VlbiB0aW1lIG9mIGhvdyBsb25nIHRoZSB3aW5lIGFnZWQgYW5kIHRoZSBDb2xvciBJbnRlbnNpdHkuDQoNCmBgYHtyfQ0KZnVsbC5tb2RlbCA9IGxtKENJX2Fic34gLiwgZGF0YSA9IHdpbmVfZmlsdGVyZWQpDQprYWJsZShzdW1tYXJ5KGZ1bGwubW9kZWwpJGNvZWYsIGNhcHRpb24gPSJTdGF0aXN0aWNzIG9mIFJlZ3Jlc3Npb24gQ29lZmZpY2llbnRzIikNCnRhYmxlKHdpbmVfZmlsdGVyZWQkV2luZVR5cGUpDQpjb3Iod2luZV9maWx0ZXJlZCkNCmBgYA0KV2UgYmVnaW4gb3VyIHNlcmFjaCBmb3IgdGhlIGZpbmFsIG1vZGVsIGJ5IGxvb2tpbmcgYXQgYSBtb2RlbCB0aGF0IGluY2x1ZGVzIGFsbCB0aGUgcHJlZGljdG9yIHZhbHVlcy4NCg0KDQpgYGB7cn0NCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KGZ1bGwubW9kZWwpDQpgYGANCldlIHNlZSBoZXIgdGhhdCBvdXIgcmVzaWR1YWxzIGFyZSBhbGwgb3ZlciB0aGVyIHBsYWNlLCBtb3N0IGxpa2VseSBiZWNhdXNlIG91ciBsYWNrIG9mIHZhcmlhYmxlcy4gT3VyIGxvb2tzIHNsaWdobHR5IG5vcm1hbCB3aXRoIHNvbWVvdXRsaWVycyBidXQgd2UgY2Fubm90IGFzc3VtZSBub3JtYWxpdHkuIFdlIGFsc28gc2VlIHVuZXF1YWwgdmFyaWFuY2UuDQoNCmBgYHtyfQ0KDQp2aWYoZnVsbC5tb2RlbCkNCg0KYGBgDQpPdXIgVklGIHZhbHVlcyBhcmUgYSBsaXR0bGUgYmlnIGJ1dCB3ZSBjYW4gY29udGludWUgb3VyIGFuYWx5c2lzLg0KDQpgYGB7cn0NCnBhcihwdHkgPSAicyIsIG1mcm93ID0gYygyLCAyKSwgb21hPWMoLjEsLjEsLjEsLjEpLCBtYXI9Yyg0LCAwLCAyLCAwKSkNCg0KYm94Y294KENJX2FicyB+IFBoZW5vbGljc19Db25jZW50cmF0aW9uICsgIGxvZyhNb250aHMpICANCiAgICAgICAsIGRhdGEgPSB3aW5lX2ZpbHRlcmVkLCBsYW1iZGEgPSBzZXEoMCwgMSwgbGVuZ3RoID0gMTApLCANCiAgICAgICB4bGFiPWV4cHJlc3Npb24ocGFzdGUobGFtYmRhLCAiOiBsb2cgbW9udGhzIikpKQ0KDQpib3hjb3goQ0lfYWJzIH4gUGhlbm9saWNzX0NvbmNlbnRyYXRpb24gKyBNb250aHMsIGRhdGEgPSB3aW5lX2ZpbHRlcmVkLCBsYW1iZGEgPSBzZXEoLTAuNSwgMSwgbGVuZ3RoID0gMTApLCANCiAgICAgICB4bGFiPWV4cHJlc3Npb24ocGFzdGUobGFtYmRhLCAiOiBtb250aHMiKSkpDQoNCmJveGNveChDSV9hYnMgfiBsb2coMStQaGVub2xpY3NfQ29uY2VudHJhdGlvbikgKyBNb250aHMsIGRhdGEgPSB3aW5lX2ZpbHRlcmVkLCBsYW1iZGEgPSBzZXEoLTAuNSwgMSwgbGVuZ3RoID0gMTApLCANCiAgICAgICB4bGFiPWV4cHJlc3Npb24ocGFzdGUobGFtYmRhLCAiOiBsb2cgcGhlbm9saWNzIikpKQ0KIyMNCmJveGNveChDSV9hYnMgfiBsb2coMStNb250aHMpICsgIGxvZyhQaGVub2xpY3NfQ29uY2VudHJhdGlvbikgDQogICAgICAsIGRhdGEgPSB3aW5lX2ZpbHRlcmVkLCBsYW1iZGEgPSBzZXEoLTAuNSwgMSwgbGVuZ3RoID0gMTApLCANCiAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEsICI6IGxvZy1tb250aHMsIGxvZy5waGVub2xpY3MiKSkpDQoNCmBgYA0KV2UgZG8gYSBCb3gtQ294IHRyYW5zZm9ybWF0aW9uIHRvIHRyeSBhbmQgZml4IG91ciBub24gbm9ybWFsIFFRIHBsb3QgYW5kIHVuZXF1YWwgdmFyaWFuY2UuDQoNCmBgYHtyfQ0Kc3FydC5DSSA9IGxtKChDSV9hYnMpXjAuNSB+IE1vbnRocyArIFBoZW5vbGljc19Db25jZW50cmF0aW9uLCBkYXRhID0gd2luZV9maWx0ZXJlZCkNCmthYmxlKHN1bW1hcnkoc3FydC5DSSkkY29lZiwgY2FwdGlvbiA9ICJsb2ctdHJhbnNmb3JtZWQgbW9kZWwiKQ0KYGBgDQpgYGB7cn0NCg0KDQpwYXIobWZyb3cgPSBjKDIsMikpDQpwbG90KHNxcnQuQ0kpDQoNCmBgYA0KRmlyc3RseSB3ZSBkbyBhIFNxdWFyZS1yb290IHRyYW5zZm9ybWF0aW9uLiBXZSBjYW4gc2VlIHRoYXQgd2Ugc3RpbGwgaGF2ZSBub24tY29uc3RhbnQgdmFyaWFuY2UgYW5kIGEgbm9uLW5vcm1hbCBRUSBwbG90Lg0KYGBge3J9DQoNCmxvZy5DSSA9IGxtKGxvZyhDSV9hYnMpIH4gTW9udGhzICsgUGhlbm9saWNzX0NvbmNlbnRyYXRpb24sIGRhdGEgPSB3aW5lX2ZpbHRlcmVkKQ0Ka2FibGUoc3VtbWFyeShsb2cuQ0kpJGNvZWYsIGNhcHRpb24gPSAibG9nLXRyYW5zZm9ybWVkIG1vZGVsIikNCg0KYGBgDQpgYGB7cn0NCnBhcihtZnJvdyA9IGMoMiwyKSkNCnBsb3QobG9nLkNJKQ0KYGBgDQpXZSB0aGVuIGRvIGEgbG9nIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBDb2xvciBJbnRlbnNpdHkgYmFzZWQgb2ZmIHRoZSBCb3ggQ294IHRyYW5zZm9ybWF0aW9uIGFuZCBidWlsZCBhIGxpbmVhciByZWdyZXNzaW9uYmFzZWQgb24gbG9nIENJLiBBZ2FpbiB0aGVzZSBwbG90cyBkbyBub3QgaGVscCBvdXIgbm9uIGNvbnN0YW50IHZhcmlhbmNlIGFuZCBub24tbm9ybWFsIFFRIHBsb3QuDQoNCmBgYHtyfQ0KcGFyKHB0eSA9ICJzIiwgbWZyb3cgPSBjKDEsIDMpKQ0KcXFub3JtKGZ1bGwubW9kZWwkcmVzaWR1YWxzLCBtYWluID0gIkZ1bGwtTW9kZWwiKQ0KcXFsaW5lKGZ1bGwubW9kZWwkcmVzaWR1YWxzKQ0KcXFub3JtKGxvZy5DSSRyZXNpZHVhbHMsIG1haW4gPSAiTG9nLUNJIikNCnFxbGluZShsb2cuQ0kkcmVzaWR1YWxzKQ0KcXFub3JtKHNxcnQuQ0kkcmVzaWR1YWxzLCBtYWluID0gInNxcnQgQ0kiKQ0KcXFsaW5lKHNxcnQuQ0kkcmVzaWR1YWxzKQ0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0Kc2VsZWN0PWZ1bmN0aW9uKG0peyANCiBlID0gbSRyZXNpZCAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIG4wID0gbGVuZ3RoKGUpICAgICAgICAgICAgICAgICAgICAgICAgDQogU1NFPShtJGRmKSooc3VtbWFyeShtKSRzaWdtYSleMiAgICAgICANCiBSLnNxPXN1bW1hcnkobSkkci5zcXVhcmVkICAgICAgICAgICAgIA0KIFIuYWRqPXN1bW1hcnkobSkkYWRqLnIgICAgICAgICAgICAgICANCiBNU0U9KHN1bW1hcnkobSkkc2lnbWEpXjIgICAgICAgICAgICAgDQogQ3A9KFNTRS9NU0UpLShuMC0yKihuMC1tJGRmKSkgICAgICAgICANCiBBSUM9bjAqbG9nKFNTRSktbjAqbG9nKG4wKSsyKihuMC1tJGRmKSAgICAgICAgICANCiBTQkM9bjAqbG9nKFNTRSktbjAqbG9nKG4wKSsobG9nKG4wKSkqKG4wLW0kZGYpICANCiBYPW1vZGVsLm1hdHJpeChtKSAgICAgICAgICAgICAgICAgICAgIA0KIEg9WCUqJXNvbHZlKHQoWCklKiVYKSUqJXQoWCkgICAgICAgICAgDQogZD1lLygxLWRpYWcoSCkpICAgICAgICAgICAgICAgICAgICAgICANCiBQUkVTUz10KGQpJSolZCAgIA0KIHRibCA9IGFzLmRhdGEuZnJhbWUoY2JpbmQoU1NFPVNTRSwgUi5zcT1SLnNxLCBSLmFkaiA9IFIuYWRqLCBDcCA9IENwLCBBSUMgPSBBSUMsIFNCQyA9IFNCQywgUFJEID0gUFJFU1MpKQ0KIG5hbWVzKHRibCk9YygiU1NFIiwgIlIuc3EiLCAiUi5hZGoiLCAiQ3AiLCAiQUlDIiwgIlNCQyIsICJQUkVTUyIpDQogdGJsDQp9DQpgYGANCldlIHRoZW4gZG8gc29tZSBnb29kbmVzcyBvZiBmaXQgbWVhc3VyZXMgZm9yIGVhY2ggb2YgdGhlIHRocmVlIG1vZGVscw0KDQpgYGB7cn0NCm91dHB1dC5zdW0gPSByYmluZChzZWxlY3QoZnVsbC5tb2RlbCksIHNlbGVjdChzcXJ0LkNJKSwgc2VsZWN0KGxvZy5DSSkpDQpyb3cubmFtZXMob3V0cHV0LnN1bSkgPSBjKCJmdWxsLm1vZGVsIiwgInNxcnQuQ0kiLCAibG9nLkNJIikNCmthYmxlKG91dHB1dC5zdW0sIGNhcHRpb24gPSAiR29vZG5lc3Mtb2YtZml0IE1lYXN1cmVzIG9mIENhbmRpZGF0ZSBNb2RlbHMiKQ0KDQpgYGANCldlIHNlZSB0aGF0IG91ciB0aGlyZCBtb2RlbCBpcyB0aGUgYmVzdCBvdXQgb2YgdGhlIHRocmVlIG1vZGVscyBiYXNlZCBvbiBSIFIgc3F1YXJlZA0KDQpgYGB7cn0NCmthYmxlKHN1bW1hcnkobG9nLkNJKSRjb2VmLCBjYXB0aW9uID0gIkluZmVyZW50aWFsIFN0YXRpc3RpY3Mgb2YgRmluYWwgTW9kZWwiKQ0KDQpgYGANCg0KSW4gb3VyIGZpbmFsIG1vZGVsIHdlIHNlZSB0aGF0IG91ciBwLXZhbHVlcyBhcmUgbm90IHNpZ25pZmljYW50IGFuZCB3ZSB3b3VsZCBuZWVkIHRvIGRvIHNvbWUgdHlwZSBvZiB2YXJpYWJsZSBzZWxlY3Rpb24uDQoNCiMjIFJlc3VsdHMNClNpbmNlIHdlIGhhdmUgYSBub24tbm9ybWFsIGFuZCB1bmVxdWFsIHZhcmlhbmNlIHdlIHJlYWxseSBoYXZlIG5vIHN0YXRpc3RpY2FsIGZpbmRpbmdzIHdlIGNhbiB0YWtlIGF3YXkuIFdlIGhhdmUgYSB2ZXJ5IHNtYWxsIHNhbXBsZSBiZWNhdXNlIG9mIHRoZSBkZWxldGlvbiBvZiBtYW55IHZhcmlhYmxlcyBhbmQgY29tYmluYXRpb24gb2Ygb3RoZXJzLiBGb3IgbGF0ZXIgcHJvamVjdHMgd2Ugc2hvdWxkIGNvbWJpbmUgdGhlIGNvbG9ycyBpbnN0ZWFkIG9mIGRlbGV0aW5nIHRoZW0gc28gaG9wZWZ1bGx5IHdlIGNhbiBhc3N1bWUgbm9ybWF0bGl0eSBhbmQgY29uc3RhbnQgdmFyaWFuY2UuIA0KDQojIyBEaXNjdXNzaW9uDQpXZSBwZXJmb3JtZWQgYSBCb3ggQ294IHRyYW5zZm9ybWF0aW9uIHRvIHNlcmNoIGZvciBhIGZpbmFsIG1vZGVsIGZvciBvdXIgZGF0YS4gV2UgaGF2ZSBhIGxvdCBvZiB2aW9sYXRpb25zIHNvIGFnYWluIHdlIGNhbm5vdCBtYWtlIGFueSBpbmZlcmVuY2VzIGFib3V0IHRoZSBkYXRhLg0K