set.seed(123)

Example 2.1: Munich Rent Index - Simple Linear Regression

Importing the dataset as in 01 Introduction.rmd, but using the R script available in import_data/munich_rent_index.R:

source("import_data/munich_rent_index.R")

Filtering by apartments build after 1966:

rent_1966 <- subset(munich_rent_index, yearc >= 1966)

summary(rent_1966)
      rent           rentsqm            area            yearc      location
 Min.   : 133.3   Min.   : 1.926   Min.   : 20.00   Min.   :1966   1:768   
 1st Qu.: 368.2   1st Qu.: 6.618   1st Qu.: 48.00   1st Qu.:1971   2:346   
 Median : 482.6   Median : 8.216   Median : 63.00   Median :1973   3: 37   
 Mean   : 508.7   Mean   : 8.242   Mean   : 63.92   Mean   :1978           
 3rd Qu.: 610.1   3rd Qu.: 9.783   3rd Qu.: 80.00   3rd Qu.:1984           
 Max.   :1517.9   Max.   :17.722   Max.   :154.00   Max.   :1997           
                                                                           
    bath          kitchen         cheating          district   
 Mode :logical   Mode :logical   Mode :logical   2024   :  28  
 FALSE:1050      FALSE:1070      FALSE:7         711    :  24  
 TRUE :101       TRUE :81        TRUE :1144      1012   :  21  
                                                 1013   :  21  
                                                 2221   :  21  
                                                 1942   :  16  
                                                 (Other):1020  

And use only average locations:

av_rent_1966 <- subset(rent_1966, location == 1)

summary(av_rent_1966)
      rent           rentsqm            area            yearc      location
 Min.   : 133.3   Min.   : 2.077   Min.   : 20.00   Min.   :1966   1:768   
 1st Qu.: 359.4   1st Qu.: 6.344   1st Qu.: 48.00   1st Qu.:1971   2:  0   
 Median : 466.3   Median : 7.892   Median : 63.00   Median :1972   3:  0   
 Mean   : 484.8   Mean   : 7.902   Mean   : 63.62   Mean   :1977           
 3rd Qu.: 578.6   3rd Qu.: 9.291   3rd Qu.: 79.00   3rd Qu.:1984           
 Max.   :1459.2   Max.   :14.872   Max.   :154.00   Max.   :1997           
                                                                           
    bath          kitchen         cheating          district  
 Mode :logical   Mode :logical   Mode :logical   2024   : 28  
 FALSE:714       FALSE:710       FALSE:1         1012   : 21  
 TRUE :54        TRUE :58        TRUE :767       1013   : 21  
                                                 2221   : 20  
                                                 1942   : 16  
                                                 1641   : 15  
                                                 (Other):647  

Then the simple linear regression model is given by

\[ \mathbb{E}({\text{rent}}) = \beta_{0} + \beta_{1} \cdot \text{area} \]

simple_model <- lm(rent ~ area, data = av_rent_1966)

summary(simple_model)

Call:
lm(formula = rent ~ area, data = av_rent_1966)

Residuals:
    Min      1Q  Median      3Q     Max 
-434.36  -81.23   -2.23   80.08  549.11 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 130.2334    14.2884   9.115   <2e-16 ***
area          5.5729     0.2133  26.128   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 123.9 on 766 degrees of freedom
Multiple R-squared:  0.4712,    Adjusted R-squared:  0.4705 
F-statistic: 682.7 on 1 and 766 DF,  p-value: < 2.2e-16
par(mfrow = c(1, 2))

plot(
  x = av_rent_1966$area,
  y = av_rent_1966$rent,
  xlab = 'area in sqm',
  ylab = 'net rent in Euro'
)

plot(
  x = av_rent_1966$area,
  y = av_rent_1966$rent,
  xlab = 'area in sqm',
  ylab = 'net rent in Euro'
)
abline(simple_model, col = "red", lwd=2)

Example 2.2: Munich Rent Index - Simple Linear Regression

Choosing the rent per square meter as response variable, we have the model:

\[ \mathbb{E}(\text{rent per sqm}) = \beta_{0} + \beta_{1} \cdot \text{area} \]

per_sqm_model <- lm(rentsqm ~ area, data = av_rent_1966)

summary(per_sqm_model)

Call:
lm(formula = rentsqm ~ area, data = av_rent_1966)

Residuals:
    Min      1Q  Median      3Q     Max 
-5.4874 -1.4274 -0.0734  1.2813  6.3396 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 10.497332   0.219984   47.72   <2e-16 ***
area        -0.040797   0.003284  -12.42   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.908 on 766 degrees of freedom
Multiple R-squared:  0.1677,    Adjusted R-squared:  0.1666 
F-statistic: 154.3 on 1 and 766 DF,  p-value: < 2.2e-16
plot(
  x = av_rent_1966$area,
  y = av_rent_1966$rentsqm,
  xlab = 'area in sqm',
  ylab = 'net rent per sqm'
)
abline(per_sqm_model, col = "red", lwd=2)

We change the variable

\[ x = \frac{1}{\text{area}} \]

Giving us the model:

\[ \mathbb{E}(\text{rent per sqm}) = \beta_{0} + \beta_{1} \cdot x = \beta_{0} + \beta_{1} \cdot \frac{1}{\text{area}} \]

av_rent_1966$inv_area <- 1 / av_rent_1966$area

per_sqm_inv_model <- lm(rentsqm ~ inv_area, data = av_rent_1966)

summary(per_sqm_inv_model)

Call:
lm(formula = rentsqm ~ inv_area, data = av_rent_1966)

Residuals:
    Min      1Q  Median      3Q     Max 
-5.5730 -1.4152 -0.0508  1.3200  6.2068 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   5.4449     0.1901   28.64   <2e-16 ***
inv_area    138.3266    10.0067   13.82   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.871 on 766 degrees of freedom
Multiple R-squared:  0.1997,    Adjusted R-squared:  0.1986 
F-statistic: 191.1 on 1 and 766 DF,  p-value: < 2.2e-16
plot(
  x = av_rent_1966$area,
  y = av_rent_1966$rentsqm,
  xlab = 'area in sqm',
  ylab = 'net rent per sqm'
)
x_seq <- seq(min(1 / av_rent_1966$area), max(1 / av_rent_1966$area), length.out = 100)
predicted <- predict(per_sqm_inv_model, newdata = data.frame(inv_area = x_seq))

lines(1 / x_seq, predicted, col = "red", lwd = 2)

Example 2.3: Munich Rent Index - Rent in Average and Good Localtions

We add the variable \(\text{good location}\) to the model:

\[ \mathbb{E}(\text{rent}) = \beta_{0} + \beta_{1} \cdot \text{area} + \beta_{2} \cdot \text{good localtion} \]

ag_rent_1966 <- subset(rent_1966, location %in% c(1, 2))
summary(ag_rent_1966)
      rent           rentsqm            area            yearc      location
 Min.   : 133.3   Min.   : 1.926   Min.   : 20.00   Min.   :1966   1:768   
 1st Qu.: 367.8   1st Qu.: 6.578   1st Qu.: 48.00   1st Qu.:1971   2:346   
 Median : 479.3   Median : 8.166   Median : 63.00   Median :1973   3:  0   
 Mean   : 502.0   Mean   : 8.201   Mean   : 63.53   Mean   :1978           
 3rd Qu.: 601.1   3rd Qu.: 9.727   3rd Qu.: 79.00   3rd Qu.:1984           
 Max.   :1517.9   Max.   :17.722   Max.   :154.00   Max.   :1997           
                                                                           
    bath          kitchen         cheating          district  
 Mode :logical   Mode :logical   Mode :logical   2024   : 28  
 FALSE:1020      FALSE:1035      FALSE:6         711    : 24  
 TRUE :94        TRUE :79        TRUE :1108      1012   : 21  
                                                 1013   : 21  
                                                 2221   : 21  
                                                 1942   : 16  
                                                 (Other):983  
ag_rent_1966$glocation <- ag_rent_1966$location == 2
summary(ag_rent_1966)
      rent           rentsqm            area            yearc      location
 Min.   : 133.3   Min.   : 1.926   Min.   : 20.00   Min.   :1966   1:768   
 1st Qu.: 367.8   1st Qu.: 6.578   1st Qu.: 48.00   1st Qu.:1971   2:346   
 Median : 479.3   Median : 8.166   Median : 63.00   Median :1973   3:  0   
 Mean   : 502.0   Mean   : 8.201   Mean   : 63.53   Mean   :1978           
 3rd Qu.: 601.1   3rd Qu.: 9.727   3rd Qu.: 79.00   3rd Qu.:1984           
 Max.   :1517.9   Max.   :17.722   Max.   :154.00   Max.   :1997           
                                                                           
    bath          kitchen         cheating          district   glocation      
 Mode :logical   Mode :logical   Mode :logical   2024   : 28   Mode :logical  
 FALSE:1020      FALSE:1035      FALSE:6         711    : 24   FALSE:768      
 TRUE :94        TRUE :79        TRUE :1108      1012   : 21   TRUE :346      
                                                 1013   : 21                  
                                                 2221   : 21                  
                                                 1942   : 16                  
                                                 (Other):983                  
good_model <- lm(rent ~ area + glocation, data = ag_rent_1966)
summary(good_model)

Call:
lm(formula = rent ~ area + glocation, data = ag_rent_1966)

Residuals:
    Min      1Q  Median      3Q     Max 
-497.96  -82.28    0.42   81.37  611.07 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)    112.686     12.973   8.686  < 2e-16 ***
area             5.849      0.189  30.942  < 2e-16 ***
glocationTRUE   57.261      8.727   6.561 8.15e-11 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 134.8 on 1111 degrees of freedom
Multiple R-squared:  0.4732,    Adjusted R-squared:  0.4722 
F-statistic: 498.9 on 2 and 1111 DF,  p-value: < 2.2e-16
par(mfrow = c(2, 2))

colors <- c("black", "red")

plot(
    x = ag_rent_1966$area,
    y = ag_rent_1966$rent,
    xlab = 'area in sqm',
    ylab = 'net rent in Euro',
    col = colors[as.numeric(ag_rent_1966$location)]
)

legend(
  "topleft",
  legend = c('average', 'good'),
  col = colors,
  pch = 19
)

g_rent_1966 <- subset(rent_1966, location == 2)
simple_good_model <- lm(rent ~ area, data = g_rent_1966)

plot(NA, xlim = range(rent_1966$area), ylim = range(rent_1966$rent), xlab = 'area in sqm', ylab = 'estimated net rent')
abline(simple_model)
abline(simple_good_model, col = "red", lwd = 2)

legend(
  "topleft",
  legend = c('average', 'good'),
  col = c('black', 'red'),
  lwd = 2
)

plot(NA, xlim = range(rent_1966$area), ylim = range(rent_1966$rent), xlab = 'area in sqm', ylab = 'esimated net rent')

beta <- good_model$coefficients

abline(beta[1], beta[2])
abline(beta[1] + beta[3], beta[2], col = "red", lwd = 2)

legend(
  "topleft",
  legend = c('average', 'good'),
  col = c('black', 'red'),
  lwd = 2
)

Example 2.4 Munich Rent Index — Nonlinear Influence of Living Area

We add the good location dummy variable to the model of example 2.2:

\[ \mathbb{E}(\text{rent per sqm}) = \beta_{0} + \beta_{1} \cdot \frac{1}{\text{area}} + \beta_{2} \cdot \text{good location} \]

g_multiple_model <- lm(rentsqm ~ I(1/area) + glocation, data = ag_rent_1966)
summary(g_multiple_model)

