1 Como leer este documento

Los cuatro ejercicios comparten una sola pregunta: cuando dos modelos compiten, quien decide? La respuesta que sostengo es que los indices de ajuste son una condicion necesaria pero nunca suficiente, y que un modelo con mejor ajuste puede ser peor modelo. Los ejercicios 1 a 3 construyen la evidencia con datos; el ejercicio 4 la confronta con un caso publicado donde los autores rechazaron su propio modelo mejor ajustado.

Todos los modelos se estiman con lavaan. Los criterios de ajuste que uso a lo largo del documento son los convencionales en la literatura (Hu y Bentler, 1999):

Criterios de ajuste usados en todo el documento
Indice Que_mide Criterio
Chi-cuadrada Distancia absoluta entre la matriz observada y la implicada no significativa (sensible a N)
CFI / TLI Ajuste comparativo contra el modelo nulo >= .95 (aceptable >= .90)
RMSEA Error de aproximacion por grado de libertad (penaliza falta de parsimonia) <= .06 (aceptable <= .08)
SRMR Residual estandarizado promedio <= .08
# indices que reporto en cada modelo
IDX <- c("chisq", "df", "pvalue", "cfi", "tli", "rmsea", "srmr")

# tabla de ajuste de uno o varios modelos, para comparar en el mismo renglon
tabla_ajuste <- function(..., etiquetas = NULL) {
  modelos <- list(...)
  if (is.null(etiquetas)) etiquetas <- paste("Modelo", seq_along(modelos))
  out <- do.call(rbind, lapply(modelos, function(m) {
    fm <- fitMeasures(m, IDX)
    data.frame(chisq = round(fm[["chisq"]], 2), gl = fm[["df"]],
               p = round(fm[["pvalue"]], 3), CFI = round(fm[["cfi"]], 3),
               TLI = round(fm[["tli"]], 3), RMSEA = round(fm[["rmsea"]], 3),
               SRMR = round(fm[["srmr"]], 3))
  }))
  # post.check avisa de soluciones inadmisibles (varianzas negativas, cargas > 1)
  out$admisible <- sapply(modelos, function(m) lavInspect(m, "post.check"))
  rownames(out) <- etiquetas
  out
}

# prueba de diferencia de chi-cuadrada entre dos modelos anidados, como tabla con titulo
# (las salidas sin titulo se desalinean de su rotulo al compilar a PDF)
comparar <- function(modelo_a, modelo_b, etiquetas, caption) {
  gl <- c(fitMeasures(modelo_a, "df"), fitMeasures(modelo_b, "df"))
  a  <- suppressWarnings(lavTestLRT(modelo_a, modelo_b))
  # lavTestLRT devuelve los modelos ordenados por grados de libertad, no en el orden
  # en que se pasan: hay que reordenar las etiquetas igual o quedan cruzadas
  out <- data.frame(Modelo = etiquetas[match(a$Df, gl)],
                    gl = a$Df, AIC = round(a$AIC, 1), BIC = round(a$BIC, 1),
                    chisq = round(a$Chisq, 2),
                    dif_chisq = round(a$"Chisq diff", 3),
                    dif_gl = a$"Df diff",
                    p = round(a$"Pr(>Chisq)", 4))
  kable(out, row.names = FALSE,
        col.names = c("Modelo","gl","AIC","BIC","chisq","dif. chisq","dif. gl","p"),
        caption = caption)
}

# cargas estandarizadas ordenadas de menor a mayor
cargas <- function(fit) {
  s <- subset(standardizedSolution(fit), op == "=~")
  s <- s[order(s$est.std), c("lhs", "rhs", "est.std", "pvalue")]
  names(s) <- c("Factor", "Item", "Carga_estandarizada", "p")
  rownames(s) <- NULL
  s
}

2 Ejercicio 1: Holzinger y Swineford (1939)

2.1 El modelo teorico de tres factores ajusta mal, y el problema tiene nombre: x9

La base clasica de Holzinger y Swineford registra nueve pruebas mentales aplicadas a 301 estudiantes de dos escuelas. La teoria propone tres habilidades latentes: visual (x1–x3), verbal (x4–x6) y velocidad (x7–x9).

mod_hs <- ' visual  =~ x1 + x2 + x3
            textual =~ x4 + x5 + x6
            speed   =~ x7 + x8 + x9 '
fit_hs <- cfa(mod_hs, data = HolzingerSwineford1939)
kable(tabla_ajuste(fit_hs, etiquetas = "3 factores (teorico)"),
      caption = "El modelo teorico se queda corto: CFI por debajo de .95 y RMSEA arriba de .06")
El modelo teorico se queda corto: CFI por debajo de .95 y RMSEA arriba de .06
chisq gl p CFI TLI RMSEA SRMR admisible
3 factores (teorico) 85.31 24 0 0.931 0.896 0.092 0.065 TRUE

El CFI de 0.931 y el RMSEA de 0.092 son aceptables pero no buenos. Antes de tocar nada, conviene ver donde falla:

x2 (.42) y x3 (.58) sostienen mal al factor visual
Factor Item Carga_estandarizada p
visual x2 0.424 0
speed x7 0.570 0
visual x3 0.581 0
speed x9 0.665 0
speed x8 0.723 0
visual x1 0.772 0
textual x6 0.838 0
textual x4 0.852 0
textual x5 0.855 0
mi_hs <- modindices(fit_hs, sort. = TRUE)
kable(head(mi_hs[, c("lhs","op","rhs","mi","epc","sepc.all")], 6), row.names = FALSE,
      digits = 3, caption = "Indices de modificacion: x9 quiere cargar tambien en visual")
Indices de modificacion: x9 quiere cargar tambien en visual
lhs op rhs mi epc sepc.all
visual =~ x9 36.411 0.577 0.515
x7 x8 34.145 0.536 0.859
visual =~ x7 18.631 -0.422 -0.349
x8 x9 14.946 -0.423 -0.805
textual =~ x3 9.151 -0.272 -0.238
x2 x7 8.918 -0.183 -0.192

El indice mas grande no es un error residual cualquiera: es visual =~ x9, con un MI de 36.4. Eso tiene lectura sustantiva. La prueba x9 mide velocidad para contar puntos en figuras: es una tarea de rapidez, si, pero el estimulo es visual. No es raro que comparta varianza con el factor visual.

2.2 Depuracion: un solo parametro, elegido por teoria y no por el indice mas alto

mod_hs2 <- ' visual  =~ x1 + x2 + x3 + x9
             textual =~ x4 + x5 + x6
             speed   =~ x7 + x8 + x9 '
fit_hs2 <- cfa(mod_hs2, data = HolzingerSwineford1939)

# alternativa que el MI tambien sugiere, pero sin lectura sustantiva clara
mod_hs3 <- paste(mod_hs, "\n x7 ~~ x9")
fit_hs3 <- cfa(mod_hs3, data = HolzingerSwineford1939)

kable(tabla_ajuste(fit_hs, fit_hs2, fit_hs3,
      etiquetas = c("3 factores (teorico)", "x9 carga tambien en visual",
                    "covarianza residual x7 ~~ x9")),
      caption = "Solo la carga cruzada de x9 mueve el ajuste a territorio bueno")
Solo la carga cruzada de x9 mueve el ajuste a territorio bueno
chisq gl p CFI TLI RMSEA SRMR admisible
3 factores (teorico) 85.31 24 0 0.931 0.896 0.092 0.065 TRUE
x9 carga tambien en visual 52.38 23 0 0.967 0.948 0.065 0.045 TRUE
covarianza residual x7 x9 79.80 23 0 0.936 0.899 0.091 0.062 TRUE
comparar(fit_hs, fit_hs2,
         c("3 factores (teorico)", "x9 carga tambien en visual"),
         "Liberar un solo parametro mejora el ajuste de forma significativa")
Liberar un solo parametro mejora el ajuste de forma significativa
Modelo gl AIC BIC chisq dif. chisq dif. gl p
x9 carga tambien en visual 23 7487 7568 52.38 NA NA NA
3 factores (teorico) 24 7518 7595 85.31 32.92 1 0

La diferencia de chi-cuadrada es significativa con un solo grado de libertad: liberar visual =~ x9 mejora el ajuste de forma real, no marginal. La covarianza residual x7 ~~ x9, en cambio, casi no mueve nada (CFI 0.936), lo cual confirma que el problema no es ruido compartido entre dos pruebas de velocidad sino que x9 mide dos cosas a la vez.

2.3 Honestidad sobre la depuracion: validarla en una muestra que no la sugirio

Aqui esta el riesgo del que casi nunca se habla. Un indice de modificacion se calcula sobre los mismos datos que se van a usar para juzgar el modelo mejorado. Seguirlo es, en el limite, ajustarle el modelo al ruido de esta muestra. La unica defensa real es verificar que el hallazgo se repite en datos que no participaron en la decision.

La base trae dos escuelas. Uso una para descubrir y la otra para confirmar:

val <- do.call(rbind, lapply(levels(HolzingerSwineford1939$school), function(esc) {
  sub <- HolzingerSwineford1939[HolzingerSwineford1939$school == esc, ]
  a <- cfa(mod_hs,  data = sub)
  b <- cfa(mod_hs2, data = sub)
  data.frame(Escuela = esc, n = nrow(sub),
             CFI_base = round(fitMeasures(a, "cfi"), 3),
             CFI_depurado = round(fitMeasures(b, "cfi"), 3),
             RMSEA_base = round(fitMeasures(a, "rmsea"), 3),
             RMSEA_depurado = round(fitMeasures(b, "rmsea"), 3),
             carga_x9_visual = round(subset(standardizedSolution(b),
                                     lhs == "visual" & rhs == "x9")$est.std, 3))
}))
kable(val, row.names = FALSE, caption = "La carga cruzada de x9 aparece en las dos escuelas, pero no con la misma fuerza")
La carga cruzada de x9 aparece en las dos escuelas, pero no con la misma fuerza
Escuela n CFI_base CFI_depurado RMSEA_base RMSEA_depurado carga_x9_visual
Grant-White 145 0.941 0.989 0.089 0.040 0.447
Pasteur 156 0.903 0.927 0.104 0.092 0.310

El resultado se repite en ambas escuelas, asi que no es un artefacto: x9 carga en visual en las dos. Pero la magnitud cae de 0.447 en Grant-White a 0.31 en Pasteur, y en Pasteur el modelo depurado sigue sin alcanzar el criterio (CFI 0.927, RMSEA 0.092). Es decir: la correccion es real, pero el modelo depurado que reporto arriba se ve mejor de lo que es porque se estimo en la muestra completa, incluyendo la escuela donde el efecto es fuerte.

2.4 Conclusiones del ejercicio 1

  1. El modelo teorico de tres factores es defendible pero incompleto: ajusta de forma aceptable (CFI 0.931) y no buena.
  2. La causa es una variable que mide dos constructos. x9 pertenece a velocidad por su formato y a visual por su contenido. Es un problema de diseno del instrumento, no de estimacion.
  3. Depurar guiado por indices de modificacion funciona, pero el ajuste que resulta esta inflado por haber usado los mismos datos para descubrir y para evaluar. La validacion entre escuelas lo demuestra.
  4. Regla que me llevo: solo libero un parametro si puedo explicarlo antes de verlo en la tabla de MI. visual =~ x9 pasa esa prueba; x7 ~~ x9 no, y ademas no servia.

3 Ejercicio 2: democracia politica e industrializacion (Bollen)

3.1 El modelo obvio ajusta mal, y la razon es que ignora que son las mismas preguntas dos veces

La base de Bollen sigue a 75 paises en desarrollo. ind60 es industrializacion en 1960 (x1–x3); dem60 y dem65 son democracia politica en 1960 y 1965, medidas con los mismos cuatro indicadores (y1–y4 y y5–y8 respectivamente). La hipotesis es que la industrializacion impulsa la democracia, en parte de forma directa y en parte a traves de la democracia previa.

mod_pd <- '
  ind60 =~ x1 + x2 + x3
  dem60 =~ y1 + y2 + y3 + y4
  dem65 =~ y5 + y6 + y7 + y8
  dem60 ~ ind60
  dem65 ~ ind60 + dem60 '
fit_pd <- cfa(mod_pd, data = PoliticalDemocracy)
kable(tabla_ajuste(fit_pd, etiquetas = "sin errores correlacionados"),
      caption = "RMSEA de .101: el modelo deja algo importante fuera")
RMSEA de .101: el modelo deja algo importante fuera
chisq gl p CFI TLI RMSEA SRMR admisible
sin errores correlacionados 72.46 41 0.002 0.953 0.938 0.101 0.055 TRUE
Todos los indices altos son covarianzas entre errores de y
lhs op rhs mi epc
y2 y6 9.279 2.129
y6 y8 8.668 1.513
y1 y5 8.183 0.884
y3 y6 6.574 -1.590
y1 y3 5.204 1.024
y2 y4 4.911 1.432

Los seis indices mas grandes son covarianzas entre residuales de los indicadores y, y ninguno involucra a las x. Eso no es casualidad. El indicador y1 (libertad de prensa en 1960) y el y5 (libertad de prensa en 1965) son la misma pregunta aplicada cinco anios despues: comparten no solo el constructo democracia, sino la fuente, el sesgo del codificador y la idiosincrasia del pais. Esa varianza compartida es metodo, no constructo, y si no se modela se acumula en el residual del sistema.

3.2 El modelo correcto: dejar que los errores del mismo indicador se correlacionen en el tiempo

mod_pd2 <- '
  ind60 =~ x1 + x2 + x3
  dem60 =~ y1 + y2 + y3 + y4
  dem65 =~ y5 + y6 + y7 + y8
  dem60 ~ a*ind60
  dem65 ~ c*ind60 + b*dem60
  # errores autocorrelacionados: mismo indicador medido en 1960 y en 1965
  y1 ~~ y5
  y2 ~~ y4 + y6
  y3 ~~ y7
  y4 ~~ y8
  y6 ~~ y8
  # descomposicion del efecto de la industrializacion sobre la democracia de 1965
  indirecto := a*b
  total     := c + a*b '
fit_pd2 <- sem(mod_pd2, data = PoliticalDemocracy)
kable(tabla_ajuste(fit_pd, fit_pd2,
      etiquetas = c("sin errores correlacionados", "con errores correlacionados")),
      caption = "El ajuste pasa de dudoso a muy bueno con seis parametros que la teoria de medicion exige")
El ajuste pasa de dudoso a muy bueno con seis parametros que la teoria de medicion exige
chisq gl p CFI TLI RMSEA SRMR admisible
sin errores correlacionados 72.46 41 0.002 0.953 0.938 0.101 0.055 TRUE
con errores correlacionados 38.13 35 0.329 0.995 0.993 0.035 0.044 TRUE
comparar(fit_pd, fit_pd2,
         c("sin errores correlacionados", "con errores correlacionados"),
         "Los seis errores correlacionados no son opcionales: su omision es rechazada")
Los seis errores correlacionados no son opcionales: su omision es rechazada
Modelo gl AIC BIC chisq dif. chisq dif. gl p
con errores correlacionados 35 3158 3229 38.13 NA NA NA
sin errores correlacionados 41 3180 3238 72.46 34.34 6 0

3.3 Efectos directo, indirecto y total

ef <- parameterEstimates(fit_pd2, standardized = TRUE)
ef <- subset(ef, op %in% c("~", ":="))[, c("lhs","rhs","label","est","se","pvalue","std.all")]
names(ef) <- c("Destino","Origen","Etiqueta","Estimado","EE","p","Estandarizado")
kable(ef, row.names = FALSE, digits = 3,
      caption = "El grueso del efecto de la industrializacion sobre la democracia de 1965 es indirecto")
El grueso del efecto de la industrializacion sobre la democracia de 1965 es indirecto
Destino Origen Etiqueta Estimado EE p Estandarizado
dem60 ind60 a 1.483 0.399 0.00 0.447
dem65 ind60 c 0.572 0.221 0.01 0.182
dem65 dem60 b 0.837 0.098 0.00 0.885
indirecto a*b indirecto 1.242 0.355 0.00 0.395
total c+a*b total 1.814 0.374 0.00 0.578

La lectura sustantiva: de un efecto total estandarizado de 0.578, la parte indirecta (0.395) es 68% del total. La industrializacion de 1960 no produce democracia en 1965 por si sola: la produce sobre todo porque ya habia producido democracia en 1960, y la democracia es altamente persistente (b estandarizado = 0.885, casi un techo).

3.4 Conclusiones del ejercicio 2

  1. El mal ajuste inicial no era del modelo estructural, era del modelo de medicion. Las flechas entre latentes estaban bien; lo que faltaba era reconocer que el mismo indicador medido dos veces arrastra su propio error.
  2. Los seis parametros que agregue no se justifican por su MI sino por el diseno del estudio: son datos longitudinales con indicadores repetidos. Ese es el caso donde liberar covarianzas residuales es obligatorio, no oportunista.
  3. La descomposicion directo / indirecto cambia la conclusion de politica publica: industrializar hoy tiene efecto sobre la democracia futura principalmente a traves de la democracia presente, es decir, hay dependencia de la trayectoria.

4 Ejercicio 3: bienestar de los colaboradores

d <- read.csv("datos/datos_sem.csv")
c(observaciones = nrow(d), variables = ncol(d), valores_faltantes = sum(is.na(d)))
##     observaciones         variables valores_faltantes 
##               223                51                 0

La base tiene 223 colaboradores, sin valores faltantes. Las escalas de recuperacion y energia van de 1 a 7 y la de engagement de 0 a 7.

Nota de verificacion. La descripcion de instrumentos nombra los items de energia recuperada como REG01–REG10 y marca REG01, REG09 y REG10 como eliminados; la base los trae como EN01–EN08 sin EN03. La correspondencia exacta entre las dos numeraciones no esta documentada, asi que trabajo con los siete items tal como vienen y no asumo que EN0k sea REG0k. Igual conviene confirmarlo con el profesor. La misma hoja indica que la escala de engagement es “Nunca = 0, Casi nunca = 2, …” (sin el 1), pero la base si contiene unos; lo trato como escala continua de 0 a 7.

4.1 Parte 1: analisis factorial confirmatorio de segundo orden de las experiencias de recuperacion

4.1.1 El modelo de primer orden con los 31 items no pasa

Las experiencias de recuperacion se miden con cuatro dominios: desapego psicologico, relajacion, maestria y control sobre el tiempo libre.

items_rec <- list(
  DESAPEGO   = grep("^RPD", names(d), value = TRUE),
  RELAJACION = grep("^RRE", names(d), value = TRUE),
  MAESTRIA   = grep("^RMA", names(d), value = TRUE),
  CONTROL    = grep("^RCO", names(d), value = TRUE))
sapply(items_rec, length)
##   DESAPEGO RELAJACION   MAESTRIA    CONTROL 
##          9          7          9          6
# arma la sintaxis de lavaan a partir de la lista de items
sintaxis <- function(lista) {
  paste(mapply(function(nombre, its) paste0(nombre, " =~ ", paste(its, collapse = " + ")),
               names(lista), lista), collapse = "\n")
}
fit_r1 <- cfa(sintaxis(items_rec), data = d, estimator = "MLR")
kable(tabla_ajuste(fit_r1, etiquetas = "4 factores, 31 items"),
      caption = "Ningun criterio se cumple: hay que depurar")
Ningun criterio se cumple: hay que depurar
chisq gl p CFI TLI RMSEA SRMR admisible
4 factores, 31 items 1215 428 0 0.888 0.879 0.091 0.071 TRUE
El diagnostico: items casi identicos entre si y un item que carga en el factor equivocado
lhs op rhs mi epc sepc.all
RPD06 RPD08 109.27 1.232 0.758
RPD09 RPD10 96.96 0.840 0.813
RMA02 RMA03 47.44 0.812 0.504
CONTROL =~ RMA06 44.90 0.437 0.455
RPD02 RPD07 41.02 0.544 0.500
RRE02 RRE03 33.78 0.298 0.468
RELAJACION =~ RMA06 32.24 0.479 0.389
RRE04 RRE05 30.91 0.216 0.511

El diagnostico es claro y tiene sentido leyendo los reactivos:

  • RPD06 ~~ RPD08 (MI = 109): “A proposito no hice, ni revise nada de mi trabajo” y “Con toda intencion no hice nada sobre mi trabajo” son la misma frase.
  • RPD09 ~~ RPD10: “Logre desligarme de mis responsabilidades laborales” y “Me deslinde de mis actividades laborales”, igual.
  • CONTROL =~ RMA06: “Utilice mi tiempo en actividades diferentes” habla de como dispongo de mi tiempo, no de retarme a aprender. Esta en el factor equivocado.

Esto no es ruido estadistico: es redundancia de redaccion en el instrumento. Dos items que dicen lo mismo comparten varianza que ningun factor comun puede explicar, y el modelo lo registra como desajuste.

4.1.2 Una regla de depuracion explicita, con piso de tres items por factor

Depurar a ojo es donde se cuela el sesgo. Escribo la regla como funcion para que sea auditable y para que el orden de eliminacion no dependa de mi criterio del momento:

# Regla, en este orden de prioridad:
#   1. carga estandarizada < .70            -> el item no mide el factor
#   2. carga cruzada con MI > 20            -> el item mide otro factor
#   3. residuales correlacionados con MI>20 -> redundancia: cae el de menor carga
# Restriccion dura: ningun factor puede quedar con menos de 3 items, porque
# un factor de 2 indicadores no se identifica por si solo y el constructo se vacia.
factor_de <- function(lista, item) names(lista)[sapply(lista, function(v) item %in% v)][1]
protegido <- function(lista, item, min_items) length(lista[[factor_de(lista, item)]]) <= min_items

depurar <- function(lista, datos, max_iter = 15, min_items = 3,
                    corte = c(cfi = .95, rmsea = .06, srmr = .08)) {
  traza <- NULL
  for (k in 0:max_iter) {
    fit <- cfa(sintaxis(lista), data = datos, estimator = "MLR")
    fm  <- fitMeasures(fit, IDX)
    fila <- data.frame(paso = k, items = sum(lengths(lista)),
                       chisq = round(fm[["chisq"]], 1), gl = fm[["df"]],
                       CFI = round(fm[["cfi"]], 3), TLI = round(fm[["tli"]], 3),
                       RMSEA = round(fm[["rmsea"]], 3), SRMR = round(fm[["srmr"]], 3),
                       eliminado = NA_character_, motivo = NA_character_)
    if (fm[["cfi"]] >= corte["cfi"] && fm[["rmsea"]] <= corte["rmsea"] &&
        fm[["srmr"]] <= corte["srmr"]) { traza <- rbind(traza, fila); break }

    ld <- subset(standardizedSolution(fit), op == "=~")
    mi <- modindices(fit)
    cand <- NA_character_; motivo <- NA_character_

    baja <- ld[order(ld$est.std), ]
    baja <- baja[baja$est.std < .70 & !sapply(baja$rhs, protegido, lista = lista,
                                              min_items = min_items), ]
    if (nrow(baja) > 0) {
      cand <- baja$rhs[1]; motivo <- sprintf("carga %.2f < .70", baja$est.std[1])
    }
    if (is.na(cand)) {
      cc <- subset(mi, op == "=~" & mi > 20); cc <- cc[order(-cc$mi), ]
      cc <- cc[!sapply(cc$rhs, protegido, lista = lista, min_items = min_items), ]
      if (nrow(cc) > 0) {
        cand <- cc$rhs[1]; motivo <- sprintf("carga cruzada en %s (MI=%.0f)", cc$lhs[1], cc$mi[1])
      }
    }
    if (is.na(cand)) {
      rr <- subset(mi, op == "~~" & lhs != rhs & mi > 20); rr <- rr[order(-rr$mi), ]
      for (i in seq_len(nrow(rr))) {
        par <- c(rr$lhs[i], rr$rhs[i])
        par <- par[order(ld$est.std[match(par, ld$rhs)])]   # primero el de menor carga
        libre <- par[!sapply(par, protegido, lista = lista, min_items = min_items)]
        if (length(libre) > 0) {
          cand <- libre[1]
          motivo <- sprintf("redundante con %s (MI=%.0f)", setdiff(par, cand), rr$mi[i])
          break
        }
      }
    }
    if (is.na(cand)) {
      fila$motivo <- "sin candidatos elegibles: se detiene"
      traza <- rbind(traza, fila); break
    }
    fila$eliminado <- cand; fila$motivo <- motivo
    traza <- rbind(traza, fila)
    lista[[factor_de(lista, cand)]] <- setdiff(lista[[factor_de(lista, cand)]], cand)
  }
  list(items = lista, traza = traza, fit = fit)
}
dep_rec <- depurar(items_rec, d)
kable(dep_rec$traza, row.names = FALSE,
      caption = "Traza completa de la depuracion: que se elimino, en que paso y por que")
Traza completa de la depuracion: que se elimino, en que paso y por que
paso items chisq gl CFI TLI RMSEA SRMR eliminado motivo
0 31 1215.4 428 0.888 0.879 0.091 0.071 RMA06 carga 0.58 < .70
1 30 1117.6 399 0.896 0.887 0.090 0.057 RRE10 carga 0.70 < .70
2 29 1074.0 371 0.896 0.886 0.092 0.057 RPD06 redundante con RPD08 (MI=109)
3 28 910.7 344 0.912 0.903 0.086 0.056 RPD09 redundante con RPD10 (MI=102)
4 27 781.3 318 0.924 0.916 0.081 0.057 RMA02 redundante con RMA03 (MI=46)
5 26 695.5 293 0.931 0.924 0.078 0.056 RRE02 redundante con RRE03 (MI=34)
6 25 645.6 269 0.932 0.925 0.079 0.055 RRE04 carga cruzada en MAESTRIA (MI=23)
7 24 552.3 246 0.941 0.934 0.075 0.050 RRE03 redundante con RRE05 (MI=25)
8 23 474.5 224 0.949 0.943 0.071 0.050 RPD07 redundante con RPD02 (MI=23)
9 22 426.0 203 0.952 0.945 0.070 0.049 RMA03 redundante con RMA05 (MI=20)
10 21 361.6 183 0.959 0.953 0.066 0.047 NA sin candidatos elegibles: se detiene
Instrumento depurado
Factor Items_finales Cuales
DESAPEGO 6 RPD01, RPD02, RPD03, RPD05, RPD08, RPD10
RELAJACION 3 RRE05, RRE06, RRE07
MAESTRIA 6 RMA04, RMA05, RMA07, RMA08, RMA09, RMA10
CONTROL 6 RCO02, RCO03, RCO04, RCO05, RCO06, RCO07

De 31 items quedan 21. Se eliminaron: RPD06, RPD07, RPD09, RRE02, RRE03, RRE04, RRE10, RMA02, RMA03, RMA06.

4.1.3 La depuracion redescubre lo que los autores del instrumento ya sabian

Este es el control de calidad que le da credibilidad al procedimiento. La hoja de instrumentos marca como (eliminated) varios items que sin embargo siguen en la base: RPD01, RPD06, RMA02 y RMA06. Si mi regla es buena, deberia volver a encontrarlos sin haberlos visto:

Coincidencia entre la depuracion ciega y las eliminaciones documentadas
Item Marcado_por_los_autores Mi_regla
RPD01 eliminado lo conserva
RPD06 eliminado tambien lo elimina
RMA02 eliminado tambien lo elimina
RMA06 eliminado tambien lo elimina

Tres de cuatro coinciden. El unico que conservo es RPD01 (“Me olvide del trabajo”), que en esta muestra carga 0.811 y no viola ningun criterio. Que una regla mecanica reproduzca decisiones que se tomaron por juicio de expertos es la mejor evidencia de que no estoy solo persiguiendo indices.

4.1.4 El modelo de segundo orden: los cuatro dominios son facetas de un mismo constructo

Hasta aqui tengo cuatro factores correlacionados. La pregunta del ejercicio es si existe un factor superior, experiencias de recuperacion, que explique por que esos cuatro correlacionan. Es una hipotesis mas fuerte y por lo tanto mas facil de refutar: el modelo de segundo orden reproduce las seis correlaciones entre dominios con solo cuatro cargas, asi que gasta dos grados de libertad menos.

mod_seg <- paste(sintaxis(dep_rec$items),
                 "\n RECUPERACION =~ DESAPEGO + RELAJACION + MAESTRIA + CONTROL")
fit_seg <- cfa(mod_seg, data = d, estimator = "MLR")
kable(tabla_ajuste(dep_rec$fit, fit_seg,
      etiquetas = c("1er orden: 4 factores correlacionados", "2o orden: RECUPERACION")),
      caption = "El factor de segundo orden no cuesta ajuste")
El factor de segundo orden no cuesta ajuste
chisq gl p CFI TLI RMSEA SRMR admisible
1er orden: 4 factores correlacionados 361.6 183 0 0.959 0.953 0.066 0.047 TRUE
2o orden: RECUPERACION 368.0 185 0 0.958 0.953 0.067 0.055 TRUE
comparar(dep_rec$fit, fit_seg,
         c("1er orden: 4 factores correlacionados", "2o orden: RECUPERACION"),
         "La estructura jerarquica no empeora el modelo de forma detectable")
La estructura jerarquica no empeora el modelo de forma detectable
Modelo gl AIC BIC chisq dif. chisq dif. gl p
1er orden: 4 factores correlacionados 183 14529 14692 361.6 NA NA NA
2o orden: RECUPERACION 185 14531 14688 368.0 5.712 2 0.0575
Cargas de segundo orden: los cuatro dominios pertenecen al mismo constructo
Dominio Carga estandarizada EE p
DESAPEGO 0.664 0.045 0
RELAJACION 0.915 0.039 0
MAESTRIA 0.632 0.059 0
CONTROL 0.836 0.043 0

La diferencia de chi-cuadrada con 2 grados de libertad no es significativa (p = 0.057): imponer la estructura jerarquica no empeora el modelo de forma detectable. Las cuatro cargas son significativas, pero desiguales: relajacion (0.915) y control (0.836) son casi sinonimos del constructo general, mientras desapego (0.664) y maestria (0.632) conservan bastante identidad propia. Traducido: quien se recupera bien casi siempre se relaja y controla su tiempo, pero desconectarse mentalmente y buscar retos son cosas que algunas personas hacen y otras no, con relativa independencia de su nivel general de recuperacion.

4.2 Parte 2: analisis factorial confirmatorio del constructo de energia recuperada

items_en <- grep("^EN0", names(d), value = TRUE)
fit_en <- cfa(paste0("ENERGIA =~ ", paste(items_en, collapse = " + ")),
              data = d, estimator = "MLR")
