REPORTE TRABAJO 1: SOLUCIÓN DE PROBLEMAS DE OPTIMIZACIÓN CON MÉTODOS HEURÍSTICOS

REDES NEURONALES Y ALGORITMOS BIOINSPIRADOS




Presentado por:

Leonardo Federico Corona Torres
David Escobar Ruiz
Johan Sebastian Robles Rincón
Sebastián Soto Arcila



Profesor: Juan David Ospina Arango

Monitor: Andrés Mauricio Zapata Rincón


University Logo

Universidad Nacional de Colombia
Facultad de Minas
Ingeniería de Sistemas e Informática

22 de junio de 2025

Contenidos

Introducción

El presente trabajo trata algunos de los métodos más relevantes de optimización numérica basada en manipulaciones del gradiente de una función objetivo (función a optimizar) y también algoritmos heurísticos basados en el comportamiento de la naturaleza, como lo son los algoritmos evolutivos. Todos estos métodos pueden llegar a ser útiles en distintos contextos en los que se busca optimizar una función para algún fin, como encontrar la mejor ruta entre ciudades o optimizar una función de pérdida en un contexto de aprendizaje de máquina. Cada método tiene particularidades interesantes que se van a explorar de manera general por medio de una breve implementación y ejecución con dos funciones muy utilizadas para probar algoritmos de optimización: la función de Rosenbrock y la función de Rastrigin.

Metodología

Para implementar y documentar la optimización se emplea R Markdown, combinando código R y texto explicativo. Se utilizan librerías para renderizar gráficos y animaciones, librerías para implementar los métodos heurísticos y librerías para manipular los datos. Para los casos 3D (tres variables) es difícil visualizar directamente la función de 3 dimensiones (espacio de 4 variables), por lo que se mostrarán únicamente los puntos óptimos alcanzados.

Parte 1. Optimización numérica

1.1 Selección e implementación de las funciones de prueba

Para observar el comportamiento de cada uno de los métodos de optimización implementados, se optó por la selección de dos funciones de prueba estándar para evaluar algoritmos de optimización: Función de Rosenbrock y Función de Rastrigin. Debido a su complejidad, ambas funciones son indicadores útiles para comparar la eficacia de optimizadores como los AG.

Previo a la implementación de los algoritmos en el lenguaje R y previo a la recopilación de resultados y la derivación de conclusiones a partir de estos, el equipo decidió realizar una breve investigación general de lo que son las funciones de prueba para problemas de optimización. La investigación se realizó de tal forma que, una vez concluída, se pudieran comprender los conceptos hasta el punto de estar en las capacidades responder las siguientes preguntas implícitamente en una breve sección de este trabajo:

  • ¿Qué es una función de prueba en optimización?

  • ¿Para qué se utiliza una función de prueba en optimización?

  • ¿Cómo se pueden clasificar las funciones de prueba?

  • ¿Cuáles son algunas de las funciones de prueba más utilizadas?

A continuación se presenta dicha sección para luego continuar con el estudio más detallado de las funciones escogidas.

1.1.1 Breve explicación de las funciones de prueba para problemas de optimización

Según (Yang, 2010), una función de prueba es una función con unas propiedades especiales que permite probar si el rendimiento de un método de optimización implementado es aceptable bajo las condiciones especiales que impone la función de prueba. 

Esto es especialmente útil para verificar que el método sea eficiente bajo distintas condiciones en las que se espera que se implemente, como por ejemplo, casos en los que la función tiene múltiples mínimos y/o máximos locales.

Según (Molga, 2005), las funciones de prueba se pueden ubicar en una de las siguientes clases, todas siendo funciones continuas:

  • Clase 1: Unimodal, convexa, multidimensional.
  • Clase 2: Multimodal, dos dimensiones con un número pequeño de extremos locales.
  • Clase 3: Multimodal, dos dimensiones con un gran número de extremos locales.
  • Clase 4: Multimodal, multidimensional, con un número amplio de extremos locales.

En el caso de las funciones elegidas, la función de Rosenbrock se clasificaría como Clase 3 y la de Rastrigin como Clase 2.

Como ejemplo, en la Figura 1 se presentan algunas funciones de prueba que no se eligieron para este trabajo, pero que son igual de relevantes, importantes y comúnmente utilizadas en la práctica (Molga, 2005):

  • Función de De Jong (Clase 1).

  • Función de Griewangk (Clase 2).

  • Función de Langermann (Clase 3).

  • Función de Ackley (Clase 4).

1.1.2 Función de Rosenbrock

Es una función no convexa introducida por Rosenbrock en 1960​ (Wikipedia, s.f., Rosenbrock function). Su paisaje forma un valle curvo estrecho que dificulta la convergencia hacia el mínimo.

Definición en n dimensiones:

\(f(X) = \sum_{i=1}^{n-1}100(X_{i+1}-X_i^2)^2 + (1-X_i)^2\) (1)

Definición en 2D:

\(f(x,y)= 100(y-x^2)^2 + (1-x)^2\)

Definición en 3D:

\(f(x,y,z)=100[(y-x^2)^2+(z-y^2)^2] + (1-x)^2 + (1-y)^2\)

Algunas características y propiedades importantes  son las siguientes:

  • Mínimo global:

    \(x_1,...,x_n =1, f(x_1,...,x_n) = 0\)

  • Dominio de búsqueda: 

    \(-\infty \leq X_i \leq \infty\)

    \(1 \leq i \leq n\)

  • Conocida también como la función banana de Rosenbrock.

  • Tiene forma de valle, el cual es trivial encontrarlo. Sin embargo, la convergencia al mínimo global es difícil.

Estas son algunas hipótesis y expectativas que se tuvieron para el rendimiento de cada método implementado con esta función:

  • Método de descenso de gradiente:

    • Si se ubica el punto inicial sobre las rectas tangentes con mayor gradiente a la función entonces el método llegará más rápido a un mínimo.
    • Por el contrario, si la recta tangente tiene una gradiente más cercana a cero, el método llegará más lentamente, es decir, requerirá de más iteraciones para llegar al punto mínimo.
  • Método de algoritmos evolutivos:

    • Los criterios para seleccionar los individuos a reproducir va a ser muy importante para el rendimiento del método.
  • Método de optimización de partículas:

    • Este método no va a tener muchas dificultades para encontrar el punto óptimo es la función de Rosenbrock.
    • El criterio para parar las iteraciones no va a cambiar mucho los resultados en este caso.
  • Método de evolución diferencial:

    • Se comporta similar a los métodos evolutivos en 2 dimensiones.

La implementación de la función de Rosenbrock en 2, 3 y N dimensiones se muestra a continuación:

# 2 Dimensiones
f_rosenbrock_2d <- function(x, y) {   
  f_value <- 100*(y-(x^2))^2 + ((1-x)^2)   
  return(f_value) 
}  

# 3 Dimensiones
f_rosenbrock_3d <- function(x, y, z) {   
  f_value <- 100*((y-x^2)^2 + (z-y^2)^2) + (1-x)^2 + (1-y)^2   
  return(f_value) 
}

# N Dimensiones
f_rosenbrock <- function(x){
  x_1 <- tail(x, -1)
  x <- head(x, -1)
  z <- sum((100*((x_1-(x^2))^2))+((1-x)^2))
  return(z)
}

Las gráficas de la función de Rosenbrock en 2 y 3 dimensiones se muestran a continuación:

Gráfica de la función de Rosenbrock 2D

Gráfica de la función de Rosenbrock 2D

Gráfica de la función de Rosenbrock 3D

Gráfica de la función de Rosenbrock 3D

1.1.3 Función de Rastrigin

La función Rastrigin (1974) es una función no convexa y altamente multimodal, con numerosos mínimos locales, lo que la hace difícil de optimizar​ (Wikipedia, s.f., Rastrigin function).

Presenta múltiples mínimos locales dispuestos de forma regular​, lo que lo convierte en un desafío típico para algoritmos de optimización.

Definición en n dimensiones:

\(f(X)=An + \sum_{i=1}^n[X_i^2 -A\cos(2\pi X_i)], A=10\)

Definición en 2D:

\(f(x,y)=x^2+y^2+A[2-\cos(2\pi x) - \cos(2\pi y)], A=10\)

Definición en 3D:

\(f(x,y)=x^2+y^2+z^2+A[3-\cos(2\pi x) - \cos(2\pi y)-\cos(2\pi z)], A=10\)

Algunas características y propiedades importantes son las siguientes:

  • Mínimo global:

    • \(f(0,...0)=0\)
  • Dominio de búsqueda:

    • \(-5.12 \leq X_i \leq 5.12\)
  • Particularmente, hallar el mínimo de esta función es un problema difícil debido a la larga cantidad de mínimos locales.

Estas son algunas hipótesis y expectativas que se tuvieron para el rendimiento de cada método implementado con esta función:

  • Método de descenso de gradiente:

    • El éxito del método en alcanzar un mínimo dependerá enormemente del punto inicial elegido debido a los múltiples mínimos locales que tiene esta función.
  • Método de algoritmos evolutivos:

    • Es importante hacer una buena representación de los individuos, ya que el rendimiento puede variar dependiendo de la selección.
    • La población inicial debe ser representativa, diferentes entre ellos y que no sean demasiados. Para esta función en particular encontrar la solución óptima va a depender mucho de la probabilidad de mutación
  • Método de optimización de partículas:

    • La ubicación de la nube de partículas va a afectar el rendimiento en esta función, ya que el algoritmo puede quedarse estancado en un mínimo local si la ubicación no es la mejor.
    • El criterio para detener el algoritmo debe estar bien ajustado, para evitar estancamientos.
  • Método de evolución diferencial:

    • Es más eficiente que los otros métodos evolutivos ya que su fuerte son las múltiples dimensiones.

La implementación de la función de Rastrigin en 2, 3 y N dimensiones se muestra a continuación:

# 2 Dimensiones 
f_rastrigin_2d <- function(x, y) {
  A = 10   
  f_value <- x^2 + y^2 + A*(2 - cos(2*pi*x) - cos(2*pi*y))   
  return(f_value) 
}  

# 3 Dimensiones 
f_rastrigin_3d <- function(x, y, z) {   
  A = 10   
  f_value <- x^2 + y^2 + z^2 + A*(3 - cos(2*pi*x) - cos(2*pi*y) - cos(2*pi*z))   
  return(f_value) 
}

# N Dimensiones
f_rastrigin <-function(x){
  A <- 10
  n <- length(x)
  z <- (A*n) + sum(x^2 - A*cos(2*pi*x))
  return(z)
}

Las gráficas de la función de Rastrigin en 2 y 3 dimensiones se muestran a continuación:

Gráfica de la función de Rastrigin 2D

Gráfica de la función de Rastrigin 2D

Gráfica de la función de Rastrigin 3D

Gráficas de la función de Rastrigin 3D

1.2 Método de descenso de gradiente

El método de optimización por descenso de gradiente es una técnica iterativa utilizada para encontrar el mínimo de una función. Consiste en actualizar sucesivamente los valores de las variables en la dirección opuesta al gradiente de la función, con el objetivo de reducir su valor en cada paso.

En nuestro caso, se utilizaron las siguientes variables para implementar el método: X₀, que representa la condición inicial del algoritmo; H, que define el tamaño de la ventana para el cálculo de la derivada numérica; y ETA, que corresponde a la tasa de aprendizaje, es decir, el tamaño del paso que se da en cada iteración hacia el mínimo.

1.2.1 Implementación en R de descenso de gradiente

# Implementación completa de optimizador multivariado por descenso de gradiente
optimizador_mult_numdev <- function(x0,fun,max_eval=100,h=0.01,eta=0.01){
  x <- matrix(NA,ncol =length(x0), nrow = max_eval)
  x[1,] <- x0
  for (i in 2:max_eval){
    num_grad_fun <- num_grad(x[i-1,],fun,h)
    H <- matriz_hessiana(x[i-1,],fun,h)
    cambio <- - eta*solve(H)%*%num_grad_fun
    x[i,] <- x[i-1,] + cambio
    cambio_opt <- sqrt(sum((x[i-1,]-x[i,])^2))
    if (cambio_opt<0.00001){
      break
    }
  }
  return(x[1:i,])
}

1.2.2 Optimización de la función de Rosenbrock en 2 dimensiones

sol_rosen2d <- optimizador_mult_numdev(f_rosenbrock, x0=c(-4,-4), h=0.005, eta=0.5)

La siguiente animación muestra el desempeño de la optimización a traves de su trayectoria:

Animación de la optimización de Rosenbrock 2D

Animación de la optimización de Rosenbrock 2D

1.2.3 Optimización de la función de Rosenbrock en 3 dimensiones

sol_rosen3d <- optimizador_mult_numdev(f_rosenbrock, x0=c(-4,-4,-4), h=0.005, eta=0.5)

En la siguiente tabla de muestran el comportamiento cada 10 iteraciones:

show_table("./Parte 1/Descenso de gradiente/rosenbrock_iter_grad.csv")

1.2.4 Optimización de la función de Rastrigin en 2 dimensiones

sol_ras2d <- optimizador_mult_numdev(f_rastrigin, x0=c(4.5,4.5), h=0.005, eta=2)

La siguiente animación muestra el desempeño de la optimización a traves de su trayectoria:

Animación de la optimización de Rastrigin 2D

Animación de la optimización de Rastrigin 2D

1.2.5 Optimización de la función de Rastrigin en 3 dimensiones

sol_ras3d <- optimizador_mult_numdev(f_rastrigin, x0=c(-4,-4,-4),  h=0.005, eta=2)

En la siguiente tabla de muestran el comportamiento cada 10 iteraciones:

show_table("./Parte 1/Descenso de gradiente/rastrigin_iter_grad.csv")

1.2.6 Conclusiones método de desenso del gradiente

El método de optimización por descenso de gradiente se caracteriza por su simplicidad y facilidad de implementación, lo que lo convierte en una herramienta útil para funciones con superficies suaves y relativamente simples. Sin embargo, al aplicarse a funciones altamente no convexas como la función de Rastrigin, este método presenta limitaciones significativas, ya que tiende a quedar atrapado en mínimos locales, dificultando la convergencia hacia una solución global óptima.

1.3 Método de evolución diferencial

La evolución diferencial es un algoritmo de optimización inspirado en la evolución biológica. Funciona manteniendo una población de soluciones, y mejorándolas generación tras generación mediante operaciones de mutación, recombinación y selección.

  • Mutación: se combinan 3 individuos distintos de la población para crear una variante.
  • Recombinación: se mezcla esa variante con el individuo actual.
  • Selección: se escoge el mejor entre el original y el nuevo.

Este proceso se repite varias veces hasta encontrar una solución óptima.

Las variables son: dim, que representa la cantidad de dimensiones o variables del problema; NP, que indica el tamaño de la población o número de soluciones en cada generación; F, que es el factor de mutación y determina la intensidad de la perturbación aplicada a las soluciones; CR, que corresponde a la tasa de recombinación y controla la probabilidad de intercambio de componentes entre vectores; gens, que define el número total de generaciones o iteraciones del algoritmo; y bounds, que establece los límites inferior y superior del espacio de búsqueda para cada dimensión.

1.3.1 Implementación en R de evolución diferencial

evolucion_diferencial <- function(fun_obj, dim = 2, NP = 30, F = 0.8, CR = 0.9,
                                  gens = 100, bounds = c(-5, 5)) {

  # Inicializar población
  poblacion <- matrix(runif(NP * dim, bounds[1], bounds[2]), ncol = dim)
  fitness <- apply(poblacion, 1, fun_obj)

  historial <- numeric(gens)
  mejores <- matrix(NA, gens, dim)

  for (gen in 1:gens) {
    for (i in 1:NP) {
      # Seleccionar 3 índices distintos
      indices <- sample(setdiff(1:NP, i), 3)
      x1 <- poblacion[indices[1], ]
      x2 <- poblacion[indices[2], ]
      x3 <- poblacion[indices[3], ]

      # Mutación
      mutado <- x1 + F * (x2 - x3)

      # Recombinar
      trial <- poblacion[i, ]
      jrand <- sample(1:dim, 1)
      for (j in 1:dim) {
        if (runif(1) < CR || j == jrand) {
          trial[j] <- mutado[j]
        }
      }

      # Selección
      if (fun_obj(trial) < fitness[i]) {
        poblacion[i, ] <- trial
        fitness[i] <- fun_obj(trial)
      }
    }

    # Guardar mejor resultado
    best_idx <- which.min(fitness)
    historial[gen] <- fitness[best_idx]
    mejores[gen, ] <- poblacion[best_idx, ]
  }

  list(mejor = poblacion[which.min(fitness), ],
       valor = min(fitness),
       historial = historial,
       trayectoria = mejores)
}

1.3.2 Optimización de la función de Rosenbrock en 2 dimensiones

En este gráfico se muestran las curvas de nivel de la función de Rosenbrock en dos dimensiones. Estas curvas representan líneas donde la función tiene igual valor, y el valle curvado al centro es donde está el mínimo global (en el punto (1,1)(1,1)).

La línea roja representa la trayectoria que siguió el algoritmo de evolución diferencial durante las iteraciones. Se puede observar cómo el enjambre de soluciones se fue acercando progresivamente hacia el mínimo, mejorando su posición en cada generación.

Animación de la optimización de Rosenbrock 2D

Animación de la optimización de Rosenbrock 2D

El resultado final obtenido fue: [1] 1.000000 1.000001 Valor mínimo encontrado: 1.91e-12

1.3.3 Optimización de la función de Rosenbrock en 3 dimensiones

En esta parte del informe se muestran los resultados numéricos para la optimización de las funciones en 3D. Dado que no se puede visualizar fácilmente en una gráfica 3D de trayectoria, se reportan las mejores posiciones y valores obtenido.

show_table("./Parte 1/Evolucion_Diferencial/rosenbrock_iter_evd.csv")

1.3.4 Optimización de la función de Rastrigin en 2 dimensiones

Aquí se grafican las curvas de nivel de la función de Rastrigin, que es multimodal, es decir, tiene muchos mínimos locales (patrón ondulado). La búsqueda es mucho más compleja que en Rosenbrock.

La línea azul muestra cómo la evolución diferencial se mueve por el espacio de búsqueda y logra escapar de los mínimos locales hasta acercarse al óptimo global, que se encuentra en (0,0)(0,0).

Animación de la optimización de Rastrigin 2D

Animación de la optimización de Rastrigin 2D

Resultado obtenido: [1] 2.176697e-06 -2.015785e-07 Valor mínimo: 9.48e-10

1.3.5 Optimización de la función de Rastrigin en 3 dimensiones

En este caso, el algoritmo encontró una solución cercana al mínimo global, aunque no exacta. Esto es esperable, ya que Rastrigin es mucho más difícil en 3D debido a la gran cantidad de mínimos locales.

show_table("./Parte 1/Evolucion_Diferencial/rastrigin_iter_evd.csv")

1.3.6 Conclusiones método de evolución diferencial

El algoritmo logró encontrar soluciones muy cercanas al mínimo global en las funciones de Rosenbrock y Rastrigin, tanto en 2D como en 3D.

En la función de Rosenbrock, se observó una convergencia estable y precisa, especialmente en dos dimensiones.

En la función de Rastrigin, que presenta muchos mínimos locales, el método evitó caer en estos y alcanzó buenos resultados.

El rendimiento se mantuvo sólido en tres dimensiones, aunque con una ligera pérdida de precisión en Rastrigin 3D debido a su complejidad.

Fue más robusto que el descenso por gradiente en funciones multimodales, ya que no necesita derivadas ni depende del punto inicial.

La evolución diferencial demostró ser un método confiable y efectivo para resolver problemas de optimización continua.

1.4 Método de optimización de partículas

El método de optimización por enjambre de partículas (PSO, por sus siglas en inglés) es un algoritmo inspirado en el comportamiento colectivo de animales como bandadas de aves o bancos de peces. Funciona mediante un conjunto de partículas (soluciones potenciales) que exploran el espacio de búsqueda moviéndose en función de su propia experiencia y la de sus vecinas. Cada partícula ajusta su posición y velocidad iterativamente para acercarse a la mejor solución conocida, guiada por su mejor posición histórica y la mejor posición global encontrada por el enjambre. Con el tiempo, las partículas tienden a converger hacia una solución óptima o cercana al óptimo.

1.4.1 Implementación en R de optimización de partículas

Se utiliza el paquete pos para implementar el método de la optimización de partículas. Adicionalmente, se implementa una función adicional para crear las animaciones del método de optimización.

1.4.2 Optimización de la función de Rosenbrock en 2 dimensiones

Animación de la optimización de Rosenbrock 2D con PSO

Animación de la optimización de Rosenbrock 2D con PSO

1.4.3 Optimización de la función de Rosenbrock en 3 dimensiones

1.4.4 Optimización de la función de Rastrigin en 2 dimensiones

Animación de la optimización de Rastrigin 2D con PSO

Animación de la optimización de Rastrigin 2D con PSO

1.4.5 Optimización de la función de Rastrigin en 3 dimensiones

# Parámetros a utilizar
n <- 3
lower_bounds <- -5
upped_bounds <- 5
# Ejecución del método
o_pso <- particle_swarm_optimization(n,f_rastrigin,lower_bounds,upper_bounds)

1.4.6 Conclusiones método de optimización de partículas

En el caso de la optimización maximizando las funciones, llegan muy rápido a una solución óptima (dentro de 10 iteraciones). Por otro lado, la optimización minimizando las funciones tardaba un poco más en llegar al óptimo, pero se acercaba mucho al mínimo global.

Estos resultados pueden deberse a la distribución de las partículas por el espacio de búsqueda, permitiendo una optimización más “abierta” a comparación con el método de descenso de gradiente.

1.5 Método de algoritmos evolutivos

Los algoritmos genéticos (AG) son técnicas de búsqueda heurística basadas en procesos de evolución natural​ . En un AG típico se define una función FITNESS que evalúa la calidad de cada solución candidata (individuo). A partir de una población inicial aleatoria, se iteran ciclos donde se seleccionan individuos más aptos, se combinan sus “genes” mediante cruces (crossover) y se introducen modificaciones aleatorias (mutaciones). Estos operadores evolucionan la población hacia regiones con mejor fitness.

Según (Scrucca, 2013), los GAs han sido exitosos en optimizar funciones continuas (diferenciables o no) y discretas. Entre los operadores genéticos clave se destacan:

  • Selección: elige individuos con mayor fitness para reproducirse, imitando la supervivencia del más apto.

  • Cruce (crossover): combina partes de dos soluciones parentales para generar descendencia, explorando nuevas regiones del espacio de búsqueda.

  • Mutación: altera aleatoriamente parte de un individuo (por ejemplo, cambiando un valor de su vector de variables) para introducir diversidad genética y evitar estancamiento en óptimos locales.