Call:
lm(formula = rentsqm ~ I(1/area) + glocation, data = ag_rent_1966)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.1795 -1.4137 -0.0329  1.3489  8.5672 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)     5.5090     0.1668  33.028  < 2e-16 ***
I(1/area)     134.7204     8.4686  15.908  < 2e-16 ***
glocationTRUE   0.8961     0.1295   6.922 7.53e-12 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.998 on 1111 degrees of freedom
Multiple R-squared:  0.2173,    Adjusted R-squared:  0.2159 
F-statistic: 154.2 on 2 and 1111 DF,  p-value: < 2.2e-16
par(mfrow = c(1, 2))

colors <- c("black", "red")

plot(
    x = ag_rent_1966$area,
    y = ag_rent_1966$rentsqm,
    xlab = 'area in sqm',
    ylab = 'net rent in Euro',
    col = colors[as.numeric(ag_rent_1966$location)]
)

legend(
  "topleft",
  legend = c('average', 'good'),
  col = colors,
  pch = 19
)

plot(NA, xlim = range(rent_1966$area), ylim = range(rent_1966$rentsqm), xlab = 'area in sqm', ylab = 'esimated net rent per sqm')

x_seq <- seq(min(ag_rent_1966$area), max(ag_rent_1966$area), length.out = 100)
beta <- g_multiple_model$coefficients

lines(x_seq, beta[1] + beta[2] * (1/x_seq), col = 'black', lwd = 2)
lines(x_seq, beta[1] + beta[2] * (1/x_seq) + beta[3], col = 'red', lwd = 2)

legend(
  "topleft",
  legend = c('average', 'good'),
  col = c('black', 'red'),
  lwd = 2
)

Example 2.5 Munich Rent Index — Interaction Between Living Area and Location

Adding the interaction term between area and good location:

\[ \mathbb{E}(\text{rent}) = \beta_{0} + \beta_{1} \cdot \text{area} + \beta_{2} \cdot \text{good location} + \beta_{3} \cdot \text{interaction} \]

ag_rent_1966$inter <- ag_rent_1966$area * as.numeric(ag_rent_1966$glocation)

summary(ag_rent_1966$inter)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00    0.00    0.00   19.67   41.00  132.00 
g_inter_model <- lm(rent ~ area + glocation + inter, data = ag_rent_1966)
summary(g_inter_model)

Call:
lm(formula = rent ~ area + glocation + inter, data = ag_rent_1966)

Residuals:
    Min      1Q  Median      3Q     Max 
-520.67  -81.88   -1.22   80.68  576.91 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)   130.2334    15.5173   8.393   <2e-16 ***
area            5.5729     0.2316  24.058   <2e-16 ***
glocationTRUE   5.2053    26.7999   0.194   0.8460    
inter           0.8208     0.3996   2.054   0.0402 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 134.6 on 1110 degrees of freedom
Multiple R-squared:  0.4752,    Adjusted R-squared:  0.4737 
F-statistic:   335 on 3 and 1110 DF,  p-value: < 2.2e-16
plot(NA, xlim = range(ag_rent_1966$area), ylim = range(ag_rent_1966$rent), xlab = 'area in sqm', ylab = 'esimated net rent')

x_seq <- seq(min(ag_rent_1966$area), max(ag_rent_1966$area), length.out = 100)
beta <- g_inter_model$coefficients

lines(x_seq, beta[1] + beta[2] * x_seq, col = 'black', lwd = 2)
lines(x_seq, beta[1] + (beta[2] + beta[4]) * x_seq + beta[3], col = 'red', lwd = 2)

legend(
  "topleft",
  legend = c('average', 'good'),
  col = c('black', 'red'),
  lwd = 2
)

Example 2.6 Munich Rent Index — Multiple Regression Model

Now we add the top location (\(\text{location} = 3\)):

munich_rent_index$glocation <- munich_rent_index$location == 2
munich_rent_index$tlocation <- munich_rent_index$location == 3
summary(munich_rent_index)
      rent            rentsqm             area            yearc      location
 Min.   :  40.51   Min.   : 0.4158   Min.   : 20.00   Min.   :1918   1:1794  
 1st Qu.: 322.03   1st Qu.: 5.2610   1st Qu.: 51.00   1st Qu.:1939   2:1210  
 Median : 426.97   Median : 6.9802   Median : 65.00   Median :1959   3:  78  
 Mean   : 459.44   Mean   : 7.1113   Mean   : 67.37   Mean   :1956           
 3rd Qu.: 559.36   3rd Qu.: 8.8408   3rd Qu.: 81.00   3rd Qu.:1972           
 Max.   :1843.38   Max.   :17.7216   Max.   :160.00   Max.   :1997           
                                                                             
    bath          kitchen         cheating          district    glocation      
 Mode :logical   Mode :logical   Mode :logical   411    :  53   Mode :logical  
 FALSE:2891      FALSE:2951      FALSE:321       623    :  53   FALSE:1872     
 TRUE :191       TRUE :131       TRUE :2761      350    :  49   TRUE :1210     
                                                 563    :  49                  
                                                 711    :  42                  
                                                 360    :  38                  
                                                 (Other):2798                  
 tlocation      
 Mode :logical  
 FALSE:3004     
 TRUE :78       
                
                
                
                

A multiple model with all available variables:

\[ \begin{matrix} \mathbb{E}(\text{rentsqm}) = & \beta_{0} + \beta_{1} \cdot \frac{1}{\text{area}} + \beta_{2} \cdot \text{yearc} + \beta_{3} \cdot \text{yearc}^2 + \beta_{4} \cdot \text{good location} + \beta_{5} \cdot \text{top location} \\ & + \beta_{6} \cdot \text{bath} + \beta_{7} \cdot \text{kitchen} + \beta_{8} \cdot \text{cheating} \\ \end{matrix} \]

multiple_model <- lm(rentsqm ~ I(1/area) + yearc + I(yearc^2) + glocation + tlocation + bath + kitchen + cheating, data = munich_rent_index)
summary(multiple_model)

Call:
lm(formula = rentsqm ~ I(1/area) + yearc + I(yearc^2) + glocation + 
    tlocation + bath + kitchen + cheating, data = munich_rent_index)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.0080 -1.2651 -0.0558  1.2261  8.0095 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)    3.685e+03  2.681e+02  13.745  < 2e-16 ***
I(1/area)      1.375e+02  5.303e+00  25.929  < 2e-16 ***
yearc         -3.801e+00  2.747e-01 -13.838  < 2e-16 ***
I(yearc^2)     9.805e-04  7.033e-05  13.941  < 2e-16 ***
glocationTRUE  6.795e-01  7.276e-02   9.340  < 2e-16 ***
tlocationTRUE  1.519e+00  2.227e-01   6.819 1.10e-11 ***
bathTRUE       5.027e-01  1.472e-01   3.416 0.000644 ***
kitchenTRUE    8.665e-01  1.752e-01   4.945 8.02e-07 ***
cheatingTRUE   1.870e+00  1.229e-01  15.225  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.921 on 3073 degrees of freedom
Multiple R-squared:   0.38, Adjusted R-squared:  0.3783 
F-statistic: 235.4 on 8 and 3073 DF,  p-value: < 2.2e-16
par(mfrow = c(1, 2))

plot(
    x = munich_rent_index$area,
    y = munich_rent_index$rentsqm,
    xlab = 'area in sqm',
    ylab = 'estimated net rent in Euro',
)

area_seq <- seq(min(munich_rent_index$area), max(munich_rent_index$area), length.out = 100)
beta <- multiple_model$coefficients

constant <- beta[5] * mean(as.numeric(munich_rent_index$glocation)) + 
  beta[6] * mean(as.numeric(munich_rent_index$tlocation)) + 
  beta[7] * mean(as.numeric(munich_rent_index$bath)) + 
  beta[8] * mean(as.numeric(munich_rent_index$kitchen)) + 
  beta[9] * mean(as.numeric(munich_rent_index$cheating))

year_constant <- beta[3] * mean(munich_rent_index$yearc) + beta[4] * mean(munich_rent_index$yearc^2)

lines(area_seq, beta[1] + beta[2] * (1 / area_seq) + constant + year_constant, col = 'red', lwd = 2)

plot(
    x = munich_rent_index$yearc,
    y = munich_rent_index$rentsqm,
    xlab = 'year of construction',
    ylab = 'estimated net rent in Euro',
)

area_constant <- beta[2] * mean(1 / munich_rent_index$area)

year_seq <- seq(min(munich_rent_index$yearc), max(munich_rent_index$yearc), length.out = 100)
lines(year_seq, beta[1] + beta[3] * year_seq + beta[4] * year_seq^2 + constant + area_constant, col = 'red', lwd = 2)

Example 2.7 Patent Opposition

Import the patent opposition from script:

source("import_data/patent_opposition.R")

We left the \(\text{opp}\) dataset as integer, so we can model the response variable as binary:

patent_opposition$opp <- as.integer(patent_opposition$opp == 1)
summary(patent_opposition$opp)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.0000  0.0000  0.4149  1.0000  1.0000 

Example 2.8: Patent Opposition

We explore the histogram of claims (\(\text{nclaims}\)) and citations (\(\text{ncit}\)):

par(mfrow = c(1, 2))

hist(patent_opposition$nclaims, ylab = 'estimated density', xlab = 'number of claims', freq = FALSE)
lines(density(patent_opposition$nclaims), col = 'red', lwd = 2)

hist(patent_opposition$ncit, ylab = 'estimated density', xlab = 'number of citations', freq = FALSE)
lines(density(patent_opposition$ncit), col = 'red', lwd = 2)

We then subset the dataset to exclude \(\text{nclaims} \leq 60\) and \(\text{ncit} \leq 15\). And also extract the biopharmacological ones (\(\text{biopharm} == 0\)):

deoutlier_patent_opp <- subset(patent_opposition, nclaims <= 60 & ncit <= 15)
not_biopharm_patent_opp <- subset(deoutlier_patent_opp, biopharm == 0)
summary(not_biopharm_patent_opp)
      opp         biopharm         ustwin          patus        
 Min.   :0.000   Mode :logical   Mode :logical   Mode :logical  
 1st Qu.:0.000   FALSE:2702      FALSE:719       FALSE:1886     
 Median :0.000                   TRUE :1983      TRUE :816      
 Mean   :0.282                                                  
 3rd Qu.:1.000                                                  
 Max.   :1.000                                                  
  patgsgr             year           ncit           ncountry     
 Mode :logical   Min.   :1980   Min.   : 0.000   Min.   : 1.000  
 FALSE:2118      1st Qu.:1988   1st Qu.: 0.000   1st Qu.: 3.000  
 TRUE :584       Median :1992   Median : 1.000   Median : 4.000  
                 Mean   :1991   Mean   : 1.387   Mean   : 5.329  
                 3rd Qu.:1994   3rd Qu.: 2.000   3rd Qu.: 6.000  
                 Max.   :1997   Max.   :14.000   Max.   :17.000  
    nclaims     
 Min.   : 1.00  
 1st Qu.: 6.00  
 Median : 9.00  
 Mean   :10.84  
 3rd Qu.:13.00  
 Max.   :60.00  

We then fit the logistic regression model:

\[ P(\text{opp}_{i} = 1) = \frac{\exp(\eta_{i})}{1 + \exp(\eta_{i})} \]

