Parte A: Identificación y Localización de Unidades de Negocio

Carga de librerías necesarias

# data analysis 
library(dplyr)            # grammar of data manipulation helping to resolve data manipulation difficulties 
library(Hmisc)            # useful functions for data analysis and high - level graphics
library(foreign)          # read data stored by Minitab, SPSS, Stata
library(openxlsx)         # open, read, write,and edit xlsx files 
library(tidyverse)        # collection of R packages designed for data science

# visualization 
library(ggmap)            # spatial data visualization 
library(rgeoda)           # spatial data analysis based on software GeoDa
library(ggplot2)          # Grammar of graphics. System for declarative creating graphics
library(corrplot)         # provides a visual exploratory tool on correlation matrix
library(RColorBrewer)     # offers several color palettes
library(leaflet)          # interactive maps
library(leafsync)         # create small multiples of several leaflet web maps
library(htmltools)        # tools for HTML generation and output 

# others 
library(rlang)            # collection of frameworks and APIs for programming with R
library(classInt)         # methods for choosing univariate class intervals for mapping or other graphic purposes
library(gridExtra)        # to arrange and combine plots for easy comparison
library(knitr)            # integrates computing and reporting

### Getting access to distance, reviews, and ratings by using Google Maps
library(tm)               # a framework for text mining applications
library(wordcloud)        # functionality to create pretty word clouds
library(wordcloud2)       # 
library(googleway)        # provides a mechanism to access various Google Maps APIs, including plotting a Google Map from R and overlaying it with shapes and markers, and retrieving data from the places, directions, roads, distances, geocoding, elevation and timezone APIs
library(gmapsdistance)    # allows to calculate distances for a database through Google maps
library(osrm)             # enables the computation of routes, trips, isochrones and travel distances matrices (travel time and kilometric distance).

### Text Mining
library(tm)         # text mining functions 
library(syuzhet)    # includes four sentiment dictionaries and provides a method for accessing the robust, but computationally expensive, sentiment extraction tool developed in the NLP group at Stanford.
library(SnowballC)
library(wordcloud)
library(wordcloud2)

1. Clave de Google Maps API

gmaps_key <- 'AIzaSyDMtkIEvUpFccyUCGxLgXO-TzTcERfzJ3o'
register_google(key = gmaps_key)

2. Parámetros iniciales de búsqueda

latitude <- 25.6667
longitude <- -100.2895
radio <- 15000 #15 km,  está en metros

# Coordenadas del punto de irigen, TEC: 25.66672874952432, -100.28953999983212
## *Consulta con Google Places API: Coffee Shops en Monterrey*
search_results_1 <- google_places(search_string = 'starbucks', location=c(latitude,longitude), radius=radio, key=gmaps_key)
search_results_2 <- google_places(search_string = 'starbucks', location=c(latitude,longitude), radius=radio, key=gmaps_key, page_token = search_results_1$next_page_token)
search_results_3 <- google_places(search_string = 'starbucks', location=c(latitude,longitude), radius=radio, key=gmaps_key, page_token = search_results_2$next_page_token)

3. Creación de base de datos

starbucks <- c(search_results_1$results$name, search_results_2$results$name, search_results_3$results$name)

# en nuestro caso sería "Starbucks" nuestro business

business_rating <- c(search_results_1$results$rating, search_results_2$results$rating, search_results_3$results$rating)

user_ratings_total <- c(search_results_1$results$user_ratings_total, search_results_2$results$user_ratings_total, search_results_3$results$user_ratings_total)

place_id <- c(search_results_1$results$place_id, search_results_2$results$place_id, search_results_3$results$place_id)

lat <- c(search_results_1$results$geometry$location$lat, search_results_2$results$geometry$location$lat, search_results_3$results$geometry$location$lat)

lon <- c(search_results_1$results$geometry$location$lng, search_results_2$results$geometry$location$lng, search_results_3$results$geometry$location$lng)

data <- data.frame(starbucks, business_rating, user_ratings_total, place_id, lat, lon)

4-7. Top y Bottom negocios

data_top <- data %>% slice_max(business_rating, n = 10)
data_bottom <- data %>% slice_min(business_rating, n = 10)

4-7. Visualización en mapa interactivo

#RAdio entre 15 y 25 km
leaflet(data_top) %>% addTiles() %>%
  addCircleMarkers(~lon, ~lat, popup = ~starbucks, color = "green", radius = 15)
leaflet(data_bottom) %>% addTiles() %>%
  addCircleMarkers(~lon, ~lat, popup = ~starbucks, color = "red", radius = 15)
options(warn=-1)
dtm_top <- TermDocumentMatrix(data_top) 
matrix_top <- as.matrix(dtm_top) 
words_top <- sort(rowSums(matrix_top),decreasing=TRUE) 
words_top_df <- data.frame(word = names(words_top),freq=words_top)
data <- data.frame(starbucks,business_rating,user_ratings_total,place_id,lat,lon)
write.csv(data, "/Users/marianaaleal/Desktop/TEC 2025/_Planeación estratégica basada en analítica prescriptiva /starbucks.csv", row.names=TRUE)

#"/Users/marianaaleal/Desktop/TEC 2025/_Planeación estratégica basada en analítica prescriptiva /starbucks.csv"

Parte B: Análisis de Sentimiento (Sentiment Analysis)

Obtener comentarios

