Resultados

  1. 3 modelos fueron ocupados: xgboost, regresión lasso y ensamblaje (stacked generalization)

  2. El modelo xgboost tuvo la mejor performance con un RMSE de 0.2223.

  3. Pareciera que las variables más importantes para predecir el precio son: la comuna en la que la casa es construida junto con los metros útiles y totales de una propiedad.

  4. En el caso de los metros útiles existe una fuerte relación lineal con el precio de la vivienda. Para los metros totales la relación con el outcome es cuadrática cóncava.

  5. El número de piezas, baños y estacionamientos también tienen un efecto sobre el precio.

  6. Aunque no tan importante como las variables anteriores, las palabras en la descripción de la casa también tienen un impacto. Entre las más importantes están los lugares (calles, barrios), los adjetivos (finas, espectacular) y las características de la casa (pozo, parquet, mediterránea, riego).

Intro

Se que esto ha sido hecho muchas veces, pero quería intentar predecir el precio de las casas en la ciudad donde vivo. Con ese objetivo hice webscrapping en la página Portal Inmobiliario, el cual es un sitio web en donde la gente publica propiedades para la venta o el arriendo. La base de datos fue recolectada en mayo de 2021. Solo casas en los distritos urbanos de la Región Metropolitana de Chile fueron consideradas.

Variables

Vamos a partir por describir nuestra variable outcome. Esta es PrecioPesos la cual es el precio de las casas en pesos chilenos.

La distribución de la variable es bastante interesante, ya que tiene 3 peaks. Esto se debe a que la gente que publica los precios prefiere poner números “bonitos” en vez de “feos”. Por ejemplo, es más común que la gente publique una propiedad con un precio de 100,000,000 o 50,000,000 en vez de números como 127,699,322. Esto es lo que provoca que la data tenga estos peaks. Los datos están cargados hacia la izquierda; hay más casas caras que baratas. La razón detrás de esto es que en nuestra muestra la mayoría de las casas proviene de comunas ricas.

Una siguiente variable es metrosUtiles que son aquellos metros que están dentro de la casa. Parece que existe una relación lineal bastante fuerte entre ésta y la variable de outcome.

Otra variable importante son los metros totales de las casas, metrosTotales3 en la base. Los metros totales es la suma de los metros que están dentro y fuera de la casa. En este caso pareciera haber una fuerte relación cuadrática. Los valores son marginalmente positivos hasta cierto punto en donde un metro cuadrado más pasa a tener un efecto negativo sobre el precio de la casa. Esto se debe posiblemente a que las casas con muchos metros totales tienden a estar en sectores rurales, en donde el precio de suelo es más bajo en comparación con las zonas urbanas.

Si miramos al resto de las variables es también posible establecer algún tipo de relación. A medida que aumenta el número de baños también aumenta el precio de las casas, como se puede apreciar en el gráfico.

En el caso de los dormitorios pareciera ser que las casas con 1 dormitorio son más caras que las que tienen dos. Pero luego el valor pareciera ir incrementando desde las 2 piezas hasta estabilizarse cerca de las 6 o 7 habitaciones.

Sobre el número de estacionamiento es claro que las casas con 1 solo estacionamiento tienen precios mucho más bajos. Luego el precio al igual que con las otras variables se incrementa hasta estancarse cerca de los 6 estacionamientos.

Otra variable importante es la comuna. En el gráfico se puede ver las claras diferencias que existen entre los diferentes distritos. La línea roja representa la mediana del precio en nuestra muestra. La mayoría de las casas en nuestra muestra vienen de los 4 distritos más exclusivos de Santiago (Lo Barnechea, Vitacura, Las Condes, Chicureo). Mirando el gráfico es claro que existen diferencias muy grandes entre los distritos. Los ochos distritos más pobres tienen una mediana de precios que no es ni la octava parte de la mediana del distrito más rico.

En el siguiente mapa 3D podemos ver la mediana del precio (En millones de pesos chilenos) de las casas por comuna. El precio está representado por el color y la altura que tiene cada distrito en el mapa. Se puede ver que las comunas ricas están hacia el noreste del mapa. Mientras que los distritos más pobres están al sur y al este del mapa. Son estos los distritos en donde, preferentemente, se relocaliza a personas que vivían en asentamientos ilegales en los años 80 ’s. Por último, tenemos a Chicureo y Colina hacia el norte separado del resto de la región metropolitana. El gráfico es interactivo por lo que se puede rotar y hacer zoom.

Existe también una pequeña descripción la cual tokenizamos con el fin de ver las palabras que tienen un efecto más grande sobre el precio de las casas. En los 2 gráficos que vienen a continuación, solo seleccionamos palabras que aparecieran como mínimo en la descripción de 200 casas. Entre las palabras con una mayor mediana en el precio hay algunas que presentan características de la casa como: cava, cine, mármol, sauna, subterráneo. Otras representan barrios (La Dehesa, El Golf) y otras a adjetivos: finas, espectacular, maravilloso, precioso. Una palabra que llama la atención es arquitecto. Esta palabra tiene probablemente un efecto positivo, debido que solo se mencionara al arquitecto, por nombre y apellido, cuando es un arquitecto reconocido. Es posible pensar que este tipo de arquitectos construyen casas muy caras. La palabra mediterránea también nos llama la atención, ésta tiene un efecto positivo porque está de moda en los barrios de clase media alta construir casas con este estilo.

Por otro lado, existen también palabras que están asociadas a precios bajos. Algunas tienen relación con lugares, en específico distritos y calles: Vespucio, Tobalaba, Maipú, Puente. Hay otras 5 palabras que me llaman la atención. La primera es villa, que es la manera de referirse a un barrio de clase media en Chile. La segunda son las palabras asociadas a los bienes raíces como corretaje, corredora. La tercera es pareada, esto se debe a que en Chile es muy común construir casas pareadas en barrios de clase media. La cuarta es pasaje, que probablemente está asociada con la forma en la que construyen los barrios de clase media. Quinto, locomoción, es obvio que esta palabra va a estar ligada a casas en barrios en que las personas no pueden comprar un auto.

Tenemos un gran grupo de variables dummy. Una que me pareció interesante es la variable piscina, está variable tiene un efecto también sobre el precio de las casas. El gráfico tiene en un eje el precio de la casa y en otro los metros útiles. El color de los hexágonos representa el porcentaje de casas con piscina en esa área Es posible constatar que la proporción de casas con piscina tiende a aumentar a medida que el precio de las casas aumenta. Ahora bien, es importante notar que esta variable pareciera también tener una relación con los metros cuadrados de la casa.

Tratamiento A Las Variables

Algunos outliers fueron removidos, principalmente algunas casas que pertenecían a sectores rurales (que no eran de nuestro interés), algunos errores de tipeo y observaciones duplicadas. Las observaciones numéricas fueron transformadas a logaritmos y normalizadas. Además, la variable comuna fue transformada a una variable numérica tomando como referencia la mediana del precio de las casas por distrito.

Resultados

Corrimos 3 modelos, uno ocupando xgboost, el segundo una regresión lasso y el último en el cual ensamblamos ambos modelos. El mejor modelo fue en xgboost. Estos fueron los resultados:

Si miramos las variables más importantes tenemos el distrito (comuna2), esto quizás se explica porque esta variable contiene muchos componentes dentro de ésta, principalmente acceso a servicios y bienes públicos como: hospitales, parques, escuelas; y otros elementos muy importantes como puede ser la seguridad.

La segunda variable más importante son los metros totales (metrosTotales3_poly_1 y metrosTotales3_poly_2) y metros útiles metrosUtiles. Lo cual tiene sentido porque uno esperaría que mientras más grande fuera la casa mayor sería el precio. Lo interesante es que los metros totales tienen una relación cuadrática cóncava, lo cual puede ser debido a que las casas con una extensión muy grande de terreno están localizadas en sectores más rurales en donde el precio del suelo es más bajo lo cual produce esta relación.

Luego de estas variables las más importantes son el número de baños baños2, la existencia de una piscina piscina, el número de dormitorios dormitorios2 y el número de estacionamientos parking20

Aunque el texto no era una variable importante en el modelo xgboost si lo era en el modelo lasso. Aquí los resultados de las palabras que tenían mayor importancia:

Entre las palabras con un efecto positivo tenemos lugares tales: los distritos de Quilicura, Providencia, condes (Las Condes) y barrios tales como damián (San Damián) y golf (El Golf). El hecho de que Quilicura tenga un efecto positivo nos toma por sorpresa ya que no es un distrito rico de Santiago. Verbo está ahí por el colegio Verbo Divino, que es uno de los establecimientos educacionales más exclusivos de Santiago. Otras palabras con un efecto positivo son: los adjetivos espectacular y finas, la presencia de parquet en la casas, cuando las casas son construidas con estilo mediterraneo y,por último, la palabra easybroker que es probablemente una compañía de corretaje.

Entre las palabras con efecto negativo tenemos Chicureo, lo cual es curioso debido a que es uno de los distritos más ricos de Santiago. La explicación es que ya que la mayoría de la muestra proviene de los 4 cuatros distritos más ricos (Lo Barnechea, Vitacura, Las Condes y Chicureo), Chicureo al tener la mediana de precios más baja de este grupo pasa a tener un efecto negativo en el total de la muestra. Chamisero es una calle en Chicureo por lo tanto esa es la razón por la que por la que esta palabra también tendría un efecto negativo.

Otras palabras como riego, pozo y bosca son señales de ruralidad porque creo que es esa la razón del efecto que tienen. Las últimas palabras son colegio y contando. Sobre éstas es un poco difícil tener una razón clara de la razón del efecto negativo. Puede ser que cuando los precios no son caros los vendedores piden el pago al contado. Colegios, puede tener un efecto negativo debido a que cuando los colegios alrededor de una propiedad no son muy conocidos, las personas solo mencionan la palabra “colegio” en vez del nombre del colegio, como pasa con el Verbo Divino.

Aquí están los resultados para todos los modelos:

Conclusiones

Primero que todo, creo que es importante precisar que hay que tener consideraciones importantes cuando se analizan estos resultados, ya que el grueso de las casas en nuestra muestra viene de barrios acomodados. Si tuviéramos una muestra más equilibrada quizás los resultados serían otros. Aquí un gráfico con las casas por comuna.

Dejando lo anterior claro aquí, la comuna es la variable que ayuda a predecir de mejor manera el precio de la vivienda. Es interesante notar como aquellas comunas que recibieron más familias relocalizadas en los 80 ’s son aquellas que tienen precios más bajos. La importancia de los metros útiles y totales no nos sorprende, lo que sí consideramos sorprendente es la relación cuadrática entre el precio de la vivienda y los metros totales del hogar.

A pesar de que intentamos no considerar sectores rurales en nuestra muestra pareciera que no fuimos del todo exitosos como indicarían las palabras: riego, pozo y bosca. Creo, además, que queda pendiente hacer un modelo con pares de palabras, binomios, en vez de solo ocupar palabras sueltas. Creo que a pesar de los buenos resultados del modelo queda espacio para mejorar la performance, seria del gran ayuda poder contar con servidores para entrenar de mejor manera nuestros datos.

LS0tDQp0aXRsZTogIlByZWRpY2llbmRvIGVsIFByZWNpbyBkZSBsYXMgQ2FzYXMgZW4gU2FudGlhZ28gZGUgQ2hpbGUiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICB0b2M6IHllcw0KLS0tDQo8c3R5bGU+DQoNCmJvZHl7DQogdGV4dC1hbGlnbjoganVzdGlmeTsNCn0NCg0KPC9zdHlsZT4NCg0KIyMgUmVzdWx0YWRvcw0KDQoxKSAzIG1vZGVsb3MgZnVlcm9uIG9jdXBhZG9zOiB4Z2Jvb3N0LCByZWdyZXNpw7NuIGxhc3NvIHkgZW5zYW1ibGFqZSAoKnN0YWNrZWQgZ2VuZXJhbGl6YXRpb24qKQ0KDQoyKSBFbCBtb2RlbG8geGdib29zdCB0dXZvIGxhIG1lam9yIHBlcmZvcm1hbmNlIGNvbiB1biBSTVNFIGRlIDAuMjIyMy4NCg0KMykgUGFyZWNpZXJhIHF1ZSBsYXMgdmFyaWFibGVzIG3DoXMgaW1wb3J0YW50ZXMgcGFyYSBwcmVkZWNpciBlbCBwcmVjaW8gc29uOiBsYSBjb211bmEgZW4gbGEgcXVlIGxhIGNhc2EgZXMgY29uc3RydWlkYSBqdW50byBjb24gbG9zIG1ldHJvcyDDunRpbGVzIHkgdG90YWxlcyBkZSB1bmEgcHJvcGllZGFkLg0KDQo0KSBFbiBlbCBjYXNvIGRlIGxvcyBtZXRyb3Mgw7p0aWxlcyBleGlzdGUgdW5hIGZ1ZXJ0ZSByZWxhY2nDs24gbGluZWFsIGNvbiBlbCBwcmVjaW8gZGUgbGEgdml2aWVuZGEuIFBhcmEgbG9zIG1ldHJvcyB0b3RhbGVzIGxhIHJlbGFjacOzbiBjb24gZWwgKm91dGNvbWUqIGVzIGN1YWRyw6F0aWNhIGPDs25jYXZhLg0KDQo1KSBFbCBuw7ptZXJvIGRlIHBpZXphcywgYmHDsW9zIHkgZXN0YWNpb25hbWllbnRvcyB0YW1iacOpbiB0aWVuZW4gdW4gZWZlY3RvIHNvYnJlIGVsIHByZWNpby4NCg0KNikgQXVucXVlIG5vIHRhbiBpbXBvcnRhbnRlIGNvbW8gbGFzIHZhcmlhYmxlcyBhbnRlcmlvcmVzLCBsYXMgcGFsYWJyYXMgZW4gbGEgZGVzY3JpcGNpw7NuIGRlIGxhIGNhc2EgdGFtYmnDqW4gdGllbmVuIHVuIGltcGFjdG8uIEVudHJlIGxhcyBtw6FzIGltcG9ydGFudGVzIGVzdMOhbiBsb3MgbHVnYXJlcyAoY2FsbGVzLCBiYXJyaW9zKSwgbG9zIGFkamV0aXZvcyAoZmluYXMsIGVzcGVjdGFjdWxhcikgeSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBsYSBjYXNhIChwb3pvLCBwYXJxdWV0LCBtZWRpdGVycsOhbmVhLCByaWVnbykuDQoNCg0KDQojIyBJbnRybw0KDQohW10oaHR0cHM6Ly9jZ3Bhcm9kaS5jbC93cC1jb250ZW50L3VwbG9hZHMvMjAxOC8wNS9wb3J0YWwtY29tcHJlc3Nvci5wbmcpDQoNClNlIHF1ZSBlc3RvIGhhIHNpZG8gaGVjaG8gbXVjaGFzIHZlY2VzLCBwZXJvIHF1ZXLDrWEgaW50ZW50YXIgcHJlZGVjaXIgZWwgcHJlY2lvIGRlIGxhcyBjYXNhcyBlbiBsYSBjaXVkYWQgZG9uZGUgdml2by4gQ29uIGVzZSBvYmpldGl2byBoaWNlIHdlYnNjcmFwcGluZyBlbiBsYSBww6FnaW5hIFtQb3J0YWwgSW5tb2JpbGlhcmlvXShodHRwczovL3d3dy5wb3J0YWxpbm1vYmlsaWFyaW8uY29tLyksDQplbCBjdWFsIGVzIHVuIHNpdGlvIHdlYiBlbiBkb25kZSBsYSBnZW50ZSBwdWJsaWNhIHByb3BpZWRhZGVzIHBhcmEgbGEgdmVudGEgbyBlbCBhcnJpZW5kby4gTGEgYmFzZSBkZSBkYXRvcyBmdWUgcmVjb2xlY3RhZGEgZW4gbWF5byBkZSAyMDIxLiBTb2xvIGNhc2FzIGVuIGxvcyBkaXN0cml0b3MgdXJiYW5vcyBkZSBsYSBSZWdpw7NuIE1ldHJvcG9saXRhbmEgZGUgQ2hpbGUgZnVlcm9uIGNvbnNpZGVyYWRhcy4NCg0KIyMgVmFyaWFibGVzDQoNClZhbW9zIGEgcGFydGlyIHBvciBkZXNjcmliaXIgbnVlc3RyYSB2YXJpYWJsZSAqb3V0Y29tZSouIEVzdGEgZXMgKipQcmVjaW9QZXNvcyoqIGxhIGN1YWwgZXMgZWwgcHJlY2lvIGRlIGxhcyBjYXNhcyBlbiBwZXNvcyBjaGlsZW5vcy4NCg0KDQpgYGB7cixlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxmaWcud2lkdGg9Ny41LCBmaWcuaGVpZ2h0PTQuMn0NCg0KZGVuc2l0eSA8LSBkZW5zaXR5KHBvcnRhbDQkcHJlY2lvUGVzb3MpDQoNCnBsb3RfbHkob3BhY2l0eT0wLjUpICU+JSANCiAgYWRkX2xpbmVzKHg9fmRlbnNpdHkkeCx5PX5kZW5zaXR5JHkpICU+JSANCmxheW91dCh0aXRsZSA9ICdEZW5zaXR5IERpc3RyaWJ1dGlvbicsDQogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJIb3VzZSBQcmljZSAoQ2hpbGVhbiBQZXNvcykiKSwNCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gImRlbnNpdHkiKSkNCmBgYA0KDQoNCkxhIGRpc3RyaWJ1Y2nDs24gZGUgbGEgdmFyaWFibGUgZXMgYmFzdGFudGUgaW50ZXJlc2FudGUsIHlhIHF1ZSB0aWVuZSAzIHBlYWtzLiBFc3RvIHNlIGRlYmUgYSBxdWUgbGEgZ2VudGUgcXVlIHB1YmxpY2EgbG9zIHByZWNpb3MgcHJlZmllcmUgcG9uZXIgbsO6bWVyb3MgImJvbml0b3MiIGVuIHZleiBkZSAiZmVvcyIuIFBvciBlamVtcGxvLCBlcyBtw6FzIGNvbcO6biBxdWUgbGEgZ2VudGUgcHVibGlxdWUgdW5hIHByb3BpZWRhZCBjb24gdW4gcHJlY2lvIGRlIDEwMCwwMDAsMDAwIG8gNTAsMDAwLDAwMCBlbiB2ZXogZGUgbsO6bWVyb3MgY29tbyAxMjcsNjk5LDMyMi4gRXN0byBlcyBsbyBxdWUgcHJvdm9jYSBxdWUgbGEgZGF0YSB0ZW5nYSBlc3RvcyBwZWFrcy4gTG9zIGRhdG9zIGVzdMOhbiAqY2FyZ2Fkb3MqIGhhY2lhIGxhIGl6cXVpZXJkYTsgaGF5IG3DoXMgY2FzYXMgY2FyYXMgcXVlIGJhcmF0YXMuIExhIHJhesOzbiBkZXRyw6FzIGRlIGVzdG8gZXMgcXVlIGVuIG51ZXN0cmEgbXVlc3RyYSBsYSBtYXlvcsOtYSBkZSBsYXMgY2FzYXMgcHJvdmllbmUgZGUgY29tdW5hcyAqcmljYXMqLg0KDQpVbmEgc2lndWllbnRlIHZhcmlhYmxlIGVzICoqbWV0cm9zVXRpbGVzKiogcXVlIHNvbiBhcXVlbGxvcyBtZXRyb3MgcXVlIGVzdMOhbiBkZW50cm8gZGUgbGEgY2FzYS4gUGFyZWNlIHF1ZSBleGlzdGUgdW5hIHJlbGFjacOzbiBsaW5lYWwgYmFzdGFudGUgZnVlcnRlIGVudHJlIMOpc3RhIHkgbGEgdmFyaWFibGUgZGUgb3V0Y29tZS4NCg0KDQoNCmBgYHtyLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFLGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9NC4yfQ0KDQptMTwtbG0obG9nKHByZWNpb1Blc29zKSB+IGxvZyhtZXRyb3NVdGlsZXMpLGRhdGE9IHBvcnRhbDMpDQoNCg0KZmlnIDwtcGxvdF9seShkYXRhID0gcG9ydGFsMywgeCA9IH5sb2cobWV0cm9zVXRpbGVzKSwgeSA9IH5sb2cocHJlY2lvUGVzb3MpKQ0KDQpmaWcgJT4lIGxheW91dCh0aXRsZSA9ICdTcXVhcmUgRmVldCB2cyBIb3VzZSBQcmljZScsDQogICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTG9nKEhvdXNlIFByaWNlKSIpLA0KICAgICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkxvZyhTcXVhcmUgRmVldCkiKSkgJT4lDQogIGFkZF9tYXJrZXJzKHNob3dsZWdlbmQgPSBGQUxTRSklPiUNCiAgYWRkX2xpbmVzKHkgPSB+Zml0dGVkKG0xKSxuYW1lID0iUG9seW5vbWlhbCIpDQoNCmBgYA0KDQoNCk90cmEgdmFyaWFibGUgaW1wb3J0YW50ZSBzb24gbG9zIG1ldHJvcyB0b3RhbGVzIGRlIGxhcyBjYXNhcywgKiptZXRyb3NUb3RhbGVzMyoqIGVuIGxhIGJhc2UuIExvcyBtZXRyb3MgdG90YWxlcyBlcyBsYSBzdW1hIGRlIGxvcyBtZXRyb3MgcXVlIGVzdMOhbiBkZW50cm8geSBmdWVyYSBkZSBsYSBjYXNhLiBFbiBlc3RlIGNhc28gcGFyZWNpZXJhIGhhYmVyIHVuYSBmdWVydGUgcmVsYWNpw7NuIGN1YWRyw6F0aWNhLiBMb3MgdmFsb3JlcyBzb24gbWFyZ2luYWxtZW50ZSBwb3NpdGl2b3MgaGFzdGEgY2llcnRvIHB1bnRvIGVuIGRvbmRlIHVuIG1ldHJvIGN1YWRyYWRvIG3DoXMgcGFzYSBhIHRlbmVyIHVuIGVmZWN0byBuZWdhdGl2byBzb2JyZSBlbCBwcmVjaW8gZGUgbGEgY2FzYS4gRXN0byBzZSBkZWJlIHBvc2libGVtZW50ZSBhIHF1ZSBsYXMgY2FzYXMgY29uIG11Y2hvcyBtZXRyb3MgdG90YWxlcyB0aWVuZGVuIGEgZXN0YXIgZW4gc2VjdG9yZXMgcnVyYWxlcywgZW4gZG9uZGUgZWwgcHJlY2lvIGRlIHN1ZWxvIGVzIG3DoXMgYmFqbyBlbiBjb21wYXJhY2nDs24gY29uIGxhcyB6b25hcyB1cmJhbmFzLg0KDQoNCmBgYHtyLGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxmaWcud2lkdGg9Ny41LCBmaWcuaGVpZ2h0PTQuMn0NCg0KbTE8LWxtKGxvZyhwcmVjaW9QZXNvcykgfiBwb2x5KGxvZyhtZXRyb3NUb3RhbGVzMyksMiksZGF0YT0gcG9ydGFsMykNCg0KDQpmaWcgPC1wbG90X2x5KGRhdGEgPSBwb3J0YWwzLCB4ID0gfmxvZyhtZXRyb3NUb3RhbGVzMyksIHkgPSB+bG9nKHByZWNpb1Blc29zKSkNCg0KZmlnICU+JSBsYXlvdXQodGl0bGUgPSAnVG90YWwgU3F1YXJlIEZlZXQgdnMgSG91c2UgUHJpY2UnLA0KICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkxvZyhIb3VzZSBQcmljZSkiKSwNCiAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICIgTG9nKFRvdGFsIFNxdWFyZSBGZWV0KSIpKSAlPiUNCiAgYWRkX21hcmtlcnMoc2hvd2xlZ2VuZCA9IEZBTFNFKSU+JQ0KICBhZGRfbGluZXMoeSA9IH5maXR0ZWQobTEpLG5hbWUgPSJQb2x5bm9taWFsIikNCmBgYCAgICAgICAgICAgDQoNClNpIG1pcmFtb3MgYWwgcmVzdG8gZGUgbGFzIHZhcmlhYmxlcyBlcyB0YW1iacOpbiBwb3NpYmxlIGVzdGFibGVjZXIgYWxnw7puIHRpcG8gZGUgcmVsYWNpw7NuLiBBIG1lZGlkYSBxdWUgYXVtZW50YSBlbCBuw7ptZXJvIGRlIGJhw7FvcyB0YW1iacOpbiBhdW1lbnRhIGVsIHByZWNpbyBkZSBsYXMgY2FzYXMsIGNvbW8gc2UgcHVlZGUgYXByZWNpYXIgZW4gZWwgZ3LDoWZpY28uDQoNCmBgYHtyLGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCg0KcG9ydGFsMyAlPiUgDQogIGdncGxvdChhZXMoeD0oZmN0X3JlbGV2ZWwoYXMuY2hhcmFjdGVyKGJhw7FvczIpLCIxMCIsIGFmdGVyID0gSW5mKSkseT1sb2cocHJlY2lvUGVzb3MpLCBmaWxsPWFzLmZhY3RvcihiYcOxb3MyKSkpK2dlb21fYm94cGxvdCgpKw0KICAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuNikgKw0KbGFicyh4PSJOdW1iZXIgb2YgQmF0aHJvb21zIiwgeT0iTG9nKEhvdXNlIFByaWNlKSIsDQogICAgIHRpdGxlPSJOdW1iZXIgb2YgQmF0aHJvb21zIFZzLiBIb3VzZSBQcmljZSIpKyANCiAgdGhlbWVfaXBzdW1fcmMoKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQoNCg0KYGBgDQoNCg0KRW4gZWwgY2FzbyBkZSBsb3MgZG9ybWl0b3Jpb3MgcGFyZWNpZXJhIHNlciBxdWUgbGFzIGNhc2FzIGNvbiAxIGRvcm1pdG9yaW8gc29uIG3DoXMgY2FyYXMgcXVlIGxhcyBxdWUgdGllbmVuIGRvcy4gUGVybyBsdWVnbyBlbCB2YWxvciBwYXJlY2llcmEgaXIgaW5jcmVtZW50YW5kbyBkZXNkZSBsYXMgMiBwaWV6YXMgaGFzdGEgZXN0YWJpbGl6YXJzZSBjZXJjYSBkZSBsYXMgNiBvIDcgaGFiaXRhY2lvbmVzLg0KDQpgYGB7cixlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCnBvcnRhbDMgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9KGZjdF9yZWxldmVsKGFzLmNoYXJhY3Rlcihkb3JtaXRvcmlvczIpLCIxMCIsIjExIiwiMTIiLGFmdGVyID0gSW5mKSkseT1sb2cocHJlY2lvUGVzb3MpLGZpbGw9YXMuZmFjdG9yKGRvcm1pdG9yaW9zMikpKStnZW9tX2JveHBsb3QoKSsNCiAgICAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUsIGFscGhhPTAuNikgKw0KbGFicyh4PSJOdW1iZXIgb2YgQmVkcm9vbXMiLCB5PSJMb2cgKEhvdXNlIFByaWNlKSIsDQogICAgIHRpdGxlPSJOdW1iZXIgb2YgQmVkcm9vbXMgVnMuIEhvdXNlIFByaWNlIikrIA0KICB0aGVtZV9pcHN1bV9yYygpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCg0KYGBgDQoNClNvYnJlIGVsIG7Dum1lcm8gZGUgZXN0YWNpb25hbWllbnRvIGVzIGNsYXJvIHF1ZSBsYXMgY2FzYXMgY29uIDEgc29sbyBlc3RhY2lvbmFtaWVudG8gdGllbmVuIHByZWNpb3MgbXVjaG8gbcOhcyBiYWpvcy4gTHVlZ28gZWwgcHJlY2lvIGFsIGlndWFsIHF1ZSBjb24gbGFzIG90cmFzIHZhcmlhYmxlcyBzZSBpbmNyZW1lbnRhIGhhc3RhIGVzdGFuY2Fyc2UgY2VyY2EgZGUgbG9zIDYgZXN0YWNpb25hbWllbnRvcy4NCg0KDQoNCmBgYHtyLGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KDQpwb3J0YWwzICU+JSANCiAgZ2dwbG90KGFlcyh4PShmY3RfcmVsZXZlbChhcy5jaGFyYWN0ZXIocGFya2luZzIwKSwiMTAiLCIxMSIsIjEyIiwiMTMiLCIxNCIsIjE1IiwiMTYiLCIxNyIsIjE4IiwiMTkiLCIyMCIsIjIyIiwiMjUiLA0KICAiMzAiLCIzOSIsYWZ0ZXIgPSBJbmYpKSx5PWxvZyhwcmVjaW9QZXNvcyksZmlsbD1hcy5mYWN0b3IocGFya2luZzIwKSkpK2dlb21fYm94cGxvdCgpKw0KICAgICAgICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYT0wLjYpICsNCmxhYnMoeD0iTnVtYmVyIG9mIFBhcmtpbmcgU3BvdHMiLCB5PSJMb2coSG91c2UgUHJpY2UpIiwNCiAgICAgdGl0bGU9Ik51bWJlciBvZiBQYXJraW5nIFNwb3RzIFZzLiBIb3VzZSBQcmljZSIpKyANCiAgdGhlbWVfaXBzdW1fcmMoKSsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpgYGANCg0KDQoNCk90cmEgdmFyaWFibGUgaW1wb3J0YW50ZSBlcyBsYSBjb211bmEuIEVuIGVsIGdyw6FmaWNvIHNlIHB1ZWRlIHZlciBsYXMgY2xhcmFzIGRpZmVyZW5jaWFzIHF1ZSBleGlzdGVuIGVudHJlIGxvcyBkaWZlcmVudGVzIGRpc3RyaXRvcy4gTGEgbMOtbmVhIHJvamEgcmVwcmVzZW50YSBsYSBtZWRpYW5hIGRlbCBwcmVjaW8gZW4gbnVlc3RyYSBtdWVzdHJhLiBMYSBtYXlvcsOtYSBkZSBsYXMgY2FzYXMgZW4gbnVlc3RyYSBtdWVzdHJhIHZpZW5lbiBkZSBsb3MgNCBkaXN0cml0b3MgbcOhcyBleGNsdXNpdm9zIGRlIFNhbnRpYWdvIChMbyBCYXJuZWNoZWEsIFZpdGFjdXJhLCBMYXMgQ29uZGVzLCBDaGljdXJlbykuIE1pcmFuZG8gZWwgZ3LDoWZpY28gZXMgY2xhcm8gcXVlIGV4aXN0ZW4gZGlmZXJlbmNpYXMgbXV5IGdyYW5kZXMgZW50cmUgbG9zIGRpc3RyaXRvcy4gTG9zIG9jaG9zIGRpc3RyaXRvcyBtw6FzIHBvYnJlcyB0aWVuZW4gdW5hIG1lZGlhbmEgZGUgcHJlY2lvcyBxdWUgbm8gZXMgbmkgbGEgb2N0YXZhIHBhcnRlIGRlIGxhIG1lZGlhbmEgZGVsIGRpc3RyaXRvIG3DoXMgcmljby4gDQoNCg0KDQpgYGB7cixlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1UUlVFfQ0KDQoNCnBvcnRhbDMlPiUgZ3JvdXBfYnkoY29tdW5hKSAlPiUgc3VtbWFyaXNlKHByZWNpb1Blc29zPW1lZGlhbihwcmVjaW9QZXNvcykpICU+JSANCiAgZ2dwbG90KGFlcyh4PWZjdF9yZW9yZGVyKGNvbXVuYSxwcmVjaW9QZXNvcyksIHk9cHJlY2lvUGVzb3MpKSArDQogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD0iI2Y2ODA2MCIsIGFscGhhPS42KSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPSBzZXEoMCw4MDAwMDAwMDAwICwgYnk9MTAwMDAwMDAwKSwgbGFiZWxzID0gY29tbWEpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PSA0ODQ3MDU4ODIsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSsNCmxhYnMoeD0iRGlzdHJpY3QiLCB5PSIgTWVkaWFuIEhvdXNlIFByaWNlIiwNCiAgICAgdGl0bGU9IkhvdXNlIFByaWNlIE1lZGlhbiBCeSBEaXN0cmljdCIpK3RoZW1lX2xpZ2h0KCkrDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCg0KYGBgDQoNCkVuIGVsIHNpZ3VpZW50ZSBtYXBhIDNEIHBvZGVtb3MgdmVyIGxhIG1lZGlhbmEgZGVsIHByZWNpbyAoRW4gbWlsbG9uZXMgZGUgcGVzb3MgY2hpbGVub3MpIGRlIGxhcyBjYXNhcyBwb3IgY29tdW5hLiBFbCBwcmVjaW8gZXN0w6EgcmVwcmVzZW50YWRvIHBvciBlbCBjb2xvciB5IGxhIGFsdHVyYSBxdWUgdGllbmUgY2FkYSBkaXN0cml0byBlbiBlbCBtYXBhLiBTZSBwdWVkZSB2ZXIgcXVlIGxhcyBjb211bmFzIHJpY2FzIGVzdMOhbiBoYWNpYSBlbCBub3Jlc3RlIGRlbCBtYXBhLiBNaWVudHJhcyBxdWUgbG9zIGRpc3RyaXRvcyBtw6FzIHBvYnJlcyBlc3TDoW4gYWwgc3VyIHkgYWwgZXN0ZSBkZWwgbWFwYS4gU29uIGVzdG9zIGxvcyBkaXN0cml0b3MgZW4gZG9uZGUsIHByZWZlcmVudGVtZW50ZSwgc2UgcmVsb2NhbGl6YSBhIHBlcnNvbmFzIHF1ZSB2aXbDrWFuIGVuIGFzZW50YW1pZW50b3MgaWxlZ2FsZXMgZW4gbG9zIGHDsW9zIDgwICdzLiBQb3Igw7psdGltbywgdGVuZW1vcyBhIENoaWN1cmVvIHkgQ29saW5hIGhhY2lhIGVsIG5vcnRlIHNlcGFyYWRvIGRlbCByZXN0byBkZSBsYSByZWdpw7NuIG1ldHJvcG9saXRhbmEuIEVsIGdyw6FmaWNvIGVzIGludGVyYWN0aXZvIHBvciBsbyBxdWUgc2UgcHVlZGUgcm90YXIgeSBoYWNlciB6b29tLg0KDQoNCg0KYGBge3IsZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9NC4yLHdhcm5pbmc9RkFMU0V9DQoNCnBsb3RfZ2coZ3JhZmljbyx6b29tID0gMC41LHdpZHRoPTcsaGVpZ2h0PTUpDQoNCnJnbDo6cmdsd2lkZ2V0KCkNCg0KYGBgDQoNCg0KDQoNCkV4aXN0ZSB0YW1iacOpbiB1bmEgcGVxdWXDsWEgZGVzY3JpcGNpw7NuIGxhIGN1YWwgKnRva2VuaXphbW9zKiBjb24gZWwgZmluIGRlIHZlciBsYXMgcGFsYWJyYXMgcXVlIHRpZW5lbiB1biBlZmVjdG8gbcOhcyBncmFuZGUgc29icmUgZWwgcHJlY2lvIGRlIGxhcyBjYXNhcy4gRW4gbG9zIDIgZ3LDoWZpY29zIHF1ZSB2aWVuZW4gYSBjb250aW51YWNpw7NuLCBzb2xvIHNlbGVjY2lvbmFtb3MgcGFsYWJyYXMgcXVlIGFwYXJlY2llcmFuIGNvbW8gbcOtbmltbyBlbiBsYSBkZXNjcmlwY2nDs24gZGUgMjAwIGNhc2FzLiBFbnRyZSBsYXMgcGFsYWJyYXMgY29uIHVuYSBtYXlvciBtZWRpYW5hIGVuIGVsIHByZWNpbyBoYXkgYWxndW5hcyBxdWUgcHJlc2VudGFuIGNhcmFjdGVyw61zdGljYXMgZGUgbGEgY2FzYSBjb21vOiBjYXZhLCBjaW5lLCBtw6FybW9sLCBzYXVuYSwgc3VidGVycsOhbmVvLiBPdHJhcyByZXByZXNlbnRhbiBiYXJyaW9zIChMYSBEZWhlc2EsIEVsIEdvbGYpIHkgb3RyYXMgYSBhZGpldGl2b3M6IGZpbmFzLCBlc3BlY3RhY3VsYXIsIG1hcmF2aWxsb3NvLCBwcmVjaW9zby4gVW5hIHBhbGFicmEgcXVlIGxsYW1hIGxhIGF0ZW5jacOzbiBlcyBhcnF1aXRlY3RvLiBFc3RhIHBhbGFicmEgdGllbmUgcHJvYmFibGVtZW50ZSB1biBlZmVjdG8gcG9zaXRpdm8sIGRlYmlkbyBxdWUgc29sbyBzZSBtZW5jaW9uYXJhIGFsIGFycXVpdGVjdG8sIHBvciBub21icmUgeSBhcGVsbGlkbywgY3VhbmRvIGVzIHVuIGFycXVpdGVjdG8gcmVjb25vY2lkby4gRXMgcG9zaWJsZSBwZW5zYXIgcXVlIGVzdGUgdGlwbyBkZSBhcnF1aXRlY3RvcyBjb25zdHJ1eWVuIGNhc2FzIG11eSBjYXJhcy4gTGEgcGFsYWJyYSBtZWRpdGVycsOhbmVhIHRhbWJpw6luIG5vcyBsbGFtYSBsYSBhdGVuY2nDs24sIMOpc3RhIHRpZW5lIHVuIGVmZWN0byBwb3NpdGl2byBwb3JxdWUgZXN0w6EgZGUgbW9kYSBlbiBsb3MgYmFycmlvcyBkZSBjbGFzZSBtZWRpYSBhbHRhIGNvbnN0cnVpciBjYXNhcyBjb24gZXN0ZSBlc3RpbG8uDQoNCg0KDQpgYGB7cixlY2hvPUZBTFNFfQ0KDQpwb3J0YWwzICU+JQ0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIGRhdG9zNCkgJT4lDQogIGdyb3VwX2J5KHdvcmQpICU+JQ0KICBzdW1tYXJpemUoYXZnX3ByaWNlPWxvZyhtZWRpYW4ocHJlY2lvUGVzb3MpKSxuPW4oKSkgJT4lIGZpbHRlcihuPjIwMCklPiUgYXJyYW5nZShkZXNjKGF2Z19wcmljZSkpICU+JSANCiAgaGVhZCgyNSkgJT4lDQogIG11dGF0ZSh3b3JkID0gZmN0X3Jlb3JkZXIod29yZCwgYXZnX3ByaWNlKSkgJT4lDQogIGdncGxvdChhZXMoYXZnX3ByaWNlLCB3b3JkLHNpemUgPSBuKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yPSJvcmFuZ2UiLGFscGhhPTAuNykrDQogIHRoZW1lX2J3KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikrZ2d0aXRsZSgiV29yZHMgQXNzb2NpYXRlZCB3aXRoIHRoZSBIaWdoZXN0IE1lYW4gUHJpY2VzIikNCiAgDQpgYGANCg0KUG9yIG90cm8gbGFkbywgZXhpc3RlbiB0YW1iacOpbiBwYWxhYnJhcyBxdWUgZXN0w6FuIGFzb2NpYWRhcyBhIHByZWNpb3MgYmFqb3MuIEFsZ3VuYXMgdGllbmVuIHJlbGFjacOzbiBjb24gbHVnYXJlcywgZW4gZXNwZWPDrWZpY28gZGlzdHJpdG9zIHkgY2FsbGVzOiBWZXNwdWNpbywgVG9iYWxhYmEsIE1haXDDuiwgUHVlbnRlLiBIYXkgb3RyYXMgNSBwYWxhYnJhcyBxdWUgbWUgbGxhbWFuIGxhIGF0ZW5jacOzbi4gTGEgcHJpbWVyYSBlcyB2aWxsYSwgcXVlIGVzIGxhIG1hbmVyYSBkZSByZWZlcmlyc2UgYSB1biBiYXJyaW8gZGUgY2xhc2UgbWVkaWEgZW4gQ2hpbGUuIExhIHNlZ3VuZGEgc29uIGxhcyBwYWxhYnJhcyBhc29jaWFkYXMgYSBsb3MgYmllbmVzIHJhw61jZXMgY29tbyBjb3JyZXRhamUsIGNvcnJlZG9yYS4gTGEgdGVyY2VyYSBlcyBwYXJlYWRhLCBlc3RvIHNlIGRlYmUgYSBxdWUgZW4gQ2hpbGUgZXMgbXV5IGNvbcO6biBjb25zdHJ1aXIgY2FzYXMgcGFyZWFkYXMgZW4gYmFycmlvcyBkZSBjbGFzZSBtZWRpYS4gTGEgY3VhcnRhIGVzIHBhc2FqZSwgcXVlIHByb2JhYmxlbWVudGUgZXN0w6EgYXNvY2lhZGEgY29uIGxhIGZvcm1hIGVuIGxhIHF1ZSBjb25zdHJ1eWVuIGxvcyBiYXJyaW9zIGRlIGNsYXNlIG1lZGlhLiBRdWludG8sIGxvY29tb2Npw7NuLCBlcyBvYnZpbyBxdWUgZXN0YSBwYWxhYnJhIHZhIGEgZXN0YXIgbGlnYWRhIGEgY2FzYXMgZW4gYmFycmlvcyBlbiBxdWUgbGFzIHBlcnNvbmFzIG5vIHB1ZWRlbiBjb21wcmFyIHVuIGF1dG8uDQoNCg0KYGBge3IsZWNobz1GQUxTRX0NCg0KcG9ydGFsMyAlPiUNCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBkYXRvczQpICU+JQ0KICBncm91cF9ieSh3b3JkKSAlPiUNCiAgc3VtbWFyaXplKGF2Z19wcmljZT1sb2cobWVkaWFuKHByZWNpb1Blc29zKSksbj1uKCkpICU+JSBmaWx0ZXIobj4yMDApJT4lIGFycmFuZ2UoZGVzYyhhdmdfcHJpY2UpKSAlPiUgDQogIHRhaWwoMjUpICU+JQ0KICBtdXRhdGUod29yZCA9IGZjdF9yZW9yZGVyKHdvcmQsIGF2Z19wcmljZSkpICU+JQ0KICBnZ3Bsb3QoYWVzKGF2Z19wcmljZSwgd29yZCxzaXplID0gbikpICsNCiAgZ2VvbV9wb2ludChjb2xvcj0ib3JhbmdlIixhbHBoYT0wLjcpKw0KICB0aGVtZV9idygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpK2dndGl0bGUoIldvcmRzIEFzc29jaWF0ZWQgd2l0aCB0aGUgTG93ZXN0IE1lYW4gUHJpY2VzIikNCiAgDQpgYGANCg0KVGVuZW1vcyB1biBncmFuIGdydXBvIGRlIHZhcmlhYmxlcyBkdW1teS4gVW5hIHF1ZSBtZSBwYXJlY2nDsyBpbnRlcmVzYW50ZSBlcyBsYSB2YXJpYWJsZSBwaXNjaW5hLCBlc3TDoSB2YXJpYWJsZSB0aWVuZSB1biBlZmVjdG8gdGFtYmnDqW4gc29icmUgZWwgcHJlY2lvIGRlIGxhcyBjYXNhcy4gRWwgZ3LDoWZpY28gdGllbmUgZW4gdW4gZWplIGVsIHByZWNpbyBkZSBsYSBjYXNhIHkgZW4gb3RybyBsb3MgbWV0cm9zIMO6dGlsZXMuIEVsIGNvbG9yIGRlIGxvcyBoZXjDoWdvbm9zIHJlcHJlc2VudGEgZWwgcG9yY2VudGFqZSBkZSBjYXNhcyBjb24gcGlzY2luYSBlbiBlc2Egw6FyZWEgRXMgcG9zaWJsZSBjb25zdGF0YXIgcXVlIGxhIHByb3BvcmNpw7NuIGRlIGNhc2FzIGNvbiBwaXNjaW5hIHRpZW5kZSBhIGF1bWVudGFyIGEgbWVkaWRhIHF1ZSBlbCBwcmVjaW8gZGUgbGFzIGNhc2FzIGF1bWVudGEuIEFob3JhIGJpZW4sIGVzIGltcG9ydGFudGUgbm90YXIgcXVlIGVzdGEgdmFyaWFibGUgcGFyZWNpZXJhIHRhbWJpw6luIHRlbmVyIHVuYSByZWxhY2nDs24gY29uIGxvcyBtZXRyb3MgY3VhZHJhZG9zIGRlIGxhIGNhc2EuDQoNCmBgYHtyLGVjaG89RkFMU0Usd2FybmluZz1GQUxTRX0NCnBvcnRhbDMgJT4lDQogIGdncGxvdChhZXMobG9nKG1ldHJvc1V0aWxlcyksIGxvZyhwcmVjaW9QZXNvcyksIHogPSBwaXNjaW5hKSkgKw0KICBzdGF0X3N1bW1hcnlfaGV4KGFscGhhID0gMC44LCBiaW5zID0gMjApICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGFiZWxzID0gcGVyY2VudCkgKw0KbGFicyh4PSJMb2coU3F1YXJlIEZlZXRzKSIsIHk9IkxvZyhIb3VzZSBQcmljZSkiLA0KICAgICB0aXRsZT0iJSBPZiBIb3VzZXMgd2l0aCBQb29sIGJ5IFNxdWFyZSBGZWV0IGFuZCBQcmljZSIpKw0KICBsYWJzKGZpbGwgPSAiJSBwb29sIikrDQogIHRoZW1lX2J3KCkNCmBgYA0KDQoNCiMjIFRyYXRhbWllbnRvIEEgTGFzIFZhcmlhYmxlcw0KICAgICAgICAgICANCkFsZ3Vub3Mgb3V0bGllcnMgZnVlcm9uIHJlbW92aWRvcywgcHJpbmNpcGFsbWVudGUgYWxndW5hcyBjYXNhcyBxdWUgcGVydGVuZWPDrWFuIGEgc2VjdG9yZXMgcnVyYWxlcyAocXVlIG5vIGVyYW4gZGUgbnVlc3RybyBpbnRlcsOpcyksIGFsZ3Vub3MgZXJyb3JlcyBkZSB0aXBlbyB5IG9ic2VydmFjaW9uZXMgZHVwbGljYWRhcy4gTGFzIG9ic2VydmFjaW9uZXMgbnVtw6lyaWNhcyBmdWVyb24gdHJhbnNmb3JtYWRhcyBhIGxvZ2FyaXRtb3MgeSBub3JtYWxpemFkYXMuIEFkZW3DoXMsIGxhIHZhcmlhYmxlIGNvbXVuYSBmdWUgdHJhbnNmb3JtYWRhIGEgdW5hIHZhcmlhYmxlIG51bcOpcmljYSB0b21hbmRvIGNvbW8gcmVmZXJlbmNpYSBsYSBtZWRpYW5hIGRlbCBwcmVjaW8gZGUgbGFzIGNhc2FzIHBvciBkaXN0cml0by4NCg0KIyMgUmVzdWx0YWRvcw0KDQpDb3JyaW1vcyAzIG1vZGVsb3MsIHVubyBvY3VwYW5kbyB4Z2Jvb3N0LCBlbCBzZWd1bmRvIHVuYSByZWdyZXNpw7NuIGxhc3NvIHkgZWwgw7psdGltbyBlbiBlbCBjdWFsIGVuc2FtYmxhbW9zIGFtYm9zIG1vZGVsb3MuIEVsIG1lam9yIG1vZGVsbyBmdWUgZW4geGdib29zdC4gRXN0b3MgZnVlcm9uIGxvcyByZXN1bHRhZG9zOg0KDQpgYGB7cixlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpmaW5hbF9yZXMgPC0gbGFzdF9maXQoZmluYWxfeGdiLCBzcGwpDQoNCmNvbGxlY3RfbWV0cmljcyhmaW5hbF9yZXMpDQpgYGANCg0KU2kgbWlyYW1vcyBsYXMgdmFyaWFibGVzIG3DoXMgaW1wb3J0YW50ZXMgdGVuZW1vcyBlbCBkaXN0cml0byAoKipjb211bmEyKiopLCBlc3RvIHF1aXrDoXMgc2UgZXhwbGljYSBwb3JxdWUgZXN0YSB2YXJpYWJsZSBjb250aWVuZSBtdWNob3MgY29tcG9uZW50ZXMgZGVudHJvIGRlIMOpc3RhLCBwcmluY2lwYWxtZW50ZSBhY2Nlc28gYSBzZXJ2aWNpb3MgeSBiaWVuZXMgcMO6YmxpY29zIGNvbW86IGhvc3BpdGFsZXMsIHBhcnF1ZXMsIGVzY3VlbGFzOyB5IG90cm9zIGVsZW1lbnRvcyBtdXkgaW1wb3J0YW50ZXMgY29tbyBwdWVkZSBzZXIgbGEgc2VndXJpZGFkLg0KDQpMYSBzZWd1bmRhIHZhcmlhYmxlIG3DoXMgaW1wb3J0YW50ZSBzb24gbG9zIG1ldHJvcyB0b3RhbGVzICgqKm1ldHJvc1RvdGFsZXMzX3BvbHlfMSoqIHkgKiptZXRyb3NUb3RhbGVzM19wb2x5XzIqKikgeSBtZXRyb3Mgw7p0aWxlcyAqKm1ldHJvc1V0aWxlcyoqLiBMbyBjdWFsIHRpZW5lIHNlbnRpZG8gcG9ycXVlIHVubyBlc3BlcmFyw61hIHF1ZSBtaWVudHJhcyBtw6FzIGdyYW5kZSBmdWVyYSBsYSBjYXNhIG1heW9yIHNlcsOtYSBlbCBwcmVjaW8uIExvIGludGVyZXNhbnRlIGVzIHF1ZSBsb3MgbWV0cm9zIHRvdGFsZXMgdGllbmVuIHVuYSByZWxhY2nDs24gY3VhZHLDoXRpY2EgY8OzbmNhdmEsIGxvIGN1YWwgcHVlZGUgc2VyIGRlYmlkbyBhIHF1ZSBsYXMgY2FzYXMgY29uIHVuYSBleHRlbnNpw7NuIG11eSBncmFuZGUgZGUgdGVycmVubyBlc3TDoW4gbG9jYWxpemFkYXMgZW4gc2VjdG9yZXMgbcOhcyBydXJhbGVzIGVuIGRvbmRlIGVsIHByZWNpbyBkZWwgc3VlbG8gZXMgbcOhcyBiYWpvIGxvIGN1YWwgcHJvZHVjZSBlc3RhIHJlbGFjacOzbi4gDQoNCkx1ZWdvIGRlIGVzdGFzIHZhcmlhYmxlcyBsYXMgbcOhcyBpbXBvcnRhbnRlcyBzb24gZWwgbsO6bWVybyBkZSBiYcOxb3MgKipiYcOxb3MyKiosIGxhIGV4aXN0ZW5jaWEgZGUgdW5hIHBpc2NpbmEgKipwaXNjaW5hKiosIGVsIG7Dum1lcm8gZGUgZG9ybWl0b3Jpb3MgKipkb3JtaXRvcmlvczIqKiB5IGVsIG7Dum1lcm8gZGUgZXN0YWNpb25hbWllbnRvcyAqKnBhcmtpbmcyMCoqDQoNCg0KYGBge3IsZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCg0KZmluYWxfeGdiICU+JQ0KICBmaXQoZGF0YSA9IHRyYWluKSAlPiUNCiAgcHVsbF93b3JrZmxvd19maXQoKSAlPiUNCiAgdmlwKGdlb20gPSAicG9pbnQiLCBudW1fZmVhdHVyZXMgPSA4KQ0KYGBgDQoNCg0KQXVucXVlIGVsIHRleHRvIG5vIGVyYSB1bmEgdmFyaWFibGUgaW1wb3J0YW50ZSBlbiBlbCBtb2RlbG8geGdib29zdCBzaSBsbyBlcmEgZW4gZWwgbW9kZWxvIGxhc3NvLiBBcXXDrSBsb3MgcmVzdWx0YWRvcyBkZSBsYXMgcGFsYWJyYXMgcXVlIHRlbsOtYW4gbWF5b3IgaW1wb3J0YW5jaWE6DQoNCg0KYGBge3IsZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmdyYXBoPC1maW5hbF9sYXNzbyAlPiUNCiAgZml0KHRyYWluKSAlPiUNCiAgcHVsbF93b3JrZmxvd19maXQoKSAlPiUNCiAgdmkobGFtYmRhID0gbG93ZXN0X3Jtc2UkcGVuYWx0eSkgJT4lDQogIG11dGF0ZSgNCiAgICBJbXBvcnRhbmNlID0gYWJzKEltcG9ydGFuY2UpLA0KICAgIFZhcmlhYmxlID0gZmN0X3Jlb3JkZXIoVmFyaWFibGUsIEltcG9ydGFuY2UpKSU+JWZpbHRlcihzdHJfZGV0ZWN0KFZhcmlhYmxlLCJ0Zl9kYXRvczQiKSkNCg0KZ3JhcGglPiVtdXRhdGUoVmFyaWFibGUyPXN0cl9yZXBsYWNlKGdyYXBoJFZhcmlhYmxlLCJ0Zl9kYXRvczRfIiwiIiksDQogICAgICAgICAgICAgICBWYXJpYWJsZSA9IGZjdF9yZW9yZGVyKFZhcmlhYmxlMiwgSW1wb3J0YW5jZSkpICU+JSANCiAgICAgICAgIGhlYWQoMjApICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gSW1wb3J0YW5jZSwgeSA9IFZhcmlhYmxlLCBmaWxsID0gU2lnbikpICsNCiAgZ2VvbV9jb2woKSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogIGxhYnMoeSA9IE5VTEwpK3RoZW1lX2xpZ2h0KCkNCmBgYA0KDQpFbnRyZSBsYXMgcGFsYWJyYXMgY29uIHVuIGVmZWN0byBwb3NpdGl2byB0ZW5lbW9zIGx1Z2FyZXMgdGFsZXM6IGxvcyBkaXN0cml0b3MgZGUgUXVpbGljdXJhLCBQcm92aWRlbmNpYSwgY29uZGVzIChMYXMgQ29uZGVzKSB5IGJhcnJpb3MgdGFsZXMgY29tbyBkYW1pw6FuIChTYW4gRGFtacOhbikgeSBnb2xmIChFbCBHb2xmKS4gRWwgaGVjaG8gZGUgcXVlIFF1aWxpY3VyYSB0ZW5nYSB1biBlZmVjdG8gcG9zaXRpdm8gbm9zIHRvbWEgcG9yIHNvcnByZXNhIHlhIHF1ZSBubyBlcyB1biBkaXN0cml0byByaWNvIGRlIFNhbnRpYWdvLiBWZXJibyBlc3TDoSBhaMOtIHBvciBlbCBjb2xlZ2lvIFZlcmJvIERpdmlubywgcXVlIGVzIHVubyBkZSBsb3MgZXN0YWJsZWNpbWllbnRvcyBlZHVjYWNpb25hbGVzIG3DoXMgZXhjbHVzaXZvcyBkZSBTYW50aWFnby4gT3RyYXMgcGFsYWJyYXMgY29uIHVuIGVmZWN0byBwb3NpdGl2byBzb246IGxvcyBhZGpldGl2b3MgZXNwZWN0YWN1bGFyIHkgZmluYXMsIGxhIHByZXNlbmNpYSBkZSAqKnBhcnF1ZXQqKiBlbiBsYSBjYXNhcywgY3VhbmRvIGxhcyBjYXNhcyBzb24gY29uc3RydWlkYXMgY29uIGVzdGlsbyAqKm1lZGl0ZXJyYW5lbyoqIHkscG9yIMO6bHRpbW8sIGxhIHBhbGFicmEgZWFzeWJyb2tlciBxdWUgZXMgKnByb2JhYmxlbWVudGUqIHVuYSBjb21wYcOxw61hIGRlIGNvcnJldGFqZS4NCg0KRW50cmUgbGFzIHBhbGFicmFzIGNvbiBlZmVjdG8gbmVnYXRpdm8gdGVuZW1vcyBDaGljdXJlbywgbG8gY3VhbCBlcyBjdXJpb3NvIGRlYmlkbyBhIHF1ZSBlcyB1bm8gZGUgbG9zIGRpc3RyaXRvcyBtw6FzIHJpY29zIGRlIFNhbnRpYWdvLiBMYSBleHBsaWNhY2nDs24gZXMgcXVlIHlhIHF1ZSBsYSBtYXlvcsOtYSBkZSBsYSBtdWVzdHJhIHByb3ZpZW5lIGRlIGxvcyA0IGN1YXRyb3MgZGlzdHJpdG9zIG3DoXMgcmljb3MgKExvIEJhcm5lY2hlYSwgVml0YWN1cmEsIExhcyBDb25kZXMgeSBDaGljdXJlbyksIENoaWN1cmVvIGFsIHRlbmVyIGxhIG1lZGlhbmEgZGUgcHJlY2lvcyBtw6FzIGJhamEgZGUgZXN0ZSBncnVwbyBwYXNhIGEgdGVuZXIgdW4gZWZlY3RvIG5lZ2F0aXZvIGVuIGVsIHRvdGFsIGRlIGxhIG11ZXN0cmEuIENoYW1pc2VybyBlcyB1bmEgY2FsbGUgZW4gQ2hpY3VyZW8gcG9yIGxvIHRhbnRvIGVzYSBlcyBsYSByYXrDs24gcG9yIGxhIHF1ZSBwb3IgbGEgcXVlIGVzdGEgcGFsYWJyYSB0YW1iacOpbiB0ZW5kcsOtYSB1biBlZmVjdG8gbmVnYXRpdm8uIA0KDQpPdHJhcyBwYWxhYnJhcyBjb21vIHJpZWdvLCBwb3pvIHkgYm9zY2Egc29uIHNlw7FhbGVzIGRlIHJ1cmFsaWRhZCBwb3JxdWUgY3JlbyBxdWUgZXMgZXNhIGxhIHJhesOzbiBkZWwgZWZlY3RvIHF1ZSB0aWVuZW4uIExhcyDDumx0aW1hcyBwYWxhYnJhcyBzb24gY29sZWdpbyB5IGNvbnRhbmRvLiBTb2JyZSDDqXN0YXMgZXMgdW4gcG9jbyBkaWbDrWNpbCB0ZW5lciB1bmEgcmF6w7NuIGNsYXJhIGRlIGxhIHJhesOzbiBkZWwgZWZlY3RvIG5lZ2F0aXZvLiBQdWVkZSBzZXIgcXVlIGN1YW5kbyBsb3MgcHJlY2lvcyBubyBzb24gY2Fyb3MgbG9zIHZlbmRlZG9yZXMgcGlkZW4gZWwgcGFnbyBhbCBjb250YWRvLiAqQ29sZWdpb3MqLCBwdWVkZSB0ZW5lciB1biBlZmVjdG8gbmVnYXRpdm8gZGViaWRvIGEgcXVlIGN1YW5kbyBsb3MgY29sZWdpb3MgYWxyZWRlZG9yIGRlIHVuYSBwcm9waWVkYWQgbm8gc29uIG11eSBjb25vY2lkb3MsIGxhcyBwZXJzb25hcyBzb2xvIG1lbmNpb25hbiBsYSBwYWxhYnJhICJjb2xlZ2lvIiBlbiB2ZXogZGVsIG5vbWJyZSBkZWwgY29sZWdpbywgY29tbyBwYXNhIGNvbiBlbCBWZXJibyBEaXZpbm8uDQoNCg0KDQpBcXXDrSBlc3TDoW4gbG9zIHJlc3VsdGFkb3MgcGFyYSB0b2RvcyBsb3MgbW9kZWxvczoNCmBgYHtyLGVjaG89RkFMU0V9DQpwcmVkaWN0KHN0YWNrX21vZGVsLCBzdGFja19maW5hbF9kZikgJT4lIA0KICBiaW5kX2NvbHMoc3RhY2tfZmluYWxfZGYpICU+JSANCiAgcmVuYW1lKCJzdGFjayIgPSAucHJlZCkgJT4lIA0KICBwaXZvdF9sb25nZXIoLXByZWNpb1Blc29zKSAlPiUgDQogIGdyb3VwX2J5KG5hbWUpICU+JSANCiAgbXNldCh0cnV0aCA9IHByZWNpb1Blc29zLCBlc3RpbWF0ZSA9IHZhbHVlKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAubWV0cmljLCB2YWx1ZXNfZnJvbSA9IC5lc3RpbWF0ZSkgJT4lIA0KICBhcnJhbmdlKHJtc2UpDQpgYGANCg0KIyMgQ29uY2x1c2lvbmVzDQoNClByaW1lcm8gcXVlIHRvZG8sIGNyZW8gcXVlIGVzIGltcG9ydGFudGUgcHJlY2lzYXIgcXVlIGhheSBxdWUgdGVuZXIgY29uc2lkZXJhY2lvbmVzIGltcG9ydGFudGVzIGN1YW5kbyBzZSBhbmFsaXphbiBlc3RvcyByZXN1bHRhZG9zLCB5YSBxdWUgZWwgZ3J1ZXNvIGRlIGxhcyBjYXNhcyBlbiBudWVzdHJhIG11ZXN0cmEgdmllbmUgZGUgYmFycmlvcyBhY29tb2RhZG9zLiBTaSB0dXZpw6lyYW1vcyB1bmEgbXVlc3RyYSBtw6FzIGVxdWlsaWJyYWRhIHF1aXrDoXMgbG9zIHJlc3VsdGFkb3Mgc2Vyw61hbiBvdHJvcy4gQXF1w60gdW4gZ3LDoWZpY28gY29uIGxhcyBjYXNhcyBwb3IgY29tdW5hLg0KDQoNCmBgYHtyLGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KDQpwb3J0YWwzICU+JSBncm91cF9ieShjb211bmEpICU+JSBzdW1tYXJpc2Uobj1uKCkpJT4lIA0KICBnZ3Bsb3QoYWVzKHg9ZmN0X3Jlb3JkZXIoY29tdW5hLG4pLG4pKSArDQogIGdlb21faGlzdG9ncmFtKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD0iI2Y2ODA2MCIsIGFscGhhPS42KSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkrDQogIGxhYnMoeD0iRGlzdHJpY3QiLCB5PSJOIiwNCiAgICAgICB0aXRsZT0iTnVtYmVyIG9mIEhvdXNlcyBCeSBEaXN0cmljdCIpK3RoZW1lX2xpZ2h0KCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KDQpEZWphbmRvIGxvIGFudGVyaW9yIGNsYXJvIGFxdcOtLCBsYSBjb211bmEgZXMgbGEgdmFyaWFibGUgcXVlIGF5dWRhIGEgcHJlZGVjaXIgZGUgbWVqb3IgbWFuZXJhIGVsIHByZWNpbyBkZSBsYSB2aXZpZW5kYS4gRXMgaW50ZXJlc2FudGUgbm90YXIgY29tbyBhcXVlbGxhcyBjb211bmFzIHF1ZSByZWNpYmllcm9uIG3DoXMgZmFtaWxpYXMgcmVsb2NhbGl6YWRhcyBlbiBsb3MgODAgJ3Mgc29uIGFxdWVsbGFzIHF1ZSB0aWVuZW4gcHJlY2lvcyBtw6FzIGJham9zLiBMYSBpbXBvcnRhbmNpYSBkZSBsb3MgbWV0cm9zIMO6dGlsZXMgeSB0b3RhbGVzIG5vIG5vcyBzb3JwcmVuZGUsIGxvIHF1ZSBzw60gY29uc2lkZXJhbW9zIHNvcnByZW5kZW50ZSBlcyBsYSByZWxhY2nDs24gY3VhZHLDoXRpY2EgZW50cmUgZWwgcHJlY2lvIGRlIGxhIHZpdmllbmRhIHkgbG9zIG1ldHJvcyB0b3RhbGVzIGRlbCBob2dhci4NCg0KQSBwZXNhciBkZSBxdWUgaW50ZW50YW1vcyBubyBjb25zaWRlcmFyIHNlY3RvcmVzIHJ1cmFsZXMgZW4gbnVlc3RyYSBtdWVzdHJhIHBhcmVjaWVyYSBxdWUgbm8gZnVpbW9zIGRlbCB0b2RvIGV4aXRvc29zIGNvbW8gaW5kaWNhcsOtYW4gbGFzIHBhbGFicmFzOiByaWVnbywgcG96byB5IGJvc2NhLiBDcmVvLCBhZGVtw6FzLCBxdWUgcXVlZGEgcGVuZGllbnRlIGhhY2VyIHVuIG1vZGVsbyBjb24gcGFyZXMgZGUgcGFsYWJyYXMsIGJpbm9taW9zLCBlbiB2ZXogZGUgc29sbyBvY3VwYXIgcGFsYWJyYXMgc3VlbHRhcy4gQ3JlbyBxdWUgYSBwZXNhciBkZSBsb3MgYnVlbm9zIHJlc3VsdGFkb3MgZGVsIG1vZGVsbyBxdWVkYSBlc3BhY2lvIHBhcmEgbWVqb3JhciBsYSBwZXJmb3JtYW5jZSwgc2VyaWEgZGVsIGdyYW4gYXl1ZGEgcG9kZXIgY29udGFyIGNvbiBzZXJ2aWRvcmVzIHBhcmEgZW50cmVuYXIgZGUgbWVqb3IgbWFuZXJhIG51ZXN0cm9zIGRhdG9zLg0KDQoNCg0KDQoNCg0KDQo=