Los algoritmos genéticos (AG) son metaheurísticas inspiradas en procesos evolutivos biológicos, que han demostrado eficacia en la búsqueda global de óptimos en funciones complejas​jstatsoft.org Los AG simulan la selección natural, la recombinación (cruce) y la mutación para iterativamente mejorar un conjunto de soluciones candidatas (población). Estas técnicas estocásticas son adecuadas para funciones no lineales, discontinuas o con múltiples óptimos locales donde los métodos basados en derivadas pueden fallar. Para evaluar la robustez de los GA, se realizarán múltiples ejecuciones independientes y se analizará la dispersión del fitness resultante.

Adicionalmente, se definen algunas funciones para poder mostrar por medio de una animación el proceso de optimización para las funciones de Rosenbrock y de Rastrigin.

Analizaremos cada función en 2 y 3 dimensiones, graficando su paisaje antes de la optimización y luego aplicando un AG con múltiples corridas para evaluar la robustez de los resultados.

1.5.1 Implementación en R de algoritmos evolutivos

Se utiliza la función ga() del paquete GA. Para problemas de minimización se define la función de fitness como el negativo del valor objetivo, ya que ga() maximiza por defecto. Se especifican los límites de búsqueda.

Los resúmenes en cada ejecución reportan el mejor fitness encontrado (negativo) y la solución óptima en cada ejecución.

1.5.2 Optimización de la función de Rosenbrock en 2 dimensiones

Animación de optimización de Rastrigin 2D con Algoritmo Genético

Animación de la optimización de Rastrigin 2D con Algoritmo Genético

1.5.3 Optimización de la función de Rosenbrock en 3 dimensiones

1.5.4 Optimización de la función de Rastrigin en 2 dimensiones

1.5.5 Optimización de la función de Rastrigin en 3 dimensiones

1.5.6 Cálculo de estadísticas y análisis

Para evaluar la variabilidad del método estocástico, se repite cada caso al menos 30 veces con semillas distintas. Se registra el mejor valor de fitness (valorizado positivamente) obtenido en cada corrida. Se calcularán estadísticas (media y desviación estándar) del mejor valor de fitness obtenido en 30 ejecuciones independientes de cada caso y se resumirán en una tabla.

Con los vectores de mejores valores (best_vals_ros, etc.), se calculan la media y desviación estándar de cada conjunto de 30 resultados. Por ejemplo, mean_ros y sd_ros arriba y las demas, Para asi presentar los resultados.

Los resultados de las múltiples ejecuciones se resumen en la Tabla 1. Esta tabla muestra la media y desviación estándar del mejor valor de fitness (recordado que es el valor de la función objetivo en su mínimo global, típicamente cercano a 0) para cada combinación de función y dimensión. Se observa que para Rosenbrock 2D, la media del fitness mínimo es cercana a 0 con baja dispersión, reflejando que el GA normalmente encuentra el mínimo global (0) o cercano. Para Rastrigin 2D, la media también puede acercarse a 0, pero con mayor desviación estándar debido a los múltiples mínimos locales. En 3D ambos problemas suelen mostrar valores medios mayores (más alejados de 0) y mayor variabilidad, lo cual indica una mayor dificultad de búsqueda al aumentar la dimensionalidad.

Tabla 1. Estadísticas (media y desviación estándar) del fitness mínimo alcanzado en 30 corridas independientes para cada función y dimensión.

1.5.7 Conclusiones método de algoritmos evolutivos

Los resultados confirman que el algoritmo genético es capaz de aproximarse a los mínimos globales de ambos problemas en múltiples dimensiones. Como era de esperar, Rastrigin mostró mayor variabilidad en los valores de fitness debido a sus muchos mínimos locales, lo que implica que algunas ejecuciones del GA pueden quedarse atrapadas en óptimos locales alejados del global. En contraste, Rosenbrock (aunque es no convexa) tiende a un único valle principal; por ello, la mayoría de las corridas alcanzaron valores cercanos al mínimo global con menor dispersión. En general se observa que al aumentar la dimensión (de 2D a 3D) la tarea se complica y la media del fitness aumenta (peor óptimo encontrado), reflejando la maldición de la dimensionalidad. El uso de múltiples ejecuciones independientes es esencial para evaluar la robustez de los AG. Debido a su naturaleza estocástica, cada ejecución puede converger a soluciones distintas. Al analizar la media y desviación estándar de los fitness finales se obtiene una medida de fiabilidad del algoritmo: una baja desviación indica resultados consistentes. En la literatura sobre algoritmos genéticos se reconoce que en muchos casos una sola ejecución puede no ser representativa​jstatsoft.org. Aunque un análisis comparativo profundo (p.ej., usando poblaciones más grandes o múltiples corridas en paralelo) queda fuera del alcance de este documento, nuestros resultados ilustran este fenómeno. Este estudio es reproducible: todo el código R necesario está incluido, permitiendo a otros investigadores replicar los experimentos, variar parámetros del GA (tasa de cruce, mutación, tamaño de población, etc.) y comparar con otros algoritmos de optimización.:Conclusiones Se ha presentado una documentación completa de la optimización de las funciones de Rosenbrock y Rastrigin en 2D y 3D empleando algoritmos genéticos en R. Mediante visualizaciones 3D iniciales se ilustraron las características de cada función de prueba. Se implementó el paquete GA para resolver cada caso y se realizaron 30 ejecuciones independientes para evaluar la robustez. Los resultados muestran que el GA puede encontrar aproximaciones al mínimo global en ambos problemas, aunque la función Rastrigin (múltiples mínimos locales) presenta más variabilidad y dificultad, especialmente en 3D. # Conclusión General

Al terminar este trabajo, la verdad es que uno se da cuenta de lo poderosos y flexibles que pueden ser los algoritmos bioinspirados cuando se trata de resolver problemas de optimización, tanto numéricos como combinatorios. En la primera parte, experimentamos con funciones clásicas como Rosenbrock y Rastrigin usando métodos como el descenso de gradiente, PSO y algoritmos genéticos. Lo interesante fue ver cómo los métodos bioinspirados, inspirados en la naturaleza y el comportamiento colectivo, logran escapar de los mínimos locales y explorar el espacio de soluciones de una forma mucho más creativa y robusta que los métodos tradicionales. No solo es cuestión de encontrar el mínimo, sino de cómo se llega a él: la diversidad, la colaboración y la adaptación constante hacen la diferencia.

Pero la cosa no se quedó ahí. En la segunda parte, nos metimos de lleno en la optimización combinatoria, enfrentándonos al clásico problema del viajante usando colonia de hormigas. Aquí, la inspiración en el comportamiento de las hormigas para encontrar rutas óptimas en la naturaleza se tradujo en un algoritmo capaz de encontrar soluciones eficientes en problemas donde la cantidad de combinaciones posibles es abrumadora. Es impresionante ver cómo, a través de la cooperación y la comunicación indirecta (como las feromonas en el caso de las hormigas), el sistema encuentra caminos cada vez mejores, incluso cuando el espacio de búsqueda es gigantesco.

En resumen, este trabajo no solo nos permitió comparar y entender diferentes algoritmos, sino que también nos mostró la importancia de pensar “fuera de la caja” y de inspirarnos en la naturaleza para resolver problemas complejos. Los algoritmos bioinspirados no son una receta mágica, pero sí una herramienta poderosa y adaptable, capaz de enfrentar desafíos tanto en el mundo continuo como en el discreto. Además, trabajar con estos métodos fomenta la creatividad, el trabajo en equipo y una visión interdisciplinaria que, sin duda, es clave en la ciencia y la ingeniería de hoy.

Parte 2. Optimización combinatoria

2.1 Planteamiento del problema

El problema se puede plantear como una instancia particular del problema del viajero en ciencias de la computación. En la Tabla 2 se muestran las 13 ciudades principales de Colombia con su respectivas latitudes y longitudes.

Latitud Longitud
Bogotá 4.7110 -74.0721
Medellín 6.2442 -75.5812
Cali 3.4516 -76.5320
Barranquilla 10.9685 -74.7813
Cartagena 10.3910 -75.4794
Cúcuta 7.8941 -72.5078
Soledad 10.9264 -74.8055
Ibagué 4.4389 -75.2322
Bucaramanga 7.1193 -73.1227
Villavicencio 4.1420 -73.6298
Santa Marta 11.2408 -74.1990
Manizales 5.0703 -75.5138
Pereira 4.8143 -75.6946

Tabla 2. Ciudades principales de Colombia junto con su latencia y longitud.

El objetivo de este problema es optimizar con respecto a los costos y no a las distancias entre ciudades, por lo que se tienen que considerar los costos de combustible, de peajes y cuánto cobra el vendedor por hora de trabajo. Sin embargo, la distancia afectará al valor de todos estos costos, y por lo tanto hay que considerarla. Adicionalmente, todos estos costos están en función de la distancia en metros, por lo que es necesario realizar la conversión de latitud-longitud a coordenadas en metros. Para esto se usó la librería “sf” para realizar la conversión al sistema de coordenadas planas UTM, el cual representa los puntos del globo en metros.

Luego, se crea la matriz de distancias en metros entre cada ciudad.

Ahora, hay que considerar los costos para poder crear una matriz de costos para resolver el problema de optimización.

Con respecto al costo del combustible, este dependerá del vehículo que el vendedor utilizará para realizar las entregas. Para este problema, se utilizará un furgón DFSK C35, el cual tiene un consumo de combustible de 7.6 litros aproximado por cada 100 Km de recorrido, que se puede traducir en 0.000076 litros por cada 1 metro (DFSK, s.f., Especificaciones Furgon C35). Adicionalmente, se considera el precio promedio de la gasolina en Colombia que, segun (La República, 2025), tiene un valor de $15.827 pesos colombianos por galón, que se puede traducir en $4.022 pesos colombianos por litro aproximadamente.

gasto_litro_por_metro <- 0.000076
precio_gasolina_por_litro <- 4.022 
costos_combustible <- distancias * gasto_litro_por_metro * precio_gasolina_por_litro
rownames(costos_combustible) <- nombre_ciudades
colnames(costos_combustible) <- nombre_ciudades
print(costos_combustible)

Considerando el costo de los peajes, se usarán los datos de (Autofact, 2024) para calcular el valor promedio de cada peaje de las ciudades consideradas y se asumirá que el vendedor pagará el valor promedio del peaje de la ciudad de origen y de la ciudad de destino exactamente 1 vez cada que las recorra.

Por último, se debe de considerar el salario por horas promedio de un vendedor que haga dichos recorridos para entregar los pedidos. Adicional a ser vendedor, esta persona realizará las entregas y la conducción de la mercancía, por lo que también hay que considerar su pago como transportista. Dicho esto, se promediaron salarios de un transportista y un vendedor para poder determinar el salario final de la persona. Según (Talent.com, s.f., Salario medio para Transporte De Carga en Colombia 2025) y (Talent.com, s.f., Salario medio para Vendedor en Colombia 2025), un transportista gana en promedio $9.341 pesos colombianos la hora y un vendedor hace $7.144 la hora; por lo tanto, el salario a utilizar será el $8.242 pesos la hora.

Asumiendo que el vendedor conducirá a una velocidad media de 50 km/h al día, que se podrían traducir en 50000 m/h para facilitar cálculos, se procede a calcular el tiempo de viaje y, junto con esto, cuánto se le pagará al vendedor por cada viaje.

velocidad_media_metros_por_hora <- 50000
salario_vendedor_colombia <- 7144
salario_transportista_colombia <- 9341
salario_final <- (salario_vendedor_colombia + salario_transportista_colombia)/2
costos_vendedor <- distancias*(1/velocidad_media_metros_por_hora)*salario_final
rownames(costos_vendedor) <- nombre_ciudades
colnames(costos_vendedor) <- nombre_ciudades
costos_vendedor

Concluyendo, la matriz de costos simplemente sería el resultado de la suma de las anteriores matrices previamente definidas, y esta será la matriz que se utilizarán en los distintos algoritmos para encontrar la mejor ruta.

2.2 Implementación Método de Colonia de hormigas

A continuación, se implementa el método de colonia de hormigas para encontrar

# Número de ciudades
n_ciudades <- 13

# Función para normalizar la matriz de costos, ya que search_tour_ants
# funciona con valores normalizados.
# Se optó por usar normalización zscore.
normalize_zscore <- function(m) {
  (m - mean(m)) / sd(m)
}

# Normalización de matriz de costos
matriz_costos_normalizada <- normalize_zscore(matriz_costos)

# Ejecución del método de colonia de hormigas
recorrido_optimizado <- search_tour_ants(matriz_costos_normalizada, n_ciudades, K = 80, N = 40, log=TRUE)
print("MEJOR RECORRIDO: ")
print(recorrido_optimizado$tour)

Conclusión General

Al terminar este trabajo, la verdad es que uno se da cuenta de lo poderosos y flexibles que pueden ser los algoritmos bioinspirados cuando se trata de resolver problemas de optimización, tanto numéricos como combinatorios. En la primera parte, experimentamos con funciones clásicas como Rosenbrock y Rastrigin usando métodos como el descenso de gradiente, PSO y algoritmos genéticos. Lo interesante fue ver cómo los métodos bioinspirados, inspirados en la naturaleza y el comportamiento colectivo, logran escapar de los mínimos locales y explorar el espacio de soluciones de una forma mucho más creativa y robusta que los métodos tradicionales. No solo es cuestión de encontrar el mínimo, sino de cómo se llega a él: la diversidad, la colaboración y la adaptación constante hacen la diferencia.

Pero la cosa no se quedó ahí. En la segunda parte, nos metimos de lleno en la optimización combinatoria, enfrentándonos al clásico problema del viajante usando colonia de hormigas. Aquí, la inspiración en el comportamiento de las hormigas para encontrar rutas óptimas en la naturaleza se tradujo en un algoritmo capaz de encontrar soluciones eficientes en problemas donde la cantidad de combinaciones posibles es abrumadora. Es impresionante ver cómo, a través de la cooperación y la comunicación indirecta (como las feromonas en el caso de las hormigas), el sistema encuentra caminos cada vez mejores, incluso cuando el espacio de búsqueda es gigantesco.

En resumen, este trabajo no solo nos permitió comparar y entender diferentes algoritmos, sino que también nos mostró la importancia de pensar “fuera de la caja” y de inspirarnos en la naturaleza para resolver problemas complejos. Los algoritmos bioinspirados no son una receta mágica, pero sí una herramienta poderosa y adaptable, capaz de enfrentar desafíos tanto en el mundo continuo como en el discreto. Además, trabajar con estos métodos fomenta la creatividad, el trabajo en equipo y una visión interdisciplinaria que, sin duda, es clave en la ciencia y la ingeniería de hoy.

Reporte de contribución individual

- Leonardo Federico Corona Torres

  • Apoyo en redacción y realización de implementaciones de sección “Método de algoritmos evolutivos”.

  • Apoyo en redacción de implementaciones de graficación en Parte 2 del reporte.

  • Búsqueda e investigación de funciones de prueba a utilizar.

  • Apoyo en redacción y realización de implementaciones de sección “Selección e implementación de las funciones de prueba”.

- David Escobar Ruiz

  • Definición y escritura de estructura del reporte.

  • Apoyo en redacción y realización de implementaciones de sección “Selección e implementación de las funciones de prueba”.

  • Apoyo en redaccióny realización de implementaciones de sección “Método de optimización de partículas”.

  • Apoyo en redacción y realización de implementaciones de métodos, planteamiento y preprocesamiento de datos Parte 2 del reporte.

- Johan Sebastián Robles Rincón

  • Implementación y prueba del método de evolución diferencial en R para funciones de Rosenbrock y Rastrigin en 2D y 3D.

  • Análisis de resultados numéricos y gráficos.

  • Apoyo en redacción de sección del contenido técnico relacionado con este método de evolucion diferencial en el informe.

- Sebastian Soto Arcila

  • Apoyo en redacción y realización de implementaciones de sección “Método de optimización por descenso de gradiente”

  • Apoyo en redacción de sección “Selección e implementación de las funciones de prueba”.

Repositorio de GitHub del proyecto

https://github.com/druiz35/RNABI2025-1-Equipo3/

Bibliografía

Autofact. (2024). Peajes en Colombia: Conoce sus ubicaciones y precios 2024. https://www.autofact.com.co/blog/mi-carro/peajes/peajes-colombia-precios

DFSK. (s.f.). Especificaciones Furgon C35. Recuperado el 2 de mayo de 2025, de http://static.multiaviso.com/vehicle/specs/22-VRZC564XLBE6-dfsk-otros-modelos-2017-furgon-c35.pdf

La República. (2025). PRECIO DE LA GASOLINA. Recuperado el 2 de mayo de 2025, de https://www.larepublica.co/precio-de-la-gasolina

Molga, Smutnicki. (2005). Test functions for optimization needs. https://robertmarks.org/Classes/ENGR5358/Papers/functions.pdf

Talent.com. (s.f.). Salario medio para Transporte De Carga en Colombia 2025. Recuperado el 2 de mayo de 2025, de https://co.talent.com/salary?job=transporte+de+carga

Talent.com. (s.f.). Salario medio para Vendedor en Colombia 2025. Recuperado el 2 de mayo de 2025, de https://co.talent.com/salary?job=vendedor

Wikipedia. (s.f.). Test functions for optimization. Wikipedia. Recuperado el 2 de mayo de 2025, de https://en.wikipedia.org/wiki/Test_functions_for_optimization

Wikipedia. (s.f.). Rosenbrock function. Wikipedia. Recuperado el 2 de mayo de 2025, de https://en.wikipedia.org/wiki/Rosenbrock_

Wikipedia. (s.f.). Rastrigin function. Wikipedia. Recuperado el 2 de mayo de 2025, de https://en.wikipedia.org/wiki/Rastrigin_function

X.-S. Yang, Test problems in optimization, in: Engineering Optimization: An Introduction with Metaheuristic Applications (Eds Xin-She Yang), John Wiley & Sons, (2010)

