package <U+393C><U+3E31>rsm<U+393C><U+3E32> was built under R version 3.5.3
Attaching package: <U+393C><U+3E31>rsm<U+393C><U+3E32>

The following objects are masked from <U+393C><U+3E31>package:qualityTools<U+393C><U+3E32>:

    cube, star

PROCESS IMPROVEMENT WITH STEEPEST ASCENT

Ejercicio 5.1,

dada la funcion \(\hat{y}=72.0+3.6x_1 - 2.5x_2\)

Problema a) grafique

Definimos nuestra funcion f_plano51 que haremos plot

f_plano51 <- function(x1, x2)
{
  y=72.0+(3.6*x1) - (2.5*x2)
  return(y)
}

la funcion Outer produce un producto carteciano del los valores indicados contruyendo una matriz

p.x1 <- p.x2 <- seq(-12, 12, length= 50)
p.y <- outer(p.x1, p.x2, f_plano51)
str(p.y)
 num [1:50, 1:50] 58.8 60.6 62.3 64.1 65.9 ...
par(bg = "slategray")
persp(p.x1, p.x2, p.y,
main="Perspective Plot of a Cone",
zlab = "y",
theta = 30, phi = 15,
col = "springgreen", shade = 0.5
,ticktype = "detailed"
)

Problema b) calcular el path del ascent generado utilizando $=1 $

Basado en RSM https://www.rdocumentation.org/packages/rsm/versions/2.10/topics/rsm

Utilizando Ave para crear el producto del par ordenado y SRM Construimos el path y el contorno

p.res=c()
for (i in 1:50){
  for (j in 1:50){
    
    p.res<-rbind( p.res,c( p.x1[i]*3.6,     - 2.5*p.x1[j],     72.0 ,    p.y[i,j]    )) 
    
}
}
df <- data.frame(p.res)
names(df) <- c('x1', 'x2', 'b', 'y')
df
heli.rsm = rsm (y ~ b+FO( x1 , x2), data = df) 
steepest(heli.rsm)
Path of steepest ascent from ridge analysis:
prediction from a rank-deficient fit may be misleading

Visualizamos el contorno

contour(heli.rsm, ~FO(x1, x2), image=TRUE, at=summary(heli.rsm$canonical$xs))
prediction from a rank-deficient fit may be misleading

Ejercicio 5.2,

dada la funcion \(\hat{y}=25+4x_1 + 3x_2-2.5x_3\) deseamos maximizar la resupesta

Basandonos en la libreria de QualityTools https://rdrr.io/cran/qualityTools/man/steepAscent.html

Definimos nuestro modelo de factorial de cubo

configuracion <- facDesign(k=3, p = 0, replicates = 1, blocks = 1, centerCube = 0)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated

definimos entonces nuestro data frame basado en el set que acabamos de construir

df <- as.data.frame(configuracion)
df

definimos la Y hat y asignamos la respuesta esto nos dara el resultado de la iteracion del Data frame

yfactor<-25+4*df$A+3*df$B-2.5*df$C
response(configuracion) <- yfactor
summary(configuracion)
Information about the factors:
-----------

verificaremos la estructura, vemos que la collection contiene el listado de factores

str(configuracion)
Formal class 'facDesign' [package "qualityTools"] with 15 slots
  ..@ name         : chr(0) 
  ..@ factors      :List of 3
  .. ..$ A:Formal class 'doeFactor' [package "qualityTools"] with 5 slots
  .. .. .. ..@ low : num -1
  .. .. .. ..@ high: num 1
  .. .. .. ..@ name: chr ""
  .. .. .. ..@ unit: chr ""
  .. .. .. ..@ type: chr "numeric"
  .. ..$ B:Formal class 'doeFactor' [package "qualityTools"] with 5 slots
  .. .. .. ..@ low : num -1
  .. .. .. ..@ high: num 1
  .. .. .. ..@ name: chr ""
  .. .. .. ..@ unit: chr ""
  .. .. .. ..@ type: chr "numeric"
  .. ..$ C:Formal class 'doeFactor' [package "qualityTools"] with 5 slots
  .. .. .. ..@ low : num -1
  .. .. .. ..@ high: num 1
  .. .. .. ..@ name: chr ""
  .. .. .. ..@ unit: chr ""
  .. .. .. ..@ type: chr "numeric"
  ..@ cube         :'data.frame':   8 obs. of  3 variables:
  .. ..$ A: num [1:8] -1 1 -1 1 -1 1 -1 1
  .. ..$ B: num [1:8] -1 -1 1 1 -1 -1 1 1
  .. ..$ C: num [1:8] -1 -1 -1 -1 1 1 1 1
  ..@ star         :'data.frame':   0 obs. of  0 variables
Formal class 'data.frame' [package "methods"] with 4 slots
  .. .. ..@ .Data    : list()
  .. .. ..@ names    : chr(0) 
  .. .. ..@ row.names: int(0) 
  .. .. ..@ .S3Class : chr "data.frame"
  ..@ centerCube   :'data.frame':   0 obs. of  0 variables
Formal class 'data.frame' [package "methods"] with 4 slots
  .. .. ..@ .Data    : list()
  .. .. ..@ names    : chr(0) 
  .. .. ..@ row.names: int(0) 
  .. .. ..@ .S3Class : chr "data.frame"
  ..@ centerStar   :'data.frame':   0 obs. of  0 variables
Formal class 'data.frame' [package "methods"] with 4 slots
  .. .. ..@ .Data    : list()
  .. .. ..@ names    : chr(0) 
  .. .. ..@ row.names: int(0) 
  .. .. ..@ .S3Class : chr "data.frame"
  ..@ generator    : NULL
  ..@ response     :'data.frame':   8 obs. of  1 variable:
  .. ..$ yfactor: num [1:8] 20.5 28.5 26.5 34.5 15.5 23.5 21.5 29.5
  ..@ block        :'data.frame':   8 obs. of  1 variable:
  .. ..$ Block: num [1:8] 1 1 1 1 1 1 1 1
  ..@ blockGen     :'data.frame':   0 obs. of  0 variables
Formal class 'data.frame' [package "methods"] with 4 slots
  .. .. ..@ .Data    : list()
  .. .. ..@ names    : chr(0) 
  .. .. ..@ row.names: int(0) 
  .. .. ..@ .S3Class : chr "data.frame"
  ..@ runOrder     :'data.frame':   8 obs. of  1 variable:
  .. ..$ RunOrder: int [1:8] 8 3 2 1 4 5 6 7
  ..@ standardOrder:'data.frame':   8 obs. of  1 variable:
  .. ..$ StandOrder: int [1:8] 1 2 3 4 5 6 7 8
  ..@ desireVal    : list()
  ..@ desirability : list()
  ..@ fits         : list()
configuracion@factors
$`A`
Name:   
low Setting:  -1 
high setting:  1 
Unit:   
type:  numeric 


$B
Name:   
low Setting:  -1 
high setting:  1 
Unit:   
type:  numeric 


$C
Name:   
low Setting:  -1 
high setting:  1 
Unit:   
type:  numeric 

Operamos el ascent

