Introducción

El presente notebook muestra el código utilizado para realizar el estudio presentado en el artículo “Metodologías de estudio estadístico de bases de datos de biodiversidad: el caso de una base de datos de la biodiversidad de avifauna en la reserva Thomas van der Hammen.” y tiene como objetivo detallar los procedimientos y análisis estadísticos aplicados a la base de datos estudiada. Se describen los pasos seguidos desde la limpieza y preparación de los datos hasta la aplicación de técnicas estadísticas avanzadas y la visualización de resultados.

Preparación de la base de datos

Es importante destacar que la base de datos original (Barrera, 2023) contenía 53 variables. Antes de trabajar en el entorno de R, se realizó un primer filtro de información, reduciendo el número de variables a 18, las cuales formaron parte del estudio final. Esta versión de la base de datos puede descargarse ingresando a este enlace.

Cargue de la base de datos

library(readr)
dbAves=read_delim("https://drive.google.com/uc?id=1SvGS1WHzoLafehGMnvDPGxGvyQLbgRKd",
                     delim = ",",
                     escape_double = FALSE,
                     trim_ws = TRUE)
Rows: 3499 Columns: 18
── Column specification ───────────────────────────────────────────
Delimiter: ","
chr (16): id, sex, behavior, associatedTaxa, occurrenceRemarks,...
dbl  (2): decimalLatitude, decimalLongitude

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
summary(dbAves)
      id                sex              behavior        
 Length:3499        Length:3499        Length:3499       
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 associatedTaxa     occurrenceRemarks    habitat         
 Length:3499        Length:3499        Length:3499       
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 verbatimLocality   decimalLatitude   decimalLongitude   
 Length:3499        Min.   : 476978   Min.   :-74101169  
 Class :character   1st Qu.:4767098   1st Qu.:-74100289  
 Mode  :character   Median :4767918   Median :-74098822  
                    Mean   :4551481   Mean   :-72875474  
                    3rd Qu.:4769195   3rd Qu.:-74097725  
                    Max.   :4772912   Max.   : -7410075  
 verbatimLatitude   verbatimLongitude  scientificName    
 Length:3499        Length:3499        Length:3499       
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    order              family             genus          
 Length:3499        Length:3499        Length:3499       
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 parentEventID      estructuraSocial   alturaObservacion 
 Length:3499        Length:3499        Length:3499       
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         

Primera fase

Del resumen obtenido anteriormente se observa que:

  • Aunque las variables decimalLatitude y decimalLongitude se identifican como cuantitativas, no son correctas, ya que sus partes decimales se convirtieron en enteros. Para corregir esto, se utilizarán las variables verbatimLatitude y verbatimLongitude. Una vez realizada esta modificación, estas dos últimas variables pueden eliminarse, ya que se habrá obtenido la medida numérica correcta.
  • Las variables que R clasifica como character deben convertirse a factores.
  • La variable alturaObservación debe ser tratada para que tome valores numéricos.

Se inicia con los procedimientos para abordar estos hallazgos.

Variables decimalLatitude y decimalLongitude

Para hacer los cambios en estas variables, se utilizarán las variables verbatimLatitude y verbatimLongitude para realizar la conversión correcta de las coordenadas de su forma GMS a decimal. Se programará una función que tome la cadena de texto con las coordenadas GMS, identifique sus componentes, los convierta a valores numéricos y luego realice las operaciones aritméticas necesarias para obtener el valor decimal de la coordenada. Una vez realizada la conversión, se eliminarán las variables verbatimLatitude y verbatimLongitude.

convLat <- function(ejemplo) {
  partes1 =strsplit(ejemplo, "\u00B0")
  grados = as.numeric(partes1[[1]][1])
  partes2=strsplit(partes1[[1]][2], "\u00B4")
  minutos =as.numeric(partes2[[1]][1])
  segundos =as.numeric(partes2[[1]][2])
  decimalLat = grados + minutos / 60 + segundos / 3600
  return(decimalLat)}
convLon=function(ejemplo){
  partes1 =strsplit(ejemplo, "\u00B0")
  grados = as.numeric(partes1[[1]][1])
  partes2=strsplit(partes1[[1]][2], "\u00B4")
  minutos =as.numeric(partes2[[1]][1])
  segundos =as.numeric(partes2[[1]][2])
  decimalLon = (grados + minutos / 60 + segundos / 3600)*-1
  return(decimalLon)
}
dbAves$decimalLatitude=sapply(dbAves$verbatimLatitude,convLat)
dbAves$decimalLongitude=sapply(dbAves$verbatimLongitude,convLon)
dbAves=subset(dbAves,select = -verbatimLatitude)
dbAves=subset(dbAves,select = -verbatimLongitude)

Conversión de variables tipo character o carácter.

Para hacer un correcto tratamiento de variables cualitativas en el entorno de R, es necesario que estas sean de tipo factor. En este caso, se realizará la conversión de las variables que inicialmente se identificaron como de tipo carácter (incluida la variable alturaObservacion para poder explorarla, a pesar de que debería ser una variable numérica).

library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
dbAves=dbAves %>%
  mutate(across(where(is.character), as.factor))

Variable alturaObservacion

En este punto, esta variable es de tipo factor, por lo que un buen primer paso es revisar las categorías que la componen.

unique(dbAves$alturaObservacion)
 [1] #N/D  10    5     3     4     2     6     7     9     8    
[11] <0.6  15    12    13    1.5-2 1     1.5   11    0.6   4.5  
[21] 2.5   Bajo  20    >4    2.4   0.80  0.8   3-5  
28 Levels: #N/D <0.6 >4 0.6 0.8 0.80 1 1.5 1.5-2 10 11 12 ... Bajo

Como se puede evidenciar, hay categorías que no son propiamente un número, como “<0.6”, “1.5-2”, “Bajo”, “>4” y “3-5”. Con respecto a la categoría “#N/D”, son datos de los cuales no se tiene un valor registrado, por lo que no se deben modificar y deben tratarse como datos faltantes.

Dado que esta es una variable de naturaleza cuantitativa, sería interesante poder tratarla como tal. Por lo tanto, para este estudio se realizarán modificaciones a estas categorías y a los registros que las contengan. Estas modificaciones se realizarán teniendo en cuenta los siguientes parámetros:

  • La categoría “#N/D” debe modificarse para que tome valores de NA.
  • A las categorías que denoten intervalos se les asignará el valor medio entre los límites del mismo.
  • A la categoría “<0.6” se le designará el valor de 0.5.
  • A la categoría “>4” se le asignará el valor de 5.
  • A la categoría “Bajo” se le designará el valor de 0.3.
dbAves <- dbAves %>%
  mutate(alturaObservacion = case_when(
    alturaObservacion == "#N/D" ~ NA_real_,
    alturaObservacion == "1.5-2" ~ 1.7,
    alturaObservacion == "3-5" ~ 4,
    alturaObservacion == "<0.6" ~ 0.5,
    alturaObservacion == ">4" ~ 5,
    alturaObservacion == "Bajo" ~ 0.3,
    TRUE ~ as.numeric(as.character(alturaObservacion))
  ))
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `alturaObservacion = case_when(...)`.
Caused by warning:
! NAs introducidos por coerción

Para finalizar esta primera fase de limpieza de la base de datos, la variable ID se convierte en el identificador de fila y no se tomará en cuenta como una variable a partir de este momento.

rownames(dbAves)=dbAves$id
Warning: Setting row names on a tibble is deprecated.
dbAves$id=NULL
summary(dbAves)
          sex                                       behavior   
 Desconocido:1666   Vuelo                               :1860  
 Hembra     :  66   Descanso                            : 842  
 Juvenil    :   5   Movimiento entre vegetación         : 385  
 Macho      : 123   Alimentación                        : 130  
 NA's       :1639   Alimentación | Movimiento vegetación:  77  
                    Autoacicalamiento                   :  53  
                    (Other)                             : 152  
                          associatedTaxa
 Huésped: Cenchrus clandestinus  : 236  
 Huésped: Smallanthus pyramidalis: 202  
 Huésped: Alnus acuminata        :  82  
 Huésped: Fraxinus uhdei         :  61  
 Huésped: Bacharis latifolia     :  52  
 (Other)                         : 491  
 NA's                            :2375  
           occurrenceRemarks                         habitat    
 Monitoreo 5, mañana: 520    Bosque mixto nativo- exótica: 365  
 Monitoreo 5, tarde : 430    Bosque Nativo               : 710  
 Monitoreo 4, mañana: 403    Espejo de agua              :  14  
 Monitoreo 3, tarde : 378    Matorral pasto Kikuyo       : 288  
 Monitoreo 3, mañana: 348    NA's                        :2122  
 Monitoreo 1, tarde : 285                                       
 (Other)            :1135                                       
              verbatimLocality decimalLatitude decimalLongitude
 Hacienda la Conejera : 467    Min.   :4.765   Min.   :-74.10  
 Hacienda las Mercedes:3032    1st Qu.:4.767   1st Qu.:-74.10  
                               Median :4.768   Median :-74.10  
                               Mean   :4.769   Mean   :-74.10  
                               3rd Qu.:4.770   3rd Qu.:-74.10  
                               Max.   :4.773   Max.   :-74.07  
                                                               
               scientificName             order     
 Zenaida auriculata   : 611   Passeriformes  :2407  
 Zonotrichia capensis : 492   Columbiformes  : 682  
 Turdus fuscater      : 295   Pelecaniformes : 112  
 Notiochelidon murina : 294   Apodiformes    :  94  
 Molothrus bonariensis: 209   Psittaciformes :  68  
 Spinus psaltria      : 159   Accipitriformes:  61  
 (Other)              :1439   (Other)        :  75  
          family               genus      parentEventID
 Columbidae  : 682   Zenaida      : 611   E:1: 467     
 Emberizidae : 525   Zonotrichia  : 492   E:2: 345     
 Hirundinidae: 419   Notiochelidon: 296   E:3:1280     
 Turdidae    : 303   Turdus       : 295   E:4:1407     
 Icteridae   : 286   Spinus       : 222                
 Thraupidae  : 280   Molothrus    : 209                
 (Other)     :1004   (Other)      :1374                
           estructuraSocial alturaObservacion
 Bandada           : 264    Min.   : 0.300   
 Grupo coespecífico:1222    1st Qu.: 2.000   
 Grupo mixto       :  43    Median : 4.000   
 Pareja            : 809    Mean   : 4.846   
 Solitario         :1161    3rd Qu.: 7.000   
                            Max.   :20.000   
                            NA's   :2532     
head(dbAves)

Segunda fase

Como se puede evidenciar en el último resumen emitido, se observa que hay variables que tienen datos faltantes (aparecen bajo la categoría “NA’s”). Se procede a revisar el porcentaje de datos faltates por variable.

falt=colSums(is.na(dbAves))
porcFalt=round((falt/nrow(dbAves))*100,0)
dfFaltantes=data.frame(Faltantes=falt,
                       Porcentaje=porcFalt)
 dfFaltantes[dfFaltantes$Porcentaje != 0, ]

La presencia de datos faltantes es común al analizar bases de datos de biodiversidad, lo cual puede afectar la confiabilidad de los análisis. En este estudio, se ha decidido eliminar del conjunto de datos aquellas variables que presenten un porcentaje de datos faltantes superior al 65%. En este caso, las variables alturaObservación y associatedTaxa cumplen con este criterio y serán excluidas del análisis.

dbAves=subset(dbAves, select=-alturaObservacion)
dbAves=subset(dbAves, select=-associatedTaxa)
sum(complete.cases(dbAves))
[1] 736

Además, se ha observado que la base de datos contiene un total de 736 registros completos. Por lo tanto, se ha decidido trabajar exclusivamente con estos registros. Se procederá a generar una copia de la base de datos que contenga únicamente estos registros, con el fin de realizar un análisis más detallado de las variables y de la base de datos en general.

sinFalt=dbAves[complete.cases(dbAves),]
write.csv(sinFalt, file = "avesSinFal.csv")

Puede descargarse una copia de esta versión de la base de datos ingresando al siguiente enlace.

Tercera fase

Para esta fase de preparación de los datos, se inicia con la revisión de un resumen de los mismos.

summary(sinFalt)
          sex                                      behavior  
 Desconocido:644   Descanso                            :444  
 Hembra     : 34   Movimiento entre vegetación         :102  
 Juvenil    :  3   Alimentación                        : 52  
 Macho      : 55   Alimentación | Movimiento vegetación: 51  
                   Vuelo                               : 41  
                   Vuelo | Movimiento vegetación       : 11  
                   (Other)                             : 35  
           occurrenceRemarks                         habitat   
 Monitoreo 5, mañana:211     Bosque mixto nativo- exótica:197  
 Monitoreo 5, tarde :139     Bosque Nativo               :442  
 Monitoreo 1, tarde : 74     Espejo de agua              :  3  
 Monitoreo 3, tarde : 44     Matorral pasto Kikuyo       : 94  
 Monitoreo 1, mañana: 43                                       
 Monitoreo 4, mañana: 43                                       
 (Other)            :182                                       
              verbatimLocality decimalLatitude decimalLongitude
 Hacienda la Conejera :175     Min.   :4.765   Min.   :-74.10  
 Hacienda las Mercedes:561     1st Qu.:4.768   1st Qu.:-74.10  
                               Median :4.770   Median :-74.10  
                               Mean   :4.769   Mean   :-74.09  
                               3rd Qu.:4.772   3rd Qu.:-74.10  
                               Max.   :4.773   Max.   :-74.07  
                                                               
               scientificName            order    
 Zonotrichia capensis :137    Passeriformes :571  
 Turdus fuscater      :119    Columbiformes :106  
 Zenaida auriculata   : 66    Apodiformes   : 21  
 Molothrus bonariensis: 40    Psittaciformes: 21  
 Patagioenas fasciata : 40    Pelecaniformes:  6  
 Diglossa humeralis   : 34    Cuculiformes  :  4  
 (Other)              :300    (Other)       :  7  
         family            genus     parentEventID
 Emberizidae:144   Zonotrichia:137   E:1:175      
 Turdidae   :122   Turdus     :119   E:2:190      
 Columbidae :106   Zenaida    : 66   E:3:189      
 Thraupidae : 76   Diglossa   : 44   E:4:182      
 Icteridae  : 70   Molothrus  : 40                
 Tyrannidae : 51   Patagioenas: 40                
 (Other)    :167   (Other)    :290                
           estructuraSocial
 Bandada           :  0    
 Grupo coespecífico:228    
 Grupo mixto       :  7    
 Pareja            :220    
 Solitario         :281    
                           
                           

Como se ha podido observar hasta el momento, el tratamiento de variables cualitativas a menudo requiere un manejo especial de cadenas de texto. A través del resumen anterior, se identificaron otras variables cualitativas en esta base de datos que, debido a la cantidad de categorías o a los valores que algunos registros pueden tomar, podrían estar introduciendo más variabilidad en el conjunto de datos. Estas variables son sex, behavior y occurrenceRemarks. A continuación se presentan los hallazgos y los tratamientos correspondientes.

Variable sex

sinFalt$sex=droplevels(sinFalt$sex)
tabSex=as.data.frame(table(sinFalt$sex))
colnames(tabSex)=c("Sexo","Frecuencia")
tabSex

En el caso de esta variable, aunque hay pocas categorías, la categoría “Juvenil” cuenta con solo tres observaciones. Para reducir el número de categorías de la variable y disminuir su variabilidad, en este estudio se ha decidido clasificar estas tres observaciones como “Desconocido”. Esta elección se basa en que determinar el sexo de un ave a simple vista es factible solo en la mitad de las especies y, usualmente, cuando estas están completamente desarrolladas (es decir, en su etapa adulta) (Griffiths, 2000). Por lo tanto, resulta más difícil determinar el sexo de un ave joven mediante métodos visuales, como durante una actividad de avistamiento de aves.

sinFalt$sex[sinFalt$sex == "Juvenil"]="Desconocido"
sinFalt$sex=droplevels(sinFalt$sex)
summary(sinFalt$sex)
Desconocido      Hembra       Macho 
        647          34          55 

Variable behavior

sinFalt$behavior=droplevels(sinFalt$behavior)
tabComp=as.data.frame(table(sinFalt$behavior))
colnames(tabComp)=c("Comportamiento","Frecuencia")
tabComp

En el caso de esta variable, se observa que hay cadenas de texto que describen más de una acción realizada por el organismo avistado, lo que ocasiona la generación de más categorías. Para este estudio, se optará por registrar en esta variable únicamente la primera acción que aparezca en la cadena de texto existente.

Se evidencia que la cadena de texto que separa la primera acción del resto del texto es ” |“, por lo que se utilizarán métodos de manipulación de cadenas de caracteres para modificar la variable.

sinFalt$behavior=as.character(sinFalt$behavior)
sinFalt$behavior=sub(" \\|.*", "", sinFalt$behavior)
sinFalt$behavior=as.factor(sinFalt$behavior)
summary(sinFalt$behavior)
               Alimentación           Autoacicalamiento 
                        103                           7 
                   Descanso Movimiento entre vegetación 
                        445                         120 
                      Vuelo 
                         61 

Con esto la variable queda reducida a 5 categorías, lo que facilitará un poco más los procesos de análisis.

Variable occurrenceRemarks

sinFalt$occurrenceRemarks=droplevels(sinFalt$occurrenceRemarks)
tabAnot=as.data.frame(table(sinFalt$occurrenceRemarks))
colnames(tabAnot)=c("Anotación","Frecuencia")
tabAnot

Esta variable debe reportar información sobre el monitoreo en el que se realizó el avistamiento, el momento del día en que se llevó a cabo, o si se avistó en un lugar particular, como un cable o un árbol muerto. Esto resulta en un alto número de categorías, con un total de 26.

Para los fines de este estudio, se registrará únicamente la información sobre el momento del día en que se realizó el avistamiento (mañana o tarde), con la intención de identificar patrones relacionados con los aspectos etológicos de las aves.

sinFalt$occurrenceRemarks=trimws(sub(".*,", "", sinFalt$occurrenceRemarks))
sinFalt$occurrenceRemarks=as.factor(sinFalt$occurrenceRemarks)
summary(sinFalt$occurrenceRemarks)
mañana  tarde 
   394    342 

Con esto, la fase de preparación se da por terminada. Se puede descargar una copia de esta versión de la base de datos en el siguiente enlace.

Análisis por categorías

Luego de la preparación de las variables, se inicia el análisis del fenómeno de biodiversidad documentado en la base de datos. Para esto, se plantean tres categorías de análisis:

  1. Aspectos relacionados con la ubicación geográfica.
  2. Aspectos taxonómicos de los organismos.
  3. Aspectos etológicos de los organismos.

Dentro de cada una de estas categorías de análisis, se incluyen variables que se analizarán, ya sea por separado o en relación con otras, para identificar patrones y características generales del fenómeno. Una vez identificadas algunas de estas características, se procederá a realizar asociaciones entre las categorías.

Inicialmente es importante reconocer el comportamiento individual de estas variables. A continuación se analiza de manera sucinta esto, por medio de representaciones gráficas, tablas de frecuencia y medidas estadísticas (para el caso de las variables cuantitativas).

Aspectos relacionados con la ubicación geográfica.

En esta categoría se incluyen las variables decimalLongitude, decimalLatitude, parentEventID y verbatimLocality.

Variables decimalLongitude y decimalLatitude

Variable decimalLongitude

library(ggplot2)
ggplot(sinFalt, aes(x = decimalLongitude)) +
  geom_density(fill = "skyblue", color = "black", alpha = 0.7) +
  labs(title = "Longitud de ubicación de las aves",
       x = "Longitud",
       y = "Densidad") +
  theme_minimal()

summary(sinFalt$decimalLongitude)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 -74.10  -74.10  -74.10  -74.09  -74.10  -74.07 

Variable decimalLatitude

ggplot(sinFalt, aes(x = decimalLatitude)) +
  geom_density(fill = "skyblue", color = "black", alpha = 0.7) +
  labs(title = "Latitud de ubicación de las aves",
       x = "Latitud",
       y = "Densidad") +
  theme_minimal()

summary(sinFalt$decimalLatitude)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  4.765   4.768   4.770   4.769   4.772   4.773 

Analizando estas dos variables por separado no se logra identificar comportamientos significativos en cuanto a sus distribuciones. Por ser coordenadas geográficas, tendrá sentido analizarlas en conjunto.

ggplot(sinFalt, aes(x = decimalLongitude, y = decimalLatitude)) +
  geom_point(color = "darkblue", alpha = 0.5, size = 1) +
  geom_density_2d(color = "darkgreen", alpha = 0.5) +
  labs(title = "Mapa de puntos y curvas de nivel de ubicación de aves y evento de muestreo",
       x = "Longitud",
       y = "Latitud") +
  theme_minimal()

De esto se puede ver que hay dos zonas claramente diferenciadas en las que se realizaron las actividades de observación de los organismos avistados, y esto tal vez este relacionado con la localidad. Esta relación se explorará más adelante.

Variable parentEventID

