Objetivos

OBJETIVO GENERAL

Determinar los factores que intervienen en el pronóstico de sobrevida pulpar de dientes permanentes con desarrollo radicular incompleto que sufren algún tipo de fractura coronaria.

OBJETIVOS ESPECÍFICOS

  • Determinar si la presencia de malos hábitos, traumatismos repetidos y control inadecuado de la higiene (por sÍ solos o asociados) influyen en el pronóstico de sobrevida pulpar de dientes permanentes con desarrollo radicular incompleto que sufren fracturas coronarias.
  • Obtener un orden de relevancia de los factores que intervienen en el pronóstico de sobrevida de dientes permanentes con desarrollo radicular incompleto que sufren fracturas coronarias.
  • Generar un protocolo de abordaje de dientes permanentes con desarrollo radicular incompleto que sufren fracturas coronarias.

Paquetes

Paquetes especÍficos

Dataset


df <- read_csv("https://docs.google.com/spreadsheets/d/e/2PACX-1vSHQ17f-felEDBHEx2uz0Jjst-_z6wHTfB7hSFHD1iX8XWwd6GYTOYBo5F8DXjLGdxpTk9BqUt_M0lG/pub?gid=1995037555&single=true&output=csv")
glimpse(df) 

Data manipulation

Creo una nueva variable: status

Pronóstico pulpar: Variable dependiente. Evaluado con radiografÍa periapical. - Buen pronóstico: (PS) sobrevivencia de la Pulpa - Sin cambio radiográfico, signos clÍnicos de vitalidad pulpar. - PCO: obliteración del conducto pulpar. - Detención del crecimiento radicular, conducto pulpar normal, longitud radicular disminuida en comparación con el homólogo.

  • Mal pronóstico: (PN) necrosis pulpar, observando amplitud del conducto radicular, espesor disminuido de paredes radiculares con o sin lesión apical - Desarrollo radicular completo, con tratamiento de endodoncia. - Detención del crecimiento radicular, con tratamiento de endodoncia.

Entonces

Sobrevida si - PCO - Detención crecimiento radicular, pulpa vital - Sin cambio rx

Sobrevida no - Desarrollo Radicular completo, con endodoncia - Detención crecimiento radicular, con endodoncia

Variables importantes

  • tiempo
  • evento
  • independientes

Tiempo

cambio las fechas a aaaa/mm/dd y calculo la diferencia en años

df <- df %>% 
  mutate(
    `FECHA TRAUMATISMO` = dmy(`FECHA TRAUMATISMO`), 
    `FECHA SOBREVIDA` = dmy(`FECHA SOBREVIDA`), 
    `FECHA DE NACIMIENTO` = dmy(`FECHA DE NACIMIENTO`)
  )

# creo time y edad

df <- df %>% 
  mutate(
    time = difftime(`FECHA SOBREVIDA`, `FECHA TRAUMATISMO`, units = "weeks") / 52.25, 
    edad =  difftime(`FECHA TRAUMATISMO`, `FECHA DE NACIMIENTO`, units = "weeks")/52.25 # edad en años
  )

Eventos

Creo una nueva variable que será el evento = 1 (si) en caso que haya algo negativo y no (0) en caso que no haya pasado nada malo

df <-  df %>% 
  mutate(
    Evento = case_when(
      `SOBREVIDA PULPAR` == "PCO" |
        `SOBREVIDA PULPAR` == "Detención crecimiento radicular, pulpa vital" |
        `SOBREVIDA PULPAR` == "Sin cambio rx" ~ 0, 
      TRUE ~ 1

    )
  )

Veo cuantos eventos hay

table(df$Evento)

Dataset clean

CORREGIDO Hay dos valores negativos, mientras los elimino

which(df\(time > 0) df[df\)time < 0, ] # ubico a la que es menor df\(time df[df\)time < 1, ] df <- df[-c(65), ] # elimino la 65 mientras tanto VERIFICAR!!!!

which(df\(edad < 0) df[df\)edad < 1, ] # hay uno que tiene edad negativa, verificar, mientras lo saco del análisis df <- df[-c(77), ]

summary(df)

Survival analysis

Creo el objeto estándar de sobrevida

km <-  with(df, Surv(time, Evento == 1))
head(km, 50)

Análisis de Kaplan Meier

Ahora el análisis de KM

km_fit <- survfit(Surv(time, Evento) ~ 1, data = df)
summary(km_fit)

Estos datos se leen de la siguiente manera:

  • en la columna time aparece el tiempo. Este es el eje X del gráfico;
  • en n.risk el n de individuos en riesgo;
  • en n.event la cantidad de eventos en ese perÍodo;
  • en survival la función de sobrevida. Corresponde al eje Y del gráfico;
  • luego el error std y los intervalos de confianza, que aparecen marcados en tono gris.
km_fit
autoplot(km_fit, 
         main = "Análisis de sobrevida Kaplan Meier para estado pulpar",
         xlab = "Años", ylab = "Probabilidad de sobrevida")

ggsurvplot(km_fit, main = "Survival curve",
   font.main = 18,
   font.x =  16,
   font.y = 16,
   font.tickslab = 14, 
   palette = "Dark Blue", 
   legend = "none", 
   ggtheme = theme_pubclean() ) +
        labs(y = "Probabilidad de sobrevida", x = "Años", 
             title = "Curva de Kaplan-Meier para sobrevida pulpar")

Ahora examino por algunas variables: sexo, dgo del trauma


autoplot(
  survfit(Surv(time, Evento) ~ GÉNERO, data = df), 
         main = "Análisis de sobrevida Kaplan Meier para estado pulpar por sexo",
         xlab = "Años", ylab = "Probabilidad de sobrevida"
) +
        theme(text = element_text(size=20))
autoplot(
  survfit(Surv(time, Evento) ~ DIAGNÓSTICO, data = df), 
          main = "Análisis de sobrevida Kaplan Meier para estado pulpar por tipo de trauma",
         xlab = "Años", ylab = "Probabilidad de sobrevida"
) +
        theme(text = element_text(size=20))

19 dic hacer solo para FCNC con y sin luxación

df_soloFCNC <- df %>% 
       filter(DIAGNÓSTICO %in% c("FCNC sin luxación", "FCNC con luxación")) 




autoplot(
  survfit(Surv(time, Evento) ~ DIAGNÓSTICO, data = df_soloFCNC), 
          main = "Análisis de sobrevida Kaplan Meier para estado pulpar por tipo de trauma",
         xlab = "Años", ylab = "Probabilidad de sobrevida"
) +
        theme(text = element_text(size=20))

Análisis de Cox

El propósito del modelo de Cox es evaluar simultáneamente el efecto de varios factores en la supervivencia. Nos permite examinar cómo diversos influyen en la tasa de un evento en particular que ocurre (por ejemplo, infección, muerte) en un momento particular. Esta tasa se conoce comúnmente como la tasa de riesgo (hazard rate). Las variables (o factores) del predictor generalmente se denominan covariables en la literatura de análisis de supervivencia.

h(t)=h0(t)×exp(b1x1+b2x2+…+bpxp) h(t)=h0(t)×exp(b1x1+b2x2+…+bpxp)

donde,

  • t representa el tiempo de supervivencia
  • h (t) h (t) es la función de riesgo determinada por un conjunto de covariables p (x1, x2, …, xpx1, x2, …, xp)
  • los coeficientes (b1, b2, …, bpb1, b2, …, bp) miden el impacto (es decir, el tamaño del efecto) de las covariables. el término h0h0 se llama riesgo de referencia. Corresponde al valor del peligro si todos los xixi son iguales a cero (la cantidad exp (0) es igual a 1). La ‘t’ en h (t) nos recuerda que el peligro puede variar con el tiempo.

El modelo de Cox se puede escribir como una regresión lineal múltiple del logaritmo del peligro en las variables xixi, con el riesgo de la lÍnea de base como un término de “intercepción” que varÍa con el tiempo.

Las cantidades exp (bi) exp (bi) se denominan relaciones de riesgo (HR). Un valor de bibi mayor que cero, o equivalente a una razón de riesgo mayor que uno, indica que a medida que el valor de la novena covariable aumenta, el riesgo de evento aumenta y, por lo tanto, la duración de la supervivencia disminuye.