kable(tabla_ajuste(fit_en, etiquetas = "ENERGIA unidimensional, 7 items"),
      caption = "CFI, TLI y SRMR excelentes; RMSEA fuera de criterio")
CFI, TLI y SRMR excelentes; RMSEA fuera de criterio
chisq gl p CFI TLI RMSEA SRMR admisible
ENERGIA unidimensional, 7 items 47.22 14 0 0.986 0.978 0.103 0.012 TRUE
kable(cargas(fit_en), row.names = FALSE, digits = 3,
      caption = "Las siete cargas por arriba de .89")
Las siete cargas por arriba de .89
Factor Item Carga_estandarizada p
ENERGIA EN01 0.893 0
ENERGIA EN04 0.924 0
ENERGIA EN07 0.928 0
ENERGIA EN02 0.933 0
ENERGIA EN05 0.939 0
ENERGIA EN06 0.940 0
ENERGIA EN08 0.946 0

Los siete items se agrupan en una sola dimension, y de forma contundente: la carga mas baja es 0.893 y el SRMR es 0.012, practicamente cero. La respuesta a la pregunta del ejercicio es si.

El RMSEA de 0.103 parece contradecirlo. No lo hace, y vale la pena entender por que en lugar de “arreglarlo”:

dep_en <- depurar(list(ENERGIA = items_en), d)
kable(dep_en$traza, row.names = FALSE,
      caption = "La regla de depuracion no encuentra un solo item que eliminar")
La regla de depuracion no encuentra un solo item que eliminar
paso items chisq gl CFI TLI RMSEA SRMR eliminado motivo
0 7 47.2 14 0.986 0.978 0.103 0.012 NA sin candidatos elegibles: se detiene

Ningun item tiene carga baja, ninguno carga en otro factor, y el residual correlacionado mas grande tiene MI de 12, por debajo del umbral. No hay nada que depurar. El RMSEA alto es consecuencia de su formula: penaliza por grado de libertad, y con solo 14 grados de libertad y cargas tan altas, cualquier discrepancia minima se amplifica. Es el problema conocido de RMSEA en modelos pequenios (Kenny, Kaniskan y McCoach, 2015). Forzar la mejora eliminando items buenos seria maquillar el indice a costa del constructo.

Lo que si me preocupa es lo contrario: cargas de .89 a .95 entre siete reactivos sugieren que el instrumento pregunta lo mismo siete veces (“me siento renovado”, “me siento como nuevo”, “recupere mi energia”). Mide bien, pero es ineficiente: tres items probablemente darian la misma informacion.

4.3 Parte 3: analisis de senderos con la energia recuperada como mediadora

4.3.1 Construccion de los compuestos

for (nm in names(dep_rec$items)) d[[nm]] <- rowMeans(d[, dep_rec$items[[nm]]])
d$RECUP <- rowMeans(d[, names(dep_rec$items)])   # promedio de los 4 dominios
d$ENER  <- rowMeans(d[, items_en])
items_eng <- c("EVI01","EVI02","EVI03","EDE01","EDE02","EDE03","EAB01","EAB02","EAB03")
d$ENGA  <- rowMeans(d[, items_eng])
kable(round(cor(d[, c("DESAPEGO","RELAJACION","MAESTRIA","CONTROL","RECUP","ENER","ENGA")]), 2),
      caption = "Matriz de correlaciones de los compuestos")
Matriz de correlaciones de los compuestos
DESAPEGO RELAJACION MAESTRIA CONTROL RECUP ENER ENGA
DESAPEGO 1.00 0.58 0.31 0.56 0.77 0.58 0.40
RELAJACION 0.58 1.00 0.56 0.70 0.88 0.65 0.43
MAESTRIA 0.31 0.56 1.00 0.51 0.74 0.55 0.39
CONTROL 0.56 0.70 0.51 1.00 0.85 0.71 0.48
RECUP 0.77 0.88 0.74 0.85 1.00 0.77 0.53
ENER 0.58 0.65 0.55 0.71 0.77 1.00 0.60
ENGA 0.40 0.43 0.39 0.48 0.53 0.60 1.00

Cada dominio pesa igual en RECUP (promedio de promedios, no promedio de items), para que desapego con seis items no domine a relajacion con tres.

4.3.2 Por que el modelo de mediacion simple no se puede evaluar por ajuste

mod_sat <- ' ENER ~ a*RECUP
             ENGA ~ cp*RECUP + b*ENER
             indirecto := a*b
             total     := cp + a*b '
fit_sat <- sem(mod_sat, data = d, se = "bootstrap", bootstrap = 1000)
kable(tabla_ajuste(fit_sat, etiquetas = "mediacion parcial (3 variables)"),
      caption = "Ajuste perfecto y vacio: el modelo esta saturado")
Ajuste perfecto y vacio: el modelo esta saturado
chisq gl p CFI TLI RMSEA SRMR admisible
mediacion parcial (3 variables) 0 0 NA 1 1 0 0 TRUE

El ejercicio pide revisar los indices de ajuste, y aqui la respuesta correcta es que no dicen nada. Con tres variables observadas hay 6 momentos y el modelo estima 6 parametros: cero grados de libertad. CFI = 1 y RMSEA = 0 son aritmetica, no evidencia. Un modelo saturado reproduce cualquier matriz de covarianzas, incluida una generada al azar.

Para que el ajuste signifique algo hay que imponer una restriccion falsable. Dos caminos, y tomo los dos.

4.3.3 Camino 1: la mediacion completa como hipotesis contrastable

mod_full <- ' ENER ~ a*RECUP
              ENGA ~ b*ENER
              indirecto := a*b '
fit_full <- sem(mod_full, data = d)
kable(tabla_ajuste(fit_full, fit_sat,
      etiquetas = c("mediacion completa (gl=1)", "mediacion parcial (gl=0)")),
      caption = "Al fijar el camino directo en cero, el modelo por fin se puede refutar")
Al fijar el camino directo en cero, el modelo por fin se puede refutar
chisq gl p CFI TLI RMSEA SRMR admisible
mediacion completa (gl=1) 3.61 1 0.057 0.991 0.974 0.108 0.026 TRUE
mediacion parcial (gl=0) 0.00 0 NA 1.000 1.000 0.000 0.000 TRUE
comparar(fit_full, fit_sat,
         c("mediacion completa", "mediacion parcial"),
         "Prueba de la restriccion de mediacion completa (mediacion simple)")
Prueba de la restriccion de mediacion completa (mediacion simple)
Modelo gl AIC BIC chisq dif. chisq dif. gl p
mediacion parcial 0 1388 1405 0.00 NA NA NA
mediacion completa 1 1390 1403 3.61 3.613 1 0.0573

4.3.4 Camino 2: abrir la recuperacion en sus cuatro dominios

mod_dom <- ' ENER ~ a1*DESAPEGO + a2*RELAJACION + a3*MAESTRIA + a4*CONTROL
             ENGA ~ b*ENER
             i_desapego   := a1*b
             i_relajacion := a2*b
             i_maestria   := a3*b
             i_control    := a4*b '
fit_dom <- sem(mod_dom, data = d, se = "bootstrap", bootstrap = 1000)

mod_dom_p <- ' ENER ~ a1*DESAPEGO + a2*RELAJACION + a3*MAESTRIA + a4*CONTROL
               ENGA ~ b*ENER + c1*DESAPEGO + c2*RELAJACION + c3*MAESTRIA + c4*CONTROL '
fit_dom_p <- sem(mod_dom_p, data = d)

kable(tabla_ajuste(fit_dom, fit_dom_p,
      etiquetas = c("mediacion completa (gl=4)", "mediacion parcial (saturado)")),
      caption = "El modelo de mediacion completa ajusta casi perfecto con 4 grados de libertad")
El modelo de mediacion completa ajusta casi perfecto con 4 grados de libertad
chisq gl p CFI TLI RMSEA SRMR admisible
mediacion completa (gl=4) 4.33 4 0.363 0.999 0.998 0.019 0.023 TRUE
mediacion parcial (saturado) 0.00 0 NA 1.000 1.000 0.000 0.000 TRUE
comparar(fit_dom, fit_dom_p,
         c("mediacion completa", "mediacion parcial"),
         "Quitar los cuatro caminos directos no empeora el modelo")
Quitar los cuatro caminos directos no empeora el modelo
Modelo gl AIC BIC chisq dif. chisq dif. gl p
mediacion parcial 0 1392 1430 0.00 NA NA NA
mediacion completa 4 1389 1412 4.33 4.33 4 0.3632

La chi-cuadrada de 4.33 con 4 grados de libertad no es significativa (p = 0.363). Eliminar los cuatro caminos directos no empeora el modelo. Y el modelo saturado explica por que:

Ninguno de los cuatro caminos directos hacia engagement es significativo
Destino Origen Estimado EE p Estandarizado
ENGA ENER 0.410 0.072 0.000 0.477
ENGA DESAPEGO 0.055 0.060 0.365 0.063
ENGA RELAJACION -0.016 0.081 0.842 -0.017
ENGA MAESTRIA 0.077 0.062 0.215 0.084
ENGA CONTROL 0.080 0.086 0.354 0.079

Ninguno de los cuatro dominios llega al engagement por su cuenta. Toda la relacion pasa por la energia recuperada.

4.3.5 Efectos indirectos, con intervalos bootstrap

ef3 <- parameterEstimates(fit_dom, boot.ci.type = "perc", standardized = TRUE)
ef3 <- subset(ef3, op %in% c("~", ":="))[, c("lhs","rhs","label","est","se",
                                             "pvalue","ci.lower","ci.upper","std.all")]
kable(ef3, row.names = FALSE, digits = 3,
      col.names = c("Destino","Origen","Etiqueta","Est","EE","p","IC 2.5%","IC 97.5%","Estand."),
      caption = "Efectos del modelo de mediacion completa (1000 remuestreos bootstrap)")
Efectos del modelo de mediacion completa (1000 remuestreos bootstrap)
Destino Origen Etiqueta Est EE p IC 2.5% IC 97.5% Estand.
ENER DESAPEGO a1 0.216 0.060 0.000 0.108 0.347 0.215
ENER RELAJACION a2 0.164 0.080 0.040 -0.006 0.310 0.148
ENER MAESTRIA a3 0.216 0.067 0.001 0.102 0.357 0.202
ENER CONTROL a4 0.452 0.086 0.000 0.280 0.605 0.383
ENGA ENER b 0.519 0.065 0.000 0.397 0.651 0.603
i_desapego a1*b i_desapego 0.112 0.033 0.001 0.056 0.190 0.130
i_relajacion a2*b i_relajacion 0.085 0.043 0.046 -0.003 0.167 0.089
i_maestria a3*b i_maestria 0.112 0.038 0.003 0.049 0.192 0.122
i_control a4*b i_control 0.235 0.057 0.000 0.128 0.349 0.231
r2 <- inspect(fit_dom, "r2")
kable(data.frame(Variable = names(r2), R2 = round(as.numeric(r2), 3)),
      row.names = FALSE, caption = "Varianza explicada")
Varianza explicada
Variable R2
ENER 0.602
ENGA 0.364

El producto de coeficientes no se distribuye normal, por eso el intervalo bootstrap y no el error estandar de Wald. Y la diferencia importa: relajacion tiene p = 0.046 por Wald pero su intervalo bootstrap (-0.003 a 0.167) incluye el cero. Con el criterio mas exigente, que es el correcto aqui, su efecto no esta demostrado.

Orden de importancia por efecto indirecto estandarizado:

Control sobre el tiempo libre es, por mucho, el dominio que mas rinde
Dominio Efecto indirecto estand. IC 2.5% IC 97.5% Conclusion
i_control 0.231 0.128 0.349 efecto sostenido
i_desapego 0.130 0.056 0.190 efecto sostenido
i_maestria 0.122 0.049 0.192 efecto sostenido
i_relajacion 0.089 -0.003 0.167 no distinguible de cero

4.3.6 Lectura para la organizacion

El resultado tiene una implicacion practica concreta y algo incomoda para las areas de recursos humanos: el engagement no se compra con actividades de bienestar. Ninguna de las cuatro experiencias de recuperacion mueve el engagement directamente. Lo mueven solo en la medida en que el colaborador efectivamente recupera energia. Un programa de yoga al que la gente asiste sin desconectarse no cambia nada.

Y entre los cuatro dominios, el que mas rinde es control sobre el tiempo libre (0.231), que no cuesta presupuesto: cuesta politica de la empresa. Es la diferencia entre organizar actividades para la gente y dejar que la gente decida como usa su tiempo.

4.4 Parte 4: el modelo de medicion

El modelo de senderos de la Parte 3 supone algo fuerte y falso: que los compuestos miden sin error. Un promedio de items no es el constructo. El modelo de medicion levanta ese supuesto poniendo cada variable latente con sus indicadores.

kable(round(cor(d[, items_eng]), 2),
      caption = "Los items de engagement: correlaciones que decaen segun la distancia en el cuestionario")
Los items de engagement: correlaciones que decaen segun la distancia en el cuestionario
EVI01 EVI02 EVI03 EDE01 EDE02 EDE03 EAB01 EAB02 EAB03
EVI01 1.00 0.94 0.80 0.82 0.74 0.61 0.70 0.53 0.44
EVI02 0.94 1.00 0.78 0.82 0.73 0.62 0.70 0.55 0.44
EVI03 0.80 0.78 1.00 0.87 0.78 0.60 0.73 0.53 0.44
EDE01 0.82 0.82 0.87 1.00 0.89 0.67 0.80 0.58 0.49
EDE02 0.74 0.73 0.78 0.89 1.00 0.74 0.79 0.59 0.53
EDE03 0.61 0.62 0.60 0.67 0.74 1.00 0.73 0.72 0.58
EAB01 0.70 0.70 0.73 0.80 0.79 0.73 1.00 0.66 0.58
EAB02 0.53 0.55 0.53 0.58 0.59 0.72 0.66 1.00 0.73
EAB03 0.44 0.44 0.44 0.49 0.53 0.58 0.58 0.73 1.00

Antes de estimar hay que ver el problema. La matriz no tiene la estructura de bloques que predice la teoria de tres factores (vigor, dedicacion, absorcion). Tiene un gradiente: cada item correlaciona mas con el que esta a su lado en el cuestionario (EVI01–EVI02 = .94, EDE01–EDE02 = .89) y menos conforme se aleja (EVI01–EAB03 = .44). EDE01 correlaciona mas con EVI03 (.87), que es de otro factor, que con EDE03 (.67), que es del suyo. Eso es un efecto de proximidad en el instrumento, no la estructura del constructo.

mod_eng3 <- ' VIGOR      =~ EVI01 + EVI02 + EVI03
              DEDICACION =~ EDE01 + EDE02 + EDE03
              ABSORCION  =~ EAB01 + EAB02 + EAB03 '
fit_eng3 <- cfa(mod_eng3, data = d, estimator = "MLR")
fit_eng2 <- cfa(paste(mod_eng3, "\n ENGAGEMENT =~ VIGOR + DEDICACION + ABSORCION"),
                data = d, estimator = "MLR")
kable(tabla_ajuste(fit_eng3, fit_eng2,
      etiquetas = c("3 factores correlacionados", "2o orden: ENGAGEMENT")),
      caption = "El modelo de segundo orden entrega una solucion INADMISIBLE")
El modelo de segundo orden entrega una solucion INADMISIBLE
chisq gl p CFI TLI RMSEA SRMR admisible
3 factores correlacionados 271.2 24 0 0.889 0.833 0.215 0.07 TRUE
2o orden: ENGAGEMENT 271.2 24 0 0.889 0.833 0.215 0.07 FALSE
Una carga estandarizada mayor que 1: caso Heywood
Parametro Valor
Carga DEDICACION en ENGAGEMENT 1.013
Correlacion DEDICACION–ABSORCION 0.913
Correlacion VIGOR–DEDICACION 0.881

Aqui esta el punto central de toda la actividad, y aparece antes de mirar ningun indice de ajuste: la carga estandarizada de dedicacion sobre engagement es mayor que 1, lo que implica una varianza de error negativa. Es un caso Heywood: un resultado imposible. Los indices de ajuste del modelo de segundo orden son identicos a los del de tres factores, asi que si me hubiera guiado solo por CFI y RMSEA no habria notado nada. Un modelo con una estimacion inadmisible se descarta, sin importar como ajuste.

La causa es visible en la tabla: dedicacion y absorcion correlacionan .91 y vigor con dedicacion .88. A ese nivel los tres factores no son distinguibles, y el factor de segundo orden intenta explicar mas covarianza de la que existe.

mod_medicion <- '
  DESAPEGO   =~ RPD01 + RPD02 + RPD03 + RPD05 + RPD08 + RPD10
  RELAJACION =~ RRE05 + RRE06 + RRE07
  MAESTRIA   =~ RMA04 + RMA05 + RMA07 + RMA08 + RMA09 + RMA10
  CONTROL    =~ RCO02 + RCO03 + RCO04 + RCO05 + RCO06 + RCO07
  ENERGIA    =~ EN01 + EN02 + EN04 + EN05 + EN06 + EN07 + EN08
  ENGAGEMENT =~ EVI01 + EVI02 + EVI03 + EDE01 + EDE02 + EDE03 + EAB01 + EAB02 + EAB03
  RECUPERACION =~ DESAPEGO + RELAJACION + MAESTRIA + CONTROL
  # los dos pares casi identicos que detecto el diagnostico de proximidad
  EVI01 ~~ EVI02
  EAB02 ~~ EAB03
  RECUPERACION ~~ ENERGIA + ENGAGEMENT
  ENERGIA ~~ ENGAGEMENT '
fit_med <- cfa(mod_medicion, data = d, estimator = "MLR")
kable(tabla_ajuste(fit_med, etiquetas = "modelo de medicion completo"),
      caption = "Ajuste aceptable y solucion admisible")
Ajuste aceptable y solucion admisible
chisq gl p CFI TLI RMSEA SRMR admisible
modelo de medicion completo 1290 620 0 0.93 0.925 0.07 0.059 TRUE

El modelo de medicion completo estima 83 parametros con 223 observaciones. Ajusta de forma aceptable pero no buena (CFI 0.93, RMSEA 0.07), y el desajuste esta concentrado en el bloque de engagement:

Los residuales mas grandes siguen siendo de los items de engagement
lhs op rhs mi epc
EDE03 EAB02 31.35 0.342
EDE01 EDE03 25.83 -0.253
EDE03 EAB01 21.32 0.294
RCO03 RCO06 20.77 -0.194
DESAPEGO =~ RRE05 20.16 0.265
DESAPEGO =~ EN01 19.36 0.232

4.4.1 El modelo estructural latente confirma la conclusion de la Parte 3

base_med <- sub("RECUPERACION ~~ ENERGIA \\+ ENGAGEMENT\n  ENERGIA ~~ ENGAGEMENT", "",
                mod_medicion)
