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.

The Matrix

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.

Men in Black

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.

Gladiator

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.

Batman and Robin

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.

Godzilla 1998

Alien: Resurrection (1997)

Cuarta entrega de la franquicia Alien, criticada por alejarse del tono original de la saga y por un guión inconsistente.

Alien Resurrection

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==