Tema de Trabajo
El objetivo de este análisis es identificar las mejores y
peores películas del género Acción según el sentimiento
expresado en las reseñas de sus espectadores.
Se analizan más de 3,900 reseñas del género Acción,
identificando patrones emocionales y léxicos que distinguen a las
películas mejor y peor recibidas por el público a finales de los años 90
e inicios de los 2000.
Librerías
library(tidyverse) # Manipulación de datos
library(syuzhet) # Análisis de sentimientos y emociones
library(tm) # Minería de texto
library(wordcloud) # Nube de palabras
library(RColorBrewer) # Paletas de colores
Carga y Preparación de Datos
datos <- read.csv("movie_reviews.csv", stringsAsFactors = FALSE)
# Filtrar solo género Acción
accion <- datos %>%
filter(first_genre == "Action") %>%
select(movie_name, review_text, year)
cat("Total de reseñas de acción:", nrow(accion), "\n")
## Total de reseñas de acción: 3944
cat("Películas únicas:", n_distinct(accion$movie_name), "\n")
## Películas únicas: 429
Análisis de Sentimientos y Emociones
Puntuación de Sentimiento por Película
# Calcular sentimiento de cada reseña
accion$sentimiento <- get_sentiment(accion$review_text, method = "syuzhet")
# Promedio por película (mínimo 10 reseñas para mayor confiabilidad)
sentimiento_peliculas <- accion %>%
group_by(movie_name) %>%
summarise(
sentimiento_promedio = mean(sentimiento, na.rm = TRUE),
n_resenas = n()
) %>%
filter(n_resenas >= 10) %>%
arrange(desc(sentimiento_promedio))
# Top 5 Mejores
mejores <- head(sentimiento_peliculas, 5)
cat("Top 5 Mejores Películas de Acción:\n")
## Top 5 Mejores Películas de Acción:
print(mejores)
## # A tibble: 5 × 3
## movie_name sentimiento_promedio n_resenas
## <chr> <dbl> <int>
## 1 Star Wars 13.2 22
## 2 Charlie's Angels 12.5 18
## 3 Space Cowboys 12.0 16
## 4 Rush Hour 11.6 34
## 5 X-Men 11.6 25
# Top 5 Peores
peores <- tail(sentimiento_peliculas, 5)
cat("\nTop 5 Peores Películas de Acción:\n")
##
## Top 5 Peores Películas de Acción:
print(peores)
## # A tibble: 5 × 3
## movie_name sentimiento_promedio n_resenas
## <chr> <dbl> <int>
## 1 Con Air -1.89 29
## 2 Alien³ -2.20 11
## 3 Battlefield Earth -3.65 24
## 4 Ghosts of Mars -3.90 10
## 5 Natural Born Killers -4.00 22
Distribución de Sentimientos
ggplot(sentimiento_peliculas, aes(x = sentimiento_promedio)) +
geom_histogram(fill = "steelblue", color = "white", bins = 25) +
geom_vline(xintercept = 0, color = "red", linetype = "dashed", linewidth = 1) +
labs(
title = "Distribución de Sentimiento Promedio",
subtitle = "Películas de Acción con 10+ reseñas",
x = "Sentimiento Promedio",
y = "Número de Películas"
) +
theme_minimal()

Comparación Mejores vs Peores
# Unir mejores y peores para graficar
top_bottom <- bind_rows(
mejores %>% mutate(categoria = "Mejores"),
peores %>% mutate(categoria = "Peores")
) %>%
mutate(movie_name = str_trunc(movie_name, 30))
ggplot(top_bottom, aes(x = reorder(movie_name, sentimiento_promedio),
y = sentimiento_promedio,
fill = categoria)) +
geom_col(show.legend = FALSE) +
coord_flip() +
scale_fill_manual(values = c("Mejores" = "#2196F3", "Peores" = "#F44336")) +
labs(
title = "Top 5 Mejores y Peores Películas de Acción",
subtitle = "Por sentimiento promedio de reseñas",
x = NULL,
y = "Sentimiento Promedio"
) +
theme_minimal()

Análisis de Emociones
# Muestra pequeña para que corra rápido (NRC es intensivo por palabra)
set.seed(42)
muestra <- accion %>% sample_n(min(100, nrow(accion)))
palabras_muestra <- get_tokens(muestra$review_text)
emociones <- get_nrc_sentiment(palabras_muestra, language = "english")
# Gráfico 1: 8 emociones básicas
colores_emociones <- brewer.pal(8, "Set2")
barplot(
colSums(prop.table(emociones[, 1:8])),
main = "Análisis de Emociones — Reseñas de Acción",
col = colores_emociones,
las = 2,
ylab = "Proporción",
cex.names = 0.85
)

# Gráfico 2: Positivo vs Negativo
sentimientos_total <- colSums(prop.table(emociones[, 9:10]))
barplot(
sentimientos_total,
main = "Sentimiento General — Reseñas de Acción",
col = c("#F44336", "#4CAF50"),
ylab = "Proporción",
names.arg = c("Negativo", "Positivo"),
ylim = c(0, max(sentimientos_total) * 1.2)
)