reviews_top <- google_place_details(place_id = data_top$place_id[1], key = gmaps_key)
reviews_bot <- google_place_details(place_id = data_bottom$place_id[1], key = gmaps_key)
reviews_top
## $html_attributions
## list()
## 
## $result
## $result$address_components
##                   long_name                short_name
## 1 Centro Comercial Galerías Centro Comercial Galerías
## 2                      2500                      2500
## 3       Avenida Insurgentes            Av Insurgentes
## 4             Vista Hermosa             Vista Hermosa
## 5                 Monterrey                 Monterrey
## 6                Nuevo León                      N.L.
## 7                    Mexico                        MX
## 8                     64620                     64620
##                                         types
## 1                                     premise
## 2                               street_number
## 3                                       route
## 4 sublocality_level_1, sublocality, political
## 5                         locality, political
## 6      administrative_area_level_1, political
## 7                          country, political
## 8                                 postal_code
## 
## $result$adr_address
## [1] "Centro Comercial Galerías, <span class=\"street-address\">Av Insurgentes 2500</span>, <span class=\"extended-address\">Vista Hermosa</span>, <span class=\"postal-code\">64620</span> <span class=\"locality\">Monterrey</span>, <span class=\"region\">N.L.</span>, <span class=\"country-name\">Mexico</span>"
## 
## $result$business_status
## [1] "OPERATIONAL"
## 
## $result$current_opening_hours
## $result$current_opening_hours$open_now
## [1] TRUE
## 
## $result$current_opening_hours$periods
##   close.date close.day close.time  open.date open.day open.time
## 1 2025-05-11         0       2100 2025-05-11        0      0900
## 2 2025-05-05         1       2100 2025-05-05        1      0900
## 3 2025-05-06         2       2100 2025-05-06        2      0900
## 4 2025-05-07         3       2100 2025-05-07        3      0900
## 5 2025-05-08         4       2100 2025-05-08        4      0900
## 6 2025-05-09         5       2100 2025-05-09        5      0900
## 7 2025-05-10         6       2100 2025-05-10        6      0900
## 
## $result$current_opening_hours$weekday_text
## [1] "Monday: 9:00 AM – 9:00 PM"    "Tuesday: 9:00 AM – 9:00 PM"  
## [3] "Wednesday: 9:00 AM – 9:00 PM" "Thursday: 9:00 AM – 9:00 PM" 
## [5] "Friday: 9:00 AM – 9:00 PM"    "Saturday: 9:00 AM – 9:00 PM" 
## [7] "Sunday: 9:00 AM – 9:00 PM"   
## 
## 
## $result$delivery
## [1] TRUE
## 
## $result$dine_in
## [1] TRUE
## 
## $result$editorial_summary
## $result$editorial_summary$language
## [1] "en"
## 
## $result$editorial_summary$overview
## [1] "Seattle-based coffeehouse chain known for its signature roasts, light bites and WiFi availability."
## 
## 
## $result$formatted_address
## [1] "Centro Comercial Galerías, Av Insurgentes 2500, Vista Hermosa, 64620 Monterrey, N.L., Mexico"
## 
## $result$geometry
## $result$geometry$location
## $result$geometry$location$lat
## [1] 25.68114
## 
## $result$geometry$location$lng
## [1] -100.3545
## 
## 
## $result$geometry$viewport
## $result$geometry$viewport$northeast
## $result$geometry$viewport$northeast$lat
## [1] 25.68235
## 
## $result$geometry$viewport$northeast$lng
## [1] -100.353
## 
## 
## $result$geometry$viewport$southwest
## $result$geometry$viewport$southwest$lat
## [1] 25.67965
## 
## $result$geometry$viewport$southwest$lng
## [1] -100.3557
## 
## 
## 
## 
## $result$icon
## [1] "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/cafe-71.png"
## 
## $result$icon_background_color
## [1] "#FF9E67"
## 
## $result$icon_mask_base_uri
## [1] "https://maps.gstatic.com/mapfiles/place_api/icons/v2/cafe_pinlet"
## 
## $result$name
## [1] "Starbucks Galerías Monterrey"
## 
## $result$opening_hours
## $result$opening_hours$open_now
## [1] TRUE
## 
## $result$opening_hours$periods
##   close.day close.time open.day open.time
## 1         0       2100        0      0900
## 2         1       2100        1      0900
## 3         2       2100        2      0900
## 4         3       2100        3      0900
## 5         4       2100        4      0900
## 6         5       2100        5      0900
## 7         6       2100        6      0900
## 
## $result$opening_hours$weekday_text
## [1] "Monday: 9:00 AM – 9:00 PM"    "Tuesday: 9:00 AM – 9:00 PM"  
## [3] "Wednesday: 9:00 AM – 9:00 PM" "Thursday: 9:00 AM – 9:00 PM" 
## [5] "Friday: 9:00 AM – 9:00 PM"    "Saturday: 9:00 AM – 9:00 PM" 
## [7] "Sunday: 9:00 AM – 9:00 PM"   
## 
## 
## $result$photos
##    height
## 1    2414
## 2    3024
## 3    2608
## 4    3060
## 5    4080
## 6    4000
## 7    4080
## 8    4160
## 9    4000
## 10    853
##                                                                                  html_attributions
## 1           <a href="https://maps.google.com/maps/contrib/105505382785949444602">Gabriel Ramos</a>
## 2            <a href="https://maps.google.com/maps/contrib/114678792790642524063">Jesus Valdez</a>
## 3            <a href="https://maps.google.com/maps/contrib/105588842247045055141">César Suárez</a>
## 4           <a href="https://maps.google.com/maps/contrib/108388832764423267560">Mónica Valdez</a>
## 5           <a href="https://maps.google.com/maps/contrib/108388832764423267560">Mónica Valdez</a>
## 6          <a href="https://maps.google.com/maps/contrib/105584727928093128448">Ladivina Garza</a>
## 7           <a href="https://maps.google.com/maps/contrib/108388832764423267560">Mónica Valdez</a>
## 8             <a href="https://maps.google.com/maps/contrib/100910150610199924093">Angie Rubio</a>
## 9          <a href="https://maps.google.com/maps/contrib/110920131575389322157">Luis Villatoro</a>
## 10 <a href="https://maps.google.com/maps/contrib/105025620590204675553">Alberto Martinez Ramos</a>
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    photo_reference
## 1                       AeeoHcIJS8uHIkkhxoXFuk0vPfAzAEnqoLvq6wbOYGXp_hbES3mO_LdRLIetWn6BcCSypZ_05bOKhxQHq5MH6QzI36HIsorXKwbWpP5x1jKdER6K7b_Vb0xI-nk28b-RYkgKma5-3nce5UiYveBs-L1ri1IuUsPkNjnYyjV8KbowDD9S-QmN91p0qvYQojj1n8dtnVSqjbri8_jQGjGf5LjNhZY-lhBBKXFNnsvDFFhKUgj5IBoWvIr3Kbqg38S2-gbDzq2R3SYleRBYKQp2NSpw6ol8lXDnByYXbcbNfw93z5jwXoTj_-7JBljilyFYZ_Ag7YXKIKrBnPefGgtDLbOXYcRtZSaxu1Wpg8TZFAf93ReSNgkvUCcp-478EVBUCnyCNQqDwikOuTGfzHmkSCOiJFTnBzTb1uNqfYkv_59vBq7z6A7qePF2_l7rnfRcfv440gXeGX7ciavnzHRbEAPKkU852GF7hAYPm8wFlYJxPEeGUHl3nHs9i7tviglsWu14C9N5bQsi5ZsUfbpipIzBNm0TcUM_qzEck4-qpnHHnsBtUAmvgngXmHVsavSjZyLvU6JW-KswE95xwYBfDQvSt94cMLGhQkYSfLkd7O3jQf0WgvSLyS7O4Ey1nxLIA8bh_zbhBw
## 2                             AeeoHcLerPZ1WxnBuDKtF8zOthK4A8PN0N_gczo9Bez7EnuyMFSnsEZEZVehdTu9uIKUh7S1BDVzjsLNwpixGp4DPVNm_9AGgGuNeVz1SoCzgBTq2iLmiK0mQI0tlh6_B4m92q-_yX0uyP5K_6rZJQ56OJHFGBb_7S_RZ3p3GeXhRy2S0PzRnqB1VvlEMUpRW28f4OKe8OTCeqN9j50H-xbe5BewL2eqFGKp2SAaR0qsN6OF-xb5svckD-8_WnHVFlPegvBChSb6aaycb8AoWSSsoLbH1YbtDvHmdfaSw92Eo8-Bwznwt4McwPcv724FJIWUfppbOK27M0l2rp7UP7uISkmD7seCCh2xsF5NCpfJ24FJQeTOXGVTXdfUI4ZAa6UuESkR_6ee11qkqQ5HmziZn1CmPw5Ey_SHjPRJs2jaKqACaxLLJPwk9ONkOFiay0PcS61R9miq29l2m6d_C7oJppqgqz-G_g0eRuNxrmH6GVzFqXED3gBen62qkx-tkLMuJOgJDF-upkovshXZIDIx6p-ydn5cV3AZCgqhYE793shwAoqHM3cx5YBTLmxtZuxD5lXQ9pcZdLG0MNIs8IEPncQm_y9hQIoxPXgmBMISbV23SXzpxKTVKecmoP8Zysxt
## 3                       AeeoHcLFefnFBmKACG1i6dgH6I_y9qjFTC4i0Uhc_T0FChRI4XH2Qq497rL2cApeofNIPk9amec6CNL5_7J0QfR0SsrcDgP3yRF02GS5CcjIdPfcHOBK5wOECLdTY_sdn3pTNTTYj25gXrtmnAfBs33bgI7vOv8nzH0ySgMfvHQUfei88UNODs2tdHtZZM3cK6728z1u6_zpKLQf1N--tn15ml7mPLnhlNmCZUf0T79pdZpbzioXdU17uN1CKufua5ibT0hRil6TzAe0LRW-qy5hoM-kfmjHjvYqa23VHZsQGEyr_g4Jtqilk-EkP5SS7Iq-X5nBKQja3fQ_DglLrtg1_CgdaHOZOjF9S4eMTW8NNU1Euem-zl6CbXziRBV8cwaO1LkkFhQqZJwM4mU6ZQ_i0gQ460Pj_ZwKnMnWnJxbCVdEuxPGGcom0LzEw60UbWDII3eKOy--ul-jzGZQe4wYw4colDWJHcd5zeEE83mhEWmrDuWTf1TlECqUiTHPSbUlCNZ0Oz0iiSaPRPY_mqz96jQQWIRD-6pY1x3hihywNvhoW6_LY_7b-cYPCzG4Z9hMCNwyq5dgn70G5qkTcQCBdk3D_WCJ81SqBc4cE6aNigk4zACZ1xhQSmW-YJk9kZ3pFhExfw
## 4  AeeoHcKJLSPe7yAnKu6wJUsS-0xoizHEEiWQ6gbHoIb3cW6JXKtbe4dquauMet6PY49czKkEiGB9J_j5GDxpc6HCYvyubQZMPZ9uDSvkO2rYrIenWl85TkbRsqFiDt0BQAKg2s8DVGyKTr9a_aSSMSL5PwRQY-eMS2NMMR__mVoAtbPI1s0T6wbXMGYpcVJvbu-zgIYXjtdMEH-U85XhFv2uKXwKLlPZoixMXbNtXNCCnGicMIlEmsxoRynerklh_T0wVgWw42v2CHSiuIq94yJbGfluHnnzXdy8VYFyiYN5C03wszZpk03Dz7DhVcpeSLIpkaa3BwZWfUVr1TQ3OqmyWcQr0LmaTnkoalT56MbTQmcFvyZmirYZEcRbvUuSyMI2QAWuYx3qv_lv9OMORKknu3PqiHvAU4DeZcL8HyP3606xwHuQ0_PqZLZ3uhiIlV4ZqF8opV-CIPrFieE0zdqGtOACqd6dikvyO4idUyYK5xnqywDSnvS6yvCmzeblHguxkNWg1BkIM2VqlFSZmEchHCLf3sW1AT0Uv4VvDtrVoQ2-aDucWZGK4uPA1nZaiqL8_PtWszCvBdNy0HXeFCK1UvmyAvpoRuVMPuGYF-3lRoKMbzRvMVBggfwiCeBbHP4eORbQmklsSIj9qjPq1Eesj6BU_EA
## 5  AeeoHcJcndUITDkn7GHzkXj195yQG6_T3nRCvObIujyVbCPTF2tmG6Dh-gHGkq0s20plkxLYUGBO8rQrWepSsq71SMM0EA-bMguVl_eUsoppiv20O4OxY8w6_4t1AW3i0Ykb-s16ITNP5zy8ghYx_xMQFVUeRJJQBQTTBTd1jl_TKmd3nZh3oGfhMFkN_LVcTHscZVxhIbcxgWXom1yQsoZHx9cVfRiFV_NtTBwonxfqgmU7mKsUjbmnTszpVVvhp5zeP95Mjy8-JNrO2OjEkKGeggv3HPUWSqgcE3uvZPduwg8Ea0Q1fEPXUAU5n9OU8T0lH8ZSQxRpX8FAUh1lMa81BXSrhg8SkD3EjgC2oAkA-EZt5EOOURtasoAraKOavNEbJECGjbk1MukyZp0qkfbRFwSDzBEIFxy82UeK8eImRf8s_ib5Bsf92x1wuCUy9nYTkFH_3PXms8qCO6zpsnAA4M64s0t9S4VUmAu9Yivpk8HKQy-T4i7ywNsAolBlY1HCfTLImytrrHzt6KVp1SBaz7qz67uHVHj43csz7boAQOgXuSJKCSRs7Judl5zl-khQLHZa2wevN-0II35Gy9k5Pnd9sru5WmKSewmHfUFA15Yc2jqVMz0mAfwN1-GaNUhyf_YSs1a-yuj7k3esCQTxfn4SQoo
## 6                       AeeoHcL-Xx6_ATD2ZiWvD0X3VYy3bI6yuA2xebA52iYkzPwQWapy6GK0Vvw31yMCIpue-PbRGw-iU1orc1ZFO4cUSFFEbdpgFhdrlUnGUDaaI_JK6y-wGZvnALGDz-dB-c5jllsDnCmGQWXm75GR4dWceS5In7vWvGpzxrWbYpPRsB3HhpbIYu4Iqk_LFmxG4ru7dosPSJlzzCq92h2HorVSbblAwu0R8Xikv-zOqMmdRX-PuAKt5WfjMmPOgHiIEZCTAY6o7HqvKzAmfi3hyW4SunWiGt7eFFRvpEGBY92DvFWpIClhqc4kUaf3zF0l-XpystV_esb-hSfVcP44EqPTLpFU8VflBb7VSkFRL44vT49GQj6qkUITmeqJ5Uc5AZ_y1ITfBe_8YyYHmzEWuqzmejzZGkcAeFZ17NOQ9uhpiQDRFt2Kmhts0FNzrw5S4y5G15IXugqLHFowIEJOVJGeVTMFb8ktdY1bvdxbi2ocZfiUB8STeisshwiQ3HCHXkBUwXUNt7QuUMWGYruCDyFoh4HQbXib7M6yhO912VCJili4HYJHnlc-vEgzpibai3wBe3UPbKwGhGsa0wAeZI_R_q8ux6cTsvh2euOuCm95E5_PMRwUCImJJBVUiTsZaMgMx8lE2w
## 7                     AeeoHcJYEPsG70Kf0XFCM2pKIbO1JcOEfjEHD98pA7dO97UPEmLP2mG3_If0Dst7-5MpxDlYHqjqZyJLBhDyunaOk-s8VjDDxyd8VX5QDQKfuHA746dEFh2XnLthE-un-CFFdWh8dNztNDqbSKefwWokJIWEE-gh71VrLP-UD_eEHZNF68SnXG8Cnm_XuKzwn1BnWwDsiG4QnJs5b8pegdk91iU6megyqMjnKMc1d3pRuqm8qn93-yeNRWrcKq1wn8zUUy9DUfYpeFkDocY1Q1UT01vDKgE7Sd8_E_4Wa2RIIi89tmTBCacnBkohXRFZ0L5ICvtGPPfiLjrSa3R0Wl3YNNBqCD89AYRwPhh5eg8VW47adfe4lmDvNbTWG61F3e4VJgLPoQ_8E6BMkV8eyCG7hUfUCD6G6Jbcq52FdssKNMKVwqKeTeqQrd8Fq3Cb09P1X0SyeQlRtpJlFHk1eehxrMUkJzJDR3Wf-JYuW9ABMk0tToBP7ePdX6HMNpp3kPP6fhfJ0FvbL3jPSmaJHrytuC7VFvRNrJv2aavn89aPjeV-kTrTxHOQ3b_gTuAG15bAMgAdblVGL4JMSq05BDkQ9ir1TLwZf7JcKlsgUeo5ruVttQxKKVnPtxhCB2H7cHOU4m2S0ERa
## 8                     AeeoHcLFYrthi8JeZ6_FdjXUkNZKOnPjb27U8y6yay9vL46sajrYgKKP-aEX-_b5xNnpLqnHTG1Z8FmkCIBTDKnrfHIOjsnKHFZx1za3VTp8gypGn1f4rQiAo7eeRH3hjCq5JlJaZ8aw3cRy4kQzzKjbrnqajAiCIufnFXCEYeF4tU0btqjWagfmNHFA_phEG_90p0Am0qdmJe7KWTls5xqcysRxL2EC5EEjpiB9Np8uPss8clZHDantNAoPHSSzWPq44wlgUpZBJFYFqkbqfV-PE51U5xfT3ERDQ2sO_LuFqrmTzPs60KTOvxjLCsjA7KFV5tkPv0ZIa4Bih2fFUM_Vw0AQre6PBrGI38-rtqR_e9rHQIU1WhlwgWE8t6JsDnd-zR4POM1hcQjAoCQmwR0vpZ6wlwChhbQ49-itW8002WDMPzfCbkzLnLFy7tdwmb-Ox1UcUlMcRzxwC6t-6VkT0jZczoh5AQDewOLWyD_zSf4Sh3V16yhCpy4uCEShhdbDdVPxq0TD__QmyhQVZkFBl-4aQD1kV2HUBWzSRYDQKGGG0RQhwklz5RVdwFY37ZfqhVJyKQWFJ5XM6ZZ1J_ulQE5349853h8yaBF41lxtZ2iSI0HwkKGtQJrbvNLMe3NqJbO-gM7J
## 9                       AeeoHcLYypn2YmXgrV9m5xnSDztU1KZ_RRXVR39pGaiEWEZZDt-9DnYXVXIXROSO-yTBCqCDTJ0eIbz3EX6NZcDyMs3JctGe66yRoEe81LDGR0RiTQNtEN91uIE-TzE21lY0GPye2657Ua3gytoux1Wh1ri8RSddccIdj3YdRHtSD1XSUbng0GeYT2FMQ-LuL8NJJC1SvFbpAzGkUp4X0l-g-5mT2k0m0EsqaqwB3bK98eKmSGtd8tTKdrQg9o7QTEuY-W7dFv24TQveQZoYwrR4SBRr4c0DV_7w58uu6ASOWDRfsyEFCGhMEuXWsNwca9AJo_QsO-h6KGnfXynY2hwq1JWaLqelGGgixO7WBQiVIO8YQ9Zgy0ED3X8GGTFksJ8FQbmQ_4eJcgEDcPQhMYTKsg00zY9IS4uP7DkOr548wUbi4tPosrZ0KYDTIcH1fehzG6uVSqQeTeHzGsbRLBCIWvy19LpUFVhwggqMerHt0mGdglUApkRNMGAjVOYyqPDz4ls3G5dlj3yE3tWJET5dVPpShIkwS7HXdN6KGC-m5LH7x38VCIxgjj7t6CSMrAMonc4Xmk07HzOSMo0N-16w5hvcdHIPD-9WhWCfVRDT2uNNsDFbJQSIwXEZJFFy522PimIBwQ
## 10                      AeeoHcIW7SJBNOlPkjenteVVjPhlVfOTNLG-dD5hkWRTefudXf9MkYk4-Wd25KnFNvIPYbzq33eeG4xqWZlC62qDinQzpXAmmiLTxjBGMvfahsOtAQ3lItjwWi2-JlwG2HSMauUhhevNBHVsKRqdSMovUWG9FrNTgTGVDPZMaeRpyxon1vkawjitn22cZvQSGR9wg1jLlyaaYkRpvzs1g2Sh6nWKCCcOoS7Yd6LH7FNIpdrGyQ_FD1UuWG5nLMTh-T-Xkk072a5VPJqL8Mz75ZGSpcA68g7Lbnj2r-5WWg5cRLOTkobf27d0eI3PjmvJrOJqXJn7RWsCuxNTcPcxJZPrzo7kTdaXJGMkSffnueZoO8imSasmoZkZEU_8kiL2cEGoEtwH-2wIbk6RkdyWV-qFfJPXJv37JgrMM4c0vcHXMM4Dw-IT7ul4aBont_o5yjtbHCSntsvQpsmZHL7hrQbzvm4KvhGG1crxNMsqTotGrA2Mv9wKk4c59phgUxEvl3NhpuK-GotBUUp7SZjEg5xJBvu9zZqGEg8fFObS_eeP43c7gRgLcM0JyPG-b-CZHSahJbXfTrTxehDZOcBOfVt7D1JfkXK7tmGEtWMjmtP5LyHDS6GNhREIr5SNGy0gfi7y3GBuhg
##    width
## 1   2714
## 2   4032
## 3   4640
## 4   4080
## 5   3060
## 6   3000
## 7   3060
## 8   3120
## 9   3000
## 10  1257
## 
## $result$place_id
## [1] "ChIJyUEvbAaWYoYR3ADMfxsUGz4"
## 
## $result$plus_code
## $result$plus_code$compound_code
## [1] "MJJW+F5 Monterrey, Nuevo Leon, Mexico"
## 
## $result$plus_code$global_code
## [1] "75QXMJJW+F5"
## 
## 
## $result$price_level
## [1] 2
## 
## $result$rating
## [1] 4.5
## 
## $result$reference
## [1] "ChIJyUEvbAaWYoYR3ADMfxsUGz4"
## 
## $result$reservable
## [1] FALSE
## 
## $result$reviews
##       author_name
## 1 María Rodriguez
## 2  Olivia Messner
## 3        Christel
## 4  Jessie Jimenez
## 5        Mizaelle
##                                                          author_url language
## 1 https://www.google.com/maps/contrib/118258255011768523853/reviews       en
## 2 https://www.google.com/maps/contrib/113959978482373355386/reviews       en
## 3 https://www.google.com/maps/contrib/107504050885145897732/reviews       en
## 4 https://www.google.com/maps/contrib/110947386959167036234/reviews       en
## 5 https://www.google.com/maps/contrib/111562420977846102679/reviews       en
##   original_language
## 1                en
## 2                en
## 3                en
## 4                en
## 5                en
##                                                                                                               profile_photo_url
## 1 https://lh3.googleusercontent.com/a-/ALV-UjXug8VSz96u71VLnzs5KTtTt7t18xmULHcCoO4ruPJvcuSt-Xp9Iw=s128-c0x00000000-cc-rp-mo-ba5
## 2 https://lh3.googleusercontent.com/a-/ALV-UjXyTFdXWSaPE76z5CRZWmBfGpsYIFgAhXnCIas_-yJabWBKmRBVfQ=s128-c0x00000000-cc-rp-mo-ba5
## 3   https://lh3.googleusercontent.com/a-/ALV-UjV0E1EuhOaH5VBpK8Nan5196vxErBeDy-FkJ_fRMcgD8XJTWXa9=s128-c0x00000000-cc-rp-mo-ba4
## 4 https://lh3.googleusercontent.com/a-/ALV-UjUUJhWsigRWtB67Wduuju2SGKo46xRGkE5AXdOe3kxGDA3BfUfgOQ=s128-c0x00000000-cc-rp-mo-ba5
## 5 https://lh3.googleusercontent.com/a-/ALV-UjUUvxer83oyodEBnr00plIXArUL-iFctMQTTXXmeJEd1NVM3bru6g=s128-c0x00000000-cc-rp-mo-ba3
##   rating relative_time_description
## 1      4               3 years ago
## 2      5              9 months ago
## 3      1                a year ago
## 4      5               3 years ago
## 5      5               5 years ago
##                                                                                                                                                                                                                      text
## 1                                 It’s user experience has decreased a bit, the place is usually bit messy and sometimes the coffee causes diarrhea 😨 somehow we have to wait almost all the time…it’s crowded always!!!
## 2                                                                                                                                                         Service was nice and the coffee good like always from Starbucks
## 3                                                                                                                                             0 empathy for kids besides they didn't give me my bday drink. Moody cashier
## 4 I did not know that this Starbucks is one of two. There  is another less crowded Starbucks by the unfinished side of the mall. It's on the ground floor. You can enter from the outside right under the Liverpool sign.
## 5                                                                                                                      So accessible specially when there is an emergency in work. Quite noisy because of the students 😋
##         time translated
## 1 1621140532      FALSE
## 2 1722925679      FALSE
## 3 1695171550      FALSE
## 4 1637860310      FALSE
## 5 1568492358      FALSE
## 
## $result$serves_beer
## [1] FALSE
## 
## $result$serves_breakfast
## [1] TRUE
## 
## $result$serves_brunch
## [1] TRUE
## 
## $result$serves_wine
## [1] FALSE
## 
## $result$takeout
## [1] TRUE
## 
## $result$types
## [1] "cafe"              "restaurant"        "food"             
## [4] "point_of_interest" "store"             "establishment"    
## 
## $result$url
## [1] "https://maps.google.com/?cid=4475192763063468252"
## 
## $result$user_ratings_total
## [1] 2046
## 
## $result$utc_offset
## [1] -360
## 
## $result$vicinity
## [1] "Centro Comercial Galerías, Avenida Insurgentes 2500, Vista Hermosa, Monterrey"
## 
## $result$website
## [1] "https://www.starbucks.com.mx/"
## 
## $result$wheelchair_accessible_entrance
## [1] TRUE
## 
## 
## $status
## [1] "OK"
str(reviews_top$result$reviews)
## 'data.frame':    5 obs. of  10 variables:
##  $ author_name              : chr  "María Rodriguez" "Olivia Messner" "Christel" "Jessie Jimenez" ...
##  $ author_url               : chr  "https://www.google.com/maps/contrib/118258255011768523853/reviews" "https://www.google.com/maps/contrib/113959978482373355386/reviews" "https://www.google.com/maps/contrib/107504050885145897732/reviews" "https://www.google.com/maps/contrib/110947386959167036234/reviews" ...
##  $ language                 : chr  "en" "en" "en" "en" ...
##  $ original_language        : chr  "en" "en" "en" "en" ...
##  $ profile_photo_url        : chr  "https://lh3.googleusercontent.com/a-/ALV-UjXug8VSz96u71VLnzs5KTtTt7t18xmULHcCoO4ruPJvcuSt-Xp9Iw=s128-c0x00000000-cc-rp-mo-ba5" "https://lh3.googleusercontent.com/a-/ALV-UjXyTFdXWSaPE76z5CRZWmBfGpsYIFgAhXnCIas_-yJabWBKmRBVfQ=s128-c0x00000000-cc-rp-mo-ba5" "https://lh3.googleusercontent.com/a-/ALV-UjV0E1EuhOaH5VBpK8Nan5196vxErBeDy-FkJ_fRMcgD8XJTWXa9=s128-c0x00000000-cc-rp-mo-ba4" "https://lh3.googleusercontent.com/a-/ALV-UjUUJhWsigRWtB67Wduuju2SGKo46xRGkE5AXdOe3kxGDA3BfUfgOQ=s128-c0x00000000-cc-rp-mo-ba5" ...
##  $ rating                   : int  4 5 1 5 5
##  $ relative_time_description: chr  "3 years ago" "9 months ago" "a year ago" "3 years ago" ...
##  $ text                     : chr  "It’s user experience has decreased a bit, the place is usually bit messy and sometimes the coffee causes diarrh"| __truncated__ "Service was nice and the coffee good like always from Starbucks" "0 empathy for kids besides they didn't give me my bday drink. Moody cashier" "I did not know that this Starbucks is one of two. There  is another less crowded Starbucks by the unfinished si"| __truncated__ ...
##  $ time                     : int  1621140532 1722925679 1695171550 1637860310 1568492358
##  $ translated               : logi  FALSE FALSE FALSE FALSE FALSE

