Introducción.

Para la realización de este proyecto, se pretende reproducir de manera parcial (de acuerdo a los datos disponibles) los resultados del artículo:

Woo WK, McKenna KE. Combination TL01 ultraviolet B phototherapy and topical calcipotriol for psoriasis: a prospective randomized placebo-controlled clinical trial. Br J Dermatol. 2003 Jul;149(1):146-50. doi: 10.1046/j.1365-2133.2003.05380.x. PMID: 12890208.

En este, se pretende estudiar y determinar los efectos que un nuevo tratamiento combinado puede tener en el tratamiento de una enfermedad cutánea llamada psoriasis. Existen inicialmente dos tratamientos independientes:

  1. Fototerapia con TL01 Ultravioleta B.
  2. Aplicación tópica de calcipotriol.

El estudio pretende investigar si combinando ambos tratamientos se obtiene un mejor resultado en el tratamiento de esta enfermedad. Para evaluar la salud de los pacientes (y por consiguiente, medir la efectividad del tratamiento) se utilizó el Psoriassi Area and Severity Index o PASI; consideramos este índice como nuestra variable en cada paciente.

Metodología seguida en artículo.

La prueba clínica seguida en este estudio fue aleatoria y con control de placebo. Había dos grupos de pacientes:

  1. Grupo activo: Este grupo de pacientes recibió un tratamiento de fototerapia y calcipotriol tópico.
  2. Grupo de control: Este grupo recibió fototerapia y un placebo tópico.

Se obtuvo el PASI de ambos grupos al inicio del tratamiento, así como 8, 14 y 20 sesiones después, como se observa en la siguiente figura (se observa el promedio de cada grupo):

Para el análisis estadístico, se realizó una evaluación de la significancia del puntaje promedio del PASI con comparaciones pareadas usando un t-test, esto para individuos del mismo grupo pero en periodos diferentes. Además, se realizó una evaluación de la significancia de las diferencias de las medias de ambos grupos para un mismo periodo. En la siguiente figura se pueden observar los dos tipos de evaluaciones (y pruebas de hipótesis) que se realizaron con los datos obtenidos:

En general, se consideraba un p value \(< 0.05\) estadísticamente significante. En el estudio, con las múltiples pruebas de hipótesis realizadas, se concluye que los datos proveen evidencia estadística de que la utilización de un tratamiento combinado de fototerapia y calcipotriol tópico es bien tolerado y efectivo en el tratamiento de la psoriasis. Esto por si mismo, y también comparado con el grupo pasivo.

Reproducción parcial de resultados.

A continuación, realizaremos una prueba de hipótesis con los datos disponibles (únicamente conocemos parte de los datos), y compararemos nuestro resultado con el obtenido en el artículo.

  1. Datos: En este caso únicamente tenemos datos del grupo activo (pacientes que están recibiendo el tratamiento tópico real y el ultravioleta juntos). Tenemos datos de \(n = 20\) individuos; esto corresponde con el tamaño de la muestra. Conocemos el Psoriasis Area and Severity Index (PASI) de cada paciente, tanto al inicio (estado inicial) como después de 8 semanas de tratamiento (estado final). Partiendo del PASI, y dado que nos interesa conocer cómo cambia esta variable después del tratamiento, realizaremos una prueba de hipótesis de comparaciones pareadas. En este caso, \(d =\) estado final \(-\) estado inicial. Los datos fueron obtenidos de [2], y se presentan en esta tabla:
Sujeto Estado inicial Después de 8 tratamientos
1 5.9 5.2
2 7.6 12.2
3 12.8 4.6
4 16.5 4.0
5 6.1 0.4
6 14.4 3.8
7 6.6 1.2
8 5.4 3.1
9 9.6 3.5
10 11.6 4.9
11 11.1 11.1
12 15.6 8.4
13 6.9 5.8
14 15.2 5.0
15 21.0 6.4
16 5.9 0.0
17 10.0 2.7
18 12.2 5.1
19 20.2 4.8
20 6.2 4.2

Entonces, obtenemos las diferencias:

# Cargamos los datos proporcionados.
estado.inicial <- c(5.9, 7.6, 12.8, 16.5, 6.1, 14.4, 6.6, 5.4, 9.6, 11.6, 11.1, 
                   15.6, 6.9, 15.2, 21.0, 5.9, 10.0, 12.2, 20.2, 6.2)

estado.final <- c(5.2, 12.2, 4.6, 4.0, 0.4, 3.8, 1.2, 3.1, 3.5, 4.9, 11.1, 8.4, 
                 5.8, 5.0, 6.4, 0.0, 2.7, 5.1, 4.8, 4.2)

# Calculamos diferencias.
diferencias <- estado.final - estado.inicial
print(diferencias)
 [1]  -0.7   4.6  -8.2 -12.5  -5.7 -10.6  -5.4  -2.3  -6.1  -6.7   0.0  -7.2  -1.1 -10.2 -14.6  -5.9  -7.3  -7.1 -15.4  -2.0
  1. Supuestos: Debemos de asumir algunas cosas para poder trabajar con estos datos. Asumimos que las diferencias observadas (obtenidas en el punto anterior) son una muestra aleatoria simple de una población de diferencias que tiene una distribución normal.

  2. Hipótesis: Dado que nos interesa reproducir los resultados del artículo [1], buscamos obtener conclusiones similares y poner a prueba las hipótesis adecuadas. Sin embargo, no realizaremos una prueba a dos colas ya que, en el caso del artículo, esto se hacía particularmente al comparar entre el grupo de control y el grupo activo. Dado que en este caso solo tenemos datos del grupo activo, haremos una prueba de una sola cola a la izquierda:

    1. Hipótesis nula: \(H_0: \mu_d \geq 0\). (El tratamiento en cuestión no funciona para reducir el PASI).
    2. Hipótesis alternativa: \(H_A: \mu_d < 0\). (El tratamiento combinado funciona).
  3. Estadístico de prueba: Bajo los supuestos y los datos que tenemos, el estadístico de prueba adecuado es:

    \[ t = \frac{ \bar{d} - \mu_{d_0}}{s_d/\sqrt{n}}\]

    donde \(\bar{d}\) es la media muestral de las diferencias, \(\mu_{d_0}\) es la hipótesis de esta media, \(n\) es el número de diferencias y \(s_d\) es la desviación estándar de las diferencias.

  4. Distribución del estadístico de prueba: Cuando la hipótesis nula \(H_0\) es cierta, el estadístico de prueba \(t\) sigue una distribución t de student con \(n-1\) grados de libertad. En este caso, \(n-1 = 19\).

  5. Regla de decisión: Al igual que el artículo, tomamos una significancia de \(\alpha = 0.05\). Obtenemos la zona de no rechazo:

# Significancia utilizada en el paper
alpha <- 0.05

# Obtenemos intervalo de confianza
t.low <- qt(alpha, df = 19)

print(paste('Límite inferior:', round(t.low, 5)))
[1] "Límite inferior: -1.72913"

Por lo tanto, nuestra regla de decisión es: Rechazar \(H_0\) si el estadístico de prueba \(t\) es menor que el valor crítico \(t_{low} = -1.72913\). La representación gráfica del intervalo de no rechazo:

Esta gráfica la realicé con Python, el código se encuentra disponible en este link y también en la sección de anexos.

  1. Cálculo del estadístico de prueba:

# Número de datos
N <- length(diferencias)
print(paste('Tamaño de la muestra:', N))
[1] "Tamaño de la muestra: 20"
# Media y desviación estándar.
diferencias.mean <- mean(diferencias)
std <- sd(diferencias)
print(paste('Media:', round(diferencias.mean, 5), 
            ', desviación estándar:', round(std, 5)))
[1] "Media: -6.22 , desviación estándar: 5.04032"
# Calculamos el estadístico de prueba.
t <- (diferencias.mean - m_0)/(std/sqrt(N))
print(paste('Estadístico de prueba:', round(t, 5)))
[1] "Estadístico de prueba: -5.51883"
  1. Decisión estadística: Dado que \(t = -5.51883 < -1.72913 = t_{low}\), y de acuerdo con nuestra regla de decisión, rechazamos la hipótesis nula \(H_0: \mu_d \geq 0\), con una significancia de \(\alpha = 0.05\).

  2. Conclusión: Por lo tanto, concluimos que los datos disponibles proveen suficiente evidencia, con un significancia de \(\alpha = 0.05\), de que que la combinación de terapias (el nuevo tratamiento) reduce el PASI score, esto es, el tratamiento funciona. Sin embargo, no podemos concluir que es mejor respecto al tratamiento solo con fototerapia (y placebo), ya que no estamos comparando ambas poblaciones.

  3. \(p\) value: Podemos obtener el \(p\) value óptimo, esto es, la significancia límite tal que podemos rechazar \(H_0\). Este \(p\) value nos proporciona mayor información respecto a la decisión estadística que hicimos.

# Obtenemos p value
p<- pt(t, df = n-1)
print(paste('P value:', p))
[1] "P value: 2.94690514300404e-05"

Por lo tanto, tenemos \(p = 0.0003\% < 1\%\), resultado que también obtenemos en el artículo. Podríamos tener una significancia de \(\alpha = 0.00003\) y aún así rechazar la hipótesis nula \(H_0\). Esto es, los datos proporcionan bastante evidencia para tomar dicha decisión estadística. Obteneos una conclusión equivalente a la mostrada en el artículo, pero partiendo de un conjunto menor de datos.

Referencias.

  1. Woo WK, McKenna KE. Combination TL01 ultraviolet B phototherapy and topical calcipotriol for psoriasis: a prospective randomized placebo-controlled clinical trial. Br J Dermatol. 2003 Jul;149(1):146-50. doi: 10.1046/j.1365-2133.2003.05380.x. PMID: 12890208.
  2. Wayne W. Daniel y Chad L. Cross, Biostatistics: A Foundation for Analysis in the Health Sciences, 10° edition, Wiley.

Anexos.

Diapositivas de presentación de proyecto.

Se pueden encontrar en este link.

Código de distribución T de student en Python.

Código para reproducción de gráfica del artículo en R.

# Guardamos la imagen.
jpeg('plot.jpeg', quality = 100)

# Eje x.
x <- c(1, 2, 3, 4)

# Datos de PASI del artículo de ambos grupos.
grupo.activo <- c(12.4, 4.8, 2.5, 1.3)
grupo.control <- c(14.1, 11.6, 6.5, 2.3)

# Graficamos ambos grupos.
plot(x, grupo.activo, type = 'b', 
     main = 'PASI score promedio durante el tratamiento.', 
     ylim = c(0,16), xlim = c(0.7, 4.3), col = 'blue',
     ylab = 'PASI score', xaxt = "n", xlab = '')
lines(x, grupo.control, col = 'red', type = 'b')

# Etiquetas de líneas.
legend("top", c("Grupo de control.", "Grupo activo."), fill=c("red", "blue"))