tabla = steepAscent(c("A","B","C"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
df_tabla_real <- as.data.frame(tabla)
df_tabla_real
y_predicho <- 25+4*df_tabla_real$A.real+3*df_tabla_real$B.real-2.5*df_tabla_real$C.real
response(tabla) <- y_predicho
tabla
plot(tabla)

Ejercicio 5.3

reconsideramndo el modelo del primer problema defina el path con un delta de 1 para x2

problema a y B) Grafique el path En esta ocacion utilizaremos el metodo de factorial del escenario anterior con el primer modelo los pasos son los siguiente 1. crear el modelo de factores 2. asignar el data set 3. escribir la funcion 4.1 construimos la tabla de steepent ascent para AB 4.2 construimos la tabla de steepent ascent para BA 5.1 construiremos la data con informacion real contra el estimado del steepest ascent AB con size 1 5.2 construiremos la data con informacion real contra el estimado del steepest ascent BA con size 1 6.1 Construimos los y predicho con los valores reales AB 6.2 Construimos los y predicho con los valores reales BA 7.1 generamos el plot con respoecto a BA (en Azul) 7.1 generamos el plot con respoecto a AB (en rojo)

configuracion <- facDesign(k=2)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated
df <- as.data.frame(configuracion)
yfactor<-72+3.6*df$A-2.5*df$B
response(configuracion) <- yfactor
tablaAB = steepAscent(c("A","B"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
tablaBA = steepAscent(c("B","A"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
df_tabla_realAB <- as.data.frame(tablaAB)
df_tabla_realBA <- as.data.frame(tablaBA)
y_predichoAB <- 72+3.6*df_tabla_realAB$A.real-2.5*df_tabla_realAB$B.real
y_predichoBA <- 72+3.6*df_tabla_realBA$A.real-2.5*df_tabla_realBA$B.real
response(tablaAB) <- y_predichoAB
response(tablaBA) <- y_predichoBA
tablaBA
df_BA <- as.data.frame(tablaBA)
df_AB <- as.data.frame(tablaAB)
plot(tablaBA)+ lines(df_BA$Delta,df_BA$y_predichoBA, col="blue" )+lines(df_AB$Delta,df_AB$y_predichoAB, col="red", type='l') +
  lines(df_BA$Delta,df_BA$y_predichoBA, col="blue", type='h' )
integer(0)

Como podemos ver en las lineas los “Y” predichos de BA estan creciendo mucho mas rapido para un size=1 en ambos casos

Ejercicio 5.4

Basados en el ejercicio 5.2 ## Problema a) muestre que tando se separa de la base y el delta es de 4 para AB en x1

configuracion <- facDesign(k=3, p = 0, replicates = 1, blocks = 1, centerCube = 1)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated
df <- as.data.frame(configuracion)
yfactor<-25+4*df$A+3*df$B-2.5*df$C
response(configuracion) <- yfactor
tablaAB = steepAscent(c("A","B","C"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
tabla4delta = steepAscent(c("A","B","C"), response = "yfactor", size = 4,data = configuracion)

Steepest Ascent for configuracion 
df_tabla_realAB <- as.data.frame(tablaAB)
df_tabla_real4delta <- as.data.frame(tabla4delta)
y_predichoAB <- 25+4*df_tabla_realAB$A.real+3*df_tabla_realAB$B.real-2.5*df_tabla_realAB$C.real
y_predicho4delta <- 25+4*df_tabla_real4delta$A.real+3*df_tabla_real4delta$B.real-2.5*df_tabla_real4delta$C.real
response(tablaAB) <- y_predichoAB
response(tabla4delta) <- y_predicho4delta
tabla4delta
df_AB <- as.data.frame(tablaAB)
df_4delta <- as.data.frame(tabla4delta)
plot(tabla4delta)+ 
  lines(df_4delta$Delta,df_4delta$y_predicho4delta, col="blue" )+
  lines(df_AB$Delta,df_AB$y_predichoAB, col="red", type='l') 
integer(0)
  lines(df_4delta$Delta,df_4delta$y_predicho4delta, col="blue", type='h' )

NA

como podemos ver la linea azul es el predicho por un delta de 4

Problema b y c)

recalcule considerendo ahora con x2 considerando 1delta y la base en 4delta

configuracion <- facDesign(k=3, p = 0, replicates = 1, blocks = 1, centerCube = 1)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated
df <- as.data.frame(configuracion)
yfactor<-25+4*df$A+3*df$B-2.5*df$C
response(configuracion) <- yfactor
tablaAB = steepAscent(c("B","A","C"), response = "yfactor", size = 4,data = configuracion)

Steepest Ascent for configuracion 
tabla4delta = steepAscent(c("B","A","C"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
df_tabla_realAB <- as.data.frame(tablaAB)
df_tabla_real4delta <- as.data.frame(tabla4delta)
y_predichoAB <- 25+4*df_tabla_realAB$A.real+3*df_tabla_realAB$B.real-2.5*df_tabla_realAB$C.real
y_predicho4delta <- 25+4*df_tabla_real4delta$A.real+3*df_tabla_real4delta$B.real-2.5*df_tabla_real4delta$C.real
response(tablaAB) <- y_predichoAB
response(tabla4delta) <- y_predicho4delta
tabla4delta
df_AB <- as.data.frame(tablaAB)
df_4delta <- as.data.frame(tabla4delta)
plot(tabla4delta)+ 
  lines(df_4delta$Delta,df_4delta$y_predicho4delta, col="blue" )+
  lines(df_AB$Delta,df_AB$y_predichoAB, col="red", type='l') 
integer(0)
  lines(df_4delta$Delta,df_4delta$y_predicho4delta, col="blue", type='h' )

NA

Como podemos observar aunque los dos metodos parten del mismo punto, la base con un delta de 4 crece mucho mas rapido

Problema 5.5

Primero construiremos el arreglo de respuestas diseñamos nuestro modelo de factor con k=4, y nuestro grid de productos ABCD y construimos el resultado basandonos en 2 a la 4 en nuestro diseño de factorial 4 efectos principales: a para el factorA, b para el factor B, c para el factor C y ?? para el factor D 6 efectos para las interacciones de orden 2, AB, AC, AD, BC, BD, CD 4 efectos para las interacciones de orden 3, ABC, ABD, BCD, ACD 1 efecto para la interacción de orden 4, ABCD

formula a utilizar y=a+b+c+d+ab+ac+ad+bc+bd+cd+abc+abd+acd+bcd+abcd

m=expand.grid(A=factor(c(-1,1)),B=factor(c(-1,1)),
              C=factor(c(-1,1)),D=factor(c(-1,1)))
m
lecturas<-unlist(m)
mx2 <- rbind(m,m)
features <- matrix(lecturas,ncol=4,byrow=TRUE)
features <- rbind(features,features)
print("duplicamos los features puesto que son dos lecturas")
[1] "duplicamos los features puesto que son dos lecturas"
features
      [,1] [,2] [,3] [,4]
 [1,] "-1" "1"  "-1" "1" 
 [2,] "-1" "1"  "-1" "1" 
 [3,] "-1" "1"  "-1" "1" 
 [4,] "-1" "1"  "-1" "1" 
 [5,] "-1" "-1" "1"  "1" 
 [6,] "-1" "-1" "1"  "1" 
 [7,] "-1" "-1" "1"  "1" 
 [8,] "-1" "-1" "1"  "1" 
 [9,] "-1" "-1" "-1" "-1"
[10,] "1"  "1"  "1"  "1" 
[11,] "-1" "-1" "-1" "-1"
[12,] "1"  "1"  "1"  "1" 
[13,] "-1" "-1" "-1" "-1"
[14,] "-1" "-1" "-1" "-1"
[15,] "1"  "1"  "1"  "1" 
[16,] "1"  "1"  "1"  "1" 
[17,] "-1" "1"  "-1" "1" 
[18,] "-1" "1"  "-1" "1" 
[19,] "-1" "1"  "-1" "1" 
[20,] "-1" "1"  "-1" "1" 
[21,] "-1" "-1" "1"  "1" 
[22,] "-1" "-1" "1"  "1" 
[23,] "-1" "-1" "1"  "1" 
[24,] "-1" "-1" "1"  "1" 
[25,] "-1" "-1" "-1" "-1"
[26,] "1"  "1"  "1"  "1" 
[27,] "-1" "-1" "-1" "-1"
[28,] "1"  "1"  "1"  "1" 
[29,] "-1" "-1" "-1" "-1"
[30,] "-1" "-1" "-1" "-1"
[31,] "1"  "1"  "1"  "1" 
[32,] "1"  "1"  "1"  "1" 
observation <- c(30.3,28.5,24.5,25.9,24.8,26.9,24.8,22.2,31.7,24.6,27.6,26.3,29.9,26.8,26.4,26.9,28.6,31.4,25.6,27.2,23.4,23.8,27.8,24.9,33.5,26.2,30.6,27.8,27.7,24.2,24.9,29.3)
experiment <- tibble(A=mx2$A,
                     B=mx2$B,
                     C=mx2$C,
                     D=mx2$D,
                     Y=observation)
print("verificamos como queda el experimiento:")
[1] "verificamos como queda el experimiento:"
experiment
df2<-experiment[complete.cases(experiment),]
df2
fit<- lm(Y~A+B+C+D+(A*B)+(A*C)+(A*D)+(B*C)+(B*D)+(C*D)+(A*B*C)+(A*B*D)+(A*C*D)+(B*C*D)+(A*B*C*D),data=df2)
summary(fit)

Call:
lm(formula = Y ~ A + B + C + D + (A * B) + (A * C) + (A * D) + 
    (B * C) + (B * D) + (C * D) + (A * B * C) + (A * B * D) + 
    (A * C * D) + (B * C * D) + (A * B * C * D), data = df2)

Residuals:
   Min     1Q Median     3Q    Max 
 -1.55  -0.95   0.00   0.95   1.55 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   29.450      1.109  26.554 1.16e-14 ***
A1             0.500      1.568   0.319  0.75401    
B1            -4.400      1.568  -2.805  0.01270 *  
C1            -5.350      1.568  -3.411  0.00358 ** 
D1             3.150      1.568   2.008  0.06179 .  
A1:B1          1.000      2.218   0.451  0.65816    
A1:C1          0.750      2.218   0.338  0.73966    
A1:D1         -7.700      2.218  -3.471  0.00315 ** 
B1:C1          6.600      2.218   2.976  0.00892 ** 
B1:D1          0.900      2.218   0.406  0.69030    
C1:D1          1.550      2.218   0.699  0.49471    
A1:B1:C1      -5.000      3.137  -1.594  0.13051    
A1:B1:D1       4.150      3.137   1.323  0.20444    
A1:C1:D1       3.150      3.137   1.004  0.33024    
B1:C1:D1      -6.250      3.137  -1.992  0.06367 .  
A1:B1:C1:D1    5.600      4.436   1.262  0.22492    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.568 on 16 degrees of freedom
Multiple R-squared:  0.819, Adjusted R-squared:  0.6494 
F-statistic: 4.828 on 15 and 16 DF,  p-value: 0.001646

Como podemos ver las variables en nuestro modelo deben considerar a las betas mas significativas

Y=29.45 + -4.4B-5.3C+3.15D-7.7(AD)+6.6(BC)-6.25(BCD)

Problema b)

Utilizaremos qualitytool determinaremos el path del steepest acent

configuracion <- facDesign(k=4, p = 0, replicates = 1, blocks = 1, centerCube = 1)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated
df <- as.data.frame(configuracion)
yfactor<-29.45 -4.4*df$B-5.3*df$C+3.15*df$D-7.7*(df$A*df$D)+6.6*(df$B*df$C)-6.25*(df$B*df$C*df$D)
response(configuracion) <- yfactor
tablaAB = steepAscent(c("A","B","C","D"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
                29.45 -4.4*df$B-5.3*df$C+3.15*df$D-7.7*(df$A*df$D)+6.6*(df$B*df$C)-6.25*(df$B*df$C*df$D)
 [1] 22.05 50.35  6.65 15.55 23.65 56.55 21.75 25.45 40.85 34.95  4.85 29.45 30.95 39.05 20.25 41.15 37.15
df_tabla_realAB <- as.data.frame(tablaAB)                
y_predichoAB <- 29.45 -4.4*df_tabla_realAB$B.real-5.3*df_tabla_realAB$C.real+3.15*df_tabla_realAB$D.real-7.7*(df_tabla_realAB$A.real*df_tabla_realAB$D.real)+6.6*(df_tabla_realAB$B.real*df_tabla_realAB$C.real)-6.25*(df_tabla_realAB$B.real*df_tabla_realAB$C.real*df_tabla_realAB$D.real)
response(tablaAB) <- y_predichoAB
tablaAB
df_AB <- as.data.frame(tablaAB)
plot(tablaAB)+ lines(df_AB$Delta,df_AB$y_predichoAB, col="blue" )
integer(0)

NA
NA

problema c) restringiendo x1+x2=2.7

Problema 5.7

E( y) = 14 + 5x1 - 10x2 + 3x1x2

problema a) Grafique el path basandose en los parametros actuales si la interaccion x1x2 es ignorada

Utilizando qualitytool para k2

configuracion <- facDesign(k=2, p = 0, replicates = 1, blocks = 1, centerCube = 1)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated
df <- as.data.frame(configuracion)
yfactor<- 14+5*df$A- 10*df$B + 3*df$A*df$B*0
response(configuracion) <- yfactor
tablaAB = steepAscent(c("A","B"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
df_tabla_realAB <- as.data.frame(tablaAB)                
y_predichoAB <- 14 +(5*df_tabla_realAB$A.coded)-(10*df_tabla_realAB$B.coded)+(3*df_tabla_realAB$A.coded*df_tabla_realAB$B.coded*0)
response(tablaAB) <- y_predichoAB
tablaAB
df_AB <- as.data.frame(tablaAB)
dflineal<-df_AB
plot(tablaAB)+ lines(df_AB$Delta,df_AB$y_predichoAB, col="blue" )
integer(0)

Problema B) muestre la relacion con x1*x2

configuracion <- facDesign(k=2, p = 0, replicates = 1, blocks = 1, centerCube = 1)
implicit list embedding of S4 objects is deprecatedimplicit list embedding of S4 objects is deprecated
df <- as.data.frame(configuracion)
yfactor<- 14+5*df$A- 10*df$B + 3*df$A*df$B
response(configuracion) <- yfactor
tablaAB = steepAscent(c("A","B"), response = "yfactor", size = 1,data = configuracion)

Steepest Ascent for configuracion 
df_tabla_realAB <- as.data.frame(tablaAB)                
y_predichoAB <- 14 +(5*df_tabla_realAB$A.coded)-(10*df_tabla_realAB$B.coded)+(3*df_tabla_realAB$A.coded*df_tabla_realAB$B.coded)
response(tablaAB) <- y_predichoAB
tablaAB
df_AB <- as.data.frame(tablaAB)
plot(tablaAB)+ lines(df_AB$Delta,df_AB$y_predichoAB, col="blue" )+ lines(dflineal$Delta,dflineal$y_predichoAB, col="blue" )
integer(0)

problema c) Aunque los dos puntos parten de la misma linea, vemos como la relación no lineal de x1x2 hace que el valor predicho de calculo se degrade con el delta

LS0tDQp0aXRsZTogIkVjb25vbWV0cmlhIDIgZmluYWwiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KYGBge3IgZWNobz1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkoY2xhc3MpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KElTTFIpDQpsaWJyYXJ5KHJzbSkNCmxpYnJhcnkocXVhbGl0eVRvb2xzKQ0KYGBgDQoNCiMgUFJPQ0VTUyBJTVBST1ZFTUVOVCBXSVRIIFNURUVQRVNUIEFTQ0VOVA0KDQojIyBFamVyY2ljaW8gNS4xLCANCg0KDQpkYWRhIGxhIGZ1bmNpb24gJFxoYXR7eX09NzIuMCszLjZ4XzEgLSAyLjV4XzIkDQoNClByb2JsZW1hIGEpIGdyYWZpcXVlDQoNCkRlZmluaW1vcyBudWVzdHJhIGZ1bmNpb24gZl9wbGFubzUxIHF1ZSBoYXJlbW9zIHBsb3QNCg0KYGBge3J9DQpmX3BsYW5vNTEgPC0gZnVuY3Rpb24oeDEsIHgyKQ0Kew0KICB5PTcyLjArKDMuNip4MSkgLSAoMi41KngyKQ0KICByZXR1cm4oeSkNCn0NCmBgYA0KDQpsYSBmdW5jaW9uIE91dGVyIHByb2R1Y2UgdW4gcHJvZHVjdG8gY2FydGVjaWFubyBkZWwgbG9zIHZhbG9yZXMgaW5kaWNhZG9zIGNvbnRydXllbmRvIHVuYSBtYXRyaXoNCg0KYGBge3J9DQpwLngxIDwtIHAueDIgPC0gc2VxKC0xMiwgMTIsIGxlbmd0aD0gNTApDQpwLnkgPC0gb3V0ZXIocC54MSwgcC54MiwgZl9wbGFubzUxKQ0Kc3RyKHAueSkNCmBgYA0KDQpgYGB7cn0NCnBhcihiZyA9ICJzbGF0ZWdyYXkiKQ0KcGVyc3AocC54MSwgcC54MiwgcC55LA0KbWFpbj0iUGVyc3BlY3RpdmUgUGxvdCBvZiBhIENvbmUiLA0KemxhYiA9ICJ5IiwNCnRoZXRhID0gMzAsIHBoaSA9IDE1LA0KY29sID0gInNwcmluZ2dyZWVuIiwgc2hhZGUgPSAwLjUNCix0aWNrdHlwZSA9ICJkZXRhaWxlZCINCikNCmBgYA0KDQoNCg0KUHJvYmxlbWEgYikgY2FsY3VsYXIgZWwgcGF0aCBkZWwgYXNjZW50IGdlbmVyYWRvIHV0aWxpemFuZG8gJFxEZWx0YXt4XzF9PTEgJA0KDQpCYXNhZG8gZW4gUlNNDQpodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvcnNtL3ZlcnNpb25zLzIuMTAvdG9waWNzL3JzbQ0KDQpVdGlsaXphbmRvIEF2ZSBwYXJhIGNyZWFyIGVsIHByb2R1Y3RvIGRlbCBwYXIgb3JkZW5hZG8geSBTUk0gQ29uc3RydWltb3MgZWwgcGF0aCB5IGVsIGNvbnRvcm5vIA0KIA0KICAgDQpgYGB7cn0NCnAucmVzPWMoKQ0KZm9yIChpIGluIDE6NTApew0KICBmb3IgKGogaW4gMTo1MCl7DQogICAgDQogICAgcC5yZXM8LXJiaW5kKCBwLnJlcyxjKCBwLngxW2ldKjMuNiwgICAgIC0gMi41KnAueDFbal0sICAgICA3Mi4wICwgICAgcC55W2ksal0gICAgKSkgDQogICAgDQp9DQp9DQpkZiA8LSBkYXRhLmZyYW1lKHAucmVzKQ0KbmFtZXMoZGYpIDwtIGMoJ3gxJywgJ3gyJywgJ2InLCAneScpDQpkZg0KYGBgDQoNCmBgYHtyfQ0KaGVsaS5yc20gPSByc20gKHkgfiBiK0ZPKCB4MSAsIHgyKSwgZGF0YSA9IGRmKSANCnN0ZWVwZXN0KGhlbGkucnNtKQ0KYGBgDQoNCg0KDQpWaXN1YWxpemFtb3MgZWwgY29udG9ybm8NCmBgYHtyfQ0KY29udG91cihoZWxpLnJzbSwgfkZPKHgxLCB4MiksIGltYWdlPVRSVUUsIGF0PXN1bW1hcnkoaGVsaS5yc20kY2Fub25pY2FsJHhzKSkNCmBgYA0KDQoNCiMjIEVqZXJjaWNpbyA1LjIsIA0KZGFkYSBsYSBmdW5jaW9uICRcaGF0e3l9PTI1KzR4XzEgKyAzeF8yLTIuNXhfMyQgZGVzZWFtb3MgbWF4aW1pemFyIGxhIHJlc3VwZXN0YSANCg0KQmFzYW5kb25vcyBlbiBsYSBsaWJyZXJpYSBkZSBRdWFsaXR5VG9vbHMgDQpodHRwczovL3JkcnIuaW8vY3Jhbi9xdWFsaXR5VG9vbHMvbWFuL3N0ZWVwQXNjZW50Lmh0bWwgDQoNCkRlZmluaW1vcyBudWVzdHJvIG1vZGVsbyBkZSBmYWN0b3JpYWwgZGUgY3Vibw0KYGBge3J9DQoNCmNvbmZpZ3VyYWNpb24gPC0gZmFjRGVzaWduKGs9MywgcCA9IDAsIHJlcGxpY2F0ZXMgPSAxLCBibG9ja3MgPSAxLCBjZW50ZXJDdWJlID0gMCkNCmBgYA0KDQpkZWZpbmltb3MgZW50b25jZXMgbnVlc3RybyBkYXRhIGZyYW1lIGJhc2FkbyBlbiBlbCBzZXQgcXVlIGFjYWJhbW9zIGRlIGNvbnN0cnVpcg0KYGBge3J9DQpkZiA8LSBhcy5kYXRhLmZyYW1lKGNvbmZpZ3VyYWNpb24pDQpkZg0KYGBgDQpkZWZpbmltb3MgbGEgWSBoYXQgeSBhc2lnbmFtb3MgbGEgcmVzcHVlc3RhIGVzdG8gbm9zIGRhcmEgZWwgcmVzdWx0YWRvIGRlIGxhIGl0ZXJhY2lvbiBkZWwgRGF0YSBmcmFtZQ0KYGBge3J9DQp5ZmFjdG9yPC0yNSs0KmRmJEErMypkZiRCLTIuNSpkZiRDDQpyZXNwb25zZShjb25maWd1cmFjaW9uKSA8LSB5ZmFjdG9yDQpzdW1tYXJ5KGNvbmZpZ3VyYWNpb24pDQpgYGANCnZlcmlmaWNhcmVtb3MgbGEgZXN0cnVjdHVyYSwgdmVtb3MgcXVlIGxhIGNvbGxlY3Rpb24gY29udGllbmUgZWwgbGlzdGFkbyBkZSBmYWN0b3Jlcw0KDQpgYGB7cn0NCnN0cihjb25maWd1cmFjaW9uKQ0KDQpgYGANCmBgYHtyfQ0KY29uZmlndXJhY2lvbkBmYWN0b3JzDQoNCmBgYA0KDQoNCk9wZXJhbW9zIGVsIGFzY2VudCANCmBgYHtyfQ0KdGFibGEgPSBzdGVlcEFzY2VudChjKCJBIiwiQiIsIkMiKSwgcmVzcG9uc2UgPSAieWZhY3RvciIsIHNpemUgPSAxLGRhdGEgPSBjb25maWd1cmFjaW9uKQ0KYGBgDQpgYGB7cn0NCg0KZGZfdGFibGFfcmVhbCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhKQ0KZGZfdGFibGFfcmVhbA0KeV9wcmVkaWNobyA8LSAyNSs0KmRmX3RhYmxhX3JlYWwkQS5yZWFsKzMqZGZfdGFibGFfcmVhbCRCLnJlYWwtMi41KmRmX3RhYmxhX3JlYWwkQy5yZWFsDQpyZXNwb25zZSh0YWJsYSkgPC0geV9wcmVkaWNobw0KdGFibGENCg0KcGxvdCh0YWJsYSkNCmBgYA0KDQojIEVqZXJjaWNpbyA1LjMNCnJlY29uc2lkZXJhbW5kbyBlbCBtb2RlbG8gZGVsIHByaW1lciBwcm9ibGVtYSBkZWZpbmEgZWwgcGF0aCBjb24gdW4gZGVsdGEgZGUgMSBwYXJhIHgyDQoNCnByb2JsZW1hIGEgeSBCKSBHcmFmaXF1ZSBlbCBwYXRoDQpFbiBlc3RhIG9jYWNpb24gdXRpbGl6YXJlbW9zIGVsIG1ldG9kbyBkZSBmYWN0b3JpYWwgZGVsIGVzY2VuYXJpbyBhbnRlcmlvciBjb24gZWwgcHJpbWVyIG1vZGVsbw0KbG9zIHBhc29zIHNvbiBsb3Mgc2lndWllbnRlIA0KMS4gY3JlYXIgZWwgbW9kZWxvIGRlIGZhY3RvcmVzDQoyLiBhc2lnbmFyIGVsIGRhdGEgc2V0DQozLiBlc2NyaWJpciBsYSBmdW5jaW9uDQo0LjEgY29uc3RydWltb3MgbGEgdGFibGEgZGUgc3RlZXBlbnQgYXNjZW50IHBhcmEgQUINCjQuMiBjb25zdHJ1aW1vcyBsYSB0YWJsYSBkZSBzdGVlcGVudCBhc2NlbnQgcGFyYSBCQQ0KNS4xIGNvbnN0cnVpcmVtb3MgbGEgZGF0YSBjb24gaW5mb3JtYWNpb24gcmVhbCBjb250cmEgZWwgZXN0aW1hZG8gZGVsIHN0ZWVwZXN0IGFzY2VudCBBQiBjb24gc2l6ZSAxDQo1LjIgY29uc3RydWlyZW1vcyBsYSBkYXRhIGNvbiBpbmZvcm1hY2lvbiByZWFsIGNvbnRyYSBlbCBlc3RpbWFkbyBkZWwgc3RlZXBlc3QgYXNjZW50IEJBIGNvbiBzaXplIDENCjYuMSBDb25zdHJ1aW1vcyBsb3MgeSBwcmVkaWNobyBjb24gbG9zIHZhbG9yZXMgcmVhbGVzIEFCDQo2LjIgQ29uc3RydWltb3MgbG9zIHkgcHJlZGljaG8gY29uIGxvcyB2YWxvcmVzIHJlYWxlcyBCQQ0KNy4xIGdlbmVyYW1vcyBlbCBwbG90IGNvbiByZXNwb2VjdG8gYSBCQSAoZW4gQXp1bCkNCjcuMSBnZW5lcmFtb3MgZWwgcGxvdCBjb24gcmVzcG9lY3RvIGEgQUIgKGVuIHJvam8pDQoNCmBgYHtyfQ0KY29uZmlndXJhY2lvbiA8LSBmYWNEZXNpZ24oaz0yKQ0KZGYgPC0gYXMuZGF0YS5mcmFtZShjb25maWd1cmFjaW9uKQ0KeWZhY3RvcjwtNzIrMy42KmRmJEEtMi41KmRmJEINCnJlc3BvbnNlKGNvbmZpZ3VyYWNpb24pIDwtIHlmYWN0b3INCnRhYmxhQUIgPSBzdGVlcEFzY2VudChjKCJBIiwiQiIpLCByZXNwb25zZSA9ICJ5ZmFjdG9yIiwgc2l6ZSA9IDEsZGF0YSA9IGNvbmZpZ3VyYWNpb24pDQp0YWJsYUJBID0gc3RlZXBBc2NlbnQoYygiQiIsIkEiKSwgcmVzcG9uc2UgPSAieWZhY3RvciIsIHNpemUgPSAxLGRhdGEgPSBjb25maWd1cmFjaW9uKQ0KZGZfdGFibGFfcmVhbEFCIDwtIGFzLmRhdGEuZnJhbWUodGFibGFBQikNCmRmX3RhYmxhX3JlYWxCQSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQkEpDQoNCnlfcHJlZGljaG9BQiA8LSA3MiszLjYqZGZfdGFibGFfcmVhbEFCJEEucmVhbC0yLjUqZGZfdGFibGFfcmVhbEFCJEIucmVhbA0KeV9wcmVkaWNob0JBIDwtIDcyKzMuNipkZl90YWJsYV9yZWFsQkEkQS5yZWFsLTIuNSpkZl90YWJsYV9yZWFsQkEkQi5yZWFsDQoNCnJlc3BvbnNlKHRhYmxhQUIpIDwtIHlfcHJlZGljaG9BQg0KcmVzcG9uc2UodGFibGFCQSkgPC0geV9wcmVkaWNob0JBDQp0YWJsYUJBDQpkZl9CQSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQkEpDQpkZl9BQiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQUIpDQpwbG90KHRhYmxhQkEpKyBsaW5lcyhkZl9CQSREZWx0YSxkZl9CQSR5X3ByZWRpY2hvQkEsIGNvbD0iYmx1ZSIgKStsaW5lcyhkZl9BQiREZWx0YSxkZl9BQiR5X3ByZWRpY2hvQUIsIGNvbD0icmVkIiwgdHlwZT0nbCcpICsNCiAgbGluZXMoZGZfQkEkRGVsdGEsZGZfQkEkeV9wcmVkaWNob0JBLCBjb2w9ImJsdWUiLCB0eXBlPSdoJyApDQpgYGANCkNvbW8gcG9kZW1vcyB2ZXIgZW4gbGFzIGxpbmVhcyBsb3MgIlkiIHByZWRpY2hvcyBkZSBCQSBlc3RhbiBjcmVjaWVuZG8gbXVjaG8gbWFzIHJhcGlkbyBwYXJhIHVuIHNpemU9MSBlbiBhbWJvcyBjYXNvcw0KDQojIEVqZXJjaWNpbyA1LjQNCkJhc2Fkb3MgZW4gZWwgZWplcmNpY2lvIDUuMiANCiMjIFByb2JsZW1hIGEpIA0KbXVlc3RyZSBxdWUgdGFuZG8gc2Ugc2VwYXJhIGRlIGxhIGJhc2UgeSBlbCBkZWx0YSBlcyBkZSA0IHBhcmEgQUIgIGVuIHgxDQoNCmBgYHtyfQ0KY29uZmlndXJhY2lvbiA8LSBmYWNEZXNpZ24oaz0zLCBwID0gMCwgcmVwbGljYXRlcyA9IDEsIGJsb2NrcyA9IDEsIGNlbnRlckN1YmUgPSAxKQ0KZGYgPC0gYXMuZGF0YS5mcmFtZShjb25maWd1cmFjaW9uKQ0KeWZhY3RvcjwtMjUrNCpkZiRBKzMqZGYkQi0yLjUqZGYkQw0KcmVzcG9uc2UoY29uZmlndXJhY2lvbikgPC0geWZhY3Rvcg0KdGFibGFBQiA9IHN0ZWVwQXNjZW50KGMoIkEiLCJCIiwiQyIpLCByZXNwb25zZSA9ICJ5ZmFjdG9yIiwgc2l6ZSA9IDEsZGF0YSA9IGNvbmZpZ3VyYWNpb24pDQp0YWJsYTRkZWx0YSA9IHN0ZWVwQXNjZW50KGMoIkEiLCJCIiwiQyIpLCByZXNwb25zZSA9ICJ5ZmFjdG9yIiwgc2l6ZSA9IDQsZGF0YSA9IGNvbmZpZ3VyYWNpb24pDQpkZl90YWJsYV9yZWFsQUIgPC0gYXMuZGF0YS5mcmFtZSh0YWJsYUFCKQ0KZGZfdGFibGFfcmVhbDRkZWx0YSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhNGRlbHRhKQ0KDQp5X3ByZWRpY2hvQUIgPC0gMjUrNCpkZl90YWJsYV9yZWFsQUIkQS5yZWFsKzMqZGZfdGFibGFfcmVhbEFCJEIucmVhbC0yLjUqZGZfdGFibGFfcmVhbEFCJEMucmVhbA0KeV9wcmVkaWNobzRkZWx0YSA8LSAyNSs0KmRmX3RhYmxhX3JlYWw0ZGVsdGEkQS5yZWFsKzMqZGZfdGFibGFfcmVhbDRkZWx0YSRCLnJlYWwtMi41KmRmX3RhYmxhX3JlYWw0ZGVsdGEkQy5yZWFsDQoNCg0KcmVzcG9uc2UodGFibGFBQikgPC0geV9wcmVkaWNob0FCDQpyZXNwb25zZSh0YWJsYTRkZWx0YSkgPC0geV9wcmVkaWNobzRkZWx0YQ0KdGFibGE0ZGVsdGENCmRmX0FCIDwtIGFzLmRhdGEuZnJhbWUodGFibGFBQikNCmRmXzRkZWx0YSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhNGRlbHRhKQ0KcGxvdCh0YWJsYTRkZWx0YSkrIA0KICBsaW5lcyhkZl80ZGVsdGEkRGVsdGEsZGZfNGRlbHRhJHlfcHJlZGljaG80ZGVsdGEsIGNvbD0iYmx1ZSIgKSsNCiAgbGluZXMoZGZfQUIkRGVsdGEsZGZfQUIkeV9wcmVkaWNob0FCLCBjb2w9InJlZCIsIHR5cGU9J2wnKSANCiAgbGluZXMoZGZfNGRlbHRhJERlbHRhLGRmXzRkZWx0YSR5X3ByZWRpY2hvNGRlbHRhLCBjb2w9ImJsdWUiLCB0eXBlPSdoJyApDQogIA0KYGBgDQpjb21vIHBvZGVtb3MgdmVyIGxhIGxpbmVhIGF6dWwgZXMgZWwgcHJlZGljaG8gcG9yIHVuIGRlbHRhIGRlIDQNCg0KDQojIyBQcm9ibGVtYSBiIHkgYykgDQpyZWNhbGN1bGUgY29uc2lkZXJlbmRvIGFob3JhIGNvbiB4MiBjb25zaWRlcmFuZG8gMWRlbHRhIHkgbGEgYmFzZSBlbiA0ZGVsdGENCg0KDQpgYGB7cn0NCmNvbmZpZ3VyYWNpb24gPC0gZmFjRGVzaWduKGs9MywgcCA9IDAsIHJlcGxpY2F0ZXMgPSAxLCBibG9ja3MgPSAxLCBjZW50ZXJDdWJlID0gMSkNCmRmIDwtIGFzLmRhdGEuZnJhbWUoY29uZmlndXJhY2lvbikNCnlmYWN0b3I8LTI1KzQqZGYkQSszKmRmJEItMi41KmRmJEMNCnJlc3BvbnNlKGNvbmZpZ3VyYWNpb24pIDwtIHlmYWN0b3INCnRhYmxhQUIgPSBzdGVlcEFzY2VudChjKCJCIiwiQSIsIkMiKSwgcmVzcG9uc2UgPSAieWZhY3RvciIsIHNpemUgPSA0LGRhdGEgPSBjb25maWd1cmFjaW9uKQ0KdGFibGE0ZGVsdGEgPSBzdGVlcEFzY2VudChjKCJCIiwiQSIsIkMiKSwgcmVzcG9uc2UgPSAieWZhY3RvciIsIHNpemUgPSAxLGRhdGEgPSBjb25maWd1cmFjaW9uKQ0KZGZfdGFibGFfcmVhbEFCIDwtIGFzLmRhdGEuZnJhbWUodGFibGFBQikNCmRmX3RhYmxhX3JlYWw0ZGVsdGEgPC0gYXMuZGF0YS5mcmFtZSh0YWJsYTRkZWx0YSkNCg0KeV9wcmVkaWNob0FCIDwtIDI1KzQqZGZfdGFibGFfcmVhbEFCJEEucmVhbCszKmRmX3RhYmxhX3JlYWxBQiRCLnJlYWwtMi41KmRmX3RhYmxhX3JlYWxBQiRDLnJlYWwNCnlfcHJlZGljaG80ZGVsdGEgPC0gMjUrNCpkZl90YWJsYV9yZWFsNGRlbHRhJEEucmVhbCszKmRmX3RhYmxhX3JlYWw0ZGVsdGEkQi5yZWFsLTIuNSpkZl90YWJsYV9yZWFsNGRlbHRhJEMucmVhbA0KDQoNCnJlc3BvbnNlKHRhYmxhQUIpIDwtIHlfcHJlZGljaG9BQg0KcmVzcG9uc2UodGFibGE0ZGVsdGEpIDwtIHlfcHJlZGljaG80ZGVsdGENCnRhYmxhNGRlbHRhDQpkZl9BQiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQUIpDQpkZl80ZGVsdGEgPC0gYXMuZGF0YS5mcmFtZSh0YWJsYTRkZWx0YSkNCnBsb3QodGFibGE0ZGVsdGEpKyANCiAgbGluZXMoZGZfNGRlbHRhJERlbHRhLGRmXzRkZWx0YSR5X3ByZWRpY2hvNGRlbHRhLCBjb2w9ImJsdWUiICkrDQogIGxpbmVzKGRmX0FCJERlbHRhLGRmX0FCJHlfcHJlZGljaG9BQiwgY29sPSJyZWQiLCB0eXBlPSdsJykgDQogIGxpbmVzKGRmXzRkZWx0YSREZWx0YSxkZl80ZGVsdGEkeV9wcmVkaWNobzRkZWx0YSwgY29sPSJibHVlIiwgdHlwZT0naCcgKQ0KICANCmBgYA0KQ29tbyBwb2RlbW9zIG9ic2VydmFyIGF1bnF1ZSBsb3MgZG9zIG1ldG9kb3MgcGFydGVuIGRlbCBtaXNtbyBwdW50bywgbGEgYmFzZSBjb24gdW4gZGVsdGEgZGUgNCBjcmVjZSBtdWNobyBtYXMgcmFwaWRvIA0KDQojIFByb2JsZW1hIDUuNQ0KUHJpbWVybyBjb25zdHJ1aXJlbW9zIGVsIGFycmVnbG8gZGUgcmVzcHVlc3Rhcw0KZGlzZfFhbW9zIG51ZXN0cm8gbW9kZWxvIGRlIGZhY3RvciBjb24gaz00LCB5IG51ZXN0cm8gZ3JpZCBkZSBwcm9kdWN0b3MgQUJDRA0KeSBjb25zdHJ1aW1vcyBlbCByZXN1bHRhZG8gYmFzYW5kb25vcyBlbiAyIGEgbGEgNCBlbiBudWVzdHJvIGRpc2XxbyBkZSBmYWN0b3JpYWwgDQo0IGVmZWN0b3MgcHJpbmNpcGFsZXM6IGEgcGFyYSBlbCBmYWN0b3JBLCBiIHBhcmEgZWwgZmFjdG9yIEIsIGMgcGFyYSBlbCBmYWN0b3IgQyB5ID8/IHBhcmEgZWwgZmFjdG9yIEQNCjYgZWZlY3RvcyBwYXJhIGxhcyBpbnRlcmFjY2lvbmVzIGRlIG9yZGVuIDIsIEFCLCBBQywgQUQsIEJDLCBCRCwgQ0QNCjQgZWZlY3RvcyBwYXJhIGxhcyBpbnRlcmFjY2lvbmVzIGRlIG9yZGVuIDMsIEFCQywgQUJELCBCQ0QsIEFDRA0KMSBlZmVjdG8gcGFyYSBsYSBpbnRlcmFjY2nzbiBkZSBvcmRlbiA0LCBBQkNEDQoNCmZvcm11bGEgYSB1dGlsaXphciB5PWErYitjK2QrYWIrYWMrYWQrYmMrYmQrY2QrYWJjK2FiZCthY2QrYmNkK2FiY2QNCmBgYHtyfQ0KbT1leHBhbmQuZ3JpZChBPWZhY3RvcihjKC0xLDEpKSxCPWZhY3RvcihjKC0xLDEpKSwNCiAgICAgICAgICAgICAgQz1mYWN0b3IoYygtMSwxKSksRD1mYWN0b3IoYygtMSwxKSkpDQptDQpsZWN0dXJhczwtdW5saXN0KG0pDQpteDIgPC0gcmJpbmQobSxtKQ0KZmVhdHVyZXMgPC0gbWF0cml4KGxlY3R1cmFzLG5jb2w9NCxieXJvdz1UUlVFKQ0KZmVhdHVyZXMgPC0gcmJpbmQoZmVhdHVyZXMsZmVhdHVyZXMpDQpwcmludCgiZHVwbGljYW1vcyBsb3MgZmVhdHVyZXMgcHVlc3RvIHF1ZSBzb24gZG9zIGxlY3R1cmFzIikNCmZlYXR1cmVzDQpvYnNlcnZhdGlvbiA8LSBjKDMwLjMsMjguNSwyNC41LDI1LjksMjQuOCwyNi45LDI0LjgsMjIuMiwzMS43LDI0LjYsMjcuNiwyNi4zLDI5LjksMjYuOCwyNi40LDI2LjksMjguNiwzMS40LDI1LjYsMjcuMiwyMy40LDIzLjgsMjcuOCwyNC45LDMzLjUsMjYuMiwzMC42LDI3LjgsMjcuNywyNC4yLDI0LjksMjkuMykNCg0KZXhwZXJpbWVudCA8LSB0aWJibGUoQT1teDIkQSwNCiAgICAgICAgICAgICAgICAgICAgIEI9bXgyJEIsDQogICAgICAgICAgICAgICAgICAgICBDPW14MiRDLA0KICAgICAgICAgICAgICAgICAgICAgRD1teDIkRCwNCiAgICAgICAgICAgICAgICAgICAgIFk9b2JzZXJ2YXRpb24pDQoNCg0KcHJpbnQoInZlcmlmaWNhbW9zIGNvbW8gcXVlZGEgZWwgZXhwZXJpbWllbnRvOiIpDQpleHBlcmltZW50DQpkZjI8LWV4cGVyaW1lbnRbY29tcGxldGUuY2FzZXMoZXhwZXJpbWVudCksXQ0KZGYyDQpmaXQ8LSBsbShZfkErQitDK0QrKEEqQikrKEEqQykrKEEqRCkrKEIqQykrKEIqRCkrKEMqRCkrKEEqQipDKSsoQSpCKkQpKyhBKkMqRCkrKEIqQypEKSsoQSpCKkMqRCksZGF0YT1kZjIpDQpzdW1tYXJ5KGZpdCkNCg0KDQpgYGANCg0KQ29tbyBwb2RlbW9zIHZlciBsYXMgdmFyaWFibGVzIGVuIG51ZXN0cm8gbW9kZWxvIGRlYmVuIGNvbnNpZGVyYXIgYSBsYXMgYmV0YXMgbWFzIHNpZ25pZmljYXRpdmFzIA0KDQpZPTI5LjQ1ICsgLTQuNEItNS4zQyszLjE1RC03LjcoQSpEKSs2LjYoQipDKS02LjI1KEIqQypEKQ0KDQpQcm9ibGVtYSBiKQ0KDQpVdGlsaXphcmVtb3MgcXVhbGl0eXRvb2wgZGV0ZXJtaW5hcmVtb3MgZWwgcGF0aCBkZWwgc3RlZXBlc3QgYWNlbnQNCmBgYHtyfQ0KY29uZmlndXJhY2lvbiA8LSBmYWNEZXNpZ24oaz00LCBwID0gMCwgcmVwbGljYXRlcyA9IDEsIGJsb2NrcyA9IDEsIGNlbnRlckN1YmUgPSAxKQ0KZGYgPC0gYXMuZGF0YS5mcmFtZShjb25maWd1cmFjaW9uKQ0KeWZhY3RvcjwtMjkuNDUgLTQuNCpkZiRCLTUuMypkZiRDKzMuMTUqZGYkRC03LjcqKGRmJEEqZGYkRCkrNi42KihkZiRCKmRmJEMpLTYuMjUqKGRmJEIqZGYkQypkZiREKQ0KcmVzcG9uc2UoY29uZmlndXJhY2lvbikgPC0geWZhY3Rvcg0KdGFibGFBQiA9IHN0ZWVwQXNjZW50KGMoIkEiLCJCIiwiQyIsIkQiKSwgcmVzcG9uc2UgPSAieWZhY3RvciIsIHNpemUgPSAxLGRhdGEgPSBjb25maWd1cmFjaW9uKQ0KICAgICAgICAgICAgICAgIDI5LjQ1IC00LjQqZGYkQi01LjMqZGYkQyszLjE1KmRmJEQtNy43KihkZiRBKmRmJEQpKzYuNiooZGYkQipkZiRDKS02LjI1KihkZiRCKmRmJEMqZGYkRCkNCmRmX3RhYmxhX3JlYWxBQiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQUIpICAgICAgICAgICAgICAgIA0KeV9wcmVkaWNob0FCIDwtIDI5LjQ1IC00LjQqZGZfdGFibGFfcmVhbEFCJEIucmVhbC01LjMqZGZfdGFibGFfcmVhbEFCJEMucmVhbCszLjE1KmRmX3RhYmxhX3JlYWxBQiRELnJlYWwtNy43KihkZl90YWJsYV9yZWFsQUIkQS5yZWFsKmRmX3RhYmxhX3JlYWxBQiRELnJlYWwpKzYuNiooZGZfdGFibGFfcmVhbEFCJEIucmVhbCpkZl90YWJsYV9yZWFsQUIkQy5yZWFsKS02LjI1KihkZl90YWJsYV9yZWFsQUIkQi5yZWFsKmRmX3RhYmxhX3JlYWxBQiRDLnJlYWwqZGZfdGFibGFfcmVhbEFCJEQucmVhbCkNCg0KDQoNCnJlc3BvbnNlKHRhYmxhQUIpIDwtIHlfcHJlZGljaG9BQg0KdGFibGFBQg0KDQpkZl9BQiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQUIpDQoNCnBsb3QodGFibGFBQikrIGxpbmVzKGRmX0FCJERlbHRhLGRmX0FCJHlfcHJlZGljaG9BQiwgY29sPSJibHVlIiApDQogIA0KICANCg0KYGBgDQoNCnByb2JsZW1hIGMpDQogcmVzdHJpbmdpZW5kbyB4MSt4Mj0yLjcNCg0KIyBQcm9ibGVtYSA1LjcNCkUoIHkpID0gMTQgKyA1eDEgLSAxMHgyICsgM3gxeDINCg0KcHJvYmxlbWEgYSkNCkdyYWZpcXVlIGVsIHBhdGggYmFzYW5kb3NlIGVuIGxvcyBwYXJhbWV0cm9zIGFjdHVhbGVzIHNpIGxhIGludGVyYWNjaW9uIHgxeDIgZXMgaWdub3JhZGEgDQoNClV0aWxpemFuZG8gcXVhbGl0eXRvb2wgcGFyYSBrMg0KYGBge3J9DQpjb25maWd1cmFjaW9uIDwtIGZhY0Rlc2lnbihrPTIsIHAgPSAwLCByZXBsaWNhdGVzID0gMSwgYmxvY2tzID0gMSwgY2VudGVyQ3ViZSA9IDEpDQpkZiA8LSBhcy5kYXRhLmZyYW1lKGNvbmZpZ3VyYWNpb24pDQp5ZmFjdG9yPC0gMTQrNSpkZiRBLSAxMCpkZiRCICsgMypkZiRBKmRmJEIqMA0KcmVzcG9uc2UoY29uZmlndXJhY2lvbikgPC0geWZhY3Rvcg0KdGFibGFBQiA9IHN0ZWVwQXNjZW50KGMoIkEiLCJCIiksIHJlc3BvbnNlID0gInlmYWN0b3IiLCBzaXplID0gMSxkYXRhID0gY29uZmlndXJhY2lvbikNCg0KDQpkZl90YWJsYV9yZWFsQUIgPC0gYXMuZGF0YS5mcmFtZSh0YWJsYUFCKSAgICAgICAgICAgICAgICANCnlfcHJlZGljaG9BQiA8LSAxNCArKDUqZGZfdGFibGFfcmVhbEFCJEEuY29kZWQpLSgxMCpkZl90YWJsYV9yZWFsQUIkQi5jb2RlZCkrKDMqZGZfdGFibGFfcmVhbEFCJEEuY29kZWQqZGZfdGFibGFfcmVhbEFCJEIuY29kZWQqMCkNCg0KDQoNCnJlc3BvbnNlKHRhYmxhQUIpIDwtIHlfcHJlZGljaG9BQg0KdGFibGFBQg0KDQpkZl9BQiA8LSBhcy5kYXRhLmZyYW1lKHRhYmxhQUIpDQpkZmxpbmVhbDwtZGZfQUINCnBsb3QodGFibGFBQikrIGxpbmVzKGRmX0FCJERlbHRhLGRmX0FCJHlfcHJlZGljaG9BQiwgY29sPSJibHVlIiApDQoNCmBgYA0KDQpQcm9ibGVtYSBCKSANCm11ZXN0cmUgbGEgcmVsYWNpb24gY29uIHgxKngyDQoNCg0KYGBge3J9DQpjb25maWd1cmFjaW9uIDwtIGZhY0Rlc2lnbihrPTIsIHAgPSAwLCByZXBsaWNhdGVzID0gMSwgYmxvY2tzID0gMSwgY2VudGVyQ3ViZSA9IDEpDQpkZiA8LSBhcy5kYXRhLmZyYW1lKGNvbmZpZ3VyYWNpb24pDQp5ZmFjdG9yPC0gMTQrNSpkZiRBLSAxMCpkZiRCICsgMypkZiRBKmRmJEINCnJlc3BvbnNlKGNvbmZpZ3VyYWNpb24pIDwtIHlmYWN0b3INCnRhYmxhQUIgPSBzdGVlcEFzY2VudChjKCJBIiwiQiIpLCByZXNwb25zZSA9ICJ5ZmFjdG9yIiwgc2l6ZSA9IDEsZGF0YSA9IGNvbmZpZ3VyYWNpb24pDQoNCg0KZGZfdGFibGFfcmVhbEFCIDwtIGFzLmRhdGEuZnJhbWUodGFibGFBQikgICAgICAgICAgICAgICAgDQp5X3ByZWRpY2hvQUIgPC0gMTQgKyg1KmRmX3RhYmxhX3JlYWxBQiRBLmNvZGVkKS0oMTAqZGZfdGFibGFfcmVhbEFCJEIuY29kZWQpKygzKmRmX3RhYmxhX3JlYWxBQiRBLmNvZGVkKmRmX3RhYmxhX3JlYWxBQiRCLmNvZGVkKQ0KDQoNCg0KcmVzcG9uc2UodGFibGFBQikgPC0geV9wcmVkaWNob0FCDQp0YWJsYUFCDQoNCmRmX0FCIDwtIGFzLmRhdGEuZnJhbWUodGFibGFBQikNCg0KcGxvdCh0YWJsYUFCKSsgbGluZXMoZGZfQUIkRGVsdGEsZGZfQUIkeV9wcmVkaWNob0FCLCBjb2w9ImJsdWUiICkrIGxpbmVzKGRmbGluZWFsJERlbHRhLGRmbGluZWFsJHlfcHJlZGljaG9BQiwgY29sPSJibHVlIiApDQoNCg0KYGBgDQoNCnByb2JsZW1hIGMpIA0KQXVucXVlIGxvcyBkb3MgcHVudG9zIHBhcnRlbiBkZSBsYSBtaXNtYSBsaW5lYSwgdmVtb3MgY29tbyBsYSByZWxhY2nzbiBubyBsaW5lYWwgZGUgeDF4MiBoYWNlIHF1ZSBlbCB2YWxvciBwcmVkaWNobyBkZSBjYWxjdWxvIHNlIGRlZ3JhZGUgY29uIGVsIGRlbHRhDQoNCg==