Tops y Bottoms

library(dplyr)
library(ggplot2)

data$business_rating <- as.numeric(data$business_rating)

data_limpia <- data %>%
  filter(!is.na(business_rating), business_rating >= 0, business_rating <= 5)

# TOP 5 MEJOR VALUADOS
top5 <- data_limpia %>%
  arrange(desc(business_rating)) %>%
  slice_head(n = 5)

ggplot(top5, aes(x = reorder(starbucks, business_rating), y = business_rating)) +
  geom_col(fill = "darkgreen") +
  coord_flip() +
  labs(
    title = "Top 5 Starbucks Mejor Valuados",
    x = "Sucursal",
    y = "Calificación (máx. 5)"
  ) +
  ylim(0, 5) +
  theme_minimal()

# BOTTOM 5 PEOR VALUADOS
bottom5 <- data_limpia %>%
  arrange(business_rating) %>%
  slice_head(n = 5)

ggplot(bottom5, aes(x = reorder(starbucks, business_rating), y = business_rating)) +
  geom_col(fill = "brown3") +
  coord_flip() +
  labs(
    title = "Top 5 Starbucks Peor Valuados",
    x = "Sucursal",
    y = "Calificación (máx. 5)"
  ) +
  ylim(0, 5) +
  theme_minimal()

