1. Introducción

La clasificación de imágenes es objeto de estudio y aplicación en múltiples áreas del conocimiento. En el caso más simple, se busca tomar una decisión con base en la información que contiene una imagen (Murcia, 2006). En este reporte se aborda el ejercicio de clasificar imágenes de sujetos con lentes/gafas utilizando técnicas de aprendizaje estadístico supervisadas.

2. Datos

El conjunto de datos se obtuvo del curso T81-855: Applications of Deep Learning dirigido por el profesor Jeff Heaton, en la Washington University in St. Louis (WUSTL). Los datos, están alojados en un reto de Kaggle del año 2020, en donde se encuentran 5000 imágenes producidas artificialmente a través de una red neuronal adversa generativa (GAN). Se pueden encontrar personas con lentes y personas sin lentes. Dentro de las imágenes de personas con lentes se hallan 6 tipos de lentes. La figura 1 presenta una muestra de los tipos de lentes que se pueden encontrar en el conjunto de datos:

Figura 1. Tipos de lentes

El conjunto de datos es revisado y se eliminan imágenes que se consideran podrían pertubar el aprendizaje del modelo, en éstas se hallaban personas con lentes a medio construir, dos rostros en una misma imagen y otras con detalles similares. Finalmente el conjunto de datos queda con 454 imágenes de sujetos con lentes y 618 de sujetos sin lentes. También, se eligió esta cantidad de datos por la capacidad y velocidad de procesamiento que se tiene al alcance.

2.1. Procesamiento

Las imágenes se pueden vectorizar. Es decir, vista la imagen como una matriz, sus columnas se ubican consecutivamente una debajo de la otra hasta obtener un vector. Luego, los vectores serán las filas de una matriz de datos con la información de intensidades para cada píxel en las respectivas imágenes.

Para describir una forma de comparar los vectores, usaremos una muestra de 6 sujetos (3 con gafas y 3 sin gafas). Las figuras serán analizadas con el paquete EBImage

Se puede evidenciar a continuación una figura de un hombre sin gafas de una de las imágenes del modelo.

Igualmente, se muestra una figura de un hombre con gafas en una de las imágenes del modelo.

Para facilitar la visualización y vectorización, se procede a convertir las imágenes en una escala de grises para no trabajar con el modelo de color CMYK* (modelo de color sustractivo que se utiliza en la impresión en colores, es la versión moderna y más precisa del antiguo modelo tradicional de coloración).

Por ende, las imágenes presentadas ahora se van a visualizar en espectro de grises.

Ya que todas las figuras fueron creadas por computadora, los lentes se ubicarán casi en la misma posición, por esa razón se delimitaron las imágenes.

Inclusive, se podría cortar solamente el septo nasal que es donde se marcan más los lentes para diferenciar las personas que usan o no gafas. El acercamiento o recorte para centrarnos en el secto nasal de las imágenes, se delimita a través de las coordenadas especificadas para cada imagen en la función definida en el modelo como se muestra a continuación: img_crop = img_g[440:590,440:580] con esta línea se delimita el área de la imagen que queremos tomar.

Se presentan unos histogramas con el fin de ver por medio de sus frecuencias si hay diferencias entre imágenes con y sin gafas. En los siguientes histogramas se busca observar la cantidad de píxeles (21.291 píxeles) versus la intensidad (0 a 1).

Finalmente, se evidenció que habían diferencias entre los histogramas de personas con o sin gafas, ya que se aprecia que hay un perfil diferente entre la personas que tienen gafas y las que no. Para ello, se utilizó la intensidad de luz que está en una escala de 0 a 1, donde el 0 representa la tonalidad más oscura de la imagen y el 1 la más clara. Es decir, si en la fotografía existen más píxeles en la parte oscura, entonces la frecuencia allí representada en el histograma será mayor.

Para las imágenes que no tienen lentes, la frecuencia está hacia el lado derecho, es decir, que la imagen tiene más intensidad de luz. Para las imágenes que tienen lentes oscuros, la frecuencia está hacia el lado izquierdo, es decir, que la imagen tiene más píxeles oscuros. Y finalmente, para las imágenes que tienen lentes transparentes, la frecuencia tiene más variabilidad pero aún así se puede notar que son diferentes a las demás.

3. Modelo

Con la intención de buscar una forma para poder comparar los vectores se crea una matriz con datos de intensidad, en donde, se establecen los cuartiles del histograma para obtener un perfil de comparación. Y además, con apoyo de una función cíclica, la cual comienza en 1 hasta el tamaño de la lista, se crea una matriz(representa las fotos con gafas) que finalmente se almacena en un archivo csv.

Se realiza el mismo proceso anterior para el caso de fotos sin gafas, que igualmente dicha matriz generada se almacena en otro archivo csv.

En este modelo, generamos 200 valores numéricos para cada imagen recortada, donde dichos valores representan la cantidad de píxeles.

A continuación se muestran los valores divididos en rangos con respecto a su nivel de intensidad de luz, para así tener más resolución en los resultados.
Tabla 1. Información de rangos de intensidad de fotos con gafas
X values face.10.png face.100.png face.101.png face.103.png face.107.png face.109.png face.111.png face.112.png face.116.png face.117.png face.12.png face.121.png face.123.png face.124.png face.126.png face.127.png face.129.png face.130.png face.131.png face.133.png face.135.png face.136.png face.137.png face.138.png face.14.png face.142.png face.145.png face.146.png face.148.png face.149.png face.15.png face.153.png face.155.png face.156.png face.158.png face.159.png face.161.png face.162.png face.163.png face.164.png face.165.png face.166.png face.17.png face.173.png face.175.png face.176.png face.178.png face.179.png face.180.png face.183.png face.184.png face.185.png face.186.png face.187.png face.188.png face.19.png face.190.png face.191.png face.195.png face.198.png face.2.png face.201.png face.203.png face.204.png face.205.png face.206.png face.207.png face.208.png face.211.png face.212.png face.214.png face.215.png face.219.png face.220.png face.221.png face.222.png face.224.png face.225.png face.229.png face.23.png face.232.png face.233.png face.234.png face.235.png face.236.png face.237.png face.238.png face.240.png face.241.png face.244.png face.245.png face.247.png face.25.png face.251.png face.252.png face.253.png face.255.png face.256.png face.257.png face.258.png face.260.png face.261.png face.262.png face.263.png face.265.png face.266.png face.267.png face.268.png face.27.png face.270.png face.271.png face.273.png face.274.png face.275.png face.276.png face.278.png face.279.png face.28.png face.281.png face.282.png face.283.png face.284.png face.286.png face.287.png face.290.png face.291.png face.292.png face.294.png face.295.png face.296.png face.297.png face.3.png face.300.png face.302.png face.303.png face.306.png face.309.png face.311.png face.312.png face.315.png face.316.png face.317.png face.32.png face.321.png face.323.png face.324.png face.326.png face.327.png face.329.png face.33.png face.330.png face.331.png face.332.png face.333.png face.334.png face.335.png face.336.png face.341.png face.342.png face.343.png face.344.png face.345.png face.348.png face.349.png face.35.png face.350.png face.352.png face.354.png face.357.png face.358.png face.36.png face.360.png face.361.png face.362.png face.363.png face.364.png face.367.png face.368.png face.369.png face.370.png face.372.png face.373.png face.374.png face.375.png face.376.png face.377.png face.378.png face.380.png face.382.png face.383.png face.384.png face.385.png face.387.png face.388.png face.390.png face.392.png face.393.png face.394.png face.395.png face.396.png face.397.png face.399.png face.402.png face.403.png face.405.png face.406.png face.407.png face.408.png face.41.png face.410.png face.413.png face.416.png face.417.png face.419.png face.42.png face.420.png face.422.png face.427.png face.428.png face.43.png face.430.png face.433.png face.437.png face.438.png face.440.png face.444.png face.446.png face.447.png face.448.png face.449.png face.450.png face.452.png face.454.png face.456.png face.457.png face.458.png face.459.png face.46.png face.460.png face.463.png face.464.png face.465.png face.467.png face.468.png face.469.png face.470.png face.472.png face.473.png face.475.png face.477.png face.483.png face.484.png face.489.png face.490.png face.492.png face.494.png face.495.png face.497.png face.50.png face.500.png face.502.png face.506.png face.508.png face.51.png face.510.png face.511.png face.512.png face.514.png face.515.png face.516.png face.517.png face.520.png face.521.png face.528.png face.529.png face.53.png face.532.png face.533.png face.534.png face.535.png face.539.png face.540.png face.543.png face.546.png face.547.png face.55.png face.551.png face.552.png face.553.png face.555.png face.557.png face.559.png face.56.png face.561.png face.562.png face.563.png face.564.png face.566.png face.567.png face.568.png face.569.png face.570.png face.571.png face.572.png face.573.png face.576.png face.577.png face.579.png face.580.png face.587.png face.588.png face.590.png face.591.png face.596.png face.597.png face.6.png face.60.png face.600.png face.602.png face.604.png face.608.png face.61.png face.612.png face.614.png face.615.png face.616.png face.617.png face.618.png face.619.png face.62.png face.620.png face.621.png face.623.png face.627.png face.628.png face.630.png face.631.png face.633.png face.634.png face.635.png face.638.png face.639.png face.640.png face.644.png face.645.png face.647.png face.648.png face.649.png face.65.png face.650.png face.651.png face.652.png face.654.png face.656.png face.658.png face.659.png face.66.png face.660.png face.661.png face.662.png face.663.png face.664.png face.665.png face.667.png face.674.png face.675.png face.676.png face.679.png face.680.png face.681.png face.683.png face.684.png face.688.png face.689.png face.691.png face.692.png face.693.png face.694.png face.695.png face.696.png face.698.png face.699.png face.7.png face.70.png face.703.png face.704.png face.705.png face.708.png face.710.png face.711.png face.712.png face.714.png face.716.png face.717.png face.719.png face.72.png face.720.png face.721.png face.725.png face.726.png face.727.png face.728.png face.73.png face.730.png face.731.png face.732.png face.734.png face.735.png face.738.png face.739.png face.74.png face.741.png face.745.png face.749.png face.750.png face.751.png face.752.png face.753.png face.758.png face.76.png face.761.png face.765.png face.766.png face.767.png face.768.png face.769.png face.77.png face.770.png face.771.png face.772.png face.774.png face.775.png face.776.png face.777.png face.78.png face.780.png face.781.png face.783.png face.784.png face.785.png face.788.png face.79.png face.790.png face.8.png face.80.png face.82.png face.83.png face.85.png face.86.png face.88.png face.94.png face.95.png face.96.png face.97.png
1 0-0.005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
2 0.005-0.01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 14 0 0 0 0 0 0 0 5 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 2 0 1 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 25 0 0 0 0 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 5 0 0 0
3 0.01-0.015 0 0 0 0 0 0 0 0 0 4 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 1 0 0 0 0 19 0 0 0 0 2 0 0 3 0 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 6 0 0 0 0 0 0 1 9 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 3 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 3 0 0 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 25 0 6 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 2 0 2 1 0 0 0 0 22 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 0 0 0 0 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 6 0 0 0 2 0 0 0 0 0 0 0 21 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 5 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 22 0 0 0 1 0 1 0 0 0 0 6 0 0 0 0 0 0 0 0 0 1 0 0 3 0 0 0 0 0 0 8 0 0 1 0 0 0 3 3 0 0 4 0 1 0 0 0 0 7 0 0 0
4 0.015-0.02 0 0 0 0 0 0 0 0 0 4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 5 0 0 8 0 0 0 0 36 0 0 0 0 3 0 0 5 0 11 0 1 0 0 2 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 20 0 0 1 0 0 0 3 15 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 1 0 0 0 8 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 5 0 5 0 11 0 0 0 4 50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 3 0 0 0 0 0 0 1 0 0 0 3 0 0 0 0 0 0 0 0 6 5 0 0 2 0 0 0 3 0 72 0 5 0 0 0 0 0 0 0 0 0 3 0 0 0 0 2 1 3 0 9 0 1 22 0 0 0 0 19 0 0 0 0 0 4 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 2 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 97 0 0 0 0 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 0 1 0 0 3 0 2 0 0 0 4 0 0 0 1 0 0 0 0 0 0 0 98 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 1 0 0 0 0 0 0 0 0 1 0 0 10 0 0 0 0 0 0 1 0 1 0 0 0 1 0 2 61 3 0 0 0 0 10 0 0 0 0 23 0 0 3 0 0 1 0 0 0 0 0 4 7 0 0 0 0 0 0 42 0 0 0 0 0 0 2 2 0 0 2 0 1 0 0 0 0 3 0 0 0
5 0.02-0.025 0 0 0 0 0 0 0 0 0 6 0 1 0 2 0 0 0 0 0 0 0 0 0 0 0 0 49 0 0 0 0 0 0 2 3 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 10 0 1 0 0 0 6 0 0 15 0 0 0 0 178 2 2 0 0 5 0 0 1 0 56 1 1 0 0 8 73 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 55 0 0 4 1 0 0 3 16 0 0 3 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 1 2 0 0 2 0 3 0 1 1 17 0 1 4 6 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 32 0 15 0 10 0 0 0 10 154 0 0 0 0 0 2 1 0 0 0 0 0 0 0 1 0 1 0 0 3 0 3 0 0 0 0 0 0 0 0 5 0 0 0 0 0 1 0 0 5 30 1 0 0 0 2 1 93 0 127 0 13 0 0 0 0 9 0 0 0 0 96 0 0 0 1 1 1 3 0 14 0 3 115 0 0 0 0 34 0 0 0 0 0 6 13 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 2 3 0 0 1 1 3 0 0 0 0 8 0 0 0 0 0 8 0 0 0 1 0 1 0 0 0 324 0 0 0 0 37 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 13 7 0 0 0 4 0 6 0 0 0 5 0 0 0 2 0 0 0 0 0 0 0 233 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 2 1 0 0 12 0 0 6 0 0 2 0 0 0 0 0 1 0 0 10 0 0 0 0 0 0 3 0 4 0 4 1 0 1 4 232 3 0 0 1 0 10 0 0 0 0 148 0 0 4 0 0 0 3 0 0 1 0 5 31 0 0 0 0 0 0 113 1 0 0 1 0 1 2 4 0 0 3 0 12 0 0 0 3 3 0 0 0
Tabla 2. Información de rangos de intensidad de fotos sin gafas
X values face.1.png face.1000.png face.1004.png face.1007.png face.1009.png face.1010.png face.1015.png face.1016.png face.1018.png face.1019.png face.102.png face.1020.png face.1021.png face.1022.png face.1024.png face.1025.png face.1026.png face.1027.png face.1028.png face.1032.png face.1035.png face.1036.png face.1037.png face.1038.png face.104.png face.1041.png face.1043.png face.1048.png face.105.png face.1050.png face.1051.png face.1054.png face.1055.png face.1057.png face.1058.png face.1059.png face.106.png face.1060.png face.1062.png face.1063.png face.1065.png face.1067.png face.1072.png face.1073.png face.1075.png face.1077.png face.1078.png face.1079.png face.108.png face.1081.png face.1084.png face.1085.png face.1090.png face.1093.png face.1094.png face.1095.png face.11.png face.110.png face.1102.png face.1103.png face.1106.png face.1108.png face.1111.png face.1113.png face.1118.png face.1121.png face.1125.png face.1127.png face.1128.png face.1129.png face.113.png face.1131.png face.1133.png face.1134.png face.1135.png face.1136.png face.1138.png face.114.png face.1142.png face.1144.png face.1145.png face.1148.png face.115.png face.1153.png face.1155.png face.1156.png face.1157.png face.1158.png face.1159.png face.1160.png face.1161.png face.1167.png face.1170.png face.1172.png face.1173.png face.1174.png face.1176.png face.1177.png face.1178.png face.118.png face.1180.png face.1182.png face.1183.png face.1185.png face.1186.png face.1188.png face.119.png face.1190.png face.1191.png face.1194.png face.1195.png face.1196.png face.120.png face.1201.png face.1203.png face.1207.png face.1209.png face.1210.png face.1211.png face.1217.png face.1218.png face.1219.png face.122.png face.1220.png face.1222.png face.1225.png face.1227.png face.1230.png face.1234.png face.1235.png face.1236.png face.1237.png face.1238.png face.1240.png face.1245.png face.1246.png face.1247.png face.1248.png face.1249.png face.125.png face.1252.png face.1253.png face.1258.png face.1259.png face.1261.png face.1263.png face.1267.png face.1268.png face.1269.png face.1271.png face.1273.png face.1275.png face.1276.png face.1279.png face.128.png face.1282.png face.1283.png face.1284.png face.1286.png face.1287.png face.1290.png face.1293.png face.1294.png face.1295.png face.1296.png face.1298.png face.13.png face.1301.png face.1302.png face.1303.png face.1304.png face.1305.png face.1307.png face.1308.png face.1309.png face.1318.png face.1319.png face.132.png face.1320.png face.1321.png face.1323.png face.1324.png face.1326.png face.1328.png face.1330.png face.1331.png face.1332.png face.1333.png face.1336.png face.1338.png face.1339.png face.134.png face.1343.png face.1344.png face.1345.png face.1347.png face.1348.png face.1349.png face.1350.png face.1351.png face.1354.png face.139.png face.140.png face.141.png face.143.png face.144.png face.147.png face.150.png face.151.png face.152.png face.154.png face.157.png face.16.png face.160.png face.1653.png face.1654.png face.1660.png face.1662.png face.1663.png face.1666.png face.167.png face.1670.png face.168.png face.169.png face.170.png face.171.png face.172.png face.174.png face.177.png face.18.png face.181.png face.182.png face.189.png face.192.png face.193.png face.194.png face.196.png face.197.png face.199.png face.20.png face.200.png face.202.png face.209.png face.21.png face.210.png face.213.png face.216.png face.217.png face.218.png face.22.png face.223.png face.226.png face.227.png face.228.png face.230.png face.231.png face.239.png face.24.png face.242.png face.243.png face.246.png face.248.png face.249.png face.250.png face.254.png face.259.png face.26.png face.264.png face.269.png face.272.png face.277.png face.280.png face.285.png face.288.png face.289.png face.29.png face.293.png face.298.png face.299.png face.30.png face.301.png face.304.png face.305.png face.307.png face.308.png face.31.png face.310.png face.313.png face.318.png face.319.png face.320.png face.322.png face.325.png face.328.png face.337.png face.338.png face.339.png face.34.png face.340.png face.346.png face.347.png face.351.png face.353.png face.355.png face.356.png face.359.png face.365.png face.366.png face.37.png face.371.png face.379.png face.38.png face.381.png face.386.png face.389.png face.39.png face.391.png face.398.png face.4.png face.40.png face.400.png face.401.png face.404.png face.409.png face.412.png face.414.png face.415.png face.418.png face.421.png face.423.png face.424.png face.425.png face.426.png face.429.png face.431.png face.432.png face.434.png face.435.png face.436.png face.439.png face.44.png face.441.png face.442.png face.443.png face.445.png face.45.png face.451.png face.453.png face.455.png face.461.png face.462.png face.466.png face.47.png face.471.png face.474.png face.476.png face.478.png face.479.png face.48.png face.480.png face.481.png face.482.png face.485.png face.486.png face.487.png face.488.png face.49.png face.491.png face.493.png face.496.png face.498.png face.499.png face.5.png face.501.png face.503.png face.504.png face.505.png face.507.png face.509.png face.513.png face.518.png face.519.png face.52.png face.522.png face.523.png face.524.png face.525.png face.526.png face.527.png face.530.png face.531.png face.536.png face.537.png face.538.png face.54.png face.541.png face.542.png face.544.png face.545.png face.548.png face.549.png face.550.png face.554.png face.556.png face.558.png face.560.png face.565.png face.57.png face.574.png face.575.png face.578.png face.58.png face.581.png face.582.png face.583.png face.584.png face.585.png face.586.png face.589.png face.59.png face.592.png face.593.png face.594.png face.595.png face.598.png face.599.png face.601.png face.603.png face.605.png face.606.png face.607.png face.609.png face.610.png face.611.png face.613.png face.622.png face.624.png face.625.png face.626.png face.629.png face.63.png face.632.png face.636.png face.637.png face.64.png face.641.png face.642.png face.643.png face.646.png face.653.png face.655.png face.657.png face.666.png face.668.png face.669.png face.67.png face.670.png face.671.png face.672.png face.673.png face.677.png face.678.png face.68.png face.682.png face.685.png face.686.png face.687.png face.69.png face.690.png face.697.png face.700.png face.701.png face.702.png face.706.png face.707.png face.709.png face.71.png face.713.png face.715.png face.718.png face.722.png face.723.png face.724.png face.729.png face.733.png face.736.png face.737.png face.740.png face.742.png face.743.png face.744.png face.746.png face.747.png face.748.png face.75.png face.754.png face.755.png face.756.png face.757.png face.760.png face.762.png face.763.png face.764.png face.773.png face.778.png face.779.png face.782.png face.786.png face.787.png face.789.png face.791.png face.792.png face.794.png face.797.png face.801.png face.804.png face.806.png face.809.png face.81.png face.811.png face.817.png face.818.png face.819.png face.820.png face.821.png face.823.png face.825.png face.826.png face.827.png face.828.png face.831.png face.833.png face.835.png face.836.png face.839.png face.84.png face.841.png face.842.png face.843.png face.846.png face.849.png face.850.png face.851.png face.853.png face.855.png face.856.png face.859.png face.861.png face.862.png face.863.png face.864.png face.865.png face.869.png face.87.png face.871.png face.872.png face.878.png face.881.png face.882.png face.887.png face.888.png face.89.png face.891.png face.892.png face.894.png face.895.png face.897.png face.9.png face.90.png face.906.png face.91.png face.910.png face.911.png face.912.png face.913.png face.915.png face.916.png face.92.png face.920.png face.924.png face.928.png face.93.png face.931.png face.932.png face.933.png face.938.png face.940.png face.941.png face.945.png face.947.png face.948.png face.949.png face.950.png face.951.png face.953.png face.954.png face.955.png face.957.png face.960.png face.964.png face.965.png face.966.png face.969.png face.972.png face.976.png face.978.png face.98.png face.986.png face.987.png face.989.png face.99.png face.990.png face.991.png face.992.png face.995.png face.996.png face.998.png face.999.png
1 0-0.005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2 0.005-0.01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 0.01-0.015 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 0.015-0.02 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5 0.02-0.025 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Luego, la información que se tiene tanto para las imágenes que tienen gafas como las que no, la adecuamos según lo requerido. Después de este proceso se agrupa la información de ambos grupos y se crea un archivo csv con los datos de entrenamiento.