\[ \eta_{i} = \beta_{0} + \beta_{1} \cdot \text{year}_{i} + \beta_{2} \cdot \text{ncit}_{i} + \beta_{3} \cdot \text{nclaims}_{i} + \beta_{4} \cdot \text{ustwin}_{i} + \beta_{5} \cdot \text{patus}_{i} + \beta_{6} \cdot \text{patgsgr}_{i} + \beta_{7} \cdot \text{ncountry}_{i} \]

pat_opp_model <- glm(opp ~ year + ncit + nclaims + ustwin + patus + patgsgr + ncountry, data = not_biopharm_patent_opp, family = binomial)
summary(pat_opp_model)

Call:
glm(formula = opp ~ year + ncit + nclaims + ustwin + patus + 
    patgsgr + ncountry, family = binomial, data = not_biopharm_patent_opp)

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept) 201.739764  22.321279   9.038  < 2e-16 ***
year         -0.102127   0.011217  -9.105  < 2e-16 ***
ncit          0.113558   0.022304   5.091 3.55e-07 ***
nclaims       0.026575   0.005922   4.488 7.20e-06 ***
ustwinTRUE   -0.402600   0.099963  -4.028 5.64e-05 ***
patusTRUE    -0.526343   0.112599  -4.675 2.95e-06 ***
patgsgrTRUE   0.196654   0.117388   1.675   0.0939 .  
ncountry      0.097517   0.014897   6.546 5.91e-11 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 3214.5  on 2701  degrees of freedom
Residual deviance: 2977.1  on 2694  degrees of freedom
AIC: 2993.1

Number of Fisher Scoring iterations: 4

We then generate the table of odd ratios:

pat_opp_odd_ratios <- cbind(pat_opp_model$coefficients, 0)
colnames(pat_opp_odd_ratios) <- c('Estimated Coefficients', 'Estimated Odd Ratios')
pat_opp_odd_ratios[, 2] <- exp(pat_opp_odd_ratios[, 1])
pat_opp_odd_ratios[1, 2] <- NA
pat_opp_odd_ratios
            Estimated Coefficients Estimated Odd Ratios
(Intercept)           201.73976353                   NA
year                   -0.10212685            0.9029150
ncit                    0.11355777            1.1202566
nclaims                 0.02657537            1.0269316
ustwinTRUE             -0.40260010            0.6685794
patusTRUE              -0.52634315            0.5907614
patgsgrTRUE             0.19665401            1.2173228
ncountry                0.09751730            1.1024305

Then we repeeat the process with the \(\text{ncountry}\) variable as a polynomial:

\[ \begin{matrix} \eta_{i} = & \beta_{0} + \beta_{1} \cdot \text{year}_{i} + \beta_{2} \cdot \text{ncit}_{i} + \beta_{3} \cdot \text{nclaims}_{i} + \beta_{4} \cdot \text{ustwin}_{i} + \beta_{5} \cdot \text{patus}_{i} + \beta_{6} \cdot \text{patgsgr}_{i} \\ & + \beta_{7} \cdot \text{ncountry}_{i} + \beta_{8} \cdot \text{ncountry}_{i}^{2} + \beta_{9} \cdot \text{ncountry}_{i}^{3} \end{matrix} \]

pat_opp_poly_model <- glm(opp ~ year + ncit + nclaims + ustwin + patus + patgsgr + ncountry + I(ncountry ^ 2) + I(ncountry ^ 3), data = not_biopharm_patent_opp, family = binomial)
summary(pat_opp_poly_model)

Call:
glm(formula = opp ~ year + ncit + nclaims + ustwin + patus + 
    patgsgr + ncountry + I(ncountry^2) + I(ncountry^3), family = binomial, 
    data = not_biopharm_patent_opp)

Coefficients:
                Estimate Std. Error z value Pr(>|z|)    
(Intercept)    1.981e+02  2.274e+01   8.713  < 2e-16 ***
year          -1.006e-01  1.141e-02  -8.821  < 2e-16 ***
ncit           1.134e-01  2.231e-02   5.085 3.68e-07 ***
nclaims        2.639e-02  5.936e-03   4.445 8.78e-06 ***
ustwinTRUE    -4.090e-01  1.001e-01  -4.085 4.40e-05 ***
patusTRUE     -5.393e-01  1.131e-01  -4.769 1.85e-06 ***
patgsgrTRUE    1.805e-01  1.191e-01   1.516    0.130    
ncountry       3.938e-01  1.836e-01   2.145    0.032 *  
I(ncountry^2) -3.782e-02  2.387e-02  -1.584    0.113    
I(ncountry^3)  1.404e-03  9.373e-04   1.498    0.134    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 3214.5  on 2701  degrees of freedom
Residual deviance: 2974.5  on 2692  degrees of freedom
AIC: 2994.5

Number of Fisher Scoring iterations: 4
par(mfrow = c(1, 2))
beta <- pat_opp_model$coefficients
constant <- beta[1] +
  beta[2] * mean(not_biopharm_patent_opp$year) +
  beta[3] * mean(not_biopharm_patent_opp$ncit) +
  beta[4] * mean(not_biopharm_patent_opp$nclaims) +
  beta[5] * mean(as.numeric(not_biopharm_patent_opp$ustwin)) +
  beta[6] * mean(as.numeric(not_biopharm_patent_opp$patus)) +
  beta[7] * mean(as.numeric(not_biopharm_patent_opp$patgsgr))

beta_poly <- pat_opp_poly_model$coefficients
poly_constant <- beta_poly[1] +
  beta_poly[2] * mean(not_biopharm_patent_opp$year) +
  beta_poly[3] * mean(not_biopharm_patent_opp$ncit) +
  beta_poly[4] * mean(not_biopharm_patent_opp$nclaims) +
  beta_poly[5] * mean(as.numeric(not_biopharm_patent_opp$ustwin)) +
  beta_poly[6] * mean(as.numeric(not_biopharm_patent_opp$patus)) +
  beta_poly[7] * mean(as.numeric(not_biopharm_patent_opp$patgsgr))

ncountry_seq <- seq(min(not_biopharm_patent_opp$ncountry), max(not_biopharm_patent_opp$ncountry), length.out = 100)
effect <- constant + beta[8] * ncountry_seq
poly_effect <- poly_constant + beta_poly[8] * ncountry_seq + beta_poly[9] * ncountry_seq ^ 2 + beta_poly[10] * ncountry_seq ^ 3
plot(
  NA,
  xlim = range(not_biopharm_patent_opp$ncountry),
  ylim = range(poly_effect),
  xlab = 'number of designated states for the patent',
  ylab = 'estimated effect'
)
lines(ncountry_seq, poly_effect)
lines(ncountry_seq, effect, col = 'red', lwd = 2)

legend(
  "topleft",
  legend = c("polynomial", "linear"),
  col = c("black", "red"),
  lwd = 2
)

poly_prob <- exp(poly_effect) / (1 + exp(poly_effect))
plot(
  NA,
  xlim  = range(not_biopharm_patent_opp$ncountry),
  ylim = range(poly_prob),
  xlab = 'number of designated states for the patent',
  ylab = 'estimated probability'
)
lines(ncountry_seq, poly_prob)
prob <- exp(effect) / (1 + exp(effect))
lines(ncountry_seq, prob, col = 'red', lwd = 2)
legend(
  "topleft",
  legend = c("polynomial", "linear"),
  col = c("black", "red"),
  lwd = 2
)

Example 2.9 Hormone Therapy with Rats

We import the Hormone Therapy with Rats dataset from the oficial page of the dataset, as the other example:

rats_url <- "https://www.uni-goettingen.de/de/document/download/3ac5a038b19297fb8609dfc28319cbb7.raw/rats.raw"

rats_dataset <- read.table(
  url(rats_url),
  header = 1,
  colClasses = c(
    "factor", "factor", "numeric",
    "integer", "numeric", "numeric",
    "factor", "factor", "factor",
    "numeric", "numeric", "numeric" 
  )
)
rats_dataset$low <- rats_dataset$low == 1
rats_dataset$high <- rats_dataset$high == 1
rats_dataset$control <- rats_dataset$control == 1
summary(rats_dataset)
    subject    group      response          time      transf_time    
 1      :  7   1:126   Min.   :66.60   Min.   : 50   Min.   :0.4055  
 10     :  7   2:119   1st Qu.:74.62   1st Qu.: 60   1st Qu.:0.9163  
 11     :  7   3:105   Median :77.88   Median : 80   Median :1.5041  
 12     :  7           Mean   :77.53   Mean   : 80   Mean   :1.3814  
 13     :  7           3rd Qu.:81.02   3rd Qu.:100   3rd Qu.:1.8718  
 14     :  7           Max.   :86.83   Max.   :110   Max.   :2.0149  
 (Other):308           NA's   :98                                    
      eff              low             high          control       
 Min.   :-0.90260   Mode :logical   Mode :logical   Mode :logical  
 1st Qu.:-0.90260   FALSE:224       FALSE:231       FALSE:245      
 Median : 0.17801   TRUE :126       TRUE :119       TRUE :105      
 Mean   :-0.00475                                                  
 3rd Qu.: 0.72833                                                  
 Max.   : 0.72833                                                  
 NA's   :98                                                        
    lowtime          hightime       controltime    
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.0000   Median :0.0000   Median :0.0000  
 Mean   :0.4973   Mean   :0.4697   Mean   :0.4144  
 3rd Qu.:1.2528   3rd Qu.:0.9163   3rd Qu.:0.9163  
 Max.   :2.0149   Max.   :2.0149   Max.   :2.0149  
                                                   

We plot the timeseries of the rats divided in the three groups: control, low and high dose:

par(mfrow = c(3, 1))

control_rats <- subset(rats_dataset, control)
low_rats <- subset(rats_dataset, low)
high_rats <- subset(rats_dataset, high)

library(viridis)
Loading required package: viridisLite
plot_rats_subsets <- function(rats_subset, title) {
  plot(
    NA,
    xlim = range(rats_dataset$time),
    ylim = range(na.omit(rats_dataset$response)),
    xlab = "age in days",
    ylab = "response",
    main = title
  )
  subjects <- unique(rats_subset$subject)
  for (i in seq_along(subjects)) {
    colors <- length(subjects)
    lines(
      subset(rats_subset, subject == subjects[i])$time,
      subset(rats_subset, subject == subjects[i])$response,
      col = viridis(colors)[i]
    )
  }
}

plot_rats_subsets(control_rats, "control group")
plot_rats_subsets(low_rats, "low dose")
plot_rats_subsets(high_rats, "high dose")

We add the transformed age:

\[ t = \log(1 + (\text{age} - 45) / 10) \]