tabEvent=as.data.frame(table(sinFalt$parentEventID))
colnames(tabEvent)=c("Evento de muestreo","Frecuencia")
tabEvent
ggplot(tabEvent, aes(x = `Evento de muestreo`, y = Frecuencia)) +
  geom_bar(stat = "identity", fill = "skyblue", width = 0.5) +  
  geom_text(aes(label = Frecuencia), vjust = -0.5, size = 4, color = "black") +
  labs(title = "Evento de muestreo",
       x = "Evento",
       y = "Frecuencia") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

Variable verbatimLocality

tabLoc=as.data.frame(table(sinFalt$verbatimLocality))
colnames(tabLoc)=c("Localidad","Frecuencia")
tabLoc
ggplot(tabLoc, aes(x = "", y = Frecuencia, fill = Localidad)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = c("skyblue3", "skyblue4")) +
  geom_text(aes(label = paste0(round(Frecuencia / sum(Frecuencia) * 100), "%")), 
            position = position_stack(vjust = 0.5)) +
  labs(title = "Avistamientos por Localidad") +
  theme_void() +
  theme(legend.position = "right",
        axis.text.y = element_blank(),     
        axis.ticks.y = element_blank(),    
        axis.title.y = element_blank())

Relación entre ubicación y evento de muestreo

Para la exploración de esta relación se realiza un mapa de calor bidimensional. En este mapa, se representa la densidad de aves avistadas mediante curvas de nivel, y la ubicación de los eventos de muestreo se mostrará mediante puntos, indicando dónde se identificaron las aves en dichas ubicaciones.

ggplot(sinFalt, aes(x = decimalLongitude, y = decimalLatitude)) +
  geom_density_2d(color = "red", alpha = 0.5) +
  geom_point(aes(color = parentEventID), alpha = 0.8) + 
  labs(title = "Mapa de calor de ubicación de aves y evento de muestreo",
       x = "Longitud",
       y = "Latitud") +
  theme_minimal() +
  scale_color_manual(breaks = levels(sinFalt$parentEventID), values = c("blue", "green", "purple","red"))

Se puede evidenciar que existen dos zonas de mayor concentración de los avistamientos de los organismos: el evento de muestreo E1 se concentra en una única zona (superior derecha) y los demás eventos en la otra zona de concentración (parte izquierda del gráfico).

Relación entre evento de muestreo y localidad

Para poder identificar las posibles relaciones entre estas dos variables se utiliza una tabla de contingencia, herramienta que permite relacionar dos variables cualitativas y evidenciar la distribución conjunta de las variables.

tabEventHac=table(sinFalt$parentEventID, sinFalt$verbatimLocality)
tabEventHac
     
      Hacienda la Conejera Hacienda las Mercedes
  E:1                  175                     0
  E:2                    0                   190
  E:3                    0                   189
  E:4                    0                   182

Con esto se evidencia que el evento E1 tuvo concentración en la zona de la Hacienda La Conejera, mientras que el resto de eventos se concentraron en la Hacienda Las Mercedes. También se puede ver esto en un mapa de calor, similar a la gráfica anterior.

ggplot(sinFalt, aes(x = decimalLongitude, y = decimalLatitude)) +
  geom_density_2d(color = "red", alpha = 0.5) +
  geom_point(aes(color = verbatimLocality), alpha = 0.8) + 
  labs(title = "Mapa de calor de ubicación de aves y localidad de avistamiento",
       x = "Longitud",
       y = "Latitud") +
  theme_minimal() +
  scale_color_manual(breaks = levels(sinFalt$verbatimLocality), values = c("blue", "green"))

Con esto, se puede concluir que, para facilitar el procesamiento de datos, se puede seccionar el estudio por medio de los eventos o de la localidad. Esto permitiría descartar más variables al momento de encontrar patrones y analizar relaciones entre variables de manera más sencilla. Se puede optar entonces por:

  • Analizar el conjunto de datos perteneciente a la Hacienda La Conejera, lo que implica descartar las variables verbatimLocality y parentEventID, sabiendo que todos estos datos pertenecen al evento de muestreo E1.
  • Analizar cada uno de los eventos restantes por separado, lo que permite descartar las variables parentEventID y verbatimLocality, teniendo en cuenta que esta última variable tomaría el valor de “Hacienda Las Mercedes” en todos los registros de estos conjunto.

Para fines de este trabajo se realizará el estudio detallado de caso de la Hacienda La Conejera.

Aspectos relacionados con la taxonomía de los organismos

En esta categoría de análisis se tendrán en cuenta las variables orden, genus, family y scientificName. Estas variables permiten reconocer la diversidad de aves observadas en el estudio. Se realizará una exploración de lo observado en toda la Reserva y lo observado en la Hacienda La Conejera. Esto puede replicarse con cada uno de los eventos de muestreo, sí es de interés del lector.

Variable order a nivel de la Reserva

sinFalt$order=droplevels(sinFalt$order)
tabOrd=as.data.frame(table(sinFalt$order))
colnames(tabOrd)=c("Orden","Frecuencia")
tabOrd = tabOrd %>%
  arrange(desc(Frecuencia))
tabOrd
tabOrd$Orden=factor(tabOrd$Orden, levels = tabOrd$Orden[order(tabOrd$Frecuencia, decreasing = FALSE)])
ggplot(tabOrd, aes(x = Frecuencia, y = `Orden`)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = Frecuencia), hjust = -0.2, size = 2, color = "black") +
  labs(title = "Ordenes de aves identificadas en la Reserva",
       x = "Frecuencia",
       y = "Ordenes") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

Variable order a nivel de la Hacienda La Conejera

AvesConejera=sinFalt[sinFalt$verbatimLocality == "Hacienda la Conejera", ]
AvesConejera$order=droplevels(AvesConejera$order)
tabOrdH=as.data.frame(table(AvesConejera$order))
colnames(tabOrdH)=c("Orden","Frecuencia")
tabOrdH = tabOrdH %>%
  arrange(desc(Frecuencia))
tabOrdH

Variable family a nivel de la Reserva

sinFalt$family=droplevels(sinFalt$family)
tabFam=as.data.frame(table(sinFalt$family))
colnames(tabFam)=c("Familia","Frecuencia")
tabFam = tabFam %>%
  arrange(desc(Frecuencia))
tabFam
tabFam$Familia=factor(tabFam$Familia, levels = tabFam$Familia[order(tabFam$Frecuencia, decreasing = FALSE)])
ggplot(tabFam, aes(x = Frecuencia, y = `Familia`)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = Frecuencia), hjust = -0.2, size = 2, color = "black") +
  labs(title = "Familias de aves identificadas en la Reserva",
       x = "Frecuencia",
       y = "Familias") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

Variable family a nivel de la Hacienda La Conejera

AvesConejera$family=droplevels(AvesConejera$family)
tabFamH=as.data.frame(table(AvesConejera$family))
colnames(tabFamH)=c("Familia","Frecuencia")
tabFamH = tabFamH %>%
  arrange(desc(Frecuencia))
tabFamH

Variable genus a nivel de la Reserva

sinFalt$genus=droplevels(sinFalt$genus)
tabGen=as.data.frame(table(sinFalt$genus))
colnames(tabGen)=c("Género","Frecuencia")
tabGen = tabGen %>%
  arrange(desc(Frecuencia))
tabGen
tabGen$Género=factor(tabGen$Género, levels = tabGen$Género[order(tabGen$Frecuencia, decreasing = FALSE)])
ggplot(tabGen, aes(x = Frecuencia, y = `Género`)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  geom_text(aes(label = Frecuencia), hjust = -0.2, size = 2, color = "black") +
  labs(title = "Género de aves identificadas en la Reserva",
       x = "Frecuencia",
       y = "Géneros") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

Variable genus a nivel de la Hacienda La Conejera

AvesConejera$genus=droplevels(AvesConejera$genus)
tabGenH=as.data.frame(table(AvesConejera$genus))
colnames(tabGenH)=c("Género","Frecuencia")
tabGenH = tabGenH %>%
  arrange(desc(Frecuencia))
tabGenH

Variable scientificName a nivel de la reserva

sinFalt$scientificName=droplevels(sinFalt$scientificName)
tabAv=as.data.frame(table(sinFalt$scientificName))
colnames(tabAv)=c("Especie","Frecuencia")
tabAv = tabAv %>%
  arrange(desc(Frecuencia))
tabAv

Variable scientificName a nivel de la Hacienda La Conejera

AvesConejera$scientificName=droplevels(AvesConejera$scientificName)
tabAvH=as.data.frame(table(AvesConejera$scientificName))
colnames(tabAvH)=c("Especie","Frecuencia")
tabAvH = tabAvH %>%
  arrange(desc(Frecuencia))
tabAvH

Relaciones entre variables taxonómicas

Es importante tener en cuenta que estas variables siguen una jerarquía, lo que garantiza una fuerte relación entre ellas. Por tanto, para la revisión de estas variables se utilizarán diagramas de árbol, empleando la librería treemap de R..

library(treemap)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
aves_count=sinFalt %>%
   dplyr::count(order, family, name = "Count")
treemap(aves_count,
       index = c("order", "family"),
       vSize = "Count",
       vColor = "Count",
       type = "value",
       title = "Distribución de Aves por Orden y Familia en la Reserva",
       palette = "Blues",  
       border.col = "black",  
       fontsize.labels = c(15, 12), 
       align.labels = list(c("center", "center"),c("left","top")),
       inflate.labels = FALSE)  

Por medio de esta gráfica, y para el caso de estudio, se tiene que los ordenes y familias de aves más se avistaron son:

Orden Familia
Passeriformes

Emberizidae

Turdidae

Thraupidae

Ictiridae

Tyrannidae

Fringillidae

Troglodyridae

Hirundinidae

Parulidae

Columbiformes Columbidae
Apodiformes Trochilidae
Psittaciformes Psittacidae
aves_count3=AvesConejera %>%
   dplyr::count(order, family, name = "Count")
treemap(aves_count3,
       index = c("order", "family"),
       vSize = "Count",
       vColor = "Count",
       type = "value",
       title = "Distribución de Aves por Orden y Familia en la Hacienda La Conejera",
       palette = "Blues",  
       border.col = "black",  
       fontsize.labels = c(15, 12), 
       align.labels = list(c("center", "center"),c("left","top")),
       inflate.labels = FALSE)  

Aunque en este tipo de gráfica se puede incluir una tercera variable, que en la jerarquía sería la variable genus, la representación gráfica resultante no es muy amigable para su lectura. Por ello, en este caso se opta por combinar las variables order y genus para visualizar la distribución de las aves avistadas.

aves_count2=sinFalt %>%
   dplyr::count(order, genus, name = "Count")
treemap(aves_count2,
       index = c("order", "genus"),
       vSize = "Count",
       vColor = "Count",
       type = "value",
       title = "Distribución de Aves por Orden y Género en la Reserva",
       palette = "Blues",  
       border.col = "black",  
       fontsize.labels = c(15, 12), 
       align.labels = list(c("center", "center"),c("left","top")),
       inflate.labels = FALSE)  

aves_count4=AvesConejera %>%
   dplyr::count(order, genus, name = "Count")
treemap(aves_count4,
       index = c("order", "genus"),
       vSize = "Count",
       vColor = "Count",
       type = "value",
       title = "Distribución de Aves por Orden y Género en la Hacienda La Conejera",
       palette = "Blues",  
       border.col = "black",  
       fontsize.labels = c(15, 12), 
       align.labels = list(c("center", "center"),c("left","top")),
       inflate.labels = FALSE)  

Aspectos etológicos

Esta categoría de análisis se compone de las variables occurrenceRemarks, habitat, estructuraSocial y behavior.

Variable occurrenceRemarks

tabAnot=as.data.frame(table(sinFalt$occurrenceRemarks))
colnames(tabAnot)=c("Momento del día","Frecuencia")
tabAnot
ggplot(tabAnot, aes(x = "", y = Frecuencia, fill = `Momento del día`)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = c("skyblue3", "skyblue4")) +
  geom_text(aes(label = paste0(round(Frecuencia / sum(Frecuencia) * 100), "%")), 
            position = position_stack(vjust = 0.5)) +
  labs(title = "Avistamientos por momento del día-Reserva") +
  theme_void() +
  theme(legend.position = "right",
        axis.text.y = element_blank(),     
        axis.ticks.y = element_blank(),    
        axis.title.y = element_blank())

tabAnotH=as.data.frame(table(AvesConejera$occurrenceRemarks))
colnames(tabAnotH)=c("Momento del día","Frecuencia")
tabAnotH
ggplot(tabAnotH, aes(x = "", y = Frecuencia, fill = `Momento del día`)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = c("skyblue3", "skyblue4")) +
  geom_text(aes(label = paste0(round(Frecuencia / sum(Frecuencia) * 100), "%")), 
            position = position_stack(vjust = 0.5)) +
  labs(title = "Avistamientos por momento del día-Hacienda La Conejera") +
  theme_void() +
  theme(legend.position = "right",
        axis.text.y = element_blank(),     
        axis.ticks.y = element_blank(),    
        axis.title.y = element_blank())

Variable habitat

tabHab=as.data.frame(table(sinFalt$habitat))
colnames(tabHab)=c("Hábitat","Frecuencia")
tabHab
ggplot(tabHab, aes(x = "", y = Frecuencia, fill =Hábitat)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = c("lightblue3","skyblue3", "skyblue4","lightblue")) +
  geom_text(aes(label = paste0(round(Frecuencia / sum(Frecuencia) * 100), "%")), 
            position = position_stack(vjust = 0.5)) +
  labs(title = "Hábitat en los que se avistaron las aves-Reserva") +
  theme_void() +
  theme(legend.position = "right",
        axis.text.y = element_blank(),     
        axis.ticks.y = element_blank(),    
        axis.title.y = element_blank())

tabHabH=as.data.frame(table(AvesConejera$habitat))
colnames(tabHabH)=c("Hábitat","Frecuencia")
tabHabH
ggplot(tabHabH[tabHabH$Frecuencia > 0, ], aes(x = "", y = Frecuencia, fill =Hábitat)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = c("lightblue3","skyblue3", "lightblue")) +
  geom_text(aes(label = paste0(round(Frecuencia / sum(Frecuencia) * 100), "%")), 
            position = position_stack(vjust = 0.5)) +
  labs(title = "Hábitat en los que se avistaron las aves-Hacienda La Conejera") +
  theme_void() +
  theme(legend.position = "right",
        axis.text.y = element_blank(),     
        axis.ticks.y = element_blank(),    
        axis.title.y = element_blank())

Variable estructuraSocial

tabEstr=as.data.frame(table(sinFalt$estructuraSocial))
colnames(tabEstr)=c("Est. Social","Frecuencia")
tabEstr
ggplot(tabEstr, aes(x = `Est. Social`, y = Frecuencia)) +
  geom_bar(stat = "identity", fill = "skyblue", width = 0.5) +  
  geom_text(aes(label = Frecuencia), vjust = -0.5, size = 4, color = "black") +
  labs(title = "Estructura social de las aves avistadas-Reserva",
       x = "Estr. Social",
       y = "Frecuencia") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

AvesConejera$estructuraSocial=droplevels(AvesConejera$estructuraSocial)
tabEstrH=as.data.frame(table(AvesConejera$estructuraSocial))
colnames(tabEstrH)=c("Est. Social","Frecuencia")
tabEstrH
ggplot(tabEstrH, aes(x = `Est. Social`, y = Frecuencia)) +
  geom_bar(stat = "identity", fill = "skyblue", width = 0.5) +  
  geom_text(aes(label = Frecuencia), vjust = -0.5, size = 4, color = "black") +
  labs(title = "Estructura social de las aves avistadas-Hacienda La Conejera",
       x = "Estr. Social",
       y = "Frecuencia") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

Variable behavior

sinFalt$behavior=droplevels(sinFalt$behavior)
tabComp=as.data.frame(table(sinFalt$behavior))
colnames(tabComp)=c("Comportamiento","Frecuencia")
tabComp
ggplot(tabComp, aes(x = Comportamiento, y = Frecuencia)) +
  geom_bar(stat = "identity", fill = "skyblue", width = 0.5) +  
  geom_text(aes(label = Frecuencia), vjust = -0.5, size = 4, color = "black") +
  labs(title = "Comportamiento de las aves avistadas-Reserva",
       x = "Comportamiento",
       y = "Frecuencia") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

AvesConejera$behavior=droplevels(AvesConejera$behavior)
tabCompH=as.data.frame(table(AvesConejera$behavior))
colnames(tabCompH)=c("Comportamiento","Frecuencia")
tabCompH
ggplot(tabCompH, aes(x = Comportamiento, y = Frecuencia)) +
  geom_bar(stat = "identity", fill = "skyblue", width = 0.5) +  
  geom_text(aes(label = Frecuencia), vjust = -0.5, size = 4, color = "black") +
  labs(title = "Comportamiento de las aves avistadas-Hacienda La Conejera",
       x = "Comportamiento",
       y = "Frecuencia") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))

Relaciones entre las variables etológicas

Para examinar cómo interactúan estas variables, se realizará un diagrama de árbol para explorar la partición correspondiente a la Hacienda La Conejera en los avistamientos realizados en la mañana, aprovechando su potencial para resumir el comportamiento de las variables en conjunto. A diferencia de las variables taxonómicas, estas no siguen una jerarquía específica, por lo que queda a discreción del investigador elegir el orden en que se presentarán en el diagrama. Para el presente estudio, se trabajarán estas variables en el siguiente orden: comportamiento, hábitat y estructura social.

AvesConeAM=AvesConejera[AvesConejera$occurrenceRemarks == "mañana", ]
AvesConeAM_count=AvesConeAM %>%
  dplyr::count(behavior,habitat,estructuraSocial,name = "Count")
treemap(AvesConeAM_count,
        index = c( "behavior","habitat","estructuraSocial"),
        vSize = "Count",
         vColor = "Count",
         type = "value",
         title = "Distribución de las aves según su comportamiento, hábitat y estr. social",
         palette = "Blues",  
         border.col = "black",  
         fontsize.labels = c(16, 13, 10), 
         align.labels =list(
           c("center", "top"),   
           c("left", "center"),  
           c("right", "bottom")  
         ),
         inflate.labels = FALSE)

Como se puede ver, la mayoría de los avistamientos de la mañana en la Hacienda La Conejera correspondieron a aves descansando en hábitats de bosque mixto nativo, en grupos coespecíficos. Posteriormente, se observó una cantidad considerable de aves desplazándose entre la vegetación, principalmente en hábitats de bosque nativo, en grupos coespecíficos o en parejas. En menor proporción, se avistaron aves alimentándose, principalmente en bosque nativo y en parejas. Con menor frecuencia, se observaron aves volando, en igual proporción en bosques mixtos y nativos, usualmente en grupos coespecíficos.

Análisis de asociaciónes por categorías

Una vez estudiado el fenómeno de biodiversidad por categorías, se propone buscar posibles relaciones entre estas para extraer información adicional que permita identificar patrones en el muestreo recolectado en la base de datos. Para esto, se utilizará un método estadístico multivariado conocido como Análisis de Correspondencia Múltiple (ACM). En el presente estudio, se analizará la partición correspondiente a la localidad de la Hacienda La Conejera y las observaciones realizadas en la jornada de la mañana. Las variables consideradas serán el orden (order), el comportamiento (behavior), la estructura social (estructuraSocial) y el hábitat (habitat).

Análisis de correspondencia múltiple

library(FactoMineR)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
datosACM=subset(AvesConeAM, select = c("order",
                                    "behavior",
                                    "estructuraSocial",
                                    "habitat"))
mca=MCA(datosACM,graph=FALSE)
library(factoextra)
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(pander)
eigenval=get_eigenvalue(mca)
pander(eigenval)

--------------------------------------------------------------------------
   &nbsp;     eigenvalue   variance.percent   cumulative.variance.percent 
------------ ------------ ------------------ -----------------------------
 **Dim.1**      0.5181          20.72                    20.72            

 **Dim.2**      0.3563          14.25                    34.97            

 **Dim.3**      0.3418          13.67                    48.65            

 **Dim.4**      0.2924           11.7                    60.34            

 **Dim.5**      0.2597          10.39                    70.73            

 **Dim.6**      0.1932          7.728                    78.46            

 **Dim.7**      0.1764          7.056                    85.51            

 **Dim.8**      0.1599          6.397                    91.91            

 **Dim.9**      0.1075          4.301                    96.21            

 **Dim.10**    0.09471          3.789                     100             
--------------------------------------------------------------------------
scpl=fviz_screeplot(mca,addlabels=TRUE)
scpl

Se tiene que las primeras cinco dimensiones determinadas por el ACM explican un 70.73% de la varianza del fénomeno estudiado. Se procede a explorar las actegorías que definen estas dimensiones.

varCont=mca$var$contrib
varContT=rowSums(varCont[, 1:5])
varContP=100*varContT/sum(varContT)
varContDF=data.frame(Variable=names(varContP), Contribución=varContP)
varContDF=varContDF[order(varContDF$Contribución, decreasing = TRUE), ]
varContDF
par(mar = c(15, 4, 4, 2) + 0.1)
barplot=barplot(varContDF$Contribución, 
                         names.arg = varContDF$Variable, 
                         las = 2, 
                         col = "#4682b4",
                         main = "Contribución de las categorias de las variables a las Dimensiones 1-5 (%)",
                         ylim = c(0, max(varContDF$Contribución) * 1.2))