Ahora, se realiza un gráfico para analizar la frecuencia con respecto a la intensidad de luz. En dicho gráfico, se ve representado por medio del boxplot rojo la información que poseen las imágenes con gafas y por medio del boxplot azul, la información que poseen las imágenes sin gafas, que se encuentran entre un rango de intensidad de luz(de 0 a 1), donde en efecto se observó, que en el boxplot que representan las imágenes con gafas(rojos) se encuentran entre rango de opacidad(lado izquierdo de la imagen), lo cual evidencia que posee un perfil diferente que el de las imágenes sin gafas(azul). Para el entrenamiento del modelo se tomarán los datos del lado izquierdo para diferenciar las imágenes con y sin gafas, dado que a la derecha la diferencia entre las imágenes es poca y tendería a contaminar el modelo.

Con el fin de reducir la dimensionalidad se utiliza el Análisis de Componentes Principales (ACP), para así representar la información original pero en un espacio de dimensión menor(limitando la pérdida de información).

De esta forma, se elabora el modelo mediante regresión de componentes principales, donde el grupo representa la variable predictora y la data a la variable de respuesta a modelar, así mismo, se creó una variable donde el número 1 representa las imágenes con gafas y 0 las imágenes sin gafas. Igualmente todo este procedimiento se guardó en un archivo csv.

Después de crear el modelo, percibimos algunos casos donde la predicción era muy baja en fotos con gafas (debido a marcos de las gafas muy finos, plateados o transparentes) o muy alta en fotos sin gafas (debido a personas con una tez más oscura), como se puede apreciar en el siguiente gráfico.

A continuación, se presenta un diagrama de violín, en donde se representa la densidad de muestras que clasifica el modelo de entrenamiento para los grupos 0 (con gafas) y 1 (sin gafas). Es fácil destacar que la gran mayoría de las observaciones sin gafas se encuentran por debajo de 0.5, proporcionándole la forma “ancha” característica y el grupo con gafas tiene una forma más alargada y alta, ocupando un rango de valores mayor.

Una manera de comprobar las diferencias entre los grupos, es realizar una prueba t para la diferencia de medias.

Prueba de hipótesis:

\(H_0\)=\(\mu_1-\mu_2=0\) vs \(H_1\)=\(\mu_1 - \mu_2 \neq 0\)

## 
##  Welch Two Sample t-test
## 
## data:  datos[which(datos$X.1 == 1), 2] and datos[which(datos$X.1 == 0), 2]
## t = 29.103, df = 557.26, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.4641408 0.5313271
## sample estimates:
## mean of x mean of y 
## 0.7104474 0.2127134

De acuerdo al resultado, nuestra sospecha es cierta de que las medias de los valores para ambos grupos son diferentes y esto se contrasta con el p-value de \(2.2e^{-16}\) arrojado por la prueba, lo cual nos permite rechazar la hipótesis nula.

4. Validación

Del modelo predictivo trabajado hasta ahora, si bien es cierto que se caracteriza por tener una lógica avanzada, requiere de términos específicos. En este caso, el entrenamiento se realizó con imágenes frontales (straight), entonces la validación debe hacerse con el mismo tipo de imágenes. Es decir, el modelo puede predecir con un cierto grado de error, si se le evalúa con imágenes similares a las que se usaron en entrenamiento.

Del conjunto de validación obtenido de UCI Machine Learning Repository tenemos 424 fotos que cumplen con esta característica, se analizarán usando la librería pixmap

Las imágenes seleccionadas se convirtieron todas de formato pgm a png. Una imagen de este conjunto es:

Una vez que se tienen todas las imágenes en formato png, repetiremos los pasos iniciales para calcular los histogramas del grupo de validación.

Finalmente se prueba y se revisan los resultados del modelo elaborado.

Para ver el porcentaje de aciertos, se analizan los valores reales vs predichos por el modelo, esto se hace en el archivo resultados.csv y resultado (1).csv generados anteriomente. En el siguiente gráfico, se observan valores de estimación más altos en las fotos con gafas, como era de esperarse en concordancia por el resultado visto anteriomente en el gráfico de violín. Se observan algunos valores atípicos.

Con la intención de visualizar el desempeño de este algoritmo(que se emplea en aprendizaje supervisado) procedemos a realizar una matriz de confusión, la cual es una herramienta muy útil para valorar qué tan bueno es un modelo de clasificación basado en aprendizaje automático. En particular, sirve para mostrar de forma explícita cuándo una clase es confundida con otra, lo cual nos permite trabajar de forma separada con distintos tipos de error (tech, 2021).

Los valores de la diagonal principal a=209(98.58%) y d=173(81.6%) corresponden tanto a los valores estimados de forma correcta por el modelo, como a los verdaderos positivos d = 173(imágenes con lentes), y a los verdaderos negativos a= 209(imágenes sin lentes).

La otra diagonal, por tanto, representa los casos en los que el modelo se ha equivocado (c=39(18,4%) falsos negativos, b=3(1.42%) falsos positivos).

Luego de haber analizado la matrix de confusión, se procede a calcular la exactitud, la precisión, la sensibilidad y la especificidad.

  • Exactitud La exactitud (o «accuracy«) representa el porcentaje de predicciones correctas frente al total. Por tanto, es el cociente entre los casos bien clasificados por el modelo (verdaderos positivos y verdaderos negativos, es decir, los valores en la diagonal de la matriz de confusión), y la suma de todos los casos.

(209+173)/(209+173+39+3)=382/424= 0.9009434*100% = 90%

El valor obtenido para la exactitud en este modelo es del 90%.

  • Precisión La precisión, (o“precision”) se refiere a lo cerca que está el resultado de una predicción del valor verdadero. Por tanto, es el cociente entre los casos positivos bien clasificados por el modelo y el total de predicciones positivas.

(173)/(173+3)= 0.9829545*100% = 98.3%

El valor obtenido para este modelo es de un 98.3%. Por tanto, nuestro modelo es más preciso que exacto.

  • Sensibilidad La sensibilidad (o recall) representa la tasa de verdaderos positivos (True Positive Rate) ó TP. Es la proporción entre los casos positivos bien clasificados por el modelo, respecto al total de positivos, el cual es, la habilidad del modelo de dectetar los casos relevantes.