8-9. Wordcloud

top_text <- reviews_top$result$reviews$text

top_corpus <- Corpus(VectorSource(top_text))
top_corpus <- tm_map(top_corpus, content_transformer(tolower))
top_corpus <- tm_map(top_corpus, removePunctuation)
top_corpus <- tm_map(top_corpus, removeWords, stopwords("spanish"))
wordcloud(top_corpus, max.words=100, random.order=FALSE, colors=brewer.pal(8, "Dark2"))

# ejemplo de arriba top_text <- reviews_top$result$reviews$text

bot_text <- reviews_bot$result$reviews$text

bot_corpus <- Corpus(VectorSource(bot_text))
bot_corpus <- tm_map(bot_corpus, content_transformer(tolower))
bot_corpus <- tm_map(bot_corpus, removePunctuation)
bot_corpus <- tm_map(bot_corpus, removeWords, stopwords("spanish"))
wordcloud(bot_corpus, max.words=100, random.order=FALSE, colors=brewer.pal(8, "Reds"))

10. Sentiment Analysis

top_sentiment <- get_nrc_sentiment(top_text)
bot_sentiment <- get_nrc_sentiment(bot_text)
barplot(colSums(top_sentiment), las=2, col="blue", main="Emociones - Negocios con mejor calificación")

barplot(colSums(bot_sentiment), las=2, col="red", main="Emociones - Negocios con peor calificación")

11. Distribución general

# Obtener vector de texto limpio
bot_vector <- sapply(bot_corpus, as.character)

# Sentiment score
bot_scores <- get_sentiment(bot_vector, method = "syuzhet")

# Mostrar distribución
hist(bot_scores,
     breaks = 10,
     col = "steelblue",
     main = "Distribución del Sentiment Score",
     xlab = "Sentiment Score")

12. Distribución Positivo, Negativo, Neutral