text(x = barplot,
      y = varContDF$Contribución,
      label = sprintf("%.1f%%", varContDF$Contribución),
      pos = 3, cex = 0.8, col = "black")

Al detallar las categorías que determinan estas cinco dimensiones, se encuentran que entre las principales 14 se resaltan ordenes taxonómicos como los cuculiformes, galliformes y los apodiformes, así como comportamientos como volar, alimentarse y moverse entre la vegetación, y la estancia de las aves en parejas. Además, hábitats como el bosque mixto nativo y el bosque nativo también figuran entre las categorías más significativas

Clusterización por k-means

Aprovechando el proceso realizado con el ACM, se procede a hacer un proceso de clusterización por k-means, con el fin de identificar grupos con características similares. Para este proceso, se hará uso de las primeras dos dimensiones generadas por el ACM (que explican el 35% de la varianza). Inicialmente se revisa las categorías que determinan estas dos dimensiones.

varContT2=rowSums(varCont[, 1:2])
varContP2=100*varContT2/sum(varContT2)
varContDF2=data.frame(Variable=names(varContP2), Contribución=varContP2)
varContDF2=varContDF2[order(varContDF2$Contribución, decreasing = TRUE), ]
varContDF2
par(mar = c(15, 4, 4, 2) + 0.1)
barplot2 = barplot(varContDF2$Contribución, 
                   names.arg = varContDF2$Variable, 
                   las = 2, 
                   col = "#4682b4",
                   main = "Contribución de las categorías de las variables a las Dimensiones 1-2 (%)",
                   ylim = c(0, max(varContDF2$Contribución) * 1.2))
text(x = barplot2,
     y = varContDF2$Contribución,
     label = sprintf("%.1f%%", varContDF2$Contribución),
     pos = 3, cex = 0.8, col = "black")

Entre las categorías que tienen contribuciones significativas a estas dimensiones se encuentran los órdenes Galliformes, Columbiformes y Cuculiformes, así como comportamientos como la alimentación y el movimiento entre vegetación, la estancia en grupos coespecíficos o en solitario.

Luego de esto, se procede a la exploración de asociaciones entre observaciones y categorías por medio de un diagrama de biplot.

par(mar = c(15, 4, 4, 2) + 0.1)
barplot2 = barplot(varContDF2$Contribución, 
                   names.arg = varContDF2$Variable, 
                   las = 2, 
                   col = "#4682b4",
                   main = "Contribución de las categorías de las variables a las Dimensiones 1-2 (%)",
                   ylim = c(0, max(varContDF2$Contribución) * 1.2))
text(x = barplot2,
     y = varContDF2$Contribución,
     label = sprintf("%.1f%%", varContDF2$Contribución),
     pos = 3, cex = 0.8, col = "black")



![](dm12nb)
Error: inesperado '[' en "!["

Usando este gráfico como base, se inicia el proceso de clusterización.

library(cluster)
indCoords=mca$ind$coord
set.seed(123)
kmRes=kmeans(indCoords, centers = 3, nstart = 25)
mca$ind$cluster=kmRes$cluster
indData=data.frame(indCoords,cluster = as.factor(kmRes$cluster))
createPolygon=function(cluster_data){
  hull=chull(cluster_data$Dim.1, cluster_data$Dim.2)
  hull=c(hull, hull[1])
  cluster_data[hull, ]
}

polygonData=indData %>%
  group_by(cluster) %>%
  do(createPolygon(.))

ggplot(indData, aes(x = Dim.1, y = Dim.2, color = cluster)) +
  geom_point() +
  geom_polygon(data = polygonData, aes(x = Dim.1, y = Dim.2, group = cluster, fill = cluster), alpha = 0.2) +
  theme_minimal() +
  labs(title = "Clusterización de Aves", x = "Dimensión 1", y = "Dimensión 2")

combPlot +
  geom_point(data = indData, aes(x = Dim.1, y = Dim.2, color = cluster)) +
  geom_polygon(data = polygonData, aes(x = Dim.1, y = Dim.2, group = cluster, fill = cluster), alpha = 0.2)

Este proceso se realizó estableciendo tres clústeres, de los cuales dos están claramente definidos en la gráfica. El primer grupo muestra que las aves del orden Columbiformes tienden a habitar bosques mixtos nativos y son avistadas en grupos coespecíficos. En el segundo clúster, se observa que las aves de los órdenes Passeriformes y Apodiformes suelen habitar bosques nativos y son avistadas mientras descansan en parejas o solas. El último grupo no está tan bien delimitado como los dos anteriores, mostrando una alta heterogeneidad y no agrupándose según las categorías predominantes de las dos dimensiones analizadas en este proceso.

Referencias

Barrera, M. C. A. (2023, agosto). Caracterización de avifauna - Reserva Thomas Vander Hammen v2.1. Dataset/Occurrence. https://doi.org/10.15472/alrlwe

Griffiths, Richard, and D Phil. (2000). “Sex Identification in Birds.”

