Resource

gapminder data set from R

Structure of data

str(gapminder)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   1704 obs. of  6 variables:
 $ country  : Factor w/ 142 levels "Afghanistan",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ continent: Factor w/ 5 levels "Africa","Americas",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
 $ lifeExp  : num  28.8 30.3 32 34 36.1 ...
 $ pop      : int  8425333 9240934 10267083 11537966 13079460 14880372 12881816 13867957 16317921 22227415 ...
 $ gdpPercap: num  779 821 853 836 740 ...

Summary of data

summary(gapminder)
        country        continent        year         lifeExp           pop              gdpPercap       
 Afghanistan:  12   Africa  :624   Min.   :1952   Min.   :23.60   Min.   :6.001e+04   Min.   :   241.2  
 Albania    :  12   Americas:300   1st Qu.:1966   1st Qu.:48.20   1st Qu.:2.794e+06   1st Qu.:  1202.1  
 Algeria    :  12   Asia    :396   Median :1980   Median :60.71   Median :7.024e+06   Median :  3531.8  
 Angola     :  12   Europe  :360   Mean   :1980   Mean   :59.47   Mean   :2.960e+07   Mean   :  7215.3  
 Argentina  :  12   Oceania : 24   3rd Qu.:1993   3rd Qu.:70.85   3rd Qu.:1.959e+07   3rd Qu.:  9325.5  
 Australia  :  12                  Max.   :2007   Max.   :82.60   Max.   :1.319e+09   Max.   :113523.1  
 (Other)    :1632                                                                                       

Quick graphical check on variables

Histograms

GDP per capita does not appear to be normally distributed.

hist(gapminder$lifeExp)

hist(gapminder$gdpPercap)

Plotting

The relationship between GDP per capita and life expectancy doe not appear to be linear.

plot(gapminder$gdpPercap, gapminder$lifeExp, col="red")
abline(lm(gapminder$lifeExp ~ gapminder$gdpPercap), col="blue")

Center the data

mgdp=mean(gapminder$gdpPercap)
gapminder$gdp_c=gapminder$gdpPercap-mgdp
hist(gapminder$gdp_c)

Linear regression

GDP per capita is significantly associated with life expectancy. Curve does not fit well. Only 34 % of the variance is explianed by the model

reg1 <-lm(gapminder$lifeExp ~ gapminder$gdp_c)
summary(reg1)

Call:
lm(formula = gapminder$lifeExp ~ gapminder$gdp_c)

Residuals:
    Min      1Q  Median      3Q     Max 
-82.754  -7.758   2.176   8.225  18.426 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     5.947e+01  2.542e-01  234.01   <2e-16 ***
gapminder$gdp_c 7.649e-04  2.579e-05   29.66   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 10.49 on 1702 degrees of freedom
Multiple R-squared:  0.3407,    Adjusted R-squared:  0.3403 
F-statistic: 879.6 on 1 and 1702 DF,  p-value: < 2.2e-16

Request confidence intervals

confint(reg1)
                       2.5 %       97.5 %
(Intercept)     5.897595e+01 5.997292e+01
gapminder$gdp_c 7.142984e-04 8.154669e-04

Use the model to predict life expectancy

gapminder$gdpvalues <- seq(4000, 114000, length.out = 1704)
gapminder$predictedvalues1 <- predict(reg1, list(gdp_v=gapminder$gdpvalues, gdp_v2=gapminder$gdpvalues*gapminder$gdpvalues))
plot(gapminder$gdpPercap, gapminder$predictedvalues1, pch=16, col = "red" )

Polynomial regression: Degree 2 or Quadratic model

GDP per capita is significantly associated with life expectancy. Curve fits relatively well. Only 53 % of the variance is explianed by the model.

summary(reg2)

Call:
lm(formula = gapminder$lifeExp ~ gapminder$gdp_c + I(gapminder$gdp_c^2))

Residuals:
     Min       1Q   Median       3Q      Max 
-28.0600  -6.4253   0.2611   7.0889  27.1752 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)           6.093e+01  2.225e-01  273.88   <2e-16 ***
gapminder$gdp_c       1.334e-03  3.098e-05   43.07   <2e-16 ***
I(gapminder$gdp_c^2) -1.502e-08  5.794e-10  -25.92   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.885 on 1701 degrees of freedom
Multiple R-squared:  0.5274,    Adjusted R-squared:  0.5268 
F-statistic: 949.1 on 2 and 1701 DF,  p-value: < 2.2e-16

Plot the model

plot(gapminder$gdpPercap, gapminder$lifeExp, type="p", lwd=3)

poly2 <- function(x) reg2$coefficient[3]*x^2 + reg2$coefficient[2]*x + reg2$coefficient[1]
curve(poly2, col="red", lwd=2)
points(gapminder$gdpPercap, gapminder$lifeExp, type="p", lwd=3)