173/(39+173) = 0.8160377*100% = 81.6%

Un 81.6% es claramente un valor muy bueno para una métrica. Podemos decir que nuestro algoritmo de clasificación es sensible, es decir, no se le escapan muchos positivos.

  • Especificidad La especificidad, por su parte, es la tasa de verdaderos negativos, (“true negative rate”)o TN. Es la proporción entre los casos negativos bien clasificados por el modelo, respecto al total de negativos.

209/(209+3) = 0.9858491*100% = 98.6%

En este caso, la especificidad tiene un valor muy bueno. Esto significa que su capacidad de discriminar los casos negativos es muy buena. Es decir, es difícil obtener falsos positivos.

  • Conclusión Como se pudo observar, para cada métrica se obtuvieron valores altos, lo cual indica que el modelo tiene alta precisión y exactitud, y además de ello tiene una alta sensibilidad(tiene alto porcentaje en detectar casos positivos) y una alta especificidad(tiene alto porcentaje en detectar casos negativos).

Nuevamente, como se hizo para el conjunto de entrenamiento, se realiza una prueba t para la diferencia de medias entre los grupos.

Prueba de hipótesis:

\(H_0\)=\(\mu_1-\mu_2=0\) vs \(H_1\)=\(\mu_1 - \mu_2 \neq 0\)

## 
##  Welch Two Sample t-test
## 
## data:  datos2[which(datos2$grupo == "Con_gafas"), 2] and datos[which(datos2$grupo == "Sin_gafas"), 2]
## t = 3.8015, df = 412.13, p-value = 0.0001655
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  1.349349 4.239047
## sample estimates:
## mean of x mean of y 
##  6.759925  3.965727

De acuerdo al resultado, nuestra sospecha es cierta de que las medias de los valores para ambos grupos son diferentes y esto se contrasta con el p-value de 0.0001655 arrojado por la prueba, lo cual nos permite rechazar la hipótesis nula.

5. Interrogantes

5.1. ¿Qué afecta la capacidad del modelo en el conjunto de validación?

  • La ubicación de los rostros. Preferiblemente se desea que todas las imágenes sean centradas en donde se denote el septo nasal. Imágenes de perfil o con el mentón levantado no son aptas para este modelo.

  • La estadarización de las imágenes. Existen fotos extrañas en el conjunto de validación, imágenes dobles ó con rostros a medias, esto genera ruido y entorpece la capacidad de clasificar correctamente.

  • La tez de las personas de las fotografías. Puede llegar a alterar el modelo debido a la cantidad de píxeles (Ya sean mas oscuros o más claros) debido a que no podría distinguir si la persona lleva gafas o no.

  • Errores humanos. El mal procedimiento a la hora de escoger una imagen y agregarla en la clasificación incorrecta.

  • Formato de imágenes. La transformación de imágenes de pgm a png para el desarrollo del modelo.

5.2. ¿Hay alguna característica de las imágenes que mejore la capacidad de respuesta?

  • Como se dijo anteriormente, que todas las imágenes sean frontales.

  • La nitidez de las imágenes.

  • Para este modelo, las personas con tez clara deberían usar lentes oscuros para que éste pueda identificar que sí poseen lentes.

6. Enlace de interés

Usted puede revisar el código y los datos usados en este proyecto en nuestro repositorio en Github

7. Referencias

Murcia, U. d. (13 de Febrero de 2006). Obtenido de https://www.um.es/geograf/sigmur/temariohtml/node74.html

tech, T. (13 de Diciembre de 2021). Obtenido de https://empresas.blogthinkbig.com/como-interpretar-la-matriz-de-confusion-ejemplo-practico/