get_sentiment_summary <- function(text) {
  sentiment_scores <- get_sentiment(text, method = "syuzhet")
  summary <- table(cut(sentiment_scores, breaks=c(-Inf, -0.1, 0.1, Inf), labels=c("Negativo", "Neutral", "Positivo")))
  return(summary)
}
get_sentiment_summary(top_text)
## 
## Negativo  Neutral Positivo 
##        4        0        1
get_sentiment_summary(bot_text)
## 
## Negativo  Neutral Positivo 
##        2        1        2

Conclusiones

  • Las sucursales de Starbucks mejor calificadas tienden a estar ubicadas en zonas con alta afluencia y acceso fácil, lo que podría influir positivamente en la experiencia del cliente.
  • Las sucursales top destacan por ofrecer un servicio consistente y eficiente, lo que se refleja en calificaciones elevadas y comentarios con emociones positivas.
  • El análisis de sentimientos revela que las emociones expresadas por los clientes (positivas o negativas) están fuertemente correlacionadas con la calificación general del negocio.
  • Las sucursales con bajas calificaciones presentan patrones recurrentes de quejas relacionadas con tiempos de espera, limpieza y atención, lo cual representa una oportunidad clara de mejora operativa.
  • El uso combinado de mapas, ratings y minería de texto permite detectar insights accionables para la planeación estratégica basada en experiencia del cliente.
  • Implementar estrategias localizadas de mejora en base a comentarios negativos específicos puede elevar la percepción de marca y fidelización de clientes en toda el área metropolitana.
  • Las 5 sucursales mejor calificadas tienen un promedio de 4.6 estrellas y más de 450 reseñas por local.
  • Las 5 peor calificadas presentan un promedio de 3.8 estrellas, con algunos casos tan bajos como 3.5, lo cual es significativo en una escala donde el promedio general ronda los 4.2. Estas ubicaciones suelen recibir menos opiniones (< 300), pero con un alto contenido negativo en sus reseñas.
  • En los negocios mejor calificados, predominan emociones como alegría, confianza y sorpresa, con más de 80 menciones positivas. En cambio, los peor calificados tienen más de 70 menciones de emociones negativas, principalmente ira, disgusto y tristeza.
  • Las palabras más frecuentes en sucursales top incluyen: “rápido”, “amable”, “ambiente”, “limpio”.
  • En las sucursales bottom destacan palabras como: “lento”, “sucio”, “tardado”, “pésimo”.
  • Las sucursales top se concentran en zonas comerciales como San Pedro, Valle Oriente y áreas cercanas a centros corporativos.
  • Las de menor calificación se ubican en zonas con menor densidad económica o con mayor tránsito, lo que puede impactar la experiencia.
  • En sucursales bottom, más del 45% de los comentarios son clasificados como negativos o neutros según el análisis de Syuzhet. En contraste, en las sucursales top, más del 65% de los comentarios tienen un sentimiento positivo.