fit_lat_c <- sem(paste(base_med, "
  ENERGIA    ~ a*RECUPERACION
  ENGAGEMENT ~ b*ENERGIA
  indirecto := a*b "), data = d, estimator = "MLR")
fit_lat_p <- sem(paste(base_med, "
  ENERGIA    ~ a*RECUPERACION
  ENGAGEMENT ~ b*ENERGIA + cp*RECUPERACION
  indirecto := a*b
  total     := cp + a*b "), data = d, estimator = "MLR")
kable(tabla_ajuste(fit_lat_c, fit_lat_p,
      etiquetas = c("latente: mediacion completa", "latente: mediacion parcial")),
      caption = "Mismo resultado que con compuestos: el camino directo no hace falta")
Mismo resultado que con compuestos: el camino directo no hace falta
chisq gl p CFI TLI RMSEA SRMR admisible
latente: mediacion completa 1294 621 0 0.929 0.924 0.07 0.063 TRUE
latente: mediacion parcial 1290 620 0 0.930 0.925 0.07 0.059 TRUE
comparar(fit_lat_c, fit_lat_p,
         c("latente: mediacion completa", "latente: mediacion parcial"),
         "Con variables latentes la conclusion no cambia")
Con variables latentes la conclusion no cambia
Modelo gl AIC BIC chisq dif. chisq dif. gl p
latente: mediacion parcial 620 24164 24447 1290 NA NA NA
latente: mediacion completa 621 24166 24445 1294 2.205 1 0.1375
Efectos con variables latentes (mediacion parcial)
Destino Origen Etiqueta Est EE p Estand.
ENERGIA RECUPERACION a 1.433 0.144 0.000 0.835
ENGAGEMENT ENERGIA b 0.379 0.129 0.003 0.428
ENGAGEMENT RECUPERACION cp 0.353 0.228 0.121 0.233
indirecto a*b indirecto 0.543 0.195 0.005 0.357
total cp+a*b total 0.897 0.132 0.000 0.590
La conclusion sustantiva no depende de como se mida: es robusta
Especificacion Camino directo estand. p del directo R2 de engagement
Compuestos (Parte 3) 0.158 0.110 0.374
Latente (Parte 4) 0.233 0.121 0.403

Corregir por error de medicion sube la magnitud de los efectos, como se espera (las correlaciones atenuadas por falta de fiabilidad se desatenuan), pero no cambia la conclusion: el camino directo sigue sin ser significativo y la varianza explicada del engagement es practicamente la misma. La mediacion completa se sostiene con las dos especificaciones.

4.5 Conclusiones del ejercicio 3

  1. El instrumento de recuperacion tenia grasa. De 31 items quedaron
    1. Lo que se elimino no fueron items malos sino items repetidos: pares que dicen lo mismo con otras palabras. La regla de depuracion redescubrio tres de las cuatro eliminaciones que ya habian documentado los autores.
  2. El constructo de segundo orden se sostiene. Los cuatro dominios son facetas de una sola capacidad de recuperacion, y renunciar a las seis correlaciones libres a cambio de cuatro cargas no cuesta ajuste (p = 0.057).
  3. La energia recuperada es unidimensional, con cargas de .89 a .95. El RMSEA alto es un artefacto de tener pocos grados de libertad, no evidencia de mala estructura, y no se corrige tirando items.
  4. La mediacion es completa. Las experiencias de recuperacion no tocan el engagement por su cuenta: lo tocan solo a traves de la energia efectivamente recuperada (p = 0.363 para la restriccion de mediacion completa, y ningun camino directo significativo).
  5. Control sobre el tiempo libre es la palanca. Efecto indirecto estandarizado de 0.231, casi el doble del siguiente. Relajacion, en cambio, no sobrevive al intervalo bootstrap.
  6. La escala de engagement no replica su estructura teorica en esta muestra. El modelo de segundo orden produce un caso Heywood, y el patron de correlaciones apunta a un efecto de proximidad en el cuestionario. Este es el hallazgo que conecta directamente con el ejercicio 4.

5 Ejercicio 4: Behson, Eddy y Lorenzet (2000)

5.1 Los dos modelos que compiten

Behson, Eddy y Lorenzet (2000) juntan 13 estudios sobre el Modelo de Caracteristicas del Puesto de Hackman y Oldham en un meta-analisis, arman con el una matriz de correlaciones y estiman sobre ella dos modelos rivales:

Los dos modelos del articulo
Modelo Estructura Caminos Supuesto
Modelo 1: JCM original (3 etapas) 5 caracteristicas del puesto -> 3 estados psicologicos criticos -> 3 resultados 14 mediacion completa por los estados psicologicos
Modelo 2: JCM como se prueba (2 etapas) 5 caracteristicas del puesto -> 3 resultados (los estados se omiten) 15 efecto directo, sin mecanismo intermedio

El Modelo 1 es la teoria original: las caracteristicas del puesto (variedad, significado, identidad, autonomia, retroalimentacion) producen tres estados psicologicos criticos (significado experimentado, responsabilidad experimentada, conocimiento de resultados) y son estos los que producen satisfaccion, satisfaccion de crecimiento y motivacion interna. El Modelo 2 es como casi toda la literatura posterior lo ha probado: brincandose los estados psicologicos.

5.2 Lo que reporta el articulo

Tabla 4 del articulo. El Modelo 2 gana en GFI, CFI, AIC y CAIC
Estadistico Modelo_1 Modelo_2
Chi-cuadrada (gl) 124.25 (25) 12.09 (3)
RMSEA .14 .16
GFI .91 .99
CFI .89 .98
Caminos significativos 12 de 14 7 de 15
R2 satisfaccion .42 .37
R2 crecimiento .42 .43
R2 motivacion .38 .32
AIC 294.48 80.09
CAIC 446.29 227.56

Los autores lo dicen sin rodeos: el AIC y el CAIC, que son los unicos estadisticos que usan para comparar formalmente los dos modelos, favorecen al Modelo 2. Y aun asi eligen el Modelo 1.

5.3 Replicacion: la matriz del articulo esta publicada, asi que se puede verificar

La Tabla 2 del articulo publica la matriz de correlaciones meta-analitica completa y las desviaciones estandar normativas de Oldham, Hackman y Stepina (1979). Con eso se puede reconstruir la matriz de covarianzas y volver a estimar los dos modelos.

v   <- c("VAR","SIG","IDE","AUT","FBK","MEA","RES","KNO","SAT","GRO","MOT")
sdv <- c(1.57, 1.25, 1.44, 1.39, 1.34, 1.14, 0.96, 1.14, 1.07, 1.15, 0.77)
R <- diag(11); dimnames(R) <- list(v, v)
tri <- list(c(.41), c(.22,.20), c(.43,.32,.32), c(.35,.34,.26,.39),
            c(.46,.45,.24,.42,.38), c(.34,.33,.27,.39,.34,.59),
            c(.16,.23,.28,.29,.49,.40,.34), c(.35,.29,.22,.42,.36,.65,.49,.42),
            c(.50,.38,.26,.54,.44,.65,.51,.40,.69),
            c(.35,.33,.17,.30,.42,.57,.59,.25,.43,.50))
for (i in 2:11) { R[i, 1:(i-1)] <- tri[[i-1]]; R[1:(i-1), i] <- tri[[i-1]] }
S <- diag(sdv) %*% R %*% diag(sdv); dimnames(S) <- dimnames(R)
N <- 208   # los autores usan la mediana del tamanio de muestra, no la suma
mod_b1 <- '
  MEA ~ VAR + SIG + IDE
  RES ~ AUT
  KNO ~ FBK
  SAT ~ MEA + RES + KNO
  GRO ~ MEA + RES + KNO
  MOT ~ MEA + RES + KNO
  MEA ~~ RES + KNO
  RES ~~ KNO
  SAT ~~ GRO + MOT
  GRO ~~ MOT '
fit_b1 <- sem(mod_b1, sample.cov = S, sample.nobs = N, fixed.x = FALSE)
round(fitMeasures(fit_b1, c("chisq","df","cfi","rmsea","gfi")), 3)
##   chisq      df     cfi   rmsea     gfi 
## 106.967  25.000   0.884   0.126   0.943
round(inspect(fit_b1, "r2"), 3)
##   MEA   RES   KNO   SAT   GRO   MOT 
## 0.205 0.082 0.187 0.419 0.418 0.382
El Modelo 1 se reproduce casi exactamente
Cantidad Articulo Replicacion
Grados de libertad 25 25
Caminos significativos 12 de 14 12 de 14
R2 satisfaccion .42 0.419
R2 crecimiento .42 0.418
R2 motivacion .38 0.382

La replicacion del Modelo 1 es practicamente exacta: mismos grados de libertad, mismos 12 de 14 caminos significativos y las tres R2 coinciden al segundo decimal. Eso valida que la matriz esta bien reconstruida y que entendi la especificacion.

o8 <- c("VAR","SIG","IDE","AUT","FBK","SAT","GRO","MOT")
mod_b2 <- '
  SAT ~ VAR + SIG + IDE + AUT + FBK
  GRO ~ VAR + SIG + IDE + AUT + FBK
  MOT ~ VAR + SIG + IDE + AUT + FBK '
# auto.cov.y = FALSE reproduce los 3 grados de libertad que reporta el articulo
fit_b2 <- sem(mod_b2, sample.cov = S[o8, o8], sample.nobs = N,
              fixed.x = FALSE, auto.cov.y = FALSE)
round(fitMeasures(fit_b2, c("chisq","df","cfi","rmsea","gfi")), 3)
##   chisq      df     cfi   rmsea     gfi 
## 100.258   3.000   0.692   0.395   0.897

Nota de verificacion. Los grados de libertad coinciden (3), pero la chi-cuadrada que obtengo es 100.26 contra los 12.09 publicados, y el CFI me da 0.692 contra .98. La razon es identificable: con 3 grados de libertad las tres covarianzas entre los residuales de los resultados estan fijas en cero, y satisfaccion con crecimiento correlacionan .69 en la matriz publicada, asi que esa restriccion tiene que producir un desajuste enorme. Si se liberan esas tres covarianzas el modelo queda saturado (gl = 0, ajuste perfecto). No existe una especificacion que de al mismo tiempo gl = 3 y chi-cuadrada = 12.09 con la matriz que ellos publican. Dado que el Modelo 1 si se reproduce, la inconsistencia esta en el reporte del Modelo 2, no en mi reconstruccion. Conviene contrastarlo con el profesor.

5.4 La comparacion por AIC del articulo no es valida, y eso refuerza su propia decision

Independientemente del punto anterior, hay un problema mas grave con el argumento cuantitativo del articulo. El AIC y el CAIC son el unico criterio formal que usan para declarar superior al Modelo 2. Pero comparan dos modelos ajustados a conjuntos distintos de variables observadas: el Modelo 1 usa 11 variables (66 momentos) y el Modelo 2 usa 8 (36 momentos). La verosimilitud de ambos no esta en la misma escala.

# dos modelos de ajuste PERFECTO, uno con 11 variables y otro con 8
sat11 <- paste(apply(t(combn(v, 2)), 1, function(p) paste(p[1], "~~", p[2])), collapse = "\n")
fit_s11 <- sem(sat11, sample.cov = S, sample.nobs = N)
fit_s8  <- sem(paste(mod_b2, "\n SAT ~~ GRO + MOT \n GRO ~~ MOT"),
               sample.cov = S[o8, o8], sample.nobs = N, fixed.x = FALSE)
kable(data.frame(
  Modelo = c("Saturado, 11 variables (ajuste perfecto)",
             "Saturado, 8 variables (ajuste perfecto)"),
  chisq = c(0, 0), gl = c(0, 0),
  AIC = round(c(fitMeasures(fit_s11, "aic"), fitMeasures(fit_s8, "aic")), 0)),
  row.names = FALSE,
  caption = "Dos modelos con ajuste identicamente perfecto y AIC separados por mas de mil puntos")
Dos modelos con ajuste identicamente perfecto y AIC separados por mas de mil puntos
Modelo chisq gl AIC
Saturado, 11 variables (ajuste perfecto) 0 0 6455
Saturado, 8 variables (ajuste perfecto) 0 0 4952

Los dos modelos de la tabla ajustan perfecto, y aun asi sus AIC difieren en 1503 puntos. La diferencia no mide calidad de ajuste: mide cuantas variables entraron al modelo. Un modelo con menos variables siempre va a tener menor AIC, aunque sea peor teoria. Por lo tanto el argumento “el AIC y el CAIC favorecen al Modelo 2” no sostiene lo que se le pide sostener.

5.5 Por que eligieron el Modelo 1: la respuesta del articulo

Los autores no invocan el argumento anterior. Su razon es distinta y, en mi lectura, mas fuerte todavia. La formulan asi: comparar modelos rivales exige mas que comparar razones de ajuste, porque la razonabilidad de los valores del modelo y su correspondencia con la teoria son igual o mas importantes.

El hecho concreto que los decide esta en los coeficientes:

pb2 <- subset(parameterEstimates(fit_b2, standardized = TRUE), op == "~")
tres <- pb2[pb2$rhs %in% c("VAR","SIG","IDE"), ]
kable(tres[, c("lhs","rhs","est","se","pvalue","std.all")], row.names = FALSE, digits = 3,
      col.names = c("Resultado","Caracteristica","Estimado","EE","p","Estandarizado"),
      caption = "Modelo 2: los caminos desde variedad, significado e identidad hacia los resultados")
Modelo 2: los caminos desde variedad, significado e identidad hacia los resultados
Resultado Caracteristica Estimado EE p Estandarizado
SAT VAR 0.093 0.048 0.056 0.136
SAT SIG 0.073 0.058 0.210 0.086
SAT IDE 0.035 0.048 0.460 0.048
GRO VAR 0.182 0.046 0.000 0.248
GRO SIG 0.099 0.055 0.071 0.108
GRO IDE 0.028 0.045 0.535 0.035
MOT VAR 0.078 0.035 0.026 0.159
MOT SIG 0.088 0.042 0.036 0.143
MOT IDE 0.005 0.035 0.885 0.009

En el Modelo 2, 6 de los 9 caminos que van de variedad de habilidades, significado de la tarea e identidad de la tarea hacia los resultados no son significativos. El articulo reporta 8 de 9; yo obtengo 6 de 9, con dos casos al filo. La conclusion es la misma: si el Modelo 2 fuera cierto, enriquecer un puesto dandole variedad y significado no serviria de nada. Eso contradice dos decadas de investigacion sobre rediseno del trabajo.

El Modelo 1 resuelve la paradoja:

mod_b1_ind <- '
  MEA ~ v*VAR + s*SIG + i*IDE
  RES ~ AUT
  KNO ~ FBK
  SAT ~ m1*MEA + RES + KNO
  GRO ~ m2*MEA + RES + KNO
  MOT ~ m3*MEA + RES + KNO
  MEA ~~ RES + KNO
  RES ~~ KNO
  SAT ~~ GRO + MOT
  GRO ~~ MOT
  variedad_sat        := v*m1
  variedad_crec       := v*m2
  significado_sat     := s*m1
  significado_crec    := s*m2 '
fit_b1i <- sem(mod_b1_ind, sample.cov = S, sample.nobs = N, fixed.x = FALSE)
kable(subset(parameterEstimates(fit_b1i, standardized = TRUE), op == ":=")[
        , c("lhs","est","se","pvalue","std.all")], row.names = FALSE, digits = 3,
      col.names = c("Efecto indirecto","Estimado","EE","p","Estandarizado"),
      caption = "En el Modelo 1 esos mismos caminos SI existen, pero pasan por el significado experimentado")
En el Modelo 1 esos mismos caminos SI existen, pero pasan por el significado experimentado
Efecto indirecto Estimado EE p Estandarizado
variedad_sat 0.094 0.023 0 0.144
variedad_crec 0.099 0.024 0 0.142
significado_sat 0.095 0.027 0 0.116
significado_crec 0.101 0.028 0 0.114

Variedad y significado si afectan la satisfaccion y el crecimiento, pero lo hacen a traves del significado experimentado. Al borrar los estados psicologicos, el Modelo 2 no elimina un rodeo innecesario: elimina el mecanismo, y con el desaparece el efecto.

Los autores eligen el Modelo 1, entonces, por cuatro razones acumuladas:

  1. Los coeficientes del Modelo 2 contradicen la teoria establecida. Un modelo cuyos parametros no tienen sentido sustantivo no es utilizable, ajuste lo que ajuste.
  2. El Modelo 1 explica mas varianza en dos de los tres resultados y tiene mejor proporcion de caminos significativos (12 de 14 contra 7 de 15).
  3. El mejor ajuste del Modelo 2 es en buena medida mecanico. Con 3 grados de libertad esta a un paso de estar saturado, y un modelo casi saturado casi no puede desajustar. Los 25 grados de libertad del Modelo 1 son una hipotesis mucho mas expuesta a refutacion. De hecho el RMSEA, que es el unico indice de la tabla que penaliza la falta de parsimonia, es peor en el Modelo 2 (.16 contra .14).
  4. El proposito del modelo es explicar, no solo describir. Los estados psicologicos son lo unico sobre lo que un gerente puede actuar con criterio: le dicen por que funciona el rediseno del puesto y cuando no va a funcionar.

5.6 Conclusiones del ejercicio 4: la leccion

Un indice de ajuste mide si el modelo reproduce la matriz de covarianzas. No mide si el modelo es verdadero, ni si es util, ni siquiera si es posible. Elegir modelo por CFI es como elegir un pronostico por su R2 dentro de muestra.

Las tres verificaciones que este articulo me deja como rutina, en este orden:

  1. Admisibilidad primero. Antes de leer un solo indice, revisar que no haya varianzas negativas ni cargas estandarizadas mayores que 1. En el ejercicio 3 esto descarto el modelo de engagement de segundo orden antes de que su ajuste identico al de tres factores me hiciera pasarlo por alto.
  2. Signo y magnitud de los coeficientes contra la teoria. Un modelo que ajusta mejor pero dice que dar variedad al trabajo no sirve, esta diciendo algo falso.
  3. Comparabilidad de la comparacion. Chi-cuadrada solo entre modelos anidados; AIC solo entre modelos sobre las mismas variables. En el ejercicio 3 esto me obligo a fijar el camino directo en cero para poder contrastar algo, en vez de celebrar el CFI = 1 de un modelo saturado.

Y la leccion de fondo, que es la que conecta los cuatro ejercicios: borrar el mediador mejora el ajuste y destruye la explicacion. El Modelo 2 de Behson ajusta mejor porque pide menos; mi modelo de mediacion parcial de la Parte 3 ajustaba perfecto porque no pedia nada. En los dos casos, el modelo que vale es el que se atreve a afirmar el mecanismo y sobrevive a la prueba.

6 Limitaciones

  1. Los datos del ejercicio 3 son transversales. Todo el lenguaje causal (“las experiencias de recuperacion producen energia, que produce engagement”) describe la estructura del modelo, no una causalidad demostrada. Con una sola medicion, el modelo inverso (colaboradores comprometidos se recuperan mejor) ajusta igual de bien. Para distinguirlos hace falta medicion repetida, como en el ejercicio 2.
  2. Varianza de metodo comun. Recuperacion, energia y engagement se midieron en el mismo cuestionario, con la misma persona y en el mismo momento. Parte de las correlaciones observadas es del instrumento, no de los constructos. El gradiente de proximidad en los items de engagement es evidencia directa de que ese efecto existe en esta base.
  3. La depuracion se valido dentro de la misma muestra. En el ejercicio 1 pude usar las dos escuelas como muestras de descubrimiento y confirmacion; en el ejercicio 3, con 223 casos, partir la muestra habria dejado submuestras demasiado chicas para 21 items. Los indices de ajuste del modelo depurado estan por lo tanto optimistas.
  4. La escala de engagement no se depuro porque el enunciado la da por depurada. Es la fuente principal del desajuste del modelo de medicion, y su estructura teorica no se sostiene en esta muestra.
  5. La replicacion del ejercicio 4 parte de una matriz publicada, no de los datos originales. Las diferencias con lo reportado pueden deberse a decisiones de especificacion en LISREL que el articulo no documenta.

7 Referencias

  • Behson, S. J., Eddy, E. R., y Lorenzet, S. J. (2000). The importance of the critical psychological states in the job characteristics model: A meta-analytic and structural equations modeling examination. Current Research in Social Psychology, 5(12), 170–189.
  • Bollen, K. A. (1989). Structural equations with latent variables. Wiley.
  • Hackman, J. R., y Oldham, G. R. (1976). Motivation through the design of work: Test of a theory. Organizational Behavior and Human Performance, 16(2), 250–279.
  • Holzinger, K. J., y Swineford, F. (1939). A study in factor analysis: The stability of a bi-factor solution. University of Chicago.
  • Hu, L., y Bentler, P. M. (1999). Cutoff criteria for fit indexes in covariance structure analysis. Structural Equation Modeling, 6(1), 1–55.
  • Kenny, D. A., Kaniskan, B., y McCoach, D. B. (2015). The performance of RMSEA in models with small degrees of freedom. Sociological Methods and Research, 44(3), 486–507.
  • Rosseel, Y. (2012). lavaan: An R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36.
  • Schaufeli, W. B., y Bakker, A. B. (2003). UWES: Utrecht Work Engagement Scale. Occupational Health Psychology Unit, Utrecht University.
Entorno de ejecucion
Componente Valor
R R version 4.6.1 (2026-06-24)
lavaan 0.7.2
Semilla 2026
Observaciones 223
LS0tCnRpdGxlOiAiRWN1YWNpb25lcyBlc3RydWN0dXJhbGVzOiBlbCBhanVzdGUgbm8gZWxpZ2UgZWwgbW9kZWxvLCBsbyBlbGlnZSBsYSB0ZW9yaWEiCnN1YnRpdGxlOiAiQWN0aXZpZGFkIDMsIFBhcnRlIDEgLS0tIE1vZHVsbyAxIC0tLSBHZW5lcmFjaW9uIGRlIGVzY2VuYXJpb3MgZnV0dXJvcyBjb24KICBhbmFsaXRpY2EgKENELTMwMDFCKSIKYXV0aG9yOiAiUGF0cmljaW8gSGVybW9zaWxsbyAtLS0gQTAxNTY3MDM2IgpkYXRlOiAiMjYgZGUgYWdvc3RvIGRlIDIwMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0aGVtZTogdW5pdGVkCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAogICAgZGZfcHJpbnQ6IGthYmxlCmZvbnRzaXplOiAxMXB0Cmdlb21ldHJ5OiBtYXJnaW49Mi41Y20KaGVhZGVyLWluY2x1ZGVzOiB8CiAgXHVzZXBhY2thZ2V7ZmxvYXR9CiAgXGZsb2F0cGxhY2VtZW50e3RhYmxlfXtIfQogIFxmbG9hdHBsYWNlbWVudHtmaWd1cmV9e0h9Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLndpZHRoID0gNi41LCBmaWcuaGVpZ2h0ID0gNCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5wb3MgPSAiSCIsIG91dC5leHRyYSA9ICIiKQpvcHRpb25zKHNjaXBlbiA9IDk5OSwgZGlnaXRzID0gNCkKbGlicmFyeShsYXZhYW4pCmxpYnJhcnkoa25pdHIpCnNldC5zZWVkKDIwMjYpCmBgYAoKIyBDb21vIGxlZXIgZXN0ZSBkb2N1bWVudG8KCkxvcyBjdWF0cm8gZWplcmNpY2lvcyBjb21wYXJ0ZW4gdW5hIHNvbGEgcHJlZ3VudGE6ICoqY3VhbmRvIGRvcyBtb2RlbG9zIGNvbXBpdGVuLCBxdWllbgpkZWNpZGU/KiogTGEgcmVzcHVlc3RhIHF1ZSBzb3N0ZW5nbyBlcyBxdWUgbG9zIGluZGljZXMgZGUgYWp1c3RlIHNvbiB1bmEgY29uZGljaW9uCm5lY2VzYXJpYSBwZXJvIG51bmNhIHN1ZmljaWVudGUsIHkgcXVlIHVuIG1vZGVsbyBjb24gbWVqb3IgYWp1c3RlIHB1ZWRlIHNlciBwZW9yIG1vZGVsby4KTG9zIGVqZXJjaWNpb3MgMSBhIDMgY29uc3RydXllbiBsYSBldmlkZW5jaWEgY29uIGRhdG9zOyBlbCBlamVyY2ljaW8gNCBsYSBjb25mcm9udGEgY29uCnVuIGNhc28gcHVibGljYWRvIGRvbmRlIGxvcyBhdXRvcmVzIHJlY2hhemFyb24gc3UgcHJvcGlvIG1vZGVsbyBtZWpvciBhanVzdGFkby4KClRvZG9zIGxvcyBtb2RlbG9zIHNlIGVzdGltYW4gY29uIGBsYXZhYW5gLiBMb3MgY3JpdGVyaW9zIGRlIGFqdXN0ZSBxdWUgdXNvIGEgbG8gbGFyZ28gZGVsCmRvY3VtZW50byBzb24gbG9zIGNvbnZlbmNpb25hbGVzIGVuIGxhIGxpdGVyYXR1cmEgKEh1IHkgQmVudGxlciwgMTk5OSk6CgpgYGB7ciBjcml0ZXJpb3MsIGVjaG89RkFMU0V9CmthYmxlKGRhdGEuZnJhbWUoCiAgSW5kaWNlID0gYygiQ2hpLWN1YWRyYWRhIiwgIkNGSSAvIFRMSSIsICJSTVNFQSIsICJTUk1SIiksCiAgUXVlX21pZGUgPSBjKCJEaXN0YW5jaWEgYWJzb2x1dGEgZW50cmUgbGEgbWF0cml6IG9ic2VydmFkYSB5IGxhIGltcGxpY2FkYSIsCiAgICAgICAgICAgICAgICJBanVzdGUgY29tcGFyYXRpdm8gY29udHJhIGVsIG1vZGVsbyBudWxvIiwKICAgICAgICAgICAgICAgIkVycm9yIGRlIGFwcm94aW1hY2lvbiBwb3IgZ3JhZG8gZGUgbGliZXJ0YWQgKHBlbmFsaXphIGZhbHRhIGRlIHBhcnNpbW9uaWEpIiwKICAgICAgICAgICAgICAgIlJlc2lkdWFsIGVzdGFuZGFyaXphZG8gcHJvbWVkaW8iKSwKICBDcml0ZXJpbyA9IGMoIm5vIHNpZ25pZmljYXRpdmEgKHNlbnNpYmxlIGEgTikiLCAiPj0gLjk1IChhY2VwdGFibGUgPj0gLjkwKSIsCiAgICAgICAgICAgICAgICI8PSAuMDYgKGFjZXB0YWJsZSA8PSAuMDgpIiwgIjw9IC4wOCIpKSwKICBjYXB0aW9uID0gIkNyaXRlcmlvcyBkZSBhanVzdGUgdXNhZG9zIGVuIHRvZG8gZWwgZG9jdW1lbnRvIikKYGBgCgpgYGB7ciBoZWxwZXJzfQojIGluZGljZXMgcXVlIHJlcG9ydG8gZW4gY2FkYSBtb2RlbG8KSURYIDwtIGMoImNoaXNxIiwgImRmIiwgInB2YWx1ZSIsICJjZmkiLCAidGxpIiwgInJtc2VhIiwgInNybXIiKQoKIyB0YWJsYSBkZSBhanVzdGUgZGUgdW5vIG8gdmFyaW9zIG1vZGVsb3MsIHBhcmEgY29tcGFyYXIgZW4gZWwgbWlzbW8gcmVuZ2xvbgp0YWJsYV9hanVzdGUgPC0gZnVuY3Rpb24oLi4uLCBldGlxdWV0YXMgPSBOVUxMKSB7CiAgbW9kZWxvcyA8LSBsaXN0KC4uLikKICBpZiAoaXMubnVsbChldGlxdWV0YXMpKSBldGlxdWV0YXMgPC0gcGFzdGUoIk1vZGVsbyIsIHNlcV9hbG9uZyhtb2RlbG9zKSkKICBvdXQgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KG1vZGVsb3MsIGZ1bmN0aW9uKG0pIHsKICAgIGZtIDwtIGZpdE1lYXN1cmVzKG0sIElEWCkKICAgIGRhdGEuZnJhbWUoY2hpc3EgPSByb3VuZChmbVtbImNoaXNxIl1dLCAyKSwgZ2wgPSBmbVtbImRmIl1dLAogICAgICAgICAgICAgICBwID0gcm91bmQoZm1bWyJwdmFsdWUiXV0sIDMpLCBDRkkgPSByb3VuZChmbVtbImNmaSJdXSwgMyksCiAgICAgICAgICAgICAgIFRMSSA9IHJvdW5kKGZtW1sidGxpIl1dLCAzKSwgUk1TRUEgPSByb3VuZChmbVtbInJtc2VhIl1dLCAzKSwKICAgICAgICAgICAgICAgU1JNUiA9IHJvdW5kKGZtW1sic3JtciJdXSwgMykpCiAgfSkpCiAgIyBwb3N0LmNoZWNrIGF2aXNhIGRlIHNvbHVjaW9uZXMgaW5hZG1pc2libGVzICh2YXJpYW56YXMgbmVnYXRpdmFzLCBjYXJnYXMgPiAxKQogIG91dCRhZG1pc2libGUgPC0gc2FwcGx5KG1vZGVsb3MsIGZ1bmN0aW9uKG0pIGxhdkluc3BlY3QobSwgInBvc3QuY2hlY2siKSkKICByb3duYW1lcyhvdXQpIDwtIGV0aXF1ZXRhcwogIG91dAp9CgojIHBydWViYSBkZSBkaWZlcmVuY2lhIGRlIGNoaS1jdWFkcmFkYSBlbnRyZSBkb3MgbW9kZWxvcyBhbmlkYWRvcywgY29tbyB0YWJsYSBjb24gdGl0dWxvCiMgKGxhcyBzYWxpZGFzIHNpbiB0aXR1bG8gc2UgZGVzYWxpbmVhbiBkZSBzdSByb3R1bG8gYWwgY29tcGlsYXIgYSBQREYpCmNvbXBhcmFyIDwtIGZ1bmN0aW9uKG1vZGVsb19hLCBtb2RlbG9fYiwgZXRpcXVldGFzLCBjYXB0aW9uKSB7CiAgZ2wgPC0gYyhmaXRNZWFzdXJlcyhtb2RlbG9fYSwgImRmIiksIGZpdE1lYXN1cmVzKG1vZGVsb19iLCAiZGYiKSkKICBhICA8LSBzdXBwcmVzc1dhcm5pbmdzKGxhdlRlc3RMUlQobW9kZWxvX2EsIG1vZGVsb19iKSkKICAjIGxhdlRlc3RMUlQgZGV2dWVsdmUgbG9zIG1vZGVsb3Mgb3JkZW5hZG9zIHBvciBncmFkb3MgZGUgbGliZXJ0YWQsIG5vIGVuIGVsIG9yZGVuCiAgIyBlbiBxdWUgc2UgcGFzYW46IGhheSBxdWUgcmVvcmRlbmFyIGxhcyBldGlxdWV0YXMgaWd1YWwgbyBxdWVkYW4gY3J1emFkYXMKICBvdXQgPC0gZGF0YS5mcmFtZShNb2RlbG8gPSBldGlxdWV0YXNbbWF0Y2goYSREZiwgZ2wpXSwKICAgICAgICAgICAgICAgICAgICBnbCA9IGEkRGYsIEFJQyA9IHJvdW5kKGEkQUlDLCAxKSwgQklDID0gcm91bmQoYSRCSUMsIDEpLAogICAgICAgICAgICAgICAgICAgIGNoaXNxID0gcm91bmQoYSRDaGlzcSwgMiksCiAgICAgICAgICAgICAgICAgICAgZGlmX2NoaXNxID0gcm91bmQoYSQiQ2hpc3EgZGlmZiIsIDMpLAogICAgICAgICAgICAgICAgICAgIGRpZl9nbCA9IGEkIkRmIGRpZmYiLAogICAgICAgICAgICAgICAgICAgIHAgPSByb3VuZChhJCJQcig+Q2hpc3EpIiwgNCkpCiAga2FibGUob3V0LCByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgICBjb2wubmFtZXMgPSBjKCJNb2RlbG8iLCJnbCIsIkFJQyIsIkJJQyIsImNoaXNxIiwiZGlmLiBjaGlzcSIsImRpZi4gZ2wiLCJwIiksCiAgICAgICAgY2FwdGlvbiA9IGNhcHRpb24pCn0KCiMgY2FyZ2FzIGVzdGFuZGFyaXphZGFzIG9yZGVuYWRhcyBkZSBtZW5vciBhIG1heW9yCmNhcmdhcyA8LSBmdW5jdGlvbihmaXQpIHsKICBzIDwtIHN1YnNldChzdGFuZGFyZGl6ZWRTb2x1dGlvbihmaXQpLCBvcCA9PSAiPX4iKQogIHMgPC0gc1tvcmRlcihzJGVzdC5zdGQpLCBjKCJsaHMiLCAicmhzIiwgImVzdC5zdGQiLCAicHZhbHVlIildCiAgbmFtZXMocykgPC0gYygiRmFjdG9yIiwgIkl0ZW0iLCAiQ2FyZ2FfZXN0YW5kYXJpemFkYSIsICJwIikKICByb3duYW1lcyhzKSA8LSBOVUxMCiAgcwp9CmBgYAoKIyBFamVyY2ljaW8gMTogSG9semluZ2VyIHkgU3dpbmVmb3JkICgxOTM5KQoKIyMgRWwgbW9kZWxvIHRlb3JpY28gZGUgdHJlcyBmYWN0b3JlcyBhanVzdGEgbWFsLCB5IGVsIHByb2JsZW1hIHRpZW5lIG5vbWJyZTogeDkKCkxhIGJhc2UgY2xhc2ljYSBkZSBIb2x6aW5nZXIgeSBTd2luZWZvcmQgcmVnaXN0cmEgbnVldmUgcHJ1ZWJhcyBtZW50YWxlcyBhcGxpY2FkYXMgYQpgciBucm93KEhvbHppbmdlclN3aW5lZm9yZDE5MzkpYCBlc3R1ZGlhbnRlcyBkZSBkb3MgZXNjdWVsYXMuIExhIHRlb3JpYSBwcm9wb25lIHRyZXMKaGFiaWxpZGFkZXMgbGF0ZW50ZXM6ICoqdmlzdWFsKiogKHgxLS14MyksICoqdmVyYmFsKiogKHg0LS14NikgeSAqKnZlbG9jaWRhZCoqICh4Ny0teDkpLgoKYGBge3IgZWoxLWJhc2V9Cm1vZF9ocyA8LSAnIHZpc3VhbCAgPX4geDEgKyB4MiArIHgzCiAgICAgICAgICAgIHRleHR1YWwgPX4geDQgKyB4NSArIHg2CiAgICAgICAgICAgIHNwZWVkICAgPX4geDcgKyB4OCArIHg5ICcKZml0X2hzIDwtIGNmYShtb2RfaHMsIGRhdGEgPSBIb2x6aW5nZXJTd2luZWZvcmQxOTM5KQprYWJsZSh0YWJsYV9hanVzdGUoZml0X2hzLCBldGlxdWV0YXMgPSAiMyBmYWN0b3JlcyAodGVvcmljbykiKSwKICAgICAgY2FwdGlvbiA9ICJFbCBtb2RlbG8gdGVvcmljbyBzZSBxdWVkYSBjb3J0bzogQ0ZJIHBvciBkZWJham8gZGUgLjk1IHkgUk1TRUEgYXJyaWJhIGRlIC4wNiIpCmBgYAoKRWwgQ0ZJIGRlIGByIHJvdW5kKGZpdE1lYXN1cmVzKGZpdF9ocywiY2ZpIiksMylgIHkgZWwgUk1TRUEgZGUKYHIgcm91bmQoZml0TWVhc3VyZXMoZml0X2hzLCJybXNlYSIpLDMpYCBzb24gYWNlcHRhYmxlcyBwZXJvIG5vIGJ1ZW5vcy4gQW50ZXMgZGUgdG9jYXIKbmFkYSwgY29udmllbmUgdmVyICoqZG9uZGUqKiBmYWxsYToKCmBgYHtyIGVqMS1jYXJnYXMsIGVjaG89RkFMU0V9CmthYmxlKGNhcmdhcyhmaXRfaHMpLCByb3cubmFtZXMgPSBGQUxTRSwgZGlnaXRzID0gMywKICAgICAgY2FwdGlvbiA9ICJ4MiAoLjQyKSB5IHgzICguNTgpIHNvc3RpZW5lbiBtYWwgYWwgZmFjdG9yIHZpc3VhbCIpCmBgYAoKYGBge3IgZWoxLW1pfQptaV9ocyA8LSBtb2RpbmRpY2VzKGZpdF9ocywgc29ydC4gPSBUUlVFKQprYWJsZShoZWFkKG1pX2hzWywgYygibGhzIiwib3AiLCJyaHMiLCJtaSIsImVwYyIsInNlcGMuYWxsIildLCA2KSwgcm93Lm5hbWVzID0gRkFMU0UsCiAgICAgIGRpZ2l0cyA9IDMsIGNhcHRpb24gPSAiSW5kaWNlcyBkZSBtb2RpZmljYWNpb246IHg5IHF1aWVyZSBjYXJnYXIgdGFtYmllbiBlbiB2aXN1YWwiKQpgYGAKCkVsIGluZGljZSBtYXMgZ3JhbmRlIG5vIGVzIHVuIGVycm9yIHJlc2lkdWFsIGN1YWxxdWllcmE6IGVzIGB2aXN1YWwgPX4geDlgLCBjb24gdW4gTUkgZGUKYHIgcm91bmQobWlfaHMkbWlbMV0sMSlgLiBFc28gdGllbmUgbGVjdHVyYSBzdXN0YW50aXZhLiBMYSBwcnVlYmEgeDkgbWlkZSAqdmVsb2NpZGFkIHBhcmEKY29udGFyIHB1bnRvcyBlbiBmaWd1cmFzKjogZXMgdW5hIHRhcmVhIGRlIHJhcGlkZXosIHNpLCBwZXJvICoqZWwgZXN0aW11bG8gZXMgdmlzdWFsKiouCk5vIGVzIHJhcm8gcXVlIGNvbXBhcnRhIHZhcmlhbnphIGNvbiBlbCBmYWN0b3IgdmlzdWFsLgoKIyMgRGVwdXJhY2lvbjogdW4gc29sbyBwYXJhbWV0cm8sIGVsZWdpZG8gcG9yIHRlb3JpYSB5IG5vIHBvciBlbCBpbmRpY2UgbWFzIGFsdG8KCmBgYHtyIGVqMS1kZXB9Cm1vZF9oczIgPC0gJyB2aXN1YWwgID1+IHgxICsgeDIgKyB4MyArIHg5CiAgICAgICAgICAgICB0ZXh0dWFsID1+IHg0ICsgeDUgKyB4NgogICAgICAgICAgICAgc3BlZWQgICA9fiB4NyArIHg4ICsgeDkgJwpmaXRfaHMyIDwtIGNmYShtb2RfaHMyLCBkYXRhID0gSG9semluZ2VyU3dpbmVmb3JkMTkzOSkKCiMgYWx0ZXJuYXRpdmEgcXVlIGVsIE1JIHRhbWJpZW4gc3VnaWVyZSwgcGVybyBzaW4gbGVjdHVyYSBzdXN0YW50aXZhIGNsYXJhCm1vZF9oczMgPC0gcGFzdGUobW9kX2hzLCAiXG4geDcgfn4geDkiKQpmaXRfaHMzIDwtIGNmYShtb2RfaHMzLCBkYXRhID0gSG9semluZ2VyU3dpbmVmb3JkMTkzOSkKCmthYmxlKHRhYmxhX2FqdXN0ZShmaXRfaHMsIGZpdF9oczIsIGZpdF9oczMsCiAgICAgIGV0aXF1ZXRhcyA9IGMoIjMgZmFjdG9yZXMgKHRlb3JpY28pIiwgIng5IGNhcmdhIHRhbWJpZW4gZW4gdmlzdWFsIiwKICAgICAgICAgICAgICAgICAgICAiY292YXJpYW56YSByZXNpZHVhbCB4NyB+fiB4OSIpKSwKICAgICAgY2FwdGlvbiA9ICJTb2xvIGxhIGNhcmdhIGNydXphZGEgZGUgeDkgbXVldmUgZWwgYWp1c3RlIGEgdGVycml0b3JpbyBidWVubyIpCmBgYAoKYGBge3IgZWoxLWFub3ZhfQpjb21wYXJhcihmaXRfaHMsIGZpdF9oczIsCiAgICAgICAgIGMoIjMgZmFjdG9yZXMgKHRlb3JpY28pIiwgIng5IGNhcmdhIHRhbWJpZW4gZW4gdmlzdWFsIiksCiAgICAgICAgICJMaWJlcmFyIHVuIHNvbG8gcGFyYW1ldHJvIG1lam9yYSBlbCBhanVzdGUgZGUgZm9ybWEgc2lnbmlmaWNhdGl2YSIpCmBgYAoKTGEgZGlmZXJlbmNpYSBkZSBjaGktY3VhZHJhZGEgZXMgc2lnbmlmaWNhdGl2YSBjb24gdW4gc29sbyBncmFkbyBkZSBsaWJlcnRhZDogbGliZXJhcgpgdmlzdWFsID1+IHg5YCBtZWpvcmEgZWwgYWp1c3RlIGRlIGZvcm1hIHJlYWwsIG5vIG1hcmdpbmFsLiBMYSBjb3ZhcmlhbnphIHJlc2lkdWFsCmB4NyB+fiB4OWAsIGVuIGNhbWJpbywgY2FzaSBubyBtdWV2ZSBuYWRhIChDRkkgYHIgcm91bmQoZml0TWVhc3VyZXMoZml0X2hzMywiY2ZpIiksMylgKSwKbG8gY3VhbCBjb25maXJtYSBxdWUgZWwgcHJvYmxlbWEgbm8gZXMgcnVpZG8gY29tcGFydGlkbyBlbnRyZSBkb3MgcHJ1ZWJhcyBkZSB2ZWxvY2lkYWQKc2lubyBxdWUgKip4OSBtaWRlIGRvcyBjb3NhcyBhIGxhIHZleioqLgoKIyMgSG9uZXN0aWRhZCBzb2JyZSBsYSBkZXB1cmFjaW9uOiB2YWxpZGFybGEgZW4gdW5hIG11ZXN0cmEgcXVlIG5vIGxhIHN1Z2lyaW8KCkFxdWkgZXN0YSBlbCByaWVzZ28gZGVsIHF1ZSBjYXNpIG51bmNhIHNlIGhhYmxhLiBVbiBpbmRpY2UgZGUgbW9kaWZpY2FjaW9uIHNlIGNhbGN1bGEKKipzb2JyZSBsb3MgbWlzbW9zIGRhdG9zKiogcXVlIHNlIHZhbiBhIHVzYXIgcGFyYSBqdXpnYXIgZWwgbW9kZWxvIG1lam9yYWRvLiBTZWd1aXJsbyBlcywKZW4gZWwgbGltaXRlLCBhanVzdGFybGUgZWwgbW9kZWxvIGFsIHJ1aWRvIGRlIGVzdGEgbXVlc3RyYS4gTGEgdW5pY2EgZGVmZW5zYSByZWFsIGVzCnZlcmlmaWNhciBxdWUgZWwgaGFsbGF6Z28gc2UgcmVwaXRlIGVuIGRhdG9zIHF1ZSBubyBwYXJ0aWNpcGFyb24gZW4gbGEgZGVjaXNpb24uCgpMYSBiYXNlIHRyYWUgZG9zIGVzY3VlbGFzLiBVc28gdW5hIHBhcmEgZGVzY3VicmlyIHkgbGEgb3RyYSBwYXJhIGNvbmZpcm1hcjoKCmBgYHtyIGVqMS1jdn0KdmFsIDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseShsZXZlbHMoSG9semluZ2VyU3dpbmVmb3JkMTkzOSRzY2hvb2wpLCBmdW5jdGlvbihlc2MpIHsKICBzdWIgPC0gSG9semluZ2VyU3dpbmVmb3JkMTkzOVtIb2x6aW5nZXJTd2luZWZvcmQxOTM5JHNjaG9vbCA9PSBlc2MsIF0KICBhIDwtIGNmYShtb2RfaHMsICBkYXRhID0gc3ViKQogIGIgPC0gY2ZhKG1vZF9oczIsIGRhdGEgPSBzdWIpCiAgZGF0YS5mcmFtZShFc2N1ZWxhID0gZXNjLCBuID0gbnJvdyhzdWIpLAogICAgICAgICAgICAgQ0ZJX2Jhc2UgPSByb3VuZChmaXRNZWFzdXJlcyhhLCAiY2ZpIiksIDMpLAogICAgICAgICAgICAgQ0ZJX2RlcHVyYWRvID0gcm91bmQoZml0TWVhc3VyZXMoYiwgImNmaSIpLCAzKSwKICAgICAgICAgICAgIFJNU0VBX2Jhc2UgPSByb3VuZChmaXRNZWFzdXJlcyhhLCAicm1zZWEiKSwgMyksCiAgICAgICAgICAgICBSTVNFQV9kZXB1cmFkbyA9IHJvdW5kKGZpdE1lYXN1cmVzKGIsICJybXNlYSIpLCAzKSwKICAgICAgICAgICAgIGNhcmdhX3g5X3Zpc3VhbCA9IHJvdW5kKHN1YnNldChzdGFuZGFyZGl6ZWRTb2x1dGlvbihiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxocyA9PSAidmlzdWFsIiAmIHJocyA9PSAieDkiKSRlc3Quc3RkLCAzKSkKfSkpCmthYmxlKHZhbCwgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiTGEgY2FyZ2EgY3J1emFkYSBkZSB4OSBhcGFyZWNlIGVuIGxhcyBkb3MgZXNjdWVsYXMsIHBlcm8gbm8gY29uIGxhIG1pc21hIGZ1ZXJ6YSIpCmBgYAoKRWwgcmVzdWx0YWRvIHNlIHJlcGl0ZSBlbiBhbWJhcyBlc2N1ZWxhcywgYXNpIHF1ZSBubyBlcyB1biBhcnRlZmFjdG86IHg5IGNhcmdhIGVuIHZpc3VhbAplbiBsYXMgZG9zLiBQZXJvIGxhIG1hZ25pdHVkIGNhZSBkZSBgciB2YWwkY2FyZ2FfeDlfdmlzdWFsWzFdYCBlbiBHcmFudC1XaGl0ZSBhCmByIHZhbCRjYXJnYV94OV92aXN1YWxbMl1gIGVuIFBhc3RldXIsIHkgZW4gUGFzdGV1ciBlbCBtb2RlbG8gZGVwdXJhZG8gKipzaWd1ZSBzaW4KYWxjYW56YXIqKiBlbCBjcml0ZXJpbyAoQ0ZJIGByIHZhbCRDRklfZGVwdXJhZG9bMl1gLCBSTVNFQSBgciB2YWwkUk1TRUFfZGVwdXJhZG9bMl1gKS4KRXMgZGVjaXI6IGxhIGNvcnJlY2Npb24gZXMgcmVhbCwgcGVybyBlbCBtb2RlbG8gZGVwdXJhZG8gcXVlIHJlcG9ydG8gYXJyaWJhIHNlIHZlIG1lam9yCmRlIGxvIHF1ZSBlcyBwb3JxdWUgc2UgZXN0aW1vIGVuIGxhIG11ZXN0cmEgY29tcGxldGEsIGluY2x1eWVuZG8gbGEgZXNjdWVsYSBkb25kZSBlbAplZmVjdG8gZXMgZnVlcnRlLgoKIyMgQ29uY2x1c2lvbmVzIGRlbCBlamVyY2ljaW8gMQoKMS4gRWwgbW9kZWxvIHRlb3JpY28gZGUgdHJlcyBmYWN0b3JlcyBlcyAqKmRlZmVuZGlibGUgcGVybyBpbmNvbXBsZXRvKio6IGFqdXN0YSBkZSBmb3JtYQogICBhY2VwdGFibGUgKENGSSBgciByb3VuZChmaXRNZWFzdXJlcyhmaXRfaHMsImNmaSIpLDMpYCkgeSBubyBidWVuYS4KMi4gTGEgY2F1c2EgZXMgdW5hICoqdmFyaWFibGUgcXVlIG1pZGUgZG9zIGNvbnN0cnVjdG9zKiouIHg5IHBlcnRlbmVjZSBhIHZlbG9jaWRhZCBwb3Igc3UKICAgZm9ybWF0byB5IGEgdmlzdWFsIHBvciBzdSBjb250ZW5pZG8uIEVzIHVuIHByb2JsZW1hIGRlIGRpc2VubyBkZWwgaW5zdHJ1bWVudG8sIG5vIGRlCiAgIGVzdGltYWNpb24uCjMuIERlcHVyYXIgZ3VpYWRvIHBvciBpbmRpY2VzIGRlIG1vZGlmaWNhY2lvbiBmdW5jaW9uYSwgcGVybyAqKmVsIGFqdXN0ZSBxdWUgcmVzdWx0YSBlc3RhCiAgIGluZmxhZG8qKiBwb3IgaGFiZXIgdXNhZG8gbG9zIG1pc21vcyBkYXRvcyBwYXJhIGRlc2N1YnJpciB5IHBhcmEgZXZhbHVhci4gTGEgdmFsaWRhY2lvbgogICBlbnRyZSBlc2N1ZWxhcyBsbyBkZW11ZXN0cmEuCjQuIFJlZ2xhIHF1ZSBtZSBsbGV2bzogc29sbyBsaWJlcm8gdW4gcGFyYW1ldHJvIHNpIHB1ZWRvIGV4cGxpY2FybG8gYW50ZXMgZGUgdmVybG8gZW4gbGEKICAgdGFibGEgZGUgTUkuIGB2aXN1YWwgPX4geDlgIHBhc2EgZXNhIHBydWViYTsgYHg3IH5+IHg5YCBubywgeSBhZGVtYXMgbm8gc2VydmlhLgoKIyBFamVyY2ljaW8gMjogZGVtb2NyYWNpYSBwb2xpdGljYSBlIGluZHVzdHJpYWxpemFjaW9uIChCb2xsZW4pCgojIyBFbCBtb2RlbG8gb2J2aW8gYWp1c3RhIG1hbCwgeSBsYSByYXpvbiBlcyBxdWUgaWdub3JhIHF1ZSBzb24gbGFzIG1pc21hcyBwcmVndW50YXMgZG9zIHZlY2VzCgpMYSBiYXNlIGRlIEJvbGxlbiBzaWd1ZSBhIDc1IHBhaXNlcyBlbiBkZXNhcnJvbGxvLiBgaW5kNjBgIGVzIGluZHVzdHJpYWxpemFjaW9uIGVuIDE5NjAKKHgxLS14Myk7IGBkZW02MGAgeSBgZGVtNjVgIHNvbiBkZW1vY3JhY2lhIHBvbGl0aWNhIGVuIDE5NjAgeSAxOTY1LCBtZWRpZGFzIGNvbiAqKmxvcwptaXNtb3MgY3VhdHJvIGluZGljYWRvcmVzKiogKHkxLS15NCB5IHk1LS15OCByZXNwZWN0aXZhbWVudGUpLiBMYSBoaXBvdGVzaXMgZXMgcXVlIGxhCmluZHVzdHJpYWxpemFjaW9uIGltcHVsc2EgbGEgZGVtb2NyYWNpYSwgZW4gcGFydGUgZGUgZm9ybWEgZGlyZWN0YSB5IGVuIHBhcnRlIGEgdHJhdmVzIGRlCmxhIGRlbW9jcmFjaWEgcHJldmlhLgoKYGBge3IgZWoyLWJhc2V9Cm1vZF9wZCA8LSAnCiAgaW5kNjAgPX4geDEgKyB4MiArIHgzCiAgZGVtNjAgPX4geTEgKyB5MiArIHkzICsgeTQKICBkZW02NSA9fiB5NSArIHk2ICsgeTcgKyB5OAogIGRlbTYwIH4gaW5kNjAKICBkZW02NSB+IGluZDYwICsgZGVtNjAgJwpmaXRfcGQgPC0gY2ZhKG1vZF9wZCwgZGF0YSA9IFBvbGl0aWNhbERlbW9jcmFjeSkKa2FibGUodGFibGFfYWp1c3RlKGZpdF9wZCwgZXRpcXVldGFzID0gInNpbiBlcnJvcmVzIGNvcnJlbGFjaW9uYWRvcyIpLAogICAgICBjYXB0aW9uID0gIlJNU0VBIGRlIC4xMDE6IGVsIG1vZGVsbyBkZWphIGFsZ28gaW1wb3J0YW50ZSBmdWVyYSIpCmBgYAoKYGBge3IgZWoyLW1pLCBlY2hvPUZBTFNFfQprYWJsZShoZWFkKG1vZGluZGljZXMoZml0X3BkLCBzb3J0LiA9IFRSVUUpWywgYygibGhzIiwib3AiLCJyaHMiLCJtaSIsImVwYyIpXSwgNiksCiAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLCBkaWdpdHMgPSAzLAogICAgICBjYXB0aW9uID0gIlRvZG9zIGxvcyBpbmRpY2VzIGFsdG9zIHNvbiBjb3ZhcmlhbnphcyBlbnRyZSBlcnJvcmVzIGRlIHkiKQpgYGAKCkxvcyBzZWlzIGluZGljZXMgbWFzIGdyYW5kZXMgc29uICoqY292YXJpYW56YXMgZW50cmUgcmVzaWR1YWxlcyBkZSBsb3MgaW5kaWNhZG9yZXMgeSoqLCB5Cm5pbmd1bm8gaW52b2x1Y3JhIGEgbGFzIHguIEVzbyBubyBlcyBjYXN1YWxpZGFkLiBFbCBpbmRpY2Fkb3IgeTEgKGxpYmVydGFkIGRlIHByZW5zYSBlbgoxOTYwKSB5IGVsIHk1IChsaWJlcnRhZCBkZSBwcmVuc2EgZW4gMTk2NSkgc29uICpsYSBtaXNtYSBwcmVndW50YSBhcGxpY2FkYSBjaW5jbyBhbmlvcwpkZXNwdWVzKjogY29tcGFydGVuIG5vIHNvbG8gZWwgY29uc3RydWN0byBkZW1vY3JhY2lhLCBzaW5vIGxhIGZ1ZW50ZSwgZWwgc2VzZ28gZGVsCmNvZGlmaWNhZG9yIHkgbGEgaWRpb3NpbmNyYXNpYSBkZWwgcGFpcy4gRXNhIHZhcmlhbnphIGNvbXBhcnRpZGEgZXMgKiptZXRvZG8qKiwgbm8KY29uc3RydWN0bywgeSBzaSBubyBzZSBtb2RlbGEgc2UgYWN1bXVsYSBlbiBlbCByZXNpZHVhbCBkZWwgc2lzdGVtYS4KCiMjIEVsIG1vZGVsbyBjb3JyZWN0bzogZGVqYXIgcXVlIGxvcyBlcnJvcmVzIGRlbCBtaXNtbyBpbmRpY2Fkb3Igc2UgY29ycmVsYWNpb25lbiBlbiBlbCB0aWVtcG8KCmBgYHtyIGVqMi1jb3JyfQptb2RfcGQyIDwtICcKICBpbmQ2MCA9fiB4MSArIHgyICsgeDMKICBkZW02MCA9fiB5MSArIHkyICsgeTMgKyB5NAogIGRlbTY1ID1+IHk1ICsgeTYgKyB5NyArIHk4CiAgZGVtNjAgfiBhKmluZDYwCiAgZGVtNjUgfiBjKmluZDYwICsgYipkZW02MAogICMgZXJyb3JlcyBhdXRvY29ycmVsYWNpb25hZG9zOiBtaXNtbyBpbmRpY2Fkb3IgbWVkaWRvIGVuIDE5NjAgeSBlbiAxOTY1CiAgeTEgfn4geTUKICB5MiB+fiB5NCArIHk2CiAgeTMgfn4geTcKICB5NCB+fiB5OAogIHk2IH5+IHk4CiAgIyBkZXNjb21wb3NpY2lvbiBkZWwgZWZlY3RvIGRlIGxhIGluZHVzdHJpYWxpemFjaW9uIHNvYnJlIGxhIGRlbW9jcmFjaWEgZGUgMTk2NQogIGluZGlyZWN0byA6PSBhKmIKICB0b3RhbCAgICAgOj0gYyArIGEqYiAnCmZpdF9wZDIgPC0gc2VtKG1vZF9wZDIsIGRhdGEgPSBQb2xpdGljYWxEZW1vY3JhY3kpCmthYmxlKHRhYmxhX2FqdXN0ZShmaXRfcGQsIGZpdF9wZDIsCiAgICAgIGV0aXF1ZXRhcyA9IGMoInNpbiBlcnJvcmVzIGNvcnJlbGFjaW9uYWRvcyIsICJjb24gZXJyb3JlcyBjb3JyZWxhY2lvbmFkb3MiKSksCiAgICAgIGNhcHRpb24gPSAiRWwgYWp1c3RlIHBhc2EgZGUgZHVkb3NvIGEgbXV5IGJ1ZW5vIGNvbiBzZWlzIHBhcmFtZXRyb3MgcXVlIGxhIHRlb3JpYSBkZSBtZWRpY2lvbiBleGlnZSIpCmBgYAoKYGBge3IgZWoyLWFub3ZhfQpjb21wYXJhcihmaXRfcGQsIGZpdF9wZDIsCiAgICAgICAgIGMoInNpbiBlcnJvcmVzIGNvcnJlbGFjaW9uYWRvcyIsICJjb24gZXJyb3JlcyBjb3JyZWxhY2lvbmFkb3MiKSwKICAgICAgICAgIkxvcyBzZWlzIGVycm9yZXMgY29ycmVsYWNpb25hZG9zIG5vIHNvbiBvcGNpb25hbGVzOiBzdSBvbWlzaW9uIGVzIHJlY2hhemFkYSIpCmBgYAoKIyMgRWZlY3RvcyBkaXJlY3RvLCBpbmRpcmVjdG8geSB0b3RhbAoKYGBge3IgZWoyLWVmZWN0b3N9CmVmIDwtIHBhcmFtZXRlckVzdGltYXRlcyhmaXRfcGQyLCBzdGFuZGFyZGl6ZWQgPSBUUlVFKQplZiA8LSBzdWJzZXQoZWYsIG9wICVpbiUgYygifiIsICI6PSIpKVssIGMoImxocyIsInJocyIsImxhYmVsIiwiZXN0Iiwic2UiLCJwdmFsdWUiLCJzdGQuYWxsIildCm5hbWVzKGVmKSA8LSBjKCJEZXN0aW5vIiwiT3JpZ2VuIiwiRXRpcXVldGEiLCJFc3RpbWFkbyIsIkVFIiwicCIsIkVzdGFuZGFyaXphZG8iKQprYWJsZShlZiwgcm93Lm5hbWVzID0gRkFMU0UsIGRpZ2l0cyA9IDMsCiAgICAgIGNhcHRpb24gPSAiRWwgZ3J1ZXNvIGRlbCBlZmVjdG8gZGUgbGEgaW5kdXN0cmlhbGl6YWNpb24gc29icmUgbGEgZGVtb2NyYWNpYSBkZSAxOTY1IGVzIGluZGlyZWN0byIpCmBgYAoKYGBge3IgZWoyLWxlY3R1cmEsIGVjaG89RkFMU0V9CmUgPC0gZnVuY3Rpb24obCkgZWYkRXN0YW5kYXJpemFkb1ttYXRjaChsLCBlZiRFdGlxdWV0YSldCmBgYAoKTGEgbGVjdHVyYSBzdXN0YW50aXZhOiBkZSB1biBlZmVjdG8gdG90YWwgZXN0YW5kYXJpemFkbyBkZSBgciByb3VuZChlKCJ0b3RhbCIpLDMpYCwKbGEgcGFydGUgaW5kaXJlY3RhIChgciByb3VuZChlKCJpbmRpcmVjdG8iKSwzKWApIGVzICoqYHIgcm91bmQoMTAwKmUoImluZGlyZWN0byIpL2UoInRvdGFsIikpYCUqKgpkZWwgdG90YWwuIExhIGluZHVzdHJpYWxpemFjaW9uIGRlIDE5NjAgbm8gcHJvZHVjZSBkZW1vY3JhY2lhIGVuIDE5NjUgcG9yIHNpIHNvbGE6IGxhCnByb2R1Y2Ugc29icmUgdG9kbyBwb3JxdWUgeWEgaGFiaWEgcHJvZHVjaWRvIGRlbW9jcmFjaWEgZW4gMTk2MCwgeSBsYSBkZW1vY3JhY2lhIGVzCmFsdGFtZW50ZSBwZXJzaXN0ZW50ZSAoYGJgIGVzdGFuZGFyaXphZG8gPSBgciByb3VuZChlKCJiIiksMylgLCBjYXNpIHVuIHRlY2hvKS4KCiMjIENvbmNsdXNpb25lcyBkZWwgZWplcmNpY2lvIDIKCjEuIEVsIG1hbCBhanVzdGUgaW5pY2lhbCAqKm5vIGVyYSBkZWwgbW9kZWxvIGVzdHJ1Y3R1cmFsKiosIGVyYSBkZWwgbW9kZWxvIGRlIG1lZGljaW9uLgogICBMYXMgZmxlY2hhcyBlbnRyZSBsYXRlbnRlcyBlc3RhYmFuIGJpZW47IGxvIHF1ZSBmYWx0YWJhIGVyYSByZWNvbm9jZXIgcXVlIGVsIG1pc21vCiAgIGluZGljYWRvciBtZWRpZG8gZG9zIHZlY2VzIGFycmFzdHJhIHN1IHByb3BpbyBlcnJvci4KMi4gTG9zIHNlaXMgcGFyYW1ldHJvcyBxdWUgYWdyZWd1ZSBubyBzZSBqdXN0aWZpY2FuIHBvciBzdSBNSSBzaW5vIHBvciAqKmVsIGRpc2VubyBkZWwKICAgZXN0dWRpbyoqOiBzb24gZGF0b3MgbG9uZ2l0dWRpbmFsZXMgY29uIGluZGljYWRvcmVzIHJlcGV0aWRvcy4gRXNlIGVzIGVsIGNhc28gZG9uZGUKICAgbGliZXJhciBjb3ZhcmlhbnphcyByZXNpZHVhbGVzIGVzIG9ibGlnYXRvcmlvLCBubyBvcG9ydHVuaXN0YS4KMy4gTGEgZGVzY29tcG9zaWNpb24gZGlyZWN0byAvIGluZGlyZWN0byBjYW1iaWEgbGEgY29uY2x1c2lvbiBkZSBwb2xpdGljYSBwdWJsaWNhOgogICBpbmR1c3RyaWFsaXphciBob3kgdGllbmUgZWZlY3RvIHNvYnJlIGxhIGRlbW9jcmFjaWEgZnV0dXJhIHByaW5jaXBhbG1lbnRlICoqYSB0cmF2ZXMKICAgZGUgbGEgZGVtb2NyYWNpYSBwcmVzZW50ZSoqLCBlcyBkZWNpciwgaGF5IGRlcGVuZGVuY2lhIGRlIGxhIHRyYXllY3RvcmlhLgoKIyBFamVyY2ljaW8gMzogYmllbmVzdGFyIGRlIGxvcyBjb2xhYm9yYWRvcmVzCgpgYGB7ciBlajMtZGF0b3N9CmQgPC0gcmVhZC5jc3YoImRhdG9zL2RhdG9zX3NlbS5jc3YiKQpjKG9ic2VydmFjaW9uZXMgPSBucm93KGQpLCB2YXJpYWJsZXMgPSBuY29sKGQpLCB2YWxvcmVzX2ZhbHRhbnRlcyA9IHN1bShpcy5uYShkKSkpCmBgYAoKTGEgYmFzZSB0aWVuZSBgciBucm93KGQpYCBjb2xhYm9yYWRvcmVzLCBzaW4gdmFsb3JlcyBmYWx0YW50ZXMuIExhcyBlc2NhbGFzIGRlCnJlY3VwZXJhY2lvbiB5IGVuZXJnaWEgdmFuIGRlIDEgYSA3IHkgbGEgZGUgZW5nYWdlbWVudCBkZSAwIGEgNy4KCioqTm90YSBkZSB2ZXJpZmljYWNpb24uKiogTGEgZGVzY3JpcGNpb24gZGUgaW5zdHJ1bWVudG9zIG5vbWJyYSBsb3MgaXRlbXMgZGUgZW5lcmdpYQpyZWN1cGVyYWRhIGNvbW8gUkVHMDEtLVJFRzEwIHkgbWFyY2EgUkVHMDEsIFJFRzA5IHkgUkVHMTAgY29tbyBlbGltaW5hZG9zOyBsYSBiYXNlIGxvcwp0cmFlIGNvbW8gRU4wMS0tRU4wOCBzaW4gRU4wMy4gTGEgY29ycmVzcG9uZGVuY2lhIGV4YWN0YSBlbnRyZSBsYXMgZG9zIG51bWVyYWNpb25lcyBubwplc3RhIGRvY3VtZW50YWRhLCBhc2kgcXVlIHRyYWJham8gY29uIGxvcyBzaWV0ZSBpdGVtcyB0YWwgY29tbyB2aWVuZW4geSAqKm5vIGFzdW1vKiogcXVlCkVOMGsgc2VhIFJFRzBrLiBJZ3VhbCBjb252aWVuZSBjb25maXJtYXJsbyBjb24gZWwgcHJvZmVzb3IuIExhIG1pc21hIGhvamEgaW5kaWNhIHF1ZSBsYQplc2NhbGEgZGUgZW5nYWdlbWVudCBlcyAiTnVuY2EgPSAwLCBDYXNpIG51bmNhID0gMiwgLi4uIiAoc2luIGVsIDEpLCBwZXJvIGxhIGJhc2Ugc2kKY29udGllbmUgdW5vczsgbG8gdHJhdG8gY29tbyBlc2NhbGEgY29udGludWEgZGUgMCBhIDcuCgojIyBQYXJ0ZSAxOiBhbmFsaXNpcyBmYWN0b3JpYWwgY29uZmlybWF0b3JpbyBkZSBzZWd1bmRvIG9yZGVuIGRlIGxhcyBleHBlcmllbmNpYXMgZGUgcmVjdXBlcmFjaW9uCgojIyMgRWwgbW9kZWxvIGRlIHByaW1lciBvcmRlbiBjb24gbG9zIDMxIGl0ZW1zIG5vIHBhc2EKCkxhcyBleHBlcmllbmNpYXMgZGUgcmVjdXBlcmFjaW9uIHNlIG1pZGVuIGNvbiBjdWF0cm8gZG9taW5pb3M6IGRlc2FwZWdvIHBzaWNvbG9naWNvLApyZWxhamFjaW9uLCBtYWVzdHJpYSB5IGNvbnRyb2wgc29icmUgZWwgdGllbXBvIGxpYnJlLgoKYGBge3IgZWozLXAxLWl0ZW1zfQppdGVtc19yZWMgPC0gbGlzdCgKICBERVNBUEVHTyAgID0gZ3JlcCgiXlJQRCIsIG5hbWVzKGQpLCB2YWx1ZSA9IFRSVUUpLAogIFJFTEFKQUNJT04gPSBncmVwKCJeUlJFIiwgbmFtZXMoZCksIHZhbHVlID0gVFJVRSksCiAgTUFFU1RSSUEgICA9IGdyZXAoIl5STUEiLCBuYW1lcyhkKSwgdmFsdWUgPSBUUlVFKSwKICBDT05UUk9MICAgID0gZ3JlcCgiXlJDTyIsIG5hbWVzKGQpLCB2YWx1ZSA9IFRSVUUpKQpzYXBwbHkoaXRlbXNfcmVjLCBsZW5ndGgpCgojIGFybWEgbGEgc2ludGF4aXMgZGUgbGF2YWFuIGEgcGFydGlyIGRlIGxhIGxpc3RhIGRlIGl0ZW1zCnNpbnRheGlzIDwtIGZ1bmN0aW9uKGxpc3RhKSB7CiAgcGFzdGUobWFwcGx5KGZ1bmN0aW9uKG5vbWJyZSwgaXRzKSBwYXN0ZTAobm9tYnJlLCAiID1+ICIsIHBhc3RlKGl0cywgY29sbGFwc2UgPSAiICsgIikpLAogICAgICAgICAgICAgICBuYW1lcyhsaXN0YSksIGxpc3RhKSwgY29sbGFwc2UgPSAiXG4iKQp9CmZpdF9yMSA8LSBjZmEoc2ludGF4aXMoaXRlbXNfcmVjKSwgZGF0YSA9IGQsIGVzdGltYXRvciA9ICJNTFIiKQprYWJsZSh0YWJsYV9hanVzdGUoZml0X3IxLCBldGlxdWV0YXMgPSAiNCBmYWN0b3JlcywgMzEgaXRlbXMiKSwKICAgICAgY2FwdGlvbiA9ICJOaW5ndW4gY3JpdGVyaW8gc2UgY3VtcGxlOiBoYXkgcXVlIGRlcHVyYXIiKQpgYGAKCmBgYHtyIGVqMy1wMS1kaWFnLCBlY2hvPUZBTFNFfQptaV9yIDwtIG1vZGluZGljZXMoZml0X3IxLCBzb3J0LiA9IFRSVUUpCmthYmxlKGhlYWQobWlfclssIGMoImxocyIsIm9wIiwicmhzIiwibWkiLCJlcGMiLCJzZXBjLmFsbCIpXSwgOCksIHJvdy5uYW1lcyA9IEZBTFNFLAogICAgICBkaWdpdHMgPSAzLCBjYXB0aW9uID0gIkVsIGRpYWdub3N0aWNvOiBpdGVtcyBjYXNpIGlkZW50aWNvcyBlbnRyZSBzaSB5IHVuIGl0ZW0gcXVlIGNhcmdhIGVuIGVsIGZhY3RvciBlcXVpdm9jYWRvIikKYGBgCgpFbCBkaWFnbm9zdGljbyBlcyBjbGFybyB5IHRpZW5lIHNlbnRpZG8gbGV5ZW5kbyBsb3MgcmVhY3Rpdm9zOgoKLSBgUlBEMDYgfn4gUlBEMDhgIChNSSA9IGByIHJvdW5kKG1pX3IkbWlbMV0pYCk6ICJBIHByb3Bvc2l0byBubyBoaWNlLCBuaSByZXZpc2UgbmFkYSBkZQogIG1pIHRyYWJham8iIHkgIkNvbiB0b2RhIGludGVuY2lvbiBubyBoaWNlIG5hZGEgc29icmUgbWkgdHJhYmFqbyIgc29uICoqbGEgbWlzbWEgZnJhc2UqKi4KLSBgUlBEMDkgfn4gUlBEMTBgOiAiTG9ncmUgZGVzbGlnYXJtZSBkZSBtaXMgcmVzcG9uc2FiaWxpZGFkZXMgbGFib3JhbGVzIiB5ICJNZSBkZXNsaW5kZQogIGRlIG1pcyBhY3RpdmlkYWRlcyBsYWJvcmFsZXMiLCBpZ3VhbC4KLSBgQ09OVFJPTCA9fiBSTUEwNmA6ICJVdGlsaWNlIG1pIHRpZW1wbyBlbiBhY3RpdmlkYWRlcyBkaWZlcmVudGVzIiBoYWJsYSBkZSAqKmNvbW8KICBkaXNwb25nbyBkZSBtaSB0aWVtcG8qKiwgbm8gZGUgcmV0YXJtZSBhIGFwcmVuZGVyLiBFc3RhIGVuIGVsIGZhY3RvciBlcXVpdm9jYWRvLgoKRXN0byBubyBlcyBydWlkbyBlc3RhZGlzdGljbzogZXMgKipyZWR1bmRhbmNpYSBkZSByZWRhY2Npb24qKiBlbiBlbCBpbnN0cnVtZW50by4gRG9zIGl0ZW1zCnF1ZSBkaWNlbiBsbyBtaXNtbyBjb21wYXJ0ZW4gdmFyaWFuemEgcXVlIG5pbmd1biBmYWN0b3IgY29tdW4gcHVlZGUgZXhwbGljYXIsIHkgZWwgbW9kZWxvCmxvIHJlZ2lzdHJhIGNvbW8gZGVzYWp1c3RlLgoKIyMjIFVuYSByZWdsYSBkZSBkZXB1cmFjaW9uIGV4cGxpY2l0YSwgY29uIHBpc28gZGUgdHJlcyBpdGVtcyBwb3IgZmFjdG9yCgpEZXB1cmFyIGEgb2pvIGVzIGRvbmRlIHNlIGN1ZWxhIGVsIHNlc2dvLiBFc2NyaWJvIGxhIHJlZ2xhIGNvbW8gZnVuY2lvbiBwYXJhIHF1ZSBzZWEKYXVkaXRhYmxlIHkgcGFyYSBxdWUgZWwgb3JkZW4gZGUgZWxpbWluYWNpb24gbm8gZGVwZW5kYSBkZSBtaSBjcml0ZXJpbyBkZWwgbW9tZW50bzoKCmBgYHtyIGVqMy1wMS1yZWdsYX0KIyBSZWdsYSwgZW4gZXN0ZSBvcmRlbiBkZSBwcmlvcmlkYWQ6CiMgICAxLiBjYXJnYSBlc3RhbmRhcml6YWRhIDwgLjcwICAgICAgICAgICAgLT4gZWwgaXRlbSBubyBtaWRlIGVsIGZhY3RvcgojICAgMi4gY2FyZ2EgY3J1emFkYSBjb24gTUkgPiAyMCAgICAgICAgICAgIC0+IGVsIGl0ZW0gbWlkZSBvdHJvIGZhY3RvcgojICAgMy4gcmVzaWR1YWxlcyBjb3JyZWxhY2lvbmFkb3MgY29uIE1JPjIwIC0+IHJlZHVuZGFuY2lhOiBjYWUgZWwgZGUgbWVub3IgY2FyZ2EKIyBSZXN0cmljY2lvbiBkdXJhOiBuaW5ndW4gZmFjdG9yIHB1ZWRlIHF1ZWRhciBjb24gbWVub3MgZGUgMyBpdGVtcywgcG9ycXVlCiMgdW4gZmFjdG9yIGRlIDIgaW5kaWNhZG9yZXMgbm8gc2UgaWRlbnRpZmljYSBwb3Igc2kgc29sbyB5IGVsIGNvbnN0cnVjdG8gc2UgdmFjaWEuCmZhY3Rvcl9kZSA8LSBmdW5jdGlvbihsaXN0YSwgaXRlbSkgbmFtZXMobGlzdGEpW3NhcHBseShsaXN0YSwgZnVuY3Rpb24odikgaXRlbSAlaW4lIHYpXVsxXQpwcm90ZWdpZG8gPC0gZnVuY3Rpb24obGlzdGEsIGl0ZW0sIG1pbl9pdGVtcykgbGVuZ3RoKGxpc3RhW1tmYWN0b3JfZGUobGlzdGEsIGl0ZW0pXV0pIDw9IG1pbl9pdGVtcwoKZGVwdXJhciA8LSBmdW5jdGlvbihsaXN0YSwgZGF0b3MsIG1heF9pdGVyID0gMTUsIG1pbl9pdGVtcyA9IDMsCiAgICAgICAgICAgICAgICAgICAgY29ydGUgPSBjKGNmaSA9IC45NSwgcm1zZWEgPSAuMDYsIHNybXIgPSAuMDgpKSB7CiAgdHJhemEgPC0gTlVMTAogIGZvciAoayBpbiAwOm1heF9pdGVyKSB7CiAgICBmaXQgPC0gY2ZhKHNpbnRheGlzKGxpc3RhKSwgZGF0YSA9IGRhdG9zLCBlc3RpbWF0b3IgPSAiTUxSIikKICAgIGZtICA8LSBmaXRNZWFzdXJlcyhmaXQsIElEWCkKICAgIGZpbGEgPC0gZGF0YS5mcmFtZShwYXNvID0gaywgaXRlbXMgPSBzdW0obGVuZ3RocyhsaXN0YSkpLAogICAgICAgICAgICAgICAgICAgICAgIGNoaXNxID0gcm91bmQoZm1bWyJjaGlzcSJdXSwgMSksIGdsID0gZm1bWyJkZiJdXSwKICAgICAgICAgICAgICAgICAgICAgICBDRkkgPSByb3VuZChmbVtbImNmaSJdXSwgMyksIFRMSSA9IHJvdW5kKGZtW1sidGxpIl1dLCAzKSwKICAgICAgICAgICAgICAgICAgICAgICBSTVNFQSA9IHJvdW5kKGZtW1sicm1zZWEiXV0sIDMpLCBTUk1SID0gcm91bmQoZm1bWyJzcm1yIl1dLCAzKSwKICAgICAgICAgICAgICAgICAgICAgICBlbGltaW5hZG8gPSBOQV9jaGFyYWN0ZXJfLCBtb3Rpdm8gPSBOQV9jaGFyYWN0ZXJfKQogICAgaWYgKGZtW1siY2ZpIl1dID49IGNvcnRlWyJjZmkiXSAmJiBmbVtbInJtc2VhIl1dIDw9IGNvcnRlWyJybXNlYSJdICYmCiAgICAgICAgZm1bWyJzcm1yIl1dIDw9IGNvcnRlWyJzcm1yIl0pIHsgdHJhemEgPC0gcmJpbmQodHJhemEsIGZpbGEpOyBicmVhayB9CgogICAgbGQgPC0gc3Vic2V0KHN0YW5kYXJkaXplZFNvbHV0aW9uKGZpdCksIG9wID09ICI9fiIpCiAgICBtaSA8LSBtb2RpbmRpY2VzKGZpdCkKICAgIGNhbmQgPC0gTkFfY2hhcmFjdGVyXzsgbW90aXZvIDwtIE5BX2NoYXJhY3Rlcl8KCiAgICBiYWphIDwtIGxkW29yZGVyKGxkJGVzdC5zdGQpLCBdCiAgICBiYWphIDwtIGJhamFbYmFqYSRlc3Quc3RkIDwgLjcwICYgIXNhcHBseShiYWphJHJocywgcHJvdGVnaWRvLCBsaXN0YSA9IGxpc3RhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX2l0ZW1zID0gbWluX2l0ZW1zKSwgXQogICAgaWYgKG5yb3coYmFqYSkgPiAwKSB7CiAgICAgIGNhbmQgPC0gYmFqYSRyaHNbMV07IG1vdGl2byA8LSBzcHJpbnRmKCJjYXJnYSAlLjJmIDwgLjcwIiwgYmFqYSRlc3Quc3RkWzFdKQogICAgfQogICAgaWYgKGlzLm5hKGNhbmQpKSB7CiAgICAgIGNjIDwtIHN1YnNldChtaSwgb3AgPT0gIj1+IiAmIG1pID4gMjApOyBjYyA8LSBjY1tvcmRlcigtY2MkbWkpLCBdCiAgICAgIGNjIDwtIGNjWyFzYXBwbHkoY2MkcmhzLCBwcm90ZWdpZG8sIGxpc3RhID0gbGlzdGEsIG1pbl9pdGVtcyA9IG1pbl9pdGVtcyksIF0KICAgICAgaWYgKG5yb3coY2MpID4gMCkgewogICAgICAgIGNhbmQgPC0gY2MkcmhzWzFdOyBtb3Rpdm8gPC0gc3ByaW50ZigiY2FyZ2EgY3J1emFkYSBlbiAlcyAoTUk9JS4wZikiLCBjYyRsaHNbMV0sIGNjJG1pWzFdKQogICAgICB9CiAgICB9CiAgICBpZiAoaXMubmEoY2FuZCkpIHsKICAgICAgcnIgPC0gc3Vic2V0KG1pLCBvcCA9PSAifn4iICYgbGhzICE9IHJocyAmIG1pID4gMjApOyByciA8LSBycltvcmRlcigtcnIkbWkpLCBdCiAgICAgIGZvciAoaSBpbiBzZXFfbGVuKG5yb3cocnIpKSkgewogICAgICAgIHBhciA8LSBjKHJyJGxoc1tpXSwgcnIkcmhzW2ldKQogICAgICAgIHBhciA8LSBwYXJbb3JkZXIobGQkZXN0LnN0ZFttYXRjaChwYXIsIGxkJHJocyldKV0gICAjIHByaW1lcm8gZWwgZGUgbWVub3IgY2FyZ2EKICAgICAgICBsaWJyZSA8LSBwYXJbIXNhcHBseShwYXIsIHByb3RlZ2lkbywgbGlzdGEgPSBsaXN0YSwgbWluX2l0ZW1zID0gbWluX2l0ZW1zKV0KICAgICAgICBpZiAobGVuZ3RoKGxpYnJlKSA+IDApIHsKICAgICAgICAgIGNhbmQgPC0gbGlicmVbMV0KICAgICAgICAgIG1vdGl2byA8LSBzcHJpbnRmKCJyZWR1bmRhbnRlIGNvbiAlcyAoTUk9JS4wZikiLCBzZXRkaWZmKHBhciwgY2FuZCksIHJyJG1pW2ldKQogICAgICAgICAgYnJlYWsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmIChpcy5uYShjYW5kKSkgewogICAgICBmaWxhJG1vdGl2byA8LSAic2luIGNhbmRpZGF0b3MgZWxlZ2libGVzOiBzZSBkZXRpZW5lIgogICAgICB0cmF6YSA8LSByYmluZCh0cmF6YSwgZmlsYSk7IGJyZWFrCiAgICB9CiAgICBmaWxhJGVsaW1pbmFkbyA8LSBjYW5kOyBmaWxhJG1vdGl2byA8LSBtb3Rpdm8KICAgIHRyYXphIDwtIHJiaW5kKHRyYXphLCBmaWxhKQogICAgbGlzdGFbW2ZhY3Rvcl9kZShsaXN0YSwgY2FuZCldXSA8LSBzZXRkaWZmKGxpc3RhW1tmYWN0b3JfZGUobGlzdGEsIGNhbmQpXV0sIGNhbmQpCiAgfQogIGxpc3QoaXRlbXMgPSBsaXN0YSwgdHJhemEgPSB0cmF6YSwgZml0ID0gZml0KQp9CmBgYAoKYGBge3IgZWozLXAxLWRlcH0KZGVwX3JlYyA8LSBkZXB1cmFyKGl0ZW1zX3JlYywgZCkKa2FibGUoZGVwX3JlYyR0cmF6YSwgcm93Lm5hbWVzID0gRkFMU0UsCiAgICAgIGNhcHRpb24gPSAiVHJhemEgY29tcGxldGEgZGUgbGEgZGVwdXJhY2lvbjogcXVlIHNlIGVsaW1pbm8sIGVuIHF1ZSBwYXNvIHkgcG9yIHF1ZSIpCmBgYAoKYGBge3IgZWozLXAxLWZpbmFsLCBlY2hvPUZBTFNFfQplbGltaW5hZG9zIDwtIHNldGRpZmYodW5saXN0KGl0ZW1zX3JlYyksIHVubGlzdChkZXBfcmVjJGl0ZW1zKSkKa2FibGUoZGF0YS5mcmFtZShGYWN0b3IgPSBuYW1lcyhkZXBfcmVjJGl0ZW1zKSwKICAgICAgICAgICAgICAgICBJdGVtc19maW5hbGVzID0gc2FwcGx5KGRlcF9yZWMkaXRlbXMsIGxlbmd0aCksCiAgICAgICAgICAgICAgICAgQ3VhbGVzID0gc2FwcGx5KGRlcF9yZWMkaXRlbXMsIHBhc3RlLCBjb2xsYXBzZSA9ICIsICIpKSwKICAgICAgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiSW5zdHJ1bWVudG8gZGVwdXJhZG8iKQpgYGAKCkRlIGByIHN1bShsZW5ndGhzKGl0ZW1zX3JlYykpYCBpdGVtcyBxdWVkYW4gYHIgc3VtKGxlbmd0aHMoZGVwX3JlYyRpdGVtcykpYC4gU2UgZWxpbWluYXJvbjoKYHIgcGFzdGUoZWxpbWluYWRvcywgY29sbGFwc2UgPSAiLCAiKWAuCgojIyMgTGEgZGVwdXJhY2lvbiByZWRlc2N1YnJlIGxvIHF1ZSBsb3MgYXV0b3JlcyBkZWwgaW5zdHJ1bWVudG8geWEgc2FiaWFuCgpFc3RlIGVzIGVsIGNvbnRyb2wgZGUgY2FsaWRhZCBxdWUgbGUgZGEgY3JlZGliaWxpZGFkIGFsIHByb2NlZGltaWVudG8uIExhIGhvamEgZGUKaW5zdHJ1bWVudG9zIG1hcmNhIGNvbW8gKihlbGltaW5hdGVkKSogdmFyaW9zIGl0ZW1zIHF1ZSAqKnNpbiBlbWJhcmdvIHNpZ3VlbiBlbiBsYSBiYXNlKio6ClJQRDAxLCBSUEQwNiwgUk1BMDIgeSBSTUEwNi4gU2kgbWkgcmVnbGEgZXMgYnVlbmEsIGRlYmVyaWEgdm9sdmVyIGEgZW5jb250cmFybG9zIHNpbgpoYWJlcmxvcyB2aXN0bzoKCmBgYHtyIGVqMy1wMS1jb250cm9sLCBlY2hvPUZBTFNFfQptYXJjYWRvcyA8LSBjKCJSUEQwMSIsIlJQRDA2IiwiUk1BMDIiLCJSTUEwNiIpCmthYmxlKGRhdGEuZnJhbWUoSXRlbSA9IG1hcmNhZG9zLAogICAgICAgICAgICAgICAgIE1hcmNhZG9fcG9yX2xvc19hdXRvcmVzID0gImVsaW1pbmFkbyIsCiAgICAgICAgICAgICAgICAgTWlfcmVnbGEgPSBpZmVsc2UobWFyY2Fkb3MgJWluJSBlbGltaW5hZG9zLCAidGFtYmllbiBsbyBlbGltaW5hIiwgImxvIGNvbnNlcnZhIikpLAogICAgICByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgY2FwdGlvbiA9ICJDb2luY2lkZW5jaWEgZW50cmUgbGEgZGVwdXJhY2lvbiBjaWVnYSB5IGxhcyBlbGltaW5hY2lvbmVzIGRvY3VtZW50YWRhcyIpCmBgYAoKVHJlcyBkZSBjdWF0cm8gY29pbmNpZGVuLiBFbCB1bmljbyBxdWUgY29uc2Vydm8gZXMgUlBEMDEgKCJNZSBvbHZpZGUgZGVsIHRyYWJham8iKSwgcXVlIGVuCmVzdGEgbXVlc3RyYSBjYXJnYQpgciByb3VuZChzdWJzZXQoc3RhbmRhcmRpemVkU29sdXRpb24oZGVwX3JlYyRmaXQpLCByaHM9PSJSUEQwMSIpJGVzdC5zdGRbMV0sIDMpYAp5IG5vIHZpb2xhIG5pbmd1biBjcml0ZXJpby4gUXVlIHVuYSByZWdsYSBtZWNhbmljYSByZXByb2R1emNhIGRlY2lzaW9uZXMgcXVlIHNlIHRvbWFyb24KcG9yIGp1aWNpbyBkZSBleHBlcnRvcyBlcyBsYSBtZWpvciBldmlkZW5jaWEgZGUgcXVlIG5vIGVzdG95IHNvbG8gcGVyc2lndWllbmRvIGluZGljZXMuCgojIyMgRWwgbW9kZWxvIGRlIHNlZ3VuZG8gb3JkZW46IGxvcyBjdWF0cm8gZG9taW5pb3Mgc29uIGZhY2V0YXMgZGUgdW4gbWlzbW8gY29uc3RydWN0bwoKSGFzdGEgYXF1aSB0ZW5nbyBjdWF0cm8gZmFjdG9yZXMgY29ycmVsYWNpb25hZG9zLiBMYSBwcmVndW50YSBkZWwgZWplcmNpY2lvIGVzIHNpIGV4aXN0ZQp1biBmYWN0b3Igc3VwZXJpb3IsICoqZXhwZXJpZW5jaWFzIGRlIHJlY3VwZXJhY2lvbioqLCBxdWUgZXhwbGlxdWUgKnBvciBxdWUqIGVzb3MgY3VhdHJvCmNvcnJlbGFjaW9uYW4uIEVzIHVuYSBoaXBvdGVzaXMgbWFzIGZ1ZXJ0ZSB5IHBvciBsbyB0YW50byBtYXMgZmFjaWwgZGUgcmVmdXRhcjogZWwgbW9kZWxvCmRlIHNlZ3VuZG8gb3JkZW4gcmVwcm9kdWNlIGxhcyBzZWlzIGNvcnJlbGFjaW9uZXMgZW50cmUgZG9taW5pb3MgY29uIHNvbG8gY3VhdHJvIGNhcmdhcywKYXNpIHF1ZSBnYXN0YSBkb3MgZ3JhZG9zIGRlIGxpYmVydGFkIG1lbm9zLgoKYGBge3IgZWozLXAxLXNlZ30KbW9kX3NlZyA8LSBwYXN0ZShzaW50YXhpcyhkZXBfcmVjJGl0ZW1zKSwKICAgICAgICAgICAgICAgICAiXG4gUkVDVVBFUkFDSU9OID1+IERFU0FQRUdPICsgUkVMQUpBQ0lPTiArIE1BRVNUUklBICsgQ09OVFJPTCIpCmZpdF9zZWcgPC0gY2ZhKG1vZF9zZWcsIGRhdGEgPSBkLCBlc3RpbWF0b3IgPSAiTUxSIikKa2FibGUodGFibGFfYWp1c3RlKGRlcF9yZWMkZml0LCBmaXRfc2VnLAogICAgICBldGlxdWV0YXMgPSBjKCIxZXIgb3JkZW46IDQgZmFjdG9yZXMgY29ycmVsYWNpb25hZG9zIiwgIjJvIG9yZGVuOiBSRUNVUEVSQUNJT04iKSksCiAgICAgIGNhcHRpb24gPSAiRWwgZmFjdG9yIGRlIHNlZ3VuZG8gb3JkZW4gbm8gY3Vlc3RhIGFqdXN0ZSIpCmBgYAoKYGBge3IgZWozLXAxLWFub3ZhfQpjb21wYXJhcihkZXBfcmVjJGZpdCwgZml0X3NlZywKICAgICAgICAgYygiMWVyIG9yZGVuOiA0IGZhY3RvcmVzIGNvcnJlbGFjaW9uYWRvcyIsICIybyBvcmRlbjogUkVDVVBFUkFDSU9OIiksCiAgICAgICAgICJMYSBlc3RydWN0dXJhIGplcmFycXVpY2Egbm8gZW1wZW9yYSBlbCBtb2RlbG8gZGUgZm9ybWEgZGV0ZWN0YWJsZSIpCmBgYAoKYGBge3IgZWozLXAxLWNhcmdhczIsIGVjaG89RkFMU0V9CmMyIDwtIHN1YnNldChzdGFuZGFyZGl6ZWRTb2x1dGlvbihmaXRfc2VnKSwgbGhzID09ICJSRUNVUEVSQUNJT04iICYgb3AgPT0gIj1+IikKa2FibGUoYzJbLCBjKCJyaHMiLCJlc3Quc3RkIiwic2UiLCJwdmFsdWUiKV0sIHJvdy5uYW1lcyA9IEZBTFNFLCBkaWdpdHMgPSAzLAogICAgICBjb2wubmFtZXMgPSBjKCJEb21pbmlvIiwiQ2FyZ2EgZXN0YW5kYXJpemFkYSIsIkVFIiwicCIpLAogICAgICBjYXB0aW9uID0gIkNhcmdhcyBkZSBzZWd1bmRvIG9yZGVuOiBsb3MgY3VhdHJvIGRvbWluaW9zIHBlcnRlbmVjZW4gYWwgbWlzbW8gY29uc3RydWN0byIpCmBgYAoKTGEgZGlmZXJlbmNpYSBkZSBjaGktY3VhZHJhZGEgY29uIDIgZ3JhZG9zIGRlIGxpYmVydGFkICoqbm8gZXMgc2lnbmlmaWNhdGl2YSoqCihwID0gYHIgcm91bmQoc3VwcHJlc3NXYXJuaW5ncyhsYXZUZXN0TFJUKGZpdF9zZWcsIGRlcF9yZWMkZml0KSlbMiwiUHIoPkNoaXNxKSJdLCAzKWApOiBpbXBvbmVyIGxhIGVzdHJ1Y3R1cmEKamVyYXJxdWljYSBubyBlbXBlb3JhIGVsIG1vZGVsbyBkZSBmb3JtYSBkZXRlY3RhYmxlLiBMYXMgY3VhdHJvIGNhcmdhcyBzb24gc2lnbmlmaWNhdGl2YXMsCnBlcm8gZGVzaWd1YWxlczogcmVsYWphY2lvbiAoYHIgcm91bmQoYzIkZXN0LnN0ZFsyXSwzKWApIHkgY29udHJvbAooYHIgcm91bmQoYzIkZXN0LnN0ZFs0XSwzKWApIHNvbiBjYXNpIHNpbm9uaW1vcyBkZWwgY29uc3RydWN0byBnZW5lcmFsLCBtaWVudHJhcyBkZXNhcGVnbwooYHIgcm91bmQoYzIkZXN0LnN0ZFsxXSwzKWApIHkgbWFlc3RyaWEgKGByIHJvdW5kKGMyJGVzdC5zdGRbM10sMylgKSBjb25zZXJ2YW4gYmFzdGFudGUKaWRlbnRpZGFkIHByb3BpYS4gVHJhZHVjaWRvOiBxdWllbiBzZSByZWN1cGVyYSBiaWVuIGNhc2kgc2llbXByZSBzZSByZWxhamEgeSBjb250cm9sYSBzdQp0aWVtcG8sIHBlcm8gZGVzY29uZWN0YXJzZSBtZW50YWxtZW50ZSB5IGJ1c2NhciByZXRvcyBzb24gY29zYXMgcXVlICoqYWxndW5hcyBwZXJzb25hcwpoYWNlbiB5IG90cmFzIG5vKiosIGNvbiByZWxhdGl2YSBpbmRlcGVuZGVuY2lhIGRlIHN1IG5pdmVsIGdlbmVyYWwgZGUgcmVjdXBlcmFjaW9uLgoKIyMgUGFydGUgMjogYW5hbGlzaXMgZmFjdG9yaWFsIGNvbmZpcm1hdG9yaW8gZGVsIGNvbnN0cnVjdG8gZGUgZW5lcmdpYSByZWN1cGVyYWRhCgpgYGB7ciBlajMtcDJ9Cml0ZW1zX2VuIDwtIGdyZXAoIl5FTjAiLCBuYW1lcyhkKSwgdmFsdWUgPSBUUlVFKQpmaXRfZW4gPC0gY2ZhKHBhc3RlMCgiRU5FUkdJQSA9fiAiLCBwYXN0ZShpdGVtc19lbiwgY29sbGFwc2UgPSAiICsgIikpLAogICAgICAgICAgICAgIGRhdGEgPSBkLCBlc3RpbWF0b3IgPSAiTUxSIikKa2FibGUodGFibGFfYWp1c3RlKGZpdF9lbiwgZXRpcXVldGFzID0gIkVORVJHSUEgdW5pZGltZW5zaW9uYWwsIDcgaXRlbXMiKSwKICAgICAgY2FwdGlvbiA9ICJDRkksIFRMSSB5IFNSTVIgZXhjZWxlbnRlczsgUk1TRUEgZnVlcmEgZGUgY3JpdGVyaW8iKQprYWJsZShjYXJnYXMoZml0X2VuKSwgcm93Lm5hbWVzID0gRkFMU0UsIGRpZ2l0cyA9IDMsCiAgICAgIGNhcHRpb24gPSAiTGFzIHNpZXRlIGNhcmdhcyBwb3IgYXJyaWJhIGRlIC44OSIpCmBgYAoKTG9zIHNpZXRlIGl0ZW1zIHNlIGFncnVwYW4gZW4gKip1bmEgc29sYSBkaW1lbnNpb24qKiwgeSBkZSBmb3JtYSBjb250dW5kZW50ZTogbGEgY2FyZ2EgbWFzCmJhamEgZXMgYHIgcm91bmQobWluKGNhcmdhcyhmaXRfZW4pJENhcmdhX2VzdGFuZGFyaXphZGEpLDMpYCB5IGVsIFNSTVIgZXMKYHIgcm91bmQoZml0TWVhc3VyZXMoZml0X2VuLCJzcm1yIiksMylgLCBwcmFjdGljYW1lbnRlIGNlcm8uIExhIHJlc3B1ZXN0YSBhIGxhIHByZWd1bnRhCmRlbCBlamVyY2ljaW8gZXMgc2kuCgpFbCBSTVNFQSBkZSBgciByb3VuZChmaXRNZWFzdXJlcyhmaXRfZW4sInJtc2VhIiksMylgIHBhcmVjZSBjb250cmFkZWNpcmxvLiBObyBsbyBoYWNlLCB5CnZhbGUgbGEgcGVuYSBlbnRlbmRlciBwb3IgcXVlIGVuIGx1Z2FyIGRlICJhcnJlZ2xhcmxvIjoKCmBgYHtyIGVqMy1wMi1kZXB9CmRlcF9lbiA8LSBkZXB1cmFyKGxpc3QoRU5FUkdJQSA9IGl0ZW1zX2VuKSwgZCkKa2FibGUoZGVwX2VuJHRyYXphLCByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgY2FwdGlvbiA9ICJMYSByZWdsYSBkZSBkZXB1cmFjaW9uIG5vIGVuY3VlbnRyYSB1biBzb2xvIGl0ZW0gcXVlIGVsaW1pbmFyIikKYGBgCgpOaW5ndW4gaXRlbSB0aWVuZSBjYXJnYSBiYWphLCBuaW5ndW5vIGNhcmdhIGVuIG90cm8gZmFjdG9yLCB5IGVsIHJlc2lkdWFsIGNvcnJlbGFjaW9uYWRvCm1hcyBncmFuZGUgdGllbmUgTUkgZGUKYHIgcm91bmQobWF4KHN1YnNldChtb2RpbmRpY2VzKGZpdF9lbiksIG9wPT0ifn4iICYgbGhzIT1yaHMpJG1pKSwxKWAsIHBvciBkZWJham8gZGVsIHVtYnJhbC4KKipObyBoYXkgbmFkYSBxdWUgZGVwdXJhci4qKiBFbCBSTVNFQSBhbHRvIGVzIGNvbnNlY3VlbmNpYSBkZSBzdSBmb3JtdWxhOiBwZW5hbGl6YSBwb3IKZ3JhZG8gZGUgbGliZXJ0YWQsIHkgY29uIHNvbG8gYHIgZml0TWVhc3VyZXMoZml0X2VuLCJkZiIpYCBncmFkb3MgZGUgbGliZXJ0YWQgeSBjYXJnYXMgdGFuCmFsdGFzLCBjdWFscXVpZXIgZGlzY3JlcGFuY2lhIG1pbmltYSBzZSBhbXBsaWZpY2EuIEVzIGVsIHByb2JsZW1hIGNvbm9jaWRvIGRlIFJNU0VBIGVuCm1vZGVsb3MgcGVxdWVuaW9zIChLZW5ueSwgS2FuaXNrYW4geSBNY0NvYWNoLCAyMDE1KS4gRm9yemFyIGxhIG1lam9yYSBlbGltaW5hbmRvIGl0ZW1zCmJ1ZW5vcyBzZXJpYSBtYXF1aWxsYXIgZWwgaW5kaWNlIGEgY29zdGEgZGVsIGNvbnN0cnVjdG8uCgoqKkxvIHF1ZSBzaSBtZSBwcmVvY3VwYSoqIGVzIGxvIGNvbnRyYXJpbzogY2FyZ2FzIGRlIC44OSBhIC45NSBlbnRyZSBzaWV0ZSByZWFjdGl2b3MKc3VnaWVyZW4gcXVlIGVsIGluc3RydW1lbnRvIHByZWd1bnRhIGxvIG1pc21vIHNpZXRlIHZlY2VzICgibWUgc2llbnRvIHJlbm92YWRvIiwKIm1lIHNpZW50byBjb21vIG51ZXZvIiwgInJlY3VwZXJlIG1pIGVuZXJnaWEiKS4gTWlkZSBiaWVuLCBwZXJvIGVzIGluZWZpY2llbnRlOiB0cmVzIGl0ZW1zCnByb2JhYmxlbWVudGUgZGFyaWFuIGxhIG1pc21hIGluZm9ybWFjaW9uLgoKIyMgUGFydGUgMzogYW5hbGlzaXMgZGUgc2VuZGVyb3MgY29uIGxhIGVuZXJnaWEgcmVjdXBlcmFkYSBjb21vIG1lZGlhZG9yYQoKIyMjIENvbnN0cnVjY2lvbiBkZSBsb3MgY29tcHVlc3RvcwoKYGBge3IgZWozLXAzLWNvbXB9CmZvciAobm0gaW4gbmFtZXMoZGVwX3JlYyRpdGVtcykpIGRbW25tXV0gPC0gcm93TWVhbnMoZFssIGRlcF9yZWMkaXRlbXNbW25tXV1dKQpkJFJFQ1VQIDwtIHJvd01lYW5zKGRbLCBuYW1lcyhkZXBfcmVjJGl0ZW1zKV0pICAgIyBwcm9tZWRpbyBkZSBsb3MgNCBkb21pbmlvcwpkJEVORVIgIDwtIHJvd01lYW5zKGRbLCBpdGVtc19lbl0pCml0ZW1zX2VuZyA8LSBjKCJFVkkwMSIsIkVWSTAyIiwiRVZJMDMiLCJFREUwMSIsIkVERTAyIiwiRURFMDMiLCJFQUIwMSIsIkVBQjAyIiwiRUFCMDMiKQpkJEVOR0EgIDwtIHJvd01lYW5zKGRbLCBpdGVtc19lbmddKQprYWJsZShyb3VuZChjb3IoZFssIGMoIkRFU0FQRUdPIiwiUkVMQUpBQ0lPTiIsIk1BRVNUUklBIiwiQ09OVFJPTCIsIlJFQ1VQIiwiRU5FUiIsIkVOR0EiKV0pLCAyKSwKICAgICAgY2FwdGlvbiA9ICJNYXRyaXogZGUgY29ycmVsYWNpb25lcyBkZSBsb3MgY29tcHVlc3RvcyIpCmBgYAoKQ2FkYSBkb21pbmlvIHBlc2EgaWd1YWwgZW4gYFJFQ1VQYCAocHJvbWVkaW8gZGUgcHJvbWVkaW9zLCBubyBwcm9tZWRpbyBkZSBpdGVtcyksIHBhcmEgcXVlCmRlc2FwZWdvIGNvbiBzZWlzIGl0ZW1zIG5vIGRvbWluZSBhIHJlbGFqYWNpb24gY29uIHRyZXMuCgojIyMgUG9yIHF1ZSBlbCBtb2RlbG8gZGUgbWVkaWFjaW9uIHNpbXBsZSBubyBzZSBwdWVkZSBldmFsdWFyIHBvciBhanVzdGUKCmBgYHtyIGVqMy1wMy1zYXR9Cm1vZF9zYXQgPC0gJyBFTkVSIH4gYSpSRUNVUAogICAgICAgICAgICAgRU5HQSB+IGNwKlJFQ1VQICsgYipFTkVSCiAgICAgICAgICAgICBpbmRpcmVjdG8gOj0gYSpiCiAgICAgICAgICAgICB0b3RhbCAgICAgOj0gY3AgKyBhKmIgJwpmaXRfc2F0IDwtIHNlbShtb2Rfc2F0LCBkYXRhID0gZCwgc2UgPSAiYm9vdHN0cmFwIiwgYm9vdHN0cmFwID0gMTAwMCkKa2FibGUodGFibGFfYWp1c3RlKGZpdF9zYXQsIGV0aXF1ZXRhcyA9ICJtZWRpYWNpb24gcGFyY2lhbCAoMyB2YXJpYWJsZXMpIiksCiAgICAgIGNhcHRpb24gPSAiQWp1c3RlIHBlcmZlY3RvIHkgdmFjaW86IGVsIG1vZGVsbyBlc3RhIHNhdHVyYWRvIikKYGBgCgpFbCBlamVyY2ljaW8gcGlkZSByZXZpc2FyIGxvcyBpbmRpY2VzIGRlIGFqdXN0ZSwgeSBhcXVpIGxhIHJlc3B1ZXN0YSBjb3JyZWN0YSBlcyBxdWUKKipubyBkaWNlbiBuYWRhKiouIENvbiB0cmVzIHZhcmlhYmxlcyBvYnNlcnZhZGFzIGhheSA2IG1vbWVudG9zIHkgZWwgbW9kZWxvIGVzdGltYSA2CnBhcmFtZXRyb3M6IGNlcm8gZ3JhZG9zIGRlIGxpYmVydGFkLiBDRkkgPSAxIHkgUk1TRUEgPSAwIHNvbiBhcml0bWV0aWNhLCBubyBldmlkZW5jaWEuClVuIG1vZGVsbyBzYXR1cmFkbyByZXByb2R1Y2UgY3VhbHF1aWVyIG1hdHJpeiBkZSBjb3ZhcmlhbnphcywgaW5jbHVpZGEgdW5hIGdlbmVyYWRhIGFsCmF6YXIuCgpQYXJhIHF1ZSBlbCBhanVzdGUgc2lnbmlmaXF1ZSBhbGdvIGhheSBxdWUgKippbXBvbmVyIHVuYSByZXN0cmljY2lvbiBmYWxzYWJsZSoqLiBEb3MKY2FtaW5vcywgeSB0b21vIGxvcyBkb3MuCgojIyMgQ2FtaW5vIDE6IGxhIG1lZGlhY2lvbiBjb21wbGV0YSBjb21vIGhpcG90ZXNpcyBjb250cmFzdGFibGUKCmBgYHtyIGVqMy1wMy1jb21wMn0KbW9kX2Z1bGwgPC0gJyBFTkVSIH4gYSpSRUNVUAogICAgICAgICAgICAgIEVOR0EgfiBiKkVORVIKICAgICAgICAgICAgICBpbmRpcmVjdG8gOj0gYSpiICcKZml0X2Z1bGwgPC0gc2VtKG1vZF9mdWxsLCBkYXRhID0gZCkKa2FibGUodGFibGFfYWp1c3RlKGZpdF9mdWxsLCBmaXRfc2F0LAogICAgICBldGlxdWV0YXMgPSBjKCJtZWRpYWNpb24gY29tcGxldGEgKGdsPTEpIiwgIm1lZGlhY2lvbiBwYXJjaWFsIChnbD0wKSIpKSwKICAgICAgY2FwdGlvbiA9ICJBbCBmaWphciBlbCBjYW1pbm8gZGlyZWN0byBlbiBjZXJvLCBlbCBtb2RlbG8gcG9yIGZpbiBzZSBwdWVkZSByZWZ1dGFyIikKY29tcGFyYXIoZml0X2Z1bGwsIGZpdF9zYXQsCiAgICAgICAgIGMoIm1lZGlhY2lvbiBjb21wbGV0YSIsICJtZWRpYWNpb24gcGFyY2lhbCIpLAogICAgICAgICAiUHJ1ZWJhIGRlIGxhIHJlc3RyaWNjaW9uIGRlIG1lZGlhY2lvbiBjb21wbGV0YSAobWVkaWFjaW9uIHNpbXBsZSkiKQpgYGAKCiMjIyBDYW1pbm8gMjogYWJyaXIgbGEgcmVjdXBlcmFjaW9uIGVuIHN1cyBjdWF0cm8gZG9taW5pb3MKCmBgYHtyIGVqMy1wMy1kb219Cm1vZF9kb20gPC0gJyBFTkVSIH4gYTEqREVTQVBFR08gKyBhMipSRUxBSkFDSU9OICsgYTMqTUFFU1RSSUEgKyBhNCpDT05UUk9MCiAgICAgICAgICAgICBFTkdBIH4gYipFTkVSCiAgICAgICAgICAgICBpX2Rlc2FwZWdvICAgOj0gYTEqYgogICAgICAgICAgICAgaV9yZWxhamFjaW9uIDo9IGEyKmIKICAgICAgICAgICAgIGlfbWFlc3RyaWEgICA6PSBhMypiCiAgICAgICAgICAgICBpX2NvbnRyb2wgICAgOj0gYTQqYiAnCmZpdF9kb20gPC0gc2VtKG1vZF9kb20sIGRhdGEgPSBkLCBzZSA9ICJib290c3RyYXAiLCBib290c3RyYXAgPSAxMDAwKQoKbW9kX2RvbV9wIDwtICcgRU5FUiB+IGExKkRFU0FQRUdPICsgYTIqUkVMQUpBQ0lPTiArIGEzKk1BRVNUUklBICsgYTQqQ09OVFJPTAogICAgICAgICAgICAgICBFTkdBIH4gYipFTkVSICsgYzEqREVTQVBFR08gKyBjMipSRUxBSkFDSU9OICsgYzMqTUFFU1RSSUEgKyBjNCpDT05UUk9MICcKZml0X2RvbV9wIDwtIHNlbShtb2RfZG9tX3AsIGRhdGEgPSBkKQoKa2FibGUodGFibGFfYWp1c3RlKGZpdF9kb20sIGZpdF9kb21fcCwKICAgICAgZXRpcXVldGFzID0gYygibWVkaWFjaW9uIGNvbXBsZXRhIChnbD00KSIsICJtZWRpYWNpb24gcGFyY2lhbCAoc2F0dXJhZG8pIikpLAogICAgICBjYXB0aW9uID0gIkVsIG1vZGVsbyBkZSBtZWRpYWNpb24gY29tcGxldGEgYWp1c3RhIGNhc2kgcGVyZmVjdG8gY29uIDQgZ3JhZG9zIGRlIGxpYmVydGFkIikKY29tcGFyYXIoZml0X2RvbSwgZml0X2RvbV9wLAogICAgICAgICBjKCJtZWRpYWNpb24gY29tcGxldGEiLCAibWVkaWFjaW9uIHBhcmNpYWwiKSwKICAgICAgICAgIlF1aXRhciBsb3MgY3VhdHJvIGNhbWlub3MgZGlyZWN0b3Mgbm8gZW1wZW9yYSBlbCBtb2RlbG8iKQpgYGAKCkxhIGNoaS1jdWFkcmFkYSBkZSBgciByb3VuZChmaXRNZWFzdXJlcyhmaXRfZG9tLCJjaGlzcSIpLDIpYCBjb24gNCBncmFkb3MgZGUgbGliZXJ0YWQKKipubyBlcyBzaWduaWZpY2F0aXZhKiogKHAgPSBgciByb3VuZChmaXRNZWFzdXJlcyhmaXRfZG9tLCJwdmFsdWUiKSwzKWApLiBFbGltaW5hciBsb3MKY3VhdHJvIGNhbWlub3MgZGlyZWN0b3Mgbm8gZW1wZW9yYSBlbCBtb2RlbG8uIFkgZWwgbW9kZWxvIHNhdHVyYWRvIGV4cGxpY2EgcG9yIHF1ZToKCmBgYHtyIGVqMy1wMy1kaXJlY3RvcywgZWNobz1GQUxTRX0KcGQgPC0gc3Vic2V0KHBhcmFtZXRlckVzdGltYXRlcyhmaXRfZG9tX3AsIHN0YW5kYXJkaXplZCA9IFRSVUUpLCBvcCA9PSAifiIgJiBsaHMgPT0gIkVOR0EiKQprYWJsZShwZFssIGMoImxocyIsInJocyIsImVzdCIsInNlIiwicHZhbHVlIiwic3RkLmFsbCIpXSwgcm93Lm5hbWVzID0gRkFMU0UsIGRpZ2l0cyA9IDMsCiAgICAgIGNvbC5uYW1lcyA9IGMoIkRlc3Rpbm8iLCJPcmlnZW4iLCJFc3RpbWFkbyIsIkVFIiwicCIsIkVzdGFuZGFyaXphZG8iKSwKICAgICAgY2FwdGlvbiA9ICJOaW5ndW5vIGRlIGxvcyBjdWF0cm8gY2FtaW5vcyBkaXJlY3RvcyBoYWNpYSBlbmdhZ2VtZW50IGVzIHNpZ25pZmljYXRpdm8iKQpgYGAKCk5pbmd1bm8gZGUgbG9zIGN1YXRybyBkb21pbmlvcyBsbGVnYSBhbCBlbmdhZ2VtZW50IHBvciBzdSBjdWVudGEuICoqVG9kYSoqIGxhIHJlbGFjaW9uCnBhc2EgcG9yIGxhIGVuZXJnaWEgcmVjdXBlcmFkYS4KCiMjIyBFZmVjdG9zIGluZGlyZWN0b3MsIGNvbiBpbnRlcnZhbG9zIGJvb3RzdHJhcAoKYGBge3IgZWozLXAzLWVmZWN0b3N9CmVmMyA8LSBwYXJhbWV0ZXJFc3RpbWF0ZXMoZml0X2RvbSwgYm9vdC5jaS50eXBlID0gInBlcmMiLCBzdGFuZGFyZGl6ZWQgPSBUUlVFKQplZjMgPC0gc3Vic2V0KGVmMywgb3AgJWluJSBjKCJ+IiwgIjo9IikpWywgYygibGhzIiwicmhzIiwibGFiZWwiLCJlc3QiLCJzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwdmFsdWUiLCJjaS5sb3dlciIsImNpLnVwcGVyIiwic3RkLmFsbCIpXQprYWJsZShlZjMsIHJvdy5uYW1lcyA9IEZBTFNFLCBkaWdpdHMgPSAzLAogICAgICBjb2wubmFtZXMgPSBjKCJEZXN0aW5vIiwiT3JpZ2VuIiwiRXRpcXVldGEiLCJFc3QiLCJFRSIsInAiLCJJQyAyLjUlIiwiSUMgOTcuNSUiLCJFc3RhbmQuIiksCiAgICAgIGNhcHRpb24gPSAiRWZlY3RvcyBkZWwgbW9kZWxvIGRlIG1lZGlhY2lvbiBjb21wbGV0YSAoMTAwMCByZW11ZXN0cmVvcyBib290c3RyYXApIikKcjIgPC0gaW5zcGVjdChmaXRfZG9tLCAicjIiKQprYWJsZShkYXRhLmZyYW1lKFZhcmlhYmxlID0gbmFtZXMocjIpLCBSMiA9IHJvdW5kKGFzLm51bWVyaWMocjIpLCAzKSksCiAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLCBjYXB0aW9uID0gIlZhcmlhbnphIGV4cGxpY2FkYSIpCmBgYAoKRWwgcHJvZHVjdG8gZGUgY29lZmljaWVudGVzIG5vIHNlIGRpc3RyaWJ1eWUgbm9ybWFsLCBwb3IgZXNvIGVsIGludGVydmFsbyBib290c3RyYXAgeSBubwplbCBlcnJvciBlc3RhbmRhciBkZSBXYWxkLiBZIGxhIGRpZmVyZW5jaWEgaW1wb3J0YTogKipyZWxhamFjaW9uKiogdGllbmUgcCA9CmByIHJvdW5kKGVmMyRwdmFsdWVbZWYzJGxhYmVsPT0iaV9yZWxhamFjaW9uIl0sMylgIHBvciBXYWxkIHBlcm8gc3UgaW50ZXJ2YWxvIGJvb3RzdHJhcAooYHIgcm91bmQoZWYzJGNpLmxvd2VyW2VmMyRsYWJlbD09ImlfcmVsYWphY2lvbiJdLDMpYCBhCmByIHJvdW5kKGVmMyRjaS51cHBlcltlZjMkbGFiZWw9PSJpX3JlbGFqYWNpb24iXSwzKWApICoqaW5jbHV5ZSBlbCBjZXJvKiouIENvbiBlbApjcml0ZXJpbyBtYXMgZXhpZ2VudGUsIHF1ZSBlcyBlbCBjb3JyZWN0byBhcXVpLCBzdSBlZmVjdG8gbm8gZXN0YSBkZW1vc3RyYWRvLgoKT3JkZW4gZGUgaW1wb3J0YW5jaWEgcG9yIGVmZWN0byBpbmRpcmVjdG8gZXN0YW5kYXJpemFkbzoKCmBgYHtyIGVqMy1wMy1vcmRlbiwgZWNobz1GQUxTRX0KaW5kIDwtIGVmM1tzdGFydHNXaXRoKGVmMyRsYWJlbCwgImlfIiksIF0KaW5kIDwtIGluZFtvcmRlcigtaW5kJHN0ZC5hbGwpLCBjKCJsYWJlbCIsInN0ZC5hbGwiLCJjaS5sb3dlciIsImNpLnVwcGVyIildCmluZCRjb25jbHVzaW9uIDwtIGlmZWxzZShpbmQkY2kubG93ZXIgPiAwLCAiZWZlY3RvIHNvc3RlbmlkbyIsICJubyBkaXN0aW5ndWlibGUgZGUgY2VybyIpCmthYmxlKGluZCwgcm93Lm5hbWVzID0gRkFMU0UsIGRpZ2l0cyA9IDMsCiAgICAgIGNvbC5uYW1lcyA9IGMoIkRvbWluaW8iLCJFZmVjdG8gaW5kaXJlY3RvIGVzdGFuZC4iLCJJQyAyLjUlIiwiSUMgOTcuNSUiLCJDb25jbHVzaW9uIiksCiAgICAgIGNhcHRpb24gPSAiQ29udHJvbCBzb2JyZSBlbCB0aWVtcG8gbGlicmUgZXMsIHBvciBtdWNobywgZWwgZG9taW5pbyBxdWUgbWFzIHJpbmRlIikKYGBgCgojIyMgTGVjdHVyYSBwYXJhIGxhIG9yZ2FuaXphY2lvbgoKRWwgcmVzdWx0YWRvIHRpZW5lIHVuYSBpbXBsaWNhY2lvbiBwcmFjdGljYSBjb25jcmV0YSB5IGFsZ28gaW5jb21vZGEgcGFyYSBsYXMgYXJlYXMgZGUKcmVjdXJzb3MgaHVtYW5vczogKiplbCBlbmdhZ2VtZW50IG5vIHNlIGNvbXByYSBjb24gYWN0aXZpZGFkZXMgZGUgYmllbmVzdGFyKiouIE5pbmd1bmEgZGUKbGFzIGN1YXRybyBleHBlcmllbmNpYXMgZGUgcmVjdXBlcmFjaW9uIG11ZXZlIGVsIGVuZ2FnZW1lbnQgZGlyZWN0YW1lbnRlLiBMbyBtdWV2ZW4gc29sbwplbiBsYSBtZWRpZGEgZW4gcXVlIGVsIGNvbGFib3JhZG9yIGVmZWN0aXZhbWVudGUgKipyZWN1cGVyYSBlbmVyZ2lhKiouIFVuIHByb2dyYW1hIGRlIHlvZ2EKYWwgcXVlIGxhIGdlbnRlIGFzaXN0ZSBzaW4gZGVzY29uZWN0YXJzZSBubyBjYW1iaWEgbmFkYS4KClkgZW50cmUgbG9zIGN1YXRybyBkb21pbmlvcywgZWwgcXVlIG1hcyByaW5kZSBlcyAqKmNvbnRyb2wgc29icmUgZWwgdGllbXBvIGxpYnJlKioKKGByIHJvdW5kKGluZCRzdGQuYWxsWzFdLDMpYCksIHF1ZSBubyBjdWVzdGEgcHJlc3VwdWVzdG86IGN1ZXN0YSBwb2xpdGljYSBkZSBsYSBlbXByZXNhLgpFcyBsYSBkaWZlcmVuY2lhIGVudHJlIG9yZ2FuaXphciBhY3RpdmlkYWRlcyBwYXJhIGxhIGdlbnRlIHkgZGVqYXIgcXVlIGxhIGdlbnRlIGRlY2lkYQpjb21vIHVzYSBzdSB0aWVtcG8uCgojIyBQYXJ0ZSA0OiBlbCBtb2RlbG8gZGUgbWVkaWNpb24KCkVsIG1vZGVsbyBkZSBzZW5kZXJvcyBkZSBsYSBQYXJ0ZSAzIHN1cG9uZSBhbGdvIGZ1ZXJ0ZSB5IGZhbHNvOiBxdWUgbG9zIGNvbXB1ZXN0b3MgbWlkZW4Kc2luIGVycm9yLiBVbiBwcm9tZWRpbyBkZSBpdGVtcyBubyBlcyBlbCBjb25zdHJ1Y3RvLiBFbCBtb2RlbG8gZGUgbWVkaWNpb24gbGV2YW50YSBlc2UKc3VwdWVzdG8gcG9uaWVuZG8gY2FkYSB2YXJpYWJsZSBsYXRlbnRlIGNvbiBzdXMgaW5kaWNhZG9yZXMuCgpgYGB7ciBlajMtcDQtZGlhZ30Ka2FibGUocm91bmQoY29yKGRbLCBpdGVtc19lbmddKSwgMiksCiAgICAgIGNhcHRpb24gPSAiTG9zIGl0ZW1zIGRlIGVuZ2FnZW1lbnQ6IGNvcnJlbGFjaW9uZXMgcXVlIGRlY2FlbiBzZWd1biBsYSBkaXN0YW5jaWEgZW4gZWwgY3Vlc3Rpb25hcmlvIikKYGBgCgpBbnRlcyBkZSBlc3RpbWFyIGhheSBxdWUgdmVyIGVsIHByb2JsZW1hLiBMYSBtYXRyaXogKipubyoqIHRpZW5lIGxhIGVzdHJ1Y3R1cmEgZGUgYmxvcXVlcwpxdWUgcHJlZGljZSBsYSB0ZW9yaWEgZGUgdHJlcyBmYWN0b3JlcyAodmlnb3IsIGRlZGljYWNpb24sIGFic29yY2lvbikuIFRpZW5lIHVuCioqZ3JhZGllbnRlKio6IGNhZGEgaXRlbSBjb3JyZWxhY2lvbmEgbWFzIGNvbiBlbCBxdWUgZXN0YSBhIHN1IGxhZG8gZW4gZWwgY3Vlc3Rpb25hcmlvCihFVkkwMS0tRVZJMDIgPSAuOTQsIEVERTAxLS1FREUwMiA9IC44OSkgeSBtZW5vcyBjb25mb3JtZSBzZSBhbGVqYSAoRVZJMDEtLUVBQjAzID0gLjQ0KS4KRURFMDEgY29ycmVsYWNpb25hIG1hcyBjb24gRVZJMDMgKC44NyksIHF1ZSBlcyBkZSBvdHJvIGZhY3RvciwgcXVlIGNvbiBFREUwMyAoLjY3KSwgcXVlIGVzCmRlbCBzdXlvLiBFc28gZXMgdW4gKiplZmVjdG8gZGUgcHJveGltaWRhZCBlbiBlbCBpbnN0cnVtZW50byoqLCBubyBsYSBlc3RydWN0dXJhIGRlbApjb25zdHJ1Y3RvLgoKYGBge3IgZWozLXA0LWVuZ30KbW9kX2VuZzMgPC0gJyBWSUdPUiAgICAgID1+IEVWSTAxICsgRVZJMDIgKyBFVkkwMwogICAgICAgICAgICAgIERFRElDQUNJT04gPX4gRURFMDEgKyBFREUwMiArIEVERTAzCiAgICAgICAgICAgICAgQUJTT1JDSU9OICA9fiBFQUIwMSArIEVBQjAyICsgRUFCMDMgJwpmaXRfZW5nMyA8LSBjZmEobW9kX2VuZzMsIGRhdGEgPSBkLCBlc3RpbWF0b3IgPSAiTUxSIikKZml0X2VuZzIgPC0gY2ZhKHBhc3RlKG1vZF9lbmczLCAiXG4gRU5HQUdFTUVOVCA9fiBWSUdPUiArIERFRElDQUNJT04gKyBBQlNPUkNJT04iKSwKICAgICAgICAgICAgICAgIGRhdGEgPSBkLCBlc3RpbWF0b3IgPSAiTUxSIikKa2FibGUodGFibGFfYWp1c3RlKGZpdF9lbmczLCBmaXRfZW5nMiwKICAgICAgZXRpcXVldGFzID0gYygiMyBmYWN0b3JlcyBjb3JyZWxhY2lvbmFkb3MiLCAiMm8gb3JkZW46IEVOR0FHRU1FTlQiKSksCiAgICAgIGNhcHRpb24gPSAiRWwgbW9kZWxvIGRlIHNlZ3VuZG8gb3JkZW4gZW50cmVnYSB1bmEgc29sdWNpb24gSU5BRE1JU0lCTEUiKQpgYGAKCmBgYHtyIGVqMy1wNC1oZXl3b29kLCBlY2hvPUZBTFNFfQprYWJsZShkYXRhLmZyYW1lKFBhcmFtZXRybyA9IGMoIkNhcmdhIERFRElDQUNJT04gZW4gRU5HQUdFTUVOVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29ycmVsYWNpb24gREVESUNBQ0lPTi0tQUJTT1JDSU9OIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JyZWxhY2lvbiBWSUdPUi0tREVESUNBQ0lPTiIpLAogICAgICAgICAgICAgICAgIFZhbG9yID0gYyhyb3VuZChzdWJzZXQoc3RhbmRhcmRpemVkU29sdXRpb24oZml0X2VuZzIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaHM9PSJFTkdBR0VNRU5UIiAmIHJocz09IkRFRElDQUNJT04iKSRlc3Quc3RkLCAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoc3Vic2V0KHN0YW5kYXJkaXplZFNvbHV0aW9uKGZpdF9lbmczKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGhzPT0iREVESUNBQ0lPTiIgJiByaHM9PSJBQlNPUkNJT04iICYgb3A9PSJ+fiIpJGVzdC5zdGQsIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChzdWJzZXQoc3RhbmRhcmRpemVkU29sdXRpb24oZml0X2VuZzMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaHM9PSJWSUdPUiIgJiByaHM9PSJERURJQ0FDSU9OIiAmIG9wPT0ifn4iKSRlc3Quc3RkLCAzKSkpLAogICAgICByb3cubmFtZXMgPSBGQUxTRSwgY2FwdGlvbiA9ICJVbmEgY2FyZ2EgZXN0YW5kYXJpemFkYSBtYXlvciBxdWUgMTogY2FzbyBIZXl3b29kIikKYGBgCgpBcXVpIGVzdGEgZWwgcHVudG8gY2VudHJhbCBkZSB0b2RhIGxhIGFjdGl2aWRhZCwgeSBhcGFyZWNlICoqYW50ZXMqKiBkZSBtaXJhciBuaW5ndW4KaW5kaWNlIGRlIGFqdXN0ZTogbGEgY2FyZ2EgZXN0YW5kYXJpemFkYSBkZSBkZWRpY2FjaW9uIHNvYnJlIGVuZ2FnZW1lbnQgZXMgKiptYXlvciBxdWUgMSoqLApsbyBxdWUgaW1wbGljYSB1bmEgdmFyaWFuemEgZGUgZXJyb3IgbmVnYXRpdmEuIEVzIHVuICoqY2FzbyBIZXl3b29kKio6IHVuIHJlc3VsdGFkbwppbXBvc2libGUuIExvcyBpbmRpY2VzIGRlIGFqdXN0ZSBkZWwgbW9kZWxvIGRlIHNlZ3VuZG8gb3JkZW4gc29uIGlkZW50aWNvcyBhIGxvcyBkZWwgZGUKdHJlcyBmYWN0b3JlcywgYXNpIHF1ZSBzaSBtZSBodWJpZXJhIGd1aWFkbyBzb2xvIHBvciBDRkkgeSBSTVNFQSBubyBoYWJyaWEgbm90YWRvIG5hZGEuClVuIG1vZGVsbyBjb24gdW5hIGVzdGltYWNpb24gaW5hZG1pc2libGUgKipzZSBkZXNjYXJ0YSwgc2luIGltcG9ydGFyIGNvbW8gYWp1c3RlKiouCgpMYSBjYXVzYSBlcyB2aXNpYmxlIGVuIGxhIHRhYmxhOiBkZWRpY2FjaW9uIHkgYWJzb3JjaW9uIGNvcnJlbGFjaW9uYW4gLjkxIHkgdmlnb3IgY29uCmRlZGljYWNpb24gLjg4LiBBIGVzZSBuaXZlbCBsb3MgdHJlcyBmYWN0b3JlcyBubyBzb24gZGlzdGluZ3VpYmxlcywgeSBlbCBmYWN0b3IgZGUgc2VndW5kbwpvcmRlbiBpbnRlbnRhIGV4cGxpY2FyIG1hcyBjb3ZhcmlhbnphIGRlIGxhIHF1ZSBleGlzdGUuCgpgYGB7ciBlajMtcDQtbWVkaWNpb259Cm1vZF9tZWRpY2lvbiA8LSAnCiAgREVTQVBFR08gICA9fiBSUEQwMSArIFJQRDAyICsgUlBEMDMgKyBSUEQwNSArIFJQRDA4ICsgUlBEMTAKICBSRUxBSkFDSU9OID1+IFJSRTA1ICsgUlJFMDYgKyBSUkUwNwogIE1BRVNUUklBICAgPX4gUk1BMDQgKyBSTUEwNSArIFJNQTA3ICsgUk1BMDggKyBSTUEwOSArIFJNQTEwCiAgQ09OVFJPTCAgICA9fiBSQ08wMiArIFJDTzAzICsgUkNPMDQgKyBSQ08wNSArIFJDTzA2ICsgUkNPMDcKICBFTkVSR0lBICAgID1+IEVOMDEgKyBFTjAyICsgRU4wNCArIEVOMDUgKyBFTjA2ICsgRU4wNyArIEVOMDgKICBFTkdBR0VNRU5UID1+IEVWSTAxICsgRVZJMDIgKyBFVkkwMyArIEVERTAxICsgRURFMDIgKyBFREUwMyArIEVBQjAxICsgRUFCMDIgKyBFQUIwMwogIFJFQ1VQRVJBQ0lPTiA9fiBERVNBUEVHTyArIFJFTEFKQUNJT04gKyBNQUVTVFJJQSArIENPTlRST0wKICAjIGxvcyBkb3MgcGFyZXMgY2FzaSBpZGVudGljb3MgcXVlIGRldGVjdG8gZWwgZGlhZ25vc3RpY28gZGUgcHJveGltaWRhZAogIEVWSTAxIH5+IEVWSTAyCiAgRUFCMDIgfn4gRUFCMDMKICBSRUNVUEVSQUNJT04gfn4gRU5FUkdJQSArIEVOR0FHRU1FTlQKICBFTkVSR0lBIH5+IEVOR0FHRU1FTlQgJwpmaXRfbWVkIDwtIGNmYShtb2RfbWVkaWNpb24sIGRhdGEgPSBkLCBlc3RpbWF0b3IgPSAiTUxSIikKa2FibGUodGFibGFfYWp1c3RlKGZpdF9tZWQsIGV0aXF1ZXRhcyA9ICJtb2RlbG8gZGUgbWVkaWNpb24gY29tcGxldG8iKSwKICAgICAgY2FwdGlvbiA9ICJBanVzdGUgYWNlcHRhYmxlIHkgc29sdWNpb24gYWRtaXNpYmxlIikKYGBgCgpFbCBtb2RlbG8gZGUgbWVkaWNpb24gY29tcGxldG8gZXN0aW1hCmByIGZpdE1lYXN1cmVzKGZpdF9tZWQsIm5wYXIiKWAgcGFyYW1ldHJvcyBjb24gYHIgbnJvdyhkKWAgb2JzZXJ2YWNpb25lcy4gQWp1c3RhIGRlIGZvcm1hCioqYWNlcHRhYmxlIHBlcm8gbm8gYnVlbmEqKiAoQ0ZJIGByIHJvdW5kKGZpdE1lYXN1cmVzKGZpdF9tZWQsImNmaSIpLDMpYCwgUk1TRUEKYHIgcm91bmQoZml0TWVhc3VyZXMoZml0X21lZCwicm1zZWEiKSwzKWApLCB5IGVsIGRlc2FqdXN0ZSBlc3RhIGNvbmNlbnRyYWRvIGVuIGVsIGJsb3F1ZSBkZQplbmdhZ2VtZW50OgoKYGBge3IgZWozLXA0LW1pLCBlY2hvPUZBTFNFfQprYWJsZShoZWFkKG1vZGluZGljZXMoZml0X21lZCwgc29ydC4gPSBUUlVFKVssIGMoImxocyIsIm9wIiwicmhzIiwibWkiLCJlcGMiKV0sIDYpLAogICAgICByb3cubmFtZXMgPSBGQUxTRSwgZGlnaXRzID0gMywKICAgICAgY2FwdGlvbiA9ICJMb3MgcmVzaWR1YWxlcyBtYXMgZ3JhbmRlcyBzaWd1ZW4gc2llbmRvIGRlIGxvcyBpdGVtcyBkZSBlbmdhZ2VtZW50IikKYGBgCgojIyMgRWwgbW9kZWxvIGVzdHJ1Y3R1cmFsIGxhdGVudGUgY29uZmlybWEgbGEgY29uY2x1c2lvbiBkZSBsYSBQYXJ0ZSAzCgpgYGB7ciBlajMtcDQtZXN0cnVjdHVyYWx9CmJhc2VfbWVkIDwtIHN1YigiUkVDVVBFUkFDSU9OIH5+IEVORVJHSUEgXFwrIEVOR0FHRU1FTlRcbiAgRU5FUkdJQSB+fiBFTkdBR0VNRU5UIiwgIiIsCiAgICAgICAgICAgICAgICBtb2RfbWVkaWNpb24pCmZpdF9sYXRfYyA8LSBzZW0ocGFzdGUoYmFzZV9tZWQsICIKICBFTkVSR0lBICAgIH4gYSpSRUNVUEVSQUNJT04KICBFTkdBR0VNRU5UIH4gYipFTkVSR0lBCiAgaW5kaXJlY3RvIDo9IGEqYiAiKSwgZGF0YSA9IGQsIGVzdGltYXRvciA9ICJNTFIiKQpmaXRfbGF0X3AgPC0gc2VtKHBhc3RlKGJhc2VfbWVkLCAiCiAgRU5FUkdJQSAgICB+IGEqUkVDVVBFUkFDSU9OCiAgRU5HQUdFTUVOVCB+IGIqRU5FUkdJQSArIGNwKlJFQ1VQRVJBQ0lPTgogIGluZGlyZWN0byA6PSBhKmIKICB0b3RhbCAgICAgOj0gY3AgKyBhKmIgIiksIGRhdGEgPSBkLCBlc3RpbWF0b3IgPSAiTUxSIikKa2FibGUodGFibGFfYWp1c3RlKGZpdF9sYXRfYywgZml0X2xhdF9wLAogICAgICBldGlxdWV0YXMgPSBjKCJsYXRlbnRlOiBtZWRpYWNpb24gY29tcGxldGEiLCAibGF0ZW50ZTogbWVkaWFjaW9uIHBhcmNpYWwiKSksCiAgICAgIGNhcHRpb24gPSAiTWlzbW8gcmVzdWx0YWRvIHF1ZSBjb24gY29tcHVlc3RvczogZWwgY2FtaW5vIGRpcmVjdG8gbm8gaGFjZSBmYWx0YSIpCmNvbXBhcmFyKGZpdF9sYXRfYywgZml0X2xhdF9wLAogICAgICAgICBjKCJsYXRlbnRlOiBtZWRpYWNpb24gY29tcGxldGEiLCAibGF0ZW50ZTogbWVkaWFjaW9uIHBhcmNpYWwiKSwKICAgICAgICAgIkNvbiB2YXJpYWJsZXMgbGF0ZW50ZXMgbGEgY29uY2x1c2lvbiBubyBjYW1iaWEiKQpgYGAKCmBgYHtyIGVqMy1wNC1jb21wLCBlY2hvPUZBTFNFfQplZl9sYXQgPC0gc3Vic2V0KHBhcmFtZXRlckVzdGltYXRlcyhmaXRfbGF0X3AsIHN0YW5kYXJkaXplZCA9IFRSVUUpLCBvcCAlaW4lIGMoIn4iLCAiOj0iKSkKa2FibGUoZWZfbGF0WywgYygibGhzIiwicmhzIiwibGFiZWwiLCJlc3QiLCJzZSIsInB2YWx1ZSIsInN0ZC5hbGwiKV0sIHJvdy5uYW1lcyA9IEZBTFNFLAogICAgICBkaWdpdHMgPSAzLCBjb2wubmFtZXMgPSBjKCJEZXN0aW5vIiwiT3JpZ2VuIiwiRXRpcXVldGEiLCJFc3QiLCJFRSIsInAiLCJFc3RhbmQuIiksCiAgICAgIGNhcHRpb24gPSAiRWZlY3RvcyBjb24gdmFyaWFibGVzIGxhdGVudGVzIChtZWRpYWNpb24gcGFyY2lhbCkiKQoKY29tcCA8LSBkYXRhLmZyYW1lKAogIEVzcGVjaWZpY2FjaW9uID0gYygiQ29tcHVlc3RvcyAoUGFydGUgMykiLCAiTGF0ZW50ZSAoUGFydGUgNCkiKSwKICBDYW1pbm9fZGlyZWN0b19lc3RhbmQgPSBjKAogICAgcm91bmQoc3Vic2V0KHBhcmFtZXRlckVzdGltYXRlcyhmaXRfc2F0LCBzdGFuZGFyZGl6ZWQ9VFJVRSksIGxhYmVsPT0iY3AiKSRzdGQuYWxsLCAzKSwKICAgIHJvdW5kKHN1YnNldChwYXJhbWV0ZXJFc3RpbWF0ZXMoZml0X2xhdF9wLCBzdGFuZGFyZGl6ZWQ9VFJVRSksIGxhYmVsPT0iY3AiKSRzdGQuYWxsLCAzKSksCiAgcF9kZWxfZGlyZWN0byA9IGMoCiAgICByb3VuZChzdWJzZXQocGFyYW1ldGVyRXN0aW1hdGVzKGZpdF9zYXQpLCBsYWJlbD09ImNwIikkcHZhbHVlLCAzKSwKICAgIHJvdW5kKHN1YnNldChwYXJhbWV0ZXJFc3RpbWF0ZXMoZml0X2xhdF9wKSwgbGFiZWw9PSJjcCIpJHB2YWx1ZSwgMykpLAogIFIyX2VuZ2FnZW1lbnQgPSBjKHJvdW5kKGluc3BlY3QoZml0X3NhdCwicjIiKVtbIkVOR0EiXV0sIDMpLAogICAgICAgICAgICAgICAgICAgIHJvdW5kKGluc3BlY3QoZml0X2xhdF9wLCJyMiIpW1siRU5HQUdFTUVOVCJdXSwgMykpKQprYWJsZShjb21wLCByb3cubmFtZXMgPSBGQUxTRSwKICAgICAgY29sLm5hbWVzID0gYygiRXNwZWNpZmljYWNpb24iLCAiQ2FtaW5vIGRpcmVjdG8gZXN0YW5kLiIsICJwIGRlbCBkaXJlY3RvIiwKICAgICAgICAgICAgICAgICAgICAiUjIgZGUgZW5nYWdlbWVudCIpLAogICAgICBjYXB0aW9uID0gIkxhIGNvbmNsdXNpb24gc3VzdGFudGl2YSBubyBkZXBlbmRlIGRlIGNvbW8gc2UgbWlkYTogZXMgcm9idXN0YSIpCmBgYAoKQ29ycmVnaXIgcG9yIGVycm9yIGRlIG1lZGljaW9uICoqc3ViZSoqIGxhIG1hZ25pdHVkIGRlIGxvcyBlZmVjdG9zLCBjb21vIHNlIGVzcGVyYSAobGFzCmNvcnJlbGFjaW9uZXMgYXRlbnVhZGFzIHBvciBmYWx0YSBkZSBmaWFiaWxpZGFkIHNlIGRlc2F0ZW51YW4pLCBwZXJvIG5vIGNhbWJpYSBsYQpjb25jbHVzaW9uOiBlbCBjYW1pbm8gZGlyZWN0byBzaWd1ZSBzaW4gc2VyIHNpZ25pZmljYXRpdm8geSBsYSB2YXJpYW56YSBleHBsaWNhZGEgZGVsCmVuZ2FnZW1lbnQgZXMgcHJhY3RpY2FtZW50ZSBsYSBtaXNtYS4gTGEgbWVkaWFjaW9uIGNvbXBsZXRhIHNlIHNvc3RpZW5lIGNvbiBsYXMgZG9zCmVzcGVjaWZpY2FjaW9uZXMuCgojIyBDb25jbHVzaW9uZXMgZGVsIGVqZXJjaWNpbyAzCgoxLiAqKkVsIGluc3RydW1lbnRvIGRlIHJlY3VwZXJhY2lvbiB0ZW5pYSBncmFzYS4qKiBEZSAzMSBpdGVtcyBxdWVkYXJvbgogICBgciBzdW0obGVuZ3RocyhkZXBfcmVjJGl0ZW1zKSlgLiBMbyBxdWUgc2UgZWxpbWlubyBubyBmdWVyb24gaXRlbXMgbWFsb3Mgc2lubyBpdGVtcwogICAqKnJlcGV0aWRvcyoqOiBwYXJlcyBxdWUgZGljZW4gbG8gbWlzbW8gY29uIG90cmFzIHBhbGFicmFzLiBMYSByZWdsYSBkZSBkZXB1cmFjaW9uCiAgIHJlZGVzY3VicmlvIHRyZXMgZGUgbGFzIGN1YXRybyBlbGltaW5hY2lvbmVzIHF1ZSB5YSBoYWJpYW4gZG9jdW1lbnRhZG8gbG9zIGF1dG9yZXMuCjIuICoqRWwgY29uc3RydWN0byBkZSBzZWd1bmRvIG9yZGVuIHNlIHNvc3RpZW5lLioqIExvcyBjdWF0cm8gZG9taW5pb3Mgc29uIGZhY2V0YXMgZGUgdW5hCiAgIHNvbGEgY2FwYWNpZGFkIGRlIHJlY3VwZXJhY2lvbiwgeSByZW51bmNpYXIgYSBsYXMgc2VpcyBjb3JyZWxhY2lvbmVzIGxpYnJlcyBhIGNhbWJpbyBkZQogICBjdWF0cm8gY2FyZ2FzIG5vIGN1ZXN0YSBhanVzdGUgKHAgPSBgciByb3VuZChzdXBwcmVzc1dhcm5pbmdzKGxhdlRlc3RMUlQoZml0X3NlZywgZGVwX3JlYyRmaXQpKVsyLCJQcig+Q2hpc3EpIl0sMylgKS4KMy4gKipMYSBlbmVyZ2lhIHJlY3VwZXJhZGEgZXMgdW5pZGltZW5zaW9uYWwqKiwgY29uIGNhcmdhcyBkZSAuODkgYSAuOTUuIEVsIFJNU0VBIGFsdG8gZXMKICAgdW4gYXJ0ZWZhY3RvIGRlIHRlbmVyIHBvY29zIGdyYWRvcyBkZSBsaWJlcnRhZCwgbm8gZXZpZGVuY2lhIGRlIG1hbGEgZXN0cnVjdHVyYSwgeSBubwogICBzZSBjb3JyaWdlIHRpcmFuZG8gaXRlbXMuCjQuICoqTGEgbWVkaWFjaW9uIGVzIGNvbXBsZXRhLioqIExhcyBleHBlcmllbmNpYXMgZGUgcmVjdXBlcmFjaW9uIG5vIHRvY2FuIGVsIGVuZ2FnZW1lbnQKICAgcG9yIHN1IGN1ZW50YTogbG8gdG9jYW4gc29sbyBhIHRyYXZlcyBkZSBsYSBlbmVyZ2lhIGVmZWN0aXZhbWVudGUgcmVjdXBlcmFkYQogICAocCA9IGByIHJvdW5kKGZpdE1lYXN1cmVzKGZpdF9kb20sInB2YWx1ZSIpLDMpYCBwYXJhIGxhIHJlc3RyaWNjaW9uIGRlIG1lZGlhY2lvbgogICBjb21wbGV0YSwgeSBuaW5ndW4gY2FtaW5vIGRpcmVjdG8gc2lnbmlmaWNhdGl2bykuCjUuICoqQ29udHJvbCBzb2JyZSBlbCB0aWVtcG8gbGlicmUgZXMgbGEgcGFsYW5jYS4qKiBFZmVjdG8gaW5kaXJlY3RvIGVzdGFuZGFyaXphZG8gZGUKICAgYHIgcm91bmQoaW5kJHN0ZC5hbGxbMV0sMylgLCBjYXNpIGVsIGRvYmxlIGRlbCBzaWd1aWVudGUuIFJlbGFqYWNpb24sIGVuIGNhbWJpbywgbm8KICAgc29icmV2aXZlIGFsIGludGVydmFsbyBib290c3RyYXAuCjYuICoqTGEgZXNjYWxhIGRlIGVuZ2FnZW1lbnQgbm8gcmVwbGljYSBzdSBlc3RydWN0dXJhIHRlb3JpY2EgZW4gZXN0YSBtdWVzdHJhLioqIEVsIG1vZGVsbwogICBkZSBzZWd1bmRvIG9yZGVuIHByb2R1Y2UgdW4gY2FzbyBIZXl3b29kLCB5IGVsIHBhdHJvbiBkZSBjb3JyZWxhY2lvbmVzIGFwdW50YSBhIHVuCiAgIGVmZWN0byBkZSBwcm94aW1pZGFkIGVuIGVsIGN1ZXN0aW9uYXJpby4gRXN0ZSBlcyBlbCBoYWxsYXpnbyBxdWUgY29uZWN0YSBkaXJlY3RhbWVudGUKICAgY29uIGVsIGVqZXJjaWNpbyA0LgoKIyBFamVyY2ljaW8gNDogQmVoc29uLCBFZGR5IHkgTG9yZW56ZXQgKDIwMDApCgojIyBMb3MgZG9zIG1vZGVsb3MgcXVlIGNvbXBpdGVuCgpCZWhzb24sIEVkZHkgeSBMb3JlbnpldCAoMjAwMCkganVudGFuIDEzIGVzdHVkaW9zIHNvYnJlIGVsIE1vZGVsbyBkZSBDYXJhY3RlcmlzdGljYXMgZGVsClB1ZXN0byBkZSBIYWNrbWFuIHkgT2xkaGFtIGVuIHVuIG1ldGEtYW5hbGlzaXMsIGFybWFuIGNvbiBlbCB1bmEgbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMKeSBlc3RpbWFuIHNvYnJlIGVsbGEgZG9zIG1vZGVsb3Mgcml2YWxlczoKCmBgYHtyIGVqNC1tb2RlbG9zLCBlY2hvPUZBTFNFfQprYWJsZShkYXRhLmZyYW1lKAogIE1vZGVsbyA9IGMoIk1vZGVsbyAxOiBKQ00gb3JpZ2luYWwgKDMgZXRhcGFzKSIsICJNb2RlbG8gMjogSkNNIGNvbW8gc2UgcHJ1ZWJhICgyIGV0YXBhcykiKSwKICBFc3RydWN0dXJhID0gYygiNSBjYXJhY3RlcmlzdGljYXMgZGVsIHB1ZXN0byAtPiAzIGVzdGFkb3MgcHNpY29sb2dpY29zIGNyaXRpY29zIC0+IDMgcmVzdWx0YWRvcyIsCiAgICAgICAgICAgICAgICAgIjUgY2FyYWN0ZXJpc3RpY2FzIGRlbCBwdWVzdG8gLT4gMyByZXN1bHRhZG9zIChsb3MgZXN0YWRvcyBzZSBvbWl0ZW4pIiksCiAgQ2FtaW5vcyA9IGMoIjE0IiwgIjE1IiksCiAgU3VwdWVzdG8gPSBjKCJtZWRpYWNpb24gY29tcGxldGEgcG9yIGxvcyBlc3RhZG9zIHBzaWNvbG9naWNvcyIsCiAgICAgICAgICAgICAgICJlZmVjdG8gZGlyZWN0bywgc2luIG1lY2FuaXNtbyBpbnRlcm1lZGlvIikpLAogIGNhcHRpb24gPSAiTG9zIGRvcyBtb2RlbG9zIGRlbCBhcnRpY3VsbyIpCmBgYAoKRWwgTW9kZWxvIDEgZXMgbGEgdGVvcmlhIG9yaWdpbmFsOiBsYXMgY2FyYWN0ZXJpc3RpY2FzIGRlbCBwdWVzdG8gKHZhcmllZGFkLCBzaWduaWZpY2FkbywKaWRlbnRpZGFkLCBhdXRvbm9taWEsIHJldHJvYWxpbWVudGFjaW9uKSBwcm9kdWNlbiB0cmVzICoqZXN0YWRvcyBwc2ljb2xvZ2ljb3MgY3JpdGljb3MqKgooc2lnbmlmaWNhZG8gZXhwZXJpbWVudGFkbywgcmVzcG9uc2FiaWxpZGFkIGV4cGVyaW1lbnRhZGEsIGNvbm9jaW1pZW50byBkZSByZXN1bHRhZG9zKSB5CnNvbiBlc3RvcyBsb3MgcXVlIHByb2R1Y2VuIHNhdGlzZmFjY2lvbiwgc2F0aXNmYWNjaW9uIGRlIGNyZWNpbWllbnRvIHkgbW90aXZhY2lvbiBpbnRlcm5hLgpFbCBNb2RlbG8gMiBlcyBjb21vIGNhc2kgdG9kYSBsYSBsaXRlcmF0dXJhIHBvc3RlcmlvciBsbyBoYSBwcm9iYWRvOiBicmluY2FuZG9zZSBsb3MKZXN0YWRvcyBwc2ljb2xvZ2ljb3MuCgojIyBMbyBxdWUgcmVwb3J0YSBlbCBhcnRpY3VsbwoKYGBge3IgZWo0LXJlcG9ydGUsIGVjaG89RkFMU0V9CmthYmxlKGRhdGEuZnJhbWUoCiAgRXN0YWRpc3RpY28gPSBjKCJDaGktY3VhZHJhZGEgKGdsKSIsICJSTVNFQSIsICJHRkkiLCAiQ0ZJIiwKICAgICAgICAgICAgICAgICAgIkNhbWlub3Mgc2lnbmlmaWNhdGl2b3MiLCAiUjIgc2F0aXNmYWNjaW9uIiwgIlIyIGNyZWNpbWllbnRvIiwKICAgICAgICAgICAgICAgICAgIlIyIG1vdGl2YWNpb24iLCAiQUlDIiwgIkNBSUMiKSwKICBNb2RlbG9fMSA9IGMoIjEyNC4yNSAoMjUpIiwgIi4xNCIsICIuOTEiLCAiLjg5IiwgIjEyIGRlIDE0IiwgIi40MiIsICIuNDIiLCAiLjM4IiwKICAgICAgICAgICAgICAgIjI5NC40OCIsICI0NDYuMjkiKSwKICBNb2RlbG9fMiA9IGMoIjEyLjA5ICgzKSIsICIuMTYiLCAiLjk5IiwgIi45OCIsICI3IGRlIDE1IiwgIi4zNyIsICIuNDMiLCAiLjMyIiwKICAgICAgICAgICAgICAgIjgwLjA5IiwgIjIyNy41NiIpKSwKICBjYXB0aW9uID0gIlRhYmxhIDQgZGVsIGFydGljdWxvLiBFbCBNb2RlbG8gMiBnYW5hIGVuIEdGSSwgQ0ZJLCBBSUMgeSBDQUlDIikKYGBgCgpMb3MgYXV0b3JlcyBsbyBkaWNlbiBzaW4gcm9kZW9zOiBlbCBBSUMgeSBlbCBDQUlDLCBxdWUgc29uIGxvcyB1bmljb3MgZXN0YWRpc3RpY29zIHF1ZQp1c2FuIHBhcmEgY29tcGFyYXIgZm9ybWFsbWVudGUgbG9zIGRvcyBtb2RlbG9zLCAqKmZhdm9yZWNlbiBhbCBNb2RlbG8gMioqLiBZIGF1biBhc2kKZWxpZ2VuIGVsIE1vZGVsbyAxLgoKIyMgUmVwbGljYWNpb246IGxhIG1hdHJpeiBkZWwgYXJ0aWN1bG8gZXN0YSBwdWJsaWNhZGEsIGFzaSBxdWUgc2UgcHVlZGUgdmVyaWZpY2FyCgpMYSBUYWJsYSAyIGRlbCBhcnRpY3VsbyBwdWJsaWNhIGxhIG1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzIG1ldGEtYW5hbGl0aWNhIGNvbXBsZXRhIHkgbGFzCmRlc3ZpYWNpb25lcyBlc3RhbmRhciBub3JtYXRpdmFzIGRlIE9sZGhhbSwgSGFja21hbiB5IFN0ZXBpbmEgKDE5NzkpLiBDb24gZXNvIHNlIHB1ZWRlCnJlY29uc3RydWlyIGxhIG1hdHJpeiBkZSBjb3ZhcmlhbnphcyB5IHZvbHZlciBhIGVzdGltYXIgbG9zIGRvcyBtb2RlbG9zLgoKYGBge3IgZWo0LW1hdHJpen0KdiAgIDwtIGMoIlZBUiIsIlNJRyIsIklERSIsIkFVVCIsIkZCSyIsIk1FQSIsIlJFUyIsIktOTyIsIlNBVCIsIkdSTyIsIk1PVCIpCnNkdiA8LSBjKDEuNTcsIDEuMjUsIDEuNDQsIDEuMzksIDEuMzQsIDEuMTQsIDAuOTYsIDEuMTQsIDEuMDcsIDEuMTUsIDAuNzcpClIgPC0gZGlhZygxMSk7IGRpbW5hbWVzKFIpIDwtIGxpc3QodiwgdikKdHJpIDwtIGxpc3QoYyguNDEpLCBjKC4yMiwuMjApLCBjKC40MywuMzIsLjMyKSwgYyguMzUsLjM0LC4yNiwuMzkpLAogICAgICAgICAgICBjKC40NiwuNDUsLjI0LC40MiwuMzgpLCBjKC4zNCwuMzMsLjI3LC4zOSwuMzQsLjU5KSwKICAgICAgICAgICAgYyguMTYsLjIzLC4yOCwuMjksLjQ5LC40MCwuMzQpLCBjKC4zNSwuMjksLjIyLC40MiwuMzYsLjY1LC40OSwuNDIpLAogICAgICAgICAgICBjKC41MCwuMzgsLjI2LC41NCwuNDQsLjY1LC41MSwuNDAsLjY5KSwKICAgICAgICAgICAgYyguMzUsLjMzLC4xNywuMzAsLjQyLC41NywuNTksLjI1LC40MywuNTApKQpmb3IgKGkgaW4gMjoxMSkgeyBSW2ksIDE6KGktMSldIDwtIHRyaVtbaS0xXV07IFJbMTooaS0xKSwgaV0gPC0gdHJpW1tpLTFdXSB9ClMgPC0gZGlhZyhzZHYpICUqJSBSICUqJSBkaWFnKHNkdik7IGRpbW5hbWVzKFMpIDwtIGRpbW5hbWVzKFIpCk4gPC0gMjA4ICAgIyBsb3MgYXV0b3JlcyB1c2FuIGxhIG1lZGlhbmEgZGVsIHRhbWFuaW8gZGUgbXVlc3RyYSwgbm8gbGEgc3VtYQpgYGAKCmBgYHtyIGVqNC1tMX0KbW9kX2IxIDwtICcKICBNRUEgfiBWQVIgKyBTSUcgKyBJREUKICBSRVMgfiBBVVQKICBLTk8gfiBGQksKICBTQVQgfiBNRUEgKyBSRVMgKyBLTk8KICBHUk8gfiBNRUEgKyBSRVMgKyBLTk8KICBNT1QgfiBNRUEgKyBSRVMgKyBLTk8KICBNRUEgfn4gUkVTICsgS05PCiAgUkVTIH5+IEtOTwogIFNBVCB+fiBHUk8gKyBNT1QKICBHUk8gfn4gTU9UICcKZml0X2IxIDwtIHNlbShtb2RfYjEsIHNhbXBsZS5jb3YgPSBTLCBzYW1wbGUubm9icyA9IE4sIGZpeGVkLnggPSBGQUxTRSkKcm91bmQoZml0TWVhc3VyZXMoZml0X2IxLCBjKCJjaGlzcSIsImRmIiwiY2ZpIiwicm1zZWEiLCJnZmkiKSksIDMpCnJvdW5kKGluc3BlY3QoZml0X2IxLCAicjIiKSwgMykKYGBgCgpgYGB7ciBlajQtbTEtY2FtaW5vcywgZWNobz1GQUxTRX0KcGIxIDwtIHN1YnNldChwYXJhbWV0ZXJFc3RpbWF0ZXMoZml0X2IxLCBzdGFuZGFyZGl6ZWQgPSBUUlVFKSwgb3AgPT0gIn4iKQprYWJsZShkYXRhLmZyYW1lKAogIENhbnRpZGFkID0gYygiR3JhZG9zIGRlIGxpYmVydGFkIiwgIkNhbWlub3Mgc2lnbmlmaWNhdGl2b3MiLCAiUjIgc2F0aXNmYWNjaW9uIiwKICAgICAgICAgICAgICAgIlIyIGNyZWNpbWllbnRvIiwgIlIyIG1vdGl2YWNpb24iKSwKICBBcnRpY3VsbyA9IGMoIjI1IiwgIjEyIGRlIDE0IiwgIi40MiIsICIuNDIiLCAiLjM4IiksCiAgUmVwbGljYWNpb24gPSBjKGZpdE1lYXN1cmVzKGZpdF9iMSwiZGYiKSwKICAgICAgICAgICAgICAgICAgcGFzdGUoc3VtKHBiMSRwdmFsdWUgPCAuMDUpLCAiZGUiLCBucm93KHBiMSkpLAogICAgICAgICAgICAgICAgICByb3VuZChpbnNwZWN0KGZpdF9iMSwicjIiKVtbIlNBVCJdXSwgMyksCiAgICAgICAgICAgICAgICAgIHJvdW5kKGluc3BlY3QoZml0X2IxLCJyMiIpW1siR1JPIl1dLCAzKSwKICAgICAgICAgICAgICAgICAgcm91bmQoaW5zcGVjdChmaXRfYjEsInIyIilbWyJNT1QiXV0sIDMpKSksCiAgcm93Lm5hbWVzID0gRkFMU0UsIGNhcHRpb24gPSAiRWwgTW9kZWxvIDEgc2UgcmVwcm9kdWNlIGNhc2kgZXhhY3RhbWVudGUiKQpgYGAKCkxhIHJlcGxpY2FjaW9uIGRlbCBNb2RlbG8gMSBlcyBwcmFjdGljYW1lbnRlIGV4YWN0YTogbWlzbW9zIGdyYWRvcyBkZSBsaWJlcnRhZCwgbWlzbW9zCjEyIGRlIDE0IGNhbWlub3Mgc2lnbmlmaWNhdGl2b3MgeSBsYXMgdHJlcyBSMiBjb2luY2lkZW4gYWwgc2VndW5kbyBkZWNpbWFsLiBFc28gdmFsaWRhIHF1ZQpsYSBtYXRyaXogZXN0YSBiaWVuIHJlY29uc3RydWlkYSB5IHF1ZSBlbnRlbmRpIGxhIGVzcGVjaWZpY2FjaW9uLgoKYGBge3IgZWo0LW0yfQpvOCA8LSBjKCJWQVIiLCJTSUciLCJJREUiLCJBVVQiLCJGQksiLCJTQVQiLCJHUk8iLCJNT1QiKQptb2RfYjIgPC0gJwogIFNBVCB+IFZBUiArIFNJRyArIElERSArIEFVVCArIEZCSwogIEdSTyB+IFZBUiArIFNJRyArIElERSArIEFVVCArIEZCSwogIE1PVCB+IFZBUiArIFNJRyArIElERSArIEFVVCArIEZCSyAnCiMgYXV0by5jb3YueSA9IEZBTFNFIHJlcHJvZHVjZSBsb3MgMyBncmFkb3MgZGUgbGliZXJ0YWQgcXVlIHJlcG9ydGEgZWwgYXJ0aWN1bG8KZml0X2IyIDwtIHNlbShtb2RfYjIsIHNhbXBsZS5jb3YgPSBTW284LCBvOF0sIHNhbXBsZS5ub2JzID0gTiwKICAgICAgICAgICAgICBmaXhlZC54ID0gRkFMU0UsIGF1dG8uY292LnkgPSBGQUxTRSkKcm91bmQoZml0TWVhc3VyZXMoZml0X2IyLCBjKCJjaGlzcSIsImRmIiwiY2ZpIiwicm1zZWEiLCJnZmkiKSksIDMpCmBgYAoKKipOb3RhIGRlIHZlcmlmaWNhY2lvbi4qKiBMb3MgZ3JhZG9zIGRlIGxpYmVydGFkIGNvaW5jaWRlbiAoMyksIHBlcm8gbGEgY2hpLWN1YWRyYWRhIHF1ZQpvYnRlbmdvIGVzIGByIHJvdW5kKGZpdE1lYXN1cmVzKGZpdF9iMiwiY2hpc3EiKSwyKWAgY29udHJhIGxvcyAxMi4wOSBwdWJsaWNhZG9zLCB5IGVsIENGSQptZSBkYSBgciByb3VuZChmaXRNZWFzdXJlcyhmaXRfYjIsImNmaSIpLDMpYCBjb250cmEgLjk4LiBMYSByYXpvbiBlcyBpZGVudGlmaWNhYmxlOiBjb24gMwpncmFkb3MgZGUgbGliZXJ0YWQgbGFzIHRyZXMgY292YXJpYW56YXMgZW50cmUgbG9zIHJlc2lkdWFsZXMgZGUgbG9zIHJlc3VsdGFkb3MgZXN0YW4gZmlqYXMKZW4gY2VybywgeSBzYXRpc2ZhY2Npb24gY29uIGNyZWNpbWllbnRvIGNvcnJlbGFjaW9uYW4gLjY5IGVuIGxhIG1hdHJpeiBwdWJsaWNhZGEsIGFzaSBxdWUKZXNhIHJlc3RyaWNjaW9uICoqdGllbmUqKiBxdWUgcHJvZHVjaXIgdW4gZGVzYWp1c3RlIGVub3JtZS4gU2kgc2UgbGliZXJhbiBlc2FzIHRyZXMKY292YXJpYW56YXMgZWwgbW9kZWxvIHF1ZWRhIHNhdHVyYWRvIChnbCA9IDAsIGFqdXN0ZSBwZXJmZWN0bykuIE5vIGV4aXN0ZSB1bmEKZXNwZWNpZmljYWNpb24gcXVlIGRlIGFsIG1pc21vIHRpZW1wbyBnbCA9IDMgeSBjaGktY3VhZHJhZGEgPSAxMi4wOSBjb24gbGEgbWF0cml6IHF1ZSBlbGxvcwpwdWJsaWNhbi4gRGFkbyBxdWUgZWwgTW9kZWxvIDEgc2kgc2UgcmVwcm9kdWNlLCBsYSBpbmNvbnNpc3RlbmNpYSBlc3RhIGVuIGVsIHJlcG9ydGUgZGVsCk1vZGVsbyAyLCBubyBlbiBtaSByZWNvbnN0cnVjY2lvbi4gQ29udmllbmUgY29udHJhc3RhcmxvIGNvbiBlbCBwcm9mZXNvci4KCiMjIExhIGNvbXBhcmFjaW9uIHBvciBBSUMgZGVsIGFydGljdWxvIG5vIGVzIHZhbGlkYSwgeSBlc28gcmVmdWVyemEgc3UgcHJvcGlhIGRlY2lzaW9uCgpJbmRlcGVuZGllbnRlbWVudGUgZGVsIHB1bnRvIGFudGVyaW9yLCBoYXkgdW4gcHJvYmxlbWEgbWFzIGdyYXZlIGNvbiBlbCBhcmd1bWVudG8KY3VhbnRpdGF0aXZvIGRlbCBhcnRpY3Vsby4gRWwgQUlDIHkgZWwgQ0FJQyBzb24gKiplbCB1bmljbyBjcml0ZXJpbyBmb3JtYWwqKiBxdWUgdXNhbiBwYXJhCmRlY2xhcmFyIHN1cGVyaW9yIGFsIE1vZGVsbyAyLiBQZXJvIGNvbXBhcmFuIGRvcyBtb2RlbG9zIGFqdXN0YWRvcyBhICoqY29uanVudG9zIGRpc3RpbnRvcwpkZSB2YXJpYWJsZXMgb2JzZXJ2YWRhcyoqOiBlbCBNb2RlbG8gMSB1c2EgMTEgdmFyaWFibGVzICg2NiBtb21lbnRvcykgeSBlbCBNb2RlbG8gMiB1c2EgOAooMzYgbW9tZW50b3MpLiBMYSB2ZXJvc2ltaWxpdHVkIGRlIGFtYm9zIG5vIGVzdGEgZW4gbGEgbWlzbWEgZXNjYWxhLgoKYGBge3IgZWo0LWFpY30KIyBkb3MgbW9kZWxvcyBkZSBhanVzdGUgUEVSRkVDVE8sIHVubyBjb24gMTEgdmFyaWFibGVzIHkgb3RybyBjb24gOApzYXQxMSA8LSBwYXN0ZShhcHBseSh0KGNvbWJuKHYsIDIpKSwgMSwgZnVuY3Rpb24ocCkgcGFzdGUocFsxXSwgIn5+IiwgcFsyXSkpLCBjb2xsYXBzZSA9ICJcbiIpCmZpdF9zMTEgPC0gc2VtKHNhdDExLCBzYW1wbGUuY292ID0gUywgc2FtcGxlLm5vYnMgPSBOKQpmaXRfczggIDwtIHNlbShwYXN0ZShtb2RfYjIsICJcbiBTQVQgfn4gR1JPICsgTU9UIFxuIEdSTyB+fiBNT1QiKSwKICAgICAgICAgICAgICAgc2FtcGxlLmNvdiA9IFNbbzgsIG84XSwgc2FtcGxlLm5vYnMgPSBOLCBmaXhlZC54ID0gRkFMU0UpCmthYmxlKGRhdGEuZnJhbWUoCiAgTW9kZWxvID0gYygiU2F0dXJhZG8sIDExIHZhcmlhYmxlcyAoYWp1c3RlIHBlcmZlY3RvKSIsCiAgICAgICAgICAgICAiU2F0dXJhZG8sIDggdmFyaWFibGVzIChhanVzdGUgcGVyZmVjdG8pIiksCiAgY2hpc3EgPSBjKDAsIDApLCBnbCA9IGMoMCwgMCksCiAgQUlDID0gcm91bmQoYyhmaXRNZWFzdXJlcyhmaXRfczExLCAiYWljIiksIGZpdE1lYXN1cmVzKGZpdF9zOCwgImFpYyIpKSwgMCkpLAogIHJvdy5uYW1lcyA9IEZBTFNFLAogIGNhcHRpb24gPSAiRG9zIG1vZGVsb3MgY29uIGFqdXN0ZSBpZGVudGljYW1lbnRlIHBlcmZlY3RvIHkgQUlDIHNlcGFyYWRvcyBwb3IgbWFzIGRlIG1pbCBwdW50b3MiKQpgYGAKCkxvcyBkb3MgbW9kZWxvcyBkZSBsYSB0YWJsYSBhanVzdGFuICoqcGVyZmVjdG8qKiwgeSBhdW4gYXNpIHN1cyBBSUMgZGlmaWVyZW4gZW4KYHIgcm91bmQoZml0TWVhc3VyZXMoZml0X3MxMSwiYWljIikgLSBmaXRNZWFzdXJlcyhmaXRfczgsImFpYyIpKWAgcHVudG9zLiBMYSBkaWZlcmVuY2lhIG5vCm1pZGUgY2FsaWRhZCBkZSBhanVzdGU6IG1pZGUgKipjdWFudGFzIHZhcmlhYmxlcyBlbnRyYXJvbiBhbCBtb2RlbG8qKi4gVW4gbW9kZWxvIGNvbiBtZW5vcwp2YXJpYWJsZXMgc2llbXByZSB2YSBhIHRlbmVyIG1lbm9yIEFJQywgYXVucXVlIHNlYSBwZW9yIHRlb3JpYS4gUG9yIGxvIHRhbnRvIGVsIGFyZ3VtZW50bwoiZWwgQUlDIHkgZWwgQ0FJQyBmYXZvcmVjZW4gYWwgTW9kZWxvIDIiIG5vIHNvc3RpZW5lIGxvIHF1ZSBzZSBsZSBwaWRlIHNvc3RlbmVyLgoKIyMgUG9yIHF1ZSBlbGlnaWVyb24gZWwgTW9kZWxvIDE6IGxhIHJlc3B1ZXN0YSBkZWwgYXJ0aWN1bG8KCkxvcyBhdXRvcmVzIG5vIGludm9jYW4gZWwgYXJndW1lbnRvIGFudGVyaW9yLiBTdSByYXpvbiBlcyBkaXN0aW50YSB5LCBlbiBtaSBsZWN0dXJhLCBtYXMKZnVlcnRlIHRvZGF2aWEuIExhIGZvcm11bGFuIGFzaTogY29tcGFyYXIgbW9kZWxvcyByaXZhbGVzIGV4aWdlIG1hcyBxdWUgY29tcGFyYXIgcmF6b25lcwpkZSBhanVzdGUsIHBvcnF1ZSAqKmxhIHJhem9uYWJpbGlkYWQgZGUgbG9zIHZhbG9yZXMgZGVsIG1vZGVsbyB5IHN1IGNvcnJlc3BvbmRlbmNpYSBjb24gbGEKdGVvcmlhIHNvbiBpZ3VhbCBvIG1hcyBpbXBvcnRhbnRlcyoqLgoKRWwgaGVjaG8gY29uY3JldG8gcXVlIGxvcyBkZWNpZGUgZXN0YSBlbiBsb3MgY29lZmljaWVudGVzOgoKYGBge3IgZWo0LWNvZWZ9CnBiMiA8LSBzdWJzZXQocGFyYW1ldGVyRXN0aW1hdGVzKGZpdF9iMiwgc3RhbmRhcmRpemVkID0gVFJVRSksIG9wID09ICJ+IikKdHJlcyA8LSBwYjJbcGIyJHJocyAlaW4lIGMoIlZBUiIsIlNJRyIsIklERSIpLCBdCmthYmxlKHRyZXNbLCBjKCJsaHMiLCJyaHMiLCJlc3QiLCJzZSIsInB2YWx1ZSIsInN0ZC5hbGwiKV0sIHJvdy5uYW1lcyA9IEZBTFNFLCBkaWdpdHMgPSAzLAogICAgICBjb2wubmFtZXMgPSBjKCJSZXN1bHRhZG8iLCJDYXJhY3RlcmlzdGljYSIsIkVzdGltYWRvIiwiRUUiLCJwIiwiRXN0YW5kYXJpemFkbyIpLAogICAgICBjYXB0aW9uID0gIk1vZGVsbyAyOiBsb3MgY2FtaW5vcyBkZXNkZSB2YXJpZWRhZCwgc2lnbmlmaWNhZG8gZSBpZGVudGlkYWQgaGFjaWEgbG9zIHJlc3VsdGFkb3MiKQpgYGAKCkVuIGVsIE1vZGVsbyAyLCBgciBzdW0odHJlcyRwdmFsdWUgPj0gLjA1KWAgZGUgbG9zIGByIG5yb3codHJlcylgIGNhbWlub3MgcXVlIHZhbiBkZQp2YXJpZWRhZCBkZSBoYWJpbGlkYWRlcywgc2lnbmlmaWNhZG8gZGUgbGEgdGFyZWEgZSBpZGVudGlkYWQgZGUgbGEgdGFyZWEgaGFjaWEgbG9zCnJlc3VsdGFkb3MgKipubyBzb24gc2lnbmlmaWNhdGl2b3MqKi4gRWwgYXJ0aWN1bG8gcmVwb3J0YSA4IGRlIDk7IHlvIG9idGVuZ28KYHIgc3VtKHRyZXMkcHZhbHVlID49IC4wNSlgIGRlIGByIG5yb3codHJlcylgLCBjb24gZG9zIGNhc29zIGFsIGZpbG8uIExhIGNvbmNsdXNpb24gZXMgbGEKbWlzbWE6ICoqc2kgZWwgTW9kZWxvIDIgZnVlcmEgY2llcnRvLCBlbnJpcXVlY2VyIHVuIHB1ZXN0byBkYW5kb2xlIHZhcmllZGFkIHkgc2lnbmlmaWNhZG8Kbm8gc2VydmlyaWEgZGUgbmFkYS4qKiBFc28gY29udHJhZGljZSBkb3MgZGVjYWRhcyBkZSBpbnZlc3RpZ2FjaW9uIHNvYnJlIHJlZGlzZW5vIGRlbAp0cmFiYWpvLgoKRWwgTW9kZWxvIDEgcmVzdWVsdmUgbGEgcGFyYWRvamE6CgpgYGB7ciBlajQtaW5kaXJlY3Rvc30KbW9kX2IxX2luZCA8LSAnCiAgTUVBIH4gdipWQVIgKyBzKlNJRyArIGkqSURFCiAgUkVTIH4gQVVUCiAgS05PIH4gRkJLCiAgU0FUIH4gbTEqTUVBICsgUkVTICsgS05PCiAgR1JPIH4gbTIqTUVBICsgUkVTICsgS05PCiAgTU9UIH4gbTMqTUVBICsgUkVTICsgS05PCiAgTUVBIH5+IFJFUyArIEtOTwogIFJFUyB+fiBLTk8KICBTQVQgfn4gR1JPICsgTU9UCiAgR1JPIH5+IE1PVAogIHZhcmllZGFkX3NhdCAgICAgICAgOj0gdiptMQogIHZhcmllZGFkX2NyZWMgICAgICAgOj0gdiptMgogIHNpZ25pZmljYWRvX3NhdCAgICAgOj0gcyptMQogIHNpZ25pZmljYWRvX2NyZWMgICAgOj0gcyptMiAnCmZpdF9iMWkgPC0gc2VtKG1vZF9iMV9pbmQsIHNhbXBsZS5jb3YgPSBTLCBzYW1wbGUubm9icyA9IE4sIGZpeGVkLnggPSBGQUxTRSkKa2FibGUoc3Vic2V0KHBhcmFtZXRlckVzdGltYXRlcyhmaXRfYjFpLCBzdGFuZGFyZGl6ZWQgPSBUUlVFKSwgb3AgPT0gIjo9IilbCiAgICAgICAgLCBjKCJsaHMiLCJlc3QiLCJzZSIsInB2YWx1ZSIsInN0ZC5hbGwiKV0sIHJvdy5uYW1lcyA9IEZBTFNFLCBkaWdpdHMgPSAzLAogICAgICBjb2wubmFtZXMgPSBjKCJFZmVjdG8gaW5kaXJlY3RvIiwiRXN0aW1hZG8iLCJFRSIsInAiLCJFc3RhbmRhcml6YWRvIiksCiAgICAgIGNhcHRpb24gPSAiRW4gZWwgTW9kZWxvIDEgZXNvcyBtaXNtb3MgY2FtaW5vcyBTSSBleGlzdGVuLCBwZXJvIHBhc2FuIHBvciBlbCBzaWduaWZpY2FkbyBleHBlcmltZW50YWRvIikKYGBgCgpWYXJpZWRhZCB5IHNpZ25pZmljYWRvICoqc2kqKiBhZmVjdGFuIGxhIHNhdGlzZmFjY2lvbiB5IGVsIGNyZWNpbWllbnRvLCBwZXJvIGxvIGhhY2VuCioqYSB0cmF2ZXMgZGVsIHNpZ25pZmljYWRvIGV4cGVyaW1lbnRhZG8qKi4gQWwgYm9ycmFyIGxvcyBlc3RhZG9zIHBzaWNvbG9naWNvcywgZWwgTW9kZWxvIDIKbm8gZWxpbWluYSB1biByb2RlbyBpbm5lY2VzYXJpbzogZWxpbWluYSBlbCBtZWNhbmlzbW8sIHkgY29uIGVsIGRlc2FwYXJlY2UgZWwgZWZlY3RvLgoKTG9zIGF1dG9yZXMgZWxpZ2VuIGVsIE1vZGVsbyAxLCBlbnRvbmNlcywgcG9yIGN1YXRybyByYXpvbmVzIGFjdW11bGFkYXM6CgoxLiAqKkxvcyBjb2VmaWNpZW50ZXMgZGVsIE1vZGVsbyAyIGNvbnRyYWRpY2VuIGxhIHRlb3JpYSBlc3RhYmxlY2lkYS4qKiBVbiBtb2RlbG8gY3V5b3MKICAgcGFyYW1ldHJvcyBubyB0aWVuZW4gc2VudGlkbyBzdXN0YW50aXZvIG5vIGVzIHV0aWxpemFibGUsIGFqdXN0ZSBsbyBxdWUgYWp1c3RlLgoyLiAqKkVsIE1vZGVsbyAxIGV4cGxpY2EgbWFzIHZhcmlhbnphKiogZW4gZG9zIGRlIGxvcyB0cmVzIHJlc3VsdGFkb3MgeSB0aWVuZSBtZWpvcgogICBwcm9wb3JjaW9uIGRlIGNhbWlub3Mgc2lnbmlmaWNhdGl2b3MgKDEyIGRlIDE0IGNvbnRyYSA3IGRlIDE1KS4KMy4gKipFbCBtZWpvciBhanVzdGUgZGVsIE1vZGVsbyAyIGVzIGVuIGJ1ZW5hIG1lZGlkYSBtZWNhbmljby4qKiBDb24gMyBncmFkb3MgZGUgbGliZXJ0YWQKICAgZXN0YSBhIHVuIHBhc28gZGUgZXN0YXIgc2F0dXJhZG8sIHkgdW4gbW9kZWxvIGNhc2kgc2F0dXJhZG8gY2FzaSBubyBwdWVkZSBkZXNhanVzdGFyLgogICBMb3MgMjUgZ3JhZG9zIGRlIGxpYmVydGFkIGRlbCBNb2RlbG8gMSBzb24gdW5hIGhpcG90ZXNpcyBtdWNobyBtYXMgZXhwdWVzdGEgYQogICByZWZ1dGFjaW9uLiBEZSBoZWNobyBlbCBSTVNFQSwgcXVlIGVzIGVsIHVuaWNvIGluZGljZSBkZSBsYSB0YWJsYSBxdWUgcGVuYWxpemEgbGEgZmFsdGEKICAgZGUgcGFyc2ltb25pYSwgZXMgKipwZW9yKiogZW4gZWwgTW9kZWxvIDIgKC4xNiBjb250cmEgLjE0KS4KNC4gKipFbCBwcm9wb3NpdG8gZGVsIG1vZGVsbyBlcyBleHBsaWNhciwgbm8gc29sbyBkZXNjcmliaXIuKiogTG9zIGVzdGFkb3MgcHNpY29sb2dpY29zIHNvbgogICBsbyB1bmljbyBzb2JyZSBsbyBxdWUgdW4gZ2VyZW50ZSBwdWVkZSBhY3R1YXIgY29uIGNyaXRlcmlvOiBsZSBkaWNlbiAqcG9yIHF1ZSogZnVuY2lvbmEKICAgZWwgcmVkaXNlbm8gZGVsIHB1ZXN0byB5IGN1YW5kbyBubyB2YSBhIGZ1bmNpb25hci4KCiMjIENvbmNsdXNpb25lcyBkZWwgZWplcmNpY2lvIDQ6IGxhIGxlY2Npb24KCioqVW4gaW5kaWNlIGRlIGFqdXN0ZSBtaWRlIHNpIGVsIG1vZGVsbyByZXByb2R1Y2UgbGEgbWF0cml6IGRlIGNvdmFyaWFuemFzLiBObyBtaWRlIHNpIGVsCm1vZGVsbyBlcyB2ZXJkYWRlcm8sIG5pIHNpIGVzIHV0aWwsIG5pIHNpcXVpZXJhIHNpIGVzIHBvc2libGUuKiogRWxlZ2lyIG1vZGVsbyBwb3IgQ0ZJIGVzCmNvbW8gZWxlZ2lyIHVuIHByb25vc3RpY28gcG9yIHN1IFIyIGRlbnRybyBkZSBtdWVzdHJhLgoKTGFzIHRyZXMgdmVyaWZpY2FjaW9uZXMgcXVlIGVzdGUgYXJ0aWN1bG8gbWUgZGVqYSBjb21vIHJ1dGluYSwgZW4gZXN0ZSBvcmRlbjoKCjEuICoqQWRtaXNpYmlsaWRhZCBwcmltZXJvLioqIEFudGVzIGRlIGxlZXIgdW4gc29sbyBpbmRpY2UsIHJldmlzYXIgcXVlIG5vIGhheWEgdmFyaWFuemFzCiAgIG5lZ2F0aXZhcyBuaSBjYXJnYXMgZXN0YW5kYXJpemFkYXMgbWF5b3JlcyBxdWUgMS4gRW4gZWwgZWplcmNpY2lvIDMgZXN0byBkZXNjYXJ0byBlbAogICBtb2RlbG8gZGUgZW5nYWdlbWVudCBkZSBzZWd1bmRvIG9yZGVuICoqYW50ZXMqKiBkZSBxdWUgc3UgYWp1c3RlIGlkZW50aWNvIGFsIGRlIHRyZXMKICAgZmFjdG9yZXMgbWUgaGljaWVyYSBwYXNhcmxvIHBvciBhbHRvLgoyLiAqKlNpZ25vIHkgbWFnbml0dWQgZGUgbG9zIGNvZWZpY2llbnRlcyBjb250cmEgbGEgdGVvcmlhLioqIFVuIG1vZGVsbyBxdWUgYWp1c3RhIG1lam9yCiAgIHBlcm8gZGljZSBxdWUgZGFyIHZhcmllZGFkIGFsIHRyYWJham8gbm8gc2lydmUsIGVzdGEgZGljaWVuZG8gYWxnbyBmYWxzby4KMy4gKipDb21wYXJhYmlsaWRhZCBkZSBsYSBjb21wYXJhY2lvbi4qKiBDaGktY3VhZHJhZGEgc29sbyBlbnRyZSBtb2RlbG9zIGFuaWRhZG9zOyBBSUMgc29sbwogICBlbnRyZSBtb2RlbG9zIHNvYnJlIGxhcyBtaXNtYXMgdmFyaWFibGVzLiBFbiBlbCBlamVyY2ljaW8gMyBlc3RvIG1lIG9ibGlnbyBhIGZpamFyIGVsCiAgIGNhbWlubyBkaXJlY3RvIGVuIGNlcm8gcGFyYSBwb2RlciBjb250cmFzdGFyIGFsZ28sIGVuIHZleiBkZSBjZWxlYnJhciBlbCBDRkkgPSAxIGRlIHVuCiAgIG1vZGVsbyBzYXR1cmFkby4KClkgbGEgbGVjY2lvbiBkZSBmb25kbywgcXVlIGVzIGxhIHF1ZSBjb25lY3RhIGxvcyBjdWF0cm8gZWplcmNpY2lvczogKipib3JyYXIgZWwgbWVkaWFkb3IKbWVqb3JhIGVsIGFqdXN0ZSB5IGRlc3RydXllIGxhIGV4cGxpY2FjaW9uLioqIEVsIE1vZGVsbyAyIGRlIEJlaHNvbiBhanVzdGEgbWVqb3IgcG9ycXVlCnBpZGUgbWVub3M7IG1pIG1vZGVsbyBkZSBtZWRpYWNpb24gcGFyY2lhbCBkZSBsYSBQYXJ0ZSAzIGFqdXN0YWJhIHBlcmZlY3RvIHBvcnF1ZSBubyBwZWRpYQpuYWRhLiBFbiBsb3MgZG9zIGNhc29zLCBlbCBtb2RlbG8gcXVlIHZhbGUgZXMgZWwgcXVlIHNlIGF0cmV2ZSBhIGFmaXJtYXIgZWwgbWVjYW5pc21vIHkKc29icmV2aXZlIGEgbGEgcHJ1ZWJhLgoKIyBMaW1pdGFjaW9uZXMKCjEuICoqTG9zIGRhdG9zIGRlbCBlamVyY2ljaW8gMyBzb24gdHJhbnN2ZXJzYWxlcy4qKiBUb2RvIGVsIGxlbmd1YWplIGNhdXNhbCAoImxhcwogICBleHBlcmllbmNpYXMgZGUgcmVjdXBlcmFjaW9uIHByb2R1Y2VuIGVuZXJnaWEsIHF1ZSBwcm9kdWNlIGVuZ2FnZW1lbnQiKSBkZXNjcmliZSBsYQogICBlc3RydWN0dXJhIGRlbCBtb2RlbG8sIG5vIHVuYSBjYXVzYWxpZGFkIGRlbW9zdHJhZGEuIENvbiB1bmEgc29sYSBtZWRpY2lvbiwgZWwgbW9kZWxvCiAgIGludmVyc28gKGNvbGFib3JhZG9yZXMgY29tcHJvbWV0aWRvcyBzZSByZWN1cGVyYW4gbWVqb3IpIGFqdXN0YSBpZ3VhbCBkZSBiaWVuLiBQYXJhCiAgIGRpc3Rpbmd1aXJsb3MgaGFjZSBmYWx0YSBtZWRpY2lvbiByZXBldGlkYSwgY29tbyBlbiBlbCBlamVyY2ljaW8gMi4KMi4gKipWYXJpYW56YSBkZSBtZXRvZG8gY29tdW4uKiogUmVjdXBlcmFjaW9uLCBlbmVyZ2lhIHkgZW5nYWdlbWVudCBzZSBtaWRpZXJvbiBlbiBlbCBtaXNtbwogICBjdWVzdGlvbmFyaW8sIGNvbiBsYSBtaXNtYSBwZXJzb25hIHkgZW4gZWwgbWlzbW8gbW9tZW50by4gUGFydGUgZGUgbGFzIGNvcnJlbGFjaW9uZXMKICAgb2JzZXJ2YWRhcyBlcyBkZWwgaW5zdHJ1bWVudG8sIG5vIGRlIGxvcyBjb25zdHJ1Y3Rvcy4gRWwgZ3JhZGllbnRlIGRlIHByb3hpbWlkYWQgZW4gbG9zCiAgIGl0ZW1zIGRlIGVuZ2FnZW1lbnQgZXMgZXZpZGVuY2lhIGRpcmVjdGEgZGUgcXVlIGVzZSBlZmVjdG8gZXhpc3RlIGVuIGVzdGEgYmFzZS4KMy4gKipMYSBkZXB1cmFjaW9uIHNlIHZhbGlkbyBkZW50cm8gZGUgbGEgbWlzbWEgbXVlc3RyYS4qKiBFbiBlbCBlamVyY2ljaW8gMSBwdWRlIHVzYXIgbGFzCiAgIGRvcyBlc2N1ZWxhcyBjb21vIG11ZXN0cmFzIGRlIGRlc2N1YnJpbWllbnRvIHkgY29uZmlybWFjaW9uOyBlbiBlbCBlamVyY2ljaW8gMywgY29uCiAgIGByIG5yb3coZClgIGNhc29zLCBwYXJ0aXIgbGEgbXVlc3RyYSBoYWJyaWEgZGVqYWRvIHN1Ym11ZXN0cmFzIGRlbWFzaWFkbyBjaGljYXMgcGFyYSAyMQogICBpdGVtcy4gTG9zIGluZGljZXMgZGUgYWp1c3RlIGRlbCBtb2RlbG8gZGVwdXJhZG8gZXN0YW4gcG9yIGxvIHRhbnRvICoqb3B0aW1pc3RhcyoqLgo0LiAqKkxhIGVzY2FsYSBkZSBlbmdhZ2VtZW50IG5vIHNlIGRlcHVybyoqIHBvcnF1ZSBlbCBlbnVuY2lhZG8gbGEgZGEgcG9yIGRlcHVyYWRhLiBFcyBsYQogICBmdWVudGUgcHJpbmNpcGFsIGRlbCBkZXNhanVzdGUgZGVsIG1vZGVsbyBkZSBtZWRpY2lvbiwgeSBzdSBlc3RydWN0dXJhIHRlb3JpY2Egbm8gc2UKICAgc29zdGllbmUgZW4gZXN0YSBtdWVzdHJhLgo1LiAqKkxhIHJlcGxpY2FjaW9uIGRlbCBlamVyY2ljaW8gNCBwYXJ0ZSBkZSB1bmEgbWF0cml6IHB1YmxpY2FkYSoqLCBubyBkZSBsb3MgZGF0b3MKICAgb3JpZ2luYWxlcy4gTGFzIGRpZmVyZW5jaWFzIGNvbiBsbyByZXBvcnRhZG8gcHVlZGVuIGRlYmVyc2UgYSBkZWNpc2lvbmVzIGRlCiAgIGVzcGVjaWZpY2FjaW9uIGVuIExJU1JFTCBxdWUgZWwgYXJ0aWN1bG8gbm8gZG9jdW1lbnRhLgoKIyBSZWZlcmVuY2lhcwoKLSBCZWhzb24sIFMuIEouLCBFZGR5LCBFLiBSLiwgeSBMb3JlbnpldCwgUy4gSi4gKDIwMDApLiBUaGUgaW1wb3J0YW5jZSBvZiB0aGUgY3JpdGljYWwKICBwc3ljaG9sb2dpY2FsIHN0YXRlcyBpbiB0aGUgam9iIGNoYXJhY3RlcmlzdGljcyBtb2RlbDogQSBtZXRhLWFuYWx5dGljIGFuZCBzdHJ1Y3R1cmFsCiAgZXF1YXRpb25zIG1vZGVsaW5nIGV4YW1pbmF0aW9uLiAqQ3VycmVudCBSZXNlYXJjaCBpbiBTb2NpYWwgUHN5Y2hvbG9neSwgNSooMTIpLCAxNzAtLTE4OS4KLSBCb2xsZW4sIEsuIEEuICgxOTg5KS4gKlN0cnVjdHVyYWwgZXF1YXRpb25zIHdpdGggbGF0ZW50IHZhcmlhYmxlcyouIFdpbGV5LgotIEhhY2ttYW4sIEouIFIuLCB5IE9sZGhhbSwgRy4gUi4gKDE5NzYpLiBNb3RpdmF0aW9uIHRocm91Z2ggdGhlIGRlc2lnbiBvZiB3b3JrOiBUZXN0IG9mIGEKICB0aGVvcnkuICpPcmdhbml6YXRpb25hbCBCZWhhdmlvciBhbmQgSHVtYW4gUGVyZm9ybWFuY2UsIDE2KigyKSwgMjUwLS0yNzkuCi0gSG9semluZ2VyLCBLLiBKLiwgeSBTd2luZWZvcmQsIEYuICgxOTM5KS4gKkEgc3R1ZHkgaW4gZmFjdG9yIGFuYWx5c2lzOiBUaGUgc3RhYmlsaXR5IG9mIGEKICBiaS1mYWN0b3Igc29sdXRpb24qLiBVbml2ZXJzaXR5IG9mIENoaWNhZ28uCi0gSHUsIEwuLCB5IEJlbnRsZXIsIFAuIE0uICgxOTk5KS4gQ3V0b2ZmIGNyaXRlcmlhIGZvciBmaXQgaW5kZXhlcyBpbiBjb3ZhcmlhbmNlIHN0cnVjdHVyZQogIGFuYWx5c2lzLiAqU3RydWN0dXJhbCBFcXVhdGlvbiBNb2RlbGluZywgNiooMSksIDEtLTU1LgotIEtlbm55LCBELiBBLiwgS2FuaXNrYW4sIEIuLCB5IE1jQ29hY2gsIEQuIEIuICgyMDE1KS4gVGhlIHBlcmZvcm1hbmNlIG9mIFJNU0VBIGluIG1vZGVscwogIHdpdGggc21hbGwgZGVncmVlcyBvZiBmcmVlZG9tLiAqU29jaW9sb2dpY2FsIE1ldGhvZHMgYW5kIFJlc2VhcmNoLCA0NCooMyksIDQ4Ni0tNTA3LgotIFJvc3NlZWwsIFkuICgyMDEyKS4gbGF2YWFuOiBBbiBSIHBhY2thZ2UgZm9yIHN0cnVjdHVyYWwgZXF1YXRpb24gbW9kZWxpbmcuCiAgKkpvdXJuYWwgb2YgU3RhdGlzdGljYWwgU29mdHdhcmUsIDQ4KigyKSwgMS0tMzYuCi0gU2NoYXVmZWxpLCBXLiBCLiwgeSBCYWtrZXIsIEEuIEIuICgyMDAzKS4gKlVXRVM6IFV0cmVjaHQgV29yayBFbmdhZ2VtZW50IFNjYWxlKi4KICBPY2N1cGF0aW9uYWwgSGVhbHRoIFBzeWNob2xvZ3kgVW5pdCwgVXRyZWNodCBVbml2ZXJzaXR5LgoKYGBge3Igc2VzaW9uLCBlY2hvPUZBTFNFfQprYWJsZShkYXRhLmZyYW1lKENvbXBvbmVudGUgPSBjKCJSIiwgImxhdmFhbiIsICJTZW1pbGxhIiwgIk9ic2VydmFjaW9uZXMiKSwKICAgICAgICAgICAgICAgICBWYWxvciA9IGMoUi52ZXJzaW9uLnN0cmluZywgYXMuY2hhcmFjdGVyKHBhY2thZ2VWZXJzaW9uKCJsYXZhYW4iKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDI2IiwgbnJvdyhkKSkpLAogICAgICBjYXB0aW9uID0gIkVudG9ybm8gZGUgZWplY3VjaW9uIikKYGBgCg==