1. Contexto
En este documento se realizaran 3 métodos de cómo se pueden manejar
los datos no estructurados. Entre los cuales se abordaran temas como un
sistema de recomendación, un chat bot y un análisis de audio.
3. Tarea 1. Sistema de recomendación

3.1 Descripción
Se utilizo las calificación de peliculas de 3 compañeros
comparandolos con algunas de mis calificaciones, dejando NA’s con la
finalidad de poder predecir si me recomendaba o no dichas peliculas.
3.2 Crear la matriz
movie_ratings_tarea <- data.frame(
KP1 = c(5, 4, 5, 4),
ENREDADOS = c(4, 5, 4, NA),
UP = c(5, 4, 5, 2),
CARS1 = c(4, 5, 3, NA),
TS3 = c(3, 5, 3, 2),
SHREK2 = c(3, 5, 4, 3),
MONJA = c(3, NA, 3, NA)
)
rownames(movie_ratings_tarea) <- c('Diego','Lalo', 'Ale', 'You' )
movie_ratings_tarea
## KP1 ENREDADOS UP CARS1 TS3 SHREK2 MONJA
## Diego 5 4 5 4 3 3 3
## Lalo 4 5 4 5 5 5 NA
## Ale 5 4 5 3 3 4 3
## You 4 NA 2 NA 2 3 NA
3.3 Proceso de matrices:
cosine_similarity <- function(vec_1, vec_2) {
vec_len <- length(vec_1)
# NA values are replaced with 0
vec_1[is.na(vec_1)] <- 0
vec_2[is.na(vec_2)] <- 0
# Computing the denominator
vec_1_denom <- sqrt(sum(vec_1^2))
vec_2_denom <- sqrt(sum(vec_2^2))
denominator <- vec_1_denom * vec_2_denom
# Computing the numerator
tib = tibble(vec_1 = vec_1, vec_2 = vec_2)
tib <- tib %>% mutate(products = vec_1 * vec_2)
numerator <- sum(tib$products)
# Return the cosine similarity
return (numerator / denominator)
}
3.4 Vectorizamos las puntuaciones:
# Obtenemos los vectores de cada persona
You <- as.numeric(as.vector(movie_ratings_tarea['You',]))
Diego <- as.numeric(as.vector(movie_ratings_tarea['Diego',]))
Lalo <- as.numeric(as.vector(movie_ratings_tarea['Lalo',]))
Ale <- as.numeric(as.vector(movie_ratings_tarea['Ale',]))
# Obtenemos "distancia" usando similitud por conseno
similarities_tarea <- data.frame(
cosine_similarity = c(cosine_similarity(You, Diego), cosine_similarity(You, Lalo), cosine_similarity(You, Ale))
)
rownames(similarities_tarea) <- c('Diego', 'Lalo', 'Ale')
similarities_tarea
## cosine_similarity
## Diego 0.7503127
## Lalo 0.7424242
## Ale 0.8003335
3.5 Promedio ponderado:
Una vez obtenidas las similaridades, realizamos un promedio ponderado
para poder recomendar “La monja”
# Creamos una función para obtener un promedio ponderado en base a los amigos
movie_rating_weighted_average <- function(movie, friends) {
denominator <- 0
numerator <- 0
for (friend in friends) {
friend_similarity <- similarities_tarea[friend,][1]
friend_rating <- movie_ratings_tarea[friend, movie][1]
# Tomaremos el promedio ponderado en cuenta solo para películas con calificación
if (is.na(friend_rating)) next
denominator <- denominator + friend_similarity
numerator <- numerator + (friend_similarity * friend_rating)
}
return (numerator / denominator)
}
3.6 Predicción
Usamos la función creada con anterioridad para predecir “La
monja”
friend_names <- c('Diego', 'Lalo', 'Ale')
new_movies <- c('ENREDADOS', 'CARS1', 'MONJA')
new_movie_predicted_ratings <- tibble()
for (n in new_movies) {
predicted_rating <- movie_rating_weighted_average(n, friend_names)
prediction_tibble <- tibble(movie = n, predicted_rating = predicted_rating)
new_movie_predicted_ratings <- bind_rows(new_movie_predicted_ratings, prediction_tibble)
}
new_movie_predicted_ratings
## # A tibble: 3 × 2
## movie predicted_rating
## <chr> <dbl>
## 1 ENREDADOS 4.32
## 2 CARS1 3.97
## 3 MONJA 3
Como podemos ver, la película con mayor rating predicho es ENREDADOS
por lo que será la película recomendada en primer lugar
4. Tarea 2. Chatbot

4.1 Descripción
El chatbot realizado es con la finalidad de mostrar los temas vistos
dentro del modulo 4 de la consentración de Inteligencia Artificial. Al
ingresar solicita al usuario que se identifique; después se mostraran
los dos temas principales: Datos Estructurados y Datos No
Estructurados. Al dar click en alguno de ellos se mostraran los
temas vistos así como un rpub del tema.
4.2 Creación del CHATBOT
Se creó un CHATBOT por medio de la aplicación
Telegram. Con la ayuda del @BotFather Donde se configuraron los
siguientes puntos de visualización.

Una vez creado el bot, así como su configuración se utilizo la
herramienta SENDPULSE, en la cual se creo una cuenta
con la finalidad de configurar el funcionamiento del chat.
Visita
SENDPULSE
Dentro de esta plataforma se vinculo el chatbot por medio del
token proporcionado en telegram. Además de un mensaje de
bienvenida al iniciar el chat.

De igual manera se estructuraron los mensajes para la interacción con
el usuario.
En este proceso se solicita el Nombre y Correo
electronico, cuyos se guardaan en variables para ser mostrados en
el siguiente mensaje.
4.4 Interacción con el Chatbot


LS0tDQp0aXRsZTogIlRhcmVhIDIsIDMgeSA0Ig0KYXV0aG9yOiAiRGllZ28gQWxlamFuZHJvIFDDqXJleiBDaXNuZXJvcyAtIEEwMTI3NTU2MSINCmRhdGU6ICIyMDI0LTA0LTIxIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IHNpbXBsZXggDQotLS0NCiANCiAhW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcZGF0b3MtZXN0cnVjdHVyYWRvcy0wMC5qcGcpDQogDQogDQojIDEuIENvbnRleHRvDQpFbiBlc3RlIGRvY3VtZW50byBzZSByZWFsaXphcmFuIDMgbcOpdG9kb3MgZGUgY8OzbW8gc2UgcHVlZGVuIG1hbmVqYXIgbG9zIGRhdG9zIG5vIGVzdHJ1Y3R1cmFkb3MuIEVudHJlIGxvcyBjdWFsZXMgc2UgYWJvcmRhcmFuIHRlbWFzIGNvbW8gdW4gc2lzdGVtYSBkZSByZWNvbWVuZGFjacOzbiwgdW4gY2hhdCBib3QgeSB1biBhbsOhbGlzaXMgZGUgYXVkaW8uDQoNCiMgMi4gSW5zdGFsYWNpw7NuIGRlIGxpYnJlcsOtYXMuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpICAgDQpsaWJyYXJ5KHJlY29tbWVuZGVybGFiKQ0KI2luc3RhbGwucGFja2FnZXMoInNpZ25hbCIpDQpsaWJyYXJ5KHNpZ25hbCkNCiNpbnN0YWxsLnBhY2thZ2VzKCJhdWRpbyIpDQpsaWJyYXJ5KGF1ZGlvKQ0KI2luc3RhbGwucGFja2FnZXMoInR1bmVSIikNCmxpYnJhcnkodHVuZVIpDQpgYGANCg0KDQojIDMuIFRhcmVhIDEuIFNpc3RlbWEgZGUgcmVjb21lbmRhY2nDs24NCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDExLjAxLjIyIEFNLmpwZWcpDQoNCiMjIDMuMSBEZXNjcmlwY2nDs24NClNlIHV0aWxpem8gbGFzIGNhbGlmaWNhY2nDs24gZGUgcGVsaWN1bGFzIGRlIDMgY29tcGHDsWVyb3MgY29tcGFyYW5kb2xvcyBjb24gYWxndW5hcyBkZSBtaXMgY2FsaWZpY2FjaW9uZXMsIGRlamFuZG8gTkEncyBjb24gbGEgZmluYWxpZGFkIGRlIHBvZGVyIHByZWRlY2lyIHNpIG1lIHJlY29tZW5kYWJhIG8gbm8gZGljaGFzIHBlbGljdWxhcy4gDQoNCiMjIDMuMiBDcmVhciBsYSBtYXRyaXoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQptb3ZpZV9yYXRpbmdzX3RhcmVhIDwtIGRhdGEuZnJhbWUoDQogIEtQMSA9IGMoNSwgNCwgNSwgNCksIA0KICBFTlJFREFET1MgPSBjKDQsIDUsIDQsIE5BKSwNCiAgVVAgPSBjKDUsIDQsIDUsIDIpLA0KICBDQVJTMSA9IGMoNCwgNSwgMywgTkEpLA0KICBUUzMgID0gYygzLCA1LCAzLCAyKSwNCiAgU0hSRUsyID0gYygzLCA1LCA0LCAzKSwNCiAgTU9OSkEgPSBjKDMsIE5BLCAzLCBOQSkNCikNCnJvd25hbWVzKG1vdmllX3JhdGluZ3NfdGFyZWEpIDwtIGMoJ0RpZWdvJywnTGFsbycsICAnQWxlJywgJ1lvdScgKQ0KbW92aWVfcmF0aW5nc190YXJlYQ0KYGBgDQoNCiMjIDMuMyBQcm9jZXNvIGRlIG1hdHJpY2VzOg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmNvc2luZV9zaW1pbGFyaXR5IDwtIGZ1bmN0aW9uKHZlY18xLCB2ZWNfMikgew0KICB2ZWNfbGVuIDwtIGxlbmd0aCh2ZWNfMSkNCiAgDQogICMgTkEgdmFsdWVzIGFyZSByZXBsYWNlZCB3aXRoIDANCiAgdmVjXzFbaXMubmEodmVjXzEpXSA8LSAwDQogIHZlY18yW2lzLm5hKHZlY18yKV0gPC0gMA0KICANCiAgIyBDb21wdXRpbmcgdGhlIGRlbm9taW5hdG9yDQogIHZlY18xX2Rlbm9tIDwtIHNxcnQoc3VtKHZlY18xXjIpKQ0KICB2ZWNfMl9kZW5vbSA8LSBzcXJ0KHN1bSh2ZWNfMl4yKSkNCiAgZGVub21pbmF0b3IgPC0gdmVjXzFfZGVub20gKiB2ZWNfMl9kZW5vbQ0KICANCiAgIyBDb21wdXRpbmcgdGhlIG51bWVyYXRvcg0KICB0aWIgPSB0aWJibGUodmVjXzEgPSB2ZWNfMSwgdmVjXzIgPSB2ZWNfMikNCiAgdGliIDwtIHRpYiAlPiUgbXV0YXRlKHByb2R1Y3RzID0gdmVjXzEgKiB2ZWNfMikNCiAgbnVtZXJhdG9yIDwtIHN1bSh0aWIkcHJvZHVjdHMpDQogIA0KICAjIFJldHVybiB0aGUgY29zaW5lIHNpbWlsYXJpdHkNCiAgcmV0dXJuIChudW1lcmF0b3IgLyBkZW5vbWluYXRvcikNCn0NCmBgYA0KIA0KIyMgMy40IFZlY3Rvcml6YW1vcyBsYXMgcHVudHVhY2lvbmVzOg0KYGBge3Igd2FybmluZz1GQUxTRX0NCiMgT2J0ZW5lbW9zIGxvcyB2ZWN0b3JlcyBkZSBjYWRhIHBlcnNvbmENCllvdSA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydZb3UnLF0pKQ0KRGllZ28gPC0gYXMubnVtZXJpYyhhcy52ZWN0b3IobW92aWVfcmF0aW5nc190YXJlYVsnRGllZ28nLF0pKQ0KTGFsbyA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydMYWxvJyxdKSkNCkFsZSA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydBbGUnLF0pKQ0KDQoNCiMgT2J0ZW5lbW9zICJkaXN0YW5jaWEiIHVzYW5kbyBzaW1pbGl0dWQgcG9yIGNvbnNlbm8NCnNpbWlsYXJpdGllc190YXJlYSA8LSBkYXRhLmZyYW1lKA0KICBjb3NpbmVfc2ltaWxhcml0eSA9IGMoY29zaW5lX3NpbWlsYXJpdHkoWW91LCBEaWVnbyksIGNvc2luZV9zaW1pbGFyaXR5KFlvdSwgTGFsbyksIGNvc2luZV9zaW1pbGFyaXR5KFlvdSwgQWxlKSkNCikNCnJvd25hbWVzKHNpbWlsYXJpdGllc190YXJlYSkgPC0gYygnRGllZ28nLCAnTGFsbycsICdBbGUnKQ0Kc2ltaWxhcml0aWVzX3RhcmVhDQpgYGANCg0KIyMgMy41IFByb21lZGlvIHBvbmRlcmFkbzoNClVuYSB2ZXogb2J0ZW5pZGFzIGxhcyBzaW1pbGFyaWRhZGVzLCByZWFsaXphbW9zIHVuIHByb21lZGlvIHBvbmRlcmFkbyBwYXJhIHBvZGVyIHJlY29tZW5kYXIgIkxhIG1vbmphIg0KYGBge3Igd2FybmluZz1GQUxTRX0NCiMgQ3JlYW1vcyB1bmEgZnVuY2nDs24gcGFyYSBvYnRlbmVyIHVuIHByb21lZGlvIHBvbmRlcmFkbyBlbiBiYXNlIGEgbG9zIGFtaWdvcw0KbW92aWVfcmF0aW5nX3dlaWdodGVkX2F2ZXJhZ2UgPC0gZnVuY3Rpb24obW92aWUsIGZyaWVuZHMpIHsNCiAgZGVub21pbmF0b3IgPC0gMA0KICBudW1lcmF0b3IgPC0gMA0KICBmb3IgKGZyaWVuZCBpbiBmcmllbmRzKSB7DQogICAgZnJpZW5kX3NpbWlsYXJpdHkgPC0gc2ltaWxhcml0aWVzX3RhcmVhW2ZyaWVuZCxdWzFdDQogICAgZnJpZW5kX3JhdGluZyA8LSBtb3ZpZV9yYXRpbmdzX3RhcmVhW2ZyaWVuZCwgbW92aWVdWzFdDQogICAgDQogICAgIyBUb21hcmVtb3MgZWwgcHJvbWVkaW8gcG9uZGVyYWRvIGVuIGN1ZW50YSBzb2xvIHBhcmEgcGVsw61jdWxhcyBjb24gY2FsaWZpY2FjacOzbg0KICAgIGlmIChpcy5uYShmcmllbmRfcmF0aW5nKSkgbmV4dA0KICAgIA0KICAgIGRlbm9taW5hdG9yIDwtIGRlbm9taW5hdG9yICsgZnJpZW5kX3NpbWlsYXJpdHkNCiAgICBudW1lcmF0b3IgPC0gbnVtZXJhdG9yICsgKGZyaWVuZF9zaW1pbGFyaXR5ICogZnJpZW5kX3JhdGluZykNCiAgfQ0KICANCiAgcmV0dXJuIChudW1lcmF0b3IgLyBkZW5vbWluYXRvcikNCn0NCmBgYA0KDQojIyAzLjYgUHJlZGljY2nDs24NClVzYW1vcyBsYSBmdW5jacOzbiBjcmVhZGEgY29uIGFudGVyaW9yaWRhZCBwYXJhIHByZWRlY2lyICJMYSBtb25qYSIgDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZnJpZW5kX25hbWVzIDwtIGMoJ0RpZWdvJywgJ0xhbG8nLCAnQWxlJykNCm5ld19tb3ZpZXMgPC0gYygnRU5SRURBRE9TJywgJ0NBUlMxJywgJ01PTkpBJykNCm5ld19tb3ZpZV9wcmVkaWN0ZWRfcmF0aW5ncyA8LSB0aWJibGUoKQ0KZm9yIChuIGluIG5ld19tb3ZpZXMpIHsNCiAgcHJlZGljdGVkX3JhdGluZyA8LSBtb3ZpZV9yYXRpbmdfd2VpZ2h0ZWRfYXZlcmFnZShuLCBmcmllbmRfbmFtZXMpDQogIHByZWRpY3Rpb25fdGliYmxlIDwtIHRpYmJsZShtb3ZpZSA9IG4sIHByZWRpY3RlZF9yYXRpbmcgPSBwcmVkaWN0ZWRfcmF0aW5nKQ0KICBuZXdfbW92aWVfcHJlZGljdGVkX3JhdGluZ3MgPC0gYmluZF9yb3dzKG5ld19tb3ZpZV9wcmVkaWN0ZWRfcmF0aW5ncywgcHJlZGljdGlvbl90aWJibGUpDQp9DQpuZXdfbW92aWVfcHJlZGljdGVkX3JhdGluZ3MNCmBgYA0KQ29tbyBwb2RlbW9zIHZlciwgbGEgcGVsw61jdWxhIGNvbiBtYXlvciByYXRpbmcgcHJlZGljaG8gZXMgRU5SRURBRE9TIHBvciBsbyBxdWUgc2Vyw6EgbGEgcGVsw61jdWxhIHJlY29tZW5kYWRhIGVuIHByaW1lciBsdWdhcg0KDQoNCiMgNC4gVGFyZWEgMi4gQ2hhdGJvdA0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXDEzMzE3MDYzXzUyMDg5OTYuanBnKQ0KDQojIyA0LjEgRGVzY3JpcGNpw7NuDQpFbCBjaGF0Ym90IHJlYWxpemFkbyBlcyBjb24gbGEgZmluYWxpZGFkIGRlIG1vc3RyYXIgbG9zIHRlbWFzIHZpc3RvcyBkZW50cm8gZGVsIG1vZHVsbyA0IGRlIGxhIGNvbnNlbnRyYWNpw7NuIGRlIEludGVsaWdlbmNpYSBBcnRpZmljaWFsLiBBbCBpbmdyZXNhciBzb2xpY2l0YSBhbCB1c3VhcmlvIHF1ZSBzZSBpZGVudGlmaXF1ZTsgZGVzcHXDqXMgc2UgbW9zdHJhcmFuIGxvcyBkb3MgdGVtYXMgcHJpbmNpcGFsZXM6ICpEYXRvcyBFc3RydWN0dXJhZG9zKiB5ICpEYXRvcyBObyBFc3RydWN0dXJhZG9zKi4gQWwgZGFyIGNsaWNrIGVuIGFsZ3VubyBkZSBlbGxvcyBzZSBtb3N0cmFyYW4gbG9zIHRlbWFzIHZpc3RvcyBhc8OtIGNvbW8gdW4gcnB1YiBkZWwgdGVtYS4NCg0KIyMgNC4yIENyZWFjacOzbiBkZWwgQ0hBVEJPVA0KU2UgY3Jlw7MgdW4gKipDSEFUQk9UKiogcG9yIG1lZGlvIGRlIGxhIGFwbGljYWNpw7NuICpUZWxlZ3JhbSouIENvbiBsYSBheXVkYSBkZWwgKipAQm90RmF0aGVyKiogRG9uZGUgc2UgY29uZmlndXJhcm9uIGxvcyBzaWd1aWVudGVzIHB1bnRvcyBkZSB2aXN1YWxpemFjacOzbi4NCg0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXFdoYXRzQXBwIEltYWdlIDIwMjQtMDQtMjEgYXQgMS4wNS4zNyBQTS5qcGVnKQ0KDQpVbmEgdmV6IGNyZWFkbyBlbCBib3QsIGFzw60gY29tbyBzdSBjb25maWd1cmFjacOzbiBzZSB1dGlsaXpvIGxhIGhlcnJhbWllbnRhICoqU0VORFBVTFNFKiosIGVuIGxhIGN1YWwgc2UgY3JlbyB1bmEgY3VlbnRhIGNvbiBsYSBmaW5hbGlkYWQgZGUgY29uZmlndXJhciBlbCBmdW5jaW9uYW1pZW50byBkZWwgY2hhdC4gDQoNCltWaXNpdGEgU0VORFBVTFNFXShodHRwczovL3NlbmRwdWxzZS5jb20vbGF0YW0vZmVhdHVyZXMvZW1haWw/e2xwdXJsfT9hbHRfc291cmNlPWdvb2dsZSZhbHRfbWVkaXVtPWNwYyZhbHRfY2FtcGFpZ249MTYxNTMzMTI5NzcmYWx0X3Rlcm09c2VuZHB1bHNlJmFsdF9jb250ZW50PWNydF82MjE4NjM0MzQ5ODN8Y2hfZ29vZ2xlfGt3bXRfYnxwc198c3JjdF9nfHRyZ3RffHNyY198Z3JvdXBJRF8xMzE1NjY2ODgwNDV8Y2FtcGFpZ25JRF8xNjE1MzMxMjk3N3xrZXl3b3JkSURfa3dkLTM2MTMwNzU2NTUxN3xleHA9YWRlLjA/JmFsdF9zb3VyY2U9Z29vZ2xlJmFsdF9tZWRpdW09Y3BjJmFsdF9jYW1wYWlnbj0xNjE1MzMxMjk3NyZhbHRfdGVybT1zZW5kcHVsc2UmYWx0X2NvbnRlbnQ9Y3J0XzYyMTg2MzQzNDk4M3xjaF9nb29nbGV8a3dtdF9ifHBzX3xzcmN0X2d8dHJndF98c3JjX3xncm91cElEXzEzMTU2NjY4ODA0NXxjYW1wYWlnbklEXzE2MTUzMzEyOTc3fGtleXdvcmRJRF9rd2QtMzYxMzA3NTY1NTE3JmdhZF9zb3VyY2U9MSZnY2xpZD1DajBLQ1FqdzhwS3hCaERfQVJJc0FQckc0NW5ISXFsZnRvWWl6bXk5bi0xZTZHQzViV00xRkwxWG1ONFZfb0xFZ0pTRU0tZzBTTGxBRU40YUFsREJFQUx3X3djQikNCg0KRGVudHJvIGRlIGVzdGEgcGxhdGFmb3JtYSBzZSB2aW5jdWxvIGVsIGNoYXRib3QgcG9yIG1lZGlvIGRlbCAqdG9rZW4qIHByb3BvcmNpb25hZG8gZW4gdGVsZWdyYW0uIEFkZW3DoXMgZGUgdW4gbWVuc2FqZSBkZSBiaWVudmVuaWRhIGFsIGluaWNpYXIgZWwgY2hhdC4NCg0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXFdoYXRzQXBwIEltYWdlIDIwMjQtMDQtMjEgYXQgMS4xNy40MCBQTS5qcGVnKQ0KDQpEZSBpZ3VhbCBtYW5lcmEgc2UgZXN0cnVjdHVyYXJvbiBsb3MgbWVuc2FqZXMgcGFyYSBsYSBpbnRlcmFjY2nDs24gY29uIGVsIHVzdWFyaW8uDQoNCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDEuMjEuMTAgUE0uanBlZykNCkVuIGVzdGUgcHJvY2VzbyBzZSBzb2xpY2l0YSBlbCAqTm9tYnJlKiB5ICpDb3JyZW8gZWxlY3Ryb25pY28qLCBjdXlvcyBzZSBndWFyZGFhbiBlbiB2YXJpYWJsZXMgcGFyYSBzZXIgbW9zdHJhZG9zIGVuIGVsIHNpZ3VpZW50ZSBtZW5zYWplLiANCg0KIyMgNC40IEludGVyYWNjacOzbiBjb24gZWwgQ2hhdGJvdA0KDQohW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcV2hhdHNBcHAgSW1hZ2UgMjAyNC0wNC0yMSBhdCAxLjQ2LjU1IFBNLmpwZWcpDQoNCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDEuNDYuNTYgUE0uanBlZykNCg0KIyMgNC4zIENoYXRib3QNCkxpbmsgZGVsIGNoYXRib3Q6DQoNCltWaXNpdGEgQ0hBVF0oaHR0cHM6Ly9kaWVnbzU1NjEtYm90LnRnLnB1bHNlLmlzLykNCg0KIyA1LiBUYXJlYSAzLiBBbsOhbGlzaXMgZGUgQXVkaW8NCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxBdWRpby13YXZlcy1taW4tMS5naWYpDQoNCiMjIDUuMSBEZXNjcmlwY2nDs24NCkVuIGVzdGEgYWN0aXZpZGFkIHNlIGNyZcOzIHVuIGF1ZGlvIGVuICoqUHl0aG9uKiogY29uIGxhIGZ1bmNpw7NuICp0ZXh0IHRvIHNwZWVjaCogYWRlbcOhcyBkZSBsYSAqKkFQSSoqICoiVGV4dC10by1zcGVlY2giKiBkZSAqKk9wZW5BSSoqLiBVdGlsaXphbmRvICoqUioqIHNlIGdlbmVyYSBlbCAqRUNPKi4NCg0KIyMgNS4yIENyZWFjacOzbiBkZSBhdWRpbw0KU2UgZXN0YWJsZWNlIGxhIGNvbmV4acOzbiBkZSBsYSAqKkFQSSoqIGNvbiAqKlB5dGhvbioqLiBVdGlsaXphbmRvIGxhIGZ1bmNpw7NuICpUZXh0LXRvLXNwZWVjaCouDQoNCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDMuNTEuNTIgUE0uanBlZykgDQoNCkRlc2NhcmdhbW8gZWwgYXVkaW8geSBjb250aW51YW1vcyBlbiAqKlIqKi4NCg0KIyMgNS4zIENyZWFjacOzbiBkZSBlY28NCiMjIyA1LjMuMSBJbXBvcnRhciBhdWRpbw0KU2UgaW1wb3J0YSBlbCBhdWRpbyBnZW5lcmFkbyBwb3IgcHl0aG9uDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZmlsZV9wYXRoIDwtICJEaWVnb190YXJlYS5tcDMiDQphdWRpb19kYXRhIDwtIHJlYWRNUDMoZmlsZV9wYXRoKQ0KeSA8LSBhdWRpb19kYXRhQGxlZnQNCkZzIDwtIGF1ZGlvX2RhdGFAc2FtcC5yYXRlDQpgYGANCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFx0MiwzLDRcXERpZWdvX3RhcmVhLm1wMykNCg0KIyMjIDUuMy4yIFBhcsOhbWV0cm9zIGRlIEVDTw0KYGBge3J9DQphbHBoYSA8LSAwLjkNCkQgPC0gMC4yNSAqIEZzICANCmVjaG8gPC0gbnVtZXJpYyhsZW5ndGgoeSkgKyBEKQ0KZWNob1sxOmxlbmd0aCh5KV0gPC0geQ0KZWNob1soRCsxKTooRCtsZW5ndGgoeSkpXSA8LSBhbHBoYSAqIHkNCmBgYA0KDQojIyMgNS4zLjMgVW5pciBhdWRpb3MgDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KeCA8LSB5ICsgZWNob1sxOmxlbmd0aCh5KV0NCm5ld19hdWRpbyA8LSBXYXZlKHgsIHNhbXAucmF0ZSA9IEZzKQ0Kb3V0cHV0X2ZpbGUgPC0gIkRpZWdvXzU1NjFfZWNoby53YXYiDQp3cml0ZVdhdmUobmV3X2F1ZGlvLCBmaWxlbmFtZSA9IG91dHB1dF9maWxlKQ0KYGBgDQohW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcRGllZ29fNTU2MV9lY2hvLndhdikNCg==