Dicho de otra manera, una razón de riesgo superior a 1 indica una covariable que está asociada positivamente con la probabilidad del evento y, por lo tanto, está asociada negativamente con la duración de la supervivencia.

En resumen,

HR = 1: sin efecto HR < 1: reducción en el riesgo HR > 1: aumento de riesgo


res.cox1 <- coxph(km ~ 
                    edad + 
                    `DIENTE AFECTADO` +
                    GÉNERO + 
                    DIAGNÓSTICO + 
                    `TRAUMATISMO REPETIDO` +
                    `TRAUMATISMO PREVIO`,
                  data =  df)

Chequeo por si se viola el riesgo proporcional (constante HR en el tiempo)

(res.zph1 <- cox.zph(res.cox1))

No se viola, asÍ que estamos OK

Ahora examino con detalle el modelo de Cox

summary(res.cox1)

Esto se lee de la siguiente manera

individuos que tienen más edad tienen más probabilidad (0.4841) de tener el evento, mientras que ser sexo masculino disminuye el riesgo (-0.0337) de tener el evento.

¿Cuanto?

UN aumento de Edad aumenta un 62% el riesgo de tener el evento, con un ic95% entre 05% y 149% (restale uno a los coeficientes)

cox_fit <- survfit(res.cox1)
autoplot(cox_fit)


aa_fit <-aareg(Surv(time, Evento) ~ 
                 `DIENTE AFECTADO` +
                    GÉNERO + 
                    DIAGNÓSTICO + 
                    `TRAUMATISMO REPETIDO` +
                    df$`TRAUMATISMO PREVIO`,
                  data =  df)

autoplot(aa_fit)

TODOS

modelo_0 <- coxph(km ~ 
                    df$GÉNERO + 
                    df$`DIENTE AFECTADO` +
                    df$DIAGNÓSTICO + 
                    df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    df$`ESTADO RADICULAR INICIAL` + 
                    df$`TRAUMATISMO REPETIDO` + 
                    df$`TRAUMATISMO PREVIO` + 
                    df$`INDICACIÓN DE HIGIENE` + 
                    df$`EVALUACIÓN DE HIGIENE` + 
                    df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_0)

TRAUMATISMO PREVIO

modelo 1

modelo 1.1 traumatismo repetido por si solo

modelo_1.1 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    # df$`ESTADO RADICULAR INICIAL` + 
                     df$`TRAUMATISMO REPETIDO`,
                    # df$`TRAUMATISMO PREVIO` + 
                    # df$`INDICACIÓN DE HIGIENE` + 
                    # df$`EVALUACIÓN DE HIGIENE` + 
                    #df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_1.1)

modelo 1.2 traumatismo previo por si solo

modelo_1.2 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    # df$`ESTADO RADICULAR INICIAL` + 
                    #  df$`TRAUMATISMO REPETIDO`,
                     df$`TRAUMATISMO PREVIO`,
                    # df$`INDICACIÓN DE HIGIENE` + 
                    # df$`EVALUACIÓN DE HIGIENE` + 
                    #df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_1.2)

EVALUACIÓN DE HIGIENE

modelo 2: indicación y evaluación de higiene

modelo_2 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    # df$`ESTADO RADICULAR INICIAL` + 
                    # df$`TRAUMATISMO REPETIDO`,
                    # df$`TRAUMATISMO PREVIO` + 
                     df$`INDICACIÓN DE HIGIENE` + 
                     df$`EVALUACIÓN DE HIGIENE`,
                    #df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_2)

modelo 2.1 indicación de higiene por si solo

modelo_2.1 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    # df$`ESTADO RADICULAR INICIAL` + 
                    # df$`TRAUMATISMO REPETIDO`,
                    # df$`TRAUMATISMO PREVIO` + 
                     df$`INDICACIÓN DE HIGIENE`, 
                    # df$`EVALUACIÓN DE HIGIENE` + 
                    #df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_2.1)

modelo 2.2 evaluación de higiene por si solo

modelo_2.2 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    # df$`ESTADO RADICULAR INICIAL` + 
                    # df$`TRAUMATISMO REPETIDO`,
                    # df$`TRAUMATISMO PREVIO` + 
                    # df$`INDICACIÓN DE HIGIENE` + 
                     df$`EVALUACIÓN DE HIGIENE`,
                    #df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_2.2)

ONICOFAGIA - INTERPOSICIÓN DE OBJETOS

modelo 3: malos hábitos

modelo_3 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                    # df$`ESTADO RADICULAR INICIAL` + 
                    # df$`TRAUMATISMO REPETIDO`,
                    # df$`TRAUMATISMO PREVIO` + 
                    # df$`INDICACIÓN DE HIGIENE` + 
                    # df$`EVALUACIÓN DE HIGIENE` + 
                    df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_3)

ESTADO RADICULAR INICIAL

modelo 4: estado radicular moorres

