Si vuole misurare una certa risposta sperimentale al variare di tre parametri specifici (due di processo e uno qualitativo):

Si inizia creando una tabella dove ogni colonna è un fattore e ogni riga è un livello secondo il modello postulato ottenuto con \(2^3\) condizioni sperimentali, ovvero 3 fattori e 2 livelli, prevedendo almeno un paio di repliche.



df = data.frame(
  Temperature = c(160,180,160,180,160,180,160,180,160,180,160,180,160,180,160,180),
  Duration = c(20,20,40,40,20,20,40,40,20,20,40,40,20,20,40,40),
  Wood_type = c('A','A','A','A','B','B','B','B','A','A','A','A','B','B','B','B'),
  Y = c(59,74,50,69,50,81,46,79,61,70,58,67,54,85,44,81)
)
#DT::datatable(df)
df %>% kable() %>% kable_material('striped')
Temperature Duration Wood_type Y
160 20 A 59
180 20 A 74
160 40 A 50
180 40 A 69
160 20 B 50
180 20 B 81
160 40 B 46
180 40 B 79
160 20 A 61
180 20 A 70
160 40 A 58
180 40 A 67
160 20 B 54
180 20 B 85
160 40 B 44
180 40 B 81


plot_ly(df, x = ~Temperature, y = ~Duration, z = ~Wood_type) %>%
  add_markers()  

Dopodiché creo una tabella con i valori precedenti codificandoli come \(-1\) e \(+1\)


x1 = c()
x2 = c()
x3 = c()

levels = c(-1,1)

for (k in 1:2){
  for (j in 1:2) {
    for (i in 1:2) {
      x1 = c(x1, levels[i])
      x2 = c(x2, levels[j])
      x3 = c(x3, levels[k])
    }
  }
}

x1 = c(x1,x1)
x2 = c(x2,x2)
x3 = c(x3,x3)

df1 = data.frame(x1,x2,x3,Y = c(59,74,50,69,50,81,46,79,61,70,58,67,54,85,44,81))

fig = df1 %>% kable() %>% kable_styling( full_width = T) 

for (m in 1:(ncol(df1)-1)) {
 fig = column_spec(fig, m ,color= 'white', background = spec_color(df1[,m],end = 0.7, option = 'A' ))
}

fig %>%  column_spec( ncol(df1) ,color= 'white', background = 'darkgreen')
x1 x2 x3 Y
-1 -1 -1 59
1 -1 -1 74
-1 1 -1 50
1 1 -1 69
-1 -1 1 50
1 -1 1 81
-1 1 1 46
1 1 1 79
-1 -1 -1 61
1 -1 -1 70
-1 1 -1 58
1 1 -1 67
-1 -1 1 54
1 -1 1 85
-1 1 1 44
1 1 1 81



Adesso aggiungo le altre colonne seguendo il modello postulato

\[ Y = b_0+b_1x_1+b_2x_2+b_3x_3+b_{12}x_1x_2+b_{13}x_1x_3+b_{23}x_2x_3+b_{123}x_1x_2x_3 \]


df3 = mutate(df1, x1x2 = x1*x2, x1x3= x1*x3, x2x3=x2*x3, x1x2x3 = x1*x2*x3)
df3 = relocate(df3, Y, .after = last_col())

fig = df3 %>% kable() %>% kable_styling( full_width = T) 

for (m in 1:(ncol(df3)-1)) {
 fig = column_spec(fig, m ,color= 'white', background = spec_color(df3[,m],end = 0.7, option = 'A' ))
}

fig %>%  column_spec( ncol(df3) ,color= 'white', background = 'darkgreen')
x1 x2 x3 x1x2 x1x3 x2x3 x1x2x3 Y
-1 -1 -1 1 1 1 -1 59
1 -1 -1 -1 -1 1 1 74
-1 1 -1 -1 1 -1 1 50
1 1 -1 1 -1 -1 -1 69
-1 -1 1 1 -1 -1 1 50
1 -1 1 -1 1 -1 -1 81
-1 1 1 -1 -1 1 -1 46
1 1 1 1 1 1 1 79
-1 -1 -1 1 1 1 -1 61
1 -1 -1 -1 -1 1 1 70
-1 1 -1 -1 1 -1 1 58
1 1 -1 1 -1 -1 -1 67
-1 -1 1 1 -1 -1 1 54
1 -1 1 -1 1 -1 -1 85
-1 1 1 -1 -1 1 -1 44
1 1 1 1 1 1 1 81