Hallazgos: Análisis de Sentimientos y Emociones
Hallazgo 1 — Predominio positivo: A pesar de ser un
género de alto impacto, la mayoría de las reseñas de películas de acción
expresan un tono positivo, lo que indica que el público
llega con expectativas favorables y disfruta el entretenimiento del
género.
Hallazgo 2 — Emoción dominante: La emoción más
frecuente en las reseñas es la anticipación, seguida de
la confianza. Esto refleja que los espectadores acuden
con altas expectativas y generalmente las reseñas expresan certeza al
emitir sus opiniones.
Hallazgo 3 — Peores películas e ira: Las películas
con sentimiento más negativo concentran altos niveles de
ira y asco en sus reseñas, sugiriendo
decepción activa —no solo indiferencia— por parte del público.
Nube de Palabras
Nube de Palabras — Mejores Películas
mejores_nombres <- mejores$movie_name
textos_mejores <- accion %>%
filter(movie_name %in% mejores_nombres) %>%
pull(review_text) %>%
paste(collapse = " ")
palabras_mejores <- get_tokens(textos_mejores)
palabras_mejores <- removeWords(
palabras_mejores,
c(stopwords("english"),
"film", "movie", "one", "like", "just", "even", "get", "can",
"will", "much", "also", "well", "made", "make", "way", "good",
"still", "really", "see", "come", "back", "two", "first", "reviews", "review", "movies", "rec", "chan", "ascci", "html")
)
set.seed(42)
wordcloud(
words = palabras_mejores,
min.freq = 3,
max.words = 80,
rot.per = 0.1,
random.order = FALSE,
colors = brewer.pal(8, "Blues"),
scale = c(4, 0.5)
)
title(main = "Palabras en Reseñas — Mejores Películas de Acción", cex.main = 1)

Nube de Palabras — Peores Películas
peores_nombres <- peores$movie_name
textos_peores <- accion %>%
filter(movie_name %in% peores_nombres) %>%
pull(review_text) %>%
paste(collapse = " ")
palabras_peores <- get_tokens(textos_peores)
palabras_peores <- removeWords(
palabras_peores,
c(stopwords("english"),
"film", "movie", "one", "like", "just", "even", "get", "can",
"will", "much", "also", "well", "made", "make", "way", "good",
"still", "really", "see", "come", "back", "two", "first", "reviews", "review", "movies", "rec", "chan", "ascci", "html")
)
set.seed(42)
wordcloud(
words = palabras_peores,
min.freq = 3,
max.words = 80,
rot.per = 0.1,
random.order = FALSE,
colors = brewer.pal(8, "Reds"),
scale = c(4, 0.5)
)
title(main = "Palabras en Reseñas — Peores Películas de Acción", cex.main = 1)

Hallazgos: Nube de Palabras
Hallazgo 4 — Vocabulario de calidad: En las mejores
películas, destacan términos como “story”,
“character”, “great”, “performance” —
indicando que el público valora la narrativa y los
personajes por encima de los efectos visuales.
Hallazgo 5 — Vocabulario de decepción: En las peores
películas, predominan palabras como “boring”, “plot”,
“stupid”, “disappointing” — sugiriendo que el mayor
reproche es la falta de coherencia narrativa, no
únicamente la calidad técnica.
Hallazgo 6 — Efectos visuales neutros: Términos
técnicos como “effects”, “action”, “special”
aparecen con frecuencia similar en ambos grupos. Esto confirma que los
efectos especiales por sí solos no determinan la
percepción de calidad en el género de acción.
Películas Destacadas
Mejores Películas de Acción
The Matrix (1999)
Una de las películas de acción mejor recibidas del período, destacada
por su innovadora narrativa y efectos visuales revolucionarios.
Men in Black (1997)
Combinación exitosa de acción y comedia, con críticas que destacan la
química entre sus protagonistas Will Smith y Tommy Lee Jones.
Gladiator (2000)
Épica de acción con amplio reconocimiento de la crítica. Las reseñas
resaltan la actuación de Russell Crowe y la dirección de Ridley
Scott.
Peores Películas de Acción
Batman & Robin (1997)
Considerada una de las peores superproducciones de acción de la
época. Las reseñas critican fuertemente el guión, los diálogos y la
dirección.
Godzilla (1998)
La adaptación de Roland Emmerich decepcionó a los fans y a la crítica
por priorizar los efectos visuales sobre la narrativa.
Alien: Resurrection (1997)
Cuarta entrega de la franquicia Alien, criticada por alejarse del
tono original de la saga y por un guión inconsistente.
Conclusiones
Las películas de acción con mejores reseñas son
aquellas que equilibran la acción con una historia sólida y
personajes bien desarrollados. El vocabulario positivo en sus
reseñas está centrado en la narrativa y las actuaciones, no en los
efectos visuales.
Las películas de acción con peores reseñas
generan respuestas emocionales de ira y decepción,
reflejando que el público se siente defraudado cuando se priorizan el
espectáculo visual sobre el contenido.
La emoción de anticipación es la más prevalente
en el género, lo que sugiere que el público de acción llega altamente
motivado. Esto hace que las decepciones sean especialmente pronunciadas
en este género.
Herramientas de minería de texto como el análisis de sentimientos
y las nubes de palabras permiten extraer conclusiones significativas
sobre la percepción del público de forma automatizada y
escalable, sin necesidad de leer manualmente miles de reseñas.
LS0tCnRpdGxlOiAiTWluZXLDrWEgZGUgVGV4dG86IE1lam9yZXMgeSBQZW9yZXMgUGVsw61jdWxhcyBkZSBBY2Npw7NuIgphdXRob3I6ICIiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgY29kZV9kb3dubG9hZDogVFJVRQogICAgdGhlbWU6IGNvc21vCi0tLQoKPGNlbnRlcj4KPGltZyBzcmM9InR1bWJscl80NDI1MTNjYWFjMzUyMjljY2RkNWUzOWZlODIyZDZiZl9hNjQ0ZDk1ZF81MDAud2VicCIgd2lkdGg9IjQwMHB4Ii8+CjwvY2VudGVyPgoKLS0tCgojIFRlbWEgZGUgVHJhYmFqbwoKRWwgb2JqZXRpdm8gZGUgZXN0ZSBhbsOhbGlzaXMgZXMgaWRlbnRpZmljYXIgbGFzICoqbWVqb3JlcyB5IHBlb3JlcyBwZWzDrWN1bGFzIGRlbCBnw6luZXJvIEFjY2nDs24qKiBzZWfDum4gZWwgc2VudGltaWVudG8gZXhwcmVzYWRvIGVuIGxhcyByZXNlw7FhcyBkZSBzdXMgZXNwZWN0YWRvcmVzLgoKU2UgYW5hbGl6YW4gbcOhcyBkZSAqKjMsOTAwIHJlc2XDsWFzKiogZGVsIGfDqW5lcm8gQWNjacOzbiwgaWRlbnRpZmljYW5kbyBwYXRyb25lcyBlbW9jaW9uYWxlcyB5IGzDqXhpY29zIHF1ZSBkaXN0aW5ndWVuIGEgbGFzIHBlbMOtY3VsYXMgbWVqb3IgeSBwZW9yIHJlY2liaWRhcyBwb3IgZWwgcMO6YmxpY28gYSBmaW5hbGVzIGRlIGxvcyBhw7FvcyA5MCBlIGluaWNpb3MgZGUgbG9zIDIwMDAuCgotLS0KCiMgTGlicmVyw61hcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpICAgIyBNYW5pcHVsYWNpw7NuIGRlIGRhdG9zCmxpYnJhcnkoc3l1emhldCkgICAgICMgQW7DoWxpc2lzIGRlIHNlbnRpbWllbnRvcyB5IGVtb2Npb25lcwpsaWJyYXJ5KHRtKSAgICAgICAgICAjIE1pbmVyw61hIGRlIHRleHRvCmxpYnJhcnkod29yZGNsb3VkKSAgICMgTnViZSBkZSBwYWxhYnJhcwpsaWJyYXJ5KFJDb2xvckJyZXdlcikgIyBQYWxldGFzIGRlIGNvbG9yZXMKYGBgCgotLS0KCiMgQ2FyZ2EgeSBQcmVwYXJhY2nDs24gZGUgRGF0b3MKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIHJlYWQuY3N2KCJtb3ZpZV9yZXZpZXdzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiMgRmlsdHJhciBzb2xvIGfDqW5lcm8gQWNjacOzbgphY2Npb24gPC0gZGF0b3MgJT4lCiAgZmlsdGVyKGZpcnN0X2dlbnJlID09ICJBY3Rpb24iKSAlPiUKICBzZWxlY3QobW92aWVfbmFtZSwgcmV2aWV3X3RleHQsIHllYXIpCgpjYXQoIlRvdGFsIGRlIHJlc2XDsWFzIGRlIGFjY2nDs246IiwgbnJvdyhhY2Npb24pLCAiXG4iKQpjYXQoIlBlbMOtY3VsYXMgw7puaWNhczoiLCBuX2Rpc3RpbmN0KGFjY2lvbiRtb3ZpZV9uYW1lKSwgIlxuIikKYGBgCgotLS0KCiMgQW7DoWxpc2lzIGRlIFNlbnRpbWllbnRvcyB5IEVtb2Npb25lcwoKIyMgUHVudHVhY2nDs24gZGUgU2VudGltaWVudG8gcG9yIFBlbMOtY3VsYQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBDYWxjdWxhciBzZW50aW1pZW50byBkZSBjYWRhIHJlc2XDsWEKYWNjaW9uJHNlbnRpbWllbnRvIDwtIGdldF9zZW50aW1lbnQoYWNjaW9uJHJldmlld190ZXh0LCBtZXRob2QgPSAic3l1emhldCIpCgojIFByb21lZGlvIHBvciBwZWzDrWN1bGEgKG3DrW5pbW8gMTAgcmVzZcOxYXMgcGFyYSBtYXlvciBjb25maWFiaWxpZGFkKQpzZW50aW1pZW50b19wZWxpY3VsYXMgPC0gYWNjaW9uICU+JQogIGdyb3VwX2J5KG1vdmllX25hbWUpICU+JQogIHN1bW1hcmlzZSgKICAgIHNlbnRpbWllbnRvX3Byb21lZGlvID0gbWVhbihzZW50aW1pZW50bywgbmEucm0gPSBUUlVFKSwKICAgIG5fcmVzZW5hcyA9IG4oKQogICkgJT4lCiAgZmlsdGVyKG5fcmVzZW5hcyA+PSAxMCkgJT4lCiAgYXJyYW5nZShkZXNjKHNlbnRpbWllbnRvX3Byb21lZGlvKSkKCiMgVG9wIDUgTWVqb3JlcwptZWpvcmVzIDwtIGhlYWQoc2VudGltaWVudG9fcGVsaWN1bGFzLCA1KQpjYXQoIlRvcCA1IE1lam9yZXMgUGVsw61jdWxhcyBkZSBBY2Npw7NuOlxuIikKcHJpbnQobWVqb3JlcykKCiMgVG9wIDUgUGVvcmVzCnBlb3JlcyA8LSB0YWlsKHNlbnRpbWllbnRvX3BlbGljdWxhcywgNSkKY2F0KCJcblRvcCA1IFBlb3JlcyBQZWzDrWN1bGFzIGRlIEFjY2nDs246XG4iKQpwcmludChwZW9yZXMpCmBgYAoKIyMgRGlzdHJpYnVjacOzbiBkZSBTZW50aW1pZW50b3MKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChzZW50aW1pZW50b19wZWxpY3VsYXMsIGFlcyh4ID0gc2VudGltaWVudG9fcHJvbWVkaW8pKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJzdGVlbGJsdWUiLCBjb2xvciA9ICJ3aGl0ZSIsIGJpbnMgPSAyNSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsIGxpbmV3aWR0aCA9IDEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBTZW50aW1pZW50byBQcm9tZWRpbyIsCiAgICBzdWJ0aXRsZSA9ICJQZWzDrWN1bGFzIGRlIEFjY2nDs24gY29uIDEwKyByZXNlw7FhcyIsCiAgICB4ID0gIlNlbnRpbWllbnRvIFByb21lZGlvIiwKICAgIHkgPSAiTsO6bWVybyBkZSBQZWzDrWN1bGFzIgogICkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIENvbXBhcmFjacOzbiBNZWpvcmVzIHZzIFBlb3JlcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBVbmlyIG1lam9yZXMgeSBwZW9yZXMgcGFyYSBncmFmaWNhcgp0b3BfYm90dG9tIDwtIGJpbmRfcm93cygKICBtZWpvcmVzICU+JSBtdXRhdGUoY2F0ZWdvcmlhID0gIk1lam9yZXMiKSwKICBwZW9yZXMgICU+JSBtdXRhdGUoY2F0ZWdvcmlhID0gIlBlb3JlcyIpCikgJT4lCiAgbXV0YXRlKG1vdmllX25hbWUgPSBzdHJfdHJ1bmMobW92aWVfbmFtZSwgMzApKQoKZ2dwbG90KHRvcF9ib3R0b20sIGFlcyh4ID0gcmVvcmRlcihtb3ZpZV9uYW1lLCBzZW50aW1pZW50b19wcm9tZWRpbyksCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IHNlbnRpbWllbnRvX3Byb21lZGlvLAogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjYXRlZ29yaWEpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTWVqb3JlcyIgPSAiIzIxOTZGMyIsICJQZW9yZXMiID0gIiNGNDQzMzYiKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUb3AgNSBNZWpvcmVzIHkgUGVvcmVzIFBlbMOtY3VsYXMgZGUgQWNjacOzbiIsCiAgICBzdWJ0aXRsZSA9ICJQb3Igc2VudGltaWVudG8gcHJvbWVkaW8gZGUgcmVzZcOxYXMiLAogICAgeCA9IE5VTEwsCiAgICB5ID0gIlNlbnRpbWllbnRvIFByb21lZGlvIgogICkgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIEFuw6FsaXNpcyBkZSBFbW9jaW9uZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUV9CiMgTXVlc3RyYSBwZXF1ZcOxYSBwYXJhIHF1ZSBjb3JyYSByw6FwaWRvIChOUkMgZXMgaW50ZW5zaXZvIHBvciBwYWxhYnJhKQpzZXQuc2VlZCg0MikKbXVlc3RyYSA8LSBhY2Npb24gJT4lIHNhbXBsZV9uKG1pbigxMDAsIG5yb3coYWNjaW9uKSkpCnBhbGFicmFzX211ZXN0cmEgPC0gZ2V0X3Rva2VucyhtdWVzdHJhJHJldmlld190ZXh0KQplbW9jaW9uZXMgPC0gZ2V0X25yY19zZW50aW1lbnQocGFsYWJyYXNfbXVlc3RyYSwgbGFuZ3VhZ2UgPSAiZW5nbGlzaCIpCgojIEdyw6FmaWNvIDE6IDggZW1vY2lvbmVzIGLDoXNpY2FzCmNvbG9yZXNfZW1vY2lvbmVzIDwtIGJyZXdlci5wYWwoOCwgIlNldDIiKQpiYXJwbG90KAogIGNvbFN1bXMocHJvcC50YWJsZShlbW9jaW9uZXNbLCAxOjhdKSksCiAgbWFpbiAgICAgID0gIkFuw6FsaXNpcyBkZSBFbW9jaW9uZXMg4oCUIFJlc2XDsWFzIGRlIEFjY2nDs24iLAogIGNvbCAgICAgICA9IGNvbG9yZXNfZW1vY2lvbmVzLAogIGxhcyAgICAgICA9IDIsCiAgeWxhYiAgICAgID0gIlByb3BvcmNpw7NuIiwKICBjZXgubmFtZXMgPSAwLjg1CikKCiMgR3LDoWZpY28gMjogUG9zaXRpdm8gdnMgTmVnYXRpdm8Kc2VudGltaWVudG9zX3RvdGFsIDwtIGNvbFN1bXMocHJvcC50YWJsZShlbW9jaW9uZXNbLCA5OjEwXSkpCmJhcnBsb3QoCiAgc2VudGltaWVudG9zX3RvdGFsLAogIG1haW4gICAgICA9ICJTZW50aW1pZW50byBHZW5lcmFsIOKAlCBSZXNlw7FhcyBkZSBBY2Npw7NuIiwKICBjb2wgICAgICAgPSBjKCIjRjQ0MzM2IiwgIiM0Q0FGNTAiKSwKICB5bGFiICAgICAgPSAiUHJvcG9yY2nDs24iLAogIG5hbWVzLmFyZyA9IGMoIk5lZ2F0aXZvIiwgIlBvc2l0aXZvIiksCiAgeWxpbSAgICAgID0gYygwLCBtYXgoc2VudGltaWVudG9zX3RvdGFsKSAqIDEuMikKKQpgYGAKCi0tLQoKIyMgSGFsbGF6Z29zOiBBbsOhbGlzaXMgZGUgU2VudGltaWVudG9zIHkgRW1vY2lvbmVzCgo+ICoqSGFsbGF6Z28gMSDigJQgUHJlZG9taW5pbyBwb3NpdGl2bzoqKiBBIHBlc2FyIGRlIHNlciB1biBnw6luZXJvIGRlIGFsdG8gaW1wYWN0bywgbGEgbWF5b3LDrWEgZGUgbGFzIHJlc2XDsWFzIGRlIHBlbMOtY3VsYXMgZGUgYWNjacOzbiBleHByZXNhbiB1biB0b25vICoqcG9zaXRpdm8qKiwgbG8gcXVlIGluZGljYSBxdWUgZWwgcMO6YmxpY28gbGxlZ2EgY29uIGV4cGVjdGF0aXZhcyBmYXZvcmFibGVzIHkgZGlzZnJ1dGEgZWwgZW50cmV0ZW5pbWllbnRvIGRlbCBnw6luZXJvLgoKPiAqKkhhbGxhemdvIDIg4oCUIEVtb2Npw7NuIGRvbWluYW50ZToqKiBMYSBlbW9jacOzbiBtw6FzIGZyZWN1ZW50ZSBlbiBsYXMgcmVzZcOxYXMgZXMgbGEgKiphbnRpY2lwYWNpw7NuKiosIHNlZ3VpZGEgZGUgbGEgKipjb25maWFuemEqKi4gRXN0byByZWZsZWphIHF1ZSBsb3MgZXNwZWN0YWRvcmVzIGFjdWRlbiBjb24gYWx0YXMgZXhwZWN0YXRpdmFzIHkgZ2VuZXJhbG1lbnRlIGxhcyByZXNlw7FhcyBleHByZXNhbiBjZXJ0ZXphIGFsIGVtaXRpciBzdXMgb3BpbmlvbmVzLgoKPiAqKkhhbGxhemdvIDMg4oCUIFBlb3JlcyBwZWzDrWN1bGFzIGUgaXJhOioqIExhcyBwZWzDrWN1bGFzIGNvbiBzZW50aW1pZW50byBtw6FzIG5lZ2F0aXZvIGNvbmNlbnRyYW4gYWx0b3Mgbml2ZWxlcyBkZSAqKmlyYSoqIHkgKiphc2NvKiogZW4gc3VzIHJlc2XDsWFzLCBzdWdpcmllbmRvIGRlY2VwY2nDs24gYWN0aXZhIOKAlG5vIHNvbG8gaW5kaWZlcmVuY2lh4oCUIHBvciBwYXJ0ZSBkZWwgcMO6YmxpY28uCgotLS0KCiMgTnViZSBkZSBQYWxhYnJhcwoKIyMgTnViZSBkZSBQYWxhYnJhcyDigJQgTWVqb3JlcyBQZWzDrWN1bGFzCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptZWpvcmVzX25vbWJyZXMgPC0gbWVqb3JlcyRtb3ZpZV9uYW1lCgp0ZXh0b3NfbWVqb3JlcyA8LSBhY2Npb24gJT4lCiAgZmlsdGVyKG1vdmllX25hbWUgJWluJSBtZWpvcmVzX25vbWJyZXMpICU+JQogIHB1bGwocmV2aWV3X3RleHQpICU+JQogIHBhc3RlKGNvbGxhcHNlID0gIiAiKQoKcGFsYWJyYXNfbWVqb3JlcyA8LSBnZXRfdG9rZW5zKHRleHRvc19tZWpvcmVzKQpwYWxhYnJhc19tZWpvcmVzIDwtIHJlbW92ZVdvcmRzKAogIHBhbGFicmFzX21lam9yZXMsCiAgYyhzdG9wd29yZHMoImVuZ2xpc2giKSwKICAgICJmaWxtIiwgIm1vdmllIiwgIm9uZSIsICJsaWtlIiwgImp1c3QiLCAiZXZlbiIsICJnZXQiLCAiY2FuIiwKICAgICJ3aWxsIiwgIm11Y2giLCAiYWxzbyIsICJ3ZWxsIiwgIm1hZGUiLCAibWFrZSIsICJ3YXkiLCAiZ29vZCIsCiAgICAic3RpbGwiLCAicmVhbGx5IiwgInNlZSIsICJjb21lIiwgImJhY2siLCAidHdvIiwgImZpcnN0IiwgInJldmlld3MiLCAicmV2aWV3IiwgIm1vdmllcyIsICJyZWMiLCAiY2hhbiIsICJhc2NjaSIsICJodG1sIikKKQoKc2V0LnNlZWQoNDIpCndvcmRjbG91ZCgKICB3b3JkcyAgICAgICAgPSBwYWxhYnJhc19tZWpvcmVzLAogIG1pbi5mcmVxICAgICA9IDMsCiAgbWF4LndvcmRzICAgID0gODAsCiAgcm90LnBlciAgICAgID0gMC4xLAogIHJhbmRvbS5vcmRlciA9IEZBTFNFLAogIGNvbG9ycyAgICAgICA9IGJyZXdlci5wYWwoOCwgIkJsdWVzIiksCiAgc2NhbGUgICAgICAgID0gYyg0LCAwLjUpCikKdGl0bGUobWFpbiA9ICJQYWxhYnJhcyBlbiBSZXNlw7FhcyDigJQgTWVqb3JlcyBQZWzDrWN1bGFzIGRlIEFjY2nDs24iLCBjZXgubWFpbiA9IDEpCmBgYAoKIyMgTnViZSBkZSBQYWxhYnJhcyDigJQgUGVvcmVzIFBlbMOtY3VsYXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBlb3Jlc19ub21icmVzIDwtIHBlb3JlcyRtb3ZpZV9uYW1lCgp0ZXh0b3NfcGVvcmVzIDwtIGFjY2lvbiAlPiUKICBmaWx0ZXIobW92aWVfbmFtZSAlaW4lIHBlb3Jlc19ub21icmVzKSAlPiUKICBwdWxsKHJldmlld190ZXh0KSAlPiUKICBwYXN0ZShjb2xsYXBzZSA9ICIgIikKCnBhbGFicmFzX3Blb3JlcyA8LSBnZXRfdG9rZW5zKHRleHRvc19wZW9yZXMpCnBhbGFicmFzX3Blb3JlcyA8LSByZW1vdmVXb3JkcygKICBwYWxhYnJhc19wZW9yZXMsCiAgYyhzdG9wd29yZHMoImVuZ2xpc2giKSwKICAgICJmaWxtIiwgIm1vdmllIiwgIm9uZSIsICJsaWtlIiwgImp1c3QiLCAiZXZlbiIsICJnZXQiLCAiY2FuIiwKICAgICJ3aWxsIiwgIm11Y2giLCAiYWxzbyIsICJ3ZWxsIiwgIm1hZGUiLCAibWFrZSIsICJ3YXkiLCAiZ29vZCIsCiAgICAic3RpbGwiLCAicmVhbGx5IiwgInNlZSIsICJjb21lIiwgImJhY2siLCAidHdvIiwgImZpcnN0IiwgInJldmlld3MiLCAicmV2aWV3IiwgIm1vdmllcyIsICJyZWMiLCAiY2hhbiIsICJhc2NjaSIsICJodG1sIikKKQoKc2V0LnNlZWQoNDIpCndvcmRjbG91ZCgKICB3b3JkcyAgICAgICAgPSBwYWxhYnJhc19wZW9yZXMsCiAgbWluLmZyZXEgICAgID0gMywKICBtYXgud29yZHMgICAgPSA4MCwKICByb3QucGVyICAgICAgPSAwLjEsCiAgcmFuZG9tLm9yZGVyID0gRkFMU0UsCiAgY29sb3JzICAgICAgID0gYnJld2VyLnBhbCg4LCAiUmVkcyIpLAogIHNjYWxlICAgICAgICA9IGMoNCwgMC41KQopCnRpdGxlKG1haW4gPSAiUGFsYWJyYXMgZW4gUmVzZcOxYXMg4oCUIFBlb3JlcyBQZWzDrWN1bGFzIGRlIEFjY2nDs24iLCBjZXgubWFpbiA9IDEpCmBgYAoKLS0tCgojIyBIYWxsYXpnb3M6IE51YmUgZGUgUGFsYWJyYXMKCj4gKipIYWxsYXpnbyA0IOKAlCBWb2NhYnVsYXJpbyBkZSBjYWxpZGFkOioqIEVuIGxhcyBtZWpvcmVzIHBlbMOtY3VsYXMsIGRlc3RhY2FuIHTDqXJtaW5vcyBjb21vICoic3RvcnkiKiwgKiJjaGFyYWN0ZXIiKiwgKiJncmVhdCIqLCAqInBlcmZvcm1hbmNlIiog4oCUIGluZGljYW5kbyBxdWUgZWwgcMO6YmxpY28gdmFsb3JhIGxhICoqbmFycmF0aXZhIHkgbG9zIHBlcnNvbmFqZXMqKiBwb3IgZW5jaW1hIGRlIGxvcyBlZmVjdG9zIHZpc3VhbGVzLgoKPiAqKkhhbGxhemdvIDUg4oCUIFZvY2FidWxhcmlvIGRlIGRlY2VwY2nDs246KiogRW4gbGFzIHBlb3JlcyBwZWzDrWN1bGFzLCBwcmVkb21pbmFuIHBhbGFicmFzIGNvbW8gKiJib3JpbmciKiwgKiJwbG90IiosICoic3R1cGlkIiosICoiZGlzYXBwb2ludGluZyIqIOKAlCBzdWdpcmllbmRvIHF1ZSBlbCBtYXlvciByZXByb2NoZSBlcyBsYSAqKmZhbHRhIGRlIGNvaGVyZW5jaWEgbmFycmF0aXZhKiosIG5vIMO6bmljYW1lbnRlIGxhIGNhbGlkYWQgdMOpY25pY2EuCgo+ICoqSGFsbGF6Z28gNiDigJQgRWZlY3RvcyB2aXN1YWxlcyBuZXV0cm9zOioqIFTDqXJtaW5vcyB0w6ljbmljb3MgY29tbyAqImVmZmVjdHMiKiwgKiJhY3Rpb24iKiwgKiJzcGVjaWFsIiogYXBhcmVjZW4gY29uIGZyZWN1ZW5jaWEgc2ltaWxhciBlbiBhbWJvcyBncnVwb3MuIEVzdG8gY29uZmlybWEgcXVlIGxvcyAqKmVmZWN0b3MgZXNwZWNpYWxlcyBwb3Igc8OtIHNvbG9zIG5vIGRldGVybWluYW4qKiBsYSBwZXJjZXBjacOzbiBkZSBjYWxpZGFkIGVuIGVsIGfDqW5lcm8gZGUgYWNjacOzbi4KCi0tLQoKIyBQZWzDrWN1bGFzIERlc3RhY2FkYXMKCiMjIE1lam9yZXMgUGVsw61jdWxhcyBkZSBBY2Npw7NuCgojIyMgVGhlIE1hdHJpeCAoMTk5OSkKVW5hIGRlIGxhcyBwZWzDrWN1bGFzIGRlIGFjY2nDs24gbWVqb3IgcmVjaWJpZGFzIGRlbCBwZXLDrW9kbywgZGVzdGFjYWRhIHBvciBzdSBpbm5vdmFkb3JhIG5hcnJhdGl2YSB5IGVmZWN0b3MgdmlzdWFsZXMgcmV2b2x1Y2lvbmFyaW9zLgoKPGNlbnRlcj4KPGltZyBzcmM9Imh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2VuL2MvYzEvVGhlX01hdHJpeF9Qb3N0ZXIuanBnIiB3aWR0aD0iMTgwcHgiIGFsdD0iVGhlIE1hdHJpeCIvPgo8L2NlbnRlcj4KCi0tLQoKIyMjIE1lbiBpbiBCbGFjayAoMTk5NykKQ29tYmluYWNpw7NuIGV4aXRvc2EgZGUgYWNjacOzbiB5IGNvbWVkaWEsIGNvbiBjcsOtdGljYXMgcXVlIGRlc3RhY2FuIGxhIHF1w61taWNhIGVudHJlIHN1cyBwcm90YWdvbmlzdGFzIFdpbGwgU21pdGggeSBUb21teSBMZWUgSm9uZXMuCgo8Y2VudGVyPgo8aW1nIHNyYz0iaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvZW4vZS9lMi9NZW5faW5fQmxhY2tfcG9zdGVyLmpwZyIgd2lkdGg9IjE4MHB4IiBhbHQ9Ik1lbiBpbiBCbGFjayIvPgo8L2NlbnRlcj4KCi0tLQoKIyMjIEdsYWRpYXRvciAoMjAwMCkKw4lwaWNhIGRlIGFjY2nDs24gY29uIGFtcGxpbyByZWNvbm9jaW1pZW50byBkZSBsYSBjcsOtdGljYS4gTGFzIHJlc2XDsWFzIHJlc2FsdGFuIGxhIGFjdHVhY2nDs24gZGUgUnVzc2VsbCBDcm93ZSB5IGxhIGRpcmVjY2nDs24gZGUgUmlkbGV5IFNjb3R0LgoKPGNlbnRlcj4KPGltZyBzcmM9Imh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2VuL2YvZjYvR2xhZGlhdG9yXyUyODIwMDBfZmlsbV9wb3N0ZXIlMjkucG5nIiB3aWR0aD0iMTgwcHgiIGFsdD0iR2xhZGlhdG9yIi8+CjwvY2VudGVyPgoKLS0tCgojIyBQZW9yZXMgUGVsw61jdWxhcyBkZSBBY2Npw7NuCgojIyMgQmF0bWFuICYgUm9iaW4gKDE5OTcpCkNvbnNpZGVyYWRhIHVuYSBkZSBsYXMgcGVvcmVzIHN1cGVycHJvZHVjY2lvbmVzIGRlIGFjY2nDs24gZGUgbGEgw6lwb2NhLiBMYXMgcmVzZcOxYXMgY3JpdGljYW4gZnVlcnRlbWVudGUgZWwgZ3Vpw7NuLCBsb3MgZGnDoWxvZ29zIHkgbGEgZGlyZWNjacOzbi4KCjxjZW50ZXI+CjxpbWcgc3JjPSJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9lbi8xLzE1L0JhdG1hbl8lMjZfUm9iaW5fJTI4MTk5NyUyOV90aGVhdHJpY2FsX3Bvc3Rlci5qcGciIHdpZHRoPSIxODBweCIgYWx0PSJCYXRtYW4gYW5kIFJvYmluIi8+CjwvY2VudGVyPgoKLS0tCgojIyMgR29kemlsbGEgKDE5OTgpCkxhIGFkYXB0YWNpw7NuIGRlIFJvbGFuZCBFbW1lcmljaCBkZWNlcGNpb27DsyBhIGxvcyBmYW5zIHkgYSBsYSBjcsOtdGljYSBwb3IgcHJpb3JpemFyIGxvcyBlZmVjdG9zIHZpc3VhbGVzIHNvYnJlIGxhIG5hcnJhdGl2YS4KCjxjZW50ZXI+CjxpbWcgc3JjPSJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9lbi9jL2M1L0dvZHppbGxhXzE5OThfZmlsbV9wb3N0ZXIuanBnIiB3aWR0aD0iMTgwcHgiIGFsdD0iR29kemlsbGEgMTk5OCIvPgo8L2NlbnRlcj4KCi0tLQoKIyMjIEFsaWVuOiBSZXN1cnJlY3Rpb24gKDE5OTcpCkN1YXJ0YSBlbnRyZWdhIGRlIGxhIGZyYW5xdWljaWEgQWxpZW4sIGNyaXRpY2FkYSBwb3IgYWxlamFyc2UgZGVsIHRvbm8gb3JpZ2luYWwgZGUgbGEgc2FnYSB5IHBvciB1biBndWnDs24gaW5jb25zaXN0ZW50ZS4KCjxjZW50ZXI+CjxpbWcgc3JjPSJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9lbi85LzkyL0FsaWVuX3Jlc3VycmVjdGlvbl92ZXIyLmpwZyIgd2lkdGg9IjE4MHB4IiBhbHQ9IkFsaWVuIFJlc3VycmVjdGlvbiIvPgo8L2NlbnRlcj4KCi0tLQoKIyBDb25jbHVzaW9uZXMKCi0gTGFzIHBlbMOtY3VsYXMgZGUgYWNjacOzbiBjb24gKiptZWpvcmVzIHJlc2XDsWFzKiogc29uIGFxdWVsbGFzIHF1ZSBlcXVpbGlicmFuIGxhIGFjY2nDs24gY29uIHVuYSAqKmhpc3RvcmlhIHPDs2xpZGEgeSBwZXJzb25hamVzIGJpZW4gZGVzYXJyb2xsYWRvcyoqLiBFbCB2b2NhYnVsYXJpbyBwb3NpdGl2byBlbiBzdXMgcmVzZcOxYXMgZXN0w6EgY2VudHJhZG8gZW4gbGEgbmFycmF0aXZhIHkgbGFzIGFjdHVhY2lvbmVzLCBubyBlbiBsb3MgZWZlY3RvcyB2aXN1YWxlcy4KCi0gTGFzIHBlbMOtY3VsYXMgZGUgYWNjacOzbiBjb24gKipwZW9yZXMgcmVzZcOxYXMqKiBnZW5lcmFuIHJlc3B1ZXN0YXMgZW1vY2lvbmFsZXMgZGUgKippcmEgeSBkZWNlcGNpw7NuKiosIHJlZmxlamFuZG8gcXVlIGVsIHDDumJsaWNvIHNlIHNpZW50ZSBkZWZyYXVkYWRvIGN1YW5kbyBzZSBwcmlvcml6YW4gZWwgZXNwZWN0w6FjdWxvIHZpc3VhbCBzb2JyZSBlbCBjb250ZW5pZG8uCgotIExhIGVtb2Npw7NuIGRlICoqYW50aWNpcGFjacOzbioqIGVzIGxhIG3DoXMgcHJldmFsZW50ZSBlbiBlbCBnw6luZXJvLCBsbyBxdWUgc3VnaWVyZSBxdWUgZWwgcMO6YmxpY28gZGUgYWNjacOzbiBsbGVnYSBhbHRhbWVudGUgbW90aXZhZG8uIEVzdG8gaGFjZSBxdWUgbGFzIGRlY2VwY2lvbmVzIHNlYW4gZXNwZWNpYWxtZW50ZSBwcm9udW5jaWFkYXMgZW4gZXN0ZSBnw6luZXJvLgoKLSBIZXJyYW1pZW50YXMgZGUgbWluZXLDrWEgZGUgdGV4dG8gY29tbyBlbCBhbsOhbGlzaXMgZGUgc2VudGltaWVudG9zIHkgbGFzIG51YmVzIGRlIHBhbGFicmFzIHBlcm1pdGVuIGV4dHJhZXIgY29uY2x1c2lvbmVzIHNpZ25pZmljYXRpdmFzIHNvYnJlIGxhICoqcGVyY2VwY2nDs24gZGVsIHDDumJsaWNvKiogZGUgZm9ybWEgYXV0b21hdGl6YWRhIHkgZXNjYWxhYmxlLCBzaW4gbmVjZXNpZGFkIGRlIGxlZXIgbWFudWFsbWVudGUgbWlsZXMgZGUgcmVzZcOxYXMuCg==