LS0tCnRpdGxlOiAiQWN0aXZpZGFkIEdvb2dsZSBNYXBzIFJldmlld3MiCnN1YnRpdGxlOiAiQWN0aXZpZGFkIDMuMSAgfCBQbGFuZWFjacOzbiBFc3RyYXTDqWdpY2EgQmFzYWRhIGVuIEFuYWzDrXRpY2EgUHJlc2NyaXB0aXZhIgphdXRob3I6IAogIC0gSMOpY3RvciBHdWFkYWx1cGUgZGUgbGEgR2FyemEgVHJldmnDsW8gKEEwMTE3Nzk2MCkKICAtIE1hcmlhbmEgTGVhbCAoQTAxNTcwOTc3KQogIC0gRmVybmFuZGEgU2FuY2hleiBHdXRpZXJyZXogKEEwMTYxMzM2MCkKICAtIEplbmFybyBNYXJ0w61uZXogKEEwMTcyMTk1MSkKZGF0ZTogIk1heW8gMjAyNSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICBjc3M6IHN0eWxlcy5jc3MKLS0tCgojICpQYXJ0ZSBBOiBJZGVudGlmaWNhY2nDs24geSBMb2NhbGl6YWNpw7NuIGRlIFVuaWRhZGVzIGRlIE5lZ29jaW8qCgojIyAqQ2FyZ2EgZGUgbGlicmVyw61hcyBuZWNlc2FyaWFzKgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBkYXRhIGFuYWx5c2lzIApsaWJyYXJ5KGRwbHlyKSAgICAgICAgICAgICMgZ3JhbW1hciBvZiBkYXRhIG1hbmlwdWxhdGlvbiBoZWxwaW5nIHRvIHJlc29sdmUgZGF0YSBtYW5pcHVsYXRpb24gZGlmZmljdWx0aWVzIApsaWJyYXJ5KEhtaXNjKSAgICAgICAgICAgICMgdXNlZnVsIGZ1bmN0aW9ucyBmb3IgZGF0YSBhbmFseXNpcyBhbmQgaGlnaCAtIGxldmVsIGdyYXBoaWNzCmxpYnJhcnkoZm9yZWlnbikgICAgICAgICAgIyByZWFkIGRhdGEgc3RvcmVkIGJ5IE1pbml0YWIsIFNQU1MsIFN0YXRhCmxpYnJhcnkob3Blbnhsc3gpICAgICAgICAgIyBvcGVuLCByZWFkLCB3cml0ZSxhbmQgZWRpdCB4bHN4IGZpbGVzIApsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgICAgICMgY29sbGVjdGlvbiBvZiBSIHBhY2thZ2VzIGRlc2lnbmVkIGZvciBkYXRhIHNjaWVuY2UKCiMgdmlzdWFsaXphdGlvbiAKbGlicmFyeShnZ21hcCkgICAgICAgICAgICAjIHNwYXRpYWwgZGF0YSB2aXN1YWxpemF0aW9uIApsaWJyYXJ5KHJnZW9kYSkgICAgICAgICAgICMgc3BhdGlhbCBkYXRhIGFuYWx5c2lzIGJhc2VkIG9uIHNvZnR3YXJlIEdlb0RhCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgIyBHcmFtbWFyIG9mIGdyYXBoaWNzLiBTeXN0ZW0gZm9yIGRlY2xhcmF0aXZlIGNyZWF0aW5nIGdyYXBoaWNzCmxpYnJhcnkoY29ycnBsb3QpICAgICAgICAgIyBwcm92aWRlcyBhIHZpc3VhbCBleHBsb3JhdG9yeSB0b29sIG9uIGNvcnJlbGF0aW9uIG1hdHJpeApsaWJyYXJ5KFJDb2xvckJyZXdlcikgICAgICMgb2ZmZXJzIHNldmVyYWwgY29sb3IgcGFsZXR0ZXMKbGlicmFyeShsZWFmbGV0KSAgICAgICAgICAjIGludGVyYWN0aXZlIG1hcHMKbGlicmFyeShsZWFmc3luYykgICAgICAgICAjIGNyZWF0ZSBzbWFsbCBtdWx0aXBsZXMgb2Ygc2V2ZXJhbCBsZWFmbGV0IHdlYiBtYXBzCmxpYnJhcnkoaHRtbHRvb2xzKSAgICAgICAgIyB0b29scyBmb3IgSFRNTCBnZW5lcmF0aW9uIGFuZCBvdXRwdXQgCgojIG90aGVycyAKbGlicmFyeShybGFuZykgICAgICAgICAgICAjIGNvbGxlY3Rpb24gb2YgZnJhbWV3b3JrcyBhbmQgQVBJcyBmb3IgcHJvZ3JhbW1pbmcgd2l0aCBSCmxpYnJhcnkoY2xhc3NJbnQpICAgICAgICAgIyBtZXRob2RzIGZvciBjaG9vc2luZyB1bml2YXJpYXRlIGNsYXNzIGludGVydmFscyBmb3IgbWFwcGluZyBvciBvdGhlciBncmFwaGljIHB1cnBvc2VzCmxpYnJhcnkoZ3JpZEV4dHJhKSAgICAgICAgIyB0byBhcnJhbmdlIGFuZCBjb21iaW5lIHBsb3RzIGZvciBlYXN5IGNvbXBhcmlzb24KbGlicmFyeShrbml0cikgICAgICAgICAgICAjIGludGVncmF0ZXMgY29tcHV0aW5nIGFuZCByZXBvcnRpbmcKCiMjIyBHZXR0aW5nIGFjY2VzcyB0byBkaXN0YW5jZSwgcmV2aWV3cywgYW5kIHJhdGluZ3MgYnkgdXNpbmcgR29vZ2xlIE1hcHMKbGlicmFyeSh0bSkgICAgICAgICAgICAgICAjIGEgZnJhbWV3b3JrIGZvciB0ZXh0IG1pbmluZyBhcHBsaWNhdGlvbnMKbGlicmFyeSh3b3JkY2xvdWQpICAgICAgICAjIGZ1bmN0aW9uYWxpdHkgdG8gY3JlYXRlIHByZXR0eSB3b3JkIGNsb3VkcwpsaWJyYXJ5KHdvcmRjbG91ZDIpICAgICAgICMgCmxpYnJhcnkoZ29vZ2xld2F5KSAgICAgICAgIyBwcm92aWRlcyBhIG1lY2hhbmlzbSB0byBhY2Nlc3MgdmFyaW91cyBHb29nbGUgTWFwcyBBUElzLCBpbmNsdWRpbmcgcGxvdHRpbmcgYSBHb29nbGUgTWFwIGZyb20gUiBhbmQgb3ZlcmxheWluZyBpdCB3aXRoIHNoYXBlcyBhbmQgbWFya2VycywgYW5kIHJldHJpZXZpbmcgZGF0YSBmcm9tIHRoZSBwbGFjZXMsIGRpcmVjdGlvbnMsIHJvYWRzLCBkaXN0YW5jZXMsIGdlb2NvZGluZywgZWxldmF0aW9uIGFuZCB0aW1lem9uZSBBUElzCmxpYnJhcnkoZ21hcHNkaXN0YW5jZSkgICAgIyBhbGxvd3MgdG8gY2FsY3VsYXRlIGRpc3RhbmNlcyBmb3IgYSBkYXRhYmFzZSB0aHJvdWdoIEdvb2dsZSBtYXBzCmxpYnJhcnkob3NybSkgICAgICAgICAgICAgIyBlbmFibGVzIHRoZSBjb21wdXRhdGlvbiBvZiByb3V0ZXMsIHRyaXBzLCBpc29jaHJvbmVzIGFuZCB0cmF2ZWwgZGlzdGFuY2VzIG1hdHJpY2VzICh0cmF2ZWwgdGltZSBhbmQga2lsb21ldHJpYyBkaXN0YW5jZSkuCgojIyMgVGV4dCBNaW5pbmcKbGlicmFyeSh0bSkgICAgICAgICAjIHRleHQgbWluaW5nIGZ1bmN0aW9ucyAKbGlicmFyeShzeXV6aGV0KSAgICAjIGluY2x1ZGVzIGZvdXIgc2VudGltZW50IGRpY3Rpb25hcmllcyBhbmQgcHJvdmlkZXMgYSBtZXRob2QgZm9yIGFjY2Vzc2luZyB0aGUgcm9idXN0LCBidXQgY29tcHV0YXRpb25hbGx5IGV4cGVuc2l2ZSwgc2VudGltZW50IGV4dHJhY3Rpb24gdG9vbCBkZXZlbG9wZWQgaW4gdGhlIE5MUCBncm91cCBhdCBTdGFuZm9yZC4KbGlicmFyeShTbm93YmFsbEMpCmxpYnJhcnkod29yZGNsb3VkKQpsaWJyYXJ5KHdvcmRjbG91ZDIpCmBgYAoKCiMjICoxLiBDbGF2ZSBkZSBHb29nbGUgTWFwcyBBUEkqCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgpnbWFwc19rZXkgPC0gJ0FJemFTeURNdGtJRXZVcEZjY3lVQ0d4TGdYTy1UelRjRVJmekozbycKcmVnaXN0ZXJfZ29vZ2xlKGtleSA9IGdtYXBzX2tleSkKCmBgYAoKCiMjICoyLiBQYXLDoW1ldHJvcyBpbmljaWFsZXMgZGUgYsO6c3F1ZWRhKgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKCmxhdGl0dWRlIDwtIDI1LjY2NjcKbG9uZ2l0dWRlIDwtIC0xMDAuMjg5NQpyYWRpbyA8LSAxNTAwMCAjMTUga20sICBlc3TDoSBlbiBtZXRyb3MKCiMgQ29vcmRlbmFkYXMgZGVsIHB1bnRvIGRlIGlyaWdlbiwgVEVDOiAyNS42NjY3Mjg3NDk1MjQzMiwgLTEwMC4yODk1Mzk5OTk4MzIxMgpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjICpDb25zdWx0YSBjb24gR29vZ2xlIFBsYWNlcyBBUEk6IENvZmZlZSBTaG9wcyBlbiBNb250ZXJyZXkqCnNlYXJjaF9yZXN1bHRzXzEgPC0gZ29vZ2xlX3BsYWNlcyhzZWFyY2hfc3RyaW5nID0gJ3N0YXJidWNrcycsIGxvY2F0aW9uPWMobGF0aXR1ZGUsbG9uZ2l0dWRlKSwgcmFkaXVzPXJhZGlvLCBrZXk9Z21hcHNfa2V5KQpzZWFyY2hfcmVzdWx0c18yIDwtIGdvb2dsZV9wbGFjZXMoc2VhcmNoX3N0cmluZyA9ICdzdGFyYnVja3MnLCBsb2NhdGlvbj1jKGxhdGl0dWRlLGxvbmdpdHVkZSksIHJhZGl1cz1yYWRpbywga2V5PWdtYXBzX2tleSwgcGFnZV90b2tlbiA9IHNlYXJjaF9yZXN1bHRzXzEkbmV4dF9wYWdlX3Rva2VuKQpzZWFyY2hfcmVzdWx0c18zIDwtIGdvb2dsZV9wbGFjZXMoc2VhcmNoX3N0cmluZyA9ICdzdGFyYnVja3MnLCBsb2NhdGlvbj1jKGxhdGl0dWRlLGxvbmdpdHVkZSksIHJhZGl1cz1yYWRpbywga2V5PWdtYXBzX2tleSwgcGFnZV90b2tlbiA9IHNlYXJjaF9yZXN1bHRzXzIkbmV4dF9wYWdlX3Rva2VuKQpgYGAKCgojIyAqMy4gQ3JlYWNpw7NuIGRlIGJhc2UgZGUgZGF0b3MqCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgpzdGFyYnVja3MgPC0gYyhzZWFyY2hfcmVzdWx0c18xJHJlc3VsdHMkbmFtZSwgc2VhcmNoX3Jlc3VsdHNfMiRyZXN1bHRzJG5hbWUsIHNlYXJjaF9yZXN1bHRzXzMkcmVzdWx0cyRuYW1lKQoKIyBlbiBudWVzdHJvIGNhc28gc2Vyw61hICJTdGFyYnVja3MiIG51ZXN0cm8gYnVzaW5lc3MKCmJ1c2luZXNzX3JhdGluZyA8LSBjKHNlYXJjaF9yZXN1bHRzXzEkcmVzdWx0cyRyYXRpbmcsIHNlYXJjaF9yZXN1bHRzXzIkcmVzdWx0cyRyYXRpbmcsIHNlYXJjaF9yZXN1bHRzXzMkcmVzdWx0cyRyYXRpbmcpCgp1c2VyX3JhdGluZ3NfdG90YWwgPC0gYyhzZWFyY2hfcmVzdWx0c18xJHJlc3VsdHMkdXNlcl9yYXRpbmdzX3RvdGFsLCBzZWFyY2hfcmVzdWx0c18yJHJlc3VsdHMkdXNlcl9yYXRpbmdzX3RvdGFsLCBzZWFyY2hfcmVzdWx0c18zJHJlc3VsdHMkdXNlcl9yYXRpbmdzX3RvdGFsKQoKcGxhY2VfaWQgPC0gYyhzZWFyY2hfcmVzdWx0c18xJHJlc3VsdHMkcGxhY2VfaWQsIHNlYXJjaF9yZXN1bHRzXzIkcmVzdWx0cyRwbGFjZV9pZCwgc2VhcmNoX3Jlc3VsdHNfMyRyZXN1bHRzJHBsYWNlX2lkKQoKbGF0IDwtIGMoc2VhcmNoX3Jlc3VsdHNfMSRyZXN1bHRzJGdlb21ldHJ5JGxvY2F0aW9uJGxhdCwgc2VhcmNoX3Jlc3VsdHNfMiRyZXN1bHRzJGdlb21ldHJ5JGxvY2F0aW9uJGxhdCwgc2VhcmNoX3Jlc3VsdHNfMyRyZXN1bHRzJGdlb21ldHJ5JGxvY2F0aW9uJGxhdCkKCmxvbiA8LSBjKHNlYXJjaF9yZXN1bHRzXzEkcmVzdWx0cyRnZW9tZXRyeSRsb2NhdGlvbiRsbmcsIHNlYXJjaF9yZXN1bHRzXzIkcmVzdWx0cyRnZW9tZXRyeSRsb2NhdGlvbiRsbmcsIHNlYXJjaF9yZXN1bHRzXzMkcmVzdWx0cyRnZW9tZXRyeSRsb2NhdGlvbiRsbmcpCgpkYXRhIDwtIGRhdGEuZnJhbWUoc3RhcmJ1Y2tzLCBidXNpbmVzc19yYXRpbmcsIHVzZXJfcmF0aW5nc190b3RhbCwgcGxhY2VfaWQsIGxhdCwgbG9uKQoKYGBgCgojIyAqNC03LiBUb3AgeSBCb3R0b20gbmVnb2Npb3MqCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpkYXRhX3RvcCA8LSBkYXRhICU+JSBzbGljZV9tYXgoYnVzaW5lc3NfcmF0aW5nLCBuID0gMTApCmRhdGFfYm90dG9tIDwtIGRhdGEgJT4lIHNsaWNlX21pbihidXNpbmVzc19yYXRpbmcsIG4gPSAxMCkKYGBgCgojIyAqNC03LiBWaXN1YWxpemFjacOzbiBlbiBtYXBhIGludGVyYWN0aXZvKgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KI1JBZGlvIGVudHJlIDE1IHkgMjUga20KbGVhZmxldChkYXRhX3RvcCkgJT4lIGFkZFRpbGVzKCkgJT4lCiAgYWRkQ2lyY2xlTWFya2Vycyh+bG9uLCB+bGF0LCBwb3B1cCA9IH5zdGFyYnVja3MsIGNvbG9yID0gImdyZWVuIiwgcmFkaXVzID0gMTUpCmBgYAoKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxlYWZsZXQoZGF0YV9ib3R0b20pICU+JSBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMofmxvbiwgfmxhdCwgcG9wdXAgPSB+c3RhcmJ1Y2tzLCBjb2xvciA9ICJyZWQiLCByYWRpdXMgPSAxNSkKYGBgCgpgYGB7cn0KCm9wdGlvbnMod2Fybj0tMSkKZHRtX3RvcCA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoZGF0YV90b3ApIAptYXRyaXhfdG9wIDwtIGFzLm1hdHJpeChkdG1fdG9wKSAKd29yZHNfdG9wIDwtIHNvcnQocm93U3VtcyhtYXRyaXhfdG9wKSxkZWNyZWFzaW5nPVRSVUUpIAp3b3Jkc190b3BfZGYgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXMod29yZHNfdG9wKSxmcmVxPXdvcmRzX3RvcCkKZGF0YSA8LSBkYXRhLmZyYW1lKHN0YXJidWNrcyxidXNpbmVzc19yYXRpbmcsdXNlcl9yYXRpbmdzX3RvdGFsLHBsYWNlX2lkLGxhdCxsb24pCndyaXRlLmNzdihkYXRhLCAiL1VzZXJzL21hcmlhbmFhbGVhbC9EZXNrdG9wL1RFQyAyMDI1L19QbGFuZWFjaW/MgW4gZXN0cmF0ZcyBZ2ljYSBiYXNhZGEgZW4gYW5hbGnMgXRpY2EgcHJlc2NyaXB0aXZhIC9zdGFyYnVja3MuY3N2Iiwgcm93Lm5hbWVzPVRSVUUpCgojIi9Vc2Vycy9tYXJpYW5hYWxlYWwvRGVza3RvcC9URUMgMjAyNS9fUGxhbmVhY2lvzIFuIGVzdHJhdGXMgWdpY2EgYmFzYWRhIGVuIGFuYWxpzIF0aWNhIHByZXNjcmlwdGl2YSAvc3RhcmJ1Y2tzLmNzdiIKYGBgCgojICpQYXJ0ZSBCOiBBbsOhbGlzaXMgZGUgU2VudGltaWVudG8gKFNlbnRpbWVudCBBbmFseXNpcykqCiMjICpPYnRlbmVyIGNvbWVudGFyaW9zKgpgYGB7cn0KcmV2aWV3c190b3AgPC0gZ29vZ2xlX3BsYWNlX2RldGFpbHMocGxhY2VfaWQgPSBkYXRhX3RvcCRwbGFjZV9pZFsxXSwga2V5ID0gZ21hcHNfa2V5KQpyZXZpZXdzX2JvdCA8LSBnb29nbGVfcGxhY2VfZGV0YWlscyhwbGFjZV9pZCA9IGRhdGFfYm90dG9tJHBsYWNlX2lkWzFdLCBrZXkgPSBnbWFwc19rZXkpCnJldmlld3NfdG9wCmBgYApgYGB7cn0Kc3RyKHJldmlld3NfdG9wJHJlc3VsdCRyZXZpZXdzKQoKYGBgCgoKIyMgKlRvcHMgeSBCb3R0b21zKgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQoKZGF0YSRidXNpbmVzc19yYXRpbmcgPC0gYXMubnVtZXJpYyhkYXRhJGJ1c2luZXNzX3JhdGluZykKCmRhdGFfbGltcGlhIDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShidXNpbmVzc19yYXRpbmcpLCBidXNpbmVzc19yYXRpbmcgPj0gMCwgYnVzaW5lc3NfcmF0aW5nIDw9IDUpCgojIFRPUCA1IE1FSk9SIFZBTFVBRE9TCnRvcDUgPC0gZGF0YV9saW1waWEgJT4lCiAgYXJyYW5nZShkZXNjKGJ1c2luZXNzX3JhdGluZykpICU+JQogIHNsaWNlX2hlYWQobiA9IDUpCgpnZ3Bsb3QodG9wNSwgYWVzKHggPSByZW9yZGVyKHN0YXJidWNrcywgYnVzaW5lc3NfcmF0aW5nKSwgeSA9IGJ1c2luZXNzX3JhdGluZykpICsKICBnZW9tX2NvbChmaWxsID0gImRhcmtncmVlbiIpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUb3AgNSBTdGFyYnVja3MgTWVqb3IgVmFsdWFkb3MiLAogICAgeCA9ICJTdWN1cnNhbCIsCiAgICB5ID0gIkNhbGlmaWNhY2nDs24gKG3DoXguIDUpIgogICkgKwogIHlsaW0oMCwgNSkgKwogIHRoZW1lX21pbmltYWwoKQoKIyBCT1RUT00gNSBQRU9SIFZBTFVBRE9TCmJvdHRvbTUgPC0gZGF0YV9saW1waWEgJT4lCiAgYXJyYW5nZShidXNpbmVzc19yYXRpbmcpICU+JQogIHNsaWNlX2hlYWQobiA9IDUpCgpnZ3Bsb3QoYm90dG9tNSwgYWVzKHggPSByZW9yZGVyKHN0YXJidWNrcywgYnVzaW5lc3NfcmF0aW5nKSwgeSA9IGJ1c2luZXNzX3JhdGluZykpICsKICBnZW9tX2NvbChmaWxsID0gImJyb3duMyIpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUb3AgNSBTdGFyYnVja3MgUGVvciBWYWx1YWRvcyIsCiAgICB4ID0gIlN1Y3Vyc2FsIiwKICAgIHkgPSAiQ2FsaWZpY2FjacOzbiAobcOheC4gNSkiCiAgKSArCiAgeWxpbSgwLCA1KSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgKjgtOS4gV29yZGNsb3VkKgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQp0b3BfdGV4dCA8LSByZXZpZXdzX3RvcCRyZXN1bHQkcmV2aWV3cyR0ZXh0Cgp0b3BfY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodG9wX3RleHQpKQp0b3BfY29ycHVzIDwtIHRtX21hcCh0b3BfY29ycHVzLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQp0b3BfY29ycHVzIDwtIHRtX21hcCh0b3BfY29ycHVzLCByZW1vdmVQdW5jdHVhdGlvbikKdG9wX2NvcnB1cyA8LSB0bV9tYXAodG9wX2NvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3Jkcygic3BhbmlzaCIpKQp3b3JkY2xvdWQodG9wX2NvcnB1cywgbWF4LndvcmRzPTEwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBlamVtcGxvIGRlIGFycmliYSB0b3BfdGV4dCA8LSByZXZpZXdzX3RvcCRyZXN1bHQkcmV2aWV3cyR0ZXh0Cgpib3RfdGV4dCA8LSByZXZpZXdzX2JvdCRyZXN1bHQkcmV2aWV3cyR0ZXh0Cgpib3RfY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoYm90X3RleHQpKQpib3RfY29ycHVzIDwtIHRtX21hcChib3RfY29ycHVzLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQpib3RfY29ycHVzIDwtIHRtX21hcChib3RfY29ycHVzLCByZW1vdmVQdW5jdHVhdGlvbikKYm90X2NvcnB1cyA8LSB0bV9tYXAoYm90X2NvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3Jkcygic3BhbmlzaCIpKQp3b3JkY2xvdWQoYm90X2NvcnB1cywgbWF4LndvcmRzPTEwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCBjb2xvcnM9YnJld2VyLnBhbCg4LCAiUmVkcyIpKQpgYGAKCgoKIyMgKjEwLiBTZW50aW1lbnQgQW5hbHlzaXMqCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnRvcF9zZW50aW1lbnQgPC0gZ2V0X25yY19zZW50aW1lbnQodG9wX3RleHQpCmJvdF9zZW50aW1lbnQgPC0gZ2V0X25yY19zZW50aW1lbnQoYm90X3RleHQpCmJhcnBsb3QoY29sU3Vtcyh0b3Bfc2VudGltZW50KSwgbGFzPTIsIGNvbD0iYmx1ZSIsIG1haW49IkVtb2Npb25lcyAtIE5lZ29jaW9zIGNvbiBtZWpvciBjYWxpZmljYWNpw7NuIikKYmFycGxvdChjb2xTdW1zKGJvdF9zZW50aW1lbnQpLCBsYXM9MiwgY29sPSJyZWQiLCBtYWluPSJFbW9jaW9uZXMgLSBOZWdvY2lvcyBjb24gcGVvciBjYWxpZmljYWNpw7NuIikKYGBgCgoKCiMjICoxMS4gRGlzdHJpYnVjacOzbiBnZW5lcmFsKgpgYGB7cn0KIyBPYnRlbmVyIHZlY3RvciBkZSB0ZXh0byBsaW1waW8KYm90X3ZlY3RvciA8LSBzYXBwbHkoYm90X2NvcnB1cywgYXMuY2hhcmFjdGVyKQoKIyBTZW50aW1lbnQgc2NvcmUKYm90X3Njb3JlcyA8LSBnZXRfc2VudGltZW50KGJvdF92ZWN0b3IsIG1ldGhvZCA9ICJzeXV6aGV0IikKCiMgTW9zdHJhciBkaXN0cmlidWNpw7NuCmhpc3QoYm90X3Njb3JlcywKICAgICBicmVha3MgPSAxMCwKICAgICBjb2wgPSAic3RlZWxibHVlIiwKICAgICBtYWluID0gIkRpc3RyaWJ1Y2nDs24gZGVsIFNlbnRpbWVudCBTY29yZSIsCiAgICAgeGxhYiA9ICJTZW50aW1lbnQgU2NvcmUiKQoKYGBgCgoKCgojIyAqMTIuIERpc3RyaWJ1Y2nDs24gUG9zaXRpdm8sIE5lZ2F0aXZvLCBOZXV0cmFsKgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ2V0X3NlbnRpbWVudF9zdW1tYXJ5IDwtIGZ1bmN0aW9uKHRleHQpIHsKICBzZW50aW1lbnRfc2NvcmVzIDwtIGdldF9zZW50aW1lbnQodGV4dCwgbWV0aG9kID0gInN5dXpoZXQiKQogIHN1bW1hcnkgPC0gdGFibGUoY3V0KHNlbnRpbWVudF9zY29yZXMsIGJyZWFrcz1jKC1JbmYsIC0wLjEsIDAuMSwgSW5mKSwgbGFiZWxzPWMoIk5lZ2F0aXZvIiwgIk5ldXRyYWwiLCAiUG9zaXRpdm8iKSkpCiAgcmV0dXJuKHN1bW1hcnkpCn0KZ2V0X3NlbnRpbWVudF9zdW1tYXJ5KHRvcF90ZXh0KQpnZXRfc2VudGltZW50X3N1bW1hcnkoYm90X3RleHQpCmBgYAoKIyAqQ29uY2x1c2lvbmVzKgotIExhcyBzdWN1cnNhbGVzIGRlIFN0YXJidWNrcyBtZWpvciBjYWxpZmljYWRhcyB0aWVuZGVuIGEgZXN0YXIgdWJpY2FkYXMgZW4gem9uYXMgY29uIGFsdGEgYWZsdWVuY2lhIHkgYWNjZXNvIGbDoWNpbCwgbG8gcXVlIHBvZHLDrWEgaW5mbHVpciBwb3NpdGl2YW1lbnRlIGVuIGxhIGV4cGVyaWVuY2lhIGRlbCBjbGllbnRlLgotIExhcyBzdWN1cnNhbGVzIHRvcCBkZXN0YWNhbiBwb3Igb2ZyZWNlciB1biBzZXJ2aWNpbyBjb25zaXN0ZW50ZSB5IGVmaWNpZW50ZSwgbG8gcXVlIHNlIHJlZmxlamEgZW4gY2FsaWZpY2FjaW9uZXMgZWxldmFkYXMgeSBjb21lbnRhcmlvcyBjb24gZW1vY2lvbmVzIHBvc2l0aXZhcy4KLSBFbCBhbsOhbGlzaXMgZGUgc2VudGltaWVudG9zIHJldmVsYSBxdWUgbGFzIGVtb2Npb25lcyBleHByZXNhZGFzIHBvciBsb3MgY2xpZW50ZXMgKHBvc2l0aXZhcyBvIG5lZ2F0aXZhcykgZXN0w6FuIGZ1ZXJ0ZW1lbnRlIGNvcnJlbGFjaW9uYWRhcyBjb24gbGEgY2FsaWZpY2FjacOzbiBnZW5lcmFsIGRlbCBuZWdvY2lvLgotICBMYXMgc3VjdXJzYWxlcyBjb24gYmFqYXMgY2FsaWZpY2FjaW9uZXMgcHJlc2VudGFuIHBhdHJvbmVzIHJlY3VycmVudGVzIGRlIHF1ZWphcyByZWxhY2lvbmFkYXMgY29uIHRpZW1wb3MgZGUgZXNwZXJhLCBsaW1waWV6YSB5IGF0ZW5jacOzbiwgbG8gY3VhbCByZXByZXNlbnRhIHVuYSBvcG9ydHVuaWRhZCBjbGFyYSBkZSBtZWpvcmEgb3BlcmF0aXZhLgotIEVsIHVzbyBjb21iaW5hZG8gZGUgbWFwYXMsIHJhdGluZ3MgeSBtaW5lcsOtYSBkZSB0ZXh0byBwZXJtaXRlIGRldGVjdGFyIGluc2lnaHRzIGFjY2lvbmFibGVzIHBhcmEgbGEgcGxhbmVhY2nDs24gZXN0cmF0w6lnaWNhIGJhc2FkYSBlbiBleHBlcmllbmNpYSBkZWwgY2xpZW50ZS4KLSBJbXBsZW1lbnRhciBlc3RyYXRlZ2lhcyBsb2NhbGl6YWRhcyBkZSBtZWpvcmEgZW4gYmFzZSBhIGNvbWVudGFyaW9zIG5lZ2F0aXZvcyBlc3BlY8OtZmljb3MgcHVlZGUgZWxldmFyIGxhIHBlcmNlcGNpw7NuIGRlIG1hcmNhIHkgZmlkZWxpemFjacOzbiBkZSBjbGllbnRlcyBlbiB0b2RhIGVsIMOhcmVhIG1ldHJvcG9saXRhbmEuCi0gTGFzIDUgc3VjdXJzYWxlcyBtZWpvciBjYWxpZmljYWRhcyB0aWVuZW4gdW4gcHJvbWVkaW8gZGUgNC42IGVzdHJlbGxhcyB5IG3DoXMgZGUgNDUwIHJlc2XDsWFzIHBvciBsb2NhbC4KLSBMYXMgNSBwZW9yIGNhbGlmaWNhZGFzIHByZXNlbnRhbiB1biBwcm9tZWRpbyBkZSAzLjggZXN0cmVsbGFzLCBjb24gYWxndW5vcyBjYXNvcyB0YW4gYmFqb3MgY29tbyAzLjUsIGxvIGN1YWwgZXMgc2lnbmlmaWNhdGl2byBlbiB1bmEgZXNjYWxhIGRvbmRlIGVsIHByb21lZGlvIGdlbmVyYWwgcm9uZGEgbG9zIDQuMi4gRXN0YXMgdWJpY2FjaW9uZXMgc3VlbGVuIHJlY2liaXIgbWVub3Mgb3BpbmlvbmVzICg8IDMwMCksIHBlcm8gY29uIHVuIGFsdG8gY29udGVuaWRvIG5lZ2F0aXZvIGVuIHN1cyByZXNlw7Fhcy4KLSBFbiBsb3MgbmVnb2Npb3MgbWVqb3IgY2FsaWZpY2Fkb3MsIHByZWRvbWluYW4gZW1vY2lvbmVzIGNvbW8gYWxlZ3LDrWEsIGNvbmZpYW56YSB5IHNvcnByZXNhLCBjb24gbcOhcyBkZSA4MCBtZW5jaW9uZXMgcG9zaXRpdmFzLiBFbiBjYW1iaW8sIGxvcyBwZW9yIGNhbGlmaWNhZG9zIHRpZW5lbiBtw6FzIGRlIDcwIG1lbmNpb25lcyBkZSBlbW9jaW9uZXMgbmVnYXRpdmFzLCBwcmluY2lwYWxtZW50ZSBpcmEsIGRpc2d1c3RvIHkgdHJpc3RlemEuCi0gTGFzIHBhbGFicmFzIG3DoXMgZnJlY3VlbnRlcyBlbiBzdWN1cnNhbGVzIHRvcCBpbmNsdXllbjog4oCccsOhcGlkb+KAnSwg4oCcYW1hYmxl4oCdLCDigJxhbWJpZW50ZeKAnSwg4oCcbGltcGlv4oCdLgotIEVuIGxhcyBzdWN1cnNhbGVzIGJvdHRvbSBkZXN0YWNhbiBwYWxhYnJhcyBjb21vOiDigJxsZW50b+KAnSwg4oCcc3VjaW/igJ0sIOKAnHRhcmRhZG/igJ0sIOKAnHDDqXNpbW/igJ0uCi0gTGFzIHN1Y3Vyc2FsZXMgdG9wIHNlIGNvbmNlbnRyYW4gZW4gem9uYXMgY29tZXJjaWFsZXMgY29tbyBTYW4gUGVkcm8sIFZhbGxlIE9yaWVudGUgeSDDoXJlYXMgY2VyY2FuYXMgYSBjZW50cm9zIGNvcnBvcmF0aXZvcy4KLSBMYXMgZGUgbWVub3IgY2FsaWZpY2FjacOzbiBzZSB1YmljYW4gZW4gem9uYXMgY29uIG1lbm9yIGRlbnNpZGFkIGVjb27Ds21pY2EgbyBjb24gbWF5b3IgdHLDoW5zaXRvLCBsbyBxdWUgcHVlZGUgaW1wYWN0YXIgbGEgZXhwZXJpZW5jaWEuCi0gRW4gc3VjdXJzYWxlcyBib3R0b20sIG3DoXMgZGVsIDQ1JSBkZSBsb3MgY29tZW50YXJpb3Mgc29uIGNsYXNpZmljYWRvcyBjb21vIG5lZ2F0aXZvcyBvIG5ldXRyb3Mgc2Vnw7puIGVsIGFuw6FsaXNpcyBkZSBTeXV6aGV0LiBFbiBjb250cmFzdGUsIGVuIGxhcyBzdWN1cnNhbGVzIHRvcCwgbcOhcyBkZWwgNjUlIGRlIGxvcyBjb21lbnRhcmlvcyB0aWVuZW4gdW4gc2VudGltaWVudG8gcG9zaXRpdm8u