modelo_4 <- coxph(km ~ 
                    # df$GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                    # df$DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                     df$`ESTADO RADICULAR INICIAL`,
                    # df$`TRAUMATISMO REPETIDO`,
                    # df$`TRAUMATISMO PREVIO` + 
                    # df$`INDICACIÓN DE HIGIENE` + 
                    # df$`EVALUACIÓN DE HIGIENE` + 
                    #df$`ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_4)

Modelo 99 que sugiero

modelo_99 <- coxph(km ~ 
                   GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                   DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                   `ESTADO RADICULAR INICIAL` + 
                    `TRAUMATISMO REPETIDO` +
                   `TRAUMATISMO PREVIO` + 
                    # df$`INDICACIÓN DE HIGIENE` + 
                    `EVALUACIÓN DE HIGIENE` + 
                    `ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)
summary(modelo_99)

Chequeo por si se viola el riesgo proporcional (constante HR en el tiempo)

(res.zph99 <- cox.zph(modelo_99))
cox_fit_99 <- survfit(modelo_99)
autoplot(cox_fit_99)

Ojo, la mediana no toca el 50%, por lo que da median = NA

cox_fit_99
summary(cox_fit_99)
aa_fit_99 <-aareg(Surv(time, Evento) ~ 
                  GÉNERO + 
                    # df$`DIENTE AFECTADO` +
                     DIAGNÓSTICO + 
                    # df$TRATAMIENTO + 
                    # df$`TIEMPO HASTA LA ATENCIÓN (en horas)` + 
                     `ESTADO RADICULAR INICIAL` + 
                     `TRAUMATISMO REPETIDO` +
                     `TRAUMATISMO PREVIO` + 
                    # df$`INDICACIÓN DE HIGIENE` + 
                     `EVALUACIÓN DE HIGIENE` + 
                     `ONICOFAGIA - INTERPOSICIÓN DE OBJETOS` , 
                  data =  df)

autoplot(aa_fit_99)

Tamaño muestral y potencia

hr = 2 # hazard ratio
hr0 = 1
pE = 0.8 # probabilidad del evento
pA = 0.5 # proporción en el grupo A
alpha = 0.05
beta = 0.20
(n=((qnorm(1-alpha/2)+qnorm(1-beta))/(log(hr)-log(hr0)))^2/(pA*(1-pA)*pE))
ceiling(n) # 82
(Power=pnorm((log(hr)-log(hr0))*sqrt(n*pA*(1-pA)*pE)-qnorm(1-alpha/2)))
LS0tDQp0aXRsZTogIkNveCBhbmFseXNpcyINCmRhdGU6IDIxIGRpYyAyMDE3DQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNCiMgT2JqZXRpdm9zDQojIyBPQkpFVElWTyBHRU5FUkFMDQpEZXRlcm1pbmFyIGxvcyBmYWN0b3JlcyBxdWUgaW50ZXJ2aWVuZW4gZW4gZWwgcHJvbsOzc3RpY28gZGUgc29icmV2aWRhIHB1bHBhciBkZSBkaWVudGVzIA0KcGVybWFuZW50ZXMgY29uIGRlc2Fycm9sbG8gcmFkaWN1bGFyIGluY29tcGxldG8gcXVlIHN1ZnJlbiBhbGfDg8K6biB0aXBvIGRlIGZyYWN0dXJhIA0KY29yb25hcmlhLiANCg0KIyMgT0JKRVRJVk9TIEVTUEVDw41GSUNPUw0KICAtIERldGVybWluYXIgc2kgbGEgcHJlc2VuY2lhIGRlIG1hbG9zIGjDoWJpdG9zLCB0cmF1bWF0aXNtb3MgcmVwZXRpZG9zIHkgY29udHJvbCBpbmFkZWN1YWRvIGRlIGxhIGhpZ2llbmUgKHBvciBzw40gc29sb3MgbyBhc29jaWFkb3MpIGluZmx1eWVuIGVuIGVsIHByb27Ds3N0aWNvIGRlIHNvYnJldmlkYSBwdWxwYXIgZGUgZGllbnRlcyBwZXJtYW5lbnRlcyBjb24gZGVzYXJyb2xsbyByYWRpY3VsYXIgaW5jb21wbGV0byBxdWUgc3VmcmVuIGZyYWN0dXJhcyBjb3JvbmFyaWFzLiANCiAgLSBPYnRlbmVyIHVuIG9yZGVuIGRlIHJlbGV2YW5jaWEgZGUgbG9zIGZhY3RvcmVzIHF1ZSBpbnRlcnZpZW5lbiBlbiBlbCBwcm9uw7NzdGljbyBkZSBzb2JyZXZpZGEgZGUgZGllbnRlcyBwZXJtYW5lbnRlcyBjb24gZGVzYXJyb2xsbyByYWRpY3VsYXIgaW5jb21wbGV0byBxdWUgc3VmcmVuIGZyYWN0dXJhcyBjb3JvbmFyaWFzLiANCiAgLSBHZW5lcmFyIHVuIHByb3RvY29sbyBkZSBhYm9yZGFqZSBkZSBkaWVudGVzIHBlcm1hbmVudGVzIGNvbiBkZXNhcnJvbGxvIHJhZGljdWxhciBpbmNvbXBsZXRvIHF1ZSBzdWZyZW4gZnJhY3R1cmFzIGNvcm9uYXJpYXMuDQogIA0KIyBQYXF1ZXRlcw0KDQpgYGB7ciBwYXF1ZXRlcyB2YXJpb3MsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpQYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCAiZm9yY2F0cyIsICJzdHJpbmdyIiwgImJyb29tIiwgImx1YnJpZGF0ZSIpDQpsYXBwbHkoUGFja2FnZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCnJtKFBhY2thZ2VzKQ0KDQoNCg0KYGBgDQojIyBQYXF1ZXRlcyBlc3BlY8ONZmljb3MNCg0KYGBge3Igc3Vydml2YWwsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHN1cnZpdmFsKSAjIGZvciBjb21wdXRpbmcgc3Vydml2YWwgYW5hbHlzZXMNCmxpYnJhcnkoc3Vydm1pbmVyKSAjIGZvciB2aXN1YWxpemluZyBzdXJ2aXZhbCBhbmFseXNpcyByZXN1bHRzDQpsaWJyYXJ5KGdnZm9ydGlmeSkgIyBuaWNlIHBsb3Qgb2Ygc3Vydml2YWwgZnVuY3Rpb24NCmBgYA0KDQoNCiMgRGF0YXNldA0KDQpgYGB7ciByZWFkIGRmfQ0KDQpkZiA8LSByZWFkX2NzdigiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvZS8yUEFDWC0xdlNIUTE3Zi1mZWxFREJIRXgydXowSmpzdC1fejZ3SFRmQjdoU0ZIRDFpWDhYV3dkNkdZVE9ZQm81RjhEWGpMR2R4cFRrOUJxVXRfTTBsRy9wdWI/Z2lkPTE5OTUwMzc1NTUmc2luZ2xlPXRydWUmb3V0cHV0PWNzdiIpDQpnbGltcHNlKGRmKSANCmBgYA0KDQojIyBEYXRhIG1hbmlwdWxhdGlvbg0KDQpDcmVvIHVuYSBudWV2YSB2YXJpYWJsZTogc3RhdHVzDQoNClByb27Ds3N0aWNvIHB1bHBhcjogVmFyaWFibGUgZGVwZW5kaWVudGUuIEV2YWx1YWRvIGNvbiByYWRpb2dyYWbDjWEgcGVyaWFwaWNhbC4gDQogICAtICoqQnVlbiBwcm9uw7NzdGljbyoqOiAoUFMpIHNvYnJldml2ZW5jaWEgZGUgbGEgUHVscGEgDQogICAgICAtIFNpbiBjYW1iaW8gcmFkaW9ncsOhZmljbywgc2lnbm9zIGNsw41uaWNvcyBkZSB2aXRhbGlkYWQgcHVscGFyLiANCiAgICAgIC0gUENPOiBvYmxpdGVyYWNpw7NuIGRlbCBjb25kdWN0byBwdWxwYXIuIA0KICAgICAgLSBEZXRlbmNpw7NuIGRlbCBjcmVjaW1pZW50byByYWRpY3VsYXIsIGNvbmR1Y3RvIHB1bHBhciBub3JtYWwsIGxvbmdpdHVkIA0KcmFkaWN1bGFyIGRpc21pbnVpZGEgZW4gY29tcGFyYWNpw7NuIGNvbiBlbCBob23Ds2xvZ28uDQoNCg0KICAgLSAqKk1hbCBwcm9uw7NzdGljbyoqOiAoUE4pIG5lY3Jvc2lzIHB1bHBhciwgb2JzZXJ2YW5kbyBhbXBsaXR1ZCBkZWwgY29uZHVjdG8gcmFkaWN1bGFyLCBlc3Blc29yIGRpc21pbnVpZG8gZGUgcGFyZWRlcyByYWRpY3VsYXJlcyBjb24gbyBzaW4gbGVzacOzbiBhcGljYWwNCiAgICAgICAgLSBEZXNhcnJvbGxvIHJhZGljdWxhciBjb21wbGV0bywgY29uIHRyYXRhbWllbnRvIGRlIGVuZG9kb25jaWEuIA0KICAgICAgICAtIERldGVuY2nDs24gZGVsIGNyZWNpbWllbnRvIHJhZGljdWxhciwgY29uIHRyYXRhbWllbnRvIGRlIGVuZG9kb25jaWEuIA0KDQpFbnRvbmNlcw0KDQoNCioqU29icmV2aWRhIHNpKioNCiAgLSBQQ08NCiAgLSBEZXRlbmNpw7NuIGNyZWNpbWllbnRvIHJhZGljdWxhciwgcHVscGEgdml0YWwNCiAgLSBTaW4gY2FtYmlvIHJ4DQoNCg0KKipTb2JyZXZpZGEgbm8qKg0KICAtIERlc2Fycm9sbG8gUmFkaWN1bGFyIGNvbXBsZXRvLCBjb24gZW5kb2RvbmNpYSANCiAgLSBEZXRlbmNpw7NuIGNyZWNpbWllbnRvIHJhZGljdWxhciwgY29uIGVuZG9kb25jaWEgDQoNCg0KDQoNCiMjIFZhcmlhYmxlcyBpbXBvcnRhbnRlcw0KDQogLSB0aWVtcG8NCiAtIGV2ZW50bw0KIC0gaW5kZXBlbmRpZW50ZXMNCg0KDQojIyMgVGllbXBvIA0KDQogY2FtYmlvIGxhcyBmZWNoYXMgYSBhYWFhL21tL2RkIHkgY2FsY3VsbyBsYSBkaWZlcmVuY2lhIGVuICoqYcOxb3MqKg0KYGBge3IgdGllbXBvIGVuIGHDsW9zfQ0KZGYgPC0gZGYgJT4lIA0KICBtdXRhdGUoDQogICAgYEZFQ0hBIFRSQVVNQVRJU01PYCA9IGRteShgRkVDSEEgVFJBVU1BVElTTU9gKSwgDQogICAgYEZFQ0hBIFNPQlJFVklEQWAgPSBkbXkoYEZFQ0hBIFNPQlJFVklEQWApLCANCiAgICBgRkVDSEEgREUgTkFDSU1JRU5UT2AgPSBkbXkoYEZFQ0hBIERFIE5BQ0lNSUVOVE9gKQ0KICApDQoNCiMgY3JlbyB0aW1lIHkgZWRhZA0KDQpkZiA8LSBkZiAlPiUgDQogIG11dGF0ZSgNCiAgICB0aW1lID0gZGlmZnRpbWUoYEZFQ0hBIFNPQlJFVklEQWAsIGBGRUNIQSBUUkFVTUFUSVNNT2AsIHVuaXRzID0gIndlZWtzIikgLyA1Mi4yNSwgDQogICAgZWRhZCA9ICBkaWZmdGltZShgRkVDSEEgVFJBVU1BVElTTU9gLCBgRkVDSEEgREUgTkFDSU1JRU5UT2AsIHVuaXRzID0gIndlZWtzIikvNTIuMjUgIyBlZGFkIGVuIGHDsW9zDQogICkNCg0KDQoNCmBgYA0KDQojIyMgRXZlbnRvcw0KQ3JlbyB1bmEgbnVldmEgdmFyaWFibGUgcXVlIHNlcsOhIGVsICoqZXZlbnRvKiogPSAxIChzaSkgZW4gY2FzbyBxdWUgaGF5YSBhbGdvIG5lZ2F0aXZvIHkgbm8gKDApIGVuIGNhc28gcXVlIG5vIGhheWEgcGFzYWRvIG5hZGEgbWFsbw0KDQpgYGB7ciBjcmVvIHZhciBldmVudG99DQpkZiA8LSAgZGYgJT4lIA0KICBtdXRhdGUoDQogICAgRXZlbnRvID0gY2FzZV93aGVuKA0KICAgICAgYFNPQlJFVklEQSBQVUxQQVJgID09ICJQQ08iIHwNCiAgICAgICAgYFNPQlJFVklEQSBQVUxQQVJgID09ICJEZXRlbmNpw7NuIGNyZWNpbWllbnRvIHJhZGljdWxhciwgcHVscGEgdml0YWwiIHwNCiAgICAgICAgYFNPQlJFVklEQSBQVUxQQVJgID09ICJTaW4gY2FtYmlvIHJ4IiB+IDAsIA0KICAgICAgVFJVRSB+IDENCg0KICAgICkNCiAgKQ0KDQoNCg0KYGBgDQpWZW8gY3VhbnRvcyBldmVudG9zIGhheSANCg0KYGBge3IgY3VhbnRvcyBldmVudG9zP30NCnRhYmxlKGRmJEV2ZW50bykNCmBgYA0KDQoNCg0KIyMgRGF0YXNldCBjbGVhbg0KQ09SUkVHSURPIEhheSBkb3MgdmFsb3JlcyBuZWdhdGl2b3MsIG1pZW50cmFzIGxvcyBlbGltaW5vDQoNCg0KIHdoaWNoKGRmJHRpbWUgPiAwKQ0KIGRmW2RmJHRpbWUgPCAwLCBdICMgdWJpY28gYSBsYSBxdWUgZXMgbWVub3INCiBkZiR0aW1lDQogZGZbZGYkdGltZSA8IDEsIF0NCiBkZiA8LSBkZlstYyg2NSksIF0gIyBlbGltaW5vIGxhIDY1IG1pZW50cmFzIHRhbnRvIFZFUklGSUNBUiEhISENCg0KIHdoaWNoKGRmJGVkYWQgPCAwKQ0KIGRmW2RmJGVkYWQgPCAxLCBdICMgaGF5IHVubyBxdWUgdGllbmUgZWRhZCBuZWdhdGl2YSwgdmVyaWZpY2FyLCBtaWVudHJhcyBsbyBzYWNvIGRlbCBhbsOhbGlzaXMNCiBkZiA8LSBkZlstYyg3NyksIF0NCg0KDQpgYGB7cn0NCnN1bW1hcnkoZGYpDQpgYGANCg0KDQojIFN1cnZpdmFsIGFuYWx5c2lzDQoNCkNyZW8gZWwgb2JqZXRvIGVzdMOhbmRhciBkZSBzb2JyZXZpZGEgDQoNCmBgYHtyIG9iamV0byBkZSBzb2JyZXZpZGF9DQprbSA8LSAgd2l0aChkZiwgU3Vydih0aW1lLCBFdmVudG8gPT0gMSkpDQpoZWFkKGttLCA1MCkNCmBgYA0KDQojIyBBbsOhbGlzaXMgZGUgS2FwbGFuIE1laWVyDQoNCkFob3JhIGVsIGFuw6FsaXNpcyBkZSBLTQ0KDQpgYGB7ciBhbmFsaXNpcyBLTX0NCmttX2ZpdCA8LSBzdXJ2Zml0KFN1cnYodGltZSwgRXZlbnRvKSB+IDEsIGRhdGEgPSBkZikNCnN1bW1hcnkoa21fZml0KQ0KYGBgDQoNCkVzdG9zIGRhdG9zIHNlIGxlZW4gZGUgbGEgc2lndWllbnRlIG1hbmVyYTogDQoNCiAgLSBlbiBsYSBjb2x1bW5hIHRpbWUgYXBhcmVjZSBlbCB0aWVtcG8uIEVzdGUgZXMgZWwgZWplIFggZGVsIGdyw6FmaWNvOyANCiAgLSBlbiBuLnJpc2sgZWwgbiBkZSBpbmRpdmlkdW9zIGVuIHJpZXNnbzsNCiAgLSBlbiBuLmV2ZW50IGxhIGNhbnRpZGFkIGRlIGV2ZW50b3MgZW4gZXNlIHBlcsONb2RvOw0KICAtIGVuIHN1cnZpdmFsIGxhIGZ1bmNpw7NuIGRlIHNvYnJldmlkYS4gQ29ycmVzcG9uZGUgYWwgZWplIFkgZGVsIGdyw6FmaWNvOyANCiAgLSBsdWVnbyBlbCBlcnJvciBzdGQgeSBsb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEsIHF1ZSBhcGFyZWNlbiBtYXJjYWRvcyBlbiB0b25vIGdyaXMuIA0KICANCmBgYHtyIHZlciBlbCBrbX0NCmttX2ZpdA0KDQoNCmBgYA0KDQoNCg0KYGBge3IgS00gcGxvdH0NCmF1dG9wbG90KGttX2ZpdCwgDQogICAgICAgICBtYWluID0gIkFuw6FsaXNpcyBkZSBzb2JyZXZpZGEgS2FwbGFuIE1laWVyIHBhcmEgZXN0YWRvIHB1bHBhciIsDQogICAgICAgICB4bGFiID0gIkHDsW9zIiwgeWxhYiA9ICJQcm9iYWJpbGlkYWQgZGUgc29icmV2aWRhIikNCmBgYA0KDQpgYGB7cn0NCg0KZ2dzdXJ2cGxvdChrbV9maXQsIG1haW4gPSAiU3Vydml2YWwgY3VydmUiLA0KICAgZm9udC5tYWluID0gMTgsDQogICBmb250LnggPSAgMTYsDQogICBmb250LnkgPSAxNiwNCiAgIGZvbnQudGlja3NsYWIgPSAxNCwgDQogICBwYWxldHRlID0gIkRhcmsgQmx1ZSIsIA0KICAgbGVnZW5kID0gIm5vbmUiLCANCiAgIGdndGhlbWUgPSB0aGVtZV9wdWJjbGVhbigpICkgKw0KICAgICAgICBsYWJzKHkgPSAiUHJvYmFiaWxpZGFkIGRlIHNvYnJldmlkYSIsIHggPSAiQcOxb3MiLCANCiAgICAgICAgICAgICB0aXRsZSA9ICJDdXJ2YSBkZSBLYXBsYW4tTWVpZXIgcGFyYSBzb2JyZXZpZGEgcHVscGFyIikNCmBgYA0KDQpBaG9yYSBleGFtaW5vIHBvciBhbGd1bmFzIHZhcmlhYmxlczogc2V4bywgZGdvIGRlbCB0cmF1bWENCg0KYGBge3IgcG9yIHNleG99DQoNCmF1dG9wbG90KA0KICBzdXJ2Zml0KFN1cnYodGltZSwgRXZlbnRvKSB+IEfDiU5FUk8sIGRhdGEgPSBkZiksIA0KICAgICAgICAgbWFpbiA9ICJBbsOhbGlzaXMgZGUgc29icmV2aWRhIEthcGxhbiBNZWllciBwYXJhIGVzdGFkbyBwdWxwYXIgcG9yIHNleG8iLA0KICAgICAgICAgeGxhYiA9ICJBw7FvcyIsIHlsYWIgPSAiUHJvYmFiaWxpZGFkIGRlIHNvYnJldmlkYSINCikgKw0KICAgICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjApKQ0KYGBgDQoNCg0KDQpgYGB7ciBwb3IgZGlhZ25vc3RpY299DQphdXRvcGxvdCgNCiAgc3VydmZpdChTdXJ2KHRpbWUsIEV2ZW50bykgfiBESUFHTsOTU1RJQ08sIGRhdGEgPSBkZiksIA0KICAgICAgICAgIG1haW4gPSAiQW7DoWxpc2lzIGRlIHNvYnJldmlkYSBLYXBsYW4gTWVpZXIgcGFyYSBlc3RhZG8gcHVscGFyIHBvciB0aXBvIGRlIHRyYXVtYSIsDQogICAgICAgICB4bGFiID0gIkHDsW9zIiwgeWxhYiA9ICJQcm9iYWJpbGlkYWQgZGUgc29icmV2aWRhIg0KKSArDQogICAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpDQpgYGANCg0KMTkgZGljDQpoYWNlciBzb2xvIHBhcmEgRkNOQyBjb24geSBzaW4gbHV4YWNpw7NuDQoNCg0KYGBge3J9DQpkZl9zb2xvRkNOQyA8LSBkZiAlPiUgDQogICAgICAgZmlsdGVyKERJQUdOw5NTVElDTyAlaW4lIGMoIkZDTkMgc2luIGx1eGFjacOzbiIsICJGQ05DIGNvbiBsdXhhY2nDs24iKSkgDQoNCg0KDQoNCmF1dG9wbG90KA0KICBzdXJ2Zml0KFN1cnYodGltZSwgRXZlbnRvKSB+IERJQUdOw5NTVElDTywgZGF0YSA9IGRmX3NvbG9GQ05DKSwgDQogICAgICAgICAgbWFpbiA9ICJBbsOhbGlzaXMgZGUgc29icmV2aWRhIEthcGxhbiBNZWllciBwYXJhIGVzdGFkbyBwdWxwYXIgcG9yIHRpcG8gZGUgdHJhdW1hIiwNCiAgICAgICAgIHhsYWIgPSAiQcOxb3MiLCB5bGFiID0gIlByb2JhYmlsaWRhZCBkZSBzb2JyZXZpZGEiDQopICsNCiAgICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkNCmBgYA0KDQojIyBBbsOhbGlzaXMgZGUgQ294DQoNCg0KRWwgcHJvcMOzc2l0byBkZWwgbW9kZWxvIGRlIENveCBlcyBldmFsdWFyIHNpbXVsdMOhbmVhbWVudGUgZWwgZWZlY3RvIGRlIHZhcmlvcyBmYWN0b3JlcyBlbiBsYSBzdXBlcnZpdmVuY2lhLiBOb3MgcGVybWl0ZSBleGFtaW5hciBjw7NtbyBkaXZlcnNvcyBpbmZsdXllbiBlbiBsYSB0YXNhIGRlIHVuIGV2ZW50byBlbiBwYXJ0aWN1bGFyIHF1ZSBvY3VycmUgKHBvciBlamVtcGxvLCBpbmZlY2Npw7NuLCBtdWVydGUpIGVuIHVuIG1vbWVudG8gcGFydGljdWxhci4gRXN0YSB0YXNhIHNlIGNvbm9jZSBjb23Dg8K6bm1lbnRlIGNvbW8gbGEgdGFzYSBkZSByaWVzZ28gKGhhemFyZCByYXRlKS4gTGFzIHZhcmlhYmxlcyAobyBmYWN0b3JlcykgZGVsIHByZWRpY3RvciBnZW5lcmFsbWVudGUgc2UgZGVub21pbmFuIGNvdmFyaWFibGVzIGVuIGxhIGxpdGVyYXR1cmEgZGUgYW7DoWxpc2lzIGRlIHN1cGVydml2ZW5jaWEuDQoNCg0KDQpoKHQpPWgwKHQpw4PCl2V4cChiMXgxK2IyeDIrLi4uK2JweHApDQpoKHQpPWgwKHQpw4PCl2V4cChiMXgxK2IyeDIrLi4uK2JweHApDQoNCmRvbmRlLA0KDQogIC0gKip0KiogcmVwcmVzZW50YSBlbCB0aWVtcG8gZGUgc3VwZXJ2aXZlbmNpYQ0KICAtICoqaCAodCkqKiBoICh0KSBlcyBsYSBmdW5jacOzbiBkZSByaWVzZ28gZGV0ZXJtaW5hZGEgcG9yIHVuIGNvbmp1bnRvIGRlIGNvdmFyaWFibGVzIHAgKHgxLCB4MiwgLi4uLCB4cHgxLCB4MiwgLi4uLCB4cCkNCiAgLSAqKmxvcyBjb2VmaWNpZW50ZXMqKiAoYjEsIGIyLCAuLi4sIGJwYjEsIGIyLCAuLi4sIGJwKSBtaWRlbiBlbCBpbXBhY3RvIChlcyBkZWNpciwgZWwgdGFtYcOxbyBkZWwgZWZlY3RvKSBkZSBsYXMgY292YXJpYWJsZXMuDQplbCB0w4PCqXJtaW5vIGgwaDAgc2UgbGxhbWEgcmllc2dvIGRlIHJlZmVyZW5jaWEuIENvcnJlc3BvbmRlIGFsIHZhbG9yIGRlbCBwZWxpZ3JvIHNpIHRvZG9zIGxvcyB4aXhpIHNvbiBpZ3VhbGVzIGEgY2VybyAobGEgY2FudGlkYWQgZXhwICgwKSBlcyBpZ3VhbCBhIDEpLiBMYSAndCcgZW4gaCAodCkgbm9zIHJlY3VlcmRhIHF1ZSBlbCBwZWxpZ3JvIHB1ZWRlIHZhcmlhciBjb24gZWwgdGllbXBvLg0KDQpFbCBtb2RlbG8gZGUgQ294IHNlIHB1ZWRlIGVzY3JpYmlyIGNvbW8gdW5hIHJlZ3Jlc2nDs24gbGluZWFsIG3Dg8K6bHRpcGxlIGRlbCBsb2dhcml0bW8gZGVsIHBlbGlncm8gZW4gbGFzIHZhcmlhYmxlcyB4aXhpLCBjb24gZWwgcmllc2dvIGRlIGxhIGzDjW5lYSBkZSBiYXNlIGNvbW8gdW4gdMODwqlybWlubyBkZSAiaW50ZXJjZXBjacOzbiIgcXVlIHZhcsONYSBjb24gZWwgdGllbXBvLg0KDQpMYXMgY2FudGlkYWRlcyBleHAgKGJpKSBleHAgKGJpKSBzZSBkZW5vbWluYW4gcmVsYWNpb25lcyBkZSByaWVzZ28gKEhSKS4gVW4gdmFsb3IgZGUgYmliaSBtYXlvciBxdWUgY2VybywgbyBlcXVpdmFsZW50ZSBhIHVuYSByYXrDs24gZGUgcmllc2dvIG1heW9yIHF1ZSB1bm8sIGluZGljYSBxdWUgYSBtZWRpZGEgcXVlIGVsIHZhbG9yIGRlIGxhIG5vdmVuYSBjb3ZhcmlhYmxlIGF1bWVudGEsIGVsIHJpZXNnbyBkZSBldmVudG8gYXVtZW50YSB5LCBwb3IgbG8gdGFudG8sIGxhIGR1cmFjacOzbiBkZSBsYSBzdXBlcnZpdmVuY2lhIGRpc21pbnV5ZS4NCg0KRGljaG8gZGUgb3RyYSBtYW5lcmEsIHVuYSByYXrDs24gZGUgcmllc2dvIHN1cGVyaW9yIGEgMSBpbmRpY2EgdW5hIGNvdmFyaWFibGUgcXVlIGVzdMOhIGFzb2NpYWRhIHBvc2l0aXZhbWVudGUgY29uIGxhIHByb2JhYmlsaWRhZCBkZWwgZXZlbnRvIHksIHBvciBsbyB0YW50bywgZXN0w6EgYXNvY2lhZGEgbmVnYXRpdmFtZW50ZSBjb24gbGEgZHVyYWNpw7NuIGRlIGxhIHN1cGVydml2ZW5jaWEuDQoNCkVuIHJlc3VtZW4sDQoNCkhSID0gMTogc2luIGVmZWN0bw0KSFIgPCAxOiByZWR1Y2Npw7NuIGVuIGVsIHJpZXNnbw0KSFIgPiAxOiBhdW1lbnRvIGRlIHJpZXNnbw0KDQoNCg0KDQpgYGB7ciBDb3h9DQoNCnJlcy5jb3gxIDwtIGNveHBoKGttIH4gDQogICAgICAgICAgICAgICAgICAgIGVkYWQgKyANCiAgICAgICAgICAgICAgICAgICAgYERJRU5URSBBRkVDVEFET2AgKw0KICAgICAgICAgICAgICAgICAgICBHw4lORVJPICsgDQogICAgICAgICAgICAgICAgICAgIERJQUdOw5NTVElDTyArIA0KICAgICAgICAgICAgICAgICAgICBgVFJBVU1BVElTTU8gUkVQRVRJRE9gICsNCiAgICAgICAgICAgICAgICAgICAgYFRSQVVNQVRJU01PIFBSRVZJT2AsDQogICAgICAgICAgICAgICAgICBkYXRhID0gIGRmKQ0KDQoNCmBgYA0KDQoNCkNoZXF1ZW8gcG9yIHNpIHNlIHZpb2xhIGVsIHJpZXNnbyBwcm9wb3JjaW9uYWwgKGNvbnN0YW50ZSBIUiBlbiBlbCB0aWVtcG8pDQoNCmBgYHtyIHJpZXNnbyBwcm9wb3JjaW9uYWw/fQ0KKHJlcy56cGgxIDwtIGNveC56cGgocmVzLmNveDEpKQ0KYGBgDQoNCk5vIHNlIHZpb2xhLCBhc8ONIHF1ZSBlc3RhbW9zIE9LDQoNCkFob3JhIGV4YW1pbm8gY29uIGRldGFsbGUgZWwgbW9kZWxvIGRlIENveA0KDQpgYGB7ciByZXN1bWVuIG1vZGVsbyByZXMuY294MX0NCnN1bW1hcnkocmVzLmNveDEpDQpgYGANCkVzdG8gc2UgbGVlIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmENCg0KaW5kaXZpZHVvcyBxdWUgdGllbmVuIG3DoXMgZWRhZCB0aWVuZW4gbcOhcyBwcm9iYWJpbGlkYWQgKDAuNDg0MSkgZGUgdGVuZXIgZWwgZXZlbnRvLCBtaWVudHJhcyBxdWUgc2VyIHNleG8gbWFzY3VsaW5vIGRpc21pbnV5ZSBlbCByaWVzZ28gKC0wLjAzMzcpIGRlIHRlbmVyIGVsIGV2ZW50by4gDQoNCsOCwr9DdWFudG8/DQoNClVOIGF1bWVudG8gZGUgRWRhZCBhdW1lbnRhIHVuIDYyJSBlbCByaWVzZ28gZGUgdGVuZXIgZWwgZXZlbnRvLCBjb24gdW4gaWM5NSUgZW50cmUgMDUlIHkgMTQ5JSAocmVzdGFsZSB1bm8gYSBsb3MgY29lZmljaWVudGVzKQ0KDQoNCg0KDQpgYGB7ciBncmFmaWNvIHJlcy5jb3gxfQ0KY294X2ZpdCA8LSBzdXJ2Zml0KHJlcy5jb3gxKQ0KYXV0b3Bsb3QoY294X2ZpdCkNCmBgYA0KDQpgYGB7ciBwcmltZXIgZ3JhZmljbyBzZXBhcmFkb30NCg0KDQphYV9maXQgPC1hYXJlZyhTdXJ2KHRpbWUsIEV2ZW50bykgfiANCiAgICAgICAgICAgICAgICAgYERJRU5URSBBRkVDVEFET2AgKw0KICAgICAgICAgICAgICAgICAgICBHw4lORVJPICsgDQogICAgICAgICAgICAgICAgICAgIERJQUdOw5NTVElDTyArIA0KICAgICAgICAgICAgICAgICAgICBgVFJBVU1BVElTTU8gUkVQRVRJRE9gICsNCiAgICAgICAgICAgICAgICAgICAgZGYkYFRSQVVNQVRJU01PIFBSRVZJT2AsDQogICAgICAgICAgICAgICAgICBkYXRhID0gIGRmKQ0KDQphdXRvcGxvdChhYV9maXQpDQpgYGANCg0KDQoNCiMjIyBUT0RPUw0KDQpgYGB7ciBDb3ggdG9kb3N9DQptb2RlbG9fMCA8LSBjb3hwaChrbSB+IA0KICAgICAgICAgICAgICAgICAgICBkZiRHw4lORVJPICsgDQogICAgICAgICAgICAgICAgICAgIGRmJGBESUVOVEUgQUZFQ1RBRE9gICsNCiAgICAgICAgICAgICAgICAgICAgZGYkRElBR07Dk1NUSUNPICsgDQogICAgICAgICAgICAgICAgICAgIGRmJFRSQVRBTUlFTlRPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYFRJRU1QTyBIQVNUQSBMQSBBVEVOQ0nDk04gKGVuIGhvcmFzKWAgKyANCiAgICAgICAgICAgICAgICAgICAgZGYkYEVTVEFETyBSQURJQ1VMQVIgSU5JQ0lBTGAgKyANCiAgICAgICAgICAgICAgICAgICAgZGYkYFRSQVVNQVRJU01PIFJFUEVUSURPYCArIA0KICAgICAgICAgICAgICAgICAgICBkZiRgVFJBVU1BVElTTU8gUFJFVklPYCArIA0KICAgICAgICAgICAgICAgICAgICBkZiRgSU5ESUNBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgZGYkYEVWQUxVQUNJw5NOIERFIEhJR0lFTkVgICsgDQogICAgICAgICAgICAgICAgICAgIGRmJGBPTklDT0ZBR0lBIC0gSU5URVJQT1NJQ0nDk04gREUgT0JKRVRPU2AgLCANCiAgICAgICAgICAgICAgICAgIGRhdGEgPSAgZGYpDQoNCmBgYA0KDQpgYGB7ciBtb2RlbG8gMCByZXN1bWVufQ0Kc3VtbWFyeShtb2RlbG9fMCkNCmBgYA0KDQoNCiMjIyBUUkFVTUFUSVNNTyBQUkVWSU8NCiMjIyMgbW9kZWxvIDENCiMjIyMgbW9kZWxvIDEuMSB0cmF1bWF0aXNtbyByZXBldGlkbyBwb3Igc2kgc29sbw0KYGBge3IgbW9kZWxvIDEuMX0NCm1vZGVsb18xLjEgPC0gY294cGgoa20gfiANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRHw4lORVJPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYERJRU5URSBBRkVDVEFET2AgKw0KICAgICAgICAgICAgICAgICAgICAjIGRmJERJQUdOw5NTVElDTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJFRSQVRBTUlFTlRPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYFRJRU1QTyBIQVNUQSBMQSBBVEVOQ0nDk04gKGVuIGhvcmFzKWAgKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgRVNUQURPIFJBRElDVUxBUiBJTklDSUFMYCArIA0KICAgICAgICAgICAgICAgICAgICAgZGYkYFRSQVVNQVRJU01PIFJFUEVUSURPYCwNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVFJBVU1BVElTTU8gUFJFVklPYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBJTkRJQ0FDScOTTiBERSBISUdJRU5FYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBFVkFMVUFDScOTTiBERSBISUdJRU5FYCArIA0KICAgICAgICAgICAgICAgICAgICAjZGYkYE9OSUNPRkFHSUEgLSBJTlRFUlBPU0lDScOTTiBERSBPQkpFVE9TYCAsIA0KICAgICAgICAgICAgICAgICAgZGF0YSA9ICBkZikNCnN1bW1hcnkobW9kZWxvXzEuMSkNCmBgYA0KDQojIyMjIG1vZGVsbyAxLjIgdHJhdW1hdGlzbW8gcHJldmlvIHBvciBzaSBzb2xvDQpgYGB7ciBtb2RlbG8gMS4yfQ0KbW9kZWxvXzEuMiA8LSBjb3hwaChrbSB+IA0KICAgICAgICAgICAgICAgICAgICAjIGRmJEfDiU5FUk8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgRElFTlRFIEFGRUNUQURPYCArDQogICAgICAgICAgICAgICAgICAgICMgZGYkRElBR07Dk1NUSUNPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkVFJBVEFNSUVOVE8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVElFTVBPIEhBU1RBIExBIEFURU5DScOTTiAoZW4gaG9yYXMpYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBFU1RBRE8gUkFESUNVTEFSIElOSUNJQUxgICsgDQogICAgICAgICAgICAgICAgICAgICMgIGRmJGBUUkFVTUFUSVNNTyBSRVBFVElET2AsDQogICAgICAgICAgICAgICAgICAgICBkZiRgVFJBVU1BVElTTU8gUFJFVklPYCwNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgSU5ESUNBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgRVZBTFVBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgI2RmJGBPTklDT0ZBR0lBIC0gSU5URVJQT1NJQ0nDk04gREUgT0JKRVRPU2AgLCANCiAgICAgICAgICAgICAgICAgIGRhdGEgPSAgZGYpDQpzdW1tYXJ5KG1vZGVsb18xLjIpDQpgYGANCg0KDQojIyMgRVZBTFVBQ0nDk04gREUgSElHSUVORQ0KIyMjIyBtb2RlbG8gMjogaW5kaWNhY2nDs24geSBldmFsdWFjacOzbiBkZSBoaWdpZW5lDQpgYGB7ciBtb2RlbG8gMn0NCm1vZGVsb18yIDwtIGNveHBoKGttIH4gDQogICAgICAgICAgICAgICAgICAgICMgZGYkR8OJTkVSTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBESUVOVEUgQUZFQ1RBRE9gICsNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRESUFHTsOTU1RJQ08gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRUUkFUQU1JRU5UTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBUSUVNUE8gSEFTVEEgTEEgQVRFTkNJw5NOIChlbiBob3JhcylgICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYEVTVEFETyBSQURJQ1VMQVIgSU5JQ0lBTGAgKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVFJBVU1BVElTTU8gUkVQRVRJRE9gLA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBUUkFVTUFUSVNNTyBQUkVWSU9gICsgDQogICAgICAgICAgICAgICAgICAgICBkZiRgSU5ESUNBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgIGRmJGBFVkFMVUFDScOTTiBERSBISUdJRU5FYCwNCiAgICAgICAgICAgICAgICAgICAgI2RmJGBPTklDT0ZBR0lBIC0gSU5URVJQT1NJQ0nDk04gREUgT0JKRVRPU2AgLCANCiAgICAgICAgICAgICAgICAgIGRhdGEgPSAgZGYpDQpzdW1tYXJ5KG1vZGVsb18yKQ0KYGBgDQoNCiMjIyMgbW9kZWxvIDIuMSBpbmRpY2FjacOzbiBkZSBoaWdpZW5lIHBvciBzaSBzb2xvDQpgYGB7ciBtb2RlbG8gMi4xfQ0KbW9kZWxvXzIuMSA8LSBjb3hwaChrbSB+IA0KICAgICAgICAgICAgICAgICAgICAjIGRmJEfDiU5FUk8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgRElFTlRFIEFGRUNUQURPYCArDQogICAgICAgICAgICAgICAgICAgICMgZGYkRElBR07Dk1NUSUNPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkVFJBVEFNSUVOVE8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVElFTVBPIEhBU1RBIExBIEFURU5DScOTTiAoZW4gaG9yYXMpYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBFU1RBRE8gUkFESUNVTEFSIElOSUNJQUxgICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYFRSQVVNQVRJU01PIFJFUEVUSURPYCwNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVFJBVU1BVElTTU8gUFJFVklPYCArIA0KICAgICAgICAgICAgICAgICAgICAgZGYkYElORElDQUNJw5NOIERFIEhJR0lFTkVgLCANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgRVZBTFVBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgI2RmJGBPTklDT0ZBR0lBIC0gSU5URVJQT1NJQ0nDk04gREUgT0JKRVRPU2AgLCANCiAgICAgICAgICAgICAgICAgIGRhdGEgPSAgZGYpDQpzdW1tYXJ5KG1vZGVsb18yLjEpDQpgYGANCiMjIyMgbW9kZWxvIDIuMiBldmFsdWFjacOzbiBkZSBoaWdpZW5lIHBvciBzaSBzb2xvDQpgYGB7ciBtb2RlbG8gMi4yfQ0KbW9kZWxvXzIuMiA8LSBjb3hwaChrbSB+IA0KICAgICAgICAgICAgICAgICAgICAjIGRmJEfDiU5FUk8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgRElFTlRFIEFGRUNUQURPYCArDQogICAgICAgICAgICAgICAgICAgICMgZGYkRElBR07Dk1NUSUNPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkVFJBVEFNSUVOVE8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVElFTVBPIEhBU1RBIExBIEFURU5DScOTTiAoZW4gaG9yYXMpYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBFU1RBRE8gUkFESUNVTEFSIElOSUNJQUxgICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYFRSQVVNQVRJU01PIFJFUEVUSURPYCwNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVFJBVU1BVElTTU8gUFJFVklPYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBJTkRJQ0FDScOTTiBERSBISUdJRU5FYCArIA0KICAgICAgICAgICAgICAgICAgICAgZGYkYEVWQUxVQUNJw5NOIERFIEhJR0lFTkVgLA0KICAgICAgICAgICAgICAgICAgICAjZGYkYE9OSUNPRkFHSUEgLSBJTlRFUlBPU0lDScOTTiBERSBPQkpFVE9TYCAsIA0KICAgICAgICAgICAgICAgICAgZGF0YSA9ICBkZikNCnN1bW1hcnkobW9kZWxvXzIuMikNCmBgYA0KDQojIyMgT05JQ09GQUdJQSAtIElOVEVSUE9TSUNJw5NOIERFIE9CSkVUT1MNCiMjIyMgbW9kZWxvIDM6IG1hbG9zIGjDoWJpdG9zDQpgYGB7ciBtb2RlbG8gM30NCm1vZGVsb18zIDwtIGNveHBoKGttIH4gDQogICAgICAgICAgICAgICAgICAgICMgZGYkR8OJTkVSTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBESUVOVEUgQUZFQ1RBRE9gICsNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRESUFHTsOTU1RJQ08gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRUUkFUQU1JRU5UTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBUSUVNUE8gSEFTVEEgTEEgQVRFTkNJw5NOIChlbiBob3JhcylgICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYEVTVEFETyBSQURJQ1VMQVIgSU5JQ0lBTGAgKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVFJBVU1BVElTTU8gUkVQRVRJRE9gLA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBUUkFVTUFUSVNNTyBQUkVWSU9gICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYElORElDQUNJw5NOIERFIEhJR0lFTkVgICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYEVWQUxVQUNJw5NOIERFIEhJR0lFTkVgICsgDQogICAgICAgICAgICAgICAgICAgIGRmJGBPTklDT0ZBR0lBIC0gSU5URVJQT1NJQ0nDk04gREUgT0JKRVRPU2AgLCANCiAgICAgICAgICAgICAgICAgIGRhdGEgPSAgZGYpDQpzdW1tYXJ5KG1vZGVsb18zKQ0KYGBgDQoNCiMjIyBFU1RBRE8gUkFESUNVTEFSIElOSUNJQUwNCiMjIyMgbW9kZWxvIDQ6IGVzdGFkbyByYWRpY3VsYXIgbW9vcnJlcw0KDQpgYGB7ciBtb2RlbG8gNH0NCm1vZGVsb180IDwtIGNveHBoKGttIH4gDQogICAgICAgICAgICAgICAgICAgICMgZGYkR8OJTkVSTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBESUVOVEUgQUZFQ1RBRE9gICsNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRESUFHTsOTU1RJQ08gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRUUkFUQU1JRU5UTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBUSUVNUE8gSEFTVEEgTEEgQVRFTkNJw5NOIChlbiBob3JhcylgICsgDQogICAgICAgICAgICAgICAgICAgICBkZiRgRVNUQURPIFJBRElDVUxBUiBJTklDSUFMYCwNCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVFJBVU1BVElTTU8gUkVQRVRJRE9gLA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBUUkFVTUFUSVNNTyBQUkVWSU9gICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYElORElDQUNJw5NOIERFIEhJR0lFTkVgICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYEVWQUxVQUNJw5NOIERFIEhJR0lFTkVgICsgDQogICAgICAgICAgICAgICAgICAgICNkZiRgT05JQ09GQUdJQSAtIElOVEVSUE9TSUNJw5NOIERFIE9CSkVUT1NgICwgDQogICAgICAgICAgICAgICAgICBkYXRhID0gIGRmKQ0Kc3VtbWFyeShtb2RlbG9fNCkNCmBgYA0KDQojIyMgTW9kZWxvIDk5IHF1ZSBzdWdpZXJvDQpgYGB7ciBtb2RlbG8gOTl9DQptb2RlbG9fOTkgPC0gY294cGgoa20gfiANCiAgICAgICAgICAgICAgICAgICBHw4lORVJPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYERJRU5URSBBRkVDVEFET2AgKw0KICAgICAgICAgICAgICAgICAgIERJQUdOw5NTVElDTyArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJFRSQVRBTUlFTlRPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYFRJRU1QTyBIQVNUQSBMQSBBVEVOQ0nDk04gKGVuIGhvcmFzKWAgKyANCiAgICAgICAgICAgICAgICAgICBgRVNUQURPIFJBRElDVUxBUiBJTklDSUFMYCArIA0KICAgICAgICAgICAgICAgICAgICBgVFJBVU1BVElTTU8gUkVQRVRJRE9gICsNCiAgICAgICAgICAgICAgICAgICBgVFJBVU1BVElTTU8gUFJFVklPYCArIA0KICAgICAgICAgICAgICAgICAgICAjIGRmJGBJTkRJQ0FDScOTTiBERSBISUdJRU5FYCArIA0KICAgICAgICAgICAgICAgICAgICBgRVZBTFVBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgYE9OSUNPRkFHSUEgLSBJTlRFUlBPU0lDScOTTiBERSBPQkpFVE9TYCAsIA0KICAgICAgICAgICAgICAgICAgZGF0YSA9ICBkZikNCnN1bW1hcnkobW9kZWxvXzk5KQ0KYGBgDQoNCkNoZXF1ZW8gcG9yIHNpIHNlIHZpb2xhIGVsIHJpZXNnbyBwcm9wb3JjaW9uYWwgKGNvbnN0YW50ZSBIUiBlbiBlbCB0aWVtcG8pDQoNCmBgYHtyIHJpZXNnbyBwcm8gOTl9DQoocmVzLnpwaDk5IDwtIGNveC56cGgobW9kZWxvXzk5KSkNCmBgYA0KDQpgYGB7cn0NCmNveF9maXRfOTkgPC0gc3VydmZpdChtb2RlbG9fOTkpDQphdXRvcGxvdChjb3hfZml0Xzk5KQ0KDQpgYGANCk9qbywgbGEgbWVkaWFuYSBubyB0b2NhIGVsIDUwJSwgcG9yIGxvIHF1ZSBkYSBtZWRpYW4gPSBOQQ0KDQpgYGB7cn0NCmNveF9maXRfOTkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoY294X2ZpdF85OSkNCmBgYA0KDQoNCmBgYHtyfQ0KYWFfZml0Xzk5IDwtYWFyZWcoU3Vydih0aW1lLCBFdmVudG8pIH4gDQogICAgICAgICAgICAgICAgICBHw4lORVJPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkYERJRU5URSBBRkVDVEFET2AgKw0KICAgICAgICAgICAgICAgICAgICAgRElBR07Dk1NUSUNPICsgDQogICAgICAgICAgICAgICAgICAgICMgZGYkVFJBVEFNSUVOVE8gKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgVElFTVBPIEhBU1RBIExBIEFURU5DScOTTiAoZW4gaG9yYXMpYCArIA0KICAgICAgICAgICAgICAgICAgICAgYEVTVEFETyBSQURJQ1VMQVIgSU5JQ0lBTGAgKyANCiAgICAgICAgICAgICAgICAgICAgIGBUUkFVTUFUSVNNTyBSRVBFVElET2AgKw0KICAgICAgICAgICAgICAgICAgICAgYFRSQVVNQVRJU01PIFBSRVZJT2AgKyANCiAgICAgICAgICAgICAgICAgICAgIyBkZiRgSU5ESUNBQ0nDk04gREUgSElHSUVORWAgKyANCiAgICAgICAgICAgICAgICAgICAgIGBFVkFMVUFDScOTTiBERSBISUdJRU5FYCArIA0KICAgICAgICAgICAgICAgICAgICAgYE9OSUNPRkFHSUEgLSBJTlRFUlBPU0lDScOTTiBERSBPQkpFVE9TYCAsIA0KICAgICAgICAgICAgICAgICAgZGF0YSA9ICBkZikNCg0KYXV0b3Bsb3QoYWFfZml0Xzk5KQ0KDQpgYGANCg0KDQojIFRhbWHDsW8gbXVlc3RyYWwgeSBwb3RlbmNpYQ0KDQpgYGB7cn0NCmhyID0gMiAjIGhhemFyZCByYXRpbw0KaHIwID0gMQ0KcEUgPSAwLjggIyBwcm9iYWJpbGlkYWQgZGVsIGV2ZW50bw0KcEEgPSAwLjUgIyBwcm9wb3JjacOzbiBlbiBlbCBncnVwbyBBDQphbHBoYSA9IDAuMDUNCmJldGEgPSAwLjIwDQoobj0oKHFub3JtKDEtYWxwaGEvMikrcW5vcm0oMS1iZXRhKSkvKGxvZyhociktbG9nKGhyMCkpKV4yLyhwQSooMS1wQSkqcEUpKQ0KY2VpbGluZyhuKSAjIDgyDQooUG93ZXI9cG5vcm0oKGxvZyhociktbG9nKGhyMCkpKnNxcnQobipwQSooMS1wQSkqcEUpLXFub3JtKDEtYWxwaGEvMikpKQ0KYGBgDQoNCiMgUmVmZXJlbmNpYXMNCg0KaHR0cHM6Ly9hbmFseXRpY3NidWRkaHUud29yZHByZXNzLmNvbS8yMDE3LzA0LzE3L2hvdy10by1kby1jb3hwcm9wb3J0aW9uYWwtaGF6YXJkLXJlZ3Jlc3Npb24tbW9kZWxsaW5nLXVzaW5nLXIvDQoNCg0KaHR0cHM6Ly93d3cub3BlbmludHJvLm9yZy9kb3dubG9hZC5waHA/ZmlsZT1zdXJ2aXZhbF9hbmFseXNpc19pbl9SJnJlZmVycmVyPS9zdGF0L3N1cnYucGhwDQoNCmh0dHBzOi8vY291cnNlcy5udXMuZWR1LnNnL2NvdXJzZS9zdGFjYXIvaW50ZXJuZXQvc3QzMjQyL2hhbmRvdXRzL25vdGVzMy5wZGYNCg0KQ2hvdyBTLCBTaGFvIEosIFdhbmcgSC4gMjAwOC4gU2FtcGxlIFNpemUgQ2FsY3VsYXRpb25zIGluIENsaW5pY2FsIFJlc2VhcmNoLiAybmQgRWQuIENoYXBtYW4gJiBIYWxsL0NSQyBCaW9zdGF0aXN0aWNzIFNlcmllcy4gcGFnZSAxNzcuDQoNCg==