LS0tDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQotLS0NCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IGZhbHNlDQogICAgY3NzOiBhcGFfc3R5bGUuY3NzDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IGZhbHNlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KYGBgez1odG1sfQ0KPCEtLQ0KICBOT1RFOiBFc3RlIGPDs2RpZ28gc2UgZWplY3V0YSwgcGVybyBubyBzZSBtdWVzdHJhIG5pIGVsIGPDs2RpZ28gbmkgbGEgc2FsaWRhDQotLT4NCmBgYA0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQojIEVzdGEgZnVuY2nDs24gbXVlc3RyYSBsYSB0YWJsZSBndWFkYWRhIGVuIHVuIENTVg0KIyAgIHJ1dGE6IGRpcmVjY2nDs24gZGVsIGNzdg0Kc2hvd190YWJsZSA8LSBmdW5jdGlvbihydXRhKSB7DQogICMgTGVlciBlbCBDU1YNCiAgdGFibGFfY29tcGxldGEgPC0gcmVhZC5jc3YocnV0YSkNCiAgDQogICMgU2VsZWNjaW9uYXIgY2FkYSAxMCBmaWxhcyAoMSwgMTEsIDIxLCAuLi4pDQogIGZpbGFzX2NhZGFfMTAgPC0gc2VxKDAsIG5yb3codGFibGFfY29tcGxldGEpLCBieSA9IDEwKQ0KICB0YWJsYV9jYWRhXzEwIDwtIHRhYmxhX2NvbXBsZXRhW2ZpbGFzX2NhZGFfMTAsIF0NCiAgcHJpbnQodGFibGFfY2FkYV8xMCkNCn0NCmBgYA0KDQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7IGNvbG9yOiBibGFjazsgbWFyZ2luLXRvcDogNjBweDsifQ0KPGgxPlJFUE9SVEUgVFJBQkFKTyAxOiBTT0xVQ0nDk04gREUgUFJPQkxFTUFTIERFIE9QVElNSVpBQ0nDk04gQ09OIE3DiVRPRE9TIEhFVVLDjVNUSUNPUzwvaDE+DQoNCjxoMj5SRURFUyBORVVST05BTEVTIFkgQUxHT1JJVE1PUyBCSU9JTlNQSVJBRE9TPC9oMj4NCg0KPGJyPjxicj48YnI+DQoNCjxwPjxzdHJvbmc+UHJlc2VudGFkbyBwb3I6PC9zdHJvbmc+PC9wPg0KDQo8cD5MZW9uYXJkbyBGZWRlcmljbyBDb3JvbmEgVG9ycmVzPGJyPiBEYXZpZCBFc2NvYmFyIFJ1aXo8YnI+IGBKb2hhbiBTZWJhc3RpYW4gUm9ibGVzIFJpbmPDs248YnI+YHs9aHRtbH1TZWJhc3Rpw6FuIFNvdG8gQXJjaWxhPC9wPg0KDQo8YnI+PGJyPg0KDQo8cD48c3Ryb25nPlByb2Zlc29yOjwvc3Ryb25nPiBKdWFuIERhdmlkIE9zcGluYSBBcmFuZ288L3A+DQoNCjxwPjxzdHJvbmc+TW9uaXRvcjo8L3N0cm9uZz4gQW5kcsOpcyBNYXVyaWNpbyBaYXBhdGEgUmluY8OzbjwvcD4NCg0KPGJyPiA8aW1nIHNyYz0ibG9nb191bmFsLnBuZyIgYWx0PSJVbml2ZXJzaXR5IExvZ28iIHdpZHRoPSIxMDBweCIvPiA8YnI+PGJyPg0KDQo8cD5Vbml2ZXJzaWRhZCBOYWNpb25hbCBkZSBDb2xvbWJpYTxicj4gRmFjdWx0YWQgZGUgTWluYXM8YnI+IEluZ2VuaWVyw61hIGRlIFNpc3RlbWFzIGUgSW5mb3Jtw6F0aWNhPC9wPg0KDQo8cD48c3Ryb25nPmByIGZvcm1hdChTeXMuRGF0ZSgpLCAiJWQgZGUgJUIgZGUgJVkiKWA8L3N0cm9uZz48L3A+DQo6OjoNCg0KYGBgez1odG1sfQ0KPCEtLQ0KICBOT1RFOiBMb3MgdGlwb3MgZGUgc2VsZWN0b3JlcyBzb246DQogICAgLSBDb21lbnphZG9zIGVuICJpdSIgcGFyYSBpdGVtcyBkZSBsaXN0YXMgbm8gb3JkZW5hZGFzDQogICAgLSBDb21lbnphZG9zIGVuICJpbyIgcGFyYSBpdGVtcyBkZSBsaXN0YXMgb3JkZW5hZGFzDQotLT4NCmBgYA0KIyBDb250ZW5pZG9zDQoNCi0gICBbSW50cm9kdWNjacOzbl0oI2l1MS4pDQotICAgW01ldG9kb2xvZ8OtYV0oI2l1Mi4pDQotICAgWzEuIE9wdGltaXphY2nDs24gbnVtw6lyaWNhXSgjaW8xLikNCi0gICBbMS4xLiBTZWxlY2Npw7NuIGUgaW1wbGVtZW50YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZGUgcHJ1ZWJhXSgjaW8xLjEuKQ0KLSAgIFsxLjEuMS4gQnJldmUgZXhwbGljYWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZGUgcHJ1ZWJhIHBhcmEgcHJvYmxlbWFzIGRlIG9wdGltaXphY2nDs25dKCNpbzEuMS4xLikNCi0gICBbMS4xLjIuIEltcGxlbWVudGFjacOzbiBkZSBmdW5jaW9uZXMgZGUgZ3JhZmljYWNpw7NuXSgjaW8xLjEuMikNCi0gICBbMS4xLjMuIEZ1bmNpw7NuIGRlIFJvc2VuYnJvY2tdKCNpbzEuMS4zLikNCi0gICBbMS4xLjQuIEZ1bmNpw7NuIGRlIFJhc3RyaWdpbl0oI2lvMS4xLjQuKQ0KLSAgIFsxLjIuIE3DqXRvZG8gZGUgZGVzY2Vuc28gZGUgZ3JhZGllbnRlXSgjaW8xLjIuKQ0KLSAgIFsxLjIuMS4gSW1wbGVtZW50YWNpw7NuIGVuIFIgZGUgZGVzY2Vuc28gcG9yIGdyYWRpZW50ZV0oI2lvMS4yLjEuKQ0KLSAgIFsxLjIuMi4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXNdKCNpbzEuMi4yLikNCi0gICBbMS4yLjMuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjIuMy4pDQotICAgWzEuMi40LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIGRpbWVuc2lvbmVzXSgjaW8xLjIuNC4pDQotICAgWzEuMi41LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjIuNS4pDQotICAgWzEuMi42LiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBkZXNlbnNvIGRlbCBncmFkaWVudGVdKCNpbzEuMi42LikNCi0gICBbMS4zLiBNw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWxdKCNpbzEuMy4pDQotICAgWzEuMy4xLiBJbXBsZW1lbnRhY2nDs24gZW4gUiBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsXSgjaW8xLjMuMS4pDQotICAgWzEuMy4yLiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMiBkaW1lbnNpb25lc10oI2lvMS4zLjIuKQ0KLSAgIFsxLjMuMy4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDMgZGltZW5zaW9uZXNdKCNpbzEuMy4zLikNCi0gICBbMS4zLjQuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXNdKCNpbzEuMy40LikNCi0gICBbMS4zLjUuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDMgZGltZW5zaW9uZXNdKCNpbzEuMy41LikNCi0gICBbMS4zLjYuIENvbmNsdXNpb25lcyBtw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWxdKCNpbzEuMy42LikNCi0gICBbMS40LiBNw6l0b2RvIGRlIG9wdGltaXphY2nDs24gZGUgcGFydMOtY3VsYXNdKCNpbzEuNC4pDQotICAgWzEuNC4xLiBJbXBsZW1lbnRhY2nDs24gZW4gUiBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzXSgjaW8xLjQuMS4pDQotICAgWzEuNC4yLiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMiBkaW1lbnNpb25lc10oI2lvMS40LjIuKQ0KLSAgIFsxLjQuMy4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDMgZGltZW5zaW9uZXNdKCNpbzEuNC4zLikNCi0gICBbMS40LjQuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXNdKCNpbzEuNC40LikNCi0gICBbMS40LjUuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDMgZGltZW5zaW9uZXNdKCNpbzEuNC41LikNCi0gICBbMS40LjYuIENvbmNsdXNpb25lcyBtw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWxdKCNpbzEuNC42LikNCi0gICBbMS41LiBNw6l0b2RvIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvc10oI2lvMS41LikNCi0gICBbMS41LjEuIEltcGxlbWVudGFjacOzbiBlbiBSIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvc10oI2lvMS41LjEuKQ0KLSAgIFsxLjUuMi4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXNdKCNpbzEuNS4yLikNCi0gICBbMS41LjMuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjUuMy4pDQotICAgWzEuNS40LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIGRpbWVuc2lvbmVzXSgjaW8xLjUuNC4pDQotICAgWzEuNS41LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjUuNS4pDQotICAgWzEuNS42LiBDw6FsY3VsbyBkZSBlc3RhZMOtc3RpY2FzIHkgYW7DoWxpc2lzXSgjaW8xLjUuNi4pDQotICAgWzEuNS43LiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3NdKCNpbzEuNS43LikNCi0gICBbMi4gT3B0aW1pemFjacOzbiBjb21iaW5hdG9yaWFdKCNpbzIuKQ0KLSAgIFsyLjEuIFBsYW50ZWFtaWVudG8gZGVsIHByb2JsZW1hXSgjaW8yLjEuKQ0KLSAgIFsyLjIuIEltcGxlbWVudGFjacOzbiBNw6l0b2RvIGRlIENvbG9uaWEgZGUgaG9ybWlnYXNdKCNpbzIuMi4pDQotICAgW0NvbmNsdXNpw7NuIEdlbmVyYWxdKCNpbzUuKQ0KLSAgIFtSZXBvcnRlIGRlIGNvbnRyaWJ1Y2nDs24gaW5kaXZpZHVhbF0oI2l1My4pDQotICAgW1JlcG9zaXRvcmlvIGRlIEdpdEh1YiBkZWwgcHJveWVjdG9dKCNpdTQuKQ0KLSAgIFtCaWJsaW9ncmFmw61hXSgjaXU1LikNCg0KPGEgbmFtZT0iaXUxLiI+PC9hPg0KDQojIEludHJvZHVjY2nDs24NCg0KRWwgcHJlc2VudGUgdHJhYmFqbyB0cmF0YSBhbGd1bm9zIGRlIGxvcyBtw6l0b2RvcyBtw6FzIHJlbGV2YW50ZXMgZGUgb3B0aW1pemFjacOzbiBudW3DqXJpY2EgYmFzYWRhIGVuIG1hbmlwdWxhY2lvbmVzIGRlbCBncmFkaWVudGUgZGUgdW5hIGZ1bmNpw7NuIG9iamV0aXZvIChmdW5jacOzbiBhIG9wdGltaXphcikgeSB0YW1iacOpbiBhbGdvcml0bW9zIGhldXLDrXN0aWNvcyBiYXNhZG9zIGVuIGVsIGNvbXBvcnRhbWllbnRvIGRlIGxhIG5hdHVyYWxlemEsIGNvbW8gbG8gc29uIGxvcyBhbGdvcml0bW9zIGV2b2x1dGl2b3MuIFRvZG9zIGVzdG9zIG3DqXRvZG9zIHB1ZWRlbiBsbGVnYXIgYSBzZXIgw7p0aWxlcyBlbiBkaXN0aW50b3MgY29udGV4dG9zIGVuIGxvcyBxdWUgc2UgYnVzY2Egb3B0aW1pemFyIHVuYSBmdW5jacOzbiBwYXJhIGFsZ8O6biBmaW4sIGNvbW8gZW5jb250cmFyIGxhIG1lam9yIHJ1dGEgZW50cmUgY2l1ZGFkZXMgbyBvcHRpbWl6YXIgdW5hIGZ1bmNpw7NuIGRlIHDDqXJkaWRhIGVuIHVuIGNvbnRleHRvIGRlIGFwcmVuZGl6YWplIGRlIG3DoXF1aW5hLiBDYWRhIG3DqXRvZG8gdGllbmUgcGFydGljdWxhcmlkYWRlcyBpbnRlcmVzYW50ZXMgcXVlIHNlIHZhbiBhIGV4cGxvcmFyIGRlIG1hbmVyYSBnZW5lcmFsIHBvciBtZWRpbyBkZSB1bmEgYnJldmUgaW1wbGVtZW50YWNpw7NuIHkgZWplY3VjacOzbiBjb24gZG9zIGZ1bmNpb25lcyBtdXkgdXRpbGl6YWRhcyBwYXJhIHByb2JhciBhbGdvcml0bW9zIGRlIG9wdGltaXphY2nDs246IGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgeSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4uDQoNCjxhIG5hbWU9Iml1Mi4iPjwvYT4NCg0KIyBNZXRvZG9sb2fDrWENCg0KUGFyYSBpbXBsZW1lbnRhciB5IGRvY3VtZW50YXIgbGEgb3B0aW1pemFjacOzbiBzZSBlbXBsZWEgUiBNYXJrZG93biwgY29tYmluYW5kbyBjw7NkaWdvIFIgeSB0ZXh0byBleHBsaWNhdGl2by4gU2UgdXRpbGl6YW4gbGlicmVyw61hcyBwYXJhIHJlbmRlcml6YXIgZ3LDoWZpY29zIHkgYW5pbWFjaW9uZXMsIGxpYnJlcsOtYXMgcGFyYSBpbXBsZW1lbnRhciBsb3MgbcOpdG9kb3MgaGV1csOtc3RpY29zIHkgbGlicmVyw61hcyBwYXJhIG1hbmlwdWxhciBsb3MgZGF0b3MuIFBhcmEgbG9zIGNhc29zIDNEICh0cmVzIHZhcmlhYmxlcykgZXMgZGlmw61jaWwgdmlzdWFsaXphciBkaXJlY3RhbWVudGUgbGEgZnVuY2nDs24gZGUgMyBkaW1lbnNpb25lcyAoZXNwYWNpbyBkZSA0IHZhcmlhYmxlcyksIHBvciBsbyBxdWUgc2UgbW9zdHJhcsOhbiDDum5pY2FtZW50ZSBsb3MgcHVudG9zIMOzcHRpbW9zIGFsY2FuemFkb3MuDQoNCjxhIG5hbWU9ImlvMS4iPjwvYT4NCg0KIyBQYXJ0ZSAxLiBPcHRpbWl6YWNpw7NuIG51bcOpcmljYQ0KDQo8YSBuYW1lPSJpbzEuMS4iPjwvYT4NCg0KIyMgMS4xIFNlbGVjY2nDs24gZSBpbXBsZW1lbnRhY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmENCg0KUGFyYSBvYnNlcnZhciBlbCBjb21wb3J0YW1pZW50byBkZSBjYWRhIHVubyBkZSBsb3MgbcOpdG9kb3MgZGUgb3B0aW1pemFjacOzbiBpbXBsZW1lbnRhZG9zLCBzZSBvcHTDsyBwb3IgbGEgc2VsZWNjacOzbiBkZSBkb3MgZnVuY2lvbmVzIGRlIHBydWViYSBlc3TDoW5kYXIgcGFyYSBldmFsdWFyIGFsZ29yaXRtb3MgZGUgb3B0aW1pemFjacOzbjogRnVuY2nDs24gZGUgUm9zZW5icm9jayB5IEZ1bmNpw7NuIGRlIFJhc3RyaWdpbi4gRGViaWRvIGEgc3UgY29tcGxlamlkYWQsIGFtYmFzIGZ1bmNpb25lcyBzb24gaW5kaWNhZG9yZXMgw7p0aWxlcyBwYXJhIGNvbXBhcmFyIGxhIGVmaWNhY2lhIGRlIG9wdGltaXphZG9yZXMgY29tbyBsb3MgQUcuDQoNClByZXZpbyBhIGxhIGltcGxlbWVudGFjacOzbiBkZSBsb3MgYWxnb3JpdG1vcyBlbiBlbCBsZW5ndWFqZSBSIHkgcHJldmlvIGEgbGEgcmVjb3BpbGFjacOzbiBkZSByZXN1bHRhZG9zIHkgbGEgZGVyaXZhY2nDs24gZGUgY29uY2x1c2lvbmVzIGEgcGFydGlyIGRlIGVzdG9zLCBlbCBlcXVpcG8gZGVjaWRpw7MgcmVhbGl6YXIgdW5hIGJyZXZlIGludmVzdGlnYWNpw7NuIGdlbmVyYWwgZGUgbG8gcXVlIHNvbiBsYXMgZnVuY2lvbmVzIGRlIHBydWViYSBwYXJhIHByb2JsZW1hcyBkZSBvcHRpbWl6YWNpw7NuLiBMYSBpbnZlc3RpZ2FjacOzbiBzZSByZWFsaXrDsyBkZSB0YWwgZm9ybWEgcXVlLCB1bmEgdmV6IGNvbmNsdcOtZGEsIHNlIHB1ZGllcmFuIGNvbXByZW5kZXIgbG9zIGNvbmNlcHRvcyBoYXN0YSBlbCBwdW50byBkZSBlc3RhciBlbiBsYXMgY2FwYWNpZGFkZXMgcmVzcG9uZGVyIGxhcyBzaWd1aWVudGVzIHByZWd1bnRhcyBpbXBsw61jaXRhbWVudGUgZW4gdW5hIGJyZXZlIHNlY2Npw7NuIGRlIGVzdGUgdHJhYmFqbzoNCg0KLSAgIMK/UXXDqSBlcyB1bmEgZnVuY2nDs24gZGUgcHJ1ZWJhIGVuIG9wdGltaXphY2nDs24/DQoNCi0gICDCv1BhcmEgcXXDqSBzZSB1dGlsaXphIHVuYSBmdW5jacOzbiBkZSBwcnVlYmEgZW4gb3B0aW1pemFjacOzbj8NCg0KLSAgIMK/Q8OzbW8gc2UgcHVlZGVuIGNsYXNpZmljYXIgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmE/DQoNCi0gICDCv0N1w6FsZXMgc29uIGFsZ3VuYXMgZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmEgbcOhcyB1dGlsaXphZGFzPw0KDQpBIGNvbnRpbnVhY2nDs24gc2UgcHJlc2VudGEgZGljaGEgc2VjY2nDs24gcGFyYSBsdWVnbyBjb250aW51YXIgY29uIGVsIGVzdHVkaW8gbcOhcyBkZXRhbGxhZG8gZGUgbGFzIGZ1bmNpb25lcyBlc2NvZ2lkYXMuDQoNCjxhIG5hbWU9ImlvMS4xLjEuIj48L2E+DQoNCiMjIyAxLjEuMSBCcmV2ZSBleHBsaWNhY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmEgcGFyYSBwcm9ibGVtYXMgZGUgb3B0aW1pemFjacOzbg0KDQpTZWfDum4gKFlhbmcsIDIwMTApLCB1bmEgZnVuY2nDs24gZGUgcHJ1ZWJhIGVzIHVuYSBmdW5jacOzbiBjb24gdW5hcyBwcm9waWVkYWRlcyBlc3BlY2lhbGVzIHF1ZSBwZXJtaXRlIHByb2JhciBzaSBlbCByZW5kaW1pZW50byBkZSB1biBtw6l0b2RvIGRlIG9wdGltaXphY2nDs24gaW1wbGVtZW50YWRvIGVzIGFjZXB0YWJsZSBiYWpvIGxhcyBjb25kaWNpb25lcyBlc3BlY2lhbGVzIHF1ZSBpbXBvbmUgbGEgZnVuY2nDs24gZGUgcHJ1ZWJhLsKgDQoNCkVzdG8gZXMgZXNwZWNpYWxtZW50ZSDDunRpbCBwYXJhIHZlcmlmaWNhciBxdWUgZWwgbcOpdG9kbyBzZWEgZWZpY2llbnRlIGJham8gZGlzdGludGFzIGNvbmRpY2lvbmVzIGVuIGxhcyBxdWUgc2UgZXNwZXJhIHF1ZSBzZSBpbXBsZW1lbnRlLCBjb21vIHBvciBlamVtcGxvLCBjYXNvcyBlbiBsb3MgcXVlIGxhIGZ1bmNpw7NuIHRpZW5lIG3Dumx0aXBsZXMgbcOtbmltb3MgeS9vIG3DoXhpbW9zIGxvY2FsZXMuDQoNClNlZ8O6biAoTW9sZ2EsIDIwMDUpLCBsYXMgZnVuY2lvbmVzIGRlIHBydWViYSBzZSBwdWVkZW4gdWJpY2FyIGVuIHVuYSBkZSBsYXMgc2lndWllbnRlcyBjbGFzZXMsIHRvZGFzIHNpZW5kbyBmdW5jaW9uZXMgY29udGludWFzOg0KDQotICAgKipDbGFzZSAxOioqIFVuaW1vZGFsLCBjb252ZXhhLCBtdWx0aWRpbWVuc2lvbmFsLg0KLSAgICoqQ2xhc2UgMjoqKiBNdWx0aW1vZGFsLCBkb3MgZGltZW5zaW9uZXMgY29uIHVuIG7Dum1lcm8gcGVxdWXDsW8gZGUgZXh0cmVtb3MgbG9jYWxlcy4NCi0gICAqKkNsYXNlIDMqKjogTXVsdGltb2RhbCwgZG9zIGRpbWVuc2lvbmVzIGNvbiB1biBncmFuIG7Dum1lcm8gZGUgZXh0cmVtb3MgbG9jYWxlcy4NCi0gICAqKkNsYXNlIDQ6KiogTXVsdGltb2RhbCwgbXVsdGlkaW1lbnNpb25hbCwgY29uIHVuIG7Dum1lcm8gYW1wbGlvIGRlIGV4dHJlbW9zIGxvY2FsZXMuDQoNCkVuIGVsIGNhc28gZGUgbGFzIGZ1bmNpb25lcyBlbGVnaWRhcywgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBzZSBjbGFzaWZpY2Fyw61hIGNvbW8gQ2xhc2UgMyB5IGxhIGRlIFJhc3RyaWdpbiBjb21vIENsYXNlIDIuDQoNCkNvbW8gZWplbXBsbywgZW4gbGEgRmlndXJhIDEgc2UgcHJlc2VudGFuIGFsZ3VuYXMgZnVuY2lvbmVzIGRlIHBydWViYSBxdWUgbm8gc2UgZWxpZ2llcm9uIHBhcmEgZXN0ZSB0cmFiYWpvLCBwZXJvIHF1ZSBzb24gaWd1YWwgZGUgcmVsZXZhbnRlcywgaW1wb3J0YW50ZXMgeSBjb23Dum5tZW50ZSB1dGlsaXphZGFzIGVuIGxhIHByw6FjdGljYSAoTW9sZ2EsIDIwMDUpOg0KDQotICAgRnVuY2nDs24gZGUgRGUgSm9uZyAoQ2xhc2UgMSkuDQoNCi0gICBGdW5jacOzbiBkZSBHcmlld2FuZ2sgKENsYXNlIDIpLg0KDQotICAgRnVuY2nDs24gZGUgTGFuZ2VybWFubiAoQ2xhc2UgMykuDQoNCi0gICBGdW5jacOzbiBkZSBBY2tsZXkgKENsYXNlIDQpLg0KDQo8YSBuYW1lPSJpbzEuMS4yLiI+PC9hPg0KDQojIyMgMS4xLjIgRnVuY2nDs24gZGUgUm9zZW5icm9jaw0KDQpFcyB1bmEgZnVuY2nDs24gbm8gY29udmV4YSBpbnRyb2R1Y2lkYSBwb3IgUm9zZW5icm9jayBlbiAxOTYw4oCLIChXaWtpcGVkaWEsIHMuZi4sIFJvc2VuYnJvY2sgZnVuY3Rpb24pLiBTdSBwYWlzYWplIGZvcm1hIHVuIHZhbGxlIGN1cnZvIGVzdHJlY2hvIHF1ZSBkaWZpY3VsdGEgbGEgY29udmVyZ2VuY2lhIGhhY2lhIGVsIG3DrW5pbW8uDQoNCkRlZmluaWNpw7NuIGVuIG4gZGltZW5zaW9uZXM6DQoNCiRmKFgpID0gXHN1bV97aT0xfV57bi0xfTEwMChYX3tpKzF9LVhfaV4yKV4yICsgKDEtWF9pKV4yJCAoMSkNCg0KRGVmaW5pY2nDs24gZW4gMkQ6DQoNCiRmKHgseSk9IDEwMCh5LXheMileMiArICgxLXgpXjIkDQoNCkRlZmluaWNpw7NuIGVuIDNEOg0KDQokZih4LHkseik9MTAwWyh5LXheMileMisoei15XjIpXjJdICsgKDEteCleMiArICgxLXkpXjIkDQoNCkFsZ3VuYXMgY2FyYWN0ZXLDrXN0aWNhcyB5IHByb3BpZWRhZGVzIGltcG9ydGFudGVzwqAgc29uIGxhcyBzaWd1aWVudGVzOg0KDQotICAgTcOtbmltbyBnbG9iYWw6DQoNCiAgICAkeF8xLC4uLix4X24gPTEsIGYoeF8xLC4uLix4X24pID0gMCQNCg0KLSAgIERvbWluaW8gZGUgYsO6c3F1ZWRhOsKgDQoNCiAgICAkLVxpbmZ0eSBcbGVxIFhfaSBcbGVxIFxpbmZ0eSQNCg0KICAgICQxIFxsZXEgaSBcbGVxIG4kDQoNCi0gICBDb25vY2lkYSB0YW1iacOpbiBjb21vIGxhIGZ1bmNpw7NuIGJhbmFuYSBkZSBSb3NlbmJyb2NrLg0KDQotICAgVGllbmUgZm9ybWEgZGUgdmFsbGUsIGVsIGN1YWwgZXMgdHJpdmlhbCBlbmNvbnRyYXJsby4gU2luIGVtYmFyZ28sIGxhIGNvbnZlcmdlbmNpYSBhbCBtw61uaW1vIGdsb2JhbCBlcyBkaWbDrWNpbC4NCg0KRXN0YXMgc29uIGFsZ3VuYXMgaGlww7N0ZXNpcyB5IGV4cGVjdGF0aXZhcyBxdWUgc2UgdHV2aWVyb24gcGFyYSBlbCByZW5kaW1pZW50byBkZSBjYWRhIG3DqXRvZG8gaW1wbGVtZW50YWRvIGNvbiBlc3RhIGZ1bmNpw7NuOg0KDQotICAgKipNw6l0b2RvIGRlIGRlc2NlbnNvIGRlIGdyYWRpZW50ZToqKg0KDQogICAgLSAgIFNpIHNlIHViaWNhIGVsIHB1bnRvIGluaWNpYWwgc29icmUgbGFzIHJlY3RhcyB0YW5nZW50ZXMgY29uIG1heW9yIGdyYWRpZW50ZSBhIGxhIGZ1bmNpw7NuIGVudG9uY2VzIGVsIG3DqXRvZG8gbGxlZ2Fyw6EgbcOhcyByw6FwaWRvIGEgdW4gbcOtbmltby4NCiAgICAtICAgUG9yIGVsIGNvbnRyYXJpbywgc2kgbGEgcmVjdGEgdGFuZ2VudGUgdGllbmUgdW5hIGdyYWRpZW50ZSBtw6FzIGNlcmNhbmEgYSBjZXJvLCBlbCBtw6l0b2RvIGxsZWdhcsOhIG3DoXMgbGVudGFtZW50ZSwgZXMgZGVjaXIsIHJlcXVlcmlyw6EgZGUgbcOhcyBpdGVyYWNpb25lcyBwYXJhIGxsZWdhciBhbCBwdW50byBtw61uaW1vLg0KDQotICAgKipNw6l0b2RvIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvczoqKg0KDQogICAgLSAgIExvcyBjcml0ZXJpb3MgcGFyYSBzZWxlY2Npb25hciBsb3MgaW5kaXZpZHVvcyBhIHJlcHJvZHVjaXIgdmEgYSBzZXIgbXV5IGltcG9ydGFudGUgcGFyYSBlbCByZW5kaW1pZW50byBkZWwgbcOpdG9kby4NCg0KLSAgICoqTcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzOioqDQoNCiAgICAtICAgRXN0ZSBtw6l0b2RvIG5vIHZhIGEgdGVuZXIgbXVjaGFzIGRpZmljdWx0YWRlcyBwYXJhIGVuY29udHJhciBlbCBwdW50byDDs3B0aW1vIGVzIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2suDQogICAgLSAgIEVsIGNyaXRlcmlvIHBhcmEgcGFyYXIgbGFzIGl0ZXJhY2lvbmVzIG5vIHZhIGEgY2FtYmlhciBtdWNobyBsb3MgcmVzdWx0YWRvcyBlbiBlc3RlIGNhc28uDQoNCi0gICAqKk3DqXRvZG8gZGUgZXZvbHVjacOzbiBkaWZlcmVuY2lhbDoqKg0KDQogICAgLSAgIFNlIGNvbXBvcnRhIHNpbWlsYXIgYSBsb3MgbcOpdG9kb3MgZXZvbHV0aXZvcyBlbiAyIGRpbWVuc2lvbmVzLg0KDQpMYSBpbXBsZW1lbnRhY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAyLCAzIHkgTiBkaW1lbnNpb25lcyBzZSBtdWVzdHJhIGEgY29udGludWFjacOzbjoNCg0KYGBge3J9DQojIDIgRGltZW5zaW9uZXMNCmZfcm9zZW5icm9ja18yZCA8LSBmdW5jdGlvbih4LCB5KSB7ICAgDQogIGZfdmFsdWUgPC0gMTAwKih5LSh4XjIpKV4yICsgKCgxLXgpXjIpICAgDQogIHJldHVybihmX3ZhbHVlKSANCn0gIA0KDQojIDMgRGltZW5zaW9uZXMNCmZfcm9zZW5icm9ja18zZCA8LSBmdW5jdGlvbih4LCB5LCB6KSB7ICAgDQogIGZfdmFsdWUgPC0gMTAwKigoeS14XjIpXjIgKyAoei15XjIpXjIpICsgKDEteCleMiArICgxLXkpXjIgICANCiAgcmV0dXJuKGZfdmFsdWUpIA0KfQ0KDQojIE4gRGltZW5zaW9uZXMNCmZfcm9zZW5icm9jayA8LSBmdW5jdGlvbih4KXsNCiAgeF8xIDwtIHRhaWwoeCwgLTEpDQogIHggPC0gaGVhZCh4LCAtMSkNCiAgeiA8LSBzdW0oKDEwMCooKHhfMS0oeF4yKSleMikpKygoMS14KV4yKSkNCiAgcmV0dXJuKHopDQp9DQpgYGANCg0KTGFzIGdyw6FmaWNhcyBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgeSAzIGRpbWVuc2lvbmVzIHNlIG11ZXN0cmFuIGEgY29udGludWFjacOzbjoNCg0KOjo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0iaW1hZ2VzXGdyYXBoaWNzXHJvc2VuYnJvY2tfMmRfZ3JhZmljYS5wbmciIGFsdD0iR3LDoWZpY2EgZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayAyRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgMkQNCjo6Og0KOjo6DQoNCjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsifQ0KPGltZyBzcmM9ImltYWdlc1xncmFwaGljc1xyb3NlbmJyb2NrXzNkX2dyYWZpY2EucG5nIiBhbHQ9Ikdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgM0QiIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpHcsOhZmljYSBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIDNEDQo6OjoNCjo6Og0KDQo8YSBuYW1lPSJpbzEuMS4zLiI+PC9hPg0KDQojIyMgMS4xLjMgRnVuY2nDs24gZGUgUmFzdHJpZ2luDQoNCkxhIGZ1bmNpw7NuIFJhc3RyaWdpbiAoMTk3NCkgZXMgdW5hIGZ1bmNpw7NuIG5vIGNvbnZleGEgeSBhbHRhbWVudGUgbXVsdGltb2RhbCwgY29uIG51bWVyb3NvcyBtw61uaW1vcyBsb2NhbGVzLCBsbyBxdWUgbGEgaGFjZSBkaWbDrWNpbCBkZSBvcHRpbWl6YXLigIsgKFdpa2lwZWRpYSwgcy5mLiwgUmFzdHJpZ2luIGZ1bmN0aW9uKS4NCg0KUHJlc2VudGEgbcO6bHRpcGxlcyBtw61uaW1vcyBsb2NhbGVzIGRpc3B1ZXN0b3MgZGUgZm9ybWEgcmVndWxhcuKAiywgbG8gcXVlIGxvIGNvbnZpZXJ0ZSBlbiB1biBkZXNhZsOtbyB0w61waWNvIHBhcmEgYWxnb3JpdG1vcyBkZSBvcHRpbWl6YWNpw7NuLg0KDQpEZWZpbmljacOzbiBlbiBuIGRpbWVuc2lvbmVzOg0KDQokZihYKT1BbiArIFxzdW1fe2k9MX1ebltYX2leMiAtQVxjb3MoMlxwaSBYX2kpXSwgQT0xMCQNCg0KRGVmaW5pY2nDs24gZW4gMkQ6DQoNCiRmKHgseSk9eF4yK3leMitBWzItXGNvcygyXHBpIHgpIC0gXGNvcygyXHBpIHkpXSwgQT0xMCQNCg0KRGVmaW5pY2nDs24gZW4gM0Q6DQoNCiRmKHgseSk9eF4yK3leMit6XjIrQVszLVxjb3MoMlxwaSB4KSAtIFxjb3MoMlxwaSB5KS1cY29zKDJccGkgeildLCBBPTEwJA0KDQpBbGd1bmFzIGNhcmFjdGVyw61zdGljYXMgeSBwcm9waWVkYWRlcyBpbXBvcnRhbnRlcyBzb24gbGFzIHNpZ3VpZW50ZXM6DQoNCi0gICBNw61uaW1vIGdsb2JhbDoNCg0KICAgIC0gICAkZigwLC4uLjApPTAkDQoNCi0gICBEb21pbmlvIGRlIGLDunNxdWVkYToNCg0KICAgIC0gICAkLTUuMTIgXGxlcSBYX2kgXGxlcSA1LjEyJA0KDQotICAgUGFydGljdWxhcm1lbnRlLCBoYWxsYXIgZWwgbcOtbmltbyBkZSBlc3RhIGZ1bmNpw7NuIGVzIHVuIHByb2JsZW1hIGRpZsOtY2lsIGRlYmlkbyBhIGxhIGxhcmdhIGNhbnRpZGFkIGRlIG3DrW5pbW9zIGxvY2FsZXMuDQoNCkVzdGFzIHNvbiBhbGd1bmFzIGhpcMOzdGVzaXMgeSBleHBlY3RhdGl2YXMgcXVlIHNlIHR1dmllcm9uIHBhcmEgZWwgcmVuZGltaWVudG8gZGUgY2FkYSBtw6l0b2RvIGltcGxlbWVudGFkbyBjb24gZXN0YSBmdW5jacOzbjoNCg0KLSAgICoqTcOpdG9kbyBkZSBkZXNjZW5zbyBkZSBncmFkaWVudGU6KioNCg0KICAgIC0gICBFbCDDqXhpdG8gZGVsIG3DqXRvZG8gZW4gYWxjYW56YXIgdW4gbcOtbmltbyBkZXBlbmRlcsOhIGVub3JtZW1lbnRlIGRlbCBwdW50byBpbmljaWFsIGVsZWdpZG8gZGViaWRvIGEgbG9zIG3Dumx0aXBsZXMgbcOtbmltb3MgbG9jYWxlcyBxdWUgdGllbmUgZXN0YSBmdW5jacOzbi4NCg0KLSAgICoqTcOpdG9kbyBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3M6KioNCg0KICAgIC0gICBFcyBpbXBvcnRhbnRlIGhhY2VyIHVuYSBidWVuYSByZXByZXNlbnRhY2nDs24gZGUgbG9zIGluZGl2aWR1b3MsIHlhIHF1ZSBlbCByZW5kaW1pZW50byBwdWVkZSB2YXJpYXIgZGVwZW5kaWVuZG8gZGUgbGEgc2VsZWNjacOzbi4NCiAgICAtICAgTGEgcG9ibGFjacOzbiBpbmljaWFsIGRlYmUgc2VyIHJlcHJlc2VudGF0aXZhLCBkaWZlcmVudGVzIGVudHJlIGVsbG9zIHkgcXVlIG5vIHNlYW4gZGVtYXNpYWRvcy4gUGFyYSBlc3RhIGZ1bmNpw7NuIGVuIHBhcnRpY3VsYXIgZW5jb250cmFyIGxhIHNvbHVjacOzbiDDs3B0aW1hIHZhIGEgZGVwZW5kZXIgbXVjaG8gZGUgbGEgcHJvYmFiaWxpZGFkIGRlIG11dGFjacOzbg0KDQotICAgKipNw6l0b2RvIGRlIG9wdGltaXphY2nDs24gZGUgcGFydMOtY3VsYXM6KioNCg0KICAgIC0gICBMYSB1YmljYWNpw7NuIGRlIGxhIG51YmUgZGUgcGFydMOtY3VsYXMgdmEgYSBhZmVjdGFyIGVsIHJlbmRpbWllbnRvIGVuIGVzdGEgZnVuY2nDs24sIHlhIHF1ZSBlbCBhbGdvcml0bW8gcHVlZGUgcXVlZGFyc2UgZXN0YW5jYWRvIGVuIHVuIG3DrW5pbW8gbG9jYWwgc2kgbGEgdWJpY2FjacOzbiBubyBlcyBsYSBtZWpvci4NCiAgICAtICAgRWwgY3JpdGVyaW8gcGFyYSBkZXRlbmVyIGVsIGFsZ29yaXRtbyBkZWJlIGVzdGFyIGJpZW4gYWp1c3RhZG8sIHBhcmEgZXZpdGFyIGVzdGFuY2FtaWVudG9zLg0KDQotICAgKipNw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWw6KioNCg0KICAgIC0gICBFcyBtw6FzIGVmaWNpZW50ZSBxdWUgbG9zIG90cm9zIG3DqXRvZG9zIGV2b2x1dGl2b3MgeWEgcXVlIHN1IGZ1ZXJ0ZSBzb24gbGFzIG3Dumx0aXBsZXMgZGltZW5zaW9uZXMuDQoNCkxhIGltcGxlbWVudGFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMiwgMyB5IE4gZGltZW5zaW9uZXMgc2UgbXVlc3RyYSBhIGNvbnRpbnVhY2nDs246DQoNCmBgYHtyfQ0KIyAyIERpbWVuc2lvbmVzIA0KZl9yYXN0cmlnaW5fMmQgPC0gZnVuY3Rpb24oeCwgeSkgew0KICBBID0gMTAgICANCiAgZl92YWx1ZSA8LSB4XjIgKyB5XjIgKyBBKigyIC0gY29zKDIqcGkqeCkgLSBjb3MoMipwaSp5KSkgICANCiAgcmV0dXJuKGZfdmFsdWUpIA0KfSAgDQoNCiMgMyBEaW1lbnNpb25lcyANCmZfcmFzdHJpZ2luXzNkIDwtIGZ1bmN0aW9uKHgsIHksIHopIHsgICANCiAgQSA9IDEwICAgDQogIGZfdmFsdWUgPC0geF4yICsgeV4yICsgel4yICsgQSooMyAtIGNvcygyKnBpKngpIC0gY29zKDIqcGkqeSkgLSBjb3MoMipwaSp6KSkgICANCiAgcmV0dXJuKGZfdmFsdWUpIA0KfQ0KDQojIE4gRGltZW5zaW9uZXMNCmZfcmFzdHJpZ2luIDwtZnVuY3Rpb24oeCl7DQogIEEgPC0gMTANCiAgbiA8LSBsZW5ndGgoeCkNCiAgeiA8LSAoQSpuKSArIHN1bSh4XjIgLSBBKmNvcygyKnBpKngpKQ0KICByZXR1cm4oeikNCn0NCmBgYA0KDQpMYXMgZ3LDoWZpY2FzIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIHkgMyBkaW1lbnNpb25lcyBzZSBtdWVzdHJhbiBhIGNvbnRpbnVhY2nDs246DQoNCjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsifQ0KPGltZyBzcmM9ImltYWdlc1xncmFwaGljc1xyYXN0cmlnaW5fMmRfZ3JhZmljYS5wbmciIGFsdD0iR3LDoWZpY2EgZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIDJEIiBzdHlsZT0id2lkdGg6MzUwcHg7IG1heC13aWR0aDo5MCU7IGRpc3BsYXk6YmxvY2s7IG1hcmdpbjphdXRvOyIvPg0KDQo6Ojoge3N0eWxlPSJmb250LXdlaWdodDpib2xkOyBtYXJnaW4tdG9wOjhweDsgZm9udC1zaXplOjEuMDVlbTsifQ0KR3LDoWZpY2EgZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIDJEDQo6OjoNCjo6Og0KDQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJpbWFnZXNcZ3JhcGhpY3NccmFzdHJpZ2luXzNkX2dyYWZpY2EucG5nIiBhbHQ9Ikdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiAzRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkdyw6FmaWNhcyBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gM0QNCjo6Og0KOjo6DQoNCjxhIG5hbWU9ImlvMS4yLiI+PC9hPg0KDQojIyAxLjIgTcOpdG9kbyBkZSBkZXNjZW5zbyBkZSBncmFkaWVudGUNCg0KRWwgbcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIHBvciBkZXNjZW5zbyBkZSBncmFkaWVudGUgZXMgdW5hIHTDqWNuaWNhIGl0ZXJhdGl2YSB1dGlsaXphZGEgcGFyYSBlbmNvbnRyYXIgZWwgbcOtbmltbyBkZSB1bmEgZnVuY2nDs24uIENvbnNpc3RlIGVuIGFjdHVhbGl6YXIgc3VjZXNpdmFtZW50ZSBsb3MgdmFsb3JlcyBkZSBsYXMgdmFyaWFibGVzIGVuIGxhIGRpcmVjY2nDs24gb3B1ZXN0YSBhbCBncmFkaWVudGUgZGUgbGEgZnVuY2nDs24sIGNvbiBlbCBvYmpldGl2byBkZSByZWR1Y2lyIHN1IHZhbG9yIGVuIGNhZGEgcGFzby4NCg0KRW4gbnVlc3RybyBjYXNvLCBzZSB1dGlsaXphcm9uIGxhcyBzaWd1aWVudGVzIHZhcmlhYmxlcyBwYXJhIGltcGxlbWVudGFyIGVsIG3DqXRvZG86ICoqWOKCgCoqLCBxdWUgcmVwcmVzZW50YSBsYSBjb25kaWNpw7NuIGluaWNpYWwgZGVsIGFsZ29yaXRtbzsgKipIKiosIHF1ZSBkZWZpbmUgZWwgdGFtYcOxbyBkZSBsYSB2ZW50YW5hIHBhcmEgZWwgY8OhbGN1bG8gZGUgbGEgZGVyaXZhZGEgbnVtw6lyaWNhOyB5ICoqRVRBKiosIHF1ZSBjb3JyZXNwb25kZSBhIGxhIHRhc2EgZGUgYXByZW5kaXphamUsIGVzIGRlY2lyLCBlbCB0YW1hw7FvIGRlbCBwYXNvIHF1ZSBzZSBkYSBlbiBjYWRhIGl0ZXJhY2nDs24gaGFjaWEgZWwgbcOtbmltby4NCg0KPGEgbmFtZT0iaW8xLjIuMS4iPjwvYT4NCg0KIyMjIDEuMi4xIEltcGxlbWVudGFjacOzbiBlbiBSIGRlIGRlc2NlbnNvIGRlIGdyYWRpZW50ZQ0KDQpgYGB7cn0NCiMgSW1wbGVtZW50YWNpw7NuIGNvbXBsZXRhIGRlIG9wdGltaXphZG9yIG11bHRpdmFyaWFkbyBwb3IgZGVzY2Vuc28gZGUgZ3JhZGllbnRlDQpvcHRpbWl6YWRvcl9tdWx0X251bWRldiA8LSBmdW5jdGlvbih4MCxmdW4sbWF4X2V2YWw9MTAwLGg9MC4wMSxldGE9MC4wMSl7DQogIHggPC0gbWF0cml4KE5BLG5jb2wgPWxlbmd0aCh4MCksIG5yb3cgPSBtYXhfZXZhbCkNCiAgeFsxLF0gPC0geDANCiAgZm9yIChpIGluIDI6bWF4X2V2YWwpew0KICAgIG51bV9ncmFkX2Z1biA8LSBudW1fZ3JhZCh4W2ktMSxdLGZ1bixoKQ0KICAgIEggPC0gbWF0cml6X2hlc3NpYW5hKHhbaS0xLF0sZnVuLGgpDQogICAgY2FtYmlvIDwtIC0gZXRhKnNvbHZlKEgpJSolbnVtX2dyYWRfZnVuDQogICAgeFtpLF0gPC0geFtpLTEsXSArIGNhbWJpbw0KICAgIGNhbWJpb19vcHQgPC0gc3FydChzdW0oKHhbaS0xLF0teFtpLF0pXjIpKQ0KICAgIGlmIChjYW1iaW9fb3B0PDAuMDAwMDEpew0KICAgICAgYnJlYWsNCiAgICB9DQogIH0NCiAgcmV0dXJuKHhbMTppLF0pDQp9DQpgYGANCg0KPGEgbmFtZT0iaW8xLjIuMi4iPjwvYT4NCg0KIyMjIDEuMi4yIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAyIGRpbWVuc2lvbmVzDQoNCmBgYHtyfQ0Kc29sX3Jvc2VuMmQgPC0gb3B0aW1pemFkb3JfbXVsdF9udW1kZXYoZl9yb3NlbmJyb2NrLCB4MD1jKC00LC00KSwgaD0wLjAwNSwgZXRhPTAuNSkNCmBgYA0KDQpMYSBzaWd1aWVudGUgYW5pbWFjacOzbiBtdWVzdHJhIGVsIGRlc2VtcGXDsW8gZGUgbGEgb3B0aW1pemFjacOzbiBhIHRyYXZlcyBkZSBzdSB0cmF5ZWN0b3JpYToNCg0KOjo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0iUGFydGUgMVxEZXNjZW5zbyBkZSBncmFkaWVudGVccm9zZW5icm9ja19vcHRfZ3JhZF8yZC5naWYiIGFsdD0iQW5pbWFjacOzbiBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIFJvc2VuYnJvY2sgMkQiIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUm9zZW5icm9jayAyRA0KOjo6DQo6OjoNCg0KPGEgbmFtZT0iaW8xLjIuMy4iPjwvYT4NCg0KIyMjIDEuMi4zIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzDQoNCmBgYHtyfQ0Kc29sX3Jvc2VuM2QgPC0gb3B0aW1pemFkb3JfbXVsdF9udW1kZXYoZl9yb3NlbmJyb2NrLCB4MD1jKC00LC00LC00KSwgaD0wLjAwNSwgZXRhPTAuNSkNCmBgYA0KDQpFbiBsYSBzaWd1aWVudGUgdGFibGEgZGUgbXVlc3RyYW4gZWwgY29tcG9ydGFtaWVudG8gY2FkYSAxMCBpdGVyYWNpb25lczoNCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRGVzY2Vuc28gZGUgZ3JhZGllbnRlL3Jvc2VuYnJvY2tfaXRlcl9ncmFkLmNzdiIpDQpgYGANCg0KPGEgbmFtZT0iaW8xLjIuNC4iPjwvYT4NCg0KIyMjIDEuMi40IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXMNCg0KYGBge3J9DQpzb2xfcmFzMmQgPC0gb3B0aW1pemFkb3JfbXVsdF9udW1kZXYoZl9yYXN0cmlnaW4sIHgwPWMoNC41LDQuNSksIGg9MC4wMDUsIGV0YT0yKQ0KYGBgDQoNCkxhIHNpZ3VpZW50ZSBhbmltYWNpw7NuIG11ZXN0cmEgZWwgZGVzZW1wZcOxbyBkZSBsYSBvcHRpbWl6YWNpw7NuIGEgdHJhdmVzIGRlIHN1IHRyYXllY3RvcmlhOg0KDQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJQYXJ0ZSAxXERlc2NlbnNvIGRlIGdyYWRpZW50ZVxyYXN0cmlnaW5fb3B0X2dyYWRfMmQuZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQiIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUmFzdHJpZ2luIDJEDQo6OjoNCjo6Og0KDQo8YSBuYW1lPSJpbzEuMi41LiI+PC9hPg0KDQojIyMgMS4yLjUgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMyBkaW1lbnNpb25lcw0KDQpgYGB7cn0NCnNvbF9yYXMzZCA8LSBvcHRpbWl6YWRvcl9tdWx0X251bWRldihmX3Jhc3RyaWdpbiwgeDA9YygtNCwtNCwtNCksICBoPTAuMDA1LCBldGE9MikNCmBgYA0KDQpFbiBsYSBzaWd1aWVudGUgdGFibGEgZGUgbXVlc3RyYW4gZWwgY29tcG9ydGFtaWVudG8gY2FkYSAxMCBpdGVyYWNpb25lczoNCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRGVzY2Vuc28gZGUgZ3JhZGllbnRlL3Jhc3RyaWdpbl9pdGVyX2dyYWQuY3N2IikNCmBgYA0KDQo8YSBuYW1lPSJpbzEuMi42LiI+PC9hPg0KDQojIyMgMS4yLjYgQ29uY2x1c2lvbmVzIG3DqXRvZG8gZGUgZGVzZW5zbyBkZWwgZ3JhZGllbnRlDQoNCkVsIG3DqXRvZG8gZGUgb3B0aW1pemFjacOzbiBwb3IgZGVzY2Vuc28gZGUgZ3JhZGllbnRlIHNlIGNhcmFjdGVyaXphIHBvciBzdSBzaW1wbGljaWRhZCB5IGZhY2lsaWRhZCBkZSBpbXBsZW1lbnRhY2nDs24sIGxvIHF1ZSBsbyBjb252aWVydGUgZW4gdW5hIGhlcnJhbWllbnRhIMO6dGlsIHBhcmEgZnVuY2lvbmVzIGNvbiBzdXBlcmZpY2llcyBzdWF2ZXMgeSByZWxhdGl2YW1lbnRlIHNpbXBsZXMuIFNpbiBlbWJhcmdvLCBhbCBhcGxpY2Fyc2UgYSBmdW5jaW9uZXMgYWx0YW1lbnRlIG5vIGNvbnZleGFzIGNvbW8gbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luLCBlc3RlIG3DqXRvZG8gcHJlc2VudGEgbGltaXRhY2lvbmVzIHNpZ25pZmljYXRpdmFzLCB5YSBxdWUgdGllbmRlIGEgcXVlZGFyIGF0cmFwYWRvIGVuIG3DrW5pbW9zIGxvY2FsZXMsIGRpZmljdWx0YW5kbyBsYSBjb252ZXJnZW5jaWEgaGFjaWEgdW5hIHNvbHVjacOzbiBnbG9iYWwgw7NwdGltYS4NCg0KPGEgbmFtZT0iaW8xLjMuIj48L2E+DQoNCiMjIDEuMyBNw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWwNCg0KTGEgZXZvbHVjacOzbiBkaWZlcmVuY2lhbCBlcyB1biBhbGdvcml0bW8gZGUgb3B0aW1pemFjacOzbiBpbnNwaXJhZG8gZW4gbGEgZXZvbHVjacOzbiBiaW9sw7NnaWNhLiBGdW5jaW9uYSBtYW50ZW5pZW5kbyB1bmEgcG9ibGFjacOzbiBkZSBzb2x1Y2lvbmVzLCB5IG1lam9yw6FuZG9sYXMgZ2VuZXJhY2nDs24gdHJhcyBnZW5lcmFjacOzbiBtZWRpYW50ZSBvcGVyYWNpb25lcyBkZSBtdXRhY2nDs24sIHJlY29tYmluYWNpw7NuIHkgc2VsZWNjacOzbi4NCg0KLSAgICoqTXV0YWNpw7NuKio6IHNlIGNvbWJpbmFuIDMgaW5kaXZpZHVvcyBkaXN0aW50b3MgZGUgbGEgcG9ibGFjacOzbiBwYXJhIGNyZWFyIHVuYSB2YXJpYW50ZS4NCi0gICAqKlJlY29tYmluYWNpw7NuKio6IHNlIG1lemNsYSBlc2EgdmFyaWFudGUgY29uIGVsIGluZGl2aWR1byBhY3R1YWwuDQotICAgKipTZWxlY2Npw7NuKio6IHNlIGVzY29nZSBlbCBtZWpvciBlbnRyZSBlbCBvcmlnaW5hbCB5IGVsIG51ZXZvLg0KDQpFc3RlIHByb2Nlc28gc2UgcmVwaXRlIHZhcmlhcyB2ZWNlcyBoYXN0YSBlbmNvbnRyYXIgdW5hIHNvbHVjacOzbiDDs3B0aW1hLg0KDQpMYXMgdmFyaWFibGVzIHNvbjogKipkaW0qKiwgcXVlIHJlcHJlc2VudGEgbGEgY2FudGlkYWQgZGUgZGltZW5zaW9uZXMgbyB2YXJpYWJsZXMgZGVsIHByb2JsZW1hOyAqKk5QKiosIHF1ZSBpbmRpY2EgZWwgdGFtYcOxbyBkZSBsYSBwb2JsYWNpw7NuIG8gbsO6bWVybyBkZSBzb2x1Y2lvbmVzIGVuIGNhZGEgZ2VuZXJhY2nDs247ICoqRioqLCBxdWUgZXMgZWwgZmFjdG9yIGRlIG11dGFjacOzbiB5IGRldGVybWluYSBsYSBpbnRlbnNpZGFkIGRlIGxhIHBlcnR1cmJhY2nDs24gYXBsaWNhZGEgYSBsYXMgc29sdWNpb25lczsgKipDUioqLCBxdWUgY29ycmVzcG9uZGUgYSBsYSB0YXNhIGRlIHJlY29tYmluYWNpw7NuIHkgY29udHJvbGEgbGEgcHJvYmFiaWxpZGFkIGRlIGludGVyY2FtYmlvIGRlIGNvbXBvbmVudGVzIGVudHJlIHZlY3RvcmVzOyAqKmdlbnMqKiwgcXVlIGRlZmluZSBlbCBuw7ptZXJvIHRvdGFsIGRlIGdlbmVyYWNpb25lcyBvIGl0ZXJhY2lvbmVzIGRlbCBhbGdvcml0bW87IHkgKipib3VuZHMqKiwgcXVlIGVzdGFibGVjZSBsb3MgbMOtbWl0ZXMgaW5mZXJpb3IgeSBzdXBlcmlvciBkZWwgZXNwYWNpbyBkZSBiw7pzcXVlZGEgcGFyYSBjYWRhIGRpbWVuc2nDs24uDQoNCjxhIG5hbWU9ImlvMS4zLjEuIj48L2E+DQoNCiMjIyAxLjMuMSBJbXBsZW1lbnRhY2nDs24gZW4gUiBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsDQoNCmBgYHtyfQ0KZXZvbHVjaW9uX2RpZmVyZW5jaWFsIDwtIGZ1bmN0aW9uKGZ1bl9vYmosIGRpbSA9IDIsIE5QID0gMzAsIEYgPSAwLjgsIENSID0gMC45LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnMgPSAxMDAsIGJvdW5kcyA9IGMoLTUsIDUpKSB7DQoNCiAgIyBJbmljaWFsaXphciBwb2JsYWNpw7NuDQogIHBvYmxhY2lvbiA8LSBtYXRyaXgocnVuaWYoTlAgKiBkaW0sIGJvdW5kc1sxXSwgYm91bmRzWzJdKSwgbmNvbCA9IGRpbSkNCiAgZml0bmVzcyA8LSBhcHBseShwb2JsYWNpb24sIDEsIGZ1bl9vYmopDQoNCiAgaGlzdG9yaWFsIDwtIG51bWVyaWMoZ2VucykNCiAgbWVqb3JlcyA8LSBtYXRyaXgoTkEsIGdlbnMsIGRpbSkNCg0KICBmb3IgKGdlbiBpbiAxOmdlbnMpIHsNCiAgICBmb3IgKGkgaW4gMTpOUCkgew0KICAgICAgIyBTZWxlY2Npb25hciAzIMOtbmRpY2VzIGRpc3RpbnRvcw0KICAgICAgaW5kaWNlcyA8LSBzYW1wbGUoc2V0ZGlmZigxOk5QLCBpKSwgMykNCiAgICAgIHgxIDwtIHBvYmxhY2lvbltpbmRpY2VzWzFdLCBdDQogICAgICB4MiA8LSBwb2JsYWNpb25baW5kaWNlc1syXSwgXQ0KICAgICAgeDMgPC0gcG9ibGFjaW9uW2luZGljZXNbM10sIF0NCg0KICAgICAgIyBNdXRhY2nDs24NCiAgICAgIG11dGFkbyA8LSB4MSArIEYgKiAoeDIgLSB4MykNCg0KICAgICAgIyBSZWNvbWJpbmFyDQogICAgICB0cmlhbCA8LSBwb2JsYWNpb25baSwgXQ0KICAgICAganJhbmQgPC0gc2FtcGxlKDE6ZGltLCAxKQ0KICAgICAgZm9yIChqIGluIDE6ZGltKSB7DQogICAgICAgIGlmIChydW5pZigxKSA8IENSIHx8IGogPT0ganJhbmQpIHsNCiAgICAgICAgICB0cmlhbFtqXSA8LSBtdXRhZG9bal0NCiAgICAgICAgfQ0KICAgICAgfQ0KDQogICAgICAjIFNlbGVjY2nDs24NCiAgICAgIGlmIChmdW5fb2JqKHRyaWFsKSA8IGZpdG5lc3NbaV0pIHsNCiAgICAgICAgcG9ibGFjaW9uW2ksIF0gPC0gdHJpYWwNCiAgICAgICAgZml0bmVzc1tpXSA8LSBmdW5fb2JqKHRyaWFsKQ0KICAgICAgfQ0KICAgIH0NCg0KICAgICMgR3VhcmRhciBtZWpvciByZXN1bHRhZG8NCiAgICBiZXN0X2lkeCA8LSB3aGljaC5taW4oZml0bmVzcykNCiAgICBoaXN0b3JpYWxbZ2VuXSA8LSBmaXRuZXNzW2Jlc3RfaWR4XQ0KICAgIG1lam9yZXNbZ2VuLCBdIDwtIHBvYmxhY2lvbltiZXN0X2lkeCwgXQ0KICB9DQoNCiAgbGlzdChtZWpvciA9IHBvYmxhY2lvblt3aGljaC5taW4oZml0bmVzcyksIF0sDQogICAgICAgdmFsb3IgPSBtaW4oZml0bmVzcyksDQogICAgICAgaGlzdG9yaWFsID0gaGlzdG9yaWFsLA0KICAgICAgIHRyYXllY3RvcmlhID0gbWVqb3JlcykNCn0NCmBgYA0KDQo8YSBuYW1lPSJpbzEuMy4yLiI+PC9hPg0KDQojIyMgMS4zLjIgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXMNCg0KRW4gZXN0ZSBncsOhZmljbyBzZSBtdWVzdHJhbiBsYXMgY3VydmFzIGRlIG5pdmVsIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gZG9zIGRpbWVuc2lvbmVzLiBFc3RhcyBjdXJ2YXMgcmVwcmVzZW50YW4gbMOtbmVhcyBkb25kZSBsYSBmdW5jacOzbiB0aWVuZSBpZ3VhbCB2YWxvciwgeSBlbCB2YWxsZSBjdXJ2YWRvIGFsIGNlbnRybyBlcyBkb25kZSBlc3TDoSBlbCBtw61uaW1vIGdsb2JhbCAoZW4gZWwgcHVudG8gKDEsMSkoMSwxKSkuDQoNCkxhIGzDrW5lYSByb2phIHJlcHJlc2VudGEgbGEgdHJheWVjdG9yaWEgcXVlIHNpZ3Vpw7MgZWwgYWxnb3JpdG1vIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWwgZHVyYW50ZSBsYXMgaXRlcmFjaW9uZXMuIFNlIHB1ZWRlIG9ic2VydmFyIGPDs21vIGVsIGVuamFtYnJlIGRlIHNvbHVjaW9uZXMgc2UgZnVlIGFjZXJjYW5kbyBwcm9ncmVzaXZhbWVudGUgaGFjaWEgZWwgbcOtbmltbywgbWVqb3JhbmRvIHN1IHBvc2ljacOzbiBlbiBjYWRhIGdlbmVyYWNpw7NuLg0KDQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJQYXJ0ZSAxXEV2b2x1Y2lvbl9EaWZlcmVuY2lhbFxyb3NlbmJyb2NrX29wdF9ldmRfMmQuZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSb3NlbmJyb2NrIDJEIiBzdHlsZT0id2lkdGg6MzUwcHg7IG1heC13aWR0aDo5MCU7IGRpc3BsYXk6YmxvY2s7IG1hcmdpbjphdXRvOyIvPg0KDQo6Ojoge3N0eWxlPSJmb250LXdlaWdodDpib2xkOyBtYXJnaW4tdG9wOjhweDsgZm9udC1zaXplOjEuMDVlbTsifQ0KQW5pbWFjacOzbiBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIFJvc2VuYnJvY2sgMkQNCjo6Og0KOjo6DQoNCkVsIHJlc3VsdGFkbyBmaW5hbCBvYnRlbmlkbyBmdWU6IFsxXSAxLjAwMDAwMCAxLjAwMDAwMSBWYWxvciBtw61uaW1vIGVuY29udHJhZG86IDEuOTFlLTEyDQoNCjxhIG5hbWU9ImlvMS4zLjMuIj48L2E+DQoNCiMjIyAxLjMuMyBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMyBkaW1lbnNpb25lcw0KDQpFbiBlc3RhIHBhcnRlIGRlbCBpbmZvcm1lIHNlIG11ZXN0cmFuIGxvcyByZXN1bHRhZG9zIG51bcOpcmljb3MgcGFyYSBsYSBvcHRpbWl6YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZW4gM0QuIERhZG8gcXVlIG5vIHNlIHB1ZWRlIHZpc3VhbGl6YXIgZsOhY2lsbWVudGUgZW4gdW5hIGdyw6FmaWNhIDNEIGRlIHRyYXllY3RvcmlhLCBzZSByZXBvcnRhbiBsYXMgbWVqb3JlcyBwb3NpY2lvbmVzIHkgdmFsb3JlcyBvYnRlbmlkby4NCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRXZvbHVjaW9uX0RpZmVyZW5jaWFsL3Jvc2VuYnJvY2tfaXRlcl9ldmQuY3N2IikNCmBgYA0KDQo8YSBuYW1lPSJpbzEuMy40LiI+PC9hPg0KDQojIyMgMS4zLjQgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMiBkaW1lbnNpb25lcw0KDQpBcXXDrSBzZSBncmFmaWNhbiBsYXMgY3VydmFzIGRlIG5pdmVsIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiwgcXVlIGVzIG11bHRpbW9kYWwsIGVzIGRlY2lyLCB0aWVuZSBtdWNob3MgbcOtbmltb3MgbG9jYWxlcyAocGF0csOzbiBvbmR1bGFkbykuIExhIGLDunNxdWVkYSBlcyBtdWNobyBtw6FzIGNvbXBsZWphIHF1ZSBlbiBSb3NlbmJyb2NrLg0KDQpMYSBsw61uZWEgYXp1bCBtdWVzdHJhIGPDs21vIGxhIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWwgc2UgbXVldmUgcG9yIGVsIGVzcGFjaW8gZGUgYsO6c3F1ZWRhIHkgbG9ncmEgZXNjYXBhciBkZSBsb3MgbcOtbmltb3MgbG9jYWxlcyBoYXN0YSBhY2VyY2Fyc2UgYWwgw7NwdGltbyBnbG9iYWwsIHF1ZSBzZSBlbmN1ZW50cmEgZW4gKDAsMCkoMCwwKS4NCg0KOjo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0iUGFydGUgMVxFdm9sdWNpb25fRGlmZXJlbmNpYWxccmFzdHJpZ2luX29wdF9ldmRfMmQuZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQiIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUmFzdHJpZ2luIDJEDQo6OjoNCjo6Og0KDQpSZXN1bHRhZG8gb2J0ZW5pZG86IFsxXSAyLjE3NjY5N2UtMDYgLTIuMDE1Nzg1ZS0wNyBWYWxvciBtw61uaW1vOiA5LjQ4ZS0xMA0KDQo8YSBuYW1lPSJpbzEuMy41LiI+PC9hPg0KDQojIyMgMS4zLjUgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMyBkaW1lbnNpb25lcw0KDQpFbiBlc3RlIGNhc28sIGVsIGFsZ29yaXRtbyBlbmNvbnRyw7MgdW5hIHNvbHVjacOzbiBjZXJjYW5hIGFsIG3DrW5pbW8gZ2xvYmFsLCBhdW5xdWUgbm8gZXhhY3RhLiBFc3RvIGVzIGVzcGVyYWJsZSwgeWEgcXVlIFJhc3RyaWdpbiBlcyBtdWNobyBtw6FzIGRpZsOtY2lsIGVuIDNEIGRlYmlkbyBhIGxhIGdyYW4gY2FudGlkYWQgZGUgbcOtbmltb3MgbG9jYWxlcy4NCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRXZvbHVjaW9uX0RpZmVyZW5jaWFsL3Jhc3RyaWdpbl9pdGVyX2V2ZC5jc3YiKQ0KYGBgDQoNCjxhIG5hbWU9ImlvMS4zLjYuIj48L2E+DQoNCiMjIyAxLjMuNiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsDQoNCkVsIGFsZ29yaXRtbyBsb2dyw7MgZW5jb250cmFyIHNvbHVjaW9uZXMgbXV5IGNlcmNhbmFzIGFsIG3DrW5pbW8gZ2xvYmFsIGVuIGxhcyBmdW5jaW9uZXMgZGUgUm9zZW5icm9jayB5IFJhc3RyaWdpbiwgdGFudG8gZW4gMkQgY29tbyBlbiAzRC4NCg0KRW4gbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jaywgc2Ugb2JzZXJ2w7MgdW5hIGNvbnZlcmdlbmNpYSBlc3RhYmxlIHkgcHJlY2lzYSwgZXNwZWNpYWxtZW50ZSBlbiBkb3MgZGltZW5zaW9uZXMuDQoNCkVuIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiwgcXVlIHByZXNlbnRhIG11Y2hvcyBtw61uaW1vcyBsb2NhbGVzLCBlbCBtw6l0b2RvIGV2aXTDsyBjYWVyIGVuIGVzdG9zIHkgYWxjYW56w7MgYnVlbm9zIHJlc3VsdGFkb3MuDQoNCkVsIHJlbmRpbWllbnRvIHNlIG1hbnR1dm8gc8OzbGlkbyBlbiB0cmVzIGRpbWVuc2lvbmVzLCBhdW5xdWUgY29uIHVuYSBsaWdlcmEgcMOpcmRpZGEgZGUgcHJlY2lzacOzbiBlbiBSYXN0cmlnaW4gM0QgZGViaWRvIGEgc3UgY29tcGxlamlkYWQuDQoNCkZ1ZSBtw6FzIHJvYnVzdG8gcXVlIGVsIGRlc2NlbnNvIHBvciBncmFkaWVudGUgZW4gZnVuY2lvbmVzIG11bHRpbW9kYWxlcywgeWEgcXVlIG5vIG5lY2VzaXRhIGRlcml2YWRhcyBuaSBkZXBlbmRlIGRlbCBwdW50byBpbmljaWFsLg0KDQpMYSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsIGRlbW9zdHLDsyBzZXIgdW4gbcOpdG9kbyBjb25maWFibGUgeSBlZmVjdGl2byBwYXJhIHJlc29sdmVyIHByb2JsZW1hcyBkZSBvcHRpbWl6YWNpw7NuwqBjb250aW51YS4NCg0KPGEgbmFtZT0iaW8xLjQuIj48L2E+DQoNCiMjIDEuNCBNw6l0b2RvIGRlIG9wdGltaXphY2nDs24gZGUgcGFydMOtY3VsYXMNCg0KRWwgbcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIHBvciBlbmphbWJyZSBkZSBwYXJ0w61jdWxhcyAoUFNPLCBwb3Igc3VzIHNpZ2xhcyBlbiBpbmdsw6lzKSBlcyB1biBhbGdvcml0bW8gaW5zcGlyYWRvIGVuIGVsIGNvbXBvcnRhbWllbnRvIGNvbGVjdGl2byBkZSBhbmltYWxlcyBjb21vIGJhbmRhZGFzIGRlIGF2ZXMgbyBiYW5jb3MgZGUgcGVjZXMuIEZ1bmNpb25hIG1lZGlhbnRlIHVuIGNvbmp1bnRvIGRlIHBhcnTDrWN1bGFzIChzb2x1Y2lvbmVzIHBvdGVuY2lhbGVzKSBxdWUgZXhwbG9yYW4gZWwgZXNwYWNpbyBkZSBiw7pzcXVlZGEgbW92acOpbmRvc2UgZW4gZnVuY2nDs24gZGUgc3UgcHJvcGlhIGV4cGVyaWVuY2lhIHkgbGEgZGUgc3VzIHZlY2luYXMuIENhZGEgcGFydMOtY3VsYSBhanVzdGEgc3UgcG9zaWNpw7NuIHkgdmVsb2NpZGFkIGl0ZXJhdGl2YW1lbnRlIHBhcmEgYWNlcmNhcnNlIGEgbGEgbWVqb3Igc29sdWNpw7NuIGNvbm9jaWRhLCBndWlhZGEgcG9yIHN1IG1lam9yIHBvc2ljacOzbiBoaXN0w7NyaWNhIHkgbGEgbWVqb3IgcG9zaWNpw7NuIGdsb2JhbCBlbmNvbnRyYWRhIHBvciBlbCBlbmphbWJyZS4gQ29uIGVsIHRpZW1wbywgbGFzIHBhcnTDrWN1bGFzIHRpZW5kZW4gYSBjb252ZXJnZXIgaGFjaWEgdW5hIHNvbHVjacOzbiDDs3B0aW1hIG8gY2VyY2FuYSBhbCDDs3B0aW1vLg0KDQo8YSBuYW1lPSJpbzEuNC4xLiI+PC9hPg0KDQojIyMgMS40LjEgSW1wbGVtZW50YWNpw7NuIGVuIFIgZGUgb3B0aW1pemFjacOzbiBkZSBwYXJ0w61jdWxhcw0KDQpTZSB1dGlsaXphIGVsIHBhcXVldGUgcG9zIHBhcmEgaW1wbGVtZW50YXIgZWwgbcOpdG9kbyBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzLiBBZGljaW9uYWxtZW50ZSwgc2UgaW1wbGVtZW50YSB1bmEgZnVuY2nDs24gYWRpY2lvbmFsIHBhcmEgY3JlYXIgbGFzIGFuaW1hY2lvbmVzIGRlbCBtw6l0b2RvIGRlIG9wdGltaXphY2nDs24uDQoNCjxhIG5hbWU9ImlvMS40LjIuIj48L2E+DQoNCiMjIyAxLjQuMiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMiBkaW1lbnNpb25lcw0KDQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJwc29fcm9zZW5icm9ja19taW4uZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSb3NlbmJyb2NrIDJEIGNvbiBQU08iIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUm9zZW5icm9jayAyRCBjb24gUFNPDQo6OjoNCjo6Og0KDQo8YSBuYW1lPSJpbzEuNC4zLiI+PC9hPg0KDQojIyMgMS40LjMgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDMgZGltZW5zaW9uZXMNCg0KPCEtLSBUT0RPOiBGYWx0YW4gQW5pbWFjacOzbiBkZSBsYSBGdW5jacOzbiAtLT4NCg0KPGEgbmFtZT0iaW8xLjQuNC4iPjwvYT4NCg0KIyMjIDEuNC40IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXMNCg0KOjo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0icHNvX3Jhc3RyaWdpbl9taW4uZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIFBTTyIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIFBTTw0KOjo6DQo6OjoNCg0KPGEgbmFtZT0iaW8xLjQuNS4iPjwvYT4NCg0KIyMjIDEuNC41IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDMgZGltZW5zaW9uZXMNCg0KYGBge3J9DQojIFBhcsOhbWV0cm9zIGEgdXRpbGl6YXINCm4gPC0gMw0KbG93ZXJfYm91bmRzIDwtIC01DQp1cHBlZF9ib3VuZHMgPC0gNQ0KIyBFamVjdWNpw7NuIGRlbCBtw6l0b2RvDQpvX3BzbyA8LSBwYXJ0aWNsZV9zd2FybV9vcHRpbWl6YXRpb24obixmX3Jhc3RyaWdpbixsb3dlcl9ib3VuZHMsdXBwZXJfYm91bmRzKQ0KYGBgDQoNCjxhIG5hbWU9ImlvMS40LjYuIj48L2E+DQoNCiMjIyAxLjQuNiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzDQoNCkVuIGVsIGNhc28gZGUgbGEgb3B0aW1pemFjacOzbiBtYXhpbWl6YW5kbyBsYXMgZnVuY2lvbmVzLCBsbGVnYW4gbXV5IHLDoXBpZG8gYSB1bmEgc29sdWNpw7NuIMOzcHRpbWEgKGRlbnRybyBkZSAxMCBpdGVyYWNpb25lcykuIFBvciBvdHJvIGxhZG8sIGxhIG9wdGltaXphY2nDs24gbWluaW1pemFuZG8gbGFzIGZ1bmNpb25lcyB0YXJkYWJhIHVuIHBvY28gbcOhcyBlbiBsbGVnYXIgYWwgw7NwdGltbywgcGVybyBzZSBhY2VyY2FiYSBtdWNobyBhbCBtw61uaW1vIGdsb2JhbC4NCg0KRXN0b3MgcmVzdWx0YWRvcyBwdWVkZW4gZGViZXJzZSBhIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbGFzIHBhcnTDrWN1bGFzIHBvciBlbCBlc3BhY2lvIGRlIGLDunNxdWVkYSwgcGVybWl0aWVuZG8gdW5hIG9wdGltaXphY2nDs24gbcOhcyAiYWJpZXJ0YSIgYSBjb21wYXJhY2nDs24gY29uIGVsIG3DqXRvZG8gZGUgZGVzY2Vuc28gZGUgZ3JhZGllbnRlLg0KDQo8YSBuYW1lPSJpbzEuNS4iPjwvYT4NCg0KIyMgMS41IE3DqXRvZG8gZGUgYWxnb3JpdG1vcyBldm9sdXRpdm9zDQoNCkxvcyBhbGdvcml0bW9zIGdlbsOpdGljb3MgKEFHKSBzb24gdMOpY25pY2FzIGRlIGLDunNxdWVkYSBoZXVyw61zdGljYSBiYXNhZGFzIGVuIHByb2Nlc29zIGRlIGV2b2x1Y2nDs24gbmF0dXJhbOKAiyAuIEVuIHVuIEFHIHTDrXBpY28gc2UgZGVmaW5lIHVuYSBmdW5jacOzbiBGSVRORVNTIHF1ZSBldmFsw7phIGxhIGNhbGlkYWQgZGUgY2FkYSBzb2x1Y2nDs24gY2FuZGlkYXRhIChpbmRpdmlkdW8pLiBBIHBhcnRpciBkZSB1bmEgcG9ibGFjacOzbiBpbmljaWFsIGFsZWF0b3JpYSwgc2UgaXRlcmFuIGNpY2xvcyBkb25kZSBzZSBzZWxlY2Npb25hbiBpbmRpdmlkdW9zIG3DoXMgYXB0b3MsIHNlIGNvbWJpbmFuIHN1cyAiZ2VuZXMiIG1lZGlhbnRlIGNydWNlcyAoY3Jvc3NvdmVyKSB5IHNlIGludHJvZHVjZW4gbW9kaWZpY2FjaW9uZXMgYWxlYXRvcmlhcyAobXV0YWNpb25lcykuIEVzdG9zIG9wZXJhZG9yZXMgZXZvbHVjaW9uYW4gbGEgcG9ibGFjacOzbiBoYWNpYSByZWdpb25lcyBjb24gbWVqb3IgZml0bmVzcy4NCg0KU2Vnw7puIChTY3J1Y2NhLCAyMDEzKSwgbG9zIEdBcyBoYW4gc2lkbyBleGl0b3NvcyBlbiBvcHRpbWl6YXIgZnVuY2lvbmVzIGNvbnRpbnVhcyAoZGlmZXJlbmNpYWJsZXMgbyBubykgeSBkaXNjcmV0YXMuIEVudHJlIGxvcyBvcGVyYWRvcmVzIGdlbsOpdGljb3MgY2xhdmUgc2UgZGVzdGFjYW46DQoNCi0gICBTZWxlY2Npw7NuOiBlbGlnZSBpbmRpdmlkdW9zIGNvbiBtYXlvciBmaXRuZXNzIHBhcmEgcmVwcm9kdWNpcnNlLCBpbWl0YW5kbyBsYSBzdXBlcnZpdmVuY2lhIGRlbCBtw6FzIGFwdG8uDQoNCi0gICBDcnVjZSAoY3Jvc3NvdmVyKTogY29tYmluYSBwYXJ0ZXMgZGUgZG9zIHNvbHVjaW9uZXMgcGFyZW50YWxlcyBwYXJhIGdlbmVyYXIgZGVzY2VuZGVuY2lhLCBleHBsb3JhbmRvIG51ZXZhcyByZWdpb25lcyBkZWwgZXNwYWNpbyBkZSBiw7pzcXVlZGEuDQoNCi0gICBNdXRhY2nDs246IGFsdGVyYSBhbGVhdG9yaWFtZW50ZSBwYXJ0ZSBkZSB1biBpbmRpdmlkdW8gKHBvciBlamVtcGxvLCBjYW1iaWFuZG8gdW4gdmFsb3IgZGUgc3UgdmVjdG9yIGRlIHZhcmlhYmxlcykgcGFyYSBpbnRyb2R1Y2lyIGRpdmVyc2lkYWQgZ2Vuw6l0aWNhIHkgZXZpdGFyIGVzdGFuY2FtaWVudG8gZW4gw7NwdGltb3MgbG9jYWxlcy4NCg0KTG9zIGFsZ29yaXRtb3MgZ2Vuw6l0aWNvcyAoQUcpIHNvbiBtZXRhaGV1csOtc3RpY2FzIGluc3BpcmFkYXMgZW4gcHJvY2Vzb3MgZXZvbHV0aXZvcyBiaW9sw7NnaWNvcywgcXVlIGhhbiBkZW1vc3RyYWRvIGVmaWNhY2lhIGVuIGxhIGLDunNxdWVkYSBnbG9iYWwgZGUgw7NwdGltb3MgZW4gZnVuY2lvbmVzIGNvbXBsZWphc+KAi2pzdGF0c29mdC5vcmcgTG9zIEFHIHNpbXVsYW4gbGEgc2VsZWNjacOzbiBuYXR1cmFsLCBsYSByZWNvbWJpbmFjacOzbiAoY3J1Y2UpIHkgbGEgbXV0YWNpw7NuIHBhcmEgaXRlcmF0aXZhbWVudGUgbWVqb3JhciB1biBjb25qdW50byBkZSBzb2x1Y2lvbmVzIGNhbmRpZGF0YXMgKHBvYmxhY2nDs24pLiBFc3RhcyB0w6ljbmljYXMgZXN0b2PDoXN0aWNhcyBzb24gYWRlY3VhZGFzIHBhcmEgZnVuY2lvbmVzIG5vIGxpbmVhbGVzLCBkaXNjb250aW51YXMgbyBjb24gbcO6bHRpcGxlcyDDs3B0aW1vcyBsb2NhbGVzIGRvbmRlIGxvcyBtw6l0b2RvcyBiYXNhZG9zIGVuIGRlcml2YWRhcyBwdWVkZW4gZmFsbGFyLiBQYXJhIGV2YWx1YXIgbGEgcm9idXN0ZXogZGUgbG9zIEdBLCBzZSByZWFsaXphcsOhbiBtw7psdGlwbGVzIGVqZWN1Y2lvbmVzIGluZGVwZW5kaWVudGVzIHkgc2UgYW5hbGl6YXLDoSBsYSBkaXNwZXJzacOzbiBkZWwgZml0bmVzcyByZXN1bHRhbnRlLg0KDQpBZGljaW9uYWxtZW50ZSwgc2UgZGVmaW5lbiBhbGd1bmFzIGZ1bmNpb25lcyBwYXJhIHBvZGVyIG1vc3RyYXIgcG9yIG1lZGlvIGRlIHVuYSBhbmltYWNpw7NuIGVsIHByb2Nlc28gZGUgb3B0aW1pemFjacOzbiBwYXJhIGxhcyBmdW5jaW9uZXMgZGUgUm9zZW5icm9jayB5IGRlIFJhc3RyaWdpbi4NCg0KQW5hbGl6YXJlbW9zIGNhZGEgZnVuY2nDs24gZW4gMiB5IDMgZGltZW5zaW9uZXMsIGdyYWZpY2FuZG8gc3UgcGFpc2FqZSBhbnRlcyBkZSBsYSBvcHRpbWl6YWNpw7NuIHkgbHVlZ28gYXBsaWNhbmRvIHVuIEFHIGNvbiBtw7psdGlwbGVzIGNvcnJpZGFzIHBhcmEgZXZhbHVhciBsYSByb2J1c3RleiBkZSBsb3MgcmVzdWx0YWRvcy4NCg0KPGEgbmFtZT0iaW8xLjUuMS4iPjwvYT4NCg0KIyMjIDEuNS4xIEltcGxlbWVudGFjacOzbiBlbiBSIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvcw0KDQpTZSB1dGlsaXphIGxhIGZ1bmNpw7NuIGdhKCkgZGVsIHBhcXVldGUgR0EuIFBhcmEgcHJvYmxlbWFzIGRlIG1pbmltaXphY2nDs24gc2UgZGVmaW5lIGxhIGZ1bmNpw7NuIGRlIGZpdG5lc3MgY29tbyBlbCBuZWdhdGl2byBkZWwgdmFsb3Igb2JqZXRpdm8sIHlhIHF1ZSBnYSgpIG1heGltaXphIHBvciBkZWZlY3RvLiBTZSBlc3BlY2lmaWNhbiBsb3MgbMOtbWl0ZXMgZGUgYsO6c3F1ZWRhLg0KDQpMb3MgcmVzw7ptZW5lcyBlbiBjYWRhIGVqZWN1Y2nDs24gcmVwb3J0YW4gZWwgbWVqb3IgZml0bmVzcyBlbmNvbnRyYWRvIChuZWdhdGl2bykgeSBsYSBzb2x1Y2nDs24gw7NwdGltYSBlbiBjYWRhIGVqZWN1Y2nDs24uDQoNCjxhIG5hbWU9ImlvMS41LjIuIj48L2E+DQoNCiMjIyAxLjUuMiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMiBkaW1lbnNpb25lcw0KDQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJvcHRpbV9yYXN0cmlnaW5fZ2EuZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIEFsZ29yaXRtbyBHZW7DqXRpY28iIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUmFzdHJpZ2luIDJEIGNvbiBBbGdvcml0bW8gR2Vuw6l0aWNvDQo6OjoNCjo6Og0KDQo8YSBuYW1lPSJpbzEuNS4zLiI+PC9hPg0KDQojIyMgMS41LjMgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDMgZGltZW5zaW9uZXMNCg0KPCEtLSBUT0RPOiBGYWx0YW4gQW5pbWFjacOzbiBkZSBsYSBGdW5jacOzbiAtLT4NCg0KPGEgbmFtZT0iaW8xLjUuNC4iPjwvYT4NCg0KIyMjIDEuNS40IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXMNCg0KPCEtLSBUT0RPOiBGYWx0YW4gQW5pbWFjacOzbiBkZSBsYSBGdW5jacOzbiAtLT4NCg0KPGEgbmFtZT0iaW8xLjUuNS4iPjwvYT4NCg0KIyMjIDEuNS41IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDMgZGltZW5zaW9uZXMNCg0KPCEtLSBUT0RPOiBGYWx0YW4gQW5pbWFjacOzbiBkZSBsYSBGdW5jacOzbiAtLT4NCg0KPGEgbmFtZT0iaW8xLjUuNi4iPjwvYT4NCg0KIyMjIDEuNS42IEPDoWxjdWxvIGRlIGVzdGFkw61zdGljYXMgeSBhbsOhbGlzaXMNCg0KUGFyYSBldmFsdWFyIGxhIHZhcmlhYmlsaWRhZCBkZWwgbcOpdG9kbyBlc3RvY8Ohc3RpY28sIHNlIHJlcGl0ZSBjYWRhIGNhc28gYWwgbWVub3MgMzAgdmVjZXMgY29uIHNlbWlsbGFzIGRpc3RpbnRhcy4gU2UgcmVnaXN0cmEgZWwgbWVqb3IgdmFsb3IgZGUgZml0bmVzcyAodmFsb3JpemFkbyBwb3NpdGl2YW1lbnRlKSBvYnRlbmlkbyBlbiBjYWRhIGNvcnJpZGEuIFNlIGNhbGN1bGFyw6FuIGVzdGFkw61zdGljYXMgKG1lZGlhIHkgZGVzdmlhY2nDs24gZXN0w6FuZGFyKSBkZWwgbWVqb3IgdmFsb3IgZGUgZml0bmVzcyBvYnRlbmlkbyBlbiAzMCBlamVjdWNpb25lcyBpbmRlcGVuZGllbnRlcyBkZSBjYWRhIGNhc28geSBzZSByZXN1bWlyw6FuIGVuIHVuYSB0YWJsYS4NCg0KQ29uIGxvcyB2ZWN0b3JlcyBkZSBtZWpvcmVzIHZhbG9yZXMgKGJlc3RfdmFsc19yb3MsIGV0Yy4pLCBzZSBjYWxjdWxhbiBsYSBtZWRpYSB5IGRlc3ZpYWNpw7NuIGVzdMOhbmRhciBkZSBjYWRhIGNvbmp1bnRvIGRlIDMwIHJlc3VsdGFkb3MuIFBvciBlamVtcGxvLCBtZWFuX3JvcyB5IHNkX3JvcyBhcnJpYmEgeSBsYXMgZGVtYXMsIFBhcmEgYXNpIHByZXNlbnRhciBsb3MgcmVzdWx0YWRvcy4NCg0KPCEtLSBUT0RPOiBGYWx0YW4gVGFibGUgZGUgbGEgRnVuY2nDs24gLS0+DQoNCkxvcyByZXN1bHRhZG9zIGRlIGxhcyBtw7psdGlwbGVzIGVqZWN1Y2lvbmVzIHNlIHJlc3VtZW4gZW4gbGEgVGFibGEgMS4gRXN0YSB0YWJsYSBtdWVzdHJhIGxhIG1lZGlhIHkgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGRlbCBtZWpvciB2YWxvciBkZSBmaXRuZXNzIChyZWNvcmRhZG8gcXVlIGVzIGVsIHZhbG9yIGRlIGxhIGZ1bmNpw7NuIG9iamV0aXZvIGVuIHN1IG3DrW5pbW8gZ2xvYmFsLCB0w61waWNhbWVudGUgY2VyY2FubyBhIDApIHBhcmEgY2FkYSBjb21iaW5hY2nDs24gZGUgZnVuY2nDs24geSBkaW1lbnNpw7NuLiBTZSBvYnNlcnZhIHF1ZSBwYXJhIFJvc2VuYnJvY2sgMkQsIGxhIG1lZGlhIGRlbCBmaXRuZXNzIG3DrW5pbW8gZXMgY2VyY2FuYSBhIDAgY29uIGJhamEgZGlzcGVyc2nDs24sIHJlZmxlamFuZG8gcXVlIGVsIEdBIG5vcm1hbG1lbnRlIGVuY3VlbnRyYSBlbCBtw61uaW1vIGdsb2JhbCAoMCkgbyBjZXJjYW5vLiBQYXJhIFJhc3RyaWdpbiAyRCwgbGEgbWVkaWEgdGFtYmnDqW4gcHVlZGUgYWNlcmNhcnNlIGEgMCwgcGVybyBjb24gbWF5b3IgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGRlYmlkbyBhIGxvcyBtw7psdGlwbGVzIG3DrW5pbW9zIGxvY2FsZXMuIEVuIDNEIGFtYm9zIHByb2JsZW1hcyBzdWVsZW4gbW9zdHJhciB2YWxvcmVzIG1lZGlvcyBtYXlvcmVzIChtw6FzIGFsZWphZG9zIGRlIDApIHkgbWF5b3IgdmFyaWFiaWxpZGFkLCBsbyBjdWFsIGluZGljYSB1bmEgbWF5b3IgZGlmaWN1bHRhZCBkZSBiw7pzcXVlZGEgYWwgYXVtZW50YXIgbGEgZGltZW5zaW9uYWxpZGFkLg0KDQo8IS0tIFRPRE86IEZhbHRhbiBBbmltYWNpw7NuIGRlIGxhIEZ1bmNpw7NuIC0tPg0KDQoqKlRhYmxhIDEuKiogRXN0YWTDrXN0aWNhcyAobWVkaWEgeSBkZXN2aWFjacOzbiBlc3TDoW5kYXIpIGRlbCBmaXRuZXNzIG3DrW5pbW8gYWxjYW56YWRvIGVuIDMwIGNvcnJpZGFzIGluZGVwZW5kaWVudGVzIHBhcmEgY2FkYSBmdW5jacOzbiB5IGRpbWVuc2nDs24uDQoNCjxhIG5hbWU9ImlvMS41LjcuIj48L2E+DQoNCiMjIyAxLjUuNyBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3MNCg0KTG9zIHJlc3VsdGFkb3MgY29uZmlybWFuIHF1ZSBlbCBhbGdvcml0bW8gZ2Vuw6l0aWNvIGVzIGNhcGF6IGRlIGFwcm94aW1hcnNlIGEgbG9zIG3DrW5pbW9zIGdsb2JhbGVzIGRlIGFtYm9zIHByb2JsZW1hcyBlbiBtw7psdGlwbGVzIGRpbWVuc2lvbmVzLiBDb21vIGVyYSBkZSBlc3BlcmFyLCBSYXN0cmlnaW4gbW9zdHLDsyBtYXlvciB2YXJpYWJpbGlkYWQgZW4gbG9zIHZhbG9yZXMgZGUgZml0bmVzcyBkZWJpZG8gYSBzdXMgbXVjaG9zIG3DrW5pbW9zIGxvY2FsZXMsIGxvIHF1ZSBpbXBsaWNhIHF1ZSBhbGd1bmFzIGVqZWN1Y2lvbmVzIGRlbCBHQSBwdWVkZW4gcXVlZGFyc2UgYXRyYXBhZGFzIGVuIMOzcHRpbW9zIGxvY2FsZXMgYWxlamFkb3MgZGVsIGdsb2JhbC4gRW4gY29udHJhc3RlLCBSb3NlbmJyb2NrIChhdW5xdWUgZXMgbm8gY29udmV4YSkgdGllbmRlIGEgdW4gw7puaWNvIHZhbGxlIHByaW5jaXBhbDsgcG9yIGVsbG8sIGxhIG1heW9yw61hIGRlIGxhcyBjb3JyaWRhcyBhbGNhbnphcm9uIHZhbG9yZXMgY2VyY2Fub3MgYWwgbcOtbmltbyBnbG9iYWwgY29uIG1lbm9yIGRpc3BlcnNpw7NuLiBFbiBnZW5lcmFsIHNlIG9ic2VydmEgcXVlIGFsIGF1bWVudGFyIGxhIGRpbWVuc2nDs24gKGRlIDJEIGEgM0QpIGxhIHRhcmVhIHNlIGNvbXBsaWNhIHkgbGEgbWVkaWEgZGVsIGZpdG5lc3MgYXVtZW50YSAocGVvciDDs3B0aW1vIGVuY29udHJhZG8pLCByZWZsZWphbmRvIGxhIG1hbGRpY2nDs24gZGUgbGEgZGltZW5zaW9uYWxpZGFkLiBFbCB1c28gZGUgbcO6bHRpcGxlcyBlamVjdWNpb25lcyBpbmRlcGVuZGllbnRlcyBlcyBlc2VuY2lhbCBwYXJhIGV2YWx1YXIgbGEgcm9idXN0ZXogZGUgbG9zIEFHLiBEZWJpZG8gYSBzdSBuYXR1cmFsZXphIGVzdG9jw6FzdGljYSwgY2FkYSBlamVjdWNpw7NuIHB1ZWRlIGNvbnZlcmdlciBhIHNvbHVjaW9uZXMgZGlzdGludGFzLiBBbCBhbmFsaXphciBsYSBtZWRpYSB5IGRlc3ZpYWNpw7NuIGVzdMOhbmRhciBkZSBsb3MgZml0bmVzcyBmaW5hbGVzIHNlIG9idGllbmUgdW5hIG1lZGlkYSBkZSBmaWFiaWxpZGFkIGRlbCBhbGdvcml0bW86IHVuYSBiYWphIGRlc3ZpYWNpw7NuIGluZGljYSByZXN1bHRhZG9zIGNvbnNpc3RlbnRlcy4gRW4gbGEgbGl0ZXJhdHVyYSBzb2JyZSBhbGdvcml0bW9zIGdlbsOpdGljb3Mgc2UgcmVjb25vY2UgcXVlIGVuIG11Y2hvcyBjYXNvcyB1bmEgc29sYSBlamVjdWNpw7NuIHB1ZWRlIG5vIHNlciByZXByZXNlbnRhdGl2YeKAi2pzdGF0c29mdC5vcmcuIEF1bnF1ZSB1biBhbsOhbGlzaXMgY29tcGFyYXRpdm8gcHJvZnVuZG8gKHAuZWouLCB1c2FuZG8gcG9ibGFjaW9uZXMgbcOhcyBncmFuZGVzIG8gbcO6bHRpcGxlcyBjb3JyaWRhcyBlbiBwYXJhbGVsbykgcXVlZGEgZnVlcmEgZGVsIGFsY2FuY2UgZGUgZXN0ZSBkb2N1bWVudG8sIG51ZXN0cm9zIHJlc3VsdGFkb3MgaWx1c3RyYW4gZXN0ZSBmZW7Ds21lbm8uIEVzdGUgZXN0dWRpbyBlcyByZXByb2R1Y2libGU6IHRvZG8gZWwgY8OzZGlnbyBSIG5lY2VzYXJpbyBlc3TDoSBpbmNsdWlkbywgcGVybWl0aWVuZG8gYSBvdHJvcyBpbnZlc3RpZ2Fkb3JlcyByZXBsaWNhciBsb3MgZXhwZXJpbWVudG9zLCB2YXJpYXIgcGFyw6FtZXRyb3MgZGVsIEdBICh0YXNhIGRlIGNydWNlLCBtdXRhY2nDs24sIHRhbWHDsW8gZGUgcG9ibGFjacOzbiwgZXRjLikgeSBjb21wYXJhciBjb24gb3Ryb3MgYWxnb3JpdG1vcyBkZSBvcHRpbWl6YWNpw7NuLjpDb25jbHVzaW9uZXMgU2UgaGEgcHJlc2VudGFkbyB1bmEgZG9jdW1lbnRhY2nDs24gY29tcGxldGEgZGUgbGEgb3B0aW1pemFjacOzbiBkZSBsYXMgZnVuY2lvbmVzIGRlIFJvc2VuYnJvY2sgeSBSYXN0cmlnaW4gZW4gMkQgeSAzRCBlbXBsZWFuZG8gYWxnb3JpdG1vcyBnZW7DqXRpY29zIGVuIFIuIE1lZGlhbnRlIHZpc3VhbGl6YWNpb25lcyAzRCBpbmljaWFsZXMgc2UgaWx1c3RyYXJvbiBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBjYWRhIGZ1bmNpw7NuIGRlIHBydWViYS4gU2UgaW1wbGVtZW50w7MgZWwgcGFxdWV0ZSBHQSBwYXJhIHJlc29sdmVyIGNhZGEgY2FzbyB5IHNlIHJlYWxpemFyb24gMzAgZWplY3VjaW9uZXMgaW5kZXBlbmRpZW50ZXMgcGFyYSBldmFsdWFyIGxhIHJvYnVzdGV6LiBMb3MgcmVzdWx0YWRvcyBtdWVzdHJhbiBxdWUgZWwgR0EgcHVlZGUgZW5jb250cmFyIGFwcm94aW1hY2lvbmVzIGFsIG3DrW5pbW8gZ2xvYmFsIGVuIGFtYm9zIHByb2JsZW1hcywgYXVucXVlIGxhIGZ1bmNpw7NuIFJhc3RyaWdpbiAobcO6bHRpcGxlcyBtw61uaW1vcyBsb2NhbGVzKSBwcmVzZW50YSBtw6FzIHZhcmlhYmlsaWRhZCB5IGRpZmljdWx0YWQsIGVzcGVjaWFsbWVudGUgZW4gM0QuIDxhIG5hbWU9ImlvMS41LjcuIj48L2E+IFwjIENvbmNsdXNpw7NuIEdlbmVyYWwNCg0KQWwgdGVybWluYXIgZXN0ZSB0cmFiYWpvLCBsYSB2ZXJkYWQgZXMgcXVlIHVubyBzZSBkYSBjdWVudGEgZGUgbG8gcG9kZXJvc29zIHkgZmxleGlibGVzIHF1ZSBwdWVkZW4gc2VyIGxvcyBhbGdvcml0bW9zIGJpb2luc3BpcmFkb3MgY3VhbmRvIHNlIHRyYXRhIGRlIHJlc29sdmVyIHByb2JsZW1hcyBkZSBvcHRpbWl6YWNpw7NuLCB0YW50byBudW3DqXJpY29zIGNvbW8gY29tYmluYXRvcmlvcy4gRW4gbGEgcHJpbWVyYSBwYXJ0ZSwgZXhwZXJpbWVudGFtb3MgY29uIGZ1bmNpb25lcyBjbMOhc2ljYXMgY29tbyBSb3NlbmJyb2NrIHkgUmFzdHJpZ2luIHVzYW5kbyBtw6l0b2RvcyBjb21vIGVsIGRlc2NlbnNvIGRlIGdyYWRpZW50ZSwgUFNPIHkgYWxnb3JpdG1vcyBnZW7DqXRpY29zLiBMbyBpbnRlcmVzYW50ZSBmdWUgdmVyIGPDs21vIGxvcyBtw6l0b2RvcyBiaW9pbnNwaXJhZG9zLCBpbnNwaXJhZG9zIGVuIGxhIG5hdHVyYWxlemEgeSBlbCBjb21wb3J0YW1pZW50byBjb2xlY3Rpdm8sIGxvZ3JhbiBlc2NhcGFyIGRlIGxvcyBtw61uaW1vcyBsb2NhbGVzIHkgZXhwbG9yYXIgZWwgZXNwYWNpbyBkZSBzb2x1Y2lvbmVzIGRlIHVuYSBmb3JtYSBtdWNobyBtw6FzIGNyZWF0aXZhIHkgcm9idXN0YSBxdWUgbG9zIG3DqXRvZG9zIHRyYWRpY2lvbmFsZXMuIE5vIHNvbG8gZXMgY3Vlc3Rpw7NuIGRlIGVuY29udHJhciBlbCBtw61uaW1vLCBzaW5vIGRlIGPDs21vIHNlIGxsZWdhIGEgw6lsOiBsYSBkaXZlcnNpZGFkLCBsYSBjb2xhYm9yYWNpw7NuIHkgbGEgYWRhcHRhY2nDs24gY29uc3RhbnRlIGhhY2VuIGxhIGRpZmVyZW5jaWEuDQoNClBlcm8gbGEgY29zYSBubyBzZSBxdWVkw7MgYWjDrS4gRW4gbGEgc2VndW5kYSBwYXJ0ZSwgbm9zIG1ldGltb3MgZGUgbGxlbm8gZW4gbGEgb3B0aW1pemFjacOzbiBjb21iaW5hdG9yaWEsIGVuZnJlbnTDoW5kb25vcyBhbCBjbMOhc2ljbyBwcm9ibGVtYSBkZWwgdmlhamFudGUgdXNhbmRvIGNvbG9uaWEgZGUgaG9ybWlnYXMuIEFxdcOtLCBsYSBpbnNwaXJhY2nDs24gZW4gZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIGhvcm1pZ2FzIHBhcmEgZW5jb250cmFyIHJ1dGFzIMOzcHRpbWFzIGVuIGxhIG5hdHVyYWxlemEgc2UgdHJhZHVqbyBlbiB1biBhbGdvcml0bW8gY2FwYXogZGUgZW5jb250cmFyIHNvbHVjaW9uZXMgZWZpY2llbnRlcyBlbiBwcm9ibGVtYXMgZG9uZGUgbGEgY2FudGlkYWQgZGUgY29tYmluYWNpb25lcyBwb3NpYmxlcyBlcyBhYnJ1bWFkb3JhLiBFcyBpbXByZXNpb25hbnRlIHZlciBjw7NtbywgYSB0cmF2w6lzIGRlIGxhIGNvb3BlcmFjacOzbiB5IGxhIGNvbXVuaWNhY2nDs24gaW5kaXJlY3RhIChjb21vIGxhcyBmZXJvbW9uYXMgZW4gZWwgY2FzbyBkZSBsYXMgaG9ybWlnYXMpLCBlbCBzaXN0ZW1hIGVuY3VlbnRyYSBjYW1pbm9zIGNhZGEgdmV6IG1lam9yZXMsIGluY2x1c28gY3VhbmRvIGVsIGVzcGFjaW8gZGUgYsO6c3F1ZWRhIGVzIGdpZ2FudGVzY28uDQoNCkVuIHJlc3VtZW4sIGVzdGUgdHJhYmFqbyBubyBzb2xvIG5vcyBwZXJtaXRpw7MgY29tcGFyYXIgeSBlbnRlbmRlciBkaWZlcmVudGVzIGFsZ29yaXRtb3MsIHNpbm8gcXVlIHRhbWJpw6luIG5vcyBtb3N0csOzIGxhIGltcG9ydGFuY2lhIGRlIHBlbnNhciAiZnVlcmEgZGUgbGEgY2FqYSIgeSBkZSBpbnNwaXJhcm5vcyBlbiBsYSBuYXR1cmFsZXphIHBhcmEgcmVzb2x2ZXIgcHJvYmxlbWFzIGNvbXBsZWpvcy4gTG9zIGFsZ29yaXRtb3MgYmlvaW5zcGlyYWRvcyBubyBzb24gdW5hIHJlY2V0YSBtw6FnaWNhLCBwZXJvIHPDrSB1bmEgaGVycmFtaWVudGEgcG9kZXJvc2EgeSBhZGFwdGFibGUsIGNhcGF6IGRlIGVuZnJlbnRhciBkZXNhZsOtb3MgdGFudG8gZW4gZWwgbXVuZG8gY29udGludW8gY29tbyBlbiBlbCBkaXNjcmV0by4gQWRlbcOhcywgdHJhYmFqYXIgY29uIGVzdG9zIG3DqXRvZG9zIGZvbWVudGEgbGEgY3JlYXRpdmlkYWQsIGVsIHRyYWJham8gZW4gZXF1aXBvIHkgdW5hIHZpc2nDs24gaW50ZXJkaXNjaXBsaW5hcmlhIHF1ZSwgc2luIGR1ZGEsIGVzIGNsYXZlIGVuIGxhIGNpZW5jaWEgeSBsYSBpbmdlbmllcsOtYSBkZSBob3kuDQoNCjxhIG5hbWU9ImlvMi4iPjwvYT4NCg0KIyBQYXJ0ZSAyLiBPcHRpbWl6YWNpw7NuIGNvbWJpbmF0b3JpYQ0KDQo8YSBuYW1lPSJpbzIuMS4iPjwvYT4NCg0KIyMgMi4xIFBsYW50ZWFtaWVudG8gZGVsIHByb2JsZW1hDQoNCkVsIHByb2JsZW1hIHNlIHB1ZWRlIHBsYW50ZWFyIGNvbW8gdW5hIGluc3RhbmNpYSBwYXJ0aWN1bGFyIGRlbCBwcm9ibGVtYSBkZWwgdmlhamVybyBlbiBjaWVuY2lhcyBkZSBsYSBjb21wdXRhY2nDs24uIEVuIGxhIFRhYmxhIDIgc2UgbXVlc3RyYW4gbGFzIDEzIGNpdWRhZGVzIHByaW5jaXBhbGVzIGRlIENvbG9tYmlhIGNvbiBzdSByZXNwZWN0aXZhcyBsYXRpdHVkZXMgeSBsb25naXR1ZGVzLg0KDQp8ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwNCnwgICAgICAgICAgICAgICAgICAgfCAqKkxhdGl0dWQqKiB8ICoqTG9uZ2l0dWQqKiB8DQp8ICoqQm9nb3TDoSoqICAgICAgICB8IDQuNzExMCAgICAgIHwgLTc0LjA3MjEgICAgIHwNCnwgKipNZWRlbGzDrW4qKiAgICAgIHwgNi4yNDQyICAgICAgfCAtNzUuNTgxMiAgICAgfA0KfCAqKkNhbGkqKiAgICAgICAgICB8IDMuNDUxNiAgICAgIHwgLTc2LjUzMjAgICAgIHwNCnwgKipCYXJyYW5xdWlsbGEqKiAgfCAxMC45Njg1ICAgICB8IC03NC43ODEzICAgICB8DQp8ICoqQ2FydGFnZW5hKiogICAgIHwgMTAuMzkxMCAgICAgfCAtNzUuNDc5NCAgICAgfA0KfCAqKkPDumN1dGEqKiAgICAgICAgfCA3Ljg5NDEgICAgICB8IC03Mi41MDc4ICAgICB8DQp8ICoqU29sZWRhZCoqICAgICAgIHwgMTAuOTI2NCAgICAgfCAtNzQuODA1NSAgICAgfA0KfCAqKkliYWd1w6kqKiAgICAgICAgfCA0LjQzODkgICAgICB8IC03NS4yMzIyICAgICB8DQp8ICoqQnVjYXJhbWFuZ2EqKiAgIHwgNy4xMTkzICAgICAgfCAtNzMuMTIyNyAgICAgfA0KfCAqKlZpbGxhdmljZW5jaW8qKiB8IDQuMTQyMCAgICAgIHwgLTczLjYyOTggICAgIHwNCnwgKipTYW50YSBNYXJ0YSoqICAgfCAxMS4yNDA4ICAgICB8IC03NC4xOTkwICAgICB8DQp8ICoqTWFuaXphbGVzKiogICAgIHwgNS4wNzAzICAgICAgfCAtNzUuNTEzOCAgICAgfA0KfCAqKlBlcmVpcmEqKiAgICAgICB8IDQuODE0MyAgICAgIHwgLTc1LjY5NDYgICAgIHwNCg0KKipUYWJsYSAyLioqIENpdWRhZGVzIHByaW5jaXBhbGVzIGRlIENvbG9tYmlhIGp1bnRvIGNvbiBzdSBsYXRlbmNpYSB5IGxvbmdpdHVkLg0KDQpFbCBvYmpldGl2byBkZSBlc3RlIHByb2JsZW1hIGVzIG9wdGltaXphciBjb24gcmVzcGVjdG8gYSBsb3MgY29zdG9zIHkgbm8gYSBsYXMgZGlzdGFuY2lhcyBlbnRyZSBjaXVkYWRlcywgcG9yIGxvIHF1ZSBzZSB0aWVuZW4gcXVlIGNvbnNpZGVyYXIgbG9zIGNvc3RvcyBkZSBjb21idXN0aWJsZSwgZGUgcGVhamVzIHkgY3XDoW50byBjb2JyYSBlbCB2ZW5kZWRvciBwb3IgaG9yYSBkZSB0cmFiYWpvLiBTaW4gZW1iYXJnbywgbGEgZGlzdGFuY2lhIGFmZWN0YXLDoSBhbCB2YWxvciBkZSB0b2RvcyBlc3RvcyBjb3N0b3MsIHkgcG9yIGxvIHRhbnRvIGhheSBxdWUgY29uc2lkZXJhcmxhLiBBZGljaW9uYWxtZW50ZSwgdG9kb3MgZXN0b3MgY29zdG9zIGVzdMOhbiBlbiBmdW5jacOzbiBkZSBsYSBkaXN0YW5jaWEgZW4gbWV0cm9zLCBwb3IgbG8gcXVlIGVzIG5lY2VzYXJpbyByZWFsaXphciBsYSBjb252ZXJzacOzbiBkZSBsYXRpdHVkLWxvbmdpdHVkIGEgY29vcmRlbmFkYXMgZW4gbWV0cm9zLiBQYXJhIGVzdG8gc2UgdXPDsyBsYSBsaWJyZXLDrWEgInNmIiBwYXJhIHJlYWxpemFyIGxhIGNvbnZlcnNpw7NuIGFsIHNpc3RlbWEgZGUgY29vcmRlbmFkYXMgcGxhbmFzIFVUTSwgZWwgY3VhbCByZXByZXNlbnRhIGxvcyBwdW50b3MgZGVsIGdsb2JvIGVuIG1ldHJvcy4NCg0KTHVlZ28sIHNlIGNyZWEgbGEgbWF0cml6IGRlIGRpc3RhbmNpYXMgZW4gbWV0cm9zIGVudHJlIGNhZGEgY2l1ZGFkLg0KDQpBaG9yYSwgaGF5IHF1ZSBjb25zaWRlcmFyIGxvcyBjb3N0b3MgcGFyYSBwb2RlciBjcmVhciB1bmEgbWF0cml6IGRlIGNvc3RvcyBwYXJhIHJlc29sdmVyIGVsIHByb2JsZW1hIGRlIG9wdGltaXphY2nDs24uDQoNCkNvbiByZXNwZWN0byBhbCBjb3N0byBkZWwgY29tYnVzdGlibGUsIGVzdGUgZGVwZW5kZXLDoSBkZWwgdmVow61jdWxvIHF1ZSBlbCB2ZW5kZWRvciB1dGlsaXphcsOhIHBhcmEgcmVhbGl6YXIgbGFzIGVudHJlZ2FzLiBQYXJhIGVzdGUgcHJvYmxlbWEsIHNlIHV0aWxpemFyw6EgdW4gZnVyZ8OzbiBERlNLIEMzNSwgZWwgY3VhbCB0aWVuZSB1biBjb25zdW1vIGRlIGNvbWJ1c3RpYmxlIGRlIDcuNiBsaXRyb3MgYXByb3hpbWFkbyBwb3IgY2FkYSAxMDAgS20gZGUgcmVjb3JyaWRvLCBxdWUgc2UgcHVlZGUgdHJhZHVjaXIgZW4gMC4wMDAwNzYgbGl0cm9zIHBvciBjYWRhIDEgbWV0cm8gKERGU0ssIHMuZi4sIEVzcGVjaWZpY2FjaW9uZXMgRnVyZ29uIEMzNSkuIEFkaWNpb25hbG1lbnRlLCBzZSBjb25zaWRlcmEgZWwgcHJlY2lvIHByb21lZGlvIGRlIGxhIGdhc29saW5hIGVuIENvbG9tYmlhIHF1ZSwgc2VndW4gKExhIFJlcMO6YmxpY2EsIDIwMjUpLCB0aWVuZSB1biB2YWxvciBkZSBcJDE1LjgyNyBwZXNvcyBjb2xvbWJpYW5vcyBwb3IgZ2Fsw7NuLCBxdWUgc2UgcHVlZGUgdHJhZHVjaXIgZW4gXCQ0LjAyMiBwZXNvcyBjb2xvbWJpYW5vcyBwb3IgbGl0cm8gYXByb3hpbWFkYW1lbnRlLg0KDQpgYGB7cn0NCmdhc3RvX2xpdHJvX3Bvcl9tZXRybyA8LSAwLjAwMDA3Ng0KcHJlY2lvX2dhc29saW5hX3Bvcl9saXRybyA8LSA0LjAyMiANCmNvc3Rvc19jb21idXN0aWJsZSA8LSBkaXN0YW5jaWFzICogZ2FzdG9fbGl0cm9fcG9yX21ldHJvICogcHJlY2lvX2dhc29saW5hX3Bvcl9saXRybw0Kcm93bmFtZXMoY29zdG9zX2NvbWJ1c3RpYmxlKSA8LSBub21icmVfY2l1ZGFkZXMNCmNvbG5hbWVzKGNvc3Rvc19jb21idXN0aWJsZSkgPC0gbm9tYnJlX2NpdWRhZGVzDQpwcmludChjb3N0b3NfY29tYnVzdGlibGUpDQpgYGANCg0KQ29uc2lkZXJhbmRvIGVsIGNvc3RvIGRlIGxvcyBwZWFqZXMsIHNlIHVzYXLDoW4gbG9zIGRhdG9zIGRlIChBdXRvZmFjdCwgMjAyNCkgcGFyYSBjYWxjdWxhciBlbCB2YWxvciBwcm9tZWRpbyBkZSBjYWRhIHBlYWplIGRlIGxhcyBjaXVkYWRlcyBjb25zaWRlcmFkYXMgeSBzZSBhc3VtaXLDoSBxdWUgZWwgdmVuZGVkb3IgcGFnYXLDoSBlbCB2YWxvciBwcm9tZWRpbyBkZWwgcGVhamUgZGUgbGEgY2l1ZGFkIGRlIG9yaWdlbiB5IGRlIGxhIGNpdWRhZCBkZSBkZXN0aW5vIGV4YWN0YW1lbnRlIDEgdmV6IGNhZGEgcXVlIGxhcyByZWNvcnJhLg0KDQpQb3Igw7psdGltbywgc2UgZGViZSBkZSBjb25zaWRlcmFyIGVsIHNhbGFyaW8gcG9yIGhvcmFzIHByb21lZGlvIGRlIHVuIHZlbmRlZG9yIHF1ZSBoYWdhIGRpY2hvcyByZWNvcnJpZG9zIHBhcmEgZW50cmVnYXIgbG9zIHBlZGlkb3MuIEFkaWNpb25hbCBhIHNlciB2ZW5kZWRvciwgZXN0YSBwZXJzb25hIHJlYWxpemFyw6EgbGFzIGVudHJlZ2FzIHkgbGEgY29uZHVjY2nDs24gZGUgbGEgbWVyY2FuY8OtYSwgcG9yIGxvIHF1ZSB0YW1iacOpbiBoYXkgcXVlIGNvbnNpZGVyYXIgc3UgcGFnbyBjb21vIHRyYW5zcG9ydGlzdGEuIERpY2hvIGVzdG8sIHNlIHByb21lZGlhcm9uIHNhbGFyaW9zIGRlIHVuIHRyYW5zcG9ydGlzdGEgeSB1biB2ZW5kZWRvciBwYXJhIHBvZGVyIGRldGVybWluYXIgZWwgc2FsYXJpbyBmaW5hbCBkZSBsYSBwZXJzb25hLiBTZWfDum4gKFRhbGVudC5jb20sIHMuZi4sICpTYWxhcmlvIG1lZGlvIHBhcmEgVHJhbnNwb3J0ZSBEZSBDYXJnYSBlbiBDb2xvbWJpYSAyMDI1KikgeSAoVGFsZW50LmNvbSwgcy5mLiwgKlNhbGFyaW8gbWVkaW8gcGFyYSBWZW5kZWRvciBlbiBDb2xvbWJpYSAyMDI1KiksIHVuIHRyYW5zcG9ydGlzdGEgZ2FuYSBlbiBwcm9tZWRpbyBcJDkuMzQxIHBlc29zIGNvbG9tYmlhbm9zIGxhIGhvcmEgeSB1biB2ZW5kZWRvciBoYWNlIFwkNy4xNDQgbGEgaG9yYTsgcG9yIGxvIHRhbnRvLCBlbCBzYWxhcmlvIGEgdXRpbGl6YXIgc2Vyw6EgZWwgXCQ4LjI0MiBwZXNvcyBsYSBob3JhLg0KDQpBc3VtaWVuZG8gcXVlIGVsIHZlbmRlZG9yIGNvbmR1Y2lyw6EgYSB1bmEgdmVsb2NpZGFkIG1lZGlhIGRlIDUwIGttL2ggYWwgZMOtYSwgcXVlIHNlIHBvZHLDrWFuIHRyYWR1Y2lyIGVuIDUwMDAwIG0vaCBwYXJhIGZhY2lsaXRhciBjw6FsY3Vsb3MsIHNlIHByb2NlZGUgYSBjYWxjdWxhciBlbCB0aWVtcG8gZGUgdmlhamUgeSwganVudG8gY29uIGVzdG8sIGN1w6FudG8gc2UgbGUgcGFnYXLDoSBhbCB2ZW5kZWRvciBwb3IgY2FkYSB2aWFqZS4NCg0KYGBge3J9DQp2ZWxvY2lkYWRfbWVkaWFfbWV0cm9zX3Bvcl9ob3JhIDwtIDUwMDAwDQpzYWxhcmlvX3ZlbmRlZG9yX2NvbG9tYmlhIDwtIDcxNDQNCnNhbGFyaW9fdHJhbnNwb3J0aXN0YV9jb2xvbWJpYSA8LSA5MzQxDQpzYWxhcmlvX2ZpbmFsIDwtIChzYWxhcmlvX3ZlbmRlZG9yX2NvbG9tYmlhICsgc2FsYXJpb190cmFuc3BvcnRpc3RhX2NvbG9tYmlhKS8yDQpjb3N0b3NfdmVuZGVkb3IgPC0gZGlzdGFuY2lhcyooMS92ZWxvY2lkYWRfbWVkaWFfbWV0cm9zX3Bvcl9ob3JhKSpzYWxhcmlvX2ZpbmFsDQpyb3duYW1lcyhjb3N0b3NfdmVuZGVkb3IpIDwtIG5vbWJyZV9jaXVkYWRlcw0KY29sbmFtZXMoY29zdG9zX3ZlbmRlZG9yKSA8LSBub21icmVfY2l1ZGFkZXMNCmNvc3Rvc192ZW5kZWRvcg0KDQpgYGANCg0KQ29uY2x1eWVuZG8sIGxhIG1hdHJpeiBkZSBjb3N0b3Mgc2ltcGxlbWVudGUgc2Vyw61hIGVsIHJlc3VsdGFkbyBkZSBsYSBzdW1hIGRlIGxhcyBhbnRlcmlvcmVzIG1hdHJpY2VzIHByZXZpYW1lbnRlIGRlZmluaWRhcywgeSBlc3RhIHNlcsOhIGxhIG1hdHJpeiBxdWUgc2UgdXRpbGl6YXLDoW4gZW4gbG9zIGRpc3RpbnRvcyBhbGdvcml0bW9zIHBhcmEgZW5jb250cmFyIGxhIG1lam9yIHJ1dGEuDQoNCjxhIG5hbWU9ImlvMi4yLiI+PC9hPg0KDQojIyAyLjIgSW1wbGVtZW50YWNpw7NuIE3DqXRvZG8gZGUgQ29sb25pYSBkZSBob3JtaWdhcw0KDQpBIGNvbnRpbnVhY2nDs24sIHNlIGltcGxlbWVudGEgZWwgbcOpdG9kbyBkZSBjb2xvbmlhIGRlIGhvcm1pZ2FzIHBhcmEgZW5jb250cmFyDQoNCmBgYHtyfQ0KIyBOw7ptZXJvIGRlIGNpdWRhZGVzDQpuX2NpdWRhZGVzIDwtIDEzDQoNCiMgRnVuY2nDs24gcGFyYSBub3JtYWxpemFyIGxhIG1hdHJpeiBkZSBjb3N0b3MsIHlhIHF1ZSBzZWFyY2hfdG91cl9hbnRzDQojIGZ1bmNpb25hIGNvbiB2YWxvcmVzIG5vcm1hbGl6YWRvcy4NCiMgU2Ugb3B0w7MgcG9yIHVzYXIgbm9ybWFsaXphY2nDs24genNjb3JlLg0Kbm9ybWFsaXplX3pzY29yZSA8LSBmdW5jdGlvbihtKSB7DQogIChtIC0gbWVhbihtKSkgLyBzZChtKQ0KfQ0KDQojIE5vcm1hbGl6YWNpw7NuIGRlIG1hdHJpeiBkZSBjb3N0b3MNCm1hdHJpel9jb3N0b3Nfbm9ybWFsaXphZGEgPC0gbm9ybWFsaXplX3pzY29yZShtYXRyaXpfY29zdG9zKQ0KDQojIEVqZWN1Y2nDs24gZGVsIG3DqXRvZG8gZGUgY29sb25pYSBkZSBob3JtaWdhcw0KcmVjb3JyaWRvX29wdGltaXphZG8gPC0gc2VhcmNoX3RvdXJfYW50cyhtYXRyaXpfY29zdG9zX25vcm1hbGl6YWRhLCBuX2NpdWRhZGVzLCBLID0gODAsIE4gPSA0MCwgbG9nPVRSVUUpDQpwcmludCgiTUVKT1IgUkVDT1JSSURPOiAiKQ0KcHJpbnQocmVjb3JyaWRvX29wdGltaXphZG8kdG91cikNCmBgYA0KDQo8IS0tIFRPRE86IEZhbHRhIE1hcGEgZGUgbGEgUnV0YXMgLS0+DQoNCjxhIG5hbWU9ImlvNS4iPjwvYT4NCg0KIyBDb25jbHVzacOzbiBHZW5lcmFsDQoNCkFsIHRlcm1pbmFyIGVzdGUgdHJhYmFqbywgbGEgdmVyZGFkIGVzIHF1ZSB1bm8gc2UgZGEgY3VlbnRhIGRlIGxvIHBvZGVyb3NvcyB5IGZsZXhpYmxlcyBxdWUgcHVlZGVuIHNlciBsb3MgYWxnb3JpdG1vcyBiaW9pbnNwaXJhZG9zIGN1YW5kbyBzZSB0cmF0YSBkZSByZXNvbHZlciBwcm9ibGVtYXMgZGUgb3B0aW1pemFjacOzbiwgdGFudG8gbnVtw6lyaWNvcyBjb21vIGNvbWJpbmF0b3Jpb3MuIEVuIGxhIHByaW1lcmEgcGFydGUsIGV4cGVyaW1lbnRhbW9zIGNvbiBmdW5jaW9uZXMgY2zDoXNpY2FzIGNvbW8gUm9zZW5icm9jayB5IFJhc3RyaWdpbiB1c2FuZG8gbcOpdG9kb3MgY29tbyBlbCBkZXNjZW5zbyBkZSBncmFkaWVudGUsIFBTTyB5IGFsZ29yaXRtb3MgZ2Vuw6l0aWNvcy4gTG8gaW50ZXJlc2FudGUgZnVlIHZlciBjw7NtbyBsb3MgbcOpdG9kb3MgYmlvaW5zcGlyYWRvcywgaW5zcGlyYWRvcyBlbiBsYSBuYXR1cmFsZXphIHkgZWwgY29tcG9ydGFtaWVudG8gY29sZWN0aXZvLCBsb2dyYW4gZXNjYXBhciBkZSBsb3MgbcOtbmltb3MgbG9jYWxlcyB5IGV4cGxvcmFyIGVsIGVzcGFjaW8gZGUgc29sdWNpb25lcyBkZSB1bmEgZm9ybWEgbXVjaG8gbcOhcyBjcmVhdGl2YSB5IHJvYnVzdGEgcXVlIGxvcyBtw6l0b2RvcyB0cmFkaWNpb25hbGVzLiBObyBzb2xvIGVzIGN1ZXN0acOzbiBkZSBlbmNvbnRyYXIgZWwgbcOtbmltbywgc2lubyBkZSBjw7NtbyBzZSBsbGVnYSBhIMOpbDogbGEgZGl2ZXJzaWRhZCwgbGEgY29sYWJvcmFjacOzbiB5IGxhIGFkYXB0YWNpw7NuIGNvbnN0YW50ZSBoYWNlbiBsYSBkaWZlcmVuY2lhLg0KDQpQZXJvIGxhIGNvc2Egbm8gc2UgcXVlZMOzIGFow60uIEVuIGxhIHNlZ3VuZGEgcGFydGUsIG5vcyBtZXRpbW9zIGRlIGxsZW5vIGVuIGxhIG9wdGltaXphY2nDs24gY29tYmluYXRvcmlhLCBlbmZyZW50w6FuZG9ub3MgYWwgY2zDoXNpY28gcHJvYmxlbWEgZGVsIHZpYWphbnRlIHVzYW5kbyBjb2xvbmlhIGRlIGhvcm1pZ2FzLiBBcXXDrSwgbGEgaW5zcGlyYWNpw7NuIGVuIGVsIGNvbXBvcnRhbWllbnRvIGRlIGxhcyBob3JtaWdhcyBwYXJhIGVuY29udHJhciBydXRhcyDDs3B0aW1hcyBlbiBsYSBuYXR1cmFsZXphIHNlIHRyYWR1am8gZW4gdW4gYWxnb3JpdG1vIGNhcGF6IGRlIGVuY29udHJhciBzb2x1Y2lvbmVzIGVmaWNpZW50ZXMgZW4gcHJvYmxlbWFzIGRvbmRlIGxhIGNhbnRpZGFkIGRlIGNvbWJpbmFjaW9uZXMgcG9zaWJsZXMgZXMgYWJydW1hZG9yYS4gRXMgaW1wcmVzaW9uYW50ZSB2ZXIgY8OzbW8sIGEgdHJhdsOpcyBkZSBsYSBjb29wZXJhY2nDs24geSBsYSBjb211bmljYWNpw7NuIGluZGlyZWN0YSAoY29tbyBsYXMgZmVyb21vbmFzIGVuIGVsIGNhc28gZGUgbGFzIGhvcm1pZ2FzKSwgZWwgc2lzdGVtYSBlbmN1ZW50cmEgY2FtaW5vcyBjYWRhIHZleiBtZWpvcmVzLCBpbmNsdXNvIGN1YW5kbyBlbCBlc3BhY2lvIGRlIGLDunNxdWVkYSBlcyBnaWdhbnRlc2NvLg0KDQpFbiByZXN1bWVuLCBlc3RlIHRyYWJham8gbm8gc29sbyBub3MgcGVybWl0acOzIGNvbXBhcmFyIHkgZW50ZW5kZXIgZGlmZXJlbnRlcyBhbGdvcml0bW9zLCBzaW5vIHF1ZSB0YW1iacOpbiBub3MgbW9zdHLDsyBsYSBpbXBvcnRhbmNpYSBkZSBwZW5zYXIgImZ1ZXJhIGRlIGxhIGNhamEiIHkgZGUgaW5zcGlyYXJub3MgZW4gbGEgbmF0dXJhbGV6YSBwYXJhIHJlc29sdmVyIHByb2JsZW1hcyBjb21wbGVqb3MuIExvcyBhbGdvcml0bW9zIGJpb2luc3BpcmFkb3Mgbm8gc29uIHVuYSByZWNldGEgbcOhZ2ljYSwgcGVybyBzw60gdW5hIGhlcnJhbWllbnRhIHBvZGVyb3NhIHkgYWRhcHRhYmxlLCBjYXBheiBkZSBlbmZyZW50YXIgZGVzYWbDrW9zIHRhbnRvIGVuIGVsIG11bmRvIGNvbnRpbnVvIGNvbW8gZW4gZWwgZGlzY3JldG8uIEFkZW3DoXMsIHRyYWJhamFyIGNvbiBlc3RvcyBtw6l0b2RvcyBmb21lbnRhIGxhIGNyZWF0aXZpZGFkLCBlbCB0cmFiYWpvIGVuIGVxdWlwbyB5IHVuYSB2aXNpw7NuIGludGVyZGlzY2lwbGluYXJpYSBxdWUsIHNpbiBkdWRhLCBlcyBjbGF2ZSBlbiBsYSBjaWVuY2lhIHkgbGEgaW5nZW5pZXLDrWEgZGUgaG95Lg0KDQo8YSBuYW1lPSJpdTMuIj48L2E+DQoNCiMgUmVwb3J0ZSBkZSBjb250cmlidWNpw7NuIGluZGl2aWR1YWwNCg0KIyMgLSBMZW9uYXJkbyBGZWRlcmljbyBDb3JvbmEgVG9ycmVzDQoNCi0gICBBcG95byBlbiByZWRhY2Npw7NuIHkgcmVhbGl6YWNpw7NuIGRlIGltcGxlbWVudGFjaW9uZXMgZGUgc2VjY2nDs24gIk3DqXRvZG8gZGUgYWxnb3JpdG1vcyBldm9sdXRpdm9zIi4NCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs24gZGUgaW1wbGVtZW50YWNpb25lcyBkZSBncmFmaWNhY2nDs24gZW4gUGFydGUgMiBkZWwgcmVwb3J0ZS4NCg0KLSAgIELDunNxdWVkYSBlIGludmVzdGlnYWNpw7NuIGRlIGZ1bmNpb25lcyBkZSBwcnVlYmEgYSB1dGlsaXphci4NCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs24geSByZWFsaXphY2nDs24gZGUgaW1wbGVtZW50YWNpb25lcyBkZSBzZWNjacOzbiAiU2VsZWNjacOzbiBlIGltcGxlbWVudGFjacOzbiBkZSBsYXMgZnVuY2lvbmVzIGRlIHBydWViYSIuDQoNCiMjIC0gRGF2aWQgRXNjb2JhciBSdWl6DQoNCi0gICBEZWZpbmljacOzbiB5IGVzY3JpdHVyYSBkZSBlc3RydWN0dXJhIGRlbCByZXBvcnRlLg0KDQotICAgQXBveW8gZW4gcmVkYWNjacOzbiB5IHJlYWxpemFjacOzbiBkZSBpbXBsZW1lbnRhY2lvbmVzIGRlIHNlY2Npw7NuICJTZWxlY2Npw7NuIGUgaW1wbGVtZW50YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZGUgcHJ1ZWJhIi4NCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs255IHJlYWxpemFjacOzbiBkZSBpbXBsZW1lbnRhY2lvbmVzIGRlIHNlY2Npw7NuICJNw6l0b2RvIGRlIG9wdGltaXphY2nDs24gZGUgcGFydMOtY3VsYXMiLg0KDQotICAgQXBveW8gZW4gcmVkYWNjacOzbiB5IHJlYWxpemFjacOzbiBkZSBpbXBsZW1lbnRhY2lvbmVzIGRlIG3DqXRvZG9zLCBwbGFudGVhbWllbnRvIHkgcHJlcHJvY2VzYW1pZW50byBkZSBkYXRvcyBQYXJ0ZSAyIGRlbCByZXBvcnRlLg0KDQojIyAtIEpvaGFuIFNlYmFzdGnDoW4gUm9ibGVzIFJpbmPDs24NCg0KLSAgIEltcGxlbWVudGFjacOzbiB5IHBydWViYSBkZWwgbcOpdG9kbyBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsIGVuIFIgcGFyYSBmdW5jaW9uZXMgZGUgUm9zZW5icm9jayB5IFJhc3RyaWdpbsKgZW7CoDJEwqB5wqAzRC4NCg0KLSAgIEFuw6FsaXNpcyBkZSByZXN1bHRhZG9zIG51bcOpcmljb3MgeSBncsOhZmljb3MuDQoNCi0gICBBcG95byBlbiByZWRhY2Npw7NuIGRlIHNlY2Npw7NuIGRlbCBjb250ZW5pZG8gdMOpY25pY28gcmVsYWNpb25hZG8gY29uIGVzdGUgbcOpdG9kbyBkZSBldm9sdWNpb24gZGlmZXJlbmNpYWzCoGVuwqBlbMKgaW5mb3JtZS4NCg0KIyMgLSBTZWJhc3RpYW4gU290byBBcmNpbGENCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs24geSByZWFsaXphY2nDs24gZGUgaW1wbGVtZW50YWNpb25lcyBkZSBzZWNjacOzbiAiTcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIHBvciBkZXNjZW5zbyBkZSBncmFkaWVudGUiDQoNCi0gICBBcG95byBlbiByZWRhY2Npw7NuIGRlIHNlY2Npw7NuICJTZWxlY2Npw7NuIGUgaW1wbGVtZW50YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZGUgcHJ1ZWJhIi4NCg0KPGEgbmFtZT0iaXU0LiI+PC9hPg0KDQojIFJlcG9zaXRvcmlvIGRlIEdpdEh1YiBkZWwgcHJveWVjdG8NCg0KW2h0dHBzOi8vZ2l0aHViLmNvbS9kcnVpejM1L1JOQUJJMjAyNS0xLUVxdWlwbzMvXShodHRwczovL2dpdGh1Yi5jb20vZHJ1aXozNS9STkFCSTIwMjUtMS1FcXVpcG8zL3RyZWUvbWFpbil7LnVyaX0NCg0KPGEgbmFtZT0iaXU1LiI+PC9hPg0KDQojIEJpYmxpb2dyYWbDrWENCg0KQXV0b2ZhY3QuICgyMDI0KS4gKlBlYWplcyBlbiBDb2xvbWJpYTogQ29ub2NlIHN1cyB1YmljYWNpb25lcyB5IHByZWNpb3MgMjAyNC4qIDxodHRwczovL3d3dy5hdXRvZmFjdC5jb20uY28vYmxvZy9taS1jYXJyby9wZWFqZXMvcGVhamVzLWNvbG9tYmlhLXByZWNpb3M+DQoNCkRGU0suIChzLmYuKS4gKkVzcGVjaWZpY2FjaW9uZXMgRnVyZ29uIEMzNS4qIFJlY3VwZXJhZG8gZWwgMiBkZSBtYXlvIGRlIDIwMjUsIGRlIDxodHRwOi8vc3RhdGljLm11bHRpYXZpc28uY29tL3ZlaGljbGUvc3BlY3MvMjItVlJaQzU2NFhMQkU2LWRmc2stb3Ryb3MtbW9kZWxvcy0yMDE3LWZ1cmdvbi1jMzUucGRmPg0KDQpMYSBSZXDDumJsaWNhLiAoMjAyNSkuICpQUkVDSU8gREUgTEEgR0FTT0xJTkEuKiBSZWN1cGVyYWRvIGVsIDIgZGUgbWF5byBkZSAyMDI1LCBkZSA8aHR0cHM6Ly93d3cubGFyZXB1YmxpY2EuY28vcHJlY2lvLWRlLWxhLWdhc29saW5hPg0KDQpNb2xnYSwgU211dG5pY2tpLiAoMjAwNSkuICpUZXN0IGZ1bmN0aW9ucyBmb3Igb3B0aW1pemF0aW9uIG5lZWRzLiogPGh0dHBzOi8vcm9iZXJ0bWFya3Mub3JnL0NsYXNzZXMvRU5HUjUzNTgvUGFwZXJzL2Z1bmN0aW9ucy5wZGY+DQoNClRhbGVudC5jb20uIChzLmYuKS4gKlNhbGFyaW8gbWVkaW8gcGFyYSBUcmFuc3BvcnRlIERlIENhcmdhIGVuIENvbG9tYmlhIDIwMjUqLiBSZWN1cGVyYWRvIGVsIDIgZGUgbWF5byBkZSAyMDI1LCBkZSA8aHR0cHM6Ly9jby50YWxlbnQuY29tL3NhbGFyeT9qb2I9dHJhbnNwb3J0ZStkZStjYXJnYT4NCg0KVGFsZW50LmNvbS4gKHMuZi4pLiAqU2FsYXJpbyBtZWRpbyBwYXJhIFZlbmRlZG9yIGVuIENvbG9tYmlhIDIwMjUqLiBSZWN1cGVyYWRvIGVsIDIgZGUgbWF5byBkZSAyMDI1LCBkZSA8aHR0cHM6Ly9jby50YWxlbnQuY29tL3NhbGFyeT9qb2I9dmVuZGVkb3I+DQoNCldpa2lwZWRpYS4gKHMuZi4pLiAqVGVzdCBmdW5jdGlvbnMgZm9yIG9wdGltaXphdGlvbiouIFdpa2lwZWRpYS4gUmVjdXBlcmFkbyBlbCAyIGRlIG1heW8gZGUgMjAyNSwgZGUgPGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Rlc3RfZnVuY3Rpb25zX2Zvcl9vcHRpbWl6YXRpb24+DQoNCldpa2lwZWRpYS4gKHMuZi4pLiAqUm9zZW5icm9jayBmdW5jdGlvbiouIFdpa2lwZWRpYS4gUmVjdXBlcmFkbyBlbCAyIGRlIG1heW8gZGUgMjAyNSwgZGUgW2h0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Jvc2VuYnJvY2tcX10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUm9zZW5icm9ja19mdW5jdGlvbil7LnVyaX0NCg0KV2lraXBlZGlhLiAocy5mLikuICpSYXN0cmlnaW4gZnVuY3Rpb24qLiBXaWtpcGVkaWEuIFJlY3VwZXJhZG8gZWwgMiBkZSBtYXlvIGRlIDIwMjUsIGRlIDxodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9SYXN0cmlnaW5fZnVuY3Rpb24+DQoNClguLVMuIFlhbmcsIFRlc3QgcHJvYmxlbXMgaW4gb3B0aW1pemF0aW9uLCBpbjogRW5naW5lZXJpbmcgT3B0aW1pemF0aW9uOiBBbiBJbnRyb2R1Y3Rpb24gd2l0aCBNZXRhaGV1cmlzdGljIEFwcGxpY2F0aW9ucyAoRWRzIFhpbi1TaGUgWWFuZyksIEpvaG4gV2lsZXkgJiBTb25zLCAoMjAxMCkNCg==