LS0tDQp0aXRsZTogIkNsYXNpZmljYWNpw7NuIGRlIGltw6FnZW5lcyBhIHRyYXbDqXMgZGUgbGEgaWRlbnRpZmljYWNpw7NuIGRlIHJvc3Ryb3MgY29uIGxlbnRlcyBvIHNpbiBsZW50ZXMiDQphdXRob3I6ICJKZXN1cyBEYXZpZCBTYW50b3MgTW9udGVzLCBLbGVpZGVyIFN0aXZlbiBWw6FzcXVleiBHw7NtZXosIERhbmllbCBBbmRyw6lzIFRvcm8gQWd1aXJyZSwgSmVsc3NpbiBEb25ub3ZhbiBSb2JsZWRvIE1lbmEsIEp1YW4gRXN0ZWJhbiBDYXJ2YWphbCBNb2xpbmEuIg0KZGF0ZTogIjMxLzAxLzIwMjIiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xhcHNlOiBmYWxzZQ0KICAgICAgDQogICAgICANCi0tLSANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KDQojIyAxLiBJbnRyb2R1Y2Npw7NuDQoNCkxhIGNsYXNpZmljYWNpw7NuIGRlIGltw6FnZW5lcyBlcyBvYmpldG8gZGUgZXN0dWRpbyB5IGFwbGljYWNpw7NuIGVuIG3Dumx0aXBsZXMgw6FyZWFzIGRlbCBjb25vY2ltaWVudG8uIEVuIGVsIGNhc28gbcOhcyBzaW1wbGUsIHNlIGJ1c2NhIHRvbWFyIHVuYSBkZWNpc2nDs24gY29uIGJhc2UgZW4gbGEgaW5mb3JtYWNpw7NuIHF1ZSBjb250aWVuZSB1bmEgaW1hZ2VuIChNdXJjaWEsIDIwMDYpLiBFbiBlc3RlIHJlcG9ydGUgc2UgYWJvcmRhIGVsIGVqZXJjaWNpbyBkZSBjbGFzaWZpY2FyIGltw6FnZW5lcyBkZSBzdWpldG9zIGNvbiBsZW50ZXMvZ2FmYXMgdXRpbGl6YW5kbyB0w6ljbmljYXMgZGUgYXByZW5kaXphamUgZXN0YWTDrXN0aWNvIHN1cGVydmlzYWRhcy4NCg0KDQojIyAyLiBEYXRvcw0KDQpFbCBjb25qdW50byBkZSBkYXRvcyBzZSBvYnR1dm8gZGVsIGN1cnNvIFQ4MS04NTU6IFtBcHBsaWNhdGlvbnMgb2YgRGVlcCBMZWFybmluZ10oaHR0cHM6Ly9zaXRlcy53dXN0bC5lZHUvamVmZmhlYXRvbi90ODEtNTU4LykgZGlyaWdpZG8gcG9yIGVsIHByb2Zlc29yIFtKZWZmIEhlYXRvbl0oaHR0cHM6Ly9naXRodWIuY29tL2plZmZoZWF0b24pLCBlbiBsYSBXYXNoaW5ndG9uIFVuaXZlcnNpdHkgaW4gU3QuIExvdWlzIChXVVNUTCkuIExvcyBkYXRvcywgZXN0w6FuIGFsb2phZG9zIGVuIHVuIHJldG8gZGUgW0thZ2dsZV0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9qZWZmaGVhdG9uL2dsYXNzZXMtb3Itbm8tZ2xhc3NlcykgZGVsIGHDsW8gMjAyMCwgZW4gZG9uZGUgc2UgZW5jdWVudHJhbiA1MDAwIGltw6FnZW5lcyBwcm9kdWNpZGFzIGFydGlmaWNpYWxtZW50ZSBhIHRyYXbDqXMgZGUgdW5hIHJlZCBuZXVyb25hbCBhZHZlcnNhIGdlbmVyYXRpdmEgKEdBTikuIFNlIHB1ZWRlbiBlbmNvbnRyYXIgcGVyc29uYXMgY29uIGxlbnRlcyB5IHBlcnNvbmFzIHNpbiBsZW50ZXMuIERlbnRybyBkZSBsYXMgaW3DoWdlbmVzIGRlIHBlcnNvbmFzIGNvbiBsZW50ZXMgc2UgaGFsbGFuIDYgdGlwb3MgZGUgbGVudGVzLiBMYSBmaWd1cmEgMSBwcmVzZW50YSB1bmEgbXVlc3RyYSBkZSBsb3MgdGlwb3MgZGUgbGVudGVzIHF1ZSBzZSBwdWVkZW4gZW5jb250cmFyIGVuIGVsIGNvbmp1bnRvIGRlIGRhdG9zOg0KDQoNCiFbRmlndXJhIDEuIFRpcG9zIGRlIGxlbnRlc10oaHR0cHM6Ly9kYXRhLmhlYXRvbnJlc2VhcmNoLmNvbS9pbWFnZXMvd3VzdGwva2FnZ2xlL2thZ2dsZS1mYWNlcy1nbGFzc2VzLTIucG5nKQ0KDQpFbCBjb25qdW50byBkZSBkYXRvcyBlcyByZXZpc2FkbyB5IHNlIGVsaW1pbmFuIGltw6FnZW5lcyBxdWUgc2UgY29uc2lkZXJhbiBwb2Ryw61hbiBwZXJ0dWJhciBlbCBhcHJlbmRpemFqZSBkZWwgbW9kZWxvLCBlbiDDqXN0YXMgc2UgaGFsbGFiYW4gcGVyc29uYXMgY29uIGxlbnRlcyBhIG1lZGlvIGNvbnN0cnVpciwgZG9zIHJvc3Ryb3MgZW4gdW5hIG1pc21hIGltYWdlbiB5IG90cmFzIGNvbiBkZXRhbGxlcyBzaW1pbGFyZXMuIEZpbmFsbWVudGUgZWwgY29uanVudG8gZGUgZGF0b3MgcXVlZGEgY29uIDQ1NCBpbcOhZ2VuZXMgZGUgc3VqZXRvcyBjb24gbGVudGVzIHkgNjE4IGRlIHN1amV0b3Mgc2luIGxlbnRlcy4gVGFtYmnDqW4sIHNlIGVsaWdpw7MgZXN0YSBjYW50aWRhZCBkZSBkYXRvcyBwb3IgbGEgY2FwYWNpZGFkIHkgdmVsb2NpZGFkIGRlIHByb2Nlc2FtaWVudG8gcXVlIHNlIHRpZW5lIGFsIGFsY2FuY2UuDQoNCg0KIyMjIDIuMS4gUHJvY2VzYW1pZW50byANCg0KTGFzIGltw6FnZW5lcyBzZSBwdWVkZW4gdmVjdG9yaXphci4gRXMgZGVjaXIsIHZpc3RhIGxhIGltYWdlbiBjb21vIHVuYSBtYXRyaXosIHN1cyBjb2x1bW5hcyBzZSB1YmljYW4gY29uc2VjdXRpdmFtZW50ZSB1bmEgZGViYWpvIGRlIGxhIG90cmEgaGFzdGEgb2J0ZW5lciB1biB2ZWN0b3IuIEx1ZWdvLCBsb3MgdmVjdG9yZXMgc2Vyw6FuIGxhcyBmaWxhcyBkZSB1bmEgbWF0cml6IGRlIGRhdG9zIGNvbiBsYSBpbmZvcm1hY2nDs24gZGUgaW50ZW5zaWRhZGVzIHBhcmEgY2FkYSBww614ZWwgZW4gbGFzIHJlc3BlY3RpdmFzIGltw6FnZW5lcy4NCg0KUGFyYSBkZXNjcmliaXIgdW5hIGZvcm1hIGRlIGNvbXBhcmFyIGxvcyB2ZWN0b3JlcywgdXNhcmVtb3MgdW5hIG11ZXN0cmEgZGUgNiBzdWpldG9zICgzIGNvbiBnYWZhcyB5IDMgc2luIGdhZmFzKS4gTGFzIGZpZ3VyYXMgc2Vyw6FuIGFuYWxpemFkYXMgY29uIGVsIHBhcXVldGUgW0VCSW1hZ2VdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9FQkltYWdlLmh0bWwpDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgZWNobz1GIH0NCiNpbnN0YWxhciBwYXF1ZXRlcyB5IGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KDQojaWYgKCFyZXF1aXJlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCg0KI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCJFQkltYWdlIikNCg0KI2luc3RhbGwucGFja2FnZXMoInBscyIpDQojaW5zdGFsbC5wYWNrYWdlcygicGl4bWFwIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJ5YXJkc3RpY2siKQ0KI2luc3RhbGwucGFja2FnZXMoIkthYmxlRXh0cmEiKQ0KDQoNCmxpYnJhcnkoRUJJbWFnZSkNCmxpYnJhcnkocGxzKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwaXhtYXApDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoeWFyZHN0aWNrKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgZWNobz1GIH0NCiNFbnRyYXIgYWwgZGlyZWN0b3JpbyBiYXNlDQoNCg0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9Nb2RlbG9zIikNCiNzZXR3ZCgiRDovVU5JVkVSU0lEQUQvVEFFL1RSQUJBSk9fMy9Nb2RlbG9zLyIpDQoNCg0KI0FicmlyIGxhcyBpbcOhZ2VuZXMgZGVsIG1vZGVsbw0KbGlzdC5maWxlcygpLT5saXN0YQ0KDQojVmVyIGxhcyBmaWd1cmFzIGNpdGFkYXMNCg0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgZWNobz1GIH0NCiNMdWVnbywgYWJyaXJlbW9zIHVuYSBkZSBlc2FzIGZpZ3VyYXMNCg0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9Nb2RlbG9zIikNCiNzZXR3ZCgiRDovVU5JVkVSU0lEQUQvVEFFL1RSQUJBSk9fMy9Nb2RlbG9zLyIpDQoNCmltYWdlbmFtZSA8LWxpc3RhWzFdDQppbWcgPSByZWFkSW1hZ2UoaW1hZ2VuYW1lKQ0KaW1hZ2VuYW1lIDwtbGlzdGFbMl0NCmltZzIgPSByZWFkSW1hZ2UoaW1hZ2VuYW1lKQ0KYGBgDQpTZSBwdWVkZSBldmlkZW5jaWFyIGEgY29udGludWFjacOzbiB1bmEgZmlndXJhIGRlIHVuIGhvbWJyZSBzaW4gZ2FmYXMgZGUgdW5hIGRlIGxhcyBpbcOhZ2VuZXMgZGVsIG1vZGVsby4NCg0KYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsZmlnLndpZHRoPSAyLGZpZy5oZWlnaHQ9IDIsZmlnLmFsaWduPSdjZW50ZXInLCBlY2hvPUZ9DQojUG9kZW1vcyBtb3N0cmFybGEgY29uIGVsIHNpZ3VpZW50ZSBjw7NkaWdvDQpkaXNwbGF5KGltZyxtZXRob2Q9J3Jhc3RlcicsYWxsPVRSVUUpDQpgYGANCg0KSWd1YWxtZW50ZSwgc2UgbXVlc3RyYSB1bmEgZmlndXJhIGRlIHVuIGhvbWJyZSBjb24gZ2FmYXMgZW4gdW5hIGRlIGxhcyBpbcOhZ2VuZXMgZGVsIG1vZGVsby4NCg0KYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsZmlnLndpZHRoPSAyLGZpZy5oZWlnaHQ9IDIsZmlnLmFsaWduPSdjZW50ZXInLCBlY2hvPUYgfQ0KZGlzcGxheShpbWcyLG1ldGhvZD0ncmFzdGVyJyxhbGw9VFJVRSkNCmBgYA0KDQpQYXJhIGZhY2lsaXRhciBsYSB2aXN1YWxpemFjacOzbiB5IHZlY3Rvcml6YWNpw7NuLCBzZSBwcm9jZWRlIGEgY29udmVydGlyIGxhcyBpbcOhZ2VuZXMgZW4gdW5hIGVzY2FsYSBkZSBncmlzZXMgcGFyYSBubyB0cmFiYWphciBjb24gZWwgbW9kZWxvIGRlIGNvbG9yIENNWUsqIChtb2RlbG8gZGUgY29sb3Igc3VzdHJhY3Rpdm8gcXVlIHNlIHV0aWxpemEgZW4gbGEgaW1wcmVzacOzbiBlbiBjb2xvcmVzLCBlcyBsYSB2ZXJzacOzbiBtb2Rlcm5hIHkgbcOhcyBwcmVjaXNhIGRlbCBhbnRpZ3VvIG1vZGVsbyB0cmFkaWNpb25hbCBkZSBjb2xvcmFjacOzbikuDQoNClBvciBlbmRlLCBsYXMgaW3DoWdlbmVzIHByZXNlbnRhZGFzIGFob3JhIHNlIHZhbiBhIHZpc3VhbGl6YXIgZW4gZXNwZWN0cm8gZGUgZ3Jpc2VzLg0KDQpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSAsIGVjaG89VCxmaWcud2lkdGg9IDIsZmlnLmhlaWdodD0gMixmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GIH0NCiNFc2NhbGEgZGUgZ3Jpc2VzLg0KDQppbWdfZzwtY2hhbm5lbChpbWcsImdyYXkiKQ0KaW1nX2cyPC1jaGFubmVsKGltZzIsImdyYXkiKQ0KDQpkaXNwbGF5KGltZ19nLG1ldGhvZD0ncmFzdGVyJyxhbGw9VFJVRSkNCmRpc3BsYXkoaW1nX2cyLG1ldGhvZD0ncmFzdGVyJyxhbGw9VFJVRSkNCmBgYA0KDQpZYSBxdWUgdG9kYXMgbGFzIGZpZ3VyYXMgZnVlcm9uIGNyZWFkYXMgcG9yIGNvbXB1dGFkb3JhLCBsb3MgbGVudGVzIHNlIHViaWNhcsOhbiBjYXNpIGVuIGxhIG1pc21hIHBvc2ljacOzbiwgcG9yIGVzYSByYXrDs24gc2UgZGVsaW1pdGFyb24gbGFzIGltw6FnZW5lcy4NCg0KYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsIGZpZy53aWR0aD0gMyxmaWcuaGVpZ2h0PSAzLGZpZy5hbGlnbj0nY2VudGVyJywgZWNobz1GIH0NCmltZ19jcm9wID0gaW1nX2dbMTUwOjkwMCwzNjA6NjUwXQ0KZGlzcGxheShpbWdfY3JvcCxtZXRob2Q9J3Jhc3RlcicsYWxsPVRSVUUpDQoNCmltZ19jcm9wMiA9IGltZ19nMlsxNTA6OTAwLDM2MDo2NTBdDQpkaXNwbGF5KGltZ19jcm9wMixtZXRob2Q9J3Jhc3RlcicsYWxsPVRSVUUpDQpgYGANCg0KSW5jbHVzaXZlLCBzZSBwb2Ryw61hIGNvcnRhciBzb2xhbWVudGUgZWwgc2VwdG8gbmFzYWwgcXVlIGVzIGRvbmRlIHNlIG1hcmNhbiBtw6FzIGxvcyBsZW50ZXMgcGFyYSBkaWZlcmVuY2lhciBsYXMgcGVyc29uYXMgcXVlIHVzYW4gbyBubyBnYWZhcy4gRWwgYWNlcmNhbWllbnRvIG8gcmVjb3J0ZSBwYXJhIGNlbnRyYXJub3MgZW4gZWwgc2VjdG8gbmFzYWwgZGUgbGFzIGltw6FnZW5lcywgc2UgZGVsaW1pdGEgYSB0cmF2w6lzIGRlIGxhcyBjb29yZGVuYWRhcyBlc3BlY2lmaWNhZGFzIHBhcmEgY2FkYSBpbWFnZW4gZW4gbGEgZnVuY2nDs24gZGVmaW5pZGEgZW4gZWwgbW9kZWxvIGNvbW8gc2UgbXVlc3RyYSBhIGNvbnRpbnVhY2nDs246IGBpbWdfY3JvcCA9IGltZ19nWzQ0MDo1OTAsNDQwOjU4MF1gIGNvbiBlc3RhIGzDrW5lYSBzZSBkZWxpbWl0YSBlbCDDoXJlYSBkZSBsYSBpbWFnZW4gcXVlIHF1ZXJlbW9zIHRvbWFyLg0KYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsIGZpZy53aWR0aD0gMyxmaWcuaGVpZ2h0PSAzLGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUYgfQ0KaW1nX2Nyb3AgPSBpbWdfZ1s0NDA6NTkwLDQ0MDo1ODBdDQpkaXNwbGF5KGltZ19jcm9wLG1ldGhvZD0ncmFzdGVyJyxhbGw9VFJVRSkNCg0KaW1nX2Nyb3AyID0gaW1nX2cyWzQ0MDo1OTAsNDQwOjU4MF0NCmRpc3BsYXkoaW1nX2Nyb3AyLG1ldGhvZD0ncmFzdGVyJyxhbGw9VFJVRSkNCmBgYA0KDQpTZSBwcmVzZW50YW4gdW5vcyBoaXN0b2dyYW1hcyBjb24gZWwgZmluIGRlIHZlciBwb3IgbWVkaW8gZGUgc3VzIGZyZWN1ZW5jaWFzIHNpIGhheSBkaWZlcmVuY2lhcyBlbnRyZSBpbcOhZ2VuZXMgY29uIHkgc2luIGdhZmFzLiBFbiBsb3Mgc2lndWllbnRlcyBoaXN0b2dyYW1hcyBzZSBidXNjYSBvYnNlcnZhciBsYSBjYW50aWRhZCBkZSBww614ZWxlcyAoMjEuMjkxIHDDrXhlbGVzKSB2ZXJzdXMgbGEgaW50ZW5zaWRhZCAoMCBhIDEpLg0KDQpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSAsIGVjaG89RiB9DQoNCnNldHdkKCJEOi9Vc2Vycy9Vc3VhcmlvL0Rlc2t0b3AvVU4vMTEuU0VNRVNUUkVYSS9UQUUvVHJhYmFqbzMvcHJveWVjdG8vTW9kZWxvcyIpDQojc2V0d2QoIkQ6L1VOSVZFUlNJREFEL1RBRS9UUkFCQUpPXzMvTW9kZWxvcy8iKQ0KDQpmb3IgKGkgaW4gMTo2KXsNCmltYWdlbmFtZSA8LWxpc3RhW2ldDQoNCmltZyA9IHJlYWRJbWFnZShpbWFnZW5hbWUpDQoNCmltZ19nPC1jaGFubmVsKGltZywiZ3JheSIpDQoNCmltZ19jcm9wID0gaW1nX2dbNDQwOjU5MCw0NDA6NTgwXQ0KcGFyKG1mcm93PWMoMSwyKSkNCmRpc3BsYXkoaW1nX2Nyb3AqMixtZXRob2Q9J3Jhc3RlcicsYWxsPVRSVUUpDQoNCmhpc3QoaW1nX2Nyb3AsYnJlYWtzPTEwMCkNCn0NCg0KYGBgDQoNCkZpbmFsbWVudGUsIHNlIGV2aWRlbmNpw7MgcXVlIGhhYsOtYW4gZGlmZXJlbmNpYXMgZW50cmUgbG9zIGhpc3RvZ3JhbWFzIGRlIHBlcnNvbmFzIGNvbiBvIHNpbiBnYWZhcywgeWEgcXVlIHNlIGFwcmVjaWEgcXVlIGhheSB1biBwZXJmaWwgZGlmZXJlbnRlIGVudHJlIGxhIHBlcnNvbmFzIHF1ZSB0aWVuZW4gZ2FmYXMgeSBsYXMgcXVlIG5vLiBQYXJhIGVsbG8sIHNlIHV0aWxpesOzIGxhIGludGVuc2lkYWQgZGUgbHV6IHF1ZSBlc3TDoSBlbiB1bmEgZXNjYWxhIGRlIDAgYSAxLCBkb25kZSBlbCAwIHJlcHJlc2VudGEgbGEgdG9uYWxpZGFkIG3DoXMgb3NjdXJhIGRlIGxhIGltYWdlbiB5IGVsIDEgbGEgbcOhcyBjbGFyYS4gRXMgZGVjaXIsIHNpIGVuIGxhIGZvdG9ncmFmw61hIGV4aXN0ZW4gbcOhcyBww614ZWxlcyBlbiBsYSBwYXJ0ZSBvc2N1cmEsIGVudG9uY2VzIGxhIGZyZWN1ZW5jaWEgYWxsw60gcmVwcmVzZW50YWRhIGVuIGVsIGhpc3RvZ3JhbWEgc2Vyw6EgbWF5b3IuDQoNClBhcmEgbGFzIGltw6FnZW5lcyBxdWUgbm8gdGllbmVuIGxlbnRlcywgbGEgZnJlY3VlbmNpYSBlc3TDoSBoYWNpYSBlbCBsYWRvIGRlcmVjaG8sIGVzIGRlY2lyLCBxdWUgbGEgaW1hZ2VuIHRpZW5lIG3DoXMgaW50ZW5zaWRhZCBkZSBsdXouIFBhcmEgbGFzIGltw6FnZW5lcyBxdWUgdGllbmVuIGxlbnRlcyBvc2N1cm9zLCBsYSBmcmVjdWVuY2lhIGVzdMOhIGhhY2lhIGVsIGxhZG8gaXpxdWllcmRvLCBlcyBkZWNpciwgcXVlIGxhIGltYWdlbiB0aWVuZSBtw6FzIHDDrXhlbGVzIG9zY3Vyb3MuIFkgZmluYWxtZW50ZSwgcGFyYSBsYXMgaW3DoWdlbmVzIHF1ZSB0aWVuZW4gbGVudGVzIHRyYW5zcGFyZW50ZXMsIGxhIGZyZWN1ZW5jaWEgdGllbmUgbcOhcyB2YXJpYWJpbGlkYWQgcGVybyBhw7puIGFzw60gc2UgcHVlZGUgbm90YXIgcXVlIHNvbiBkaWZlcmVudGVzIGEgbGFzIGRlbcOhcy4NCg0KIyMgMy4gTW9kZWxvDQoNCkNvbiBsYSBpbnRlbmNpw7NuIGRlIGJ1c2NhciB1bmEgZm9ybWEgcGFyYSBwb2RlciBjb21wYXJhciBsb3MgdmVjdG9yZXMgc2UgY3JlYSB1bmEgbWF0cml6IGNvbiBkYXRvcyBkZSBpbnRlbnNpZGFkLCBlbiBkb25kZSwgc2UgZXN0YWJsZWNlbiBsb3MgY3VhcnRpbGVzIGRlbCBoaXN0b2dyYW1hIHBhcmEgb2J0ZW5lciB1biBwZXJmaWwgZGUgY29tcGFyYWNpw7NuLiBZIGFkZW3DoXMsIGNvbiBhcG95byBkZSB1bmEgZnVuY2nDs24gY8OtY2xpY2EsIGxhIGN1YWwgY29taWVuemEgZW4gMSBoYXN0YSBlbCB0YW1hw7FvIGRlIGxhIGxpc3RhLCBzZSBjcmVhIHVuYSBtYXRyaXoocmVwcmVzZW50YSBsYXMgZm90b3MgY29uIGdhZmFzKSBxdWUgZmluYWxtZW50ZSBzZSBhbG1hY2VuYSBlbiB1biBhcmNoaXZvIGNzdi4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgZWNobz1GfQ0KI0VudHJhciBhbCBkaXJlY3RvcmlvIGJhc2UNCg0KIyBzZXR3ZCgiRDovVXNlcnMvVXN1YXJpby9EZXNrdG9wL1VOLzExLlNFTUVTVFJFWEkvVEFFL1RyYWJham8zL3Byb3llY3RvL0Nvbl9nYWZhc190cmFpbmluZyIpDQojIA0KIyAjQWJyaXIgbGFzIGltw6FnZW5lcyBkZWwgbW9kZWxvDQojIGxpc3QuZmlsZXMoKS0+bGlzdGENCg0KI1ZhbW9zIGEgY3JlYXIgdW5hIGNvbHVtbmEgY29uIGxvcyBjdWFydGlsZXMgbmVjZXNhcmlvcyAoYmFzYWRvIGVuIGVsIGNvbmNlcHRvIGRlIGhpc3RvZ3JhbWEpDQoNCiMgcGFzdGUwKHNlcSgwLDAuOTk1LDAuMDA1KSwiLSIsc2VxKDAuMDA1LDEsMC4wMDUpKS0+Y3VhcnRpbGVzDQojIA0KIyBkYXRhLmZyYW1lKHZhbHVlcz1jdWFydGlsZXMpLT5nYWZhcw0KIyANCiMgZm9yIChpIGluIDE6bGVuZ3RoKGxpc3RhKSl7DQojIGltYWdlbmFtZSA8LWxpc3RhW2ldDQojIA0KIyBpbWcgPSByZWFkSW1hZ2UoaW1hZ2VuYW1lKQ0KIyANCiMgaW1nX2c8LWNoYW5uZWwoaW1nLCJncmF5IikNCiMgDQojIGltZ19jcm9wID0gaW1nX2dbNDQwOjU5MCw0NDA6NTgwXQ0KIyBoaXN0KGltZ19jcm9wLGJyZWFrcz1zZXEoMCwxLDAuMDA1KSktPmRhZG9zDQojIGRhdGEuZnJhbWUoZ2FmYXMsZGFkb3MkY291bnRzKS0+Z2FmYXMNCiMgDQojIH0NCiMgY29sbmFtZXMoZ2FmYXMpPC1jKCJ2YWx1ZXMiLGxpc3RhKQ0KDQojZ3VhcmRhbmRvIGVzdGUgcmVzdWx0YWRvDQoNCiN3cml0ZS5jc3YoZ2FmYXMsIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9Gb3Rvc0NvbkdhZmFzLmNzdiIpDQpgYGANCg0KU2UgcmVhbGl6YSBlbCBtaXNtbyBwcm9jZXNvIGFudGVyaW9yIHBhcmEgZWwgY2FzbyBkZSBmb3RvcyBzaW4gZ2FmYXMsIHF1ZSBpZ3VhbG1lbnRlIGRpY2hhIG1hdHJpeiBnZW5lcmFkYSBzZSBhbG1hY2VuYSBlbiBvdHJvIGFyY2hpdm8gY3N2Lg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgZWNobz1GfQ0KDQojRW50cmFyIGFsIGRpcmVjdG9yaW8gYmFzZQ0KDQojc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9TaW5fZ2FmYXNfdHJhaW5pbmciKQ0KDQojIA0KIyAjQWJyaXIgbGFzIGltw6FnZW5lcyBkZWwgbW9kZWxvDQojIGxpc3QuZmlsZXMoKS0+bGlzdGENCiMgDQojICNWYW1vcyBhIGNyZWFyIHVuYSBjb2x1bW5hIGNvbiBsb3MgY3VhcnRpbGVzIG5lY2VzYXJpb3MgKGJhc2FkbyBlbiBlbCBjb25jZXB0byBkZSBoaXN0b2dyYW1hKQ0KIyANCiMgcGFzdGUwKHNlcSgwLDAuOTk1LDAuMDA1KSwiLSIsc2VxKDAuMDA1LDEsMC4wMDUpKS0+Y3VhcnRpbGVzDQojIA0KIyBkYXRhLmZyYW1lKHZhbHVlcz1jdWFydGlsZXMpLT5TZ2FmYXMNCiMgDQojIGZvciAoaSBpbiAxOmxlbmd0aChsaXN0YSkpew0KIyBpbWFnZW5hbWUgPC1saXN0YVtpXQ0KIyANCiMgaW1nID0gcmVhZEltYWdlKGltYWdlbmFtZSkNCiMgDQojIGltZ19nPC1jaGFubmVsKGltZywiZ3JheSIpDQojIA0KIyBpbWdfY3JvcCA9IGltZ19nWzQ0MDo1OTAsNDQwOjU4MF0NCiMgaGlzdChpbWdfY3JvcCxicmVha3M9c2VxKDAsMSwwLjAwNSkpLT5kYWRvcw0KIyBkYXRhLmZyYW1lKFNnYWZhcyxkYWRvcyRjb3VudHMpLT5TZ2FmYXMNCiMgDQojIH0NCiMgY29sbmFtZXMoU2dhZmFzKTwtYygidmFsdWVzIixsaXN0YSkNCiMgDQojICNndWFyZGFuZG8gZXN0ZSByZXN1bHRhZG8NCiMgDQojIHdyaXRlLmNzdihnYWZhcywiRDovVXNlcnMvVXN1YXJpby9EZXNrdG9wL1VOLzExLlNFTUVTVFJFWEkvVEFFL1RyYWJham8zL3Byb3llY3RvL0ZvdG9zU2luR2FmYXMuY3N2IikNCmBgYA0KDQpFbiBlc3RlIG1vZGVsbywgZ2VuZXJhbW9zIDIwMCB2YWxvcmVzIG51bcOpcmljb3MgcGFyYSBjYWRhIGltYWdlbiByZWNvcnRhZGEsIGRvbmRlIGRpY2hvcyB2YWxvcmVzIHJlcHJlc2VudGFuIGxhIGNhbnRpZGFkIGRlIHDDrXhlbGVzLg0KDQpBIGNvbnRpbnVhY2nDs24gc2UgbXVlc3RyYW4gbG9zIHZhbG9yZXMgZGl2aWRpZG9zIGVuIHJhbmdvcyBjb24gcmVzcGVjdG8gYSBzdSBuaXZlbCBkZSBpbnRlbnNpZGFkIGRlIGx1eiwgcGFyYSBhc8OtIHRlbmVyIG3DoXMgcmVzb2x1Y2nDs24gZW4gbG9zIHJlc3VsdGFkb3MuDQpgYGB7ciwgZmlnLmRpbSA9IGMoMTgsIDYpLCBkcGk9NjAwLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZ9DQojRW50cmFyIGFsIGRpcmVjdG9yaW8gYmFzZQ0KDQpzZXR3ZCgiRDovVXNlcnMvVXN1YXJpby9EZXNrdG9wL1VOLzExLlNFTUVTVFJFWEkvVEFFL1RyYWJham8zL3Byb3llY3RvIikNCiNzZXR3ZCgiRDovVU5JVkVSU0lEQUQvVEFFL1RSQUJBSk9fMy9Nb2RlbG9zLyIpDQoNCiNMZWVyIGxvcyBhcmNoaXZvcw0KDQpyZWFkLmNzdigiRm90b3NDb25HYWZhcy5jc3YiKS0+Z2FmYXMNCg0KI2dhZmFzIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9MZW5vdm8vRG93bmxvYWRzL0ZvdG9zQ29uR2FmYXMuY3N2IikNCg0KcmVhZC5jc3YoIkZvdG9zU2luR2FmYXMuY3N2IiktPlNnYWZhcw0KDQojU2dhZmFzIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9MZW5vdm8vRG93bmxvYWRzL0ZvdG9zU2luR2FmYXMuY3N2IikNCg0KI1ZhbW9zIGEgdmVyIHLDoXBpZGFtZW50ZSBsb3MgYXJjaGl2b3M6DQoNCmdhZmFzX2sgPC0gaGVhZChnYWZhcyw1KQ0Ka2JsKGdhZmFzX2ssY2FwdGlvbiA9ICJUYWJsYSAxLiBJbmZvcm1hY2nDs24gZGUgcmFuZ29zIGRlIGludGVuc2lkYWQgZGUgZm90b3MgY29uIGdhZmFzIikgJT4lIGthYmxlX3N0eWxpbmcobGF0ZXhfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCJjb25kZW5zZWQiLCJIT0xEX3Bvc2l0aW9uIiksIHBvc2l0aW9uID0gImNlbnRlciIsZnVsbF93aWR0aCA9IEZBTFNFKQ0KDQpTZ2FmYXNfayA8LSBoZWFkKFNnYWZhcyw1KQ0Ka2JsKFNnYWZhc19rLGNhcHRpb24gPSAiVGFibGEgMi4gSW5mb3JtYWNpw7NuIGRlIHJhbmdvcyBkZSBpbnRlbnNpZGFkIGRlIGZvdG9zIHNpbiBnYWZhcyIpICU+JSBrYWJsZV9zdHlsaW5nKGxhdGV4X29wdGlvbnMgPSBjKCJzdHJpcGVkIiwiY29uZGVuc2VkIiwiSE9MRF9wb3NpdGlvbiIpLCBwb3NpdGlvbiA9ICJjZW50ZXIiLGZ1bGxfd2lkdGggPSBGQUxTRSkNCg0KYGBgDQoNCkx1ZWdvLCBsYSBpbmZvcm1hY2nDs24gcXVlIHNlIHRpZW5lIHRhbnRvIHBhcmEgbGFzIGltw6FnZW5lcyBxdWUgdGllbmVuIGdhZmFzIGNvbW8gbGFzIHF1ZSBubywgbGEgYWRlY3VhbW9zIHNlZ8O6biBsbyByZXF1ZXJpZG8uIERlc3B1w6lzIGRlIGVzdGUgcHJvY2VzbyBzZSBhZ3J1cGEgbGEgaW5mb3JtYWNpw7NuICBkZSBhbWJvcyBncnVwb3MgeSBzZSBjcmVhIHVuIGFyY2hpdm8gY3N2IGNvbiBsb3MgZGF0b3MgZGUgZW50cmVuYW1pZW50by4NCmBgYHtyLCBmaWcuZGltID0gYygxOCwgNiksIGRwaT02MDAsIG1lc3NhZ2U9RkFMU0UsIGVjaG89Rn0NCiNvcmRlbmFyIHRhYmxhcywgY29sdW1uYXMsIGNhbWJpYXIgbm9tYnJlcw0KDQpnYWZhc1ssMl0tPnJvd25hbWVzKGdhZmFzKQ0KZ2FmYXNbLC1jKDE6MildLT5nYWZhcw0KdChnYWZhcyktPmdhZmFzDQoNCg0KU2dhZmFzWywyXS0+cm93bmFtZXMoU2dhZmFzKQ0KU2dhZmFzWywtYygxOjIpXS0+U2dhZmFzDQp0KFNnYWZhcyktPlNnYWZhcw0KDQojSnVudGFuZG8gbGEgaW5mb3JtYWNpw7NuDQoNCnRyYWluPC1kYXRhLmZyYW1lKHJiaW5kKGdhZmFzLFNnYWZhcyksZ3J1cG89YyhyZXAoIkNvbl9HYWZhcyIsbnJvdyhnYWZhcykpLHJlcCgiU2luX0dhZmFzIixucm93KFNnYWZhcykpKSkNCmNvbG5hbWVzKHRyYWluKTwtYyhjb2xuYW1lcyhnYWZhcyksImdydXBvIikNCg0KI3dyaXRlLmNzdih0cmFpbiwidHJhaW5fMS5jc3YiKQ0KYGBgDQoNCkFob3JhLCBzZSByZWFsaXphIHVuIGdyw6FmaWNvIHBhcmEgYW5hbGl6YXIgbGEgZnJlY3VlbmNpYSBjb24gcmVzcGVjdG8gYSBsYSBpbnRlbnNpZGFkIGRlIGx1ei4NCmBgYHtyLCBmaWcuZGltID0gYygxOCwgNiksIGRwaT02MDAsIG1lc3NhZ2U9RkFMU0UsIGVjaG89Rn0NCiNyZXZpc2FuZG8gbG9zIGhpc3RvZ3JhbWFzDQoNCg0KdHJhaW4gJT4lIHBpdm90X2xvbmdlcighZ3J1cG8sbmFtZXNfdG89InJhbmdlIix2YWx1ZXNfdG89InZhbHVlIiktPmRhdG9zDQoNCg0KZ2dwbG90KGRhdG9zLCBhZXMoeD1yYW5nZSwgeT12YWx1ZSwgY29sb3I9Z3J1cG8pKSArDQogIGdlb21fYm94cGxvdCgpKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSxzaXplPTgpKQ0KYGBgDQpFbiBkaWNobyBncsOhZmljbywgc2UgdmUgcmVwcmVzZW50YWRvIHBvciBtZWRpbyBkZWwgYm94cGxvdCByb2pvIGxhIGluZm9ybWFjacOzbiBxdWUgcG9zZWVuIGxhcyBpbcOhZ2VuZXMgY29uIGdhZmFzIHkgcG9yIG1lZGlvIGRlbCBib3hwbG90IGF6dWwsIGxhIGluZm9ybWFjacOzbiBxdWUgcG9zZWVuIGxhcyBpbcOhZ2VuZXMgc2luIGdhZmFzLCBxdWUgc2UgZW5jdWVudHJhbiBlbnRyZSB1biByYW5nbyBkZSBpbnRlbnNpZGFkIGRlIGx1eihkZSAwIGEgMSksIGRvbmRlIGVuIGVmZWN0byBzZSBvYnNlcnbDsywgcXVlIGVuIGVsIGJveHBsb3QgcXVlIHJlcHJlc2VudGFuIGxhcyBpbcOhZ2VuZXMgY29uIGdhZmFzKHJvam9zKSBzZSBlbmN1ZW50cmFuIGVudHJlIHJhbmdvIGRlIG9wYWNpZGFkKGxhZG8gaXpxdWllcmRvIGRlIGxhIGltYWdlbiksIGxvIGN1YWwgZXZpZGVuY2lhIHF1ZSBwb3NlZSB1biBwZXJmaWwgZGlmZXJlbnRlIHF1ZSBlbCBkZSBsYXMgaW3DoWdlbmVzIHNpbiBnYWZhcyhhenVsKS4gUGFyYSBlbCBlbnRyZW5hbWllbnRvIGRlbCBtb2RlbG8gc2UgdG9tYXLDoW4gbG9zIGRhdG9zIGRlbCBsYWRvIGl6cXVpZXJkbyBwYXJhIGRpZmVyZW5jaWFyIGxhcyBpbcOhZ2VuZXMgY29uIHkgc2luIGdhZmFzLCBkYWRvIHF1ZSBhIGxhIGRlcmVjaGEgbGEgZGlmZXJlbmNpYSBlbnRyZSBsYXMgaW3DoWdlbmVzIGVzIHBvY2EgeSB0ZW5kZXLDrWEgYSBjb250YW1pbmFyIGVsIG1vZGVsby4NCg0KYGBge3IsIGZpZy5kaW0gPSBjKDE4LCA2KSwgZHBpPTYwMCwgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgZWNobz1GfQ0KcG5nKCJCb3hwbG90X2dlbmVyYWwucG5nIix3aWR0aD0xMjAwMCwgaGVpZ2h0PTUwMDAscmVzPTYwMCkNCmdncGxvdChkYXRvcywgYWVzKHg9cmFuZ2UsIHk9dmFsdWUsIGNvbG9yPWdydXBvKSkgKw0KICBnZW9tX2JveHBsb3QoKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEsc2l6ZT04KSkNCmRldi5vZmYoKQ0KYGBgDQoNCkNvbiBlbCBmaW4gZGUgcmVkdWNpciBsYSBkaW1lbnNpb25hbGlkYWQgc2UgdXRpbGl6YSBlbCBBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMgKEFDUCksIHBhcmEgYXPDrSByZXByZXNlbnRhciBsYSBpbmZvcm1hY2nDs24gb3JpZ2luYWwgcGVybyBlbiB1biBlc3BhY2lvIGRlIGRpbWVuc2nDs24gbWVub3IobGltaXRhbmRvIGxhIHDDqXJkaWRhIGRlIGluZm9ybWFjacOzbikuDQoNCkRlIGVzdGEgZm9ybWEsIHNlIGVsYWJvcmEgZWwgbW9kZWxvIG1lZGlhbnRlIHJlZ3Jlc2nDs24gZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMsIGRvbmRlIGVsIGdydXBvIHJlcHJlc2VudGEgbGEgdmFyaWFibGUgcHJlZGljdG9yYSB5IGxhIGRhdGEgYSBsYSB2YXJpYWJsZSBkZSByZXNwdWVzdGEgYSBtb2RlbGFyLCBhc8OtIG1pc21vLCBzZSBjcmXDsyB1bmEgdmFyaWFibGUgZG9uZGUgZWwgbsO6bWVybyAxIHJlcHJlc2VudGEgbGFzIGltw6FnZW5lcyBjb24gZ2FmYXMgeSAwIGxhcyBpbcOhZ2VuZXMgc2luIGdhZmFzLiBJZ3VhbG1lbnRlIHRvZG8gZXN0ZSBwcm9jZWRpbWllbnRvIHNlIGd1YXJkw7MgZW4gdW4gYXJjaGl2byBjc3YuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPUZ9DQoNCiNFamVjdXRhbmRvIGVsIEFDUA0KDQoNCm11dGF0ZSh0cmFpbixncnVwbz1pZmVsc2UoZ3J1cG89PSJDb25fR2FmYXMiLDEsMCkpLT50cmFpbjINCg0KI2NyZWFjacOzbiBkZWwgbW9kZWxvDQpwY3IoZ3J1cG9+LixkYXRhPXRyYWluMlssYygxOjYwLDIwMSldLHNjYWxlPVRSVUUsdmFsaWRhdGlvbj0iQ1YiKS0+bW9kZWwNCg0KI1BydWViYSByZWR1bmRhbnRlIA0KcHJlZGljdChtb2RlbCx0cmFpbjJbLC0yMDFdLG5jb21wPTEwKS0+cHJvYg0KDQojU2kgc2UgZGVzZWEsIHNlIHB1ZWRlbiBqdW50YXIgbG9zIGRhdG9zIGNyZWFkb3MgY29uIGxvcyB2YWxvcmVzIHJlYWxlcyAoY29sdW1uYSBncnVwbyBkZSBsYSB0YWJsYSB0cmFpbikNCiBjYmluZChwcm9iLHRyYWluMlssMjAxXSktPnByb2INCg0KICN3cml0ZS5jc3YocHJvYiwiZGF0b3NfZ2VuZXJhZG9zLmNzdiIpDQogDQpgYGANCg0KDQpEZXNwdcOpcyBkZSBjcmVhciBlbCBtb2RlbG8sIHBlcmNpYmltb3MgYWxndW5vcyBjYXNvcyBkb25kZSBsYSBwcmVkaWNjacOzbiBlcmEgbXV5IGJhamEgZW4gZm90b3MgY29uIGdhZmFzIChkZWJpZG8gYSBtYXJjb3MgZGUgbGFzIGdhZmFzIG11eSBmaW5vcywgcGxhdGVhZG9zIG8gdHJhbnNwYXJlbnRlcykgbyBtdXkgYWx0YSBlbiBmb3RvcyBzaW4gZ2FmYXMgKGRlYmlkbyBhIHBlcnNvbmFzIGNvbiB1bmEgdGV6IG3DoXMgb3NjdXJhKSwgY29tbyBzZSBwdWVkZSBhcHJlY2lhciBlbiBlbCBzaWd1aWVudGUgZ3LDoWZpY28uDQoNCg0KDQpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSAsIGVjaG89VCxmaWcud2lkdGg9IDIsZmlnLmhlaWdodD0gMixmaWcuYWxpZ249J2NlbnRlcicsIGVjaG89Rn0NCg0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9TaW5fZ2FmYXNfdHJhaW5pbmciKQ0KI3NldHdkKCJEOi9VTklWRVJTSURBRC9UQUUvVFJBQkFKT18zL1NpbiBnYWZhc190cmFpbmluZyIpDQoNCg0KDQojQWJyaXIgbGFzIGltw6FnZW5lcyBkZWwgbW9kZWxvDQpsaXN0LmZpbGVzKCktPmxpc3RhDQoNCmk8LTEyNw0KaW1hZ2VuYW1lIDwtbGlzdGFbaV0NCg0KaW1nID0gcmVhZEltYWdlKGltYWdlbmFtZSkNCg0KaW1nX2c8LWNoYW5uZWwoaW1nLCJncmF5IikNCg0KaW1nX2Nyb3AgPSBpbWdfZ1s0NDA6NTkwLDQ0MDo1ODBdDQpkaXNwbGF5KGltZ19nLG1ldGhvZD0ncmFzdGVyJykNCg0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9Db25fZ2FmYXNfdHJhaW5pbmciKQ0KDQojc2V0d2QoIkQ6L1VOSVZFUlNJREFEL1RBRS9UUkFCQUpPXzMvQ29uIGdhZmFzX3RyYWluaW5nIikNCg0KI0FicmlyIGxhcyBpbcOhZ2VuZXMgZGVsIG1vZGVsbw0KbGlzdC5maWxlcygpLT5saXN0YQ0KDQppPC0yMTkNCmltYWdlbmFtZSA8LWxpc3RhW2ldDQoNCmltZyA9IHJlYWRJbWFnZShpbWFnZW5hbWUpDQoNCmltZ19nPC1jaGFubmVsKGltZywiZ3JheSIpDQoNCmltZ19jcm9wID0gaW1nX2dbNDQwOjU5MCw0NDA6NTgwXQ0KZGlzcGxheShpbWdfZyxtZXRob2Q9J3Jhc3RlcicpDQoNCg0KDQpgYGANCg0KQSBjb250aW51YWNpw7NuLCBzZSBwcmVzZW50YSB1biBkaWFncmFtYSBkZSB2aW9sw61uLCBlbiBkb25kZSBzZSByZXByZXNlbnRhIGxhIGRlbnNpZGFkIGRlIG11ZXN0cmFzIHF1ZSBjbGFzaWZpY2EgZWwgbW9kZWxvIGRlIGVudHJlbmFtaWVudG8gcGFyYSBsb3MgZ3J1cG9zIDAgKGNvbiBnYWZhcykgeSAxIChzaW4gZ2FmYXMpLiBFcyBmw6FjaWwgZGVzdGFjYXIgcXVlIGxhIGdyYW4gbWF5b3LDrWEgZGUgbGFzIG9ic2VydmFjaW9uZXMgc2luIGdhZmFzIHNlIGVuY3VlbnRyYW4gcG9yIGRlYmFqbyBkZSAwLjUsIHByb3BvcmNpb27DoW5kb2xlIGxhIGZvcm1hICJhbmNoYSIgY2FyYWN0ZXLDrXN0aWNhIHkgZWwgZ3J1cG8gY29uIGdhZmFzIHRpZW5lIHVuYSBmb3JtYSBtw6FzIGFsYXJnYWRhIHkgYWx0YSwgb2N1cGFuZG8gdW4gcmFuZ28gZGUgdmFsb3JlcyBtYXlvci4NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFICwgZWNobz1ULGZpZy53aWR0aD0gMyxmaWcuaGVpZ2h0PSAzLGZpZy5hbGlnbj0nY2VudGVyJywgZWNobz1GfQ0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0byIpDQpyZWFkLmNzdigiZGF0b3NfZ2VuZXJhZG9zLmNzdiIpLT5kYXRvcw0KDQojc2V0d2QoIkQ6L1VOSVZFUlNJREFEL1RBRS9UUkFCQUpPXzMvU2luIGdhZmFzX3RyYWluaW5nIikNCg0KI2RhdG9zIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9MZW5vdm8vRG93bmxvYWRzL2RhdG9zX2dlbmVyYWRvcy5jc3YiKQ0KDQojRW4gZWwgc2lndWllbnRlIGdyw6FmaWNvLCBzZSBtdWVzdHJhIGNvbW8gMCwgYXF1ZWxsYXMgaW3DoWdlbmVzIHF1ZSBubyBkZWJlcsOtYW4gdGVuZXIgZ2FmYXMgeSBjb21vIDEsIGFxdWVsbGFzIHF1ZSBkZWJlcsOtYW4gbW9zdHJhciBnYWZhcy4gDQpnZ3Bsb3QoZGF0b3MsYWVzKHg9YXMuZmFjdG9yKFguMSkseT1wcm9iKSkrZ2VvbV92aW9saW4oKQ0KYGBgDQoNClVuYSBtYW5lcmEgZGUgY29tcHJvYmFyIGxhcyBkaWZlcmVuY2lhcyBlbnRyZSBsb3MgZ3J1cG9zLCBlcyByZWFsaXphciB1bmEgcHJ1ZWJhIHQgcGFyYSBsYSBkaWZlcmVuY2lhIGRlIG1lZGlhcy4NCg0KUHJ1ZWJhIGRlIGhpcMOzdGVzaXM6DQoNCiRIXzAkPSRcbXVfMS1cbXVfMj0wJCAgdnMgJEhfMSQ9JFxtdV8xIC0gXG11XzIgXG5lcSAwJA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSAsIGVjaG89Rn0NCiNQYXJhIGNvbXByb2JhciBsb3MgZGF0b3MgeSBsYXMgZGlmZXJlbmNpYXMgc2lnbmlmaWNhdGl2YXMsIHBvZGVtb3MgZWplY3V0YXIgdW4gYW7DoWxpc2lzIGRlIGNvbXBhcmFjacOzbiBkZSBwcm9tZWRpb3MgKHBydWViYSB0KQ0KdC50ZXN0KGRhdG9zW3doaWNoKGRhdG9zJFguMT09MSksMl0sZGF0b3Nbd2hpY2goZGF0b3MkWC4xPT0wKSwyXSkNCg0KYGBgDQoNCkRlIGFjdWVyZG8gYWwgcmVzdWx0YWRvLCBudWVzdHJhIHNvc3BlY2hhIGVzIGNpZXJ0YSBkZSBxdWUgbGFzIG1lZGlhcyBkZSBsb3MgdmFsb3JlcyBwYXJhIGFtYm9zIGdydXBvcyBzb24gZGlmZXJlbnRlcyB5IGVzdG8gc2UgY29udHJhc3RhIGNvbiBlbCBwLXZhbHVlIGRlICQyLjJlXnstMTZ9JCBhcnJvamFkbyBwb3IgbGEgcHJ1ZWJhLCBsbyBjdWFsIG5vcyBwZXJtaXRlIHJlY2hhemFyIGxhIGhpcMOzdGVzaXMgbnVsYS4NCg0KDQojIyA0LiBWYWxpZGFjacOzbg0KDQpEZWwgbW9kZWxvIHByZWRpY3Rpdm8gdHJhYmFqYWRvIGhhc3RhIGFob3JhLCBzaSBiaWVuIGVzIGNpZXJ0byBxdWUgc2UgY2FyYWN0ZXJpemEgcG9yIHRlbmVyIHVuYSBsw7NnaWNhIGF2YW56YWRhLCByZXF1aWVyZSBkZSB0w6lybWlub3MgZXNwZWPDrWZpY29zLiBFbiBlc3RlIGNhc28sIGVsIGVudHJlbmFtaWVudG8gc2UgcmVhbGl6w7MgY29uIGltw6FnZW5lcyBmcm9udGFsZXMgKHN0cmFpZ2h0KSwgZW50b25jZXMgbGEgdmFsaWRhY2nDs24gZGViZSBoYWNlcnNlIGNvbiBlbCBtaXNtbyB0aXBvIGRlIGltw6FnZW5lcy4gRXMgZGVjaXIsIGVsIG1vZGVsbyBwdWVkZSBwcmVkZWNpciBjb24gdW4gY2llcnRvIGdyYWRvIGRlIGVycm9yLCBzaSBzZSBsZSBldmFsw7phIGNvbiBpbcOhZ2VuZXMgc2ltaWxhcmVzIGEgbGFzIHF1ZSBzZSB1c2Fyb24gZW4gZW50cmVuYW1pZW50by4NCg0KRGVsIGNvbmp1bnRvIGRlIHZhbGlkYWNpw7NuIG9idGVuaWRvIGRlIFtVQ0kgTWFjaGluZSBMZWFybmluZyBSZXBvc2l0b3J5XShodHRwczovL2FyY2hpdmUuaWNzLnVjaS5lZHUvbWwvZGF0YXNldHMvQ01VK0ZhY2UrSW1hZ2VzKSB0ZW5lbW9zIDQyNCBmb3RvcyBxdWUgY3VtcGxlbiBjb24gZXN0YSBjYXJhY3RlcsOtc3RpY2EsIHNlIGFuYWxpemFyw6FuIHVzYW5kbyBsYSBsaWJyZXLDrWEgW3BpeG1hcF0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3BpeG1hcC92ZXJzaW9ucy8wLjQtMTIvdG9waWNzL3BubSkNCg0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHMgPSAnaGlkZScsIGVjaG89Rn0NCg0KDQojIHNldHdkKCJEOi9Vc2Vycy9Vc3VhcmlvL0Rlc2t0b3AvVU4vMTEuU0VNRVNUUkVYSS9UQUUvVHJhYmFqbzMvcHJveWVjdG8vVGVzdFZhbGlkbyIpDQojIA0KIyBsaXN0LmZpbGVzKCktPmxpc3RhDQojIA0KIyAjQ29udmVydGlyIHRvZG8gcGFyYSBwbmcNCiMgZm9yIChpIGluIDE6bGVuZ3RoKGxpc3RhKSl7DQojIHJlYWQucG5tKGxpc3RhW2ldKS0+YQ0KIyBwbmcocGFzdGUwKGxpc3RhW2ldLCIucG5nIikpDQojIHBsb3QoYSkNCiMgZGV2Lm9mZigpDQojIH0NCg0KYGBgDQoNCg0KTGFzIGltw6FnZW5lcyBzZWxlY2Npb25hZGFzIHNlIGNvbnZpcnRpZXJvbiB0b2RhcyBkZSBmb3JtYXRvIHBnbSBhIHBuZy4gVW5hIGltYWdlbiBkZSBlc3RlIGNvbmp1bnRvIGVzOg0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsZmlnLndpZHRoPSAyLGZpZy5oZWlnaHQ9IDIsZmlnLmFsaWduPSdjZW50ZXInLCBlY2hvPUZ9DQoNCnNldHdkKCJEOi9Vc2Vycy9Vc3VhcmlvL0Rlc2t0b3AvVU4vMTEuU0VNRVNUUkVYSS9UQUUvVHJhYmFqbzMvcHJveWVjdG8vVGVzdF9QTkciKQ0KDQojc2V0d2QoIkQ6L1VOSVZFUlNJREFEL1RBRS9UUkFCQUpPXzMvVGVzdF9QTkciKQ0KDQojQWJyaXIgbGFzIGltw6FnZW5lcyBkZWwgbW9kZWxvDQpsaXN0LmZpbGVzKCktPmxpc3RhDQoNCmk8LTQNCmltYWdlbmFtZSA8LWxpc3RhW2ldDQoNCmltZyA9IHJlYWRJbWFnZShpbWFnZW5hbWUpDQoNCmltZ19nPC1jaGFubmVsKGltZywiZ3JheSIpDQoNCg0KZGlzcGxheShpbWdfZyxtZXRob2Q9J3Jhc3RlcicpDQoNCmBgYA0KDQoNCg0KVW5hIHZleiBxdWUgc2UgdGllbmVuIHRvZGFzIGxhcyBpbcOhZ2VuZXMgZW4gZm9ybWF0byBwbmcsIHJlcGV0aXJlbW9zIGxvcyBwYXNvcyBpbmljaWFsZXMgcGFyYSBjYWxjdWxhciBsb3MgaGlzdG9ncmFtYXMgZGVsIGdydXBvIGRlIHZhbGlkYWNpw7NuLg0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHMgPSAnaGlkZScsIGVjaG89Rn0NCiMgc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by9UZXN0X1BORyIpDQojIA0KIyANCiMgI0FicmlyIGxhcyBpbcOhZ2VuZXMgZGVsIG1vZGVsbw0KIyBsaXN0LmZpbGVzKCktPmxpc3RhDQojIA0KIyAjVmFtb3MgYSBjcmVhciB1bmEgY29sdW1uYSBjb24gbG9zIGN1YXJ0aWxlcyBuZWNlc2FyaW9zIA0KIyANCiMgcGFzdGUwKHNlcSgwLDAuOTk1LDAuMDA1KSwiLSIsc2VxKDAuMDA1LDEsMC4wMDUpKS0+Y3VhcnRpbGVzDQojIA0KIyBkYXRhLmZyYW1lKHZhbHVlcz1jdWFydGlsZXMpLT50ZXN0DQojIA0KIyBmb3IgKGkgaW4gMTpsZW5ndGgobGlzdGEpKXsNCiMgaW1hZ2VuYW1lIDwtbGlzdGFbaV0NCiMgDQojIGltZyA9IHJlYWRJbWFnZShpbWFnZW5hbWUpDQojIA0KIyBpbWdfZzwtY2hhbm5lbChpbWcsImdyYXkiKQ0KIyANCiMgaW1nX2Nyb3AgPSBpbWdfZ1syNDU6MjY1LDIwMDoyNTBdDQojIGhpc3QoaW1nX2Nyb3AsYnJlYWtzPXNlcSgwLDEsMC4wMDUpKS0+ZGFkb3MNCiMgZGF0YS5mcmFtZSh0ZXN0LGRhZG9zJGNvdW50cyktPnRlc3QNCiMgDQojIH0NCiMgY29sbmFtZXModGVzdCk8LWMoInZhbHVlcyIsbGlzdGEpDQoNCiNHdWFyZGFuZG8gZXN0ZSByZXN1bHRhZG8NCg0KI3dyaXRlLmNzdih0ZXN0LCJEOi9Vc2Vycy9Vc3VhcmlvL0Rlc2t0b3AvVU4vMTEuU0VNRVNUUkVYSS9UQUUvVHJhYmFqbzMvcHJveWVjdG8vdGVzdC5jc3YiKQ0KDQoNCmBgYA0KDQpGaW5hbG1lbnRlIHNlIHBydWViYSB5IHNlIHJldmlzYW4gbG9zIHJlc3VsdGFkb3MgZGVsIG1vZGVsbyBlbGFib3JhZG8uDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgZWNobz1GIH0NCg0KDQojIHNldHdkKCJEOi9Vc2Vycy9Vc3VhcmlvL0Rlc2t0b3AvVU4vMTEuU0VNRVNUUkVYSS9UQUUvVHJhYmFqbzMvcHJveWVjdG8vIikNCiMgDQojIHJlYWQuY3N2KCJ0cmFpbl8xLmNzdiIpLT50cmFpbg0KIyANCiMgDQojIA0KIyB0cmFpblssMV0tPnJvd25hbWVzKHRyYWluKQ0KIyB0cmFpblssLTFdLT50cmFpbg0KIyANCiMgbXV0YXRlKHRyYWluLGdydXBvPWlmZWxzZShncnVwbz09IkNvbl9HYWZhcyIsMSwwKSktPnRyYWluMg0KIyANCiMgDQojIA0KIyAjY3JlYWNpw7NuIGRlbCBtb2RlbG8NCiMgcGNyKGdydXBvfi4sZGF0YT10cmFpbjJbLGMoMTo2MCwyMDEpXSxzY2FsZT1UUlVFLHZhbGlkYXRpb249IkNWIiktPm1vZGVsDQojIA0KIyAjUHJ1ZWJhIGNvbiBncnVwbyB0ZXN0DQojIHJlYWQuY3N2KCJ0ZXN0LmNzdiIpLT50ZXN0DQojIHRlc3RbLDJdLT5yb3duYW1lcyh0ZXN0KSANCiMgdGVzdFssLWMoMToyKV0tPnRlc3QNCiMgdCh0ZXN0KS0+dGVzdA0KIyANCiMgcHJlZGljdChtb2RlbCxuZXdkYXRhPXRlc3RbLDE6NjBdLG5jb21wPTEwKS0+cHJvYg0KDQojU2kgc2UgZGVzZWEsIHNlIHB1ZWRlbiBqdW50YXIgbG9zIGRhdG9zIGNyZWFkb3MgY29uIGxvcyB2YWxvcmVzIHJlYWxlcyAoY29sdW1uYSBncnVwbyBkZSBsYSB0YWJsYSB0cmFpbikNCiAjIHdyaXRlLmNzdihwcm9iLCJyZXN1bHRhZG9zLmNzdiIpDQogDQoNCmBgYA0KUGFyYSB2ZXIgZWwgcG9yY2VudGFqZSBkZSBhY2llcnRvcywgc2UgYW5hbGl6YW4gbG9zIHZhbG9yZXMgcmVhbGVzIHZzIHByZWRpY2hvcyBwb3IgZWwgbW9kZWxvLCBlc3RvIHNlIGhhY2UgZW4gZWwgYXJjaGl2byByZXN1bHRhZG9zLmNzdiB5IHJlc3VsdGFkbyAoMSkuY3N2IGdlbmVyYWRvcyBhbnRlcmlvbWVudGUuIEVuIGVsIHNpZ3VpZW50ZSBncsOhZmljbywgc2Ugb2JzZXJ2YW4gdmFsb3JlcyBkZSBlc3RpbWFjacOzbiBtw6FzIGFsdG9zIGVuIGxhcyBmb3RvcyBjb24gZ2FmYXMsIGNvbW8gZXJhIGRlIGVzcGVyYXJzZSBlbiBjb25jb3JkYW5jaWEgcG9yIGVsIHJlc3VsdGFkbyB2aXN0byBhbnRlcmlvbWVudGUgZW4gZWwgZ3LDoWZpY28gZGUgdmlvbMOtbi4gU2Ugb2JzZXJ2YW4gYWxndW5vcyB2YWxvcmVzIGF0w61waWNvcy4gDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsZmlnLndpZHRoPSAzLGZpZy5oZWlnaHQ9IDMsZmlnLmFsaWduPSdjZW50ZXInLGVjaG89Rn0NCg0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by8iKQ0KcmVhZC5jc3YoInJlc3VsdGFkb3MuY3N2IiktPmRhdG9zDQoNCiNkYXRvcyA8LSByZWFkLmNzdigiQzovVXNlcnMvTGVub3ZvL0Rvd25sb2Fkcy9yZXN1bHRhZG9zLmNzdiIpDQoNCnJiaW5kKG11dGF0ZShkYXRvc1tkYXRvcyRYICVsaWtlJSAib3BlbiIsXSxncnVwbz0iU2luX2dhZmFzIiksDQogICAgICBtdXRhdGUoZGF0b3NbZGF0b3MkWCAlbGlrZSUgInN1bmdsYSIsXSxncnVwbz0iQ29uX2dhZmFzIikpLT5kYXRvczINCg0KDQpnZ3Bsb3QoZGF0b3MyLGFlcyh4PWdydXBvLHk9Z3J1cG8uMTAuY29tcHMpKStnZW9tX2JveHBsb3QoKStzY2FsZV95X2xvZzEwKCkNCmBgYA0KQ29uIGxhIGludGVuY2nDs24gZGUgdmlzdWFsaXphciBlbCBkZXNlbXBlw7FvIGRlIGVzdGUgYWxnb3JpdG1vKHF1ZSBzZSBlbXBsZWEgZW4gYXByZW5kaXphamUgc3VwZXJ2aXNhZG8pIHByb2NlZGVtb3MgYSByZWFsaXphciB1bmEgbWF0cml6IGRlIGNvbmZ1c2nDs24sIGxhIGN1YWwgZXMgdW5hIGhlcnJhbWllbnRhIG11eSDDunRpbCBwYXJhIHZhbG9yYXIgcXXDqSB0YW4gYnVlbm8gZXMgdW4gbW9kZWxvIGRlIGNsYXNpZmljYWNpw7NuIGJhc2FkbyBlbiBhcHJlbmRpemFqZSBhdXRvbcOhdGljby4gRW4gcGFydGljdWxhciwgc2lydmUgcGFyYSBtb3N0cmFyIGRlIGZvcm1hIGV4cGzDrWNpdGEgY3XDoW5kbyB1bmEgY2xhc2UgZXMgY29uZnVuZGlkYSBjb24gb3RyYSwgbG8gY3VhbCBub3MgcGVybWl0ZSB0cmFiYWphciBkZSBmb3JtYSBzZXBhcmFkYSBjb24gZGlzdGludG9zIHRpcG9zIGRlIGVycm9yICh0ZWNoLCAyMDIxKS4NCg0KYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPVQsZmlnLndpZHRoPSAzLGZpZy5oZWlnaHQ9IDMsZmlnLmFsaWduPSdjZW50ZXInLGVjaG89Rn0NCiNkYXRvc213IDwtIHJlYWRfZXhjZWwoIkM6L1VzZXJzL0xlbm92by9Eb3dubG9hZHMvcmVzdWx0YWRvcyAoMSkueGxzeCIpDQoNCg0Kc2V0d2QoIkQ6L1VzZXJzL1VzdWFyaW8vRGVza3RvcC9VTi8xMS5TRU1FU1RSRVhJL1RBRS9UcmFiYWpvMy9wcm95ZWN0by8iKQ0KZGF0b3NtdyA8LSByZWFkeGw6OnJlYWRfZXhjZWwoInJlc3VsdGFkb3MoMSkueGxzeCIpICAgDQoNCmRhdG9zbXckVGXDs3JpY28gPC0gYXMuZmFjdG9yKGRhdG9zbXckVGXDs3JpY28pDQpkYXRvc213JEVzdGltYWRvIDwtIGFzLmZhY3RvcihkYXRvc213JEVzdGltYWRvKQ0KDQpjbSA8LSBjb25mX21hdChkYXRvc213LCBFc3RpbWFkbywgVGXDs3JpY28pDQoNCmF1dG9wbG90KGNtLCB0eXBlID0gImhlYXRtYXAiKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInBpbmsiLCBoaWdoID0gImN5YW4iKQ0KDQoNCmBgYA0KTG9zIHZhbG9yZXMgZGUgbGEgZGlhZ29uYWwgcHJpbmNpcGFsIGE9MjA5KDk4LjU4JSkgeSBkPTE3Myg4MS42JSkgY29ycmVzcG9uZGVuIHRhbnRvIGEgbG9zIHZhbG9yZXMgZXN0aW1hZG9zIGRlIGZvcm1hIGNvcnJlY3RhIHBvciBlbCBtb2RlbG8sIGNvbW8gYSBsb3MgdmVyZGFkZXJvcyBwb3NpdGl2b3MgZCA9IDE3MyhpbcOhZ2VuZXMgY29uIGxlbnRlcyksIHkgYSBsb3MgdmVyZGFkZXJvcyBuZWdhdGl2b3MgYT0gMjA5KGltw6FnZW5lcyBzaW4gbGVudGVzKS4NCg0KTGEgb3RyYSBkaWFnb25hbCwgcG9yIHRhbnRvLCByZXByZXNlbnRhIGxvcyBjYXNvcyBlbiBsb3MgcXVlIGVsIG1vZGVsbyBzZSBoYSBlcXVpdm9jYWRvIChjPTM5KDE4LDQlKSBmYWxzb3MgbmVnYXRpdm9zLCBiPTMoMS40MiUpIGZhbHNvcyBwb3NpdGl2b3MpLg0KDQpMdWVnbyBkZSBoYWJlciBhbmFsaXphZG8gbGEgbWF0cml4IGRlIGNvbmZ1c2nDs24sIHNlIHByb2NlZGUgYSBjYWxjdWxhciBsYSBleGFjdGl0dWQsIGxhIHByZWNpc2nDs24sIGxhIHNlbnNpYmlsaWRhZCB5IGxhIGVzcGVjaWZpY2lkYWQuDQoNCi0gRXhhY3RpdHVkDQpMYSBleGFjdGl0dWQgKG8gwqthY2N1cmFjecKrKSByZXByZXNlbnRhIGVsIHBvcmNlbnRhamUgZGUgcHJlZGljY2lvbmVzIGNvcnJlY3RhcyBmcmVudGUgYWwgdG90YWwuIFBvciB0YW50bywgZXMgZWwgY29jaWVudGUgZW50cmUgbG9zIGNhc29zIGJpZW4gY2xhc2lmaWNhZG9zIHBvciBlbCBtb2RlbG8gKHZlcmRhZGVyb3MgcG9zaXRpdm9zIHkgdmVyZGFkZXJvcyBuZWdhdGl2b3MsIGVzIGRlY2lyLCBsb3MgdmFsb3JlcyBlbiBsYSBkaWFnb25hbCBkZSBsYSBtYXRyaXogZGUgY29uZnVzacOzbiksIHkgbGEgc3VtYSBkZSB0b2RvcyBsb3MgY2Fzb3MuDQoNCigyMDkrMTczKS8oMjA5KzE3MyszOSszKT0zODIvNDI0PSAwLjkwMDk0MzQqMTAwJSA9IDkwJQ0KDQpFbCB2YWxvciBvYnRlbmlkbyBwYXJhIGxhIGV4YWN0aXR1ZCBlbiBlc3RlIG1vZGVsbyBlcyBkZWwgOTAlLg0KDQotIFByZWNpc2nDs24NCkxhIHByZWNpc2nDs24sIChv4oCccHJlY2lzaW9u4oCdKSBzZSByZWZpZXJlIGEgbG8gY2VyY2EgcXVlIGVzdMOhIGVsIHJlc3VsdGFkbyBkZSB1bmEgcHJlZGljY2nDs24gZGVsIHZhbG9yIHZlcmRhZGVyby4gUG9yIHRhbnRvLCBlcyBlbCBjb2NpZW50ZSBlbnRyZSBsb3MgY2Fzb3MgcG9zaXRpdm9zIGJpZW4gY2xhc2lmaWNhZG9zIHBvciBlbCBtb2RlbG8geSBlbCB0b3RhbCBkZSBwcmVkaWNjaW9uZXMgcG9zaXRpdmFzLg0KDQooMTczKS8oMTczKzMpPSAwLjk4Mjk1NDUqMTAwJSA9IDk4LjMlDQoNCkVsIHZhbG9yIG9idGVuaWRvIHBhcmEgZXN0ZSBtb2RlbG8gZXMgZGUgdW4gOTguMyUuIFBvciB0YW50bywgbnVlc3RybyBtb2RlbG8gZXMgbcOhcyBwcmVjaXNvIHF1ZSBleGFjdG8uDQoNCi0gU2Vuc2liaWxpZGFkDQpMYSBzZW5zaWJpbGlkYWQgKG8gcmVjYWxsKSByZXByZXNlbnRhIGxhIHRhc2EgZGUgdmVyZGFkZXJvcyBwb3NpdGl2b3MgKFRydWUgUG9zaXRpdmUgUmF0ZSkgw7MgVFAuIEVzIGxhIHByb3BvcmNpw7NuIGVudHJlIGxvcyBjYXNvcyBwb3NpdGl2b3MgYmllbiBjbGFzaWZpY2Fkb3MgcG9yIGVsIG1vZGVsbywgcmVzcGVjdG8gYWwgdG90YWwgZGUgcG9zaXRpdm9zLCBlbCBjdWFsIGVzLCBsYSBoYWJpbGlkYWQgZGVsIG1vZGVsbyBkZSBkZWN0ZXRhciBsb3MgY2Fzb3MgcmVsZXZhbnRlcy4NCg0KMTczLygzOSsxNzMpID0gMC44MTYwMzc3KjEwMCUgPSA4MS42JQ0KDQpVbiA4MS42JSBlcyBjbGFyYW1lbnRlIHVuIHZhbG9yIG11eSBidWVubyBwYXJhIHVuYSBtw6l0cmljYS4gUG9kZW1vcyBkZWNpciBxdWUgbnVlc3RybyBhbGdvcml0bW8gZGUgY2xhc2lmaWNhY2nDs24gZXMgc2Vuc2libGUsIGVzIGRlY2lyLCBubyBzZSBsZSBlc2NhcGFuIG11Y2hvcyBwb3NpdGl2b3MuDQoNCi0gRXNwZWNpZmljaWRhZA0KTGEgZXNwZWNpZmljaWRhZCwgcG9yIHN1IHBhcnRlLCBlcyBsYSB0YXNhIGRlIHZlcmRhZGVyb3MgbmVnYXRpdm9zLCAo4oCcdHJ1ZSBuZWdhdGl2ZSByYXRl4oCdKW8gVE4uIEVzIGxhIHByb3BvcmNpw7NuIGVudHJlIGxvcyBjYXNvcyBuZWdhdGl2b3MgYmllbiBjbGFzaWZpY2Fkb3MgcG9yIGVsIG1vZGVsbywgcmVzcGVjdG8gYWwgdG90YWwgZGUgbmVnYXRpdm9zLg0KDQoyMDkvKDIwOSszKSA9IDAuOTg1ODQ5MSoxMDAlID0gOTguNiUNCg0KRW4gZXN0ZSBjYXNvLCBsYSBlc3BlY2lmaWNpZGFkIHRpZW5lIHVuIHZhbG9yIG11eSBidWVuby4gRXN0byBzaWduaWZpY2EgcXVlIHN1IGNhcGFjaWRhZCBkZSBkaXNjcmltaW5hciBsb3MgY2Fzb3MgbmVnYXRpdm9zIGVzIG11eSBidWVuYS4gRXMgZGVjaXIsIGVzIGRpZsOtY2lsIG9idGVuZXIgZmFsc29zIHBvc2l0aXZvcy4NCg0KLSBDb25jbHVzacOzbg0KQ29tbyBzZSBwdWRvIG9ic2VydmFyLCBwYXJhIGNhZGEgbcOpdHJpY2Egc2Ugb2J0dXZpZXJvbiB2YWxvcmVzIGFsdG9zLCBsbyBjdWFsIGluZGljYSBxdWUgZWwgbW9kZWxvIHRpZW5lIGFsdGEgcHJlY2lzacOzbiB5IGV4YWN0aXR1ZCwgeSBhZGVtw6FzIGRlIGVsbG8gdGllbmUgdW5hIGFsdGEgc2Vuc2liaWxpZGFkKHRpZW5lIGFsdG8gcG9yY2VudGFqZSBlbiBkZXRlY3RhciBjYXNvcyBwb3NpdGl2b3MpIHkgdW5hIGFsdGEgZXNwZWNpZmljaWRhZCh0aWVuZSBhbHRvIHBvcmNlbnRhamUgZW4gZGV0ZWN0YXIgY2Fzb3MgbmVnYXRpdm9zKS4NCg0KTnVldmFtZW50ZSwgY29tbyBzZSBoaXpvIHBhcmEgZWwgY29uanVudG8gZGUgZW50cmVuYW1pZW50bywgc2UgcmVhbGl6YSB1bmEgcHJ1ZWJhIHQgcGFyYSBsYSBkaWZlcmVuY2lhIGRlIG1lZGlhcyBlbnRyZSBsb3MgZ3J1cG9zLg0KDQpQcnVlYmEgZGUgaGlww7N0ZXNpczoNCg0KJEhfMCQ9JFxtdV8xLVxtdV8yPTAkICB2cyAkSF8xJD0kXG11XzEgLSBcbXVfMiBcbmVxIDAkDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UgLCBlY2hvPUZ9DQojUGFyYSBjb21wcm9iYXIgbG9zIGRhdG9zIHkgbGFzIGRpZmVyZW5jaWFzIHNpZ25pZmljYXRpdmFzLCBwb2RlbW9zIGVqZWN1dGFyIHVuIGFuw6FsaXNpcyBkZSBjb21wYXJhY2nDs24gZGUgbWVkaWFzIChwcnVlYmEgdCkNCnQudGVzdChkYXRvczJbd2hpY2goZGF0b3MyJGdydXBvPT0iQ29uX2dhZmFzIiksMl0sZGF0b3Nbd2hpY2goZGF0b3MyJGdydXBvPT0iU2luX2dhZmFzIiksMl0pDQoNCg0KYGBgDQpEZSBhY3VlcmRvIGFsIHJlc3VsdGFkbywgbnVlc3RyYSBzb3NwZWNoYSBlcyBjaWVydGEgZGUgcXVlIGxhcyBtZWRpYXMgZGUgbG9zIHZhbG9yZXMgcGFyYSBhbWJvcyBncnVwb3Mgc29uIGRpZmVyZW50ZXMgeSBlc3RvIHNlIGNvbnRyYXN0YSBjb24gZWwgcC12YWx1ZSBkZSAwLjAwMDE2NTUgYXJyb2phZG8gcG9yIGxhIHBydWViYSwgbG8gY3VhbCBub3MgcGVybWl0ZSByZWNoYXphciBsYSBoaXDDs3Rlc2lzIG51bGEuDQoNCg0KDQoNCg0KIyMgNS4gSW50ZXJyb2dhbnRlcyANCg0KDQojIyMgNS4xLiDCv1F1w6kgYWZlY3RhIGxhIGNhcGFjaWRhZCBkZWwgbW9kZWxvIGVuIGVsIGNvbmp1bnRvIGRlIHZhbGlkYWNpw7NuPw0KDQotIExhIHViaWNhY2nDs24gZGUgbG9zIHJvc3Ryb3MuIFByZWZlcmlibGVtZW50ZSBzZSBkZXNlYSBxdWUgdG9kYXMgbGFzIGltw6FnZW5lcyBzZWFuIGNlbnRyYWRhcyBlbiBkb25kZSBzZSBkZW5vdGUgZWwgc2VwdG8gbmFzYWwuIEltw6FnZW5lcyBkZSBwZXJmaWwgbyBjb24gZWwgbWVudMOzbiBsZXZhbnRhZG8gbm8gc29uIGFwdGFzIHBhcmEgZXN0ZSBtb2RlbG8uDQoNCi0gTGEgZXN0YWRhcml6YWNpw7NuIGRlIGxhcyBpbcOhZ2VuZXMuIEV4aXN0ZW4gZm90b3MgZXh0cmHDsWFzIGVuIGVsIGNvbmp1bnRvIGRlIHZhbGlkYWNpw7NuLCBpbcOhZ2VuZXMgZG9ibGVzIMOzIGNvbiByb3N0cm9zIGEgbWVkaWFzLCBlc3RvIGdlbmVyYSBydWlkbyB5IGVudG9ycGVjZSBsYSBjYXBhY2lkYWQgZGUgY2xhc2lmaWNhciBjb3JyZWN0YW1lbnRlLg0KDQotIExhIHRleiBkZSBsYXMgcGVyc29uYXMgZGUgbGFzIGZvdG9ncmFmw61hcy4gUHVlZGUgbGxlZ2FyIGEgYWx0ZXJhciBlbCBtb2RlbG8gZGViaWRvIGEgIGxhIGNhbnRpZGFkIGRlIHDDrXhlbGVzIChZYSBzZWFuIG1hcyBvc2N1cm9zIG8gbcOhcyBjbGFyb3MpIGRlYmlkbyBhIHF1ZSBubyBwb2Ryw61hIGRpc3Rpbmd1aXIgc2kgbGEgcGVyc29uYSBsbGV2YSBnYWZhcyBvIG5vLg0KDQotIEVycm9yZXMgaHVtYW5vcy4gRWwgbWFsIHByb2NlZGltaWVudG8gYSBsYSBob3JhIGRlIGVzY29nZXIgdW5hIGltYWdlbiB5IGFncmVnYXJsYSBlbiBsYSBjbGFzaWZpY2FjacOzbiBpbmNvcnJlY3RhLg0KDQotIEZvcm1hdG8gZGUgaW3DoWdlbmVzLiBMYSB0cmFuc2Zvcm1hY2nDs24gZGUgaW3DoWdlbmVzIGRlIHBnbSBhIHBuZyBwYXJhIGVsIGRlc2Fycm9sbG8gZGVsIG1vZGVsby4NCg0KDQoNCiMjIyA1LjIuIMK/SGF5IGFsZ3VuYSBjYXJhY3RlcsOtc3RpY2EgZGUgbGFzIGltw6FnZW5lcyBxdWUgbWVqb3JlIGxhIGNhcGFjaWRhZCBkZSByZXNwdWVzdGE/DQoNCg0KLSBDb21vIHNlIGRpam8gYW50ZXJpb3JtZW50ZSwgcXVlIHRvZGFzIGxhcyBpbcOhZ2VuZXMgc2VhbiBmcm9udGFsZXMuDQoNCi0gTGEgbml0aWRleiBkZSBsYXMgaW3DoWdlbmVzLg0KDQotIFBhcmEgZXN0ZSBtb2RlbG8sIGxhcyBwZXJzb25hcyBjb24gdGV6IGNsYXJhIGRlYmVyw61hbiB1c2FyIGxlbnRlcyBvc2N1cm9zIHBhcmEgcXVlIMOpc3RlIHB1ZWRhIGlkZW50aWZpY2FyIHF1ZSBzw60gcG9zZWVuIGxlbnRlcy4NCg0KDQojIyA2LiBFbmxhY2UgZGUgaW50ZXLDqXMNCg0KVXN0ZWQgcHVlZGUgcmV2aXNhciBlbCBjw7NkaWdvIHkgbG9zIGRhdG9zIHVzYWRvcyBlbiBlc3RlIHByb3llY3RvIGVuIG51ZXN0cm8gcmVwb3NpdG9yaW8gZW4gW0dpdGh1Yl0oaHR0cHM6Ly9naXRodWIuY29tL2RhYXRvcm9hZy9QUk9ZRUNUT1MtVEFFL3RyZWUvbWFpbi9UZXJjZXJhJTIwZW50cmVnYSkNCg0KIyMgNy4gUmVmZXJlbmNpYXMNCg0KTXVyY2lhLCBVLiBkLiAoMTMgZGUgRmVicmVybyBkZSAyMDA2KS4gT2J0ZW5pZG8gZGUgaHR0cHM6Ly93d3cudW0uZXMvZ2VvZ3JhZi9zaWdtdXIvdGVtYXJpb2h0bWwvbm9kZTc0Lmh0bWwgIA0KDQp0ZWNoLCBULiAoMTMgZGUgRGljaWVtYnJlIGRlIDIwMjEpLiBPYnRlbmlkbyBkZSBodHRwczovL2VtcHJlc2FzLmJsb2d0aGlua2JpZy5jb20vY29tby1pbnRlcnByZXRhci1sYS1tYXRyaXotZGUtY29uZnVzaW9uLWVqZW1wbG8tcHJhY3RpY28vDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K