Use the quadratic model to predict life expectancy

gapminder$gdpvalues <- seq(4000, 114000, length.out = 1704)
gapminder$predictedvalues2 <- predict(reg2, list(gdp_v=gapminder$gdpvalues, gdp_v2=gapminder$gdpvalues*gapminder$gdpvalues))
plot(gapminder$gdpPercap, gapminder$predictedvalues2, pch=16, col = "red" )

Polynomial regression: Degree 3 or Cubic model

GDP per capita is significantly associated with life expectancy. Curve does not fit well. Only 60 % of the variance is explianed by the model.

summary(reg3)

Call:
lm(formula = gapminder$lifeExp ~ gapminder$gdp_c + I(gapminder$gdp_c^2) + 
    I(gapminder$gdp_c^3))

Residuals:
     Min       1Q   Median       3Q      Max 
-27.0491  -4.9994   0.1297   5.8643  26.2220 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)           6.373e+01  2.577e-01  247.30   <2e-16 ***
gapminder$gdp_c       1.803e-03  3.878e-05   46.49   <2e-16 ***
I(gapminder$gdp_c^2) -5.929e-08  2.545e-09  -23.30   <2e-16 ***
I(gapminder$gdp_c^3)  4.093e-13  2.301e-14   17.79   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.161 on 1700 degrees of freedom
Multiple R-squared:  0.6016,    Adjusted R-squared:  0.6009 
F-statistic: 855.6 on 3 and 1700 DF,  p-value: < 2.2e-16

Request confidence intervals

confint(reg3)
                             2.5 %        97.5 %
(Intercept)           6.322037e+01  6.423121e+01
gapminder$gdp_c       1.726987e-03  1.879115e-03
I(gapminder$gdp_c^2) -6.428661e-08 -5.430236e-08
I(gapminder$gdp_c^3)  3.641838e-13  4.544460e-13

Plot the model

plot(gapminder$gdpPercap, gapminder$lifeExp, type="p", lwd=3)

poly3 <- function(x) reg3$coefficient[3]*x^2 + reg3$coefficient[2]*x + reg3$coefficient[1]
curve(poly3, col="red", lwd=2)
points(gapminder$gdpPercap, gapminder$lifeExp, type="p", lwd=3)

Use the cubic model to predict life expectancy

gapminder$gdpvalues <- seq(4000, 114000, length.out = 1704)
gapminder$predictedvalues3 <- predict(reg3, list(gdp_v=gapminder$gdpvalues, gdp_v2=gapminder$gdpvalues*gapminder$gdpvalues))
plot(gapminder$gdpPercap, gapminder$predictedvalues3, pch=16, col = "red" )

Compare the models

Regression models (linear/reg1 and quadratic/reg2) are statistically different.

anova(reg1, reg2)
Analysis of Variance Table

Model 1: gapminder$lifeExp ~ gapminder$gdp_c
Model 2: gapminder$lifeExp ~ gapminder$gdp_c + I(gapminder$gdp_c^2)
  Res.Df    RSS Df Sum of Sq      F    Pr(>F)    
1   1702 187335                                  
2   1701 134289  1     53046 671.92 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Regression models (quadratic/reg2 and cubic/reg3) are also statistically different.

anova(reg2, reg3)
Analysis of Variance Table

Model 1: gapminder$lifeExp ~ gapminder$gdp_c + I(gapminder$gdp_c^2)
Model 2: gapminder$lifeExp ~ gapminder$gdp_c + I(gapminder$gdp_c^2) + 
    I(gapminder$gdp_c^3)
  Res.Df    RSS Df Sum of Sq      F    Pr(>F)    
1   1701 134289                                  
2   1700 113216  1     21073 316.43 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Run dignostics for the cubic model

influence.measures(reg3)
Influence measures of
     lm(formula = gapminder$lifeExp ~ gapminder$gdp_c + I(gapminder$gdp_c^2) +      I(gapminder$gdp_c^3)) :

Analysis of the gapminder data set using SAS

Import data;


%let path=/folders/myshortcuts/datasets;
libname usr "&path";

proc import datafile="&path/gapminder_r.csv"  dbms=csv   out=gapminder_r replace;
getnames=yes;
run;

Scatterplotwith linear regression line;


proc sgplot data=gapminder_r;
  reg x=gdppercap y=lifeexp / lineattrs=(color=blue thickness=2) clm;
  yaxis label="Life expectancy";
  xaxis label="GDP per capita";
run;
scatterplot/linear

scatterplot/linear

Scatterplot with quadratic line;


proc sgplot data=gapminder_r;
  reg x=gdppercap y=lifeexp / lineattrs=(color=green thickness=2) degree=2 clm;
  yaxis label="Life expectancy";
  xaxis label="GDP per capita";
run;
Scatterplot/quadratic

Scatterplot/quadratic

Scatterplot with cubic line;