Creo un modello di regressione


a = c()
for (i in colnames(df3[-ncol(df3)])){
  a = paste(a , '+', i, sep = '')
}
fmla = as.formula(paste('Y ~ ', a))

model = lm(fmla, df3)
model
## 
## Call:
## lm(formula = fmla, data = df3)
## 
## Coefficients:
## (Intercept)           x1           x2           x3         x1x2         x1x3  
##   6.425e+01    1.150e+01   -2.500e+00    7.500e-01    7.500e-01    5.000e+00  
##        x2x3       x1x2x3  
##   7.216e-16    2.500e-01
## 
## Call:
## lm(formula = fmla, data = df3)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
##  -4.00  -1.25   0.00   1.25   4.00 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  6.425e+01  7.071e-01  90.863 2.40e-13 ***
## x1           1.150e+01  7.071e-01  16.263 2.06e-07 ***
## x2          -2.500e+00  7.071e-01  -3.536 0.007670 ** 
## x3           7.500e-01  7.071e-01   1.061 0.319813    
## x1x2         7.500e-01  7.071e-01   1.061 0.319813    
## x1x3         5.000e+00  7.071e-01   7.071 0.000105 ***
## x2x3         7.216e-16  7.071e-01   0.000 1.000000    
## x1x2x3       2.500e-01  7.071e-01   0.354 0.732810    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.828 on 8 degrees of freedom
## Multiple R-squared:  0.9763, Adjusted R-squared:  0.9555 
## F-statistic: 47.05 on 7 and 8 DF,  p-value: 7.071e-06

Osservo la significatività di P e scarto i valori superiori al mio limite di confidenza (5%). Il P-value può essere visto come la probabilità di sbagliare nel rigettare l’ipotesi nulla.

(Noto che c’è una correlazione tra \(x_1\) e \(x_3\) (temperatura e tipo di legno), quindi tengo come significativo anche il vettore \(x_3\))


Ripeto la regressione dopo aver scartatato dalla mia tabella le tre colonne non significative: \(x_1x_2,x_2x_3,x_1x_2x_3\)

model2 = lm(Y ~ x1 + x2 + x3 + x1x3, df3)
summary(model2)
## 
## Call:
## lm(formula = Y ~ x1 + x2 + x3 + x1x3, data = df3)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
##  -4.50  -1.25   0.00   1.50   3.50 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  64.2500     0.6484  99.086  < 2e-16 ***
## x1           11.5000     0.6484  17.735 1.93e-09 ***
## x2           -2.5000     0.6484  -3.855  0.00267 ** 
## x3            0.7500     0.6484   1.157  0.27192    
## x1x3          5.0000     0.6484   7.711 9.25e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.594 on 11 degrees of freedom
## Multiple R-squared:  0.9726, Adjusted R-squared:  0.9626 
## F-statistic: 97.55 on 4 and 11 DF,  p-value: 1.629e-08

Il vettore con i valori calcolati sarà

fitted(model2)
##    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
## 59.5 72.5 54.5 67.5 51.0 84.0 46.0 79.0 59.5 72.5 54.5 67.5 51.0 84.0 46.0 79.0

Posso a questo punto crare un grafico per vedere i valori osservati sperimentalmente e quelli calcolati dal modello di regressione


df_y = data.frame(Y_cal=fitted(model2), Y_sper = df3$Y)

bisettrice = data.frame(x=c(40,90), y=c(40,90))

ggplot(df_y, aes(Y_sper,Y_cal))+ 
  geom_point()+ 
  geom_line(data=bisettrice, aes(x,y, color='red'), show.legend = FALSE)+ 
  ggtitle( 'Y sperimentale vs Y calcolata')+ 
  theme_minimal()+
  theme(plot.title = element_text(hjust=0.5))