rats_dataset$t <- log(1 + (rats_dataset$time - 45) / 10)
rats_dataset$C <- as.integer(rats_dataset$control)
rats_dataset$L <- as.integer(rats_dataset$low)
rats_dataset$H <- as.integer(rats_dataset$high)
summary(rats_dataset)
    subject    group      response          time      transf_time    
 1      :  7   1:126   Min.   :66.60   Min.   : 50   Min.   :0.4055  
 10     :  7   2:119   1st Qu.:74.62   1st Qu.: 60   1st Qu.:0.9163  
 11     :  7   3:105   Median :77.88   Median : 80   Median :1.5041  
 12     :  7           Mean   :77.53   Mean   : 80   Mean   :1.3814  
 13     :  7           3rd Qu.:81.02   3rd Qu.:100   3rd Qu.:1.8718  
 14     :  7           Max.   :86.83   Max.   :110   Max.   :2.0149  
 (Other):308           NA's   :98                                    
      eff              low             high          control       
 Min.   :-0.90260   Mode :logical   Mode :logical   Mode :logical  
 1st Qu.:-0.90260   FALSE:224       FALSE:231       FALSE:245      
 Median : 0.17801   TRUE :126       TRUE :119       TRUE :105      
 Mean   :-0.00475                                                  
 3rd Qu.: 0.72833                                                  
 Max.   : 0.72833                                                  
 NA's   :98                                                        
    lowtime          hightime       controltime           t         
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.4055  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.9163  
 Median :0.0000   Median :0.0000   Median :0.0000   Median :1.5041  
 Mean   :0.4973   Mean   :0.4697   Mean   :0.4144   Mean   :1.3814  
 3rd Qu.:1.2528   3rd Qu.:0.9163   3rd Qu.:0.9163   3rd Qu.:1.8718  
 Max.   :2.0149   Max.   :2.0149   Max.   :2.0149   Max.   :2.0149  
                                                                    
       C             L              H       
 Min.   :0.0   Min.   :0.00   Min.   :0.00  
 1st Qu.:0.0   1st Qu.:0.00   1st Qu.:0.00  
 Median :0.0   Median :0.00   Median :0.00  
 Mean   :0.3   Mean   :0.36   Mean   :0.34  
 3rd Qu.:1.0   3rd Qu.:1.00   3rd Qu.:1.00  
 Max.   :1.0   Max.   :1.00   Max.   :1.00  
                                            

And we fit the model:

\[ y_{ij} = \beta_{0} + \gamma_{0i} + \beta_{1} L_{i} \cdot t_{ij} + \beta_{2} H_{i} \cdot t_{ij} + \beta_{3} C_{i} \cdot t_{ij} + \gamma_{1i} \cdot t_{ij} + \epsilon_{ij} \]

With \(\epsilon_{ij} \sim N(0, \sigma^2)\) as in all these examples. And \(\gamma_{0i}\) and \(\gamma_{1i}\) are random effects associated with the subjects following:

\[ \gamma_{0i} \sim N(0, \tau_{0}^2) \wedge \gamma_{1i} \sim N(0, \tau_{1}^2) \]

Example 2.10 Hormone Therapy with Rats

library(lme4)
Loading required package: Matrix
rats_model <- lmer(
  response ~ L:t + H:t + C:t + (1 + t | subject), data = rats_dataset
)
boundary (singular) fit: see help('isSingular')
summary(rats_model)
Linear mixed model fit by REML ['lmerMod']
Formula: response ~ L:t + H:t + C:t + (1 + t | subject)
   Data: rats_dataset

REML criterion at convergence: 932.4

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.25589 -0.66674 -0.01327  0.58310  2.89228 

Random effects:
 Groups   Name        Variance Std.Dev. Corr
 subject  (Intercept) 3.429240 1.85182      
          t           0.001081 0.03288  1.00
 Residual             1.444602 1.20192      
Number of obs: 252, groups:  subject, 50

Fixed effects:
            Estimate Std. Error t value
(Intercept)  68.6061     0.3272  209.70
L:t           7.5045     0.2274   32.99
t:H           6.8750     0.2301   29.88
t:C           7.3178     0.2836   25.80

Correlation of Fixed Effects:
    (Intr) L:t    t:H   
L:t -0.336              
t:H -0.325  0.109       
t:C -0.316  0.106  0.103
optimizer (nloptwrap) convergence code: 0 (OK)
boundary (singular) fit: see help('isSingular')

And the simpler model eliminating the subject-specific term \(\tau_{1i} \cdot t_{ij}\):

\[ y_{ij} = \beta_{0} + \gamma_{0i} + \beta_{1} L_{i} \cdot t_{ij} + \beta_{2} H_{i} \cdot t_{ij} + \beta_{3} C_{i} \cdot t_{ij} + \epsilon_{ij} \]

simple_rats_model <- lmer(
  response ~ L:t + H:t + C:t + (1 | subject), data = rats_dataset
)
summary(simple_rats_model)
Linear mixed model fit by REML ['lmerMod']
Formula: response ~ L:t + H:t + C:t + (1 | subject)
   Data: rats_dataset

REML criterion at convergence: 932.4

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.25575 -0.65899 -0.01164  0.58358  2.88309 

Random effects:
 Groups   Name        Variance Std.Dev.
 subject  (Intercept) 3.565    1.888   
 Residual             1.445    1.202   
Number of obs: 252, groups:  subject, 50

Fixed effects:
            Estimate Std. Error t value
(Intercept)  68.6074     0.3312  207.13
L:t           7.5069     0.2252   33.34
t:H           6.8711     0.2276   30.19
t:C           7.3139     0.2808   26.05

Correlation of Fixed Effects:
    (Intr) L:t    t:H   
L:t -0.351              
t:H -0.340  0.119       
t:C -0.327  0.115  0.111

We then plot a kernel density estimator with a normal distribution for those values. Alongside a normal quantity plot:

par(mfrow = c(1, 2))
tau_0i <- ranef(rats_model)$subject[, 1]

kde <- density(tau_0i)

tau_seq <- seq(min(kde$x), max(kde$x), length.out = 100)

plot(
  x = tau_seq,
  y = dnorm(tau_seq, mean = mean(tau_0i), sd = sd(tau_0i)),
  type = 'l',
  main = 'random intercept',
  xlab = 'random intercept',
  ylab = 'density',
  col = 'red',
  lwd = 2
)

lines(
  x = kde$x,
  y = kde$y,
  col = 'black',
  lwd = 2
)

legend(
  'topleft',
  legend = c('kde', 'adapted normal'),
  col = c('black', 'red'),
  lwd = 2
)

qqnorm(
  tau_0i, 
  main = 'random intercept',
  xlab = 'quantiles of normal distribution',
  ylab = 'random intercept',
  pch = 19,
  col = "darkblue"
)

# Add reference line
qqline(
  tau_0i,
  col = "black", 
  lwd = 2
)

Example 2.11 Malnutrition in Zambia

Import data from script:

source("import_data/malnutrition_zambia.R")

To be continued…

LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBNb2RlbHMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpzZXQuc2VlZCgxMjMpCmBgYAoKIyMgRXhhbXBsZSAyLjE6IE11bmljaCBSZW50IEluZGV4IC0gU2ltcGxlIExpbmVhciBSZWdyZXNzaW9uCgpJbXBvcnRpbmcgdGhlIGRhdGFzZXQgYXMgaW4gWzAxIEludHJvZHVjdGlvbi5ybWRdKDAxLUludHJvZHVjdGlvbi5uYi5odG1sKSwgYnV0IHVzaW5nIHRoZSBSIHNjcmlwdCBhdmFpbGFibGUgaW4gW2BpbXBvcnRfZGF0YS9tdW5pY2hfcmVudF9pbmRleC5SYF0oaW1wb3J0X2RhdGEvbXVuaWNoX3JlbnRfaW5kZXguUik6CgpgYGB7cn0Kc291cmNlKCJpbXBvcnRfZGF0YS9tdW5pY2hfcmVudF9pbmRleC5SIikKYGBgCgpGaWx0ZXJpbmcgYnkgYXBhcnRtZW50cyBidWlsZCBhZnRlciAxOTY2OgoKYGBge3J9CnJlbnRfMTk2NiA8LSBzdWJzZXQobXVuaWNoX3JlbnRfaW5kZXgsIHllYXJjID49IDE5NjYpCgpzdW1tYXJ5KHJlbnRfMTk2NikKYGBgCgpBbmQgdXNlIG9ubHkgYXZlcmFnZSBsb2NhdGlvbnM6CgpgYGB7cn0KYXZfcmVudF8xOTY2IDwtIHN1YnNldChyZW50XzE5NjYsIGxvY2F0aW9uID09IDEpCgpzdW1tYXJ5KGF2X3JlbnRfMTk2NikKYGBgCgpUaGVuIHRoZSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgaXMgZ2l2ZW4gYnkKCiQkClxtYXRoYmJ7RX0oe1x0ZXh0e3JlbnR9fSkgPSBcYmV0YV97MH0gKyBcYmV0YV97MX0gXGNkb3QgXHRleHR7YXJlYX0KJCQKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NCwgZmlnLmFsaWduPSdjZW50ZXInfQpzaW1wbGVfbW9kZWwgPC0gbG0ocmVudCB+IGFyZWEsIGRhdGEgPSBhdl9yZW50XzE5NjYpCgpzdW1tYXJ5KHNpbXBsZV9tb2RlbCkKCnBhcihtZnJvdyA9IGMoMSwgMikpCgpwbG90KAogIHggPSBhdl9yZW50XzE5NjYkYXJlYSwKICB5ID0gYXZfcmVudF8xOTY2JHJlbnQsCiAgeGxhYiA9ICdhcmVhIGluIHNxbScsCiAgeWxhYiA9ICduZXQgcmVudCBpbiBFdXJvJwopCgpwbG90KAogIHggPSBhdl9yZW50XzE5NjYkYXJlYSwKICB5ID0gYXZfcmVudF8xOTY2JHJlbnQsCiAgeGxhYiA9ICdhcmVhIGluIHNxbScsCiAgeWxhYiA9ICduZXQgcmVudCBpbiBFdXJvJwopCmFibGluZShzaW1wbGVfbW9kZWwsIGNvbCA9ICJyZWQiLCBsd2Q9MikKYGBgCgojIyBFeGFtcGxlIDIuMjogTXVuaWNoIFJlbnQgSW5kZXggLSBTaW1wbGUgTGluZWFyIFJlZ3Jlc3Npb24KCkNob29zaW5nIHRoZSByZW50IHBlciBzcXVhcmUgbWV0ZXIgYXMgcmVzcG9uc2UgdmFyaWFibGUsIHdlIGhhdmUgdGhlIG1vZGVsOgoKJCQKXG1hdGhiYntFfShcdGV4dHtyZW50IHBlciBzcW19KSA9IFxiZXRhX3swfSArIFxiZXRhX3sxfSBcY2RvdCBcdGV4dHthcmVhfQokJAoKYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTQsIGZpZy5hbGlnbj0nY2VudGVyJ30KcGVyX3NxbV9tb2RlbCA8LSBsbShyZW50c3FtIH4gYXJlYSwgZGF0YSA9IGF2X3JlbnRfMTk2NikKCnN1bW1hcnkocGVyX3NxbV9tb2RlbCkKCnBsb3QoCiAgeCA9IGF2X3JlbnRfMTk2NiRhcmVhLAogIHkgPSBhdl9yZW50XzE5NjYkcmVudHNxbSwKICB4bGFiID0gJ2FyZWEgaW4gc3FtJywKICB5bGFiID0gJ25ldCByZW50IHBlciBzcW0nCikKYWJsaW5lKHBlcl9zcW1fbW9kZWwsIGNvbCA9ICJyZWQiLCBsd2Q9MikKYGBgCgpXZSBjaGFuZ2UgdGhlIHZhcmlhYmxlCgokJAp4ID0gXGZyYWN7MX17XHRleHR7YXJlYX19CiQkCgpHaXZpbmcgdXMgdGhlIG1vZGVsOgoKJCQKXG1hdGhiYntFfShcdGV4dHtyZW50IHBlciBzcW19KSA9IFxiZXRhX3swfSArIFxiZXRhX3sxfSBcY2RvdCB4ID0gXGJldGFfezB9ICsgXGJldGFfezF9IFxjZG90IFxmcmFjezF9e1x0ZXh0e2FyZWF9fQokJAoKYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTQsIGZpZy5hbGlnbj0nY2VudGVyJ30KYXZfcmVudF8xOTY2JGludl9hcmVhIDwtIDEgLyBhdl9yZW50XzE5NjYkYXJlYQoKcGVyX3NxbV9pbnZfbW9kZWwgPC0gbG0ocmVudHNxbSB+IGludl9hcmVhLCBkYXRhID0gYXZfcmVudF8xOTY2KQoKc3VtbWFyeShwZXJfc3FtX2ludl9tb2RlbCkKCnBsb3QoCiAgeCA9IGF2X3JlbnRfMTk2NiRhcmVhLAogIHkgPSBhdl9yZW50XzE5NjYkcmVudHNxbSwKICB4bGFiID0gJ2FyZWEgaW4gc3FtJywKICB5bGFiID0gJ25ldCByZW50IHBlciBzcW0nCikKeF9zZXEgPC0gc2VxKG1pbigxIC8gYXZfcmVudF8xOTY2JGFyZWEpLCBtYXgoMSAvIGF2X3JlbnRfMTk2NiRhcmVhKSwgbGVuZ3RoLm91dCA9IDEwMCkKcHJlZGljdGVkIDwtIHByZWRpY3QocGVyX3NxbV9pbnZfbW9kZWwsIG5ld2RhdGEgPSBkYXRhLmZyYW1lKGludl9hcmVhID0geF9zZXEpKQoKbGluZXMoMSAvIHhfc2VxLCBwcmVkaWN0ZWQsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQpgYGAKCiMjIEV4YW1wbGUgMi4zOiBNdW5pY2ggUmVudCBJbmRleCAtIFJlbnQgaW4gQXZlcmFnZSBhbmQgR29vZCBMb2NhbHRpb25zCgpXZSBhZGQgdGhlIHZhcmlhYmxlICRcdGV4dHtnb29kIGxvY2F0aW9ufSQgdG8gdGhlIG1vZGVsOgoKJCQKXG1hdGhiYntFfShcdGV4dHtyZW50fSkgPSBcYmV0YV97MH0gKyBcYmV0YV97MX0gXGNkb3QgXHRleHR7YXJlYX0gKyBcYmV0YV97Mn0gXGNkb3QgXHRleHR7Z29vZCBsb2NhbHRpb259CiQkCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTgsIGZpZy5hbGlnbj0nY2VudGVyJ30KYWdfcmVudF8xOTY2IDwtIHN1YnNldChyZW50XzE5NjYsIGxvY2F0aW9uICVpbiUgYygxLCAyKSkKc3VtbWFyeShhZ19yZW50XzE5NjYpCgphZ19yZW50XzE5NjYkZ2xvY2F0aW9uIDwtIGFnX3JlbnRfMTk2NiRsb2NhdGlvbiA9PSAyCnN1bW1hcnkoYWdfcmVudF8xOTY2KQoKZ29vZF9tb2RlbCA8LSBsbShyZW50IH4gYXJlYSArIGdsb2NhdGlvbiwgZGF0YSA9IGFnX3JlbnRfMTk2NikKc3VtbWFyeShnb29kX21vZGVsKQoKcGFyKG1mcm93ID0gYygyLCAyKSkKCmNvbG9ycyA8LSBjKCJibGFjayIsICJyZWQiKQoKcGxvdCgKICAgIHggPSBhZ19yZW50XzE5NjYkYXJlYSwKICAgIHkgPSBhZ19yZW50XzE5NjYkcmVudCwKICAgIHhsYWIgPSAnYXJlYSBpbiBzcW0nLAogICAgeWxhYiA9ICduZXQgcmVudCBpbiBFdXJvJywKICAgIGNvbCA9IGNvbG9yc1thcy5udW1lcmljKGFnX3JlbnRfMTk2NiRsb2NhdGlvbildCikKCmxlZ2VuZCgKICAidG9wbGVmdCIsCiAgbGVnZW5kID0gYygnYXZlcmFnZScsICdnb29kJyksCiAgY29sID0gY29sb3JzLAogIHBjaCA9IDE5CikKCmdfcmVudF8xOTY2IDwtIHN1YnNldChyZW50XzE5NjYsIGxvY2F0aW9uID09IDIpCnNpbXBsZV9nb29kX21vZGVsIDwtIGxtKHJlbnQgfiBhcmVhLCBkYXRhID0gZ19yZW50XzE5NjYpCgpwbG90KE5BLCB4bGltID0gcmFuZ2UocmVudF8xOTY2JGFyZWEpLCB5bGltID0gcmFuZ2UocmVudF8xOTY2JHJlbnQpLCB4bGFiID0gJ2FyZWEgaW4gc3FtJywgeWxhYiA9ICdlc3RpbWF0ZWQgbmV0IHJlbnQnKQphYmxpbmUoc2ltcGxlX21vZGVsKQphYmxpbmUoc2ltcGxlX2dvb2RfbW9kZWwsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQoKbGVnZW5kKAogICJ0b3BsZWZ0IiwKICBsZWdlbmQgPSBjKCdhdmVyYWdlJywgJ2dvb2QnKSwKICBjb2wgPSBjKCdibGFjaycsICdyZWQnKSwKICBsd2QgPSAyCikKCnBsb3QoTkEsIHhsaW0gPSByYW5nZShyZW50XzE5NjYkYXJlYSksIHlsaW0gPSByYW5nZShyZW50XzE5NjYkcmVudCksIHhsYWIgPSAnYXJlYSBpbiBzcW0nLCB5bGFiID0gJ2VzaW1hdGVkIG5ldCByZW50JykKCmJldGEgPC0gZ29vZF9tb2RlbCRjb2VmZmljaWVudHMKCmFibGluZShiZXRhWzFdLCBiZXRhWzJdKQphYmxpbmUoYmV0YVsxXSArIGJldGFbM10sIGJldGFbMl0sIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQoKbGVnZW5kKAogICJ0b3BsZWZ0IiwKICBsZWdlbmQgPSBjKCdhdmVyYWdlJywgJ2dvb2QnKSwKICBjb2wgPSBjKCdibGFjaycsICdyZWQnKSwKICBsd2QgPSAyCikKYGBgCgojIyBFeGFtcGxlIDIuNCBNdW5pY2ggUmVudCBJbmRleCDigJQgTm9ubGluZWFyIEluZmx1ZW5jZSBvZiBMaXZpbmcgQXJlYQoKV2UgYWRkIHRoZSBnb29kIGxvY2F0aW9uIGR1bW15IHZhcmlhYmxlIHRvIHRoZSBtb2RlbCBvZiBleGFtcGxlIDIuMjoKCiQkClxtYXRoYmJ7RX0oXHRleHR7cmVudCBwZXIgc3FtfSkgPSBcYmV0YV97MH0gKyBcYmV0YV97MX0gXGNkb3QgXGZyYWN7MX17XHRleHR7YXJlYX19ICsgXGJldGFfezJ9IFxjZG90IFx0ZXh0e2dvb2QgbG9jYXRpb259CiQkCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTQsIGZpZy5hbGlnbj0nY2VudGVyJ30KZ19tdWx0aXBsZV9tb2RlbCA8LSBsbShyZW50c3FtIH4gSSgxL2FyZWEpICsgZ2xvY2F0aW9uLCBkYXRhID0gYWdfcmVudF8xOTY2KQpzdW1tYXJ5KGdfbXVsdGlwbGVfbW9kZWwpCgpwYXIobWZyb3cgPSBjKDEsIDIpKQoKY29sb3JzIDwtIGMoImJsYWNrIiwgInJlZCIpCgpwbG90KAogICAgeCA9IGFnX3JlbnRfMTk2NiRhcmVhLAogICAgeSA9IGFnX3JlbnRfMTk2NiRyZW50c3FtLAogICAgeGxhYiA9ICdhcmVhIGluIHNxbScsCiAgICB5bGFiID0gJ25ldCByZW50IGluIEV1cm8nLAogICAgY29sID0gY29sb3JzW2FzLm51bWVyaWMoYWdfcmVudF8xOTY2JGxvY2F0aW9uKV0KKQoKbGVnZW5kKAogICJ0b3BsZWZ0IiwKICBsZWdlbmQgPSBjKCdhdmVyYWdlJywgJ2dvb2QnKSwKICBjb2wgPSBjb2xvcnMsCiAgcGNoID0gMTkKKQoKcGxvdChOQSwgeGxpbSA9IHJhbmdlKHJlbnRfMTk2NiRhcmVhKSwgeWxpbSA9IHJhbmdlKHJlbnRfMTk2NiRyZW50c3FtKSwgeGxhYiA9ICdhcmVhIGluIHNxbScsIHlsYWIgPSAnZXNpbWF0ZWQgbmV0IHJlbnQgcGVyIHNxbScpCgp4X3NlcSA8LSBzZXEobWluKGFnX3JlbnRfMTk2NiRhcmVhKSwgbWF4KGFnX3JlbnRfMTk2NiRhcmVhKSwgbGVuZ3RoLm91dCA9IDEwMCkKYmV0YSA8LSBnX211bHRpcGxlX21vZGVsJGNvZWZmaWNpZW50cwoKbGluZXMoeF9zZXEsIGJldGFbMV0gKyBiZXRhWzJdICogKDEveF9zZXEpLCBjb2wgPSAnYmxhY2snLCBsd2QgPSAyKQpsaW5lcyh4X3NlcSwgYmV0YVsxXSArIGJldGFbMl0gKiAoMS94X3NlcSkgKyBiZXRhWzNdLCBjb2wgPSAncmVkJywgbHdkID0gMikKCmxlZ2VuZCgKICAidG9wbGVmdCIsCiAgbGVnZW5kID0gYygnYXZlcmFnZScsICdnb29kJyksCiAgY29sID0gYygnYmxhY2snLCAncmVkJyksCiAgbHdkID0gMgopCmBgYAoKIyMgRXhhbXBsZSAyLjUgTXVuaWNoIFJlbnQgSW5kZXgg4oCUIEludGVyYWN0aW9uIEJldHdlZW4gTGl2aW5nIEFyZWEgYW5kIExvY2F0aW9uCgpBZGRpbmcgdGhlIGludGVyYWN0aW9uIHRlcm0gYmV0d2VlbiBhcmVhIGFuZCBnb29kIGxvY2F0aW9uOgoKJCQKXG1hdGhiYntFfShcdGV4dHtyZW50fSkgPSBcYmV0YV97MH0gKyBcYmV0YV97MX0gXGNkb3QgXHRleHR7YXJlYX0gKyBcYmV0YV97Mn0gXGNkb3QgXHRleHR7Z29vZCBsb2NhdGlvbn0gKyBcYmV0YV97M30gXGNkb3QgXHRleHR7aW50ZXJhY3Rpb259CiQkCgpgYGB7ciwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NCwgZmlnLmFsaWduPSdjZW50ZXInfQphZ19yZW50XzE5NjYkaW50ZXIgPC0gYWdfcmVudF8xOTY2JGFyZWEgKiBhcy5udW1lcmljKGFnX3JlbnRfMTk2NiRnbG9jYXRpb24pCgpzdW1tYXJ5KGFnX3JlbnRfMTk2NiRpbnRlcikKCmdfaW50ZXJfbW9kZWwgPC0gbG0ocmVudCB+IGFyZWEgKyBnbG9jYXRpb24gKyBpbnRlciwgZGF0YSA9IGFnX3JlbnRfMTk2NikKc3VtbWFyeShnX2ludGVyX21vZGVsKQoKcGxvdChOQSwgeGxpbSA9IHJhbmdlKGFnX3JlbnRfMTk2NiRhcmVhKSwgeWxpbSA9IHJhbmdlKGFnX3JlbnRfMTk2NiRyZW50KSwgeGxhYiA9ICdhcmVhIGluIHNxbScsIHlsYWIgPSAnZXNpbWF0ZWQgbmV0IHJlbnQnKQoKeF9zZXEgPC0gc2VxKG1pbihhZ19yZW50XzE5NjYkYXJlYSksIG1heChhZ19yZW50XzE5NjYkYXJlYSksIGxlbmd0aC5vdXQgPSAxMDApCmJldGEgPC0gZ19pbnRlcl9tb2RlbCRjb2VmZmljaWVudHMKCmxpbmVzKHhfc2VxLCBiZXRhWzFdICsgYmV0YVsyXSAqIHhfc2VxLCBjb2wgPSAnYmxhY2snLCBsd2QgPSAyKQpsaW5lcyh4X3NlcSwgYmV0YVsxXSArIChiZXRhWzJdICsgYmV0YVs0XSkgKiB4X3NlcSArIGJldGFbM10sIGNvbCA9ICdyZWQnLCBsd2QgPSAyKQoKbGVnZW5kKAogICJ0b3BsZWZ0IiwKICBsZWdlbmQgPSBjKCdhdmVyYWdlJywgJ2dvb2QnKSwKICBjb2wgPSBjKCdibGFjaycsICdyZWQnKSwKICBsd2QgPSAyCikKYGBgCgojIyBFeGFtcGxlIDIuNiBNdW5pY2ggUmVudCBJbmRleCDigJQgTXVsdGlwbGUgUmVncmVzc2lvbiBNb2RlbAoKTm93IHdlIGFkZCB0aGUgdG9wIGxvY2F0aW9uICgkXHRleHR7bG9jYXRpb259ID0gMyQpOgoKYGBge3J9Cm11bmljaF9yZW50X2luZGV4JGdsb2NhdGlvbiA8LSBtdW5pY2hfcmVudF9pbmRleCRsb2NhdGlvbiA9PSAyCm11bmljaF9yZW50X2luZGV4JHRsb2NhdGlvbiA8LSBtdW5pY2hfcmVudF9pbmRleCRsb2NhdGlvbiA9PSAzCnN1bW1hcnkobXVuaWNoX3JlbnRfaW5kZXgpCmBgYAoKQSBtdWx0aXBsZSBtb2RlbCB3aXRoIGFsbCBhdmFpbGFibGUgdmFyaWFibGVzOgoKJCQKXGJlZ2lue21hdHJpeH0KXG1hdGhiYntFfShcdGV4dHtyZW50c3FtfSkgPSAmIFxiZXRhX3swfSArIFxiZXRhX3sxfSBcY2RvdCBcZnJhY3sxfXtcdGV4dHthcmVhfX0gKyBcYmV0YV97Mn0gXGNkb3QgXHRleHR7eWVhcmN9ICsgXGJldGFfezN9IFxjZG90IFx0ZXh0e3llYXJjfV4yICsgXGJldGFfezR9IFxjZG90IFx0ZXh0e2dvb2QgbG9jYXRpb259ICsgXGJldGFfezV9IFxjZG90IFx0ZXh0e3RvcCBsb2NhdGlvbn0gXFwKICYgICsgXGJldGFfezZ9IFxjZG90IFx0ZXh0e2JhdGh9ICsgXGJldGFfezd9IFxjZG90IFx0ZXh0e2tpdGNoZW59ICsgXGJldGFfezh9IFxjZG90IFx0ZXh0e2NoZWF0aW5nfSBcXApcZW5ke21hdHJpeH0KJCQKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NCwgZmlnLmFsaWduPSdjZW50ZXInfQptdWx0aXBsZV9tb2RlbCA8LSBsbShyZW50c3FtIH4gSSgxL2FyZWEpICsgeWVhcmMgKyBJKHllYXJjXjIpICsgZ2xvY2F0aW9uICsgdGxvY2F0aW9uICsgYmF0aCArIGtpdGNoZW4gKyBjaGVhdGluZywgZGF0YSA9IG11bmljaF9yZW50X2luZGV4KQpzdW1tYXJ5KG11bHRpcGxlX21vZGVsKQoKcGFyKG1mcm93ID0gYygxLCAyKSkKCnBsb3QoCiAgICB4ID0gbXVuaWNoX3JlbnRfaW5kZXgkYXJlYSwKICAgIHkgPSBtdW5pY2hfcmVudF9pbmRleCRyZW50c3FtLAogICAgeGxhYiA9ICdhcmVhIGluIHNxbScsCiAgICB5bGFiID0gJ2VzdGltYXRlZCBuZXQgcmVudCBpbiBFdXJvJywKKQoKYXJlYV9zZXEgPC0gc2VxKG1pbihtdW5pY2hfcmVudF9pbmRleCRhcmVhKSwgbWF4KG11bmljaF9yZW50X2luZGV4JGFyZWEpLCBsZW5ndGgub3V0ID0gMTAwKQpiZXRhIDwtIG11bHRpcGxlX21vZGVsJGNvZWZmaWNpZW50cwoKY29uc3RhbnQgPC0gYmV0YVs1XSAqIG1lYW4oYXMubnVtZXJpYyhtdW5pY2hfcmVudF9pbmRleCRnbG9jYXRpb24pKSArIAogIGJldGFbNl0gKiBtZWFuKGFzLm51bWVyaWMobXVuaWNoX3JlbnRfaW5kZXgkdGxvY2F0aW9uKSkgKyAKICBiZXRhWzddICogbWVhbihhcy5udW1lcmljKG11bmljaF9yZW50X2luZGV4JGJhdGgpKSArIAogIGJldGFbOF0gKiBtZWFuKGFzLm51bWVyaWMobXVuaWNoX3JlbnRfaW5kZXgka2l0Y2hlbikpICsgCiAgYmV0YVs5XSAqIG1lYW4oYXMubnVtZXJpYyhtdW5pY2hfcmVudF9pbmRleCRjaGVhdGluZykpCgp5ZWFyX2NvbnN0YW50IDwtIGJldGFbM10gKiBtZWFuKG11bmljaF9yZW50X2luZGV4JHllYXJjKSArIGJldGFbNF0gKiBtZWFuKG11bmljaF9yZW50X2luZGV4JHllYXJjXjIpCgpsaW5lcyhhcmVhX3NlcSwgYmV0YVsxXSArIGJldGFbMl0gKiAoMSAvIGFyZWFfc2VxKSArIGNvbnN0YW50ICsgeWVhcl9jb25zdGFudCwgY29sID0gJ3JlZCcsIGx3ZCA9IDIpCgpwbG90KAogICAgeCA9IG11bmljaF9yZW50X2luZGV4JHllYXJjLAogICAgeSA9IG11bmljaF9yZW50X2luZGV4JHJlbnRzcW0sCiAgICB4bGFiID0gJ3llYXIgb2YgY29uc3RydWN0aW9uJywKICAgIHlsYWIgPSAnZXN0aW1hdGVkIG5ldCByZW50IGluIEV1cm8nLAopCgphcmVhX2NvbnN0YW50IDwtIGJldGFbMl0gKiBtZWFuKDEgLyBtdW5pY2hfcmVudF9pbmRleCRhcmVhKQoKeWVhcl9zZXEgPC0gc2VxKG1pbihtdW5pY2hfcmVudF9pbmRleCR5ZWFyYyksIG1heChtdW5pY2hfcmVudF9pbmRleCR5ZWFyYyksIGxlbmd0aC5vdXQgPSAxMDApCmxpbmVzKHllYXJfc2VxLCBiZXRhWzFdICsgYmV0YVszXSAqIHllYXJfc2VxICsgYmV0YVs0XSAqIHllYXJfc2VxXjIgKyBjb25zdGFudCArIGFyZWFfY29uc3RhbnQsIGNvbCA9ICdyZWQnLCBsd2QgPSAyKQpgYGAKCiMjIEV4YW1wbGUgMi43IFBhdGVudCBPcHBvc2l0aW9uCgpJbXBvcnQgdGhlIHBhdGVudCBvcHBvc2l0aW9uIGZyb20gc2NyaXB0OgoKYGBge3J9CnNvdXJjZSgiaW1wb3J0X2RhdGEvcGF0ZW50X29wcG9zaXRpb24uUiIpCmBgYAoKV2UgbGVmdCB0aGUgJFx0ZXh0e29wcH0kIGRhdGFzZXQgYXMgaW50ZWdlciwgc28gd2UgY2FuIG1vZGVsIHRoZSByZXNwb25zZSB2YXJpYWJsZSBhcyBiaW5hcnk6CgpgYGB7cn0KcGF0ZW50X29wcG9zaXRpb24kb3BwIDwtIGFzLmludGVnZXIocGF0ZW50X29wcG9zaXRpb24kb3BwID09IDEpCnN1bW1hcnkocGF0ZW50X29wcG9zaXRpb24kb3BwKQpgYGAKCiMjIEV4YW1wbGUgMi44OiBQYXRlbnQgT3Bwb3NpdGlvbgoKV2UgZXhwbG9yZSB0aGUgaGlzdG9ncmFtIG9mIGNsYWltcyAoJFx0ZXh0e25jbGFpbXN9JCkgYW5kIGNpdGF0aW9ucyAoJFx0ZXh0e25jaXR9JCk6CgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTQsIGZpZy5hbGlnbj0nY2VudGVyJ30KcGFyKG1mcm93ID0gYygxLCAyKSkKCmhpc3QocGF0ZW50X29wcG9zaXRpb24kbmNsYWltcywgeWxhYiA9ICdlc3RpbWF0ZWQgZGVuc2l0eScsIHhsYWIgPSAnbnVtYmVyIG9mIGNsYWltcycsIGZyZXEgPSBGQUxTRSkKbGluZXMoZGVuc2l0eShwYXRlbnRfb3Bwb3NpdGlvbiRuY2xhaW1zKSwgY29sID0gJ3JlZCcsIGx3ZCA9IDIpCgpoaXN0KHBhdGVudF9vcHBvc2l0aW9uJG5jaXQsIHlsYWIgPSAnZXN0aW1hdGVkIGRlbnNpdHknLCB4bGFiID0gJ251bWJlciBvZiBjaXRhdGlvbnMnLCBmcmVxID0gRkFMU0UpCmxpbmVzKGRlbnNpdHkocGF0ZW50X29wcG9zaXRpb24kbmNpdCksIGNvbCA9ICdyZWQnLCBsd2QgPSAyKQpgYGAKCldlIHRoZW4gc3Vic2V0IHRoZSBkYXRhc2V0IHRvIGV4Y2x1ZGUgJFx0ZXh0e25jbGFpbXN9IFxsZXEgNjAkIGFuZCAkXHRleHR7bmNpdH0gXGxlcSAxNSQuIEFuZCBhbHNvIGV4dHJhY3QgdGhlIGJpb3BoYXJtYWNvbG9naWNhbCBvbmVzICgkXHRleHR7YmlvcGhhcm19ID09IDAkKToKCmBgYHtyfQpkZW91dGxpZXJfcGF0ZW50X29wcCA8LSBzdWJzZXQocGF0ZW50X29wcG9zaXRpb24sIG5jbGFpbXMgPD0gNjAgJiBuY2l0IDw9IDE1KQpub3RfYmlvcGhhcm1fcGF0ZW50X29wcCA8LSBzdWJzZXQoZGVvdXRsaWVyX3BhdGVudF9vcHAsIGJpb3BoYXJtID09IDApCnN1bW1hcnkobm90X2Jpb3BoYXJtX3BhdGVudF9vcHApCmBgYAoKV2UgdGhlbiBmaXQgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWw6CgokJApQKFx0ZXh0e29wcH1fe2l9ID0gMSkgPSBcZnJhY3tcZXhwKFxldGFfe2l9KX17MSArIFxleHAoXGV0YV97aX0pfQokJAoKJCQKXGV0YV97aX0gPSBcYmV0YV97MH0gKyBcYmV0YV97MX0gXGNkb3QgXHRleHR7eWVhcn1fe2l9ICsgXGJldGFfezJ9IFxjZG90IFx0ZXh0e25jaXR9X3tpfSArIFxiZXRhX3szfSBcY2RvdCBcdGV4dHtuY2xhaW1zfV97aX0gKyBcYmV0YV97NH0gXGNkb3QgXHRleHR7dXN0d2lufV97aX0gKyBcYmV0YV97NX0gXGNkb3QgXHRleHR7cGF0dXN9X3tpfSArIFxiZXRhX3s2fSBcY2RvdCBcdGV4dHtwYXRnc2dyfV97aX0gKyBcYmV0YV97N30gXGNkb3QgXHRleHR7bmNvdW50cnl9X3tpfQokJAoKYGBge3J9CnBhdF9vcHBfbW9kZWwgPC0gZ2xtKG9wcCB+IHllYXIgKyBuY2l0ICsgbmNsYWltcyArIHVzdHdpbiArIHBhdHVzICsgcGF0Z3NnciArIG5jb3VudHJ5LCBkYXRhID0gbm90X2Jpb3BoYXJtX3BhdGVudF9vcHAsIGZhbWlseSA9IGJpbm9taWFsKQpzdW1tYXJ5KHBhdF9vcHBfbW9kZWwpCmBgYAoKV2UgdGhlbiBnZW5lcmF0ZSB0aGUgdGFibGUgb2Ygb2RkIHJhdGlvczoKCmBgYHtyfQpwYXRfb3BwX29kZF9yYXRpb3MgPC0gY2JpbmQocGF0X29wcF9tb2RlbCRjb2VmZmljaWVudHMsIDApCmNvbG5hbWVzKHBhdF9vcHBfb2RkX3JhdGlvcykgPC0gYygnRXN0aW1hdGVkIENvZWZmaWNpZW50cycsICdFc3RpbWF0ZWQgT2RkIFJhdGlvcycpCnBhdF9vcHBfb2RkX3JhdGlvc1ssIDJdIDwtIGV4cChwYXRfb3BwX29kZF9yYXRpb3NbLCAxXSkKcGF0X29wcF9vZGRfcmF0aW9zWzEsIDJdIDwtIE5BCnBhdF9vcHBfb2RkX3JhdGlvcwpgYGAKClRoZW4gd2UgcmVwZWVhdCB0aGUgcHJvY2VzcyB3aXRoIHRoZSAkXHRleHR7bmNvdW50cnl9JCB2YXJpYWJsZSBhcyBhIHBvbHlub21pYWw6CgokJApcYmVnaW57bWF0cml4fQpcZXRhX3tpfSA9ICYgXGJldGFfezB9ICsgXGJldGFfezF9IFxjZG90IFx0ZXh0e3llYXJ9X3tpfSArIFxiZXRhX3syfSBcY2RvdCBcdGV4dHtuY2l0fV97aX0gKyBcYmV0YV97M30gXGNkb3QgXHRleHR7bmNsYWltc31fe2l9ICsgXGJldGFfezR9IFxjZG90IFx0ZXh0e3VzdHdpbn1fe2l9ICsgXGJldGFfezV9IFxjZG90IFx0ZXh0e3BhdHVzfV97aX0gKyBcYmV0YV97Nn0gXGNkb3QgXHRleHR7cGF0Z3Nncn1fe2l9IFxcCiAmICsgXGJldGFfezd9IFxjZG90IFx0ZXh0e25jb3VudHJ5fV97aX0gKyBcYmV0YV97OH0gXGNkb3QgXHRleHR7bmNvdW50cnl9X3tpfV57Mn0gKyBcYmV0YV97OX0gXGNkb3QgXHRleHR7bmNvdW50cnl9X3tpfV57M30KXGVuZHttYXRyaXh9CiQkCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTQsIGZpZy5hbGlnbj0nY2VudGVyJ30KcGF0X29wcF9wb2x5X21vZGVsIDwtIGdsbShvcHAgfiB5ZWFyICsgbmNpdCArIG5jbGFpbXMgKyB1c3R3aW4gKyBwYXR1cyArIHBhdGdzZ3IgKyBuY291bnRyeSArIEkobmNvdW50cnkgXiAyKSArIEkobmNvdW50cnkgXiAzKSwgZGF0YSA9IG5vdF9iaW9waGFybV9wYXRlbnRfb3BwLCBmYW1pbHkgPSBiaW5vbWlhbCkKc3VtbWFyeShwYXRfb3BwX3BvbHlfbW9kZWwpCgpwYXIobWZyb3cgPSBjKDEsIDIpKQpiZXRhIDwtIHBhdF9vcHBfbW9kZWwkY29lZmZpY2llbnRzCmNvbnN0YW50IDwtIGJldGFbMV0gKwogIGJldGFbMl0gKiBtZWFuKG5vdF9iaW9waGFybV9wYXRlbnRfb3BwJHllYXIpICsKICBiZXRhWzNdICogbWVhbihub3RfYmlvcGhhcm1fcGF0ZW50X29wcCRuY2l0KSArCiAgYmV0YVs0XSAqIG1lYW4obm90X2Jpb3BoYXJtX3BhdGVudF9vcHAkbmNsYWltcykgKwogIGJldGFbNV0gKiBtZWFuKGFzLm51bWVyaWMobm90X2Jpb3BoYXJtX3BhdGVudF9vcHAkdXN0d2luKSkgKwogIGJldGFbNl0gKiBtZWFuKGFzLm51bWVyaWMobm90X2Jpb3BoYXJtX3BhdGVudF9vcHAkcGF0dXMpKSArCiAgYmV0YVs3XSAqIG1lYW4oYXMubnVtZXJpYyhub3RfYmlvcGhhcm1fcGF0ZW50X29wcCRwYXRnc2dyKSkKCmJldGFfcG9seSA8LSBwYXRfb3BwX3BvbHlfbW9kZWwkY29lZmZpY2llbnRzCnBvbHlfY29uc3RhbnQgPC0gYmV0YV9wb2x5WzFdICsKICBiZXRhX3BvbHlbMl0gKiBtZWFuKG5vdF9iaW9waGFybV9wYXRlbnRfb3BwJHllYXIpICsKICBiZXRhX3BvbHlbM10gKiBtZWFuKG5vdF9iaW9waGFybV9wYXRlbnRfb3BwJG5jaXQpICsKICBiZXRhX3BvbHlbNF0gKiBtZWFuKG5vdF9iaW9waGFybV9wYXRlbnRfb3BwJG5jbGFpbXMpICsKICBiZXRhX3BvbHlbNV0gKiBtZWFuKGFzLm51bWVyaWMobm90X2Jpb3BoYXJtX3BhdGVudF9vcHAkdXN0d2luKSkgKwogIGJldGFfcG9seVs2XSAqIG1lYW4oYXMubnVtZXJpYyhub3RfYmlvcGhhcm1fcGF0ZW50X29wcCRwYXR1cykpICsKICBiZXRhX3BvbHlbN10gKiBtZWFuKGFzLm51bWVyaWMobm90X2Jpb3BoYXJtX3BhdGVudF9vcHAkcGF0Z3NncikpCgpuY291bnRyeV9zZXEgPC0gc2VxKG1pbihub3RfYmlvcGhhcm1fcGF0ZW50X29wcCRuY291bnRyeSksIG1heChub3RfYmlvcGhhcm1fcGF0ZW50X29wcCRuY291bnRyeSksIGxlbmd0aC5vdXQgPSAxMDApCmVmZmVjdCA8LSBjb25zdGFudCArIGJldGFbOF0gKiBuY291bnRyeV9zZXEKcG9seV9lZmZlY3QgPC0gcG9seV9jb25zdGFudCArIGJldGFfcG9seVs4XSAqIG5jb3VudHJ5X3NlcSArIGJldGFfcG9seVs5XSAqIG5jb3VudHJ5X3NlcSBeIDIgKyBiZXRhX3BvbHlbMTBdICogbmNvdW50cnlfc2VxIF4gMwpwbG90KAogIE5BLAogIHhsaW0gPSByYW5nZShub3RfYmlvcGhhcm1fcGF0ZW50X29wcCRuY291bnRyeSksCiAgeWxpbSA9IHJhbmdlKHBvbHlfZWZmZWN0KSwKICB4bGFiID0gJ251bWJlciBvZiBkZXNpZ25hdGVkIHN0YXRlcyBmb3IgdGhlIHBhdGVudCcsCiAgeWxhYiA9ICdlc3RpbWF0ZWQgZWZmZWN0JwopCmxpbmVzKG5jb3VudHJ5X3NlcSwgcG9seV9lZmZlY3QpCmxpbmVzKG5jb3VudHJ5X3NlcSwgZWZmZWN0LCBjb2wgPSAncmVkJywgbHdkID0gMikKCmxlZ2VuZCgKICAidG9wbGVmdCIsCiAgbGVnZW5kID0gYygicG9seW5vbWlhbCIsICJsaW5lYXIiKSwKICBjb2wgPSBjKCJibGFjayIsICJyZWQiKSwKICBsd2QgPSAyCikKCnBvbHlfcHJvYiA8LSBleHAocG9seV9lZmZlY3QpIC8gKDEgKyBleHAocG9seV9lZmZlY3QpKQpwbG90KAogIE5BLAogIHhsaW0gID0gcmFuZ2Uobm90X2Jpb3BoYXJtX3BhdGVudF9vcHAkbmNvdW50cnkpLAogIHlsaW0gPSByYW5nZShwb2x5X3Byb2IpLAogIHhsYWIgPSAnbnVtYmVyIG9mIGRlc2lnbmF0ZWQgc3RhdGVzIGZvciB0aGUgcGF0ZW50JywKICB5bGFiID0gJ2VzdGltYXRlZCBwcm9iYWJpbGl0eScKKQpsaW5lcyhuY291bnRyeV9zZXEsIHBvbHlfcHJvYikKcHJvYiA8LSBleHAoZWZmZWN0KSAvICgxICsgZXhwKGVmZmVjdCkpCmxpbmVzKG5jb3VudHJ5X3NlcSwgcHJvYiwgY29sID0gJ3JlZCcsIGx3ZCA9IDIpCmxlZ2VuZCgKICAidG9wbGVmdCIsCiAgbGVnZW5kID0gYygicG9seW5vbWlhbCIsICJsaW5lYXIiKSwKICBjb2wgPSBjKCJibGFjayIsICJyZWQiKSwKICBsd2QgPSAyCikKYGBgCgojIyBFeGFtcGxlIDIuOSBIb3Jtb25lIFRoZXJhcHkgd2l0aCBSYXRzCgpXZSBpbXBvcnQgdGhlIF9Ib3Jtb25lIFRoZXJhcHkgd2l0aCBSYXRzXyBkYXRhc2V0IGZyb20gdGhlIFtvZmljaWFsIHBhZ2Ugb2YgdGhlIGRhdGFzZXRdKGh0dHBzOi8vd3d3LnVuaS1nb2V0dGluZ2VuLmRlL2VuLzU1MTYyNS5odG1sKSwgYXMgdGhlIG90aGVyIGV4YW1wbGU6CgpgYGB7cn0KcmF0c191cmwgPC0gImh0dHBzOi8vd3d3LnVuaS1nb2V0dGluZ2VuLmRlL2RlL2RvY3VtZW50L2Rvd25sb2FkLzNhYzVhMDM4YjE5Mjk3ZmI4NjA5ZGZjMjgzMTljYmI3LnJhdy9yYXRzLnJhdyIKCnJhdHNfZGF0YXNldCA8LSByZWFkLnRhYmxlKAogIHVybChyYXRzX3VybCksCiAgaGVhZGVyID0gMSwKICBjb2xDbGFzc2VzID0gYygKICAgICJmYWN0b3IiLCAiZmFjdG9yIiwgIm51bWVyaWMiLAogICAgImludGVnZXIiLCAibnVtZXJpYyIsICJudW1lcmljIiwKICAgICJmYWN0b3IiLCAiZmFjdG9yIiwgImZhY3RvciIsCiAgICAibnVtZXJpYyIsICJudW1lcmljIiwgIm51bWVyaWMiIAogICkKKQpyYXRzX2RhdGFzZXQkbG93IDwtIHJhdHNfZGF0YXNldCRsb3cgPT0gMQpyYXRzX2RhdGFzZXQkaGlnaCA8LSByYXRzX2RhdGFzZXQkaGlnaCA9PSAxCnJhdHNfZGF0YXNldCRjb250cm9sIDwtIHJhdHNfZGF0YXNldCRjb250cm9sID09IDEKc3VtbWFyeShyYXRzX2RhdGFzZXQpCmBgYAoKV2UgcGxvdCB0aGUgdGltZXNlcmllcyBvZiB0aGUgcmF0cyBkaXZpZGVkIGluIHRoZSB0aHJlZSBncm91cHM6ICoqY29udHJvbCoqLCAqKmxvdyoqIGFuZCAqKmhpZ2gqKiBkb3NlOgoKYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTEyLCBmaWcuYWxpZ249J2NlbnRlcid9CnBhcihtZnJvdyA9IGMoMywgMSkpCgpjb250cm9sX3JhdHMgPC0gc3Vic2V0KHJhdHNfZGF0YXNldCwgY29udHJvbCkKbG93X3JhdHMgPC0gc3Vic2V0KHJhdHNfZGF0YXNldCwgbG93KQpoaWdoX3JhdHMgPC0gc3Vic2V0KHJhdHNfZGF0YXNldCwgaGlnaCkKCmxpYnJhcnkodmlyaWRpcykKCnBsb3RfcmF0c19zdWJzZXRzIDwtIGZ1bmN0aW9uKHJhdHNfc3Vic2V0LCB0aXRsZSkgewogIHBsb3QoCiAgICBOQSwKICAgIHhsaW0gPSByYW5nZShyYXRzX2RhdGFzZXQkdGltZSksCiAgICB5bGltID0gcmFuZ2UobmEub21pdChyYXRzX2RhdGFzZXQkcmVzcG9uc2UpKSwKICAgIHhsYWIgPSAiYWdlIGluIGRheXMiLAogICAgeWxhYiA9ICJyZXNwb25zZSIsCiAgICBtYWluID0gdGl0bGUKICApCiAgc3ViamVjdHMgPC0gdW5pcXVlKHJhdHNfc3Vic2V0JHN1YmplY3QpCiAgZm9yIChpIGluIHNlcV9hbG9uZyhzdWJqZWN0cykpIHsKICAgIGNvbG9ycyA8LSBsZW5ndGgoc3ViamVjdHMpCiAgICBsaW5lcygKICAgICAgc3Vic2V0KHJhdHNfc3Vic2V0LCBzdWJqZWN0ID09IHN1YmplY3RzW2ldKSR0aW1lLAogICAgICBzdWJzZXQocmF0c19zdWJzZXQsIHN1YmplY3QgPT0gc3ViamVjdHNbaV0pJHJlc3BvbnNlLAogICAgICBjb2wgPSB2aXJpZGlzKGNvbG9ycylbaV0KICAgICkKICB9Cn0KCnBsb3RfcmF0c19zdWJzZXRzKGNvbnRyb2xfcmF0cywgImNvbnRyb2wgZ3JvdXAiKQpwbG90X3JhdHNfc3Vic2V0cyhsb3dfcmF0cywgImxvdyBkb3NlIikKcGxvdF9yYXRzX3N1YnNldHMoaGlnaF9yYXRzLCAiaGlnaCBkb3NlIikKYGBgCgpXZSBhZGQgdGhlIHRyYW5zZm9ybWVkIGFnZToKCiQkCnQgPSBcbG9nKDEgKyAoXHRleHR7YWdlfSAtIDQ1KSAvIDEwKQokJAoKYGBge3J9CnJhdHNfZGF0YXNldCR0IDwtIGxvZygxICsgKHJhdHNfZGF0YXNldCR0aW1lIC0gNDUpIC8gMTApCnJhdHNfZGF0YXNldCRDIDwtIGFzLmludGVnZXIocmF0c19kYXRhc2V0JGNvbnRyb2wpCnJhdHNfZGF0YXNldCRMIDwtIGFzLmludGVnZXIocmF0c19kYXRhc2V0JGxvdykKcmF0c19kYXRhc2V0JEggPC0gYXMuaW50ZWdlcihyYXRzX2RhdGFzZXQkaGlnaCkKc3VtbWFyeShyYXRzX2RhdGFzZXQpCmBgYAoKQW5kIHdlIGZpdCB0aGUgbW9kZWw6CgokJAp5X3tpan0gPSBcYmV0YV97MH0gKyBcZ2FtbWFfezBpfSArIFxiZXRhX3sxfSBMX3tpfSBcY2RvdCB0X3tpan0gKyBcYmV0YV97Mn0gSF97aX0gXGNkb3QgdF97aWp9ICsgXGJldGFfezN9IENfe2l9IFxjZG90IHRfe2lqfSArIFxnYW1tYV97MWl9IFxjZG90IHRfe2lqfSArIFxlcHNpbG9uX3tpan0KJCQKCldpdGggJFxlcHNpbG9uX3tpan0gXHNpbSBOKDAsIFxzaWdtYV4yKSQgYXMgaW4gYWxsIHRoZXNlIGV4YW1wbGVzLiBBbmQgJFxnYW1tYV97MGl9JCBhbmQgJFxnYW1tYV97MWl9JCBhcmUgcmFuZG9tIGVmZmVjdHMgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdWJqZWN0cyBmb2xsb3dpbmc6CgokJApcZ2FtbWFfezBpfSBcc2ltIE4oMCwgXHRhdV97MH1eMikgXHdlZGdlIFxnYW1tYV97MWl9IFxzaW0gTigwLCBcdGF1X3sxfV4yKQokJAoKIyMgRXhhbXBsZSAyLjEwIEhvcm1vbmUgVGhlcmFweSB3aXRoIFJhdHMKCmBgYHtyfQpsaWJyYXJ5KGxtZTQpCnJhdHNfbW9kZWwgPC0gbG1lcigKICByZXNwb25zZSB+IEw6dCArIEg6dCArIEM6dCArICgxICsgdCB8IHN1YmplY3QpLCBkYXRhID0gcmF0c19kYXRhc2V0CikKc3VtbWFyeShyYXRzX21vZGVsKQpgYGAKCkFuZCB0aGUgc2ltcGxlciBtb2RlbCBlbGltaW5hdGluZyB0aGUgc3ViamVjdC1zcGVjaWZpYyB0ZXJtICRcdGF1X3sxaX0gXGNkb3QgdF97aWp9JDoKCiQkCnlfe2lqfSA9IFxiZXRhX3swfSArIFxnYW1tYV97MGl9ICsgXGJldGFfezF9IExfe2l9IFxjZG90IHRfe2lqfSArIFxiZXRhX3syfSBIX3tpfSBcY2RvdCB0X3tpan0gKyBcYmV0YV97M30gQ197aX0gXGNkb3QgdF97aWp9ICsgXGVwc2lsb25fe2lqfQokJAoKYGBge3J9CnNpbXBsZV9yYXRzX21vZGVsIDwtIGxtZXIoCiAgcmVzcG9uc2UgfiBMOnQgKyBIOnQgKyBDOnQgKyAoMSB8IHN1YmplY3QpLCBkYXRhID0gcmF0c19kYXRhc2V0CikKc3VtbWFyeShzaW1wbGVfcmF0c19tb2RlbCkKYGBgCgpXZSB0aGVuIHBsb3QgYSBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0b3Igd2l0aCBhIG5vcm1hbCBkaXN0cmlidXRpb24gZm9yIHRob3NlIHZhbHVlcy4gQWxvbmdzaWRlIGEgbm9ybWFsIHF1YW50aXR5IHBsb3Q6CgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTQsIGZpZy5hbGlnbj0nY2VudGVyJ30KcGFyKG1mcm93ID0gYygxLCAyKSkKdGF1XzBpIDwtIHJhbmVmKHJhdHNfbW9kZWwpJHN1YmplY3RbLCAxXQoKa2RlIDwtIGRlbnNpdHkodGF1XzBpKQoKdGF1X3NlcSA8LSBzZXEobWluKGtkZSR4KSwgbWF4KGtkZSR4KSwgbGVuZ3RoLm91dCA9IDEwMCkKCnBsb3QoCiAgeCA9IHRhdV9zZXEsCiAgeSA9IGRub3JtKHRhdV9zZXEsIG1lYW4gPSBtZWFuKHRhdV8waSksIHNkID0gc2QodGF1XzBpKSksCiAgdHlwZSA9ICdsJywKICBtYWluID0gJ3JhbmRvbSBpbnRlcmNlcHQnLAogIHhsYWIgPSAncmFuZG9tIGludGVyY2VwdCcsCiAgeWxhYiA9ICdkZW5zaXR5JywKICBjb2wgPSAncmVkJywKICBsd2QgPSAyCikKCmxpbmVzKAogIHggPSBrZGUkeCwKICB5ID0ga2RlJHksCiAgY29sID0gJ2JsYWNrJywKICBsd2QgPSAyCikKCmxlZ2VuZCgKICAndG9wbGVmdCcsCiAgbGVnZW5kID0gYygna2RlJywgJ2FkYXB0ZWQgbm9ybWFsJyksCiAgY29sID0gYygnYmxhY2snLCAncmVkJyksCiAgbHdkID0gMgopCgpxcW5vcm0oCiAgdGF1XzBpLCAKICBtYWluID0gJ3JhbmRvbSBpbnRlcmNlcHQnLAogIHhsYWIgPSAncXVhbnRpbGVzIG9mIG5vcm1hbCBkaXN0cmlidXRpb24nLAogIHlsYWIgPSAncmFuZG9tIGludGVyY2VwdCcsCiAgcGNoID0gMTksCiAgY29sID0gImRhcmtibHVlIgopCgojIEFkZCByZWZlcmVuY2UgbGluZQpxcWxpbmUoCiAgdGF1XzBpLAogIGNvbCA9ICJibGFjayIsIAogIGx3ZCA9IDIKKQpgYGAKCiMjIEV4YW1wbGUgMi4xMSBNYWxudXRyaXRpb24gaW4gWmFtYmlhCgpJbXBvcnQgZGF0YSBmcm9tIHNjcmlwdDoKCmBgYHtyfQpzb3VyY2UoImltcG9ydF9kYXRhL21hbG51dHJpdGlvbl96YW1iaWEuUiIpCmBgYAoKX1RvIGJlIGNvbnRpbnVlZC4uLl8K