proc sgplot data=gapminder_r;
  reg x=gdppercap y=lifeexp / lineattrs=(color=green thickness=2) degree=3clm;
  yaxis label="Life expectancy";
  xaxis label="GDP per capita";
run;
scatterplot/cubic

scatterplot/cubic

Scatterplot with linear, quadratic and cubic regression line;


proc sgplot data=gapminder_r;
  reg x=gdppercap y=lifeexp / lineattrs=(color=blue thickness=2) degree=1 clm;
  reg x=gdppercap y=lifeexp / lineattrs=(color=green thickness=2) degree=2 clm;
  reg x=gdppercap y=lifeexp / lineattrs=(color=green thickness=2) degree=3clm;
  yaxis label="Life expectancy";
  xaxis label="GDP per capita";
run;
scatterplot/degrees1,2&3

scatterplot/degrees1,2&3

Center the quantitative explanatory variable and check its accuracy;


proc means data=gapminder_r; 
var lifeexp gdppercap;
run;

data gapminder_c; 
set gapminder_r;
if lifeexp ne . and gdppercap ne . ;
gdppercap_c=gdppercap-7215.33;
lifeexp_c=lifeexp-59.4744;
run;

proc means data=gapminder_c; 
var lifeexp_c gdppercap_c;
run;
centering_variables

centering_variables

Regression analysis using proc glm

Linear regression model;

PROC glm data=gapminder_c; 
model lifeexp=gdppercap_c/solution clparm; 
run;
linear regression

linear regression

Polynomial regression model: quadratic;

PROC glm data=gapminder_c; 
model lifeexp=gdppercap_c gdppercap_c*gdppercap_c/solution clparm;
run;
polynomial/quadratic regression

polynomial/quadratic regression

Polynomial regression model: cubic;

PROC glm data=gapminder_c; 
model lifeexp=gdppercap_c gdppercap_c*gdppercap_c gdppercap_c*gdppercap_c*gdppercap_c/solution clparm;
run;
polynomial/cubic regression

polynomial/cubic regression

Regression analysis using proc reg

Proc reg needs additional manipulation for polynomial terms;

 data gapminder_c;
    set gapminder_c;
    gdppercap_c2 = gdppercap_c*gdppercap_c; 
    gdppercap_c3  = gdppercap_c*gdppercap_c*gdppercap_c;
 run;

Simple linear regression;

proc reg data=gapminder_c alpha=0.05 
    plots(only)=(diagnostics residuals fitplot observedbypredicted RStudentByLeverage(label) CooksD(label)
                Residuals(smooth) DFFITS(label) DFBETAS ObservedByPredicted(label));
    model lifeexp=gdppercap_c;
    run;
quit;

Polynomial regression model: quadratic;

proc reg data=gapminder_c alpha=0.05 
    plots(only)=(diagnostics residuals fitplot observedbypredicted RStudentByLeverage(label) CooksD(label)
                Residuals(smooth) DFFITS(label) DFBETAS ObservedByPredicted(label));
    model lifeexp=gdppercap_c gdppercap_c2;
    run;
quit;

Polynomial regression model: cubic;

proc reg data=gapminder_c alpha=0.05 
    plots(only)=(diagnostics residuals fitplot observedbypredicted RStudentByLeverage(label) CooksD(label)
                Residuals(smooth) DFFITS(label) DFBETAS ObservedByPredicted(label));
    model lifeexp=gdppercap_c gdppercap_c2 gdppercap_c3 /;
    run;
quit;
proc_reg/cubic

proc_reg/cubic

image

image

image

image

image

image

image

image

image

image

image

image

image

image