# Cambiamos etiquetas en eje x.
LS0tDQp0aXRsZTogIlByb3llY3RvIDEgLSBFc3RhZMOtc3RpY2EgYXZhbnphZGEuIg0KYXV0aG9yOiAiR2FicmllbCBNaXNzYWVsIEJhcmNvLiBOVUE6IDQyNzA3MS4iDQpkYXRlOiAiOSBkZSBTZXB0aWVtYnJlIGRlIDIwMjEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8c3R5bGU+DQpib2R5IHt0ZXh0LWFsaWduOiBqdXN0aWZ5OyBmb250LXNpemU6IDEycHR9DQo8L3N0eWxlPg0KDQo8Y2VudGVyPg0KICAgIDxpbWcgd2lkdGg9IjYwJSIgc3JjPSJodHRwczovL2kuaW1ndXIuY29tL1VhbzlDSXkucG5nIj4NCjwvY2VudGVyPg0KDQojIyBJbnRyb2R1Y2Npw7NuLg0KDQpQYXJhIGxhIHJlYWxpemFjacOzbiBkZSBlc3RlIHByb3llY3RvLCBzZSBwcmV0ZW5kZSByZXByb2R1Y2lyIGRlIG1hbmVyYSBwYXJjaWFsIChkZSBhY3VlcmRvIGEgbG9zIGRhdG9zIGRpc3BvbmlibGVzKSBsb3MgcmVzdWx0YWRvcyBkZWwgYXJ0w61jdWxvOg0KDQo+ICoqV29vIFdLLCBNY0tlbm5hIEtFKiouICpDb21iaW5hdGlvbiBUTDAxIHVsdHJhdmlvbGV0IEIgcGhvdG90aGVyYXB5IGFuZCB0b3BpY2FsIGNhbGNpcG90cmlvbCBmb3IgcHNvcmlhc2lzOiBhIHByb3NwZWN0aXZlIHJhbmRvbWl6ZWQgcGxhY2Viby1jb250cm9sbGVkIGNsaW5pY2FsIHRyaWFsKi4gQnIgSiBEZXJtYXRvbC4gMjAwMyBKdWw7MTQ5KDEpOjE0Ni01MC4gZG9pOiAxMC4xMDQ2L2ouMTM2NS0yMTMzLjIwMDMuMDUzODAueC4gUE1JRDogMTI4OTAyMDguDQoNCkVuIGVzdGUsIHNlIHByZXRlbmRlIGVzdHVkaWFyIHkgZGV0ZXJtaW5hciBsb3MgZWZlY3RvcyBxdWUgdW4gbnVldm8gdHJhdGFtaWVudG8gY29tYmluYWRvIHB1ZWRlIHRlbmVyIGVuIGVsIHRyYXRhbWllbnRvIGRlIHVuYSBlbmZlcm1lZGFkIGN1dMOhbmVhIGxsYW1hZGEgKipwc29yaWFzaXMqKi4gRXhpc3RlbiBpbmljaWFsbWVudGUgZG9zIHRyYXRhbWllbnRvcyBpbmRlcGVuZGllbnRlczoNCg0KMS4gRm90b3RlcmFwaWEgY29uIFRMMDEgVWx0cmF2aW9sZXRhIEIuIA0KMi4gQXBsaWNhY2nDs24gdMOzcGljYSBkZSBjYWxjaXBvdHJpb2wuIA0KDQpFbCBlc3R1ZGlvIHByZXRlbmRlIGludmVzdGlnYXIgc2kgY29tYmluYW5kbyBhbWJvcyB0cmF0YW1pZW50b3Mgc2Ugb2J0aWVuZSB1biBtZWpvciByZXN1bHRhZG8gZW4gZWwgdHJhdGFtaWVudG8gZGUgZXN0YSBlbmZlcm1lZGFkLiBQYXJhIGV2YWx1YXIgbGEgc2FsdWQgZGUgbG9zIHBhY2llbnRlcyAoeSBwb3IgY29uc2lndWllbnRlLCBtZWRpciBsYSBlZmVjdGl2aWRhZCBkZWwgdHJhdGFtaWVudG8pIHNlIHV0aWxpesOzIGVsIF9Qc29yaWFzc2kgQXJlYSBhbmQgU2V2ZXJpdHkgSW5kZXhfIG8gX1BBU0lfOyBjb25zaWRlcmFtb3MgZXN0ZSDDrW5kaWNlIGNvbW8gbnVlc3RyYSB2YXJpYWJsZSBlbiBjYWRhIHBhY2llbnRlLiANCg0KIyMgTWV0b2RvbG9nw61hIHNlZ3VpZGEgZW4gYXJ0w61jdWxvLg0KDQpMYSBwcnVlYmEgY2zDrW5pY2Egc2VndWlkYSBlbiBlc3RlIGVzdHVkaW8gZnVlIGFsZWF0b3JpYSB5IGNvbiBjb250cm9sIGRlIHBsYWNlYm8uIEhhYsOtYSBkb3MgZ3J1cG9zIGRlIHBhY2llbnRlczogDQoNCjEuIF9HcnVwbyBhY3Rpdm9fOiBFc3RlIGdydXBvIGRlIHBhY2llbnRlcyByZWNpYmnDsyB1biB0cmF0YW1pZW50byBkZSBmb3RvdGVyYXBpYSB5IGNhbGNpcG90cmlvbCB0w7NwaWNvLiANCjIuIF9HcnVwbyBkZSBjb250cm9sXzogRXN0ZSBncnVwbyByZWNpYmnDsyBmb3RvdGVyYXBpYSB5IHVuICoqcGxhY2VibyoqIHTDs3BpY28uIA0KDQpTZSBvYnR1dm8gZWwgX1BBU0lfIGRlIGFtYm9zIGdydXBvcyBhbCBpbmljaW8gZGVsIHRyYXRhbWllbnRvLCBhc8OtIGNvbW8gOCwgMTQgeSAyMCBzZXNpb25lcyBkZXNwdcOpcywgY29tbyBzZSBvYnNlcnZhIGVuIGxhIHNpZ3VpZW50ZSBmaWd1cmEgKHNlIG9ic2VydmEgZWwgcHJvbWVkaW8gZGUgY2FkYSBncnVwbyk6DQoNCjxjZW50ZXI+DQogICAgPGltZyB3aWR0aD0iNjAlIiBzcmM9Imh0dHBzOi8vaS5pbWd1ci5jb20vaXFJRXJNdC5qcGciPg0KPC9jZW50ZXI+DQoNClBhcmEgZWwgYW7DoWxpc2lzIGVzdGFkw61zdGljbywgc2UgcmVhbGl6w7MgdW5hIGV2YWx1YWNpw7NuIGRlIGxhIHNpZ25pZmljYW5jaWEgZGVsIHB1bnRhamUgcHJvbWVkaW8gZGVsIFBBU0kgY29uIGNvbXBhcmFjaW9uZXMgcGFyZWFkYXMgdXNhbmRvIHVuIF90LXRlc3RfLCBlc3RvIHBhcmEgaW5kaXZpZHVvcyBkZWwgbWlzbW8gZ3J1cG8gcGVybyBlbiBwZXJpb2RvcyBkaWZlcmVudGVzLiBBZGVtw6FzLCBzZSByZWFsaXrDsyB1bmEgZXZhbHVhY2nDs24gZGUgbGEgc2lnbmlmaWNhbmNpYSBkZSBsYXMgZGlmZXJlbmNpYXMgZGUgbGFzIG1lZGlhcyBkZSBhbWJvcyBncnVwb3MgcGFyYSB1biBtaXNtbyBwZXJpb2RvLiBFbiBsYSBzaWd1aWVudGUgZmlndXJhIHNlIHB1ZWRlbiBvYnNlcnZhciBsb3MgZG9zIHRpcG9zIGRlIGV2YWx1YWNpb25lcyAoeSBwcnVlYmFzIGRlIGhpcMOzdGVzaXMpIHF1ZSBzZSByZWFsaXphcm9uIGNvbiBsb3MgZGF0b3Mgb2J0ZW5pZG9zOiANCg0KPGNlbnRlcj4NCiAgICA8aW1nIHdpZHRoPSI4MCUiIHNyYz0iaHR0cHM6Ly9pLmltZ3VyLmNvbS9kcHpvRXFXLnBuZyI+DQo8L2NlbnRlcj4NCg0KRW4gZ2VuZXJhbCwgc2UgY29uc2lkZXJhYmEgdW4gX3AgdmFsdWVfICQ8IDAuMDUkIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYW50ZS4gRW4gZWwgZXN0dWRpbywgY29uIGxhcyBtw7psdGlwbGVzIHBydWViYXMgZGUgaGlww7N0ZXNpcyByZWFsaXphZGFzLCBzZSBjb25jbHV5ZSBxdWUgbG9zIGRhdG9zIHByb3ZlZW4gZXZpZGVuY2lhIGVzdGFkw61zdGljYSBkZSBxdWUgbGEgdXRpbGl6YWNpw7NuIGRlIHVuIHRyYXRhbWllbnRvIGNvbWJpbmFkbyBkZSBmb3RvdGVyYXBpYSB5IGNhbGNpcG90cmlvbCB0w7NwaWNvIGVzIGJpZW4gdG9sZXJhZG8geSBlZmVjdGl2byBlbiBlbCB0cmF0YW1pZW50byBkZSBsYSBwc29yaWFzaXMuIEVzdG8gcG9yIHNpIG1pc21vLCB5IHRhbWJpw6luIGNvbXBhcmFkbyBjb24gZWwgZ3J1cG8gcGFzaXZvLg0KDQojIyBSZXByb2R1Y2Npw7NuIHBhcmNpYWwgZGUgcmVzdWx0YWRvcy4NCg0KQSBjb250aW51YWNpw7NuLCByZWFsaXphcmVtb3MgdW5hIHBydWViYSBkZSBoaXDDs3Rlc2lzIGNvbiBsb3MgZGF0b3MgZGlzcG9uaWJsZXMgKMO6bmljYW1lbnRlIGNvbm9jZW1vcyBwYXJ0ZSBkZSBsb3MgZGF0b3MpLCB5IGNvbXBhcmFyZW1vcyBudWVzdHJvIHJlc3VsdGFkbyBjb24gZWwgb2J0ZW5pZG8gZW4gZWwgYXJ0w61jdWxvLg0KDQoxLiAqKkRhdG9zKio6IEVuIGVzdGUgY2FzbyDDum5pY2FtZW50ZSB0ZW5lbW9zIGRhdG9zIGRlbCBncnVwbyBhY3Rpdm8gKHBhY2llbnRlcyBxdWUgZXN0w6FuIHJlY2liaWVuZG8gZWwgdHJhdGFtaWVudG8gdMOzcGljbyByZWFsIHkgZWwgdWx0cmF2aW9sZXRhIGp1bnRvcykuIFRlbmVtb3MgZGF0b3MgZGUgJG4gPSAyMCQgaW5kaXZpZHVvczsgZXN0byBjb3JyZXNwb25kZSBjb24gZWwgdGFtYcOxbyBkZSBsYSBtdWVzdHJhLiBDb25vY2Vtb3MgZWwgX1Bzb3JpYXNpcyBBcmVhIGFuZCBTZXZlcml0eSBJbmRleCAoUEFTSSlfIGRlIGNhZGEgcGFjaWVudGUsIHRhbnRvIGFsIGluaWNpbyAoZXN0YWRvIGluaWNpYWwpIGNvbW8gZGVzcHXDqXMgZGUgOCBzZW1hbmFzIGRlIHRyYXRhbWllbnRvIChlc3RhZG8gZmluYWwpLiBQYXJ0aWVuZG8gZGVsIF9QQVNJXywgeSBkYWRvIHF1ZSBub3MgaW50ZXJlc2EgY29ub2NlciBjw7NtbyBjYW1iaWEgZXN0YSB2YXJpYWJsZSBkZXNwdcOpcyBkZWwgdHJhdGFtaWVudG8sIHJlYWxpemFyZW1vcyB1bmEgcHJ1ZWJhIGRlIGhpcMOzdGVzaXMgZGUgY29tcGFyYWNpb25lcyBwYXJlYWRhcy4gRW4gZXN0ZSBjYXNvLCAgJGQgPSQgZXN0YWRvIGZpbmFsICQtJCBlc3RhZG8gaW5pY2lhbC4gTG9zIGRhdG9zIGZ1ZXJvbiBvYnRlbmlkb3MgZGUgWzJdLCB5IHNlIHByZXNlbnRhbiBlbiBlc3RhIHRhYmxhOg0KDQp8IFN1amV0byB8IEVzdGFkbyBpbmljaWFsIHwgRGVzcHXDqXMgZGUgOCB0cmF0YW1pZW50b3MgfA0KfCA6LS06IHwgOi0tOiB8IDotLTogfA0KfCAxIHwgNS45IHwgNS4yIHwNCnwgMiB8IDcuNiB8IDEyLjIgfA0KfCAzIHwgMTIuOCB8IDQuNiB8DQp8IDQgfCAxNi41IHwgNC4wIHwNCnwgNSB8IDYuMSB8IDAuNCB8DQp8IDYgfCAxNC40IHwgMy44IHwNCnwgNyB8IDYuNiB8IDEuMiB8DQp8IDggfCA1LjQgfCAzLjEgfA0KfCA5IHwgOS42IHwgMy41IHwNCnwgMTAgfCAxMS42IHwgNC45IHwNCnwgMTEgfCAxMS4xIHwgMTEuMSB8DQp8IDEyIHwgMTUuNiB8IDguNCB8DQp8IDEzIHwgNi45IHwgNS44IHwNCnwgMTQgfCAxNS4yIHwgNS4wIHwNCnwgMTUgfCAyMS4wIHwgNi40IHwNCnwgMTYgfCA1LjkgfCAwLjAgfA0KfCAxNyB8IDEwLjAgfCAyLjcgfA0KfCAxOCB8IDEyLjIgfCA1LjEgfA0KfCAxOSB8IDIwLjIgfCA0LjggfA0KfCAyMCB8IDYuMiB8IDQuMiB8DQoNCkVudG9uY2VzLCBvYnRlbmVtb3MgbGFzIGRpZmVyZW5jaWFzOiANCg0KYGBge3J9DQojIENhcmdhbW9zIGxvcyBkYXRvcyBwcm9wb3JjaW9uYWRvcy4NCmVzdGFkby5pbmljaWFsIDwtIGMoNS45LCA3LjYsIDEyLjgsIDE2LjUsIDYuMSwgMTQuNCwgNi42LCA1LjQsIDkuNiwgMTEuNiwgMTEuMSwgDQogICAgICAgICAgICAgICAgICAgMTUuNiwgNi45LCAxNS4yLCAyMS4wLCA1LjksIDEwLjAsIDEyLjIsIDIwLjIsIDYuMikNCg0KZXN0YWRvLmZpbmFsIDwtIGMoNS4yLCAxMi4yLCA0LjYsIDQuMCwgMC40LCAzLjgsIDEuMiwgMy4xLCAzLjUsIDQuOSwgMTEuMSwgOC40LCANCiAgICAgICAgICAgICAgICAgNS44LCA1LjAsIDYuNCwgMC4wLCAyLjcsIDUuMSwgNC44LCA0LjIpDQoNCiMgQ2FsY3VsYW1vcyBkaWZlcmVuY2lhcy4NCmRpZmVyZW5jaWFzIDwtIGVzdGFkby5maW5hbCAtIGVzdGFkby5pbmljaWFsDQpwcmludChkaWZlcmVuY2lhcykNCmBgYA0KDQoNCjIuICoqU3VwdWVzdG9zKio6IERlYmVtb3MgZGUgYXN1bWlyIGFsZ3VuYXMgY29zYXMgcGFyYSBwb2RlciB0cmFiYWphciBjb24gZXN0b3MgZGF0b3MuIEFzdW1pbW9zIHF1ZSBsYXMgZGlmZXJlbmNpYXMgb2JzZXJ2YWRhcyAob2J0ZW5pZGFzIGVuIGVsIHB1bnRvIGFudGVyaW9yKSBzb24gdW5hIG11ZXN0cmEgYWxlYXRvcmlhIHNpbXBsZSBkZSB1bmEgcG9ibGFjacOzbiBkZSBkaWZlcmVuY2lhcyBxdWUgdGllbmUgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLg0KDQozLiAqKkhpcMOzdGVzaXM6KiogRGFkbyBxdWUgbm9zIGludGVyZXNhIHJlcHJvZHVjaXIgbG9zIHJlc3VsdGFkb3MgZGVsIGFydMOtY3VsbyBbMV0sIGJ1c2NhbW9zIG9idGVuZXIgY29uY2x1c2lvbmVzIHNpbWlsYXJlcyB5IHBvbmVyIGEgcHJ1ZWJhIGxhcyBoaXDDs3Rlc2lzIGFkZWN1YWRhcy4gU2luIGVtYmFyZ28sIG5vIHJlYWxpemFyZW1vcyB1bmEgcHJ1ZWJhIGEgZG9zIGNvbGFzIHlhIHF1ZSwgZW4gZWwgY2FzbyBkZWwgYXJ0w61jdWxvLCBlc3RvIHNlIGhhY8OtYSBwYXJ0aWN1bGFybWVudGUgYWwgY29tcGFyYXIgZW50cmUgZWwgZ3J1cG8gZGUgY29udHJvbCB5IGVsIGdydXBvIGFjdGl2by4gRGFkbyBxdWUgZW4gZXN0ZSBjYXNvIHNvbG8gdGVuZW1vcyBkYXRvcyBkZWwgZ3J1cG8gYWN0aXZvLCBoYXJlbW9zIHVuYSBwcnVlYmEgZGUgdW5hIHNvbGEgY29sYSBhIGxhIGl6cXVpZXJkYTogDQoNCiAgICBhLiBIaXDDs3Rlc2lzIG51bGE6ICRIXzA6IFxtdV9kIFxnZXEgMCQuIChFbCB0cmF0YW1pZW50byBlbiBjdWVzdGnDs24gbm8gZnVuY2lvbmEgcGFyYSByZWR1Y2lyIGVsIFBBU0kpLg0KICAgIGIuIEhpcMOzdGVzaXMgYWx0ZXJuYXRpdmE6ICRIX0E6IFxtdV9kIDwgMCQuIChFbCB0cmF0YW1pZW50byBjb21iaW5hZG8gZnVuY2lvbmEpLg0KDQoNCjQuICoqRXN0YWTDrXN0aWNvIGRlIHBydWViYSoqOiBCYWpvIGxvcyBzdXB1ZXN0b3MgeSBsb3MgZGF0b3MgcXVlIHRlbmVtb3MsIGVsIGVzdGFkw61zdGljbyBkZSBwcnVlYmEgYWRlY3VhZG8gZXM6DQoNCiAgICAkJCB0ID0gXGZyYWN7IFxiYXJ7ZH0gLSBcbXVfe2RfMH19e3NfZC9cc3FydHtufX0kJA0KICAgIA0KICAgIGRvbmRlICRcYmFye2R9JCBlcyBsYSBtZWRpYSBtdWVzdHJhbCBkZSBsYXMgZGlmZXJlbmNpYXMsICRcbXVfe2RfMH0kIGVzIGxhIGhpcMOzdGVzaXMgZGUgZXN0YSBtZWRpYSwgJG4kIGVzIGVsIG7Dum1lcm8gZGUgZGlmZXJlbmNpYXMgeSAkc19kJCBlcyBsYSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgZGUgbGFzIGRpZmVyZW5jaWFzLg0KDQoNCjUuICoqRGlzdHJpYnVjacOzbiBkZWwgZXN0YWTDrXN0aWNvIGRlIHBydWViYSoqOiBDdWFuZG8gbGEgaGlww7N0ZXNpcyBudWxhICRIXzAkIGVzIGNpZXJ0YSwgZWwgZXN0YWTDrXN0aWNvIGRlIHBydWViYSAkdCQgc2lndWUgdW5hIGRpc3RyaWJ1Y2nDs24gX3QgZGUgc3R1ZGVudF8gY29uICRuLTEkIGdyYWRvcyBkZSBsaWJlcnRhZC4gRW4gZXN0ZSBjYXNvLCAkbi0xID0gMTkkLg0KDQo2LiAqKlJlZ2xhIGRlIGRlY2lzacOzbioqOiBBbCBpZ3VhbCBxdWUgZWwgYXJ0w61jdWxvLCB0b21hbW9zIHVuYSBzaWduaWZpY2FuY2lhIGRlICRcYWxwaGEgPSAwLjA1JC4gT2J0ZW5lbW9zIGxhIHpvbmEgZGUgbm8gcmVjaGF6bzoNCg0KYGBge3J9DQojIFNpZ25pZmljYW5jaWEgdXRpbGl6YWRhIGVuIGVsIHBhcGVyDQphbHBoYSA8LSAwLjA1DQoNCiMgT2J0ZW5lbW9zIGludGVydmFsbyBkZSBjb25maWFuemENCnQubG93IDwtIHF0KGFscGhhLCBkZiA9IDE5KQ0KDQpwcmludChwYXN0ZSgnTMOtbWl0ZSBpbmZlcmlvcjonLCByb3VuZCh0LmxvdywgNSkpKQ0KYGBgDQoNClBvciBsbyB0YW50bywgbnVlc3RyYSByZWdsYSBkZSBkZWNpc2nDs24gZXM6IF9SZWNoYXphciAkSF8wJCBzaSBlbCBlc3RhZMOtc3RpY28gZGUgcHJ1ZWJhICR0JCBlcyBtZW5vciBxdWUgZWwgdmFsb3IgY3LDrXRpY28gJHRfe2xvd30gPSAgLTEuNzI5MTMkLl8gTGEgcmVwcmVzZW50YWNpw7NuIGdyw6FmaWNhIGRlbCBpbnRlcnZhbG8gZGUgbm8gcmVjaGF6bzogDQoNCjxjZW50ZXI+DQogICAgPGltZyB3aWR0aD0iNjAlIiBzcmM9Imh0dHBzOi8vaS5pbWd1ci5jb20vUThBdEhaOC5wbmciPg0KPC9jZW50ZXI+DQoNCkVzdGEgZ3LDoWZpY2EgbGEgcmVhbGljw6kgY29uIFB5dGhvbiwgZWwgY8OzZGlnbyBzZSBlbmN1ZW50cmEgZGlzcG9uaWJsZSBlbiBlc3RlIFtsaW5rXShodHRwczovL2dpc3QuZ2l0aHViLmNvbS9HYWJyaWVsTWlzc2FlbC82OTg3ZmZkNWU3ZmQ4M2UyOTA2YWUyMDEyNDVkODQ3YiNmaWxlLW5vcm1hbF9kaXN0LXB5KSB5IHRhbWJpw6luIGVuIGxhIHNlY2Npw7NuIGRlIGFuZXhvcy4NCg0KNy4gKipDw6FsY3VsbyBkZWwgZXN0YWTDrXN0aWNvIGRlIHBydWViYSoqOg0KDQpgYGB7cn0NCg0KIyBOw7ptZXJvIGRlIGRhdG9zDQpOIDwtIGxlbmd0aChkaWZlcmVuY2lhcykNCnByaW50KHBhc3RlKCdUYW1hw7FvIGRlIGxhIG11ZXN0cmE6JywgTikpDQoNCiMgTWVkaWEgeSBkZXN2aWFjacOzbiBlc3TDoW5kYXIuDQpkaWZlcmVuY2lhcy5tZWFuIDwtIG1lYW4oZGlmZXJlbmNpYXMpDQpzdGQgPC0gc2QoZGlmZXJlbmNpYXMpDQpwcmludChwYXN0ZSgnTWVkaWE6Jywgcm91bmQoZGlmZXJlbmNpYXMubWVhbiwgNSksIA0KICAgICAgICAgICAgJywgZGVzdmlhY2nDs24gZXN0w6FuZGFyOicsIHJvdW5kKHN0ZCwgNSkpKQ0KDQojIENhbGN1bGFtb3MgZWwgZXN0YWTDrXN0aWNvIGRlIHBydWViYS4NCnQgPC0gKGRpZmVyZW5jaWFzLm1lYW4gLSBtXzApLyhzdGQvc3FydChOKSkNCnByaW50KHBhc3RlKCdFc3RhZMOtc3RpY28gZGUgcHJ1ZWJhOicsIHJvdW5kKHQsIDUpKSkNCmBgYA0KDQo4LiAqKkRlY2lzacOzbiBlc3RhZMOtc3RpY2EqKjogRGFkbyBxdWUgJHQgPSAtNS41MTg4MyA8IC0xLjcyOTEzID0gdF97bG93fSQsIHkgZGUgYWN1ZXJkbyBjb24gbnVlc3RyYSByZWdsYSBkZSBkZWNpc2nDs24sIHJlY2hhemFtb3MgbGEgaGlww7N0ZXNpcyBudWxhICRIXzA6IFxtdV9kIFxnZXEgMCQsIGNvbiB1bmEgc2lnbmlmaWNhbmNpYSBkZSAkXGFscGhhID0gMC4wNSQuDQoNCjkuICoqQ29uY2x1c2nDs24qKjogUG9yIGxvIHRhbnRvLCBjb25jbHVpbW9zIHF1ZSBsb3MgZGF0b3MgZGlzcG9uaWJsZXMgcHJvdmVlbiBzdWZpY2llbnRlIGV2aWRlbmNpYSwgY29uIHVuIHNpZ25pZmljYW5jaWEgZGUgJFxhbHBoYSA9IDAuMDUkLCBkZSBxdWUgcXVlIGxhIGNvbWJpbmFjacOzbiBkZSB0ZXJhcGlhcyAoZWwgbnVldm8gdHJhdGFtaWVudG8pIHJlZHVjZSBlbCBfUEFTSSBzY29yZV8sIGVzdG8gZXMsIGVsIHRyYXRhbWllbnRvIGZ1bmNpb25hLiBTaW4gZW1iYXJnbywgbm8gcG9kZW1vcyBjb25jbHVpciBxdWUgZXMgbWVqb3IgcmVzcGVjdG8gYWwgdHJhdGFtaWVudG8gc29sbyBjb24gZm90b3RlcmFwaWEgKHkgcGxhY2VibyksIHlhIHF1ZSBubyBlc3RhbW9zIGNvbXBhcmFuZG8gYW1iYXMgcG9ibGFjaW9uZXMuDQoNCjEwLiAqKiRwJCB2YWx1ZSoqOiBQb2RlbW9zIG9idGVuZXIgZWwgJHAkIHZhbHVlIMOzcHRpbW8sIGVzdG8gZXMsIGxhIHNpZ25pZmljYW5jaWEgbMOtbWl0ZSB0YWwgcXVlIHBvZGVtb3MgcmVjaGF6YXIgJEhfMCQuIEVzdGUgJHAkIHZhbHVlIG5vcyBwcm9wb3JjaW9uYSBtYXlvciBpbmZvcm1hY2nDs24gcmVzcGVjdG8gYSBsYSBkZWNpc2nDs24gZXN0YWTDrXN0aWNhIHF1ZSBoaWNpbW9zLg0KDQpgYGB7cn0NCiMgT2J0ZW5lbW9zIHAgdmFsdWUNCnA8LSBwdCh0LCBkZiA9IG4tMSkNCnByaW50KHBhc3RlKCdQIHZhbHVlOicsIHApKQ0KYGBgDQpQb3IgbG8gdGFudG8sIHRlbmVtb3MgJHAgPSAwLjAwMDNcJSA8IDFcJSQsIHJlc3VsdGFkbyBxdWUgdGFtYmnDqW4gb2J0ZW5lbW9zIGVuIGVsIGFydMOtY3Vsby4gUG9kcsOtYW1vcyB0ZW5lciB1bmEgc2lnbmlmaWNhbmNpYSBkZSAkXGFscGhhID0gMC4wMDAwMyQgeSBhw7puIGFzw60gcmVjaGF6YXIgbGEgaGlww7N0ZXNpcyBudWxhICRIXzAkLiBFc3RvIGVzLCBsb3MgZGF0b3MgcHJvcG9yY2lvbmFuIGJhc3RhbnRlIGV2aWRlbmNpYSBwYXJhIHRvbWFyIGRpY2hhIGRlY2lzacOzbiBlc3RhZMOtc3RpY2EuICoqT2J0ZW5lb3MgdW5hIGNvbmNsdXNpw7NuIGVxdWl2YWxlbnRlIGEgbGEgbW9zdHJhZGEgZW4gZWwgYXJ0w61jdWxvLCBwZXJvIHBhcnRpZW5kbyBkZSB1biBjb25qdW50byBtZW5vciBkZSBkYXRvcyoqLg0KDQojIyBSZWZlcmVuY2lhcy4NCg0KMS4gKipXb28gV0ssIE1jS2VubmEgS0UqKi4gKkNvbWJpbmF0aW9uIFRMMDEgdWx0cmF2aW9sZXQgQiBwaG90b3RoZXJhcHkgYW5kIHRvcGljYWwgY2FsY2lwb3RyaW9sIGZvciBwc29yaWFzaXM6IGEgcHJvc3BlY3RpdmUgcmFuZG9taXplZCBwbGFjZWJvLWNvbnRyb2xsZWQgY2xpbmljYWwgdHJpYWwqLiBCciBKIERlcm1hdG9sLiAyMDAzIEp1bDsxNDkoMSk6MTQ2LTUwLiBkb2k6IDEwLjEwNDYvai4xMzY1LTIxMzMuMjAwMy4wNTM4MC54LiBQTUlEOiAxMjg5MDIwOC4NCjIuICoqV2F5bmUgVy4gRGFuaWVsIHkgQ2hhZCBMLiBDcm9zcyoqLCAqQmlvc3RhdGlzdGljczogQSBGb3VuZGF0aW9uIGZvciBBbmFseXNpcyBpbiB0aGUgSGVhbHRoIFNjaWVuY2VzKiwgMTDCsCBlZGl0aW9uLCBXaWxleS4NCg0KIyMgQW5leG9zLg0KDQojIyMgRGlhcG9zaXRpdmFzIGRlIHByZXNlbnRhY2nDs24gZGUgcHJveWVjdG8uIA0KDQpTZSBwdWVkZW4gZW5jb250cmFyIGVuIGVzdGUgW2xpbmtdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3ByZXNlbnRhdGlvbi9kL2UvMlBBQ1gtMXZUZGFCQWlxWTg1TDBqMTA5YWVmS19xUW02akRWR18tNWlERXdTbm9Bd25fMzNwd19CN21sTkJHZE9YeDRFcmhDbU5CV2xVdjRIZG51VmQvcHViP3N0YXJ0PWZhbHNlJmxvb3A9dHJ1ZSZkZWxheW1zPTEwMDAwKS4NCg0KIyMjIEPDs2RpZ28gZGUgZGlzdHJpYnVjacOzbiBUIGRlIHN0dWRlbnQgZW4gUHl0aG9uLg0KDQo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vR2FicmllbE1pc3NhZWwvMDJjNzNkOGViYjU2OWQwYjU1NWJlOWEyMDlhZDUwZjIuanMiPjwvc2NyaXB0Pg0KDQojIyMgQ8OzZGlnbyBwYXJhIHJlcHJvZHVjY2nDs24gZGUgZ3LDoWZpY2EgZGVsIGFydMOtY3VsbyBlbiBSLg0KDQpgYGB7cn0NCiMgR3VhcmRhbW9zIGxhIGltYWdlbi4NCmpwZWcoJ3Bsb3QuanBlZycsIHF1YWxpdHkgPSAxMDApDQoNCiMgRWplIHguDQp4IDwtIGMoMSwgMiwgMywgNCkNCg0KIyBEYXRvcyBkZSBQQVNJIGRlbCBhcnTDrWN1bG8gZGUgYW1ib3MgZ3J1cG9zLg0KZ3J1cG8uYWN0aXZvIDwtIGMoMTIuNCwgNC44LCAyLjUsIDEuMykNCmdydXBvLmNvbnRyb2wgPC0gYygxNC4xLCAxMS42LCA2LjUsIDIuMykNCg0KIyBHcmFmaWNhbW9zIGFtYm9zIGdydXBvcy4NCnBsb3QoeCwgZ3J1cG8uYWN0aXZvLCB0eXBlID0gJ2InLCANCiAgICAgbWFpbiA9ICdQQVNJIHNjb3JlIHByb21lZGlvIGR1cmFudGUgZWwgdHJhdGFtaWVudG8uJywgDQogICAgIHlsaW0gPSBjKDAsMTYpLCB4bGltID0gYygwLjcsIDQuMyksIGNvbCA9ICdibHVlJywNCiAgICAgeWxhYiA9ICdQQVNJIHNjb3JlJywgeGF4dCA9ICJuIiwgeGxhYiA9ICcnKQ0KbGluZXMoeCwgZ3J1cG8uY29udHJvbCwgY29sID0gJ3JlZCcsIHR5cGUgPSAnYicpDQoNCiMgRXRpcXVldGFzIGRlIGzDrW5lYXMuDQpsZWdlbmQoInRvcCIsIGMoIkdydXBvIGRlIGNvbnRyb2wuIiwgIkdydXBvIGFjdGl2by4iKSwgZmlsbD1jKCJyZWQiLCAiYmx1ZSIpKQ0KDQojIENhbWJpYW1vcyBldGlxdWV0YXMgZW4gZWplIHguDQpheGlzKDEsIGF0ID0geCwgbGFiZWxzID0gYygnRXN0YWRvIGluaWNpYWwnLCAnOCBzZXNpb25lcycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAnMTQgc2VzaW9uZXMnLCAnMjAgc2VzaW9uZXMnKSkNCg0KIyBBZ3JlZ2Ftb3MgdW5hIGN1YWRyw61jdWxhLg0KZ3JpZCgpDQpkZXYub2ZmKCkNCmBgYA0KDQoNCg0KDQo=