LS0tDQp0aXRsZTogIkFuw6FsaXNpcyBkZSB1bmEgYmFzZSBkZSBkYXRvcyBkZSBiaW9kaXZlcnNpZGFkOiBhdmlmYXVuYSBlbiBsYSBSZXNlcnZhIFRob21hcyB2YW5kZXIgSGFtbWVuIg0KYXV0aG9yOiAnTWljaGVsbGUgUGVuYWdvcy1WYXJnYXMnDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHRydWUNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgdGhlbWU6IGx1bWVuDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UNCi0tLQ0KDQojIEludHJvZHVjY2nDs24NCg0KRWwgcHJlc2VudGUgbm90ZWJvb2sgbXVlc3RyYSBlbCBjw7NkaWdvIHV0aWxpemFkbyBwYXJhIHJlYWxpemFyIGVsIGVzdHVkaW8gcHJlc2VudGFkbyBlbiBlbCBhcnTDrWN1bG8gIk1ldG9kb2xvZ8OtYXMgZGUgZXN0dWRpbyBlc3RhZMOtc3RpY28gZGUgYmFzZXMgZGUgZGF0b3MgZGUgYmlvZGl2ZXJzaWRhZDogZWwgY2FzbyBkZSB1bmEgYmFzZSBkZSBkYXRvcyBkZSBsYSBiaW9kaXZlcnNpZGFkIGRlIGF2aWZhdW5hIGVuIGxhIHJlc2VydmEgVGhvbWFzIHZhbiBkZXIgSGFtbWVuLiIgeSB0aWVuZSBjb21vIG9iamV0aXZvIGRldGFsbGFyIGxvcyBwcm9jZWRpbWllbnRvcyB5IGFuw6FsaXNpcyBlc3RhZMOtc3RpY29zIGFwbGljYWRvcyBhIGxhIGJhc2UgZGUgZGF0b3MgZXN0dWRpYWRhLiBTZSBkZXNjcmliZW4gbG9zIHBhc29zIHNlZ3VpZG9zIGRlc2RlIGxhIGxpbXBpZXphIHkgcHJlcGFyYWNpw7NuIGRlIGxvcyBkYXRvcyBoYXN0YSBsYSBhcGxpY2FjacOzbiBkZSB0w6ljbmljYXMgZXN0YWTDrXN0aWNhcyBhdmFuemFkYXMgeSBsYSB2aXN1YWxpemFjacOzbiBkZSByZXN1bHRhZG9zLg0KDQojIFByZXBhcmFjacOzbiBkZSBsYSBiYXNlIGRlIGRhdG9zDQoNCkVzIGltcG9ydGFudGUgZGVzdGFjYXIgcXVlIGxhIGJhc2UgZGUgZGF0b3Mgb3JpZ2luYWwgKEJhcnJlcmEsIDIwMjMpIGNvbnRlbsOtYSA1MyB2YXJpYWJsZXMuIEFudGVzIGRlIHRyYWJhamFyIGVuIGVsIGVudG9ybm8gZGUgUiwgc2UgcmVhbGl6w7MgdW4gcHJpbWVyIGZpbHRybyBkZSBpbmZvcm1hY2nDs24sIHJlZHVjaWVuZG8gZWwgbsO6bWVybyBkZSB2YXJpYWJsZXMgYSAxOCwgbGFzIGN1YWxlcyBmb3JtYXJvbiBwYXJ0ZSBkZWwgZXN0dWRpbyBmaW5hbC4gRXN0YSB2ZXJzacOzbiBkZSBsYSBiYXNlIGRlIGRhdG9zIHB1ZWRlIGRlc2NhcmdhcnNlIGluZ3Jlc2FuZG8gYSBlc3RlIFtlbmxhY2VdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS91Yz9pZD0xU3ZHUzFXSHpvTGFmZWhHTW52RFBHeEd2eVFMYmdSS2QpLg0KDQoqKkNhcmd1ZSBkZSBsYSBiYXNlIGRlIGRhdG9zKioNCg0KYGBge3IgQ2FyZ3VlIGRlIGxhIGJhc2UgZGUgZGF0b3N9DQpsaWJyYXJ5KHJlYWRyKQ0KZGJBdmVzPXJlYWRfZGVsaW0oImh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS91Yz9pZD0xU3ZHUzFXSHpvTGFmZWhHTW52RFBHeEd2eVFMYmdSS2QiLA0KICAgICAgICAgICAgICAgICAgICAgZGVsaW0gPSAiLCIsDQogICAgICAgICAgICAgICAgICAgICBlc2NhcGVfZG91YmxlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICB0cmltX3dzID0gVFJVRSkNCmBgYA0KDQpgYGB7ciBBcnJlZ2xvIGRlIHZhcmlhYmxlcywgaW5jbHVkZT1GQUxTRX0NCmRiQXZlcyRlc3RydWN0dXJhU29jaWFsPWRiQXZlcyRgRXN0cnVjdHVyYSBzb2NpYWxgDQpkYkF2ZXM9c3Vic2V0KGRiQXZlcyxzZWxlY3Q9LWBFc3RydWN0dXJhIHNvY2lhbGApDQpkYkF2ZXMkYWx0dXJhT2JzZXJ2YWNpb249ZGJBdmVzJGBBbHR1cmEgZGUgb2JzZXJ2YWNpw7NuYA0KZGJBdmVzPXN1YnNldChkYkF2ZXMsc2VsZWN0PS1gQWx0dXJhIGRlIG9ic2VydmFjacOzbmApDQpgYGANCg0KYGBge3IgUmVzdW1lbiAxfQ0Kc3VtbWFyeShkYkF2ZXMpDQpgYGANCg0KIyMgUHJpbWVyYSBmYXNlDQoNCkRlbCByZXN1bWVuIG9idGVuaWRvIGFudGVyaW9ybWVudGUgc2Ugb2JzZXJ2YSBxdWU6DQoNCi0gICBBdW5xdWUgbGFzIHZhcmlhYmxlcyBgZGVjaW1hbExhdGl0dWRlYCB5IGBkZWNpbWFsTG9uZ2l0dWRlYCBzZSBpZGVudGlmaWNhbiBjb21vIGN1YW50aXRhdGl2YXMsIG5vIHNvbiBjb3JyZWN0YXMsIHlhIHF1ZSBzdXMgcGFydGVzIGRlY2ltYWxlcyBzZSBjb252aXJ0aWVyb24gZW4gZW50ZXJvcy4gUGFyYSBjb3JyZWdpciBlc3RvLCBzZSB1dGlsaXphcsOhbiBsYXMgdmFyaWFibGVzIGB2ZXJiYXRpbUxhdGl0dWRlYCB5IGB2ZXJiYXRpbUxvbmdpdHVkZWAuIFVuYSB2ZXogcmVhbGl6YWRhIGVzdGEgbW9kaWZpY2FjacOzbiwgZXN0YXMgZG9zIMO6bHRpbWFzIHZhcmlhYmxlcyBwdWVkZW4gZWxpbWluYXJzZSwgeWEgcXVlIHNlIGhhYnLDoSBvYnRlbmlkbyBsYSBtZWRpZGEgbnVtw6lyaWNhIGNvcnJlY3RhLg0KLSAgIExhcyB2YXJpYWJsZXMgcXVlIFIgY2xhc2lmaWNhIGNvbW8gKmNoYXJhY3RlciogZGViZW4gY29udmVydGlyc2UgYSBmYWN0b3Jlcy4NCi0gICBMYSB2YXJpYWJsZSBgYWx0dXJhT2JzZXJ2YWNpw7NuYCBkZWJlIHNlciB0cmF0YWRhIHBhcmEgcXVlIHRvbWUgdmFsb3JlcyBudW3DqXJpY29zLg0KDQpTZSBpbmljaWEgY29uIGxvcyBwcm9jZWRpbWllbnRvcyBwYXJhIGFib3JkYXIgZXN0b3MgaGFsbGF6Z29zLg0KDQojIyMgVmFyaWFibGVzIGBkZWNpbWFsTGF0aXR1ZGVgIHkgYGRlY2ltYWxMb25naXR1ZGVgDQoNClBhcmEgaGFjZXIgbG9zIGNhbWJpb3MgZW4gZXN0YXMgdmFyaWFibGVzLCBzZSB1dGlsaXphcsOhbiBsYXMgdmFyaWFibGVzIGB2ZXJiYXRpbUxhdGl0dWRlYCB5IGB2ZXJiYXRpbUxvbmdpdHVkZWAgcGFyYSByZWFsaXphciBsYSBjb252ZXJzacOzbiBjb3JyZWN0YSBkZSBsYXMgY29vcmRlbmFkYXMgZGUgc3UgZm9ybWEgR01TIGEgZGVjaW1hbC4gU2UgcHJvZ3JhbWFyw6EgdW5hIGZ1bmNpw7NuIHF1ZSB0b21lIGxhIGNhZGVuYSBkZSB0ZXh0byBjb24gbGFzIGNvb3JkZW5hZGFzIEdNUywgaWRlbnRpZmlxdWUgc3VzIGNvbXBvbmVudGVzLCBsb3MgY29udmllcnRhIGEgdmFsb3JlcyBudW3DqXJpY29zIHkgbHVlZ28gcmVhbGljZSBsYXMgb3BlcmFjaW9uZXMgYXJpdG3DqXRpY2FzIG5lY2VzYXJpYXMgcGFyYSBvYnRlbmVyIGVsIHZhbG9yIGRlY2ltYWwgZGUgbGEgY29vcmRlbmFkYS4gVW5hIHZleiByZWFsaXphZGEgbGEgY29udmVyc2nDs24sIHNlIGVsaW1pbmFyw6FuIGxhcyB2YXJpYWJsZXMgYHZlcmJhdGltTGF0aXR1ZGVgIHkgYHZlcmJhdGltTG9uZ2l0dWRlYC4NCg0KYGBge3IgVHJhdGFtaWVudG8gZGUgbGF0aXR1ZGVzIHkgbG9uZ2l0dWRlc30NCmNvbnZMYXQgPC0gZnVuY3Rpb24oZWplbXBsbykgew0KICBwYXJ0ZXMxID1zdHJzcGxpdChlamVtcGxvLCAiXHUwMEIwIikNCiAgZ3JhZG9zID0gYXMubnVtZXJpYyhwYXJ0ZXMxW1sxXV1bMV0pDQogIHBhcnRlczI9c3Ryc3BsaXQocGFydGVzMVtbMV1dWzJdLCAiXHUwMEI0IikNCiAgbWludXRvcyA9YXMubnVtZXJpYyhwYXJ0ZXMyW1sxXV1bMV0pDQogIHNlZ3VuZG9zID1hcy5udW1lcmljKHBhcnRlczJbWzFdXVsyXSkNCiAgZGVjaW1hbExhdCA9IGdyYWRvcyArIG1pbnV0b3MgLyA2MCArIHNlZ3VuZG9zIC8gMzYwMA0KICByZXR1cm4oZGVjaW1hbExhdCl9DQpjb252TG9uPWZ1bmN0aW9uKGVqZW1wbG8pew0KICBwYXJ0ZXMxID1zdHJzcGxpdChlamVtcGxvLCAiXHUwMEIwIikNCiAgZ3JhZG9zID0gYXMubnVtZXJpYyhwYXJ0ZXMxW1sxXV1bMV0pDQogIHBhcnRlczI9c3Ryc3BsaXQocGFydGVzMVtbMV1dWzJdLCAiXHUwMEI0IikNCiAgbWludXRvcyA9YXMubnVtZXJpYyhwYXJ0ZXMyW1sxXV1bMV0pDQogIHNlZ3VuZG9zID1hcy5udW1lcmljKHBhcnRlczJbWzFdXVsyXSkNCiAgZGVjaW1hbExvbiA9IChncmFkb3MgKyBtaW51dG9zIC8gNjAgKyBzZWd1bmRvcyAvIDM2MDApKi0xDQogIHJldHVybihkZWNpbWFsTG9uKQ0KfQ0KZGJBdmVzJGRlY2ltYWxMYXRpdHVkZT1zYXBwbHkoZGJBdmVzJHZlcmJhdGltTGF0aXR1ZGUsY29udkxhdCkNCmRiQXZlcyRkZWNpbWFsTG9uZ2l0dWRlPXNhcHBseShkYkF2ZXMkdmVyYmF0aW1Mb25naXR1ZGUsY29udkxvbikNCmRiQXZlcz1zdWJzZXQoZGJBdmVzLHNlbGVjdCA9IC12ZXJiYXRpbUxhdGl0dWRlKQ0KZGJBdmVzPXN1YnNldChkYkF2ZXMsc2VsZWN0ID0gLXZlcmJhdGltTG9uZ2l0dWRlKQ0KYGBgDQoNCiMjIyBDb252ZXJzacOzbiBkZSB2YXJpYWJsZXMgdGlwbyBgY2hhcmFjdGVyYCBvIGNhcsOhY3Rlci4NCg0KUGFyYSBoYWNlciB1biBjb3JyZWN0byB0cmF0YW1pZW50byBkZSB2YXJpYWJsZXMgY3VhbGl0YXRpdmFzIGVuIGVsIGVudG9ybm8gZGUgUiwgZXMgbmVjZXNhcmlvIHF1ZSBlc3RhcyBzZWFuIGRlIHRpcG8gZmFjdG9yLiBFbiBlc3RlIGNhc28sIHNlIHJlYWxpemFyw6EgbGEgY29udmVyc2nDs24gZGUgbGFzIHZhcmlhYmxlcyBxdWUgaW5pY2lhbG1lbnRlIHNlIGlkZW50aWZpY2Fyb24gY29tbyBkZSB0aXBvIGNhcsOhY3RlciAoaW5jbHVpZGEgbGEgdmFyaWFibGUgYGFsdHVyYU9ic2VydmFjaW9uYCBwYXJhIHBvZGVyIGV4cGxvcmFybGEsIGEgcGVzYXIgZGUgcXVlIGRlYmVyw61hIHNlciB1bmEgdmFyaWFibGUgbnVtw6lyaWNhKS4NCg0KYGBge3IgQ29udmVyc2nDs24gYSBmYWN0b3J9DQpsaWJyYXJ5KGRwbHlyKQ0KZGJBdmVzPWRiQXZlcyAlPiUNCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCBhcy5mYWN0b3IpKQ0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgYWx0dXJhT2JzZXJ2YWNpb25gDQoNCkVuIGVzdGUgcHVudG8sIGVzdGEgdmFyaWFibGUgZXMgZGUgdGlwbyBmYWN0b3IsIHBvciBsbyBxdWUgdW4gYnVlbiBwcmltZXIgcGFzbyBlcyByZXZpc2FyIGxhcyBjYXRlZ29yw61hcyBxdWUgbGEgY29tcG9uZW4uDQoNCmBgYHtyIEV4YW1pbmFuZG8gdmFyaWJsZSBhbHR1cmFPYnNlcnZhY2lvbn0NCnVuaXF1ZShkYkF2ZXMkYWx0dXJhT2JzZXJ2YWNpb24pDQpgYGANCg0KQ29tbyBzZSBwdWVkZSBldmlkZW5jaWFyLCBoYXkgY2F0ZWdvcsOtYXMgcXVlIG5vIHNvbiBwcm9waWFtZW50ZSB1biBuw7ptZXJvLCBjb21vICJcPDAuNiIsICIxLjUtMiIsICJCYWpvIiwgIlw+NCIgeSAiMy01Ii4gQ29uIHJlc3BlY3RvIGEgbGEgY2F0ZWdvcsOtYSAiI04vRCIsIHNvbiBkYXRvcyBkZSBsb3MgY3VhbGVzIG5vIHNlIHRpZW5lIHVuIHZhbG9yIHJlZ2lzdHJhZG8sIHBvciBsbyBxdWUgbm8gc2UgZGViZW4gbW9kaWZpY2FyIHkgZGViZW4gdHJhdGFyc2UgY29tbyBkYXRvcyBmYWx0YW50ZXMuDQoNCkRhZG8gcXVlIGVzdGEgZXMgdW5hIHZhcmlhYmxlIGRlIG5hdHVyYWxlemEgY3VhbnRpdGF0aXZhLCBzZXLDrWEgaW50ZXJlc2FudGUgcG9kZXIgdHJhdGFybGEgY29tbyB0YWwuIFBvciBsbyB0YW50bywgcGFyYSBlc3RlIGVzdHVkaW8gc2UgcmVhbGl6YXLDoW4gbW9kaWZpY2FjaW9uZXMgYSBlc3RhcyBjYXRlZ29yw61hcyB5IGEgbG9zIHJlZ2lzdHJvcyBxdWUgbGFzIGNvbnRlbmdhbi4gRXN0YXMgbW9kaWZpY2FjaW9uZXMgc2UgcmVhbGl6YXLDoW4gdGVuaWVuZG8gZW4gY3VlbnRhIGxvcyBzaWd1aWVudGVzIHBhcsOhbWV0cm9zOg0KDQotICAgTGEgY2F0ZWdvcsOtYSAiI04vRCIgZGViZSBtb2RpZmljYXJzZSBwYXJhIHF1ZSB0b21lIHZhbG9yZXMgZGUgTkEuDQotICAgQSBsYXMgY2F0ZWdvcsOtYXMgcXVlIGRlbm90ZW4gaW50ZXJ2YWxvcyBzZSBsZXMgYXNpZ25hcsOhIGVsIHZhbG9yIG1lZGlvIGVudHJlIGxvcyBsw61taXRlcyBkZWwgbWlzbW8uDQotICAgQSBsYSBjYXRlZ29yw61hICJcPDAuNiIgc2UgbGUgZGVzaWduYXLDoSBlbCB2YWxvciBkZSAwLjUuDQotICAgQSBsYSBjYXRlZ29yw61hICJcPjQiIHNlIGxlIGFzaWduYXLDoSBlbCB2YWxvciBkZSA1Lg0KLSAgIEEgbGEgY2F0ZWdvcsOtYSAiQmFqbyIgc2UgbGUgZGVzaWduYXLDoSBlbCB2YWxvciBkZSAwLjMuDQoNCmBgYHtyIE1vZGlmaWNhbmRvIGxhIHZhcmlhYmxlIGFsdHVyYU9ic2VydmFjaW9ufQ0KZGJBdmVzIDwtIGRiQXZlcyAlPiUNCiAgbXV0YXRlKGFsdHVyYU9ic2VydmFjaW9uID0gY2FzZV93aGVuKA0KICAgIGFsdHVyYU9ic2VydmFjaW9uID09ICIjTi9EIiB+IE5BX3JlYWxfLA0KICAgIGFsdHVyYU9ic2VydmFjaW9uID09ICIxLjUtMiIgfiAxLjcsDQogICAgYWx0dXJhT2JzZXJ2YWNpb24gPT0gIjMtNSIgfiA0LA0KICAgIGFsdHVyYU9ic2VydmFjaW9uID09ICI8MC42IiB+IDAuNSwNCiAgICBhbHR1cmFPYnNlcnZhY2lvbiA9PSAiPjQiIH4gNSwNCiAgICBhbHR1cmFPYnNlcnZhY2lvbiA9PSAiQmFqbyIgfiAwLjMsDQogICAgVFJVRSB+IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGFsdHVyYU9ic2VydmFjaW9uKSkNCiAgKSkNCmBgYA0KDQpQYXJhIGZpbmFsaXphciBlc3RhIHByaW1lcmEgZmFzZSBkZSBsaW1waWV6YSBkZSBsYSBiYXNlIGRlIGRhdG9zLCBsYSB2YXJpYWJsZSBgSURgIHNlIGNvbnZpZXJ0ZSBlbiBlbCBpZGVudGlmaWNhZG9yIGRlIGZpbGEgeSBubyBzZSB0b21hcsOhIGVuIGN1ZW50YSBjb21vIHVuYSB2YXJpYWJsZSBhIHBhcnRpciBkZSBlc3RlIG1vbWVudG8uDQoNCmBgYHtyIFZhcmlhYmxlIElEfQ0Kcm93bmFtZXMoZGJBdmVzKT1kYkF2ZXMkaWQNCmRiQXZlcyRpZD1OVUxMDQpgYGANCg0KYGBge3IgUmVzdW1lbiAyfQ0Kc3VtbWFyeShkYkF2ZXMpDQpoZWFkKGRiQXZlcykNCmBgYA0KDQojIyBTZWd1bmRhIGZhc2UNCg0KQ29tbyBzZSBwdWVkZSBldmlkZW5jaWFyIGVuIGVsIMO6bHRpbW8gcmVzdW1lbiBlbWl0aWRvLCBzZSBvYnNlcnZhIHF1ZSBoYXkgdmFyaWFibGVzIHF1ZSB0aWVuZW4gZGF0b3MgZmFsdGFudGVzIChhcGFyZWNlbiBiYWpvIGxhIGNhdGVnb3LDrWEgIk5BJ3MiKS4gU2UgcHJvY2VkZSBhIHJldmlzYXIgZWwgcG9yY2VudGFqZSBkZSBkYXRvcyBmYWx0YXRlcyBwb3IgdmFyaWFibGUuDQoNCmBgYHtyIERhdG9zIGZhbHRhbnRlc30NCmZhbHQ9Y29sU3Vtcyhpcy5uYShkYkF2ZXMpKQ0KcG9yY0ZhbHQ9cm91bmQoKGZhbHQvbnJvdyhkYkF2ZXMpKSoxMDAsMCkNCmRmRmFsdGFudGVzPWRhdGEuZnJhbWUoRmFsdGFudGVzPWZhbHQsDQogICAgICAgICAgICAgICAgICAgICAgIFBvcmNlbnRhamU9cG9yY0ZhbHQpDQogZGZGYWx0YW50ZXNbZGZGYWx0YW50ZXMkUG9yY2VudGFqZSAhPSAwLCBdDQpgYGANCg0KTGEgcHJlc2VuY2lhIGRlIGRhdG9zIGZhbHRhbnRlcyBlcyBjb23Dum4gYWwgYW5hbGl6YXIgYmFzZXMgZGUgZGF0b3MgZGUgYmlvZGl2ZXJzaWRhZCwgbG8gY3VhbCBwdWVkZSBhZmVjdGFyIGxhIGNvbmZpYWJpbGlkYWQgZGUgbG9zIGFuw6FsaXNpcy4gRW4gZXN0ZSBlc3R1ZGlvLCBzZSBoYSBkZWNpZGlkbyBlbGltaW5hciBkZWwgY29uanVudG8gZGUgZGF0b3MgYXF1ZWxsYXMgdmFyaWFibGVzIHF1ZSBwcmVzZW50ZW4gdW4gcG9yY2VudGFqZSBkZSBkYXRvcyBmYWx0YW50ZXMgc3VwZXJpb3IgYWwgNjUlLiBFbiBlc3RlIGNhc28sIGxhcyB2YXJpYWJsZXMgYGFsdHVyYU9ic2VydmFjacOzbmAgeSBgYXNzb2NpYXRlZFRheGFgIGN1bXBsZW4gY29uIGVzdGUgY3JpdGVyaW8geSBzZXLDoW4gZXhjbHVpZGFzIGRlbCBhbsOhbGlzaXMuDQoNCmBgYHtyIEVsaW1pbmFjacOzbiBkZSB2YXJpYWJsZXN9DQpkYkF2ZXM9c3Vic2V0KGRiQXZlcywgc2VsZWN0PS1hbHR1cmFPYnNlcnZhY2lvbikNCmRiQXZlcz1zdWJzZXQoZGJBdmVzLCBzZWxlY3Q9LWFzc29jaWF0ZWRUYXhhKQ0Kc3VtKGNvbXBsZXRlLmNhc2VzKGRiQXZlcykpDQpgYGANCg0KQWRlbcOhcywgc2UgaGEgb2JzZXJ2YWRvIHF1ZSBsYSBiYXNlIGRlIGRhdG9zIGNvbnRpZW5lIHVuIHRvdGFsIGRlIDczNiByZWdpc3Ryb3MgY29tcGxldG9zLiBQb3IgbG8gdGFudG8sIHNlIGhhIGRlY2lkaWRvIHRyYWJhamFyIGV4Y2x1c2l2YW1lbnRlIGNvbiBlc3RvcyByZWdpc3Ryb3MuIFNlIHByb2NlZGVyw6EgYSBnZW5lcmFyIHVuYSBjb3BpYSBkZSBsYSBiYXNlIGRlIGRhdG9zIHF1ZSBjb250ZW5nYSDDum5pY2FtZW50ZSBlc3RvcyByZWdpc3Ryb3MsIGNvbiBlbCBmaW4gZGUgcmVhbGl6YXIgdW4gYW7DoWxpc2lzIG3DoXMgZGV0YWxsYWRvIGRlIGxhcyB2YXJpYWJsZXMgeSBkZSBsYSBiYXNlIGRlIGRhdG9zIGVuIGdlbmVyYWwuDQoNCmBgYHtyIENvcGlhIGRlIGxhIGJhc2UgZGUgZGF0b3N9DQpzaW5GYWx0PWRiQXZlc1tjb21wbGV0ZS5jYXNlcyhkYkF2ZXMpLF0NCndyaXRlLmNzdihzaW5GYWx0LCBmaWxlID0gImF2ZXNTaW5GYWwuY3N2IikNCmBgYA0KDQpQdWVkZSBkZXNjYXJnYXJzZSB1bmEgY29waWEgZGUgZXN0YSB2ZXJzacOzbiBkZSBsYSBiYXNlIGRlIGRhdG9zIGluZ3Jlc2FuZG8gYWwgc2lndWllbnRlIFtlbmxhY2VdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS91Yz9pZD0xOVZtSXRCdXlVb2JBcXg5d0RDS3l4MHpzZ05nNjZPNk0pLg0KDQojIyBUZXJjZXJhIGZhc2UNCg0KUGFyYSBlc3RhIGZhc2UgZGUgcHJlcGFyYWNpw7NuIGRlIGxvcyBkYXRvcywgc2UgaW5pY2lhIGNvbiBsYSByZXZpc2nDs24gZGUgdW4gcmVzdW1lbiBkZSBsb3MgbWlzbW9zLg0KDQpgYGB7ciBSZXN1bWVuIDN9DQpzdW1tYXJ5KHNpbkZhbHQpDQpgYGANCg0KQ29tbyBzZSBoYSBwb2RpZG8gb2JzZXJ2YXIgaGFzdGEgZWwgbW9tZW50bywgZWwgdHJhdGFtaWVudG8gZGUgdmFyaWFibGVzIGN1YWxpdGF0aXZhcyBhIG1lbnVkbyByZXF1aWVyZSB1biBtYW5lam8gZXNwZWNpYWwgZGUgY2FkZW5hcyBkZSB0ZXh0by4gQSB0cmF2w6lzIGRlbCByZXN1bWVuIGFudGVyaW9yLCBzZSBpZGVudGlmaWNhcm9uIG90cmFzIHZhcmlhYmxlcyBjdWFsaXRhdGl2YXMgZW4gZXN0YSBiYXNlIGRlIGRhdG9zIHF1ZSwgZGViaWRvIGEgbGEgY2FudGlkYWQgZGUgY2F0ZWdvcsOtYXMgbyBhIGxvcyB2YWxvcmVzIHF1ZSBhbGd1bm9zIHJlZ2lzdHJvcyBwdWVkZW4gdG9tYXIsIHBvZHLDrWFuIGVzdGFyIGludHJvZHVjaWVuZG8gbcOhcyB2YXJpYWJpbGlkYWQgZW4gZWwgY29uanVudG8gZGUgZGF0b3MuIEVzdGFzIHZhcmlhYmxlcyBzb24gYHNleGAsIGBiZWhhdmlvcmAgeSBgb2NjdXJyZW5jZVJlbWFya3NgLiBBIGNvbnRpbnVhY2nDs24gc2UgcHJlc2VudGFuIGxvcyBoYWxsYXpnb3MgeSBsb3MgdHJhdGFtaWVudG9zIGNvcnJlc3BvbmRpZW50ZXMuDQoNCiMjIyBWYXJpYWJsZSBgc2V4YA0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhIHNleH0NCnNpbkZhbHQkc2V4PWRyb3BsZXZlbHMoc2luRmFsdCRzZXgpDQp0YWJTZXg9YXMuZGF0YS5mcmFtZSh0YWJsZShzaW5GYWx0JHNleCkpDQpjb2xuYW1lcyh0YWJTZXgpPWMoIlNleG8iLCJGcmVjdWVuY2lhIikNCnRhYlNleA0KYGBgDQoNCkVuIGVsIGNhc28gZGUgZXN0YSB2YXJpYWJsZSwgYXVucXVlIGhheSBwb2NhcyBjYXRlZ29yw61hcywgbGEgY2F0ZWdvcsOtYSAiSnV2ZW5pbCIgY3VlbnRhIGNvbiBzb2xvIHRyZXMgb2JzZXJ2YWNpb25lcy4gUGFyYSByZWR1Y2lyIGVsIG7Dum1lcm8gZGUgY2F0ZWdvcsOtYXMgZGUgbGEgdmFyaWFibGUgeSBkaXNtaW51aXIgc3UgdmFyaWFiaWxpZGFkLCBlbiBlc3RlIGVzdHVkaW8gc2UgaGEgZGVjaWRpZG8gY2xhc2lmaWNhciBlc3RhcyB0cmVzIG9ic2VydmFjaW9uZXMgY29tbyAiRGVzY29ub2NpZG8iLiBFc3RhIGVsZWNjacOzbiBzZSBiYXNhIGVuIHF1ZSBkZXRlcm1pbmFyIGVsIHNleG8gZGUgdW4gYXZlIGEgc2ltcGxlIHZpc3RhIGVzIGZhY3RpYmxlIHNvbG8gZW4gbGEgbWl0YWQgZGUgbGFzIGVzcGVjaWVzIHksIHVzdWFsbWVudGUsIGN1YW5kbyBlc3RhcyBlc3TDoW4gY29tcGxldGFtZW50ZSBkZXNhcnJvbGxhZGFzIChlcyBkZWNpciwgZW4gc3UgZXRhcGEgYWR1bHRhKSAoR3JpZmZpdGhzLCAyMDAwKS4gUG9yIGxvIHRhbnRvLCByZXN1bHRhIG3DoXMgZGlmw61jaWwgZGV0ZXJtaW5hciBlbCBzZXhvIGRlIHVuIGF2ZSBqb3ZlbiBtZWRpYW50ZSBtw6l0b2RvcyB2aXN1YWxlcywgY29tbyBkdXJhbnRlIHVuYSBhY3RpdmlkYWQgZGUgYXZpc3RhbWllbnRvIGRlIGF2ZXMuDQoNCmBgYHtyIFJlc3VsdGFkb3MgbW9kaWZpY2FjacOzbiB2YXJpYWJsZSBzZXh9DQpzaW5GYWx0JHNleFtzaW5GYWx0JHNleCA9PSAiSnV2ZW5pbCJdPSJEZXNjb25vY2lkbyINCnNpbkZhbHQkc2V4PWRyb3BsZXZlbHMoc2luRmFsdCRzZXgpDQpzdW1tYXJ5KHNpbkZhbHQkc2V4KQ0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgYmVoYXZpb3JgDQoNCmBgYHtyIFRhYmxhIGRlIGZyZWN1ZW5jaWEgYmVoYXZpb3J9DQpzaW5GYWx0JGJlaGF2aW9yPWRyb3BsZXZlbHMoc2luRmFsdCRiZWhhdmlvcikNCnRhYkNvbXA9YXMuZGF0YS5mcmFtZSh0YWJsZShzaW5GYWx0JGJlaGF2aW9yKSkNCmNvbG5hbWVzKHRhYkNvbXApPWMoIkNvbXBvcnRhbWllbnRvIiwiRnJlY3VlbmNpYSIpDQp0YWJDb21wDQpgYGANCg0KRW4gZWwgY2FzbyBkZSBlc3RhIHZhcmlhYmxlLCBzZSBvYnNlcnZhIHF1ZSBoYXkgY2FkZW5hcyBkZSB0ZXh0byBxdWUgZGVzY3JpYmVuIG3DoXMgZGUgdW5hIGFjY2nDs24gcmVhbGl6YWRhIHBvciBlbCBvcmdhbmlzbW8gYXZpc3RhZG8sIGxvIHF1ZSBvY2FzaW9uYSBsYSBnZW5lcmFjacOzbiBkZSBtw6FzIGNhdGVnb3LDrWFzLiBQYXJhIGVzdGUgZXN0dWRpbywgc2Ugb3B0YXLDoSBwb3IgcmVnaXN0cmFyIGVuIGVzdGEgdmFyaWFibGUgw7puaWNhbWVudGUgbGEgcHJpbWVyYSBhY2Npw7NuIHF1ZSBhcGFyZXpjYSBlbiBsYSBjYWRlbmEgZGUgdGV4dG8gZXhpc3RlbnRlLg0KDQpTZSBldmlkZW5jaWEgcXVlIGxhIGNhZGVuYSBkZSB0ZXh0byBxdWUgc2VwYXJhIGxhIHByaW1lcmEgYWNjacOzbiBkZWwgcmVzdG8gZGVsIHRleHRvIGVzICIgXHwiLCBwb3IgbG8gcXVlIHNlIHV0aWxpemFyw6FuIG3DqXRvZG9zIGRlIG1hbmlwdWxhY2nDs24gZGUgY2FkZW5hcyBkZSBjYXJhY3RlcmVzIHBhcmEgbW9kaWZpY2FyIGxhIHZhcmlhYmxlLg0KDQpgYGB7ciBNb2RpZmljYWNpw7NuIHZhcmlhYmxlIGJlaGF2aW9yfQ0Kc2luRmFsdCRiZWhhdmlvcj1hcy5jaGFyYWN0ZXIoc2luRmFsdCRiZWhhdmlvcikNCnNpbkZhbHQkYmVoYXZpb3I9c3ViKCIgXFx8LioiLCAiIiwgc2luRmFsdCRiZWhhdmlvcikNCnNpbkZhbHQkYmVoYXZpb3I9YXMuZmFjdG9yKHNpbkZhbHQkYmVoYXZpb3IpDQpzdW1tYXJ5KHNpbkZhbHQkYmVoYXZpb3IpDQpgYGANCg0KQ29uIGVzdG8gbGEgdmFyaWFibGUgcXVlZGEgcmVkdWNpZGEgYSA1IGNhdGVnb3LDrWFzLCBsbyBxdWUgZmFjaWxpdGFyw6EgdW4gcG9jbyBtw6FzIGxvcyBwcm9jZXNvcyBkZSBhbsOhbGlzaXMuDQoNCiMjIyBWYXJpYWJsZSBgb2NjdXJyZW5jZVJlbWFya3NgDQoNCmBgYHtyIFRhYmxhIGRlIGZyZWN1ZW5jaWFzIG9jY3VycmVuY2VSZW1hcmtzfQ0Kc2luRmFsdCRvY2N1cnJlbmNlUmVtYXJrcz1kcm9wbGV2ZWxzKHNpbkZhbHQkb2NjdXJyZW5jZVJlbWFya3MpDQp0YWJBbm90PWFzLmRhdGEuZnJhbWUodGFibGUoc2luRmFsdCRvY2N1cnJlbmNlUmVtYXJrcykpDQpjb2xuYW1lcyh0YWJBbm90KT1jKCJBbm90YWNpw7NuIiwiRnJlY3VlbmNpYSIpDQp0YWJBbm90DQpgYGANCg0KRXN0YSB2YXJpYWJsZSBkZWJlIHJlcG9ydGFyIGluZm9ybWFjacOzbiBzb2JyZSBlbCBtb25pdG9yZW8gZW4gZWwgcXVlIHNlIHJlYWxpesOzIGVsIGF2aXN0YW1pZW50bywgZWwgbW9tZW50byBkZWwgZMOtYSBlbiBxdWUgc2UgbGxldsOzIGEgY2FibywgbyBzaSBzZSBhdmlzdMOzIGVuIHVuIGx1Z2FyIHBhcnRpY3VsYXIsIGNvbW8gdW4gY2FibGUgbyB1biDDoXJib2wgbXVlcnRvLiBFc3RvIHJlc3VsdGEgZW4gdW4gYWx0byBuw7ptZXJvIGRlIGNhdGVnb3LDrWFzLCBjb24gdW4gdG90YWwgZGUgMjYuDQoNClBhcmEgbG9zIGZpbmVzIGRlIGVzdGUgZXN0dWRpbywgc2UgcmVnaXN0cmFyw6Egw7puaWNhbWVudGUgbGEgaW5mb3JtYWNpw7NuIHNvYnJlIGVsIG1vbWVudG8gZGVsIGTDrWEgZW4gcXVlIHNlIHJlYWxpesOzIGVsIGF2aXN0YW1pZW50byAobWHDsWFuYSBvIHRhcmRlKSwgY29uIGxhIGludGVuY2nDs24gZGUgaWRlbnRpZmljYXIgcGF0cm9uZXMgcmVsYWNpb25hZG9zIGNvbiBsb3MgYXNwZWN0b3MgZXRvbMOzZ2ljb3MgZGUgbGFzIGF2ZXMuDQoNCmBgYHtyIE1vZGlmaWNhY2nDs24gdmFyaWFibGUgb2NjdXJyZW5jZVJlbWFya3N9DQpzaW5GYWx0JG9jY3VycmVuY2VSZW1hcmtzPXRyaW13cyhzdWIoIi4qLCIsICIiLCBzaW5GYWx0JG9jY3VycmVuY2VSZW1hcmtzKSkNCnNpbkZhbHQkb2NjdXJyZW5jZVJlbWFya3M9YXMuZmFjdG9yKHNpbkZhbHQkb2NjdXJyZW5jZVJlbWFya3MpDQpzdW1tYXJ5KHNpbkZhbHQkb2NjdXJyZW5jZVJlbWFya3MpDQpgYGANCg0KYGBge3IgQ29waWEgZGUgbGEgZGIxLCBpbmNsdWRlPUZBTFNFfQ0Kd3JpdGUuY3N2KHNpbkZhbHQsIGZpbGUgPSAiYXZlc0ZpbmFsLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpDQpgYGANCg0KQ29uIGVzdG8sIGxhIGZhc2UgZGUgcHJlcGFyYWNpw7NuIHNlIGRhIHBvciB0ZXJtaW5hZGEuIFNlIHB1ZWRlIGRlc2NhcmdhciB1bmEgY29waWEgZGUgZXN0YSB2ZXJzacOzbiBkZSBsYSBiYXNlIGRlIGRhdG9zIGVuIGVsIHNpZ3VpZW50ZSBbZW5sYWNlXShodHRwczovL2RyaXZlLmdvb2dsZS5jb20vdWM/aWQ9MVdyRzNCNlpxWkxscElDWmhjRGRjX0pobXVZc0JFTWlWKS4NCg0KIyBBbsOhbGlzaXMgcG9yIGNhdGVnb3LDrWFzDQoNCkx1ZWdvIGRlIGxhIHByZXBhcmFjacOzbiBkZSBsYXMgdmFyaWFibGVzLCBzZSBpbmljaWEgZWwgYW7DoWxpc2lzIGRlbCBmZW7Ds21lbm8gZGUgYmlvZGl2ZXJzaWRhZCBkb2N1bWVudGFkbyBlbiBsYSBiYXNlIGRlIGRhdG9zLiBQYXJhIGVzdG8sIHNlIHBsYW50ZWFuIHRyZXMgY2F0ZWdvcsOtYXMgZGUgYW7DoWxpc2lzOg0KDQoxLiAgQXNwZWN0b3MgcmVsYWNpb25hZG9zIGNvbiBsYSB1YmljYWNpw7NuIGdlb2dyw6FmaWNhLg0KMi4gIEFzcGVjdG9zIHRheG9uw7NtaWNvcyBkZSBsb3Mgb3JnYW5pc21vcy4NCjMuICBBc3BlY3RvcyBldG9sw7NnaWNvcyBkZSBsb3Mgb3JnYW5pc21vcy4NCg0KRGVudHJvIGRlIGNhZGEgdW5hIGRlIGVzdGFzIGNhdGVnb3LDrWFzIGRlIGFuw6FsaXNpcywgc2UgaW5jbHV5ZW4gdmFyaWFibGVzIHF1ZSBzZSBhbmFsaXphcsOhbiwgeWEgc2VhIHBvciBzZXBhcmFkbyBvIGVuIHJlbGFjacOzbiBjb24gb3RyYXMsIHBhcmEgaWRlbnRpZmljYXIgcGF0cm9uZXMgeSBjYXJhY3RlcsOtc3RpY2FzIGdlbmVyYWxlcyBkZWwgZmVuw7NtZW5vLiBVbmEgdmV6IGlkZW50aWZpY2FkYXMgYWxndW5hcyBkZSBlc3RhcyBjYXJhY3RlcsOtc3RpY2FzLCBzZSBwcm9jZWRlcsOhIGEgcmVhbGl6YXIgYXNvY2lhY2lvbmVzIGVudHJlIGxhcyBjYXRlZ29yw61hcy4NCg0KSW5pY2lhbG1lbnRlIGVzIGltcG9ydGFudGUgcmVjb25vY2VyIGVsIGNvbXBvcnRhbWllbnRvIGluZGl2aWR1YWwgZGUgZXN0YXMgdmFyaWFibGVzLiBBIGNvbnRpbnVhY2nDs24gc2UgYW5hbGl6YSBkZSBtYW5lcmEgc3VjaW50YSBlc3RvLCBwb3IgbWVkaW8gZGUgcmVwcmVzZW50YWNpb25lcyBncsOhZmljYXMsIHRhYmxhcyBkZSBmcmVjdWVuY2lhIHkgbWVkaWRhcyBlc3RhZMOtc3RpY2FzIChwYXJhIGVsIGNhc28gZGUgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzKS4NCg0KIyMgQXNwZWN0b3MgcmVsYWNpb25hZG9zIGNvbiBsYSB1YmljYWNpw7NuIGdlb2dyw6FmaWNhLg0KDQpFbiBlc3RhIGNhdGVnb3LDrWEgc2UgaW5jbHV5ZW4gbGFzIHZhcmlhYmxlcyBgZGVjaW1hbExvbmdpdHVkZWAsIGBkZWNpbWFsTGF0aXR1ZGVgLCBgcGFyZW50RXZlbnRJRGAgeSBgdmVyYmF0aW1Mb2NhbGl0eWAuDQoNCiMjIyBWYXJpYWJsZXMgYGRlY2ltYWxMb25naXR1ZGVgIHkgYGRlY2ltYWxMYXRpdHVkZWANCg0KKipWYXJpYWJsZSBgZGVjaW1hbExvbmdpdHVkZWAqKg0KDQpgYGB7ciBHcsOhZmljYSBsb25naXR1ZH0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChzaW5GYWx0LCBhZXMoeCA9IGRlY2ltYWxMb25naXR1ZGUpKSArDQogIGdlb21fZGVuc2l0eShmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArDQogIGxhYnModGl0bGUgPSAiTG9uZ2l0dWQgZGUgdWJpY2FjacOzbiBkZSBsYXMgYXZlcyIsDQogICAgICAgeCA9ICJMb25naXR1ZCIsDQogICAgICAgeSA9ICJEZW5zaWRhZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3IgTWVkaWRhcyBlc3RhZMOtc3RpY2FzIGRlIGxvbmdpdHVkfQ0Kc3VtbWFyeShzaW5GYWx0JGRlY2ltYWxMb25naXR1ZGUpDQpgYGANCg0KKipWYXJpYWJsZSBgZGVjaW1hbExhdGl0dWRlYCoqDQoNCmBgYHtyIFJlcHJlc2VudGFjacOzbiBncsOhZmljYSBsYXRpdHVkfQ0KZ2dwbG90KHNpbkZhbHQsIGFlcyh4ID0gZGVjaW1hbExhdGl0dWRlKSkgKw0KICBnZW9tX2RlbnNpdHkoZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKw0KICBsYWJzKHRpdGxlID0gIkxhdGl0dWQgZGUgdWJpY2FjacOzbiBkZSBsYXMgYXZlcyIsDQogICAgICAgeCA9ICJMYXRpdHVkIiwNCiAgICAgICB5ID0gIkRlbnNpZGFkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7ciBNZWRpZGFzIGVzdGFkw61zdGljYXMgZGUgbGF0aXR1ZH0NCnN1bW1hcnkoc2luRmFsdCRkZWNpbWFsTGF0aXR1ZGUpDQpgYGANCg0KQW5hbGl6YW5kbyBlc3RhcyBkb3MgdmFyaWFibGVzIHBvciBzZXBhcmFkbyBubyBzZSBsb2dyYSBpZGVudGlmaWNhciBjb21wb3J0YW1pZW50b3Mgc2lnbmlmaWNhdGl2b3MgZW4gY3VhbnRvIGEgc3VzIGRpc3RyaWJ1Y2lvbmVzLiBQb3Igc2VyIGNvb3JkZW5hZGFzIGdlb2dyw6FmaWNhcywgdGVuZHLDoSBzZW50aWRvIGFuYWxpemFybGFzIGVuIGNvbmp1bnRvLg0KDQpgYGB7ciBHcsOhZmljYSBjb29yZGVuYWRhcyBkZSB1YmljYWNpw7NufQ0KZ2dwbG90KHNpbkZhbHQsIGFlcyh4ID0gZGVjaW1hbExvbmdpdHVkZSwgeSA9IGRlY2ltYWxMYXRpdHVkZSkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrYmx1ZSIsIGFscGhhID0gMC41LCBzaXplID0gMSkgKw0KICBnZW9tX2RlbnNpdHlfMmQoY29sb3IgPSAiZGFya2dyZWVuIiwgYWxwaGEgPSAwLjUpICsNCiAgbGFicyh0aXRsZSA9ICJNYXBhIGRlIHB1bnRvcyB5IGN1cnZhcyBkZSBuaXZlbCBkZSB1YmljYWNpw7NuIGRlIGF2ZXMgeSBldmVudG8gZGUgbXVlc3RyZW8iLA0KICAgICAgIHggPSAiTG9uZ2l0dWQiLA0KICAgICAgIHkgPSAiTGF0aXR1ZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KRGUgZXN0byBzZSBwdWVkZSB2ZXIgcXVlIGhheSBkb3Mgem9uYXMgY2xhcmFtZW50ZSBkaWZlcmVuY2lhZGFzIGVuIGxhcyBxdWUgc2UgcmVhbGl6YXJvbiBsYXMgYWN0aXZpZGFkZXMgZGUgb2JzZXJ2YWNpw7NuIGRlIGxvcyBvcmdhbmlzbW9zIGF2aXN0YWRvcywgeSBlc3RvIHRhbCB2ZXogZXN0ZSByZWxhY2lvbmFkbyBjb24gbGEgbG9jYWxpZGFkLiBFc3RhIHJlbGFjacOzbiBzZSBleHBsb3JhcsOhIG3DoXMgYWRlbGFudGUuDQoNCiMjIyBWYXJpYWJsZSBgcGFyZW50RXZlbnRJRGANCg0KYGBge3IgVGFibGEgZGUgZnJlY3VlbmNpYXMgRXZlbnRvIGRlIG11ZXN0cmVvfQ0KdGFiRXZlbnQ9YXMuZGF0YS5mcmFtZSh0YWJsZShzaW5GYWx0JHBhcmVudEV2ZW50SUQpKQ0KY29sbmFtZXModGFiRXZlbnQpPWMoIkV2ZW50byBkZSBtdWVzdHJlbyIsIkZyZWN1ZW5jaWEiKQ0KdGFiRXZlbnQNCmBgYA0KDQpgYGB7ciBHcsOhZmljYSBFdmVudG8gZGUgbXVlc3RyZW99DQpnZ3Bsb3QodGFiRXZlbnQsIGFlcyh4ID0gYEV2ZW50byBkZSBtdWVzdHJlb2AsIHkgPSBGcmVjdWVuY2lhKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIiwgd2lkdGggPSAwLjUpICsgIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlY3VlbmNpYSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHRpdGxlID0gIkV2ZW50byBkZSBtdWVzdHJlbyIsDQogICAgICAgeCA9ICJFdmVudG8iLA0KICAgICAgIHkgPSAiRnJlY3VlbmNpYSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQ0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgdmVyYmF0aW1Mb2NhbGl0eWANCg0KYGBge3IgVGFibGEgZGUgZnJlY3VlbmNpYXMgTG9jYWxpZGFkfQ0KdGFiTG9jPWFzLmRhdGEuZnJhbWUodGFibGUoc2luRmFsdCR2ZXJiYXRpbUxvY2FsaXR5KSkNCmNvbG5hbWVzKHRhYkxvYyk9YygiTG9jYWxpZGFkIiwiRnJlY3VlbmNpYSIpDQp0YWJMb2MNCmBgYA0KDQpgYGB7ciBSZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgTG9jYWxpZGFkfQ0KZ2dwbG90KHRhYkxvYywgYWVzKHggPSAiIiwgeSA9IEZyZWN1ZW5jaWEsIGZpbGwgPSBMb2NhbGlkYWQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic2t5Ymx1ZTMiLCAic2t5Ymx1ZTQiKSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKEZyZWN1ZW5jaWEgLyBzdW0oRnJlY3VlbmNpYSkgKiAxMDApLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIkF2aXN0YW1pZW50b3MgcG9yIExvY2FsaWRhZCIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksICAgICANCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCAgICANCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNCiMjIyBSZWxhY2nDs24gZW50cmUgdWJpY2FjacOzbiB5IGV2ZW50byBkZSBtdWVzdHJlbw0KDQpQYXJhIGxhIGV4cGxvcmFjacOzbiBkZSBlc3RhIHJlbGFjacOzbiBzZSByZWFsaXphIHVuIG1hcGEgZGUgY2Fsb3IgYmlkaW1lbnNpb25hbC4gRW4gZXN0ZSBtYXBhLCBzZSByZXByZXNlbnRhIGxhIGRlbnNpZGFkIGRlIGF2ZXMgYXZpc3RhZGFzIG1lZGlhbnRlIGN1cnZhcyBkZSBuaXZlbCwgeSBsYSB1YmljYWNpw7NuIGRlIGxvcyBldmVudG9zIGRlIG11ZXN0cmVvIHNlIG1vc3RyYXLDoSBtZWRpYW50ZSBwdW50b3MsIGluZGljYW5kbyBkw7NuZGUgc2UgaWRlbnRpZmljYXJvbiBsYXMgYXZlcyBlbiBkaWNoYXMgdWJpY2FjaW9uZXMuDQoNCmBgYHtyIEdyYWZpY2EgY29vcmRlbmFkYXMgdnMuIGV2ZW50byBkZSBtdWVzdHJlb30NCmdncGxvdChzaW5GYWx0LCBhZXMoeCA9IGRlY2ltYWxMb25naXR1ZGUsIHkgPSBkZWNpbWFsTGF0aXR1ZGUpKSArDQogIGdlb21fZGVuc2l0eV8yZChjb2xvciA9ICJyZWQiLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBhcmVudEV2ZW50SUQpLCBhbHBoYSA9IDAuOCkgKyANCiAgbGFicyh0aXRsZSA9ICJNYXBhIGRlIGNhbG9yIGRlIHViaWNhY2nDs24gZGUgYXZlcyB5IGV2ZW50byBkZSBtdWVzdHJlbyIsDQogICAgICAgeCA9ICJMb25naXR1ZCIsDQogICAgICAgeSA9ICJMYXRpdHVkIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gbGV2ZWxzKHNpbkZhbHQkcGFyZW50RXZlbnRJRCksIHZhbHVlcyA9IGMoImJsdWUiLCAiZ3JlZW4iLCAicHVycGxlIiwicmVkIikpDQpgYGANCg0KU2UgcHVlZGUgZXZpZGVuY2lhciBxdWUgZXhpc3RlbiBkb3Mgem9uYXMgZGUgbWF5b3IgY29uY2VudHJhY2nDs24gZGUgbG9zIGF2aXN0YW1pZW50b3MgZGUgbG9zIG9yZ2FuaXNtb3M6IGVsIGV2ZW50byBkZSBtdWVzdHJlbyBFMSBzZSBjb25jZW50cmEgZW4gdW5hIMO6bmljYSB6b25hIChzdXBlcmlvciBkZXJlY2hhKSB5IGxvcyBkZW3DoXMgZXZlbnRvcyBlbiBsYSBvdHJhIHpvbmEgZGUgY29uY2VudHJhY2nDs24gKHBhcnRlIGl6cXVpZXJkYSBkZWwgZ3LDoWZpY28pLg0KDQojIyMgUmVsYWNpw7NuIGVudHJlIGV2ZW50byBkZSBtdWVzdHJlbyB5IGxvY2FsaWRhZA0KDQpQYXJhIHBvZGVyIGlkZW50aWZpY2FyIGxhcyBwb3NpYmxlcyByZWxhY2lvbmVzIGVudHJlIGVzdGFzIGRvcyB2YXJpYWJsZXMgc2UgdXRpbGl6YSB1bmEgdGFibGEgZGUgY29udGluZ2VuY2lhLCBoZXJyYW1pZW50YSBxdWUgcGVybWl0ZSByZWxhY2lvbmFyIGRvcyB2YXJpYWJsZXMgY3VhbGl0YXRpdmFzIHkgZXZpZGVuY2lhciBsYSBkaXN0cmlidWNpw7NuIGNvbmp1bnRhIGRlIGxhcyB2YXJpYWJsZXMuDQoNCmBgYHtyIFRhYmxhIGRlIGNvbnRpbmdlbmNpYSBldmVudG8gZGUgbXVlc3RyZW8gdnMuIGxvY2FsaWRhZH0NCnRhYkV2ZW50SGFjPXRhYmxlKHNpbkZhbHQkcGFyZW50RXZlbnRJRCwgc2luRmFsdCR2ZXJiYXRpbUxvY2FsaXR5KQ0KdGFiRXZlbnRIYWMNCmBgYA0KDQpDb24gZXN0byBzZSBldmlkZW5jaWEgcXVlIGVsIGV2ZW50byBFMSB0dXZvIGNvbmNlbnRyYWNpw7NuIGVuIGxhIHpvbmEgZGUgbGEgSGFjaWVuZGEgTGEgQ29uZWplcmEsIG1pZW50cmFzIHF1ZSBlbCByZXN0byBkZSBldmVudG9zIHNlIGNvbmNlbnRyYXJvbiBlbiBsYSBIYWNpZW5kYSBMYXMgTWVyY2VkZXMuIFRhbWJpw6luIHNlIHB1ZWRlIHZlciBlc3RvIGVuIHVuIG1hcGEgZGUgY2Fsb3IsIHNpbWlsYXIgYSBsYSBncsOhZmljYSBhbnRlcmlvci4NCg0KYGBge3IgR3LDoWZpY2EgY29vcmRlbmFkYXMgdnMuIGxvY2FsaWRhZH0NCmdncGxvdChzaW5GYWx0LCBhZXMoeCA9IGRlY2ltYWxMb25naXR1ZGUsIHkgPSBkZWNpbWFsTGF0aXR1ZGUpKSArDQogIGdlb21fZGVuc2l0eV8yZChjb2xvciA9ICJyZWQiLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHZlcmJhdGltTG9jYWxpdHkpLCBhbHBoYSA9IDAuOCkgKyANCiAgbGFicyh0aXRsZSA9ICJNYXBhIGRlIGNhbG9yIGRlIHViaWNhY2nDs24gZGUgYXZlcyB5IGxvY2FsaWRhZCBkZSBhdmlzdGFtaWVudG8iLA0KICAgICAgIHggPSAiTG9uZ2l0dWQiLA0KICAgICAgIHkgPSAiTGF0aXR1ZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKGJyZWFrcyA9IGxldmVscyhzaW5GYWx0JHZlcmJhdGltTG9jYWxpdHkpLCB2YWx1ZXMgPSBjKCJibHVlIiwgImdyZWVuIikpDQpgYGANCg0KQ29uIGVzdG8sIHNlIHB1ZWRlIGNvbmNsdWlyIHF1ZSwgcGFyYSBmYWNpbGl0YXIgZWwgcHJvY2VzYW1pZW50byBkZSBkYXRvcywgc2UgcHVlZGUgc2VjY2lvbmFyIGVsIGVzdHVkaW8gcG9yIG1lZGlvIGRlIGxvcyBldmVudG9zIG8gZGUgbGEgbG9jYWxpZGFkLiBFc3RvIHBlcm1pdGlyw61hIGRlc2NhcnRhciBtw6FzIHZhcmlhYmxlcyBhbCBtb21lbnRvIGRlIGVuY29udHJhciBwYXRyb25lcyB5IGFuYWxpemFyIHJlbGFjaW9uZXMgZW50cmUgdmFyaWFibGVzIGRlIG1hbmVyYSBtw6FzIHNlbmNpbGxhLiBTZSBwdWVkZSBvcHRhciBlbnRvbmNlcyBwb3I6DQoNCi0gICBBbmFsaXphciBlbCBjb25qdW50byBkZSBkYXRvcyBwZXJ0ZW5lY2llbnRlIGEgbGEgSGFjaWVuZGEgTGEgQ29uZWplcmEsIGxvIHF1ZSBpbXBsaWNhIGRlc2NhcnRhciBsYXMgdmFyaWFibGVzIGB2ZXJiYXRpbUxvY2FsaXR5YCB5IGBwYXJlbnRFdmVudElEYCwgc2FiaWVuZG8gcXVlIHRvZG9zIGVzdG9zIGRhdG9zIHBlcnRlbmVjZW4gYWwgZXZlbnRvIGRlIG11ZXN0cmVvIEUxLg0KLSAgIEFuYWxpemFyIGNhZGEgdW5vIGRlIGxvcyBldmVudG9zIHJlc3RhbnRlcyBwb3Igc2VwYXJhZG8sIGxvIHF1ZSBwZXJtaXRlIGRlc2NhcnRhciBsYXMgdmFyaWFibGVzIGBwYXJlbnRFdmVudElEYCB5IGB2ZXJiYXRpbUxvY2FsaXR5YCwgdGVuaWVuZG8gZW4gY3VlbnRhIHF1ZSBlc3RhIMO6bHRpbWEgdmFyaWFibGUgdG9tYXLDrWEgZWwgdmFsb3IgZGUgIkhhY2llbmRhIExhcyBNZXJjZWRlcyIgZW4gdG9kb3MgbG9zIHJlZ2lzdHJvcyBkZSBlc3RvcyBjb25qdW50by4NCg0KUGFyYSBmaW5lcyBkZSBlc3RlIHRyYWJham8gc2UgcmVhbGl6YXLDoSBlbCBlc3R1ZGlvIGRldGFsbGFkbyBkZSBjYXNvIGRlIGxhIEhhY2llbmRhIExhIENvbmVqZXJhLg0KDQojIyBBc3BlY3RvcyByZWxhY2lvbmFkb3MgY29uIGxhIHRheG9ub23DrWEgZGUgbG9zIG9yZ2FuaXNtb3MNCg0KRW4gZXN0YSBjYXRlZ29yw61hIGRlIGFuw6FsaXNpcyBzZSB0ZW5kcsOhbiBlbiBjdWVudGEgbGFzIHZhcmlhYmxlcyBgb3JkZW5gLCBgZ2VudXNgLCBgZmFtaWx5YCB5IGBzY2llbnRpZmljTmFtZWAuIEVzdGFzIHZhcmlhYmxlcyBwZXJtaXRlbiByZWNvbm9jZXIgbGEgZGl2ZXJzaWRhZCBkZSBhdmVzIG9ic2VydmFkYXMgZW4gZWwgZXN0dWRpby4gU2UgcmVhbGl6YXLDoSB1bmEgZXhwbG9yYWNpw7NuIGRlIGxvIG9ic2VydmFkbyBlbiB0b2RhIGxhIFJlc2VydmEgeSBsbyBvYnNlcnZhZG8gZW4gbGEgSGFjaWVuZGEgTGEgQ29uZWplcmEuIEVzdG8gcHVlZGUgcmVwbGljYXJzZSBjb24gY2FkYSB1bm8gZGUgbG9zIGV2ZW50b3MgZGUgbXVlc3RyZW8sIHPDrSBlcyBkZSBpbnRlcsOpcyBkZWwgbGVjdG9yLg0KDQojIyMgVmFyaWFibGUgYG9yZGVyYCBhIG5pdmVsIGRlIGxhIFJlc2VydmENCg0KYGBge3IgVGFibGEgZGUgZnJlY3VlbmNpYXMgdmFyaWFibGUgb3JkZW4tUmVzZXJ2YX0NCnNpbkZhbHQkb3JkZXI9ZHJvcGxldmVscyhzaW5GYWx0JG9yZGVyKQ0KdGFiT3JkPWFzLmRhdGEuZnJhbWUodGFibGUoc2luRmFsdCRvcmRlcikpDQpjb2xuYW1lcyh0YWJPcmQpPWMoIk9yZGVuIiwiRnJlY3VlbmNpYSIpDQp0YWJPcmQgPSB0YWJPcmQgJT4lDQogIGFycmFuZ2UoZGVzYyhGcmVjdWVuY2lhKSkNCnRhYk9yZA0KYGBgDQoNCmBgYHtyIEdyw6FmaWNhIHZhcmlhYmxlIG9yZGVuLVJlc2VydmF9DQp0YWJPcmQkT3JkZW49ZmFjdG9yKHRhYk9yZCRPcmRlbiwgbGV2ZWxzID0gdGFiT3JkJE9yZGVuW29yZGVyKHRhYk9yZCRGcmVjdWVuY2lhLCBkZWNyZWFzaW5nID0gRkFMU0UpXSkNCmdncGxvdCh0YWJPcmQsIGFlcyh4ID0gRnJlY3VlbmNpYSwgeSA9IGBPcmRlbmApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVjdWVuY2lhKSwgaGp1c3QgPSAtMC4yLCBzaXplID0gMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiT3JkZW5lcyBkZSBhdmVzIGlkZW50aWZpY2FkYXMgZW4gbGEgUmVzZXJ2YSIsDQogICAgICAgeCA9ICJGcmVjdWVuY2lhIiwNCiAgICAgICB5ID0gIk9yZGVuZXMiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkNCmBgYA0KDQojIyMgVmFyaWFibGUgYG9yZGVyYCBhIG5pdmVsIGRlIGxhIEhhY2llbmRhIExhIENvbmVqZXJhDQoNCmBgYHtyIFBhcnRpY2nDs24gZGUgbGEgYmFzZSBkZSBkYXRvc30NCkF2ZXNDb25lamVyYT1zaW5GYWx0W3NpbkZhbHQkdmVyYmF0aW1Mb2NhbGl0eSA9PSAiSGFjaWVuZGEgbGEgQ29uZWplcmEiLCBdDQpgYGANCg0KYGBge3IgVGFibGEgZGUgZnJlY3VlbmNpYXMgdmFyaWFibGUgb3JkZW4tSGFjaWVuZGF9DQpBdmVzQ29uZWplcmEkb3JkZXI9ZHJvcGxldmVscyhBdmVzQ29uZWplcmEkb3JkZXIpDQp0YWJPcmRIPWFzLmRhdGEuZnJhbWUodGFibGUoQXZlc0NvbmVqZXJhJG9yZGVyKSkNCmNvbG5hbWVzKHRhYk9yZEgpPWMoIk9yZGVuIiwiRnJlY3VlbmNpYSIpDQp0YWJPcmRIID0gdGFiT3JkSCAlPiUNCiAgYXJyYW5nZShkZXNjKEZyZWN1ZW5jaWEpKQ0KdGFiT3JkSA0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgZmFtaWx5YCBhIG5pdmVsIGRlIGxhIFJlc2VydmENCg0KYGBge3IgVGFibGEgZGUgZnJlY3VlbmNpYXMgdmFyaWFibGUgZmFtaWxpYX0NCnNpbkZhbHQkZmFtaWx5PWRyb3BsZXZlbHMoc2luRmFsdCRmYW1pbHkpDQp0YWJGYW09YXMuZGF0YS5mcmFtZSh0YWJsZShzaW5GYWx0JGZhbWlseSkpDQpjb2xuYW1lcyh0YWJGYW0pPWMoIkZhbWlsaWEiLCJGcmVjdWVuY2lhIikNCnRhYkZhbSA9IHRhYkZhbSAlPiUNCiAgYXJyYW5nZShkZXNjKEZyZWN1ZW5jaWEpKQ0KdGFiRmFtDQpgYGANCg0KYGBge3IgR3LDoWZpY2EgdmFyaWFibGUgZmFtaWxpYX0NCnRhYkZhbSRGYW1pbGlhPWZhY3Rvcih0YWJGYW0kRmFtaWxpYSwgbGV2ZWxzID0gdGFiRmFtJEZhbWlsaWFbb3JkZXIodGFiRmFtJEZyZWN1ZW5jaWEsIGRlY3JlYXNpbmcgPSBGQUxTRSldKQ0KZ2dwbG90KHRhYkZhbSwgYWVzKHggPSBGcmVjdWVuY2lhLCB5ID0gYEZhbWlsaWFgKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlY3VlbmNpYSksIGhqdXN0ID0gLTAuMiwgc2l6ZSA9IDIsIGNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHRpdGxlID0gIkZhbWlsaWFzIGRlIGF2ZXMgaWRlbnRpZmljYWRhcyBlbiBsYSBSZXNlcnZhIiwNCiAgICAgICB4ID0gIkZyZWN1ZW5jaWEiLA0KICAgICAgIHkgPSAiRmFtaWxpYXMiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkNCmBgYA0KDQojIyMgVmFyaWFibGUgYGZhbWlseWAgYSBuaXZlbCBkZSBsYSBIYWNpZW5kYSBMYSBDb25lamVyYQ0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyB2YXJpYWJsZSBmYW1pbGlhLUhhY2llbmRhfQ0KQXZlc0NvbmVqZXJhJGZhbWlseT1kcm9wbGV2ZWxzKEF2ZXNDb25lamVyYSRmYW1pbHkpDQp0YWJGYW1IPWFzLmRhdGEuZnJhbWUodGFibGUoQXZlc0NvbmVqZXJhJGZhbWlseSkpDQpjb2xuYW1lcyh0YWJGYW1IKT1jKCJGYW1pbGlhIiwiRnJlY3VlbmNpYSIpDQp0YWJGYW1IID0gdGFiRmFtSCAlPiUNCiAgYXJyYW5nZShkZXNjKEZyZWN1ZW5jaWEpKQ0KdGFiRmFtSA0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgZ2VudXNgIGEgbml2ZWwgZGUgbGEgUmVzZXJ2YQ0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyB2YXJpYWJsZSBnw6luZXJvfQ0Kc2luRmFsdCRnZW51cz1kcm9wbGV2ZWxzKHNpbkZhbHQkZ2VudXMpDQp0YWJHZW49YXMuZGF0YS5mcmFtZSh0YWJsZShzaW5GYWx0JGdlbnVzKSkNCmNvbG5hbWVzKHRhYkdlbik9YygiR8OpbmVybyIsIkZyZWN1ZW5jaWEiKQ0KdGFiR2VuID0gdGFiR2VuICU+JQ0KICBhcnJhbmdlKGRlc2MoRnJlY3VlbmNpYSkpDQp0YWJHZW4NCmBgYA0KDQpgYGB7ciBHcsOhZmljYSB2YXJpYWJsZSBnw6luZXJvfQ0KdGFiR2VuJEfDqW5lcm89ZmFjdG9yKHRhYkdlbiRHw6luZXJvLCBsZXZlbHMgPSB0YWJHZW4kR8OpbmVyb1tvcmRlcih0YWJHZW4kRnJlY3VlbmNpYSwgZGVjcmVhc2luZyA9IEZBTFNFKV0pDQpnZ3Bsb3QodGFiR2VuLCBhZXMoeCA9IEZyZWN1ZW5jaWEsIHkgPSBgR8OpbmVyb2ApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVjdWVuY2lhKSwgaGp1c3QgPSAtMC4yLCBzaXplID0gMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiR8OpbmVybyBkZSBhdmVzIGlkZW50aWZpY2FkYXMgZW4gbGEgUmVzZXJ2YSIsDQogICAgICAgeCA9ICJGcmVjdWVuY2lhIiwNCiAgICAgICB5ID0gIkfDqW5lcm9zIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpDQpgYGANCg0KIyMjIFZhcmlhYmxlIGBnZW51c2AgYSBuaXZlbCBkZSBsYSBIYWNpZW5kYSBMYSBDb25lamVyYQ0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyB2YXJpYWJsZSBnw6luZXJvLUhhY2llbmRhfQ0KQXZlc0NvbmVqZXJhJGdlbnVzPWRyb3BsZXZlbHMoQXZlc0NvbmVqZXJhJGdlbnVzKQ0KdGFiR2VuSD1hcy5kYXRhLmZyYW1lKHRhYmxlKEF2ZXNDb25lamVyYSRnZW51cykpDQpjb2xuYW1lcyh0YWJHZW5IKT1jKCJHw6luZXJvIiwiRnJlY3VlbmNpYSIpDQp0YWJHZW5IID0gdGFiR2VuSCAlPiUNCiAgYXJyYW5nZShkZXNjKEZyZWN1ZW5jaWEpKQ0KdGFiR2VuSA0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgc2NpZW50aWZpY05hbWVgIGEgbml2ZWwgZGUgbGEgcmVzZXJ2YQ0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyB2YXJpYWJsZSBub21icmUgY2llbnTDrWZpY299DQpzaW5GYWx0JHNjaWVudGlmaWNOYW1lPWRyb3BsZXZlbHMoc2luRmFsdCRzY2llbnRpZmljTmFtZSkNCnRhYkF2PWFzLmRhdGEuZnJhbWUodGFibGUoc2luRmFsdCRzY2llbnRpZmljTmFtZSkpDQpjb2xuYW1lcyh0YWJBdik9YygiRXNwZWNpZSIsIkZyZWN1ZW5jaWEiKQ0KdGFiQXYgPSB0YWJBdiAlPiUNCiAgYXJyYW5nZShkZXNjKEZyZWN1ZW5jaWEpKQ0KdGFiQXYNCmBgYA0KDQpgYGB7ciBHcsOhZmljYSB2YXJpYWJsZSBub21icmUgY2llbnTDrWZpY28sIGluY2x1ZGU9RkFMU0V9DQp0YWJBdiRFc3BlY2llPWZhY3Rvcih0YWJBdiRFc3BlY2llLCBsZXZlbHMgPSB0YWJBdiRFc3BlY2llW29yZGVyKHRhYkF2JEZyZWN1ZW5jaWEsIGRlY3JlYXNpbmcgPSBGQUxTRSldKQ0KZ2dwbG90KHRhYkF2LCBhZXMoeCA9IEZyZWN1ZW5jaWEsIHkgPSBgRXNwZWNpZWApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVjdWVuY2lhKSwgaGp1c3QgPSAtMC4yLCBzaXplID0gMiwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiQXZlcyBpZGVudGlmaWNhZGFzIGVuIGxhIFJlc2VydmEiLA0KICAgICAgIHggPSAiRnJlY3VlbmNpYSIsDQogICAgICAgeSA9ICJBdmUiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkNCmBgYA0KDQohW10oYXZlc0dyYXBoKQ0KDQojIyMgVmFyaWFibGUgYHNjaWVudGlmaWNOYW1lYCBhIG5pdmVsIGRlIGxhIEhhY2llbmRhIExhIENvbmVqZXJhDQoNCmBgYHtyIFRhYmxhIGRlIGZyZWN1ZW5jaWFzIHZhcmlhYmxlIG5vbWJyZSBjaWVudMOtZmljby1IYWNpZW5kYX0NCkF2ZXNDb25lamVyYSRzY2llbnRpZmljTmFtZT1kcm9wbGV2ZWxzKEF2ZXNDb25lamVyYSRzY2llbnRpZmljTmFtZSkNCnRhYkF2SD1hcy5kYXRhLmZyYW1lKHRhYmxlKEF2ZXNDb25lamVyYSRzY2llbnRpZmljTmFtZSkpDQpjb2xuYW1lcyh0YWJBdkgpPWMoIkVzcGVjaWUiLCJGcmVjdWVuY2lhIikNCnRhYkF2SCA9IHRhYkF2SCAlPiUNCiAgYXJyYW5nZShkZXNjKEZyZWN1ZW5jaWEpKQ0KdGFiQXZIDQpgYGANCg0KIyMjIFJlbGFjaW9uZXMgZW50cmUgdmFyaWFibGVzIHRheG9uw7NtaWNhcw0KDQpFcyBpbXBvcnRhbnRlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZXN0YXMgdmFyaWFibGVzIHNpZ3VlbiB1bmEgamVyYXJxdcOtYSwgbG8gcXVlIGdhcmFudGl6YSB1bmEgZnVlcnRlIHJlbGFjacOzbiBlbnRyZSBlbGxhcy4gUG9yIHRhbnRvLCBwYXJhIGxhIHJldmlzacOzbiBkZSBlc3RhcyB2YXJpYWJsZXMgc2UgdXRpbGl6YXLDoW4gZGlhZ3JhbWFzIGRlIMOhcmJvbCwgZW1wbGVhbmRvIGxhIGxpYnJlcsOtYSBgdHJlZW1hcGAgZGUgUi4uDQoNCmBgYHtyIEdyw6FmaWNhIG9yZGVuIHZzLiBmYW1pbGlhIGEgbml2ZWwgZGUgbGEgUmVzZXJ2YX0NCmxpYnJhcnkodHJlZW1hcCkNCmF2ZXNfY291bnQ9c2luRmFsdCAlPiUNCiAgIGRwbHlyOjpjb3VudChvcmRlciwgZmFtaWx5LCBuYW1lID0gIkNvdW50IikNCnRyZWVtYXAoYXZlc19jb3VudCwNCiAgICAgICBpbmRleCA9IGMoIm9yZGVyIiwgImZhbWlseSIpLA0KICAgICAgIHZTaXplID0gIkNvdW50IiwNCiAgICAgICB2Q29sb3IgPSAiQ291bnQiLA0KICAgICAgIHR5cGUgPSAidmFsdWUiLA0KICAgICAgIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgQXZlcyBwb3IgT3JkZW4geSBGYW1pbGlhIGVuIGxhIFJlc2VydmEiLA0KICAgICAgIHBhbGV0dGUgPSAiQmx1ZXMiLCAgDQogICAgICAgYm9yZGVyLmNvbCA9ICJibGFjayIsICANCiAgICAgICBmb250c2l6ZS5sYWJlbHMgPSBjKDE1LCAxMiksIA0KICAgICAgIGFsaWduLmxhYmVscyA9IGxpc3QoYygiY2VudGVyIiwgImNlbnRlciIpLGMoImxlZnQiLCJ0b3AiKSksDQogICAgICAgaW5mbGF0ZS5sYWJlbHMgPSBGQUxTRSkgIA0KYGBgDQoNClBvciBtZWRpbyBkZSBlc3RhIGdyw6FmaWNhLCB5IHBhcmEgZWwgY2FzbyBkZSBlc3R1ZGlvLCBzZSB0aWVuZSBxdWUgbG9zIG9yZGVuZXMgeSBmYW1pbGlhcyBkZSBhdmVzIG3DoXMgc2UgYXZpc3Rhcm9uIHNvbjoNCg0KKzotLS0tLS0tLS0tLS0tLTorOi0tLS0tLS0tLS0tLS06Kw0KfCAqKk9yZGVuKiogICAgICB8ICoqRmFtaWxpYSoqICAgfA0KKy0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tKw0KfCBQYXNzZXJpZm9ybWVzICB8IEVtYmVyaXppZGFlICAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IFR1cmRpZGFlICAgICAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IFRocmF1cGlkYWUgICAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IEljdGlyaWRhZSAgICAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IFR5cmFubmlkYWUgICAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IEZyaW5naWxsaWRhZSAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IFRyb2dsb2R5cmlkYWUgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IEhpcnVuZGluaWRhZSAgfA0KfCAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICB8IFBhcnVsaWRhZSAgICAgfA0KKy0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tKw0KfCBDb2x1bWJpZm9ybWVzICB8IENvbHVtYmlkYWUgICAgfA0KKy0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tKw0KfCBBcG9kaWZvcm1lcyAgICB8IFRyb2NoaWxpZGFlICAgfA0KKy0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tKw0KfCBQc2l0dGFjaWZvcm1lcyB8IFBzaXR0YWNpZGFlICAgfA0KKy0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tKw0KDQpgYGB7ciBHcsOhZmljYSBvcmRlbiB2cy4gZmFtaWxpYSBhIG5pdmVsIGRlIGxhIEhhY2llbmRhIExhIENvbmVqZXJhfQ0KYXZlc19jb3VudDM9QXZlc0NvbmVqZXJhICU+JQ0KICAgZHBseXI6OmNvdW50KG9yZGVyLCBmYW1pbHksIG5hbWUgPSAiQ291bnQiKQ0KdHJlZW1hcChhdmVzX2NvdW50MywNCiAgICAgICBpbmRleCA9IGMoIm9yZGVyIiwgImZhbWlseSIpLA0KICAgICAgIHZTaXplID0gIkNvdW50IiwNCiAgICAgICB2Q29sb3IgPSAiQ291bnQiLA0KICAgICAgIHR5cGUgPSAidmFsdWUiLA0KICAgICAgIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgQXZlcyBwb3IgT3JkZW4geSBGYW1pbGlhIGVuIGxhIEhhY2llbmRhIExhIENvbmVqZXJhIiwNCiAgICAgICBwYWxldHRlID0gIkJsdWVzIiwgIA0KICAgICAgIGJvcmRlci5jb2wgPSAiYmxhY2siLCAgDQogICAgICAgZm9udHNpemUubGFiZWxzID0gYygxNSwgMTIpLCANCiAgICAgICBhbGlnbi5sYWJlbHMgPSBsaXN0KGMoImNlbnRlciIsICJjZW50ZXIiKSxjKCJsZWZ0IiwidG9wIikpLA0KICAgICAgIGluZmxhdGUubGFiZWxzID0gRkFMU0UpICANCmBgYA0KDQpBdW5xdWUgZW4gZXN0ZSB0aXBvIGRlIGdyw6FmaWNhIHNlIHB1ZWRlIGluY2x1aXIgdW5hIHRlcmNlcmEgdmFyaWFibGUsIHF1ZSBlbiBsYSBqZXJhcnF1w61hIHNlcsOtYSBsYSB2YXJpYWJsZSBgZ2VudXNgLCBsYSByZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgcmVzdWx0YW50ZSBubyBlcyBtdXkgYW1pZ2FibGUgcGFyYSBzdSBsZWN0dXJhLiBQb3IgZWxsbywgZW4gZXN0ZSBjYXNvIHNlIG9wdGEgcG9yIGNvbWJpbmFyIGxhcyB2YXJpYWJsZXMgYG9yZGVyYCB5IGBnZW51c2AgcGFyYSB2aXN1YWxpemFyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbGFzIGF2ZXMgYXZpc3RhZGFzLg0KDQpgYGB7ciBHcsOhZmljYSBvcmRlbiB2cy4gR8OpbmVybyBhIG5pdmVsIGRlIGxhIFJlc2VydmF9DQphdmVzX2NvdW50Mj1zaW5GYWx0ICU+JQ0KICAgZHBseXI6OmNvdW50KG9yZGVyLCBnZW51cywgbmFtZSA9ICJDb3VudCIpDQp0cmVlbWFwKGF2ZXNfY291bnQyLA0KICAgICAgIGluZGV4ID0gYygib3JkZXIiLCAiZ2VudXMiKSwNCiAgICAgICB2U2l6ZSA9ICJDb3VudCIsDQogICAgICAgdkNvbG9yID0gIkNvdW50IiwNCiAgICAgICB0eXBlID0gInZhbHVlIiwNCiAgICAgICB0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIEF2ZXMgcG9yIE9yZGVuIHkgR8OpbmVybyBlbiBsYSBSZXNlcnZhIiwNCiAgICAgICBwYWxldHRlID0gIkJsdWVzIiwgIA0KICAgICAgIGJvcmRlci5jb2wgPSAiYmxhY2siLCAgDQogICAgICAgZm9udHNpemUubGFiZWxzID0gYygxNSwgMTIpLCANCiAgICAgICBhbGlnbi5sYWJlbHMgPSBsaXN0KGMoImNlbnRlciIsICJjZW50ZXIiKSxjKCJsZWZ0IiwidG9wIikpLA0KICAgICAgIGluZmxhdGUubGFiZWxzID0gRkFMU0UpICANCmBgYA0KDQpgYGB7ciBHcsOhZmljYSBvcmRlbiB2cy4gR8OpbmVybyBhIG5pdmVsIGRlIGxhIEhhY2llbmRhIExhIENvbmVqZXJhfQ0KYXZlc19jb3VudDQ9QXZlc0NvbmVqZXJhICU+JQ0KICAgZHBseXI6OmNvdW50KG9yZGVyLCBnZW51cywgbmFtZSA9ICJDb3VudCIpDQp0cmVlbWFwKGF2ZXNfY291bnQ0LA0KICAgICAgIGluZGV4ID0gYygib3JkZXIiLCAiZ2VudXMiKSwNCiAgICAgICB2U2l6ZSA9ICJDb3VudCIsDQogICAgICAgdkNvbG9yID0gIkNvdW50IiwNCiAgICAgICB0eXBlID0gInZhbHVlIiwNCiAgICAgICB0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIEF2ZXMgcG9yIE9yZGVuIHkgR8OpbmVybyBlbiBsYSBIYWNpZW5kYSBMYSBDb25lamVyYSIsDQogICAgICAgcGFsZXR0ZSA9ICJCbHVlcyIsICANCiAgICAgICBib3JkZXIuY29sID0gImJsYWNrIiwgIA0KICAgICAgIGZvbnRzaXplLmxhYmVscyA9IGMoMTUsIDEyKSwgDQogICAgICAgYWxpZ24ubGFiZWxzID0gbGlzdChjKCJjZW50ZXIiLCAiY2VudGVyIiksYygibGVmdCIsInRvcCIpKSwNCiAgICAgICBpbmZsYXRlLmxhYmVscyA9IEZBTFNFKSAgDQpgYGANCg0KIyMgQXNwZWN0b3MgZXRvbMOzZ2ljb3MNCg0KRXN0YSBjYXRlZ29yw61hIGRlIGFuw6FsaXNpcyBzZSBjb21wb25lIGRlIGxhcyB2YXJpYWJsZXMgYG9jY3VycmVuY2VSZW1hcmtzYCwgYGhhYml0YXRgLCBgZXN0cnVjdHVyYVNvY2lhbGAgeSBgYmVoYXZpb3JgLg0KDQojIyMgVmFyaWFibGUgYG9jY3VycmVuY2VSZW1hcmtzYA0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyB2YXJpYWJsZSBvY2N1cnJlbmNlUmVtYXJrcy1SZXNlcnZhfQ0KdGFiQW5vdD1hcy5kYXRhLmZyYW1lKHRhYmxlKHNpbkZhbHQkb2NjdXJyZW5jZVJlbWFya3MpKQ0KY29sbmFtZXModGFiQW5vdCk9YygiTW9tZW50byBkZWwgZMOtYSIsIkZyZWN1ZW5jaWEiKQ0KdGFiQW5vdA0KYGBgDQoNCmBgYHtyIFJlcHJlc2VudGFjacOzbiBncsOhZmljYSBvY2N1cnJlbmNlUmVtYXJrcy1SZXNlcnZhfQ0KZ2dwbG90KHRhYkFub3QsIGFlcyh4ID0gIiIsIHkgPSBGcmVjdWVuY2lhLCBmaWxsID0gYE1vbWVudG8gZGVsIGTDrWFgKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQgPSAwKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNreWJsdWUzIiwgInNreWJsdWU0IikpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChGcmVjdWVuY2lhIC8gc3VtKEZyZWN1ZW5jaWEpICogMTAwKSwgIiUiKSksIA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICJBdmlzdGFtaWVudG9zIHBvciBtb21lbnRvIGRlbCBkw61hLVJlc2VydmEiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCAgICAgDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwgICAgDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyB2YXJpYWJsZSBvY2N1cnJlbmNlUmVtYXJrcy1IYWNpZW5kYSBMYSBDb25lamVyYX0NCnRhYkFub3RIPWFzLmRhdGEuZnJhbWUodGFibGUoQXZlc0NvbmVqZXJhJG9jY3VycmVuY2VSZW1hcmtzKSkNCmNvbG5hbWVzKHRhYkFub3RIKT1jKCJNb21lbnRvIGRlbCBkw61hIiwiRnJlY3VlbmNpYSIpDQp0YWJBbm90SA0KYGBgDQoNCmBgYHtyIFJlcHJlc2VudGFjacOzbiBncsOhZmljYSBvY2N1cnJlbmNlUmVtYXJrcy1IYWNpZW5kYX0NCmdncGxvdCh0YWJBbm90SCwgYWVzKHggPSAiIiwgeSA9IEZyZWN1ZW5jaWEsIGZpbGwgPSBgTW9tZW50byBkZWwgZMOtYWApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic2t5Ymx1ZTMiLCAic2t5Ymx1ZTQiKSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKEZyZWN1ZW5jaWEgLyBzdW0oRnJlY3VlbmNpYSkgKiAxMDApLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBsYWJzKHRpdGxlID0gIkF2aXN0YW1pZW50b3MgcG9yIG1vbWVudG8gZGVsIGTDrWEtSGFjaWVuZGEgTGEgQ29uZWplcmEiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCAgICAgDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwgICAgDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQojIyMgVmFyaWFibGUgYGhhYml0YXRgDQoNCmBgYHtyIFRhYmxhIGRlIGZyZWN1ZW5jaWFzIHZhcmlhYmxlIGhhYml0YXQtUmVzZXJ2YX0NCnRhYkhhYj1hcy5kYXRhLmZyYW1lKHRhYmxlKHNpbkZhbHQkaGFiaXRhdCkpDQpjb2xuYW1lcyh0YWJIYWIpPWMoIkjDoWJpdGF0IiwiRnJlY3VlbmNpYSIpDQp0YWJIYWINCmBgYA0KDQpgYGB7ciBSZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgaGFiaXRhdC1SZXNlcnZhfQ0KZ2dwbG90KHRhYkhhYiwgYWVzKHggPSAiIiwgeSA9IEZyZWN1ZW5jaWEsIGZpbGwgPUjDoWJpdGF0KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQgPSAwKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImxpZ2h0Ymx1ZTMiLCJza3libHVlMyIsICJza3libHVlNCIsImxpZ2h0Ymx1ZSIpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQoRnJlY3VlbmNpYSAvIHN1bShGcmVjdWVuY2lhKSAqIDEwMCksICIlIikpLCANCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArDQogIGxhYnModGl0bGUgPSAiSMOhYml0YXQgZW4gbG9zIHF1ZSBzZSBhdmlzdGFyb24gbGFzIGF2ZXMtUmVzZXJ2YSIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksICAgICANCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCAgICANCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNCmBgYHtyIFRhYmxhIGRlIGZyZWN1ZW5jaWFzIHZhcmlhYmxlIGhhYml0YXQtSGFjaWVuZGEgTGEgQ29uZWplcmF9DQp0YWJIYWJIPWFzLmRhdGEuZnJhbWUodGFibGUoQXZlc0NvbmVqZXJhJGhhYml0YXQpKQ0KY29sbmFtZXModGFiSGFiSCk9YygiSMOhYml0YXQiLCJGcmVjdWVuY2lhIikNCnRhYkhhYkgNCmBgYA0KDQpgYGB7ciBSZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgaGFiaXRhdC1IYWNpZW5kYSBMYSBDb25lamVyYX0NCmdncGxvdCh0YWJIYWJIW3RhYkhhYkgkRnJlY3VlbmNpYSA+IDAsIF0sIGFlcyh4ID0gIiIsIHkgPSBGcmVjdWVuY2lhLCBmaWxsID1Iw6FiaXRhdCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJsaWdodGJsdWUzIiwic2t5Ymx1ZTMiLCAibGlnaHRibHVlIikpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChGcmVjdWVuY2lhIC8gc3VtKEZyZWN1ZW5jaWEpICogMTAwKSwgIiUiKSksIA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICJIw6FiaXRhdCBlbiBsb3MgcXVlIHNlIGF2aXN0YXJvbiBsYXMgYXZlcy1IYWNpZW5kYSBMYSBDb25lamVyYSIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksICAgICANCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCAgICANCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNCiMjIyBWYXJpYWJsZSBgZXN0cnVjdHVyYVNvY2lhbGANCg0KYGBge3IgVGFibGEgZGUgZnJlY3VlbmNpYXMgRXN0cnVjdHVyYSBTb2NpYWwtUmVzZXJ2YX0NCnRhYkVzdHI9YXMuZGF0YS5mcmFtZSh0YWJsZShzaW5GYWx0JGVzdHJ1Y3R1cmFTb2NpYWwpKQ0KY29sbmFtZXModGFiRXN0cik9YygiRXN0LiBTb2NpYWwiLCJGcmVjdWVuY2lhIikNCnRhYkVzdHINCmBgYA0KDQpgYGB7ciBHcsOhZmljYSBFc3RydWN0dXJhIFNvY2lhbC1SZXNlcnZhfQ0KZ2dwbG90KHRhYkVzdHIsIGFlcyh4ID0gYEVzdC4gU29jaWFsYCwgeSA9IEZyZWN1ZW5jaWEpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiLCB3aWR0aCA9IDAuNSkgKyAgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVjdWVuY2lhKSwgdmp1c3QgPSAtMC41LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiRXN0cnVjdHVyYSBzb2NpYWwgZGUgbGFzIGF2ZXMgYXZpc3RhZGFzLVJlc2VydmEiLA0KICAgICAgIHggPSAiRXN0ci4gU29jaWFsIiwNCiAgICAgICB5ID0gIkZyZWN1ZW5jaWEiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkNCmBgYA0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyBFc3RydWN0dXJhIFNvY2lhbC1IYWNpZW5kYSBMYSBDb25lamVyYX0NCkF2ZXNDb25lamVyYSRlc3RydWN0dXJhU29jaWFsPWRyb3BsZXZlbHMoQXZlc0NvbmVqZXJhJGVzdHJ1Y3R1cmFTb2NpYWwpDQp0YWJFc3RySD1hcy5kYXRhLmZyYW1lKHRhYmxlKEF2ZXNDb25lamVyYSRlc3RydWN0dXJhU29jaWFsKSkNCmNvbG5hbWVzKHRhYkVzdHJIKT1jKCJFc3QuIFNvY2lhbCIsIkZyZWN1ZW5jaWEiKQ0KdGFiRXN0ckgNCmBgYA0KDQpgYGB7ciBHcsOhZmljYSBFc3RydWN0dXJhIFNvY2lhbC1IYWNpZW5kYSBMYSBDb25lamVyYX0NCmdncGxvdCh0YWJFc3RySCwgYWVzKHggPSBgRXN0LiBTb2NpYWxgLCB5ID0gRnJlY3VlbmNpYSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIsIHdpZHRoID0gMC41KSArICANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZWN1ZW5jaWEpLCB2anVzdCA9IC0wLjUsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIpICsNCiAgbGFicyh0aXRsZSA9ICJFc3RydWN0dXJhIHNvY2lhbCBkZSBsYXMgYXZlcyBhdmlzdGFkYXMtSGFjaWVuZGEgTGEgQ29uZWplcmEiLA0KICAgICAgIHggPSAiRXN0ci4gU29jaWFsIiwNCiAgICAgICB5ID0gIkZyZWN1ZW5jaWEiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkNCmBgYA0KDQojIyMgVmFyaWFibGUgYGJlaGF2aW9yYA0KDQpgYGB7ciBUYWJsYSBkZSBmcmVjdWVuY2lhcyBDb21wb3J0YW1pZW50by1SZXNlcnZhfQ0Kc2luRmFsdCRiZWhhdmlvcj1kcm9wbGV2ZWxzKHNpbkZhbHQkYmVoYXZpb3IpDQp0YWJDb21wPWFzLmRhdGEuZnJhbWUodGFibGUoc2luRmFsdCRiZWhhdmlvcikpDQpjb2xuYW1lcyh0YWJDb21wKT1jKCJDb21wb3J0YW1pZW50byIsIkZyZWN1ZW5jaWEiKQ0KdGFiQ29tcA0KYGBgDQoNCmBgYHtyIEdyw6FmaWNhIENvbXBvcnRhbWllbnRvLVJlc2VydmF9DQpnZ3Bsb3QodGFiQ29tcCwgYWVzKHggPSBDb21wb3J0YW1pZW50bywgeSA9IEZyZWN1ZW5jaWEpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiLCB3aWR0aCA9IDAuNSkgKyAgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVjdWVuY2lhKSwgdmp1c3QgPSAtMC41LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiQ29tcG9ydGFtaWVudG8gZGUgbGFzIGF2ZXMgYXZpc3RhZGFzLVJlc2VydmEiLA0KICAgICAgIHggPSAiQ29tcG9ydGFtaWVudG8iLA0KICAgICAgIHkgPSAiRnJlY3VlbmNpYSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQ0KYGBgDQoNCmBgYHtyIFRhYmxhIGRlIGZyZWN1ZW5jaWFzIENvbXBvcnRhbWllbnRvLUhhY2llbmRhIExhIENvbmVqZXJhfQ0KQXZlc0NvbmVqZXJhJGJlaGF2aW9yPWRyb3BsZXZlbHMoQXZlc0NvbmVqZXJhJGJlaGF2aW9yKQ0KdGFiQ29tcEg9YXMuZGF0YS5mcmFtZSh0YWJsZShBdmVzQ29uZWplcmEkYmVoYXZpb3IpKQ0KY29sbmFtZXModGFiQ29tcEgpPWMoIkNvbXBvcnRhbWllbnRvIiwiRnJlY3VlbmNpYSIpDQp0YWJDb21wSA0KYGBgDQoNCmBgYHtyIEdyw6FmaWNhIENvbXBvcnRhbWllbnRvLUhhY2llbmRhIExhIENvbmVqZXJhfQ0KZ2dwbG90KHRhYkNvbXBILCBhZXMoeCA9IENvbXBvcnRhbWllbnRvLCB5ID0gRnJlY3VlbmNpYSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIsIHdpZHRoID0gMC41KSArICANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZWN1ZW5jaWEpLCB2anVzdCA9IC0wLjUsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIpICsNCiAgbGFicyh0aXRsZSA9ICJDb21wb3J0YW1pZW50byBkZSBsYXMgYXZlcyBhdmlzdGFkYXMtSGFjaWVuZGEgTGEgQ29uZWplcmEiLA0KICAgICAgIHggPSAiQ29tcG9ydGFtaWVudG8iLA0KICAgICAgIHkgPSAiRnJlY3VlbmNpYSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQ0KYGBgDQoNCiMjIyBSZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMgZXRvbMOzZ2ljYXMNCg0KUGFyYSBleGFtaW5hciBjw7NtbyBpbnRlcmFjdMO6YW4gZXN0YXMgdmFyaWFibGVzLCBzZSByZWFsaXphcsOhIHVuIGRpYWdyYW1hIGRlIMOhcmJvbCBwYXJhIGV4cGxvcmFyIGxhIHBhcnRpY2nDs24gY29ycmVzcG9uZGllbnRlIGEgbGEgSGFjaWVuZGEgTGEgQ29uZWplcmEgZW4gbG9zIGF2aXN0YW1pZW50b3MgcmVhbGl6YWRvcyBlbiBsYSBtYcOxYW5hLCBhcHJvdmVjaGFuZG8gc3UgcG90ZW5jaWFsIHBhcmEgcmVzdW1pciBlbCBjb21wb3J0YW1pZW50byBkZSBsYXMgdmFyaWFibGVzIGVuIGNvbmp1bnRvLiBBIGRpZmVyZW5jaWEgZGUgbGFzIHZhcmlhYmxlcyB0YXhvbsOzbWljYXMsIGVzdGFzIG5vIHNpZ3VlbiB1bmEgamVyYXJxdcOtYSBlc3BlY8OtZmljYSwgcG9yIGxvIHF1ZSBxdWVkYSBhIGRpc2NyZWNpw7NuIGRlbCBpbnZlc3RpZ2Fkb3IgZWxlZ2lyIGVsIG9yZGVuIGVuIHF1ZSBzZSBwcmVzZW50YXLDoW4gZW4gZWwgZGlhZ3JhbWEuIFBhcmEgZWwgcHJlc2VudGUgZXN0dWRpbywgc2UgdHJhYmFqYXLDoW4gZXN0YXMgdmFyaWFibGVzIGVuIGVsIHNpZ3VpZW50ZSBvcmRlbjogY29tcG9ydGFtaWVudG8sIGjDoWJpdGF0IHkgZXN0cnVjdHVyYSBzb2NpYWwuDQoNCmBgYHtyIFBhcnRpY2nDs24gSGFjaWVuZGEgTGEgQ29uZWplcmEtQXZpc3RhbWllbnRvcyBkZSBsYSBtYcOxYW5hfQ0KQXZlc0NvbmVBTT1BdmVzQ29uZWplcmFbQXZlc0NvbmVqZXJhJG9jY3VycmVuY2VSZW1hcmtzID09ICJtYcOxYW5hIiwgXQ0KYGBgDQoNCmBgYHtyIFJlbGFjacOzbiBlbnRyZSBjb21wb3J0YW1pZW50bywgaMOhYml0YXQgeSBlc3RydWN0dXJhIHNvY2lhbH0NCkF2ZXNDb25lQU1fY291bnQ9QXZlc0NvbmVBTSAlPiUNCiAgZHBseXI6OmNvdW50KGJlaGF2aW9yLGhhYml0YXQsZXN0cnVjdHVyYVNvY2lhbCxuYW1lID0gIkNvdW50IikNCnRyZWVtYXAoQXZlc0NvbmVBTV9jb3VudCwNCiAgICAgICAgaW5kZXggPSBjKCAiYmVoYXZpb3IiLCJoYWJpdGF0IiwiZXN0cnVjdHVyYVNvY2lhbCIpLA0KICAgICAgICB2U2l6ZSA9ICJDb3VudCIsDQogICAgICAgICB2Q29sb3IgPSAiQ291bnQiLA0KICAgICAgICAgdHlwZSA9ICJ2YWx1ZSIsDQogICAgICAgICB0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIGxhcyBhdmVzIHNlZ8O6biBzdSBjb21wb3J0YW1pZW50bywgaMOhYml0YXQgeSBlc3RyLiBzb2NpYWwiLA0KICAgICAgICAgcGFsZXR0ZSA9ICJCbHVlcyIsICANCiAgICAgICAgIGJvcmRlci5jb2wgPSAiYmxhY2siLCAgDQogICAgICAgICBmb250c2l6ZS5sYWJlbHMgPSBjKDE2LCAxMywgMTApLCANCiAgICAgICAgIGFsaWduLmxhYmVscyA9bGlzdCgNCiAgICAgICAgICAgYygiY2VudGVyIiwgInRvcCIpLCAgIA0KICAgICAgICAgICBjKCJsZWZ0IiwgImNlbnRlciIpLCAgDQogICAgICAgICAgIGMoInJpZ2h0IiwgImJvdHRvbSIpICANCiAgICAgICAgICksDQogICAgICAgICBpbmZsYXRlLmxhYmVscyA9IEZBTFNFKQ0KYGBgDQoNCkNvbW8gc2UgcHVlZGUgdmVyLCBsYSBtYXlvcsOtYSBkZSBsb3MgYXZpc3RhbWllbnRvcyBkZSBsYSBtYcOxYW5hIGVuIGxhIEhhY2llbmRhIExhIENvbmVqZXJhIGNvcnJlc3BvbmRpZXJvbiBhIGF2ZXMgZGVzY2Fuc2FuZG8gZW4gaMOhYml0YXRzIGRlIGJvc3F1ZSBtaXh0byBuYXRpdm8sIGVuIGdydXBvcyBjb2VzcGVjw61maWNvcy4gUG9zdGVyaW9ybWVudGUsIHNlIG9ic2VydsOzIHVuYSBjYW50aWRhZCBjb25zaWRlcmFibGUgZGUgYXZlcyBkZXNwbGF6w6FuZG9zZSBlbnRyZSBsYSB2ZWdldGFjacOzbiwgcHJpbmNpcGFsbWVudGUgZW4gaMOhYml0YXRzIGRlIGJvc3F1ZSBuYXRpdm8sIGVuIGdydXBvcyBjb2VzcGVjw61maWNvcyBvIGVuIHBhcmVqYXMuIEVuIG1lbm9yIHByb3BvcmNpw7NuLCBzZSBhdmlzdGFyb24gYXZlcyBhbGltZW50w6FuZG9zZSwgcHJpbmNpcGFsbWVudGUgZW4gYm9zcXVlIG5hdGl2byB5IGVuIHBhcmVqYXMuIENvbiBtZW5vciBmcmVjdWVuY2lhLCBzZSBvYnNlcnZhcm9uIGF2ZXMgdm9sYW5kbywgZW4gaWd1YWwgcHJvcG9yY2nDs24gZW4gYm9zcXVlcyBtaXh0b3MgeSBuYXRpdm9zLCB1c3VhbG1lbnRlIGVuIGdydXBvcyBjb2VzcGVjw61maWNvcy4NCg0KIyBBbsOhbGlzaXMgZGUgYXNvY2lhY2nDs25lcyBwb3IgY2F0ZWdvcsOtYXMNCg0KVW5hIHZleiBlc3R1ZGlhZG8gZWwgZmVuw7NtZW5vIGRlIGJpb2RpdmVyc2lkYWQgcG9yIGNhdGVnb3LDrWFzLCBzZSBwcm9wb25lIGJ1c2NhciBwb3NpYmxlcyByZWxhY2lvbmVzIGVudHJlIGVzdGFzIHBhcmEgZXh0cmFlciBpbmZvcm1hY2nDs24gYWRpY2lvbmFsIHF1ZSBwZXJtaXRhIGlkZW50aWZpY2FyIHBhdHJvbmVzIGVuIGVsIG11ZXN0cmVvIHJlY29sZWN0YWRvIGVuIGxhIGJhc2UgZGUgZGF0b3MuIFBhcmEgZXN0bywgc2UgdXRpbGl6YXLDoSB1biBtw6l0b2RvIGVzdGFkw61zdGljbyBtdWx0aXZhcmlhZG8gY29ub2NpZG8gY29tbyBBbsOhbGlzaXMgZGUgQ29ycmVzcG9uZGVuY2lhIE3Dumx0aXBsZSAoQUNNKS4gRW4gZWwgcHJlc2VudGUgZXN0dWRpbywgc2UgYW5hbGl6YXLDoSBsYSBwYXJ0aWNpw7NuIGNvcnJlc3BvbmRpZW50ZSBhIGxhIGxvY2FsaWRhZCBkZSBsYSBIYWNpZW5kYSBMYSBDb25lamVyYSB5IGxhcyBvYnNlcnZhY2lvbmVzIHJlYWxpemFkYXMgZW4gbGEgam9ybmFkYSBkZSBsYSBtYcOxYW5hLiBMYXMgdmFyaWFibGVzIGNvbnNpZGVyYWRhcyBzZXLDoW4gZWwgb3JkZW4gKGBvcmRlcmApLCBlbCBjb21wb3J0YW1pZW50byAoYGJlaGF2aW9yYCksIGxhIGVzdHJ1Y3R1cmEgc29jaWFsIChgZXN0cnVjdHVyYVNvY2lhbGApIHkgZWwgaMOhYml0YXQgKGBoYWJpdGF0YCkuDQoNCiMjIEFuw6FsaXNpcyBkZSBjb3JyZXNwb25kZW5jaWEgbcO6bHRpcGxlDQoNCmBgYHtyIEFDTX0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCmRhdG9zQUNNPXN1YnNldChBdmVzQ29uZUFNLCBzZWxlY3QgPSBjKCJvcmRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmVoYXZpb3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImVzdHJ1Y3R1cmFTb2NpYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhhYml0YXQiKSkNCm1jYT1NQ0EoZGF0b3NBQ00sZ3JhcGg9RkFMU0UpDQpgYGANCg0KYGBge3IgVmFyaWFuemEgZXhwbGljYWRhIHBvciBsYXMgZGltZW5zaW9uZXN9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KHBhbmRlcikNCmVpZ2VudmFsPWdldF9laWdlbnZhbHVlKG1jYSkNCnBhbmRlcihlaWdlbnZhbCkNCnNjcGw9ZnZpel9zY3JlZXBsb3QobWNhLGFkZGxhYmVscz1UUlVFKQ0Kc2NwbA0KYGBgDQoNClNlIHRpZW5lIHF1ZSBsYXMgcHJpbWVyYXMgY2luY28gZGltZW5zaW9uZXMgZGV0ZXJtaW5hZGFzIHBvciBlbCBBQ00gZXhwbGljYW4gdW4gNzAuNzMlIGRlIGxhIHZhcmlhbnphIGRlbCBmw6lub21lbm8gZXN0dWRpYWRvLiBTZSBwcm9jZWRlIGEgZXhwbG9yYXIgbGFzIGFjdGVnb3LDrWFzIHF1ZSBkZWZpbmVuIGVzdGFzIGRpbWVuc2lvbmVzLg0KDQpgYGB7ciBDb250cmlidWNpb25lc30NCnZhckNvbnQ9bWNhJHZhciRjb250cmliDQp2YXJDb250VD1yb3dTdW1zKHZhckNvbnRbLCAxOjVdKQ0KdmFyQ29udFA9MTAwKnZhckNvbnRUL3N1bSh2YXJDb250VCkNCnZhckNvbnRERj1kYXRhLmZyYW1lKFZhcmlhYmxlPW5hbWVzKHZhckNvbnRQKSwgQ29udHJpYnVjacOzbj12YXJDb250UCkNCnZhckNvbnRERj12YXJDb250REZbb3JkZXIodmFyQ29udERGJENvbnRyaWJ1Y2nDs24sIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0KdmFyQ29udERGDQpgYGANCg0KYGBge3IgR3LDoWZpY2EgY29udHJpYnVjaW9uZXMsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCnBhcihtYXIgPSBjKDE1LCA0LCA0LCAyKSArIDAuMSkNCmJhcnBsb3Q9YmFycGxvdCh2YXJDb250REYkQ29udHJpYnVjacOzbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMuYXJnID0gdmFyQ29udERGJFZhcmlhYmxlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBsYXMgPSAyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSAiIzQ2ODJiNCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICJDb250cmlidWNpw7NuIGRlIGxhcyBjYXRlZ29yaWFzIGRlIGxhcyB2YXJpYWJsZXMgYSBsYXMgRGltZW5zaW9uZXMgMS01ICglKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgeWxpbSA9IGMoMCwgbWF4KHZhckNvbnRERiRDb250cmlidWNpw7NuKSAqIDEuMikpDQp0ZXh0KHggPSBiYXJwbG90LA0KICAgICAgeSA9IHZhckNvbnRERiRDb250cmlidWNpw7NuLA0KICAgICAgbGFiZWwgPSBzcHJpbnRmKCIlLjFmJSUiLCB2YXJDb250REYkQ29udHJpYnVjacOzbiksDQogICAgICBwb3MgPSAzLCBjZXggPSAwLjgsIGNvbCA9ICJibGFjayIpDQpgYGANCg0KIVtdKGRpbTE1bmIpDQoNCkFsIGRldGFsbGFyIGxhcyBjYXRlZ29yw61hcyBxdWUgZGV0ZXJtaW5hbiBlc3RhcyBjaW5jbyBkaW1lbnNpb25lcywgc2UgZW5jdWVudHJhbiBxdWUgZW50cmUgbGFzIHByaW5jaXBhbGVzIDE0IHNlIHJlc2FsdGFuIG9yZGVuZXMgdGF4b27Ds21pY29zIGNvbW8gbG9zIGN1Y3VsaWZvcm1lcywgZ2FsbGlmb3JtZXMgeSBsb3MgYXBvZGlmb3JtZXMsIGFzw60gY29tbyBjb21wb3J0YW1pZW50b3MgY29tbyB2b2xhciwgYWxpbWVudGFyc2UgeSBtb3ZlcnNlIGVudHJlIGxhIHZlZ2V0YWNpw7NuLCB5IGxhIGVzdGFuY2lhIGRlIGxhcyBhdmVzIGVuIHBhcmVqYXMuIEFkZW3DoXMsIGjDoWJpdGF0cyBjb21vIGVsIGJvc3F1ZSBtaXh0byBuYXRpdm8geSBlbCBib3NxdWUgbmF0aXZvIHRhbWJpw6luIGZpZ3VyYW4gZW50cmUgbGFzIGNhdGVnb3LDrWFzIG3DoXMgc2lnbmlmaWNhdGl2YXMNCg0KIyMgQ2x1c3Rlcml6YWNpw7NuIHBvciBrLW1lYW5zDQoNCkFwcm92ZWNoYW5kbyBlbCBwcm9jZXNvIHJlYWxpemFkbyBjb24gZWwgQUNNLCBzZSBwcm9jZWRlIGEgaGFjZXIgdW4gcHJvY2VzbyBkZSBjbHVzdGVyaXphY2nDs24gcG9yIGstbWVhbnMsIGNvbiBlbCBmaW4gZGUgaWRlbnRpZmljYXIgZ3J1cG9zIGNvbiBjYXJhY3RlcsOtc3RpY2FzIHNpbWlsYXJlcy4gUGFyYSBlc3RlIHByb2Nlc28sIHNlIGhhcsOhIHVzbyBkZSBsYXMgcHJpbWVyYXMgZG9zIGRpbWVuc2lvbmVzIGdlbmVyYWRhcyBwb3IgZWwgQUNNIChxdWUgZXhwbGljYW4gZWwgMzUlIGRlIGxhIHZhcmlhbnphKS4gSW5pY2lhbG1lbnRlIHNlIHJldmlzYSBsYXMgY2F0ZWdvcsOtYXMgcXVlIGRldGVybWluYW4gZXN0YXMgZG9zIGRpbWVuc2lvbmVzLg0KDQpgYGB7ciBDb250cmlidWNpb25lcyBkaW1lbnNpb25lcyAxIHkgMn0NCnZhckNvbnRUMj1yb3dTdW1zKHZhckNvbnRbLCAxOjJdKQ0KdmFyQ29udFAyPTEwMCp2YXJDb250VDIvc3VtKHZhckNvbnRUMikNCnZhckNvbnRERjI9ZGF0YS5mcmFtZShWYXJpYWJsZT1uYW1lcyh2YXJDb250UDIpLCBDb250cmlidWNpw7NuPXZhckNvbnRQMikNCnZhckNvbnRERjI9dmFyQ29udERGMltvcmRlcih2YXJDb250REYyJENvbnRyaWJ1Y2nDs24sIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0KdmFyQ29udERGMg0KYGBgDQoNCmBgYHtyIEdyw6FmaWNhIGRlIGNvbnRyaWJ1Y2lvbmVzIDEgeSAyLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9DQpwYXIobWFyID0gYygxNSwgNCwgNCwgMikgKyAwLjEpDQpiYXJwbG90MiA9IGJhcnBsb3QodmFyQ29udERGMiRDb250cmlidWNpw7NuLCANCiAgICAgICAgICAgICAgICAgICBuYW1lcy5hcmcgPSB2YXJDb250REYyJFZhcmlhYmxlLCANCiAgICAgICAgICAgICAgICAgICBsYXMgPSAyLCANCiAgICAgICAgICAgICAgICAgICBjb2wgPSAiIzQ2ODJiNCIsDQogICAgICAgICAgICAgICAgICAgbWFpbiA9ICJDb250cmlidWNpw7NuIGRlIGxhcyBjYXRlZ29yw61hcyBkZSBsYXMgdmFyaWFibGVzIGEgbGFzIERpbWVuc2lvbmVzIDEtMiAoJSkiLA0KICAgICAgICAgICAgICAgICAgIHlsaW0gPSBjKDAsIG1heCh2YXJDb250REYyJENvbnRyaWJ1Y2nDs24pICogMS4yKSkNCnRleHQoeCA9IGJhcnBsb3QyLA0KICAgICB5ID0gdmFyQ29udERGMiRDb250cmlidWNpw7NuLA0KICAgICBsYWJlbCA9IHNwcmludGYoIiUuMWYlJSIsIHZhckNvbnRERjIkQ29udHJpYnVjacOzbiksDQogICAgIHBvcyA9IDMsIGNleCA9IDAuOCwgY29sID0gImJsYWNrIikNCmBgYA0KDQohW10oZG0xMm5iKQ0KDQpFbnRyZSBsYXMgY2F0ZWdvcsOtYXMgcXVlIHRpZW5lbiBjb250cmlidWNpb25lcyBzaWduaWZpY2F0aXZhcyBhIGVzdGFzIGRpbWVuc2lvbmVzIHNlIGVuY3VlbnRyYW4gbG9zIMOzcmRlbmVzIEdhbGxpZm9ybWVzLCBDb2x1bWJpZm9ybWVzIHkgQ3VjdWxpZm9ybWVzLCBhc8OtIGNvbW8gY29tcG9ydGFtaWVudG9zIGNvbW8gbGEgYWxpbWVudGFjacOzbiB5IGVsIG1vdmltaWVudG8gZW50cmUgdmVnZXRhY2nDs24sIGxhIGVzdGFuY2lhIGVuIGdydXBvcyBjb2VzcGVjw61maWNvcyBvIGVuIHNvbGl0YXJpby4NCg0KTHVlZ28gZGUgZXN0bywgc2UgcHJvY2VkZSBhIGxhIGV4cGxvcmFjacOzbiBkZSBhc29jaWFjaW9uZXMgZW50cmUgb2JzZXJ2YWNpb25lcyB5IGNhdGVnb3LDrWFzIHBvciBtZWRpbyBkZSB1biBkaWFncmFtYSBkZSBiaXBsb3QuDQoNCmBgYHtyfQ0KcGxvdChtY2EsIGludmlzaWJsZSA9ICJpbmQiLCBjb2wudmFyID0gImJsdWUiLCBjZXggPSAwLjgpDQppbmRQbG90PWZ2aXpfbWNhX2luZChtY2EsZ2VvbS5pbmQ9InBvaW50Iixjb2wuaW5kPSJibHVlIixyZXBlbD1GQUxTRSkNCnZhclBsb3Q9ZnZpel9tY2FfdmFyKG1jYSxjb2wudmFyPSJyZWQiLHJlcGVsPVRSVUUpDQpjb21iUGxvdD1mdml6X21jYV9iaXBsb3QobWNhLCBnZW9tLmluZD0icG9pbnQiLGNvbC5pbmQ9ImJsdWUiLGNvbC52YXI9InJlZCIscmVwZWw9VFJVRSkNCmNvbWJQbG90DQpgYGANClVzYW5kbyBlc3RlIGdyw6FmaWNvIGNvbW8gYmFzZSwgc2UgaW5pY2lhIGVsIHByb2Nlc28gZGUgY2x1c3Rlcml6YWNpw7NuLg0KDQpgYGB7cn0NCmxpYnJhcnkoY2x1c3RlcikNCmluZENvb3Jkcz1tY2EkaW5kJGNvb3JkDQpzZXQuc2VlZCgxMjMpDQprbVJlcz1rbWVhbnMoaW5kQ29vcmRzLCBjZW50ZXJzID0gMywgbnN0YXJ0ID0gMjUpDQptY2EkaW5kJGNsdXN0ZXI9a21SZXMkY2x1c3Rlcg0KaW5kRGF0YT1kYXRhLmZyYW1lKGluZENvb3JkcyxjbHVzdGVyID0gYXMuZmFjdG9yKGttUmVzJGNsdXN0ZXIpKQ0KYGBgDQpgYGB7ciBHcsOhZmljYSBjbMO6c3RlcmVzIHVzYW5kbyBwb2zDrWdvbm9zIHBhcmEgZGVsaW1pdGFyIGdydXBvc30NCmNyZWF0ZVBvbHlnb249ZnVuY3Rpb24oY2x1c3Rlcl9kYXRhKXsNCiAgaHVsbD1jaHVsbChjbHVzdGVyX2RhdGEkRGltLjEsIGNsdXN0ZXJfZGF0YSREaW0uMikNCiAgaHVsbD1jKGh1bGwsIGh1bGxbMV0pDQogIGNsdXN0ZXJfZGF0YVtodWxsLCBdDQp9DQoNCnBvbHlnb25EYXRhPWluZERhdGEgJT4lDQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQ0KICBkbyhjcmVhdGVQb2x5Z29uKC4pKQ0KDQpnZ3Bsb3QoaW5kRGF0YSwgYWVzKHggPSBEaW0uMSwgeSA9IERpbS4yLCBjb2xvciA9IGNsdXN0ZXIpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fcG9seWdvbihkYXRhID0gcG9seWdvbkRhdGEsIGFlcyh4ID0gRGltLjEsIHkgPSBEaW0uMiwgZ3JvdXAgPSBjbHVzdGVyLCBmaWxsID0gY2x1c3RlciksIGFscGhhID0gMC4yKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiQ2x1c3Rlcml6YWNpw7NuIGRlIEF2ZXMiLCB4ID0gIkRpbWVuc2nDs24gMSIsIHkgPSAiRGltZW5zacOzbiAyIikNCmNvbWJQbG90ICsNCiAgZ2VvbV9wb2ludChkYXRhID0gaW5kRGF0YSwgYWVzKHggPSBEaW0uMSwgeSA9IERpbS4yLCBjb2xvciA9IGNsdXN0ZXIpKSArDQogIGdlb21fcG9seWdvbihkYXRhID0gcG9seWdvbkRhdGEsIGFlcyh4ID0gRGltLjEsIHkgPSBEaW0uMiwgZ3JvdXAgPSBjbHVzdGVyLCBmaWxsID0gY2x1c3RlciksIGFscGhhID0gMC4yKQ0KDQpgYGANCkVzdGUgcHJvY2VzbyBzZSByZWFsaXrDsyBlc3RhYmxlY2llbmRvIHRyZXMgY2zDunN0ZXJlcywgZGUgbG9zIGN1YWxlcyBkb3MgZXN0w6FuIGNsYXJhbWVudGUgZGVmaW5pZG9zIGVuIGxhIGdyw6FmaWNhLiBFbCBwcmltZXIgZ3J1cG8gbXVlc3RyYSBxdWUgbGFzIGF2ZXMgZGVsIG9yZGVuIENvbHVtYmlmb3JtZXMgdGllbmRlbiBhIGhhYml0YXIgYm9zcXVlcyBtaXh0b3MgbmF0aXZvcyB5IHNvbiBhdmlzdGFkYXMgZW4gZ3J1cG9zIGNvZXNwZWPDrWZpY29zLiBFbiBlbCBzZWd1bmRvIGNsw7pzdGVyLCBzZSBvYnNlcnZhIHF1ZSBsYXMgYXZlcyBkZSBsb3Mgw7NyZGVuZXMgUGFzc2VyaWZvcm1lcyB5IEFwb2RpZm9ybWVzIHN1ZWxlbiBoYWJpdGFyIGJvc3F1ZXMgbmF0aXZvcyB5IHNvbiBhdmlzdGFkYXMgbWllbnRyYXMgZGVzY2Fuc2FuIGVuIHBhcmVqYXMgbyBzb2xhcy4gRWwgw7psdGltbyBncnVwbyBubyBlc3TDoSB0YW4gYmllbiBkZWxpbWl0YWRvIGNvbW8gbG9zIGRvcyBhbnRlcmlvcmVzLCBtb3N0cmFuZG8gdW5hIGFsdGEgaGV0ZXJvZ2VuZWlkYWQgeSBubyBhZ3J1cMOhbmRvc2Ugc2Vnw7puIGxhcyBjYXRlZ29yw61hcyBwcmVkb21pbmFudGVzIGRlIGxhcyBkb3MgZGltZW5zaW9uZXMgYW5hbGl6YWRhcyBlbiBlc3RlIHByb2Nlc28uDQoNCg0KIyBSZWZlcmVuY2lhcw0KDQpCYXJyZXJhLCBNLiBDLiBBLiAoMjAyMywgYWdvc3RvKS4gQ2FyYWN0ZXJpemFjacOzbiBkZSBhdmlmYXVuYSAtIFJlc2VydmEgVGhvbWFzIFZhbmRlciBIYW1tZW4gdjIuMS4gRGF0YXNldC9PY2N1cnJlbmNlLiA8aHR0cHM6Ly9kb2kub3JnLzEwLjE1NDcyL2Fscmx3ZT4NCg0KR3JpZmZpdGhzLCBSaWNoYXJkLCBhbmQgRCBQaGlsLiAoMjAwMCkuIOKAnFNleCBJZGVudGlmaWNhdGlvbiBpbiBCaXJkcy7igJ0NCg==