LS0tDQp0aXRsZTogIlNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBhbmQgcG9seW5vbWlhbCByZWdyZXNzaW9uIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQphdXRob3I6IEJoYWdpcmF0aGkgRGFzaA0KLS0tDQojIFJlc291cmNlDQoNCmdhcG1pbmRlciBkYXRhIHNldCBmcm9tIFINCg0KIyBTdHJ1Y3R1cmUgb2YgZGF0YQ0KDQpgYGB7cn0NCnN0cihnYXBtaW5kZXIpDQpgYGANCg0KIyBTdW1tYXJ5IG9mIGRhdGENCg0KYGBge3J9DQpzdW1tYXJ5KGdhcG1pbmRlcikNCmBgYA0KDQoNCiMgUXVpY2sgZ3JhcGhpY2FsIGNoZWNrIG9uIHZhcmlhYmxlcw0KDQojIyBIaXN0b2dyYW1zDQoNCkdEUCBwZXIgY2FwaXRhIGRvZXMgbm90IGFwcGVhciB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4NCg0KYGBge3J9DQpoaXN0KGdhcG1pbmRlciRsaWZlRXhwKQ0KaGlzdChnYXBtaW5kZXIkZ2RwUGVyY2FwKQ0KYGBgDQoNCiMjIFBsb3R0aW5nDQoNClRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBHRFAgcGVyIGNhcGl0YSBhbmQgbGlmZSBleHBlY3RhbmN5IGRvZSBub3QgYXBwZWFyIHRvIGJlIGxpbmVhci4NCg0KYGBge3J9DQpwbG90KGdhcG1pbmRlciRnZHBQZXJjYXAsIGdhcG1pbmRlciRsaWZlRXhwLCBjb2w9InJlZCIpDQphYmxpbmUobG0oZ2FwbWluZGVyJGxpZmVFeHAgfiBnYXBtaW5kZXIkZ2RwUGVyY2FwKSwgY29sPSJibHVlIikNCmBgYA0KDQoNCiMgQ2VudGVyIHRoZSBkYXRhDQoNCmBgYHtyfQ0KbWdkcD1tZWFuKGdhcG1pbmRlciRnZHBQZXJjYXApDQpnYXBtaW5kZXIkZ2RwX2M9Z2FwbWluZGVyJGdkcFBlcmNhcC1tZ2RwDQpoaXN0KGdhcG1pbmRlciRnZHBfYykNCmBgYA0KDQoNCiMgTGluZWFyIHJlZ3Jlc3Npb24NCg0KR0RQIHBlciBjYXBpdGEgaXMgc2lnbmlmaWNhbnRseSBhc3NvY2lhdGVkIHdpdGggbGlmZSBleHBlY3RhbmN5LiANCkN1cnZlIGRvZXMgbm90IGZpdCB3ZWxsLg0KT25seSAzNCAlIG9mIHRoZSB2YXJpYW5jZSBpcyBleHBsaWFuZWQgYnkgdGhlIG1vZGVsDQoNCmBgYHtyfQ0KcmVnMSA8LWxtKGdhcG1pbmRlciRsaWZlRXhwIH4gZ2FwbWluZGVyJGdkcF9jKQ0Kc3VtbWFyeShyZWcxKQ0KYGBgDQoNCiMjIFJlcXVlc3QgY29uZmlkZW5jZSBpbnRlcnZhbHMNCg0KYGBge3J9DQpjb25maW50KHJlZzEpDQpgYGANCg0KDQoNCiMjIFVzZSB0aGUgbW9kZWwgdG8gcHJlZGljdCBsaWZlIGV4cGVjdGFuY3kgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyJGdkcHZhbHVlcyA8LSBzZXEoNDAwMCwgMTE0MDAwLCBsZW5ndGgub3V0ID0gMTcwNCkNCmdhcG1pbmRlciRwcmVkaWN0ZWR2YWx1ZXMxIDwtIHByZWRpY3QocmVnMSwgbGlzdChnZHBfdj1nYXBtaW5kZXIkZ2RwdmFsdWVzLCBnZHBfdjI9Z2FwbWluZGVyJGdkcHZhbHVlcypnYXBtaW5kZXIkZ2RwdmFsdWVzKSkNCnBsb3QoZ2FwbWluZGVyJGdkcFBlcmNhcCwgZ2FwbWluZGVyJHByZWRpY3RlZHZhbHVlczEsIHBjaD0xNiwgY29sID0gInJlZCIgKQ0KYGBgDQoNCg0KIyBQb2x5bm9taWFsIHJlZ3Jlc3Npb246IERlZ3JlZSAyIG9yIFF1YWRyYXRpYyBtb2RlbA0KDQpHRFAgcGVyIGNhcGl0YSBpcyBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBsaWZlIGV4cGVjdGFuY3kuIA0KQ3VydmUgZml0cyByZWxhdGl2ZWx5IHdlbGwuDQpPbmx5ICA1MyAlIG9mIHRoZSB2YXJpYW5jZSBpcyBleHBsaWFuZWQgYnkgdGhlIG1vZGVsLg0KDQpgYGB7cn0NCnJlZzIgPC1sbShnYXBtaW5kZXIkbGlmZUV4cCB+IGdhcG1pbmRlciRnZHBfYyArIEkoZ2FwbWluZGVyJGdkcF9jXjIpKQ0Kc3VtbWFyeShyZWcyKQ0KYGBgDQoNCg0KIyMgUGxvdCB0aGUgbW9kZWwNCg0KYGBge3J9DQpwbG90KGdhcG1pbmRlciRnZHBQZXJjYXAsIGdhcG1pbmRlciRsaWZlRXhwLCB0eXBlPSJwIiwgbHdkPTMpDQpwb2x5MiA8LSBmdW5jdGlvbih4KSByZWcyJGNvZWZmaWNpZW50WzNdKnheMiArIHJlZzIkY29lZmZpY2llbnRbMl0qeCArIHJlZzIkY29lZmZpY2llbnRbMV0NCmN1cnZlKHBvbHkyLCBjb2w9InJlZCIsIGx3ZD0yKQ0KcG9pbnRzKGdhcG1pbmRlciRnZHBQZXJjYXAsIGdhcG1pbmRlciRsaWZlRXhwLCB0eXBlPSJwIiwgbHdkPTMpDQpgYGANCg0KDQoNCg0KIyMgVXNlIHRoZSBxdWFkcmF0aWMgbW9kZWwgdG8gcHJlZGljdCBsaWZlIGV4cGVjdGFuY3kgDQoNCmBgYHtyfQ0KZ2FwbWluZGVyJGdkcHZhbHVlcyA8LSBzZXEoNDAwMCwgMTE0MDAwLCBsZW5ndGgub3V0ID0gMTcwNCkNCmdhcG1pbmRlciRwcmVkaWN0ZWR2YWx1ZXMyIDwtIHByZWRpY3QocmVnMiwgbGlzdChnZHBfdj1nYXBtaW5kZXIkZ2RwdmFsdWVzLCBnZHBfdjI9Z2FwbWluZGVyJGdkcHZhbHVlcypnYXBtaW5kZXIkZ2RwdmFsdWVzKSkNCnBsb3QoZ2FwbWluZGVyJGdkcFBlcmNhcCwgZ2FwbWluZGVyJHByZWRpY3RlZHZhbHVlczIsIHBjaD0xNiwgY29sID0gInJlZCIgKQ0KYGBgDQoNCiMgUG9seW5vbWlhbCByZWdyZXNzaW9uOiBEZWdyZWUgMyBvciBDdWJpYyBtb2RlbA0KDQpHRFAgcGVyIGNhcGl0YSBpcyBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBsaWZlIGV4cGVjdGFuY3kuIA0KQ3VydmUgZG9lcyBub3QgZml0IHdlbGwuDQpPbmx5ICA2MCAlIG9mIHRoZSB2YXJpYW5jZSBpcyBleHBsaWFuZWQgYnkgdGhlIG1vZGVsLg0KDQpgYGB7cn0NCnJlZzMgPC1sbShnYXBtaW5kZXIkbGlmZUV4cCB+IGdhcG1pbmRlciRnZHBfYyArIEkoZ2FwbWluZGVyJGdkcF9jXjIpICsgSShnYXBtaW5kZXIkZ2RwX2NeMykpDQpzdW1tYXJ5KHJlZzMpDQpgYGANCiMjIFJlcXVlc3QgY29uZmlkZW5jZSBpbnRlcnZhbHMNCg0KYGBge3J9DQpjb25maW50KHJlZzMpDQpgYGANCg0KDQojIyBQbG90IHRoZSBtb2RlbA0KDQpgYGB7cn0NCnBsb3QoZ2FwbWluZGVyJGdkcFBlcmNhcCwgZ2FwbWluZGVyJGxpZmVFeHAsIHR5cGU9InAiLCBsd2Q9MykNCnBvbHkzIDwtIGZ1bmN0aW9uKHgpIHJlZzMkY29lZmZpY2llbnRbM10qeF4yICsgcmVnMyRjb2VmZmljaWVudFsyXSp4ICsgcmVnMyRjb2VmZmljaWVudFsxXQ0KY3VydmUocG9seTMsIGNvbD0icmVkIiwgbHdkPTIpDQpwb2ludHMoZ2FwbWluZGVyJGdkcFBlcmNhcCwgZ2FwbWluZGVyJGxpZmVFeHAsIHR5cGU9InAiLCBsd2Q9MykNCmBgYA0KDQojIyBVc2UgdGhlIGN1YmljIG1vZGVsIHRvIHByZWRpY3QgbGlmZSBleHBlY3RhbmN5IA0KDQpgYGB7cn0NCmdhcG1pbmRlciRnZHB2YWx1ZXMgPC0gc2VxKDQwMDAsIDExNDAwMCwgbGVuZ3RoLm91dCA9IDE3MDQpDQpnYXBtaW5kZXIkcHJlZGljdGVkdmFsdWVzMyA8LSBwcmVkaWN0KHJlZzMsIGxpc3QoZ2RwX3Y9Z2FwbWluZGVyJGdkcHZhbHVlcywgZ2RwX3YyPWdhcG1pbmRlciRnZHB2YWx1ZXMqZ2FwbWluZGVyJGdkcHZhbHVlcykpDQpwbG90KGdhcG1pbmRlciRnZHBQZXJjYXAsIGdhcG1pbmRlciRwcmVkaWN0ZWR2YWx1ZXMzLCBwY2g9MTYsIGNvbCA9ICJyZWQiICkNCmBgYA0KDQoNCiMgQ29tcGFyZSB0aGUgbW9kZWxzDQoNCiMjIFJlZ3Jlc3Npb24gbW9kZWxzIChsaW5lYXIvcmVnMSBhbmQgcXVhZHJhdGljL3JlZzIpIGFyZSBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudC4NCg0KYGBge3J9DQphbm92YShyZWcxLCByZWcyKQ0KYGBgDQoNCg0KIyMgUmVncmVzc2lvbiBtb2RlbHMgKHF1YWRyYXRpYy9yZWcyIGFuZCBjdWJpYy9yZWczKSBhcmUgYWxzbyBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudC4NCg0KYGBge3J9DQphbm92YShyZWcyLCByZWczKQ0KYGBgDQoNCiMgUnVuIGRpZ25vc3RpY3MgZm9yIHRoZSBjdWJpYyBtb2RlbA0KDQpgYGB7cn0NCmluZmx1ZW5jZS5tZWFzdXJlcyhyZWczKQ0KDQpgYGANCg0KDQoNCg0KIyBBbmFseXNpcyBvZiB0aGUgZ2FwbWluZGVyIGRhdGEgc2V0IHVzaW5nIFNBUw0KDQojIEltcG9ydCBkYXRhOw0KDQpgYGB7c2FzfQ0KDQolbGV0IHBhdGg9L2ZvbGRlcnMvbXlzaG9ydGN1dHMvZGF0YXNldHM7DQpsaWJuYW1lIHVzciAiJnBhdGgiOw0KDQpwcm9jIGltcG9ydCBkYXRhZmlsZT0iJnBhdGgvZ2FwbWluZGVyX3IuY3N2IiAgZGJtcz1jc3YgICBvdXQ9Z2FwbWluZGVyX3IgcmVwbGFjZTsNCmdldG5hbWVzPXllczsNCnJ1bjsNCg0KYGBgDQoNCg0KIyBTY2F0dGVycGxvdHdpdGggbGluZWFyIHJlZ3Jlc3Npb24gbGluZTsNCg0KDQpgYGB7c2FzfQ0KDQpwcm9jIHNncGxvdCBkYXRhPWdhcG1pbmRlcl9yOw0KICByZWcgeD1nZHBwZXJjYXAgeT1saWZlZXhwIC8gbGluZWF0dHJzPShjb2xvcj1ibHVlIHRoaWNrbmVzcz0yKSBjbG07DQogIHlheGlzIGxhYmVsPSJMaWZlIGV4cGVjdGFuY3kiOw0KICB4YXhpcyBsYWJlbD0iR0RQIHBlciBjYXBpdGEiOw0KcnVuOw0KDQpgYGANCg0KIVtzY2F0dGVycGxvdC9saW5lYXJdKGxpZmVleHB0dnNnZHAtZGVncmVlMS5wbmcpDQoNCg0KIyBTY2F0dGVycGxvdCB3aXRoIHF1YWRyYXRpYyBsaW5lOw0KDQpgYGB7c2FzfQ0KDQpwcm9jIHNncGxvdCBkYXRhPWdhcG1pbmRlcl9yOw0KICByZWcgeD1nZHBwZXJjYXAgeT1saWZlZXhwIC8gbGluZWF0dHJzPShjb2xvcj1ncmVlbiB0aGlja25lc3M9MikgZGVncmVlPTIgY2xtOw0KICB5YXhpcyBsYWJlbD0iTGlmZSBleHBlY3RhbmN5IjsNCiAgeGF4aXMgbGFiZWw9IkdEUCBwZXIgY2FwaXRhIjsNCnJ1bjsNCmBgYA0KDQohW1NjYXR0ZXJwbG90L3F1YWRyYXRpY10obGlmZWV4cHR2c2dkcC1kZWdyZWUyLnBuZykNCg0KIyBTY2F0dGVycGxvdCB3aXRoIGN1YmljIGxpbmU7DQoNCmBgYHtzYXN9DQoNCnByb2Mgc2dwbG90IGRhdGE9Z2FwbWluZGVyX3I7DQogIHJlZyB4PWdkcHBlcmNhcCB5PWxpZmVleHAgLyBsaW5lYXR0cnM9KGNvbG9yPWdyZWVuIHRoaWNrbmVzcz0yKSBkZWdyZWU9M2NsbTsNCiAgeWF4aXMgbGFiZWw9IkxpZmUgZXhwZWN0YW5jeSI7DQogIHhheGlzIGxhYmVsPSJHRFAgcGVyIGNhcGl0YSI7DQpydW47DQpgYGANCg0KIVtzY2F0dGVycGxvdC9jdWJpY10obGlmZWV4cHR2c2dkcC1kZWdyZWUzLnBuZykNCg0KIyBTY2F0dGVycGxvdCB3aXRoIGxpbmVhciwgcXVhZHJhdGljIGFuZCBjdWJpYyByZWdyZXNzaW9uIGxpbmU7DQoNCmBgYHtzYXN9DQoNCnByb2Mgc2dwbG90IGRhdGE9Z2FwbWluZGVyX3I7DQogIHJlZyB4PWdkcHBlcmNhcCB5PWxpZmVleHAgLyBsaW5lYXR0cnM9KGNvbG9yPWJsdWUgdGhpY2tuZXNzPTIpIGRlZ3JlZT0xIGNsbTsNCiAgcmVnIHg9Z2RwcGVyY2FwIHk9bGlmZWV4cCAvIGxpbmVhdHRycz0oY29sb3I9Z3JlZW4gdGhpY2tuZXNzPTIpIGRlZ3JlZT0yIGNsbTsNCiAgcmVnIHg9Z2RwcGVyY2FwIHk9bGlmZWV4cCAvIGxpbmVhdHRycz0oY29sb3I9Z3JlZW4gdGhpY2tuZXNzPTIpIGRlZ3JlZT0zY2xtOw0KICB5YXhpcyBsYWJlbD0iTGlmZSBleHBlY3RhbmN5IjsNCiAgeGF4aXMgbGFiZWw9IkdEUCBwZXIgY2FwaXRhIjsNCnJ1bjsNCmBgYA0KDQoNCiFbc2NhdHRlcnBsb3QvZGVncmVlczEsMiYzXShsaWZlZXhwdHZzZ2RwLWRlZ3JlZXMtMS0yLTMucG5nKQ0KDQoNCg0KIyBDZW50ZXIgdGhlIHF1YW50aXRhdGl2ZSBleHBsYW5hdG9yeSB2YXJpYWJsZSBhbmQgY2hlY2sgaXRzIGFjY3VyYWN5Ow0KDQoNCmBgYHtzYXN9DQoNCnByb2MgbWVhbnMgZGF0YT1nYXBtaW5kZXJfcjsgDQp2YXIgbGlmZWV4cCBnZHBwZXJjYXA7DQpydW47DQoNCmRhdGEgZ2FwbWluZGVyX2M7IA0Kc2V0IGdhcG1pbmRlcl9yOw0KaWYgbGlmZWV4cCBuZSAuIGFuZCBnZHBwZXJjYXAgbmUgLiA7DQpnZHBwZXJjYXBfYz1nZHBwZXJjYXAtNzIxNS4zMzsNCmxpZmVleHBfYz1saWZlZXhwLTU5LjQ3NDQ7DQpydW47DQoNCnByb2MgbWVhbnMgZGF0YT1nYXBtaW5kZXJfYzsgDQp2YXIgbGlmZWV4cF9jIGdkcHBlcmNhcF9jOw0KcnVuOw0KYGBgDQoNCg0KIVtjZW50ZXJpbmdfdmFyaWFibGVzXShjZW50ZXJpbmcuSlBHKQ0KDQoNCiMgUmVncmVzc2lvbiBhbmFseXNpcyB1c2luZyBwcm9jIGdsbQ0KDQojIyBMaW5lYXIgcmVncmVzc2lvbiBtb2RlbDsNCg0KYGBge3Nhc30NClBST0MgZ2xtIGRhdGE9Z2FwbWluZGVyX2M7IA0KbW9kZWwgbGlmZWV4cD1nZHBwZXJjYXBfYy9zb2x1dGlvbiBjbHBhcm07IA0KcnVuOw0KYGBgDQoNCg0KIVtsaW5lYXIgcmVncmVzc2lvbl0ocHJvY2dsbS1kZzEuUE5HKQ0KDQojIyBQb2x5bm9taWFsIHJlZ3Jlc3Npb24gbW9kZWw6IHF1YWRyYXRpYzsNCg0KYGBge3Nhc30NClBST0MgZ2xtIGRhdGE9Z2FwbWluZGVyX2M7IA0KbW9kZWwgbGlmZWV4cD1nZHBwZXJjYXBfYyBnZHBwZXJjYXBfYypnZHBwZXJjYXBfYy9zb2x1dGlvbiBjbHBhcm07DQpydW47DQpgYGANCg0KIVtwb2x5bm9taWFsL3F1YWRyYXRpYyByZWdyZXNzaW9uXShwcm9jZ2xtLWRnMi5QTkcpDQoNCiMjIFBvbHlub21pYWwgcmVncmVzc2lvbiBtb2RlbDogY3ViaWM7DQoNCmBgYHtzYXN9DQpQUk9DIGdsbSBkYXRhPWdhcG1pbmRlcl9jOyANCm1vZGVsIGxpZmVleHA9Z2RwcGVyY2FwX2MgZ2RwcGVyY2FwX2MqZ2RwcGVyY2FwX2MgZ2RwcGVyY2FwX2MqZ2RwcGVyY2FwX2MqZ2RwcGVyY2FwX2Mvc29sdXRpb24gY2xwYXJtOw0KcnVuOw0KYGBgDQoNCiFbcG9seW5vbWlhbC9jdWJpYyByZWdyZXNzaW9uXShwcm9jZ2xtLWRnMy5QTkcpDQoNCg0KDQojIFJlZ3Jlc3Npb24gYW5hbHlzaXMgdXNpbmcgcHJvYyByZWcNCg0KIyMgUHJvYyByZWcgbmVlZHMgYWRkaXRpb25hbCBtYW5pcHVsYXRpb24gZm9yIHBvbHlub21pYWwgdGVybXM7DQoNCg0KYGBge3Nhc30NCiBkYXRhIGdhcG1pbmRlcl9jOw0KICAgIHNldCBnYXBtaW5kZXJfYzsNCiAgICBnZHBwZXJjYXBfYzIgPSBnZHBwZXJjYXBfYypnZHBwZXJjYXBfYzsgDQogICAgZ2RwcGVyY2FwX2MzICA9IGdkcHBlcmNhcF9jKmdkcHBlcmNhcF9jKmdkcHBlcmNhcF9jOw0KIHJ1bjsNCmBgYA0KDQojIyBTaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb247DQoNCmBgYHtzYXN9DQpwcm9jIHJlZyBkYXRhPWdhcG1pbmRlcl9jIGFscGhhPTAuMDUgDQoJcGxvdHMob25seSk9KGRpYWdub3N0aWNzIHJlc2lkdWFscyBmaXRwbG90IG9ic2VydmVkYnlwcmVkaWN0ZWQgUlN0dWRlbnRCeUxldmVyYWdlKGxhYmVsKSBDb29rc0QobGFiZWwpDQoJCQkJUmVzaWR1YWxzKHNtb290aCkgREZGSVRTKGxhYmVsKSBERkJFVEFTIE9ic2VydmVkQnlQcmVkaWN0ZWQobGFiZWwpKTsNCgltb2RlbCBsaWZlZXhwPWdkcHBlcmNhcF9jOw0KCXJ1bjsNCnF1aXQ7DQpgYGANCg0KIyMgUG9seW5vbWlhbCByZWdyZXNzaW9uIG1vZGVsOiBxdWFkcmF0aWM7DQoNCmBgYHtzYXN9DQpwcm9jIHJlZyBkYXRhPWdhcG1pbmRlcl9jIGFscGhhPTAuMDUgDQoJcGxvdHMob25seSk9KGRpYWdub3N0aWNzIHJlc2lkdWFscyBmaXRwbG90IG9ic2VydmVkYnlwcmVkaWN0ZWQgUlN0dWRlbnRCeUxldmVyYWdlKGxhYmVsKSBDb29rc0QobGFiZWwpDQoJCQkJUmVzaWR1YWxzKHNtb290aCkgREZGSVRTKGxhYmVsKSBERkJFVEFTIE9ic2VydmVkQnlQcmVkaWN0ZWQobGFiZWwpKTsNCgltb2RlbCBsaWZlZXhwPWdkcHBlcmNhcF9jIGdkcHBlcmNhcF9jMjsNCglydW47DQpxdWl0Ow0KYGBgDQoNCiMjIFBvbHlub21pYWwgcmVncmVzc2lvbiBtb2RlbDogY3ViaWM7DQoNCmBgYHtzYXN9DQpwcm9jIHJlZyBkYXRhPWdhcG1pbmRlcl9jIGFscGhhPTAuMDUgDQoJcGxvdHMob25seSk9KGRpYWdub3N0aWNzIHJlc2lkdWFscyBmaXRwbG90IG9ic2VydmVkYnlwcmVkaWN0ZWQgUlN0dWRlbnRCeUxldmVyYWdlKGxhYmVsKSBDb29rc0QobGFiZWwpDQoJCQkJUmVzaWR1YWxzKHNtb290aCkgREZGSVRTKGxhYmVsKSBERkJFVEFTIE9ic2VydmVkQnlQcmVkaWN0ZWQobGFiZWwpKTsNCgltb2RlbCBsaWZlZXhwPWdkcHBlcmNhcF9jIGdkcHBlcmNhcF9jMiBnZHBwZXJjYXBfYzMgLzsNCglydW47DQpxdWl0Ow0KYGBgDQoNCg0KIVtwcm9jX3JlZy9jdWJpY10ocHJvY3JlZ2RnMy5wbmcpDQoNCg0KDQohW2ltYWdlXShvYnN2c3ByZWQtZGczLnBuZykNCg0KDQohW2ltYWdlXShjb29rc2QtZGczLnBuZykNCg0KIVtpbWFnZV0obGV2ZXJhZ2UtZGczLnBuZykNCg0KIVtpbWFnZV0oaW5mbHVlbmNlLWRmZml0cy5wbmcpDQoNCiFbaW1hZ2VdKGluZmx1ZW5jZS1kZmJldGFzLnBuZykNCg0KIVtpbWFnZV0oZGlnbm9zdGljcy1kZzMucG5nKQ0KDQoNCiFbaW1hZ2VdKGxvZXNzc21vb3RoLWRnMy5wbmcpDQoNCg0K