modelcoeff = coefficients(model2)
modelcoeff %>% round(digits = 2)
## (Intercept)          x1          x2          x3        x1x3 
##       64.25       11.50       -2.50        0.75        5.00


x = seq(from = -1,  to = 1, by = 0.1)
y = seq(from = -1,  to = 1, by = 0.1)
x3 = c(-1,1)
z = c()

for (k in x3) {
  for (j in y){
    for (i in x){
    z = c(z, modelcoeff[1]+modelcoeff[2]*i+modelcoeff[3]*j+ modelcoeff[4]*k+modelcoeff[5]*i*k)
    }
  }
}
z = array(z, dim = c(length(x), length(y),length(x3)))

Z = melt(z)

Temp = seq(from = 160, to = 180, by = 1) 
Time = seq(from = 20, to = 40, by = 1)
Wood = c(1:2)
Wd = c()
Tm = c()
Tp = c()

for (k in Wood) {
  for (j in Time){
    for (i in Temp){
      Tp = c(Tp, i)
      Tm = c(Tm, j)
      Wd = c(Wd, k)
    
    }
  }
}


plot_ly(x=Tp, y= Tm, z= Wd, color = Z$value) %>% add_markers() %>%
  layout(scene = list(
                 xaxis = list(title = 'Temperature'),
                 yaxis = list(title = 'Time'),
                 zaxis = list(title = 'Wood_type'),
                 aspectmode = 'cube')) %>%
  colorbar(title = "Yield")
LS0tDQp0aXRsZTogIkZhY3RvcmlhbCBkZXNpZ24iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgY29kZV9mb2xkaW5nOiBoaWRlIA0KICAgIGNvZGVfZG93bmxvYWQ6IFRydWUNCi0tLQ0KDQo8YnIvPg0KDQpTaSB2dW9sZSBtaXN1cmFyZSB1bmEgY2VydGEgcmlzcG9zdGEgc3BlcmltZW50YWxlIGFsIHZhcmlhcmUgZGkgdHJlIHBhcmFtZXRyaSBzcGVjaWZpY2kgKGR1ZSBkaSBwcm9jZXNzbyBlIHVubyBxdWFsaXRhdGl2byk6DQoNCi0gICB0ZW1wZXJhdHVyYQ0KLSAgIGR1cmF0YSBkZWwgdHJhdHRhbWVudG8NCi0gICB0aXBvIGRpIGxlZ25vDQoNClNpIGluaXppYSBjcmVhbmRvIHVuYSB0YWJlbGxhIGRvdmUgb2duaSBjb2xvbm5hIMOoIHVuIGZhdHRvcmUgZSBvZ25pIHJpZ2Egw6ggdW4gbGl2ZWxsbyBzZWNvbmRvIGlsIG1vZGVsbG8gcG9zdHVsYXRvIG90dGVudXRvIGNvbiAkMl4zJCBjb25kaXppb25pIHNwZXJpbWVudGFsaSwgb3Z2ZXJvIDMgZmF0dG9yaSBlIDIgbGl2ZWxsaSwgcHJldmVkZW5kbyBhbG1lbm8gdW4gcGFpbyBkaSByZXBsaWNoZS4gXA0KDQo8YnIvPg0KDQo8Y2VudGVyPg0KDQohW10oZmFjdG9yaWFsLnBuZyl7d2lkdGg9IjI1MCJ9DQoNCjwvY2VudGVyPg0KDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpgYGB7ciBMaWJyYXJpZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShqYW5pdG9yKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShyZXNoYXBlMikNCg0KYGBgDQoNCmBgYHtyfQ0KZGYgPSBkYXRhLmZyYW1lKA0KICBUZW1wZXJhdHVyZSA9IGMoMTYwLDE4MCwxNjAsMTgwLDE2MCwxODAsMTYwLDE4MCwxNjAsMTgwLDE2MCwxODAsMTYwLDE4MCwxNjAsMTgwKSwNCiAgRHVyYXRpb24gPSBjKDIwLDIwLDQwLDQwLDIwLDIwLDQwLDQwLDIwLDIwLDQwLDQwLDIwLDIwLDQwLDQwKSwNCiAgV29vZF90eXBlID0gYygnQScsJ0EnLCdBJywnQScsJ0InLCdCJywnQicsJ0InLCdBJywnQScsJ0EnLCdBJywnQicsJ0InLCdCJywnQicpLA0KICBZID0gYyg1OSw3NCw1MCw2OSw1MCw4MSw0Niw3OSw2MSw3MCw1OCw2Nyw1NCw4NSw0NCw4MSkNCikNCiNEVDo6ZGF0YXRhYmxlKGRmKQ0KZGYgJT4lIGthYmxlKCkgJT4lIGthYmxlX21hdGVyaWFsKCdzdHJpcGVkJykNCiANCg0KYGBgDQo8YnIvPg0KDQo8Y2VudGVyPg0KYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnBsb3RfbHkoZGYsIHggPSB+VGVtcGVyYXR1cmUsIHkgPSB+RHVyYXRpb24sIHogPSB+V29vZF90eXBlKSAlPiUNCiAgYWRkX21hcmtlcnMoKSAgDQoNCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCkRvcG9kaWNow6kgY3JlbyB1bmEgdGFiZWxsYSBjb24gaSB2YWxvcmkgcHJlY2VkZW50aSBjb2RpZmljYW5kb2xpIGNvbWUgJC0xJCBlICQrMSQgXA0KDQo8YnIvPg0KDQpgYGB7cn0NCg0KeDEgPSBjKCkNCngyID0gYygpDQp4MyA9IGMoKQ0KDQpsZXZlbHMgPSBjKC0xLDEpDQoNCmZvciAoayBpbiAxOjIpew0KICBmb3IgKGogaW4gMToyKSB7DQogICAgZm9yIChpIGluIDE6Mikgew0KICAgICAgeDEgPSBjKHgxLCBsZXZlbHNbaV0pDQogICAgICB4MiA9IGMoeDIsIGxldmVsc1tqXSkNCiAgICAgIHgzID0gYyh4MywgbGV2ZWxzW2tdKQ0KICAgIH0NCiAgfQ0KfQ0KDQp4MSA9IGMoeDEseDEpDQp4MiA9IGMoeDIseDIpDQp4MyA9IGMoeDMseDMpDQoNCmRmMSA9IGRhdGEuZnJhbWUoeDEseDIseDMsWSA9IGMoNTksNzQsNTAsNjksNTAsODEsNDYsNzksNjEsNzAsNTgsNjcsNTQsODUsNDQsODEpKQ0KDQpmaWcgPSBkZjEgJT4lIGthYmxlKCkgJT4lIGthYmxlX3N0eWxpbmcoIGZ1bGxfd2lkdGggPSBUKSANCg0KZm9yIChtIGluIDE6KG5jb2woZGYxKS0xKSkgew0KIGZpZyA9IGNvbHVtbl9zcGVjKGZpZywgbSAsY29sb3I9ICd3aGl0ZScsIGJhY2tncm91bmQgPSBzcGVjX2NvbG9yKGRmMVssbV0sZW5kID0gMC43LCBvcHRpb24gPSAnQScgKSkNCn0NCg0KZmlnICU+JSAgY29sdW1uX3NwZWMoIG5jb2woZGYxKSAsY29sb3I9ICd3aGl0ZScsIGJhY2tncm91bmQgPSAnZGFya2dyZWVuJykNCg0KYGBgDQo8YnIvPg0KDQotLS0NCg0KQWRlc3NvIGFnZ2l1bmdvIGxlIGFsdHJlIGNvbG9ubmUgc2VndWVuZG8gaWwgbW9kZWxsbyBwb3N0dWxhdG8NCg0KDQokJA0KICBZID0gYl8wK2JfMXhfMStiXzJ4XzIrYl8zeF8zK2JfezEyfXhfMXhfMitiX3sxM314XzF4XzMrYl97MjN9eF8yeF8zK2JfezEyM314XzF4XzJ4XzMNCiQkDQoNCjxici8+DQoNCg0KDQpgYGB7cn0NCmRmMyA9IG11dGF0ZShkZjEsIHgxeDIgPSB4MSp4MiwgeDF4Mz0geDEqeDMsIHgyeDM9eDIqeDMsIHgxeDJ4MyA9IHgxKngyKngzKQ0KZGYzID0gcmVsb2NhdGUoZGYzLCBZLCAuYWZ0ZXIgPSBsYXN0X2NvbCgpKQ0KDQpmaWcgPSBkZjMgJT4lIGthYmxlKCkgJT4lIGthYmxlX3N0eWxpbmcoIGZ1bGxfd2lkdGggPSBUKSANCg0KZm9yIChtIGluIDE6KG5jb2woZGYzKS0xKSkgew0KIGZpZyA9IGNvbHVtbl9zcGVjKGZpZywgbSAsY29sb3I9ICd3aGl0ZScsIGJhY2tncm91bmQgPSBzcGVjX2NvbG9yKGRmM1ssbV0sZW5kID0gMC43LCBvcHRpb24gPSAnQScgKSkNCn0NCg0KZmlnICU+JSAgY29sdW1uX3NwZWMoIG5jb2woZGYzKSAsY29sb3I9ICd3aGl0ZScsIGJhY2tncm91bmQgPSAnZGFya2dyZWVuJykNCg0KYGBgDQoNCg0KDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCkNyZW8gdW4gbW9kZWxsbyBkaSByZWdyZXNzaW9uZSANCg0KPGJyLz4NCg0KYGBge3J9DQphID0gYygpDQpmb3IgKGkgaW4gY29sbmFtZXMoZGYzWy1uY29sKGRmMyldKSl7DQogIGEgPSBwYXN0ZShhICwgJysnLCBpLCBzZXAgPSAnJykNCn0NCmZtbGEgPSBhcy5mb3JtdWxhKHBhc3RlKCdZIH4gJywgYSkpDQoNCm1vZGVsID0gbG0oZm1sYSwgZGYzKQ0KbW9kZWwNCg0KYGBgDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCnN1bW1hcnkobW9kZWwpDQoNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KT3NzZXJ2byBsYSBzaWduaWZpY2F0aXZpdMOgIGRpIFAgZSBzY2FydG8gaSB2YWxvcmkgc3VwZXJpb3JpIGFsIG1pbyBsaW1pdGUgZGkgY29uZmlkZW56YSAoNSUpLiBJbCBQLXZhbHVlIHB1w7IgZXNzZXJlIHZpc3RvIGNvbWUgbGEgcHJvYmFiaWxpdMOgIGRpIHNiYWdsaWFyZSBuZWwgcmlnZXR0YXJlIGwnaXBvdGVzaSBudWxsYS5cDQoNCihOb3RvIGNoZSBjJ8OoIHVuYSBjb3JyZWxhemlvbmUgdHJhICR4XzEkIGUgJHhfMyQgKHRlbXBlcmF0dXJhIGUgdGlwbyBkaSBsZWdubyksIHF1aW5kaSB0ZW5nbyBjb21lIHNpZ25pZmljYXRpdm8gYW5jaGUgaWwgdmV0dG9yZSAkeF8zJClcDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpSaXBldG8gbGEgcmVncmVzc2lvbmUgZG9wbyBhdmVyIHNjYXJ0YXRhdG8gZGFsbGEgbWlhIHRhYmVsbGEgbGUgdHJlIGNvbG9ubmUgbm9uIHNpZ25pZmljYXRpdmU6ICR4XzF4XzIseF8yeF8zLHhfMXhfMnhfMyQNCg0KYGBge3J9DQptb2RlbDIgPSBsbShZIH4geDEgKyB4MiArIHgzICsgeDF4MywgZGYzKQ0Kc3VtbWFyeShtb2RlbDIpDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCklsIHZldHRvcmUgY29uIGkgdmFsb3JpIGNhbGNvbGF0aSBzYXLDoA0KDQpgYGB7cn0NCmZpdHRlZChtb2RlbDIpDQoNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KUG9zc28gYSBxdWVzdG8gcHVudG8gY3JhcmUgdW4gZ3JhZmljbyBwZXIgdmVkZXJlIGkgdmFsb3JpIG9zc2VydmF0aSBzcGVyaW1lbnRhbG1lbnRlIGUgcXVlbGxpIGNhbGNvbGF0aSBkYWwgbW9kZWxsbyBkaSByZWdyZXNzaW9uZQ0KDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJ30NCg0KZGZfeSA9IGRhdGEuZnJhbWUoWV9jYWw9Zml0dGVkKG1vZGVsMiksIFlfc3BlciA9IGRmMyRZKQ0KDQpiaXNldHRyaWNlID0gZGF0YS5mcmFtZSh4PWMoNDAsOTApLCB5PWMoNDAsOTApKQ0KDQpnZ3Bsb3QoZGZfeSwgYWVzKFlfc3BlcixZX2NhbCkpKyANCiAgZ2VvbV9wb2ludCgpKyANCiAgZ2VvbV9saW5lKGRhdGE9YmlzZXR0cmljZSwgYWVzKHgseSwgY29sb3I9J3JlZCcpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSsgDQogIGdndGl0bGUoICdZIHNwZXJpbWVudGFsZSB2cyBZIGNhbGNvbGF0YScpKyANCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpDQogIA0KYGBgDQo8YnIvPg0KDQpgYGB7cn0NCm1vZGVsY29lZmYgPSBjb2VmZmljaWVudHMobW9kZWwyKQ0KbW9kZWxjb2VmZiAlPiUgcm91bmQoZGlnaXRzID0gMikNCg0KYGBgDQo8YnIvPg0KDQoNCmBgYHtyfQ0KDQp4ID0gc2VxKGZyb20gPSAtMSwgIHRvID0gMSwgYnkgPSAwLjEpDQp5ID0gc2VxKGZyb20gPSAtMSwgIHRvID0gMSwgYnkgPSAwLjEpDQp4MyA9IGMoLTEsMSkNCnogPSBjKCkNCg0KZm9yIChrIGluIHgzKSB7DQogIGZvciAoaiBpbiB5KXsNCiAgICBmb3IgKGkgaW4geCl7DQogICAgeiA9IGMoeiwgbW9kZWxjb2VmZlsxXSttb2RlbGNvZWZmWzJdKmkrbW9kZWxjb2VmZlszXSpqKyBtb2RlbGNvZWZmWzRdKmsrbW9kZWxjb2VmZls1XSppKmspDQogICAgfQ0KICB9DQp9DQp6ID0gYXJyYXkoeiwgZGltID0gYyhsZW5ndGgoeCksIGxlbmd0aCh5KSxsZW5ndGgoeDMpKSkNCg0KWiA9IG1lbHQoeikNCg0KVGVtcCA9IHNlcShmcm9tID0gMTYwLCB0byA9IDE4MCwgYnkgPSAxKSANClRpbWUgPSBzZXEoZnJvbSA9IDIwLCB0byA9IDQwLCBieSA9IDEpDQpXb29kID0gYygxOjIpDQpXZCA9IGMoKQ0KVG0gPSBjKCkNClRwID0gYygpDQoNCmZvciAoayBpbiBXb29kKSB7DQogIGZvciAoaiBpbiBUaW1lKXsNCiAgICBmb3IgKGkgaW4gVGVtcCl7DQogICAgICBUcCA9IGMoVHAsIGkpDQogICAgICBUbSA9IGMoVG0sIGopDQogICAgICBXZCA9IGMoV2QsIGspDQogICAgDQogICAgfQ0KICB9DQp9DQoNCg0KcGxvdF9seSh4PVRwLCB5PSBUbSwgej0gV2QsIGNvbG9yID0gWiR2YWx1ZSkgJT4lIGFkZF9tYXJrZXJzKCkgJT4lDQogIGxheW91dChzY2VuZSA9IGxpc3QoDQogICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdUZW1wZXJhdHVyZScpLA0KICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnVGltZScpLA0KICAgICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnV29vZF90eXBlJyksDQogICAgICAgICAgICAgICAgIGFzcGVjdG1vZGUgPSAnY3ViZScpKSAlPiUNCiAgY29sb3JiYXIodGl0bGUgPSAiWWllbGQiKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQo=