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.

2. Instalación de librerías.

library(tidyverse)   
library(recommenderlab)
#install.packages("signal")
library(signal)
#install.packages("audio")
library(audio)
#install.packages("tuneR")
library(tuneR)

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

4.3 Chatbot

Link del chatbot:

Visita CHAT

5. Tarea 3. Análisis de Audio

5.1 Descripción

En esta actividad se creó un audio en Python con la función text to speech además de la API “Text-to-speech” de OpenAI. Utilizando R se genera el ECO.

5.2 Creación de audio

Se establece la conexión de la API con Python. Utilizando la función Text-to-speech.

Descargamo el audio y continuamos en R.

5.3 Creación de eco

5.3.1 Importar audio

Se importa el audio generado por python

file_path <- "Diego_tarea.mp3"
audio_data <- readMP3(file_path)
y <- audio_data@left
Fs <- audio_data@samp.rate

5.3.2 Parámetros de ECO

alpha <- 0.9
D <- 0.25 * Fs  
echo <- numeric(length(y) + D)
echo[1:length(y)] <- y
echo[(D+1):(D+length(y))] <- alpha * y

5.3.3 Unir audios

x <- y + echo[1:length(y)]
new_audio <- Wave(x, samp.rate = Fs)
output_file <- "Diego_5561_echo.wav"
writeWave(new_audio, filename = output_file)

LS0tDQp0aXRsZTogIlRhcmVhIDIsIDMgeSA0Ig0KYXV0aG9yOiAiRGllZ28gQWxlamFuZHJvIFDDqXJleiBDaXNuZXJvcyAtIEEwMTI3NTU2MSINCmRhdGU6ICIyMDI0LTA0LTIxIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IHNpbXBsZXggDQotLS0NCiANCiAhW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcZGF0b3MtZXN0cnVjdHVyYWRvcy0wMC5qcGcpDQogDQogDQojIDEuIENvbnRleHRvDQpFbiBlc3RlIGRvY3VtZW50byBzZSByZWFsaXphcmFuIDMgbcOpdG9kb3MgZGUgY8OzbW8gc2UgcHVlZGVuIG1hbmVqYXIgbG9zIGRhdG9zIG5vIGVzdHJ1Y3R1cmFkb3MuIEVudHJlIGxvcyBjdWFsZXMgc2UgYWJvcmRhcmFuIHRlbWFzIGNvbW8gdW4gc2lzdGVtYSBkZSByZWNvbWVuZGFjacOzbiwgdW4gY2hhdCBib3QgeSB1biBhbsOhbGlzaXMgZGUgYXVkaW8uDQoNCiMgMi4gSW5zdGFsYWNpw7NuIGRlIGxpYnJlcsOtYXMuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpICAgDQpsaWJyYXJ5KHJlY29tbWVuZGVybGFiKQ0KI2luc3RhbGwucGFja2FnZXMoInNpZ25hbCIpDQpsaWJyYXJ5KHNpZ25hbCkNCiNpbnN0YWxsLnBhY2thZ2VzKCJhdWRpbyIpDQpsaWJyYXJ5KGF1ZGlvKQ0KI2luc3RhbGwucGFja2FnZXMoInR1bmVSIikNCmxpYnJhcnkodHVuZVIpDQpgYGANCg0KDQojIDMuIFRhcmVhIDEuIFNpc3RlbWEgZGUgcmVjb21lbmRhY2nDs24NCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDExLjAxLjIyIEFNLmpwZWcpDQoNCiMjIDMuMSBEZXNjcmlwY2nDs24NClNlIHV0aWxpem8gbGFzIGNhbGlmaWNhY2nDs24gZGUgcGVsaWN1bGFzIGRlIDMgY29tcGHDsWVyb3MgY29tcGFyYW5kb2xvcyBjb24gYWxndW5hcyBkZSBtaXMgY2FsaWZpY2FjaW9uZXMsIGRlamFuZG8gTkEncyBjb24gbGEgZmluYWxpZGFkIGRlIHBvZGVyIHByZWRlY2lyIHNpIG1lIHJlY29tZW5kYWJhIG8gbm8gZGljaGFzIHBlbGljdWxhcy4gDQoNCiMjIDMuMiBDcmVhciBsYSBtYXRyaXoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQptb3ZpZV9yYXRpbmdzX3RhcmVhIDwtIGRhdGEuZnJhbWUoDQogIEtQMSA9IGMoNSwgNCwgNSwgNCksIA0KICBFTlJFREFET1MgPSBjKDQsIDUsIDQsIE5BKSwNCiAgVVAgPSBjKDUsIDQsIDUsIDIpLA0KICBDQVJTMSA9IGMoNCwgNSwgMywgTkEpLA0KICBUUzMgID0gYygzLCA1LCAzLCAyKSwNCiAgU0hSRUsyID0gYygzLCA1LCA0LCAzKSwNCiAgTU9OSkEgPSBjKDMsIE5BLCAzLCBOQSkNCikNCnJvd25hbWVzKG1vdmllX3JhdGluZ3NfdGFyZWEpIDwtIGMoJ0RpZWdvJywnTGFsbycsICAnQWxlJywgJ1lvdScgKQ0KbW92aWVfcmF0aW5nc190YXJlYQ0KYGBgDQoNCiMjIDMuMyBQcm9jZXNvIGRlIG1hdHJpY2VzOg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmNvc2luZV9zaW1pbGFyaXR5IDwtIGZ1bmN0aW9uKHZlY18xLCB2ZWNfMikgew0KICB2ZWNfbGVuIDwtIGxlbmd0aCh2ZWNfMSkNCiAgDQogICMgTkEgdmFsdWVzIGFyZSByZXBsYWNlZCB3aXRoIDANCiAgdmVjXzFbaXMubmEodmVjXzEpXSA8LSAwDQogIHZlY18yW2lzLm5hKHZlY18yKV0gPC0gMA0KICANCiAgIyBDb21wdXRpbmcgdGhlIGRlbm9taW5hdG9yDQogIHZlY18xX2Rlbm9tIDwtIHNxcnQoc3VtKHZlY18xXjIpKQ0KICB2ZWNfMl9kZW5vbSA8LSBzcXJ0KHN1bSh2ZWNfMl4yKSkNCiAgZGVub21pbmF0b3IgPC0gdmVjXzFfZGVub20gKiB2ZWNfMl9kZW5vbQ0KICANCiAgIyBDb21wdXRpbmcgdGhlIG51bWVyYXRvcg0KICB0aWIgPSB0aWJibGUodmVjXzEgPSB2ZWNfMSwgdmVjXzIgPSB2ZWNfMikNCiAgdGliIDwtIHRpYiAlPiUgbXV0YXRlKHByb2R1Y3RzID0gdmVjXzEgKiB2ZWNfMikNCiAgbnVtZXJhdG9yIDwtIHN1bSh0aWIkcHJvZHVjdHMpDQogIA0KICAjIFJldHVybiB0aGUgY29zaW5lIHNpbWlsYXJpdHkNCiAgcmV0dXJuIChudW1lcmF0b3IgLyBkZW5vbWluYXRvcikNCn0NCmBgYA0KIA0KIyMgMy40IFZlY3Rvcml6YW1vcyBsYXMgcHVudHVhY2lvbmVzOg0KYGBge3Igd2FybmluZz1GQUxTRX0NCiMgT2J0ZW5lbW9zIGxvcyB2ZWN0b3JlcyBkZSBjYWRhIHBlcnNvbmENCllvdSA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydZb3UnLF0pKQ0KRGllZ28gPC0gYXMubnVtZXJpYyhhcy52ZWN0b3IobW92aWVfcmF0aW5nc190YXJlYVsnRGllZ28nLF0pKQ0KTGFsbyA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydMYWxvJyxdKSkNCkFsZSA8LSBhcy5udW1lcmljKGFzLnZlY3Rvcihtb3ZpZV9yYXRpbmdzX3RhcmVhWydBbGUnLF0pKQ0KDQoNCiMgT2J0ZW5lbW9zICJkaXN0YW5jaWEiIHVzYW5kbyBzaW1pbGl0dWQgcG9yIGNvbnNlbm8NCnNpbWlsYXJpdGllc190YXJlYSA8LSBkYXRhLmZyYW1lKA0KICBjb3NpbmVfc2ltaWxhcml0eSA9IGMoY29zaW5lX3NpbWlsYXJpdHkoWW91LCBEaWVnbyksIGNvc2luZV9zaW1pbGFyaXR5KFlvdSwgTGFsbyksIGNvc2luZV9zaW1pbGFyaXR5KFlvdSwgQWxlKSkNCikNCnJvd25hbWVzKHNpbWlsYXJpdGllc190YXJlYSkgPC0gYygnRGllZ28nLCAnTGFsbycsICdBbGUnKQ0Kc2ltaWxhcml0aWVzX3RhcmVhDQpgYGANCg0KIyMgMy41IFByb21lZGlvIHBvbmRlcmFkbzoNClVuYSB2ZXogb2J0ZW5pZGFzIGxhcyBzaW1pbGFyaWRhZGVzLCByZWFsaXphbW9zIHVuIHByb21lZGlvIHBvbmRlcmFkbyBwYXJhIHBvZGVyIHJlY29tZW5kYXIgIkxhIG1vbmphIg0KYGBge3Igd2FybmluZz1GQUxTRX0NCiMgQ3JlYW1vcyB1bmEgZnVuY2nDs24gcGFyYSBvYnRlbmVyIHVuIHByb21lZGlvIHBvbmRlcmFkbyBlbiBiYXNlIGEgbG9zIGFtaWdvcw0KbW92aWVfcmF0aW5nX3dlaWdodGVkX2F2ZXJhZ2UgPC0gZnVuY3Rpb24obW92aWUsIGZyaWVuZHMpIHsNCiAgZGVub21pbmF0b3IgPC0gMA0KICBudW1lcmF0b3IgPC0gMA0KICBmb3IgKGZyaWVuZCBpbiBmcmllbmRzKSB7DQogICAgZnJpZW5kX3NpbWlsYXJpdHkgPC0gc2ltaWxhcml0aWVzX3RhcmVhW2ZyaWVuZCxdWzFdDQogICAgZnJpZW5kX3JhdGluZyA8LSBtb3ZpZV9yYXRpbmdzX3RhcmVhW2ZyaWVuZCwgbW92aWVdWzFdDQogICAgDQogICAgIyBUb21hcmVtb3MgZWwgcHJvbWVkaW8gcG9uZGVyYWRvIGVuIGN1ZW50YSBzb2xvIHBhcmEgcGVsw61jdWxhcyBjb24gY2FsaWZpY2FjacOzbg0KICAgIGlmIChpcy5uYShmcmllbmRfcmF0aW5nKSkgbmV4dA0KICAgIA0KICAgIGRlbm9taW5hdG9yIDwtIGRlbm9taW5hdG9yICsgZnJpZW5kX3NpbWlsYXJpdHkNCiAgICBudW1lcmF0b3IgPC0gbnVtZXJhdG9yICsgKGZyaWVuZF9zaW1pbGFyaXR5ICogZnJpZW5kX3JhdGluZykNCiAgfQ0KICANCiAgcmV0dXJuIChudW1lcmF0b3IgLyBkZW5vbWluYXRvcikNCn0NCmBgYA0KDQojIyAzLjYgUHJlZGljY2nDs24NClVzYW1vcyBsYSBmdW5jacOzbiBjcmVhZGEgY29uIGFudGVyaW9yaWRhZCBwYXJhIHByZWRlY2lyICJMYSBtb25qYSIgDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZnJpZW5kX25hbWVzIDwtIGMoJ0RpZWdvJywgJ0xhbG8nLCAnQWxlJykNCm5ld19tb3ZpZXMgPC0gYygnRU5SRURBRE9TJywgJ0NBUlMxJywgJ01PTkpBJykNCm5ld19tb3ZpZV9wcmVkaWN0ZWRfcmF0aW5ncyA8LSB0aWJibGUoKQ0KZm9yIChuIGluIG5ld19tb3ZpZXMpIHsNCiAgcHJlZGljdGVkX3JhdGluZyA8LSBtb3ZpZV9yYXRpbmdfd2VpZ2h0ZWRfYXZlcmFnZShuLCBmcmllbmRfbmFtZXMpDQogIHByZWRpY3Rpb25fdGliYmxlIDwtIHRpYmJsZShtb3ZpZSA9IG4sIHByZWRpY3RlZF9yYXRpbmcgPSBwcmVkaWN0ZWRfcmF0aW5nKQ0KICBuZXdfbW92aWVfcHJlZGljdGVkX3JhdGluZ3MgPC0gYmluZF9yb3dzKG5ld19tb3ZpZV9wcmVkaWN0ZWRfcmF0aW5ncywgcHJlZGljdGlvbl90aWJibGUpDQp9DQpuZXdfbW92aWVfcHJlZGljdGVkX3JhdGluZ3MNCmBgYA0KQ29tbyBwb2RlbW9zIHZlciwgbGEgcGVsw61jdWxhIGNvbiBtYXlvciByYXRpbmcgcHJlZGljaG8gZXMgRU5SRURBRE9TIHBvciBsbyBxdWUgc2Vyw6EgbGEgcGVsw61jdWxhIHJlY29tZW5kYWRhIGVuIHByaW1lciBsdWdhcg0KDQoNCiMgNC4gVGFyZWEgMi4gQ2hhdGJvdA0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXDEzMzE3MDYzXzUyMDg5OTYuanBnKQ0KDQojIyA0LjEgRGVzY3JpcGNpw7NuDQpFbCBjaGF0Ym90IHJlYWxpemFkbyBlcyBjb24gbGEgZmluYWxpZGFkIGRlIG1vc3RyYXIgbG9zIHRlbWFzIHZpc3RvcyBkZW50cm8gZGVsIG1vZHVsbyA0IGRlIGxhIGNvbnNlbnRyYWNpw7NuIGRlIEludGVsaWdlbmNpYSBBcnRpZmljaWFsLiBBbCBpbmdyZXNhciBzb2xpY2l0YSBhbCB1c3VhcmlvIHF1ZSBzZSBpZGVudGlmaXF1ZTsgZGVzcHXDqXMgc2UgbW9zdHJhcmFuIGxvcyBkb3MgdGVtYXMgcHJpbmNpcGFsZXM6ICpEYXRvcyBFc3RydWN0dXJhZG9zKiB5ICpEYXRvcyBObyBFc3RydWN0dXJhZG9zKi4gQWwgZGFyIGNsaWNrIGVuIGFsZ3VubyBkZSBlbGxvcyBzZSBtb3N0cmFyYW4gbG9zIHRlbWFzIHZpc3RvcyBhc8OtIGNvbW8gdW4gcnB1YiBkZWwgdGVtYS4NCg0KIyMgNC4yIENyZWFjacOzbiBkZWwgQ0hBVEJPVA0KU2UgY3Jlw7MgdW4gKipDSEFUQk9UKiogcG9yIG1lZGlvIGRlIGxhIGFwbGljYWNpw7NuICpUZWxlZ3JhbSouIENvbiBsYSBheXVkYSBkZWwgKipAQm90RmF0aGVyKiogRG9uZGUgc2UgY29uZmlndXJhcm9uIGxvcyBzaWd1aWVudGVzIHB1bnRvcyBkZSB2aXN1YWxpemFjacOzbi4NCg0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXFdoYXRzQXBwIEltYWdlIDIwMjQtMDQtMjEgYXQgMS4wNS4zNyBQTS5qcGVnKQ0KDQpVbmEgdmV6IGNyZWFkbyBlbCBib3QsIGFzw60gY29tbyBzdSBjb25maWd1cmFjacOzbiBzZSB1dGlsaXpvIGxhIGhlcnJhbWllbnRhICoqU0VORFBVTFNFKiosIGVuIGxhIGN1YWwgc2UgY3JlbyB1bmEgY3VlbnRhIGNvbiBsYSBmaW5hbGlkYWQgZGUgY29uZmlndXJhciBlbCBmdW5jaW9uYW1pZW50byBkZWwgY2hhdC4gDQoNCltWaXNpdGEgU0VORFBVTFNFXShodHRwczovL3NlbmRwdWxzZS5jb20vbGF0YW0vZmVhdHVyZXMvZW1haWw/e2xwdXJsfT9hbHRfc291cmNlPWdvb2dsZSZhbHRfbWVkaXVtPWNwYyZhbHRfY2FtcGFpZ249MTYxNTMzMTI5NzcmYWx0X3Rlcm09c2VuZHB1bHNlJmFsdF9jb250ZW50PWNydF82MjE4NjM0MzQ5ODN8Y2hfZ29vZ2xlfGt3bXRfYnxwc198c3JjdF9nfHRyZ3RffHNyY198Z3JvdXBJRF8xMzE1NjY2ODgwNDV8Y2FtcGFpZ25JRF8xNjE1MzMxMjk3N3xrZXl3b3JkSURfa3dkLTM2MTMwNzU2NTUxN3xleHA9YWRlLjA/JmFsdF9zb3VyY2U9Z29vZ2xlJmFsdF9tZWRpdW09Y3BjJmFsdF9jYW1wYWlnbj0xNjE1MzMxMjk3NyZhbHRfdGVybT1zZW5kcHVsc2UmYWx0X2NvbnRlbnQ9Y3J0XzYyMTg2MzQzNDk4M3xjaF9nb29nbGV8a3dtdF9ifHBzX3xzcmN0X2d8dHJndF98c3JjX3xncm91cElEXzEzMTU2NjY4ODA0NXxjYW1wYWlnbklEXzE2MTUzMzEyOTc3fGtleXdvcmRJRF9rd2QtMzYxMzA3NTY1NTE3JmdhZF9zb3VyY2U9MSZnY2xpZD1DajBLQ1FqdzhwS3hCaERfQVJJc0FQckc0NW5ISXFsZnRvWWl6bXk5bi0xZTZHQzViV00xRkwxWG1ONFZfb0xFZ0pTRU0tZzBTTGxBRU40YUFsREJFQUx3X3djQikNCg0KRGVudHJvIGRlIGVzdGEgcGxhdGFmb3JtYSBzZSB2aW5jdWxvIGVsIGNoYXRib3QgcG9yIG1lZGlvIGRlbCAqdG9rZW4qIHByb3BvcmNpb25hZG8gZW4gdGVsZWdyYW0uIEFkZW3DoXMgZGUgdW4gbWVuc2FqZSBkZSBiaWVudmVuaWRhIGFsIGluaWNpYXIgZWwgY2hhdC4NCg0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXFdoYXRzQXBwIEltYWdlIDIwMjQtMDQtMjEgYXQgMS4xNy40MCBQTS5qcGVnKQ0KDQpEZSBpZ3VhbCBtYW5lcmEgc2UgZXN0cnVjdHVyYXJvbiBsb3MgbWVuc2FqZXMgcGFyYSBsYSBpbnRlcmFjY2nDs24gY29uIGVsIHVzdWFyaW8uDQoNCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDEuMjEuMTAgUE0uanBlZykNCkVuIGVzdGUgcHJvY2VzbyBzZSBzb2xpY2l0YSBlbCAqTm9tYnJlKiB5ICpDb3JyZW8gZWxlY3Ryb25pY28qLCBjdXlvcyBzZSBndWFyZGFhbiBlbiB2YXJpYWJsZXMgcGFyYSBzZXIgbW9zdHJhZG9zIGVuIGVsIHNpZ3VpZW50ZSBtZW5zYWplLiANCg0KIyMgNC40IEludGVyYWNjacOzbiBjb24gZWwgQ2hhdGJvdA0KDQohW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcV2hhdHNBcHAgSW1hZ2UgMjAyNC0wNC0yMSBhdCAxLjQ2LjU1IFBNLmpwZWcpDQoNCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDEuNDYuNTYgUE0uanBlZykNCg0KIyMgNC4zIENoYXRib3QNCkxpbmsgZGVsIGNoYXRib3Q6DQoNCltWaXNpdGEgQ0hBVF0oaHR0cHM6Ly9kaWVnbzU1NjEtYm90LnRnLnB1bHNlLmlzLykNCg0KIyA1LiBUYXJlYSAzLiBBbsOhbGlzaXMgZGUgQXVkaW8NCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxBdWRpby13YXZlcy1taW4tMS5naWYpDQoNCiMjIDUuMSBEZXNjcmlwY2nDs24NCkVuIGVzdGEgYWN0aXZpZGFkIHNlIGNyZcOzIHVuIGF1ZGlvIGVuICoqUHl0aG9uKiogY29uIGxhIGZ1bmNpw7NuICp0ZXh0IHRvIHNwZWVjaCogYWRlbcOhcyBkZSBsYSAqKkFQSSoqICoiVGV4dC10by1zcGVlY2giKiBkZSAqKk9wZW5BSSoqLiBVdGlsaXphbmRvICoqUioqIHNlIGdlbmVyYSBlbCAqRUNPKi4NCg0KIyMgNS4yIENyZWFjacOzbiBkZSBhdWRpbw0KU2UgZXN0YWJsZWNlIGxhIGNvbmV4acOzbiBkZSBsYSAqKkFQSSoqIGNvbiAqKlB5dGhvbioqLiBVdGlsaXphbmRvIGxhIGZ1bmNpw7NuICpUZXh0LXRvLXNwZWVjaCouDQoNCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxXaGF0c0FwcCBJbWFnZSAyMDI0LTA0LTIxIGF0IDMuNTEuNTIgUE0uanBlZykgDQoNCkRlc2NhcmdhbW8gZWwgYXVkaW8geSBjb250aW51YW1vcyBlbiAqKlIqKi4NCg0KIyMgNS4zIENyZWFjacOzbiBkZSBlY28NCiMjIyA1LjMuMSBJbXBvcnRhciBhdWRpbw0KU2UgaW1wb3J0YSBlbCBhdWRpbyBnZW5lcmFkbyBwb3IgcHl0aG9uDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZmlsZV9wYXRoIDwtICJEaWVnb190YXJlYS5tcDMiDQphdWRpb19kYXRhIDwtIHJlYWRNUDMoZmlsZV9wYXRoKQ0KeSA8LSBhdWRpb19kYXRhQGxlZnQNCkZzIDwtIGF1ZGlvX2RhdGFAc2FtcC5yYXRlDQpgYGANCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFx0MiwzLDRcXERpZWdvX3RhcmVhLm1wMykNCg0KIyMjIDUuMy4yIFBhcsOhbWV0cm9zIGRlIEVDTw0KYGBge3J9DQphbHBoYSA8LSAwLjkNCkQgPC0gMC4yNSAqIEZzICANCmVjaG8gPC0gbnVtZXJpYyhsZW5ndGgoeSkgKyBEKQ0KZWNob1sxOmxlbmd0aCh5KV0gPC0geQ0KZWNob1soRCsxKTooRCtsZW5ndGgoeSkpXSA8LSBhbHBoYSAqIHkNCmBgYA0KDQojIyMgNS4zLjMgVW5pciBhdWRpb3MgDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KeCA8LSB5ICsgZWNob1sxOmxlbmd0aCh5KV0NCm5ld19hdWRpbyA8LSBXYXZlKHgsIHNhbXAucmF0ZSA9IEZzKQ0Kb3V0cHV0X2ZpbGUgPC0gIkRpZWdvXzU1NjFfZWNoby53YXYiDQp3cml0ZVdhdmUobmV3X2F1ZGlvLCBmaWxlbmFtZSA9IG91dHB1dF9maWxlKQ0KYGBgDQohW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcRGllZ29fNTU2MV9lY2hvLndhdikNCg==