D. 視覺化的分析結果與解釋
系統參數設定
Sys.setlocale(category = "LC_ALL", locale = "zh_TW.UTF-8") # 避免中文亂碼
[1] "zh_TW.UTF-8/zh_TW.UTF-8/zh_TW.UTF-8/C/zh_TW.UTF-8/zh_TW.UTF-8"
安裝需要的packages
packages = c("tidytext","dplyr", "jiebaR", "stringr", "wordcloud2", "ggplot2", "tidyr", "NLP", "ggraph")
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)
載入套件
library(tidytext)
library(dplyr)
library(jiebaR)
library(stringr)
library(wordcloud2)
library(ggplot2)
library(tidyr) # spread
library(NLP) # ngrams
library(ggraph) # bigram network
設定工作目錄 (方便之後讀檔改相對路徑撰寫)
setwd("/Users/zic/Desktop/google_game_mining")
chi_text_theme = theme(text = element_text(family = "Heiti TC Light")) # 定義中文字主題
讀取所有資料檔
files = list.files("./data/GooglePlayGames", full.names=T) # 列出所有資料檔
data.list = lapply(files, function(x) {
df = read.csv(x, stringsAsFactors = F) # 讀取資料檔
df$gameTitle = basename(x) # 將檔案名稱視為gameTitle
return(df)
})
source_df = do.call("rbind", data.list) # 合併資料至df
# 欄位整理
source_df$gameTitle = str_replace(source_df$gameTitle, "result_", "") # 去掉前綴
source_df$gameTitle = str_replace(source_df$gameTitle, ".csv", "") # 去掉副檔名
source_df = separate(source_df, gameTitle, c("gameRank", "gameTitle"), sep = "_", convert = TRUE)
source_df$date = as.Date(source_df$date, "%Y年%m月%d日")
source_df$gameRank = as.factor(source_df$gameRank) # 轉成factor,之後圖形繪製時顏色比較分開
source_df$ratings = as.factor(source_df$ratings)
# 資料清理
data_cleaned = source_df %>%
mutate(comment = str_replace(comment, "(http|https)://.*", "")) %>% # 去除網址
mutate(comment = str_replace_all(comment, "[( 0-9.%)]+"," ")) %>% # 去除數字
mutate(comment = str_replace_all(comment, "[ ?!. ,']+"," ")) %>% # 去除標點符號
mutate(comment = str_replace_all(comment, "\\s+"," ")) %>% # 去除連續空白
filter(nchar(comment) > 0)
data_cleaned
資料欄位說明
name: 留評論的玩家名稱
ratings: 留評論時給的星評
date: 留評論的時間
helpful.vote: 多少人對此評論按讚
comment: 評論內容

檢視各遊戲的討論數量, 及資料區間
data_cleaned %>%
count(gameRank) %>%
ggplot(aes(gameRank, n)) +
geom_col() +
ylab("count") +
scale_x_discrete(limits = 1:12) +
chi_text_theme

# 檢視資料區間
data.frame(
minDate = min(source_df$date),
maxDate = max(source_df$date))
上圖中,x 軸為排行榜名次,y 軸為評論數量
由上圖看來,遊戲的評論數量與排行榜名次並無明顯關係。
整份遊戲資料區間為2019-03-28 至 2019-04-19
準備jieba 斷詞函式
由於資料有中文/英文,故採jieba 進行斷詞(unnest_token)
jieba_tokenizer = worker()
# 動態新增自訂詞彙
new_user_word(jieba_tokenizer, c(""))
[1] TRUE
# 定義斷詞函式
chi_tokenizer <- function(t) {
lapply(t, function(x) {
tryCatch({
tokens <- segment(x, jieba_tokenizer)
tokens <- tokens[nchar(tokens)>1]
return(tokens)
},
# 遇到 error 時的自訂處理函數
error = function(msg) {
message(x)
return(NA)
})
})
}
透過自定義的jieba 進行對資料進行unnest。轉成tidy 格式
tokens = data_cleaned %>%
unnest_tokens(word, comment, token=chi_tokenizer)
繪製出現次數較高的詞
tokens %>%
count(word, sort = TRUE) %>% # 計算詞頻
mutate(word = reorder(word, n)) %>%
top_n(20, n) %>%
ggplot(aes(word, n)) +
geom_col() +
xlab(NULL) +
chi_text_theme +
coord_flip()

透過文字雲觀察斷詞結果
tokens %>%
count(word) %>%
filter(n > 25) %>%
wordcloud2(size = .6) # size=.8, 避免在rnotebook 中過大的文字未渲染
從上述結果看來「遊戲」和「好玩」是兩個出現最高的詞,剛好跟Google Play 遊戲應用程式的主要開發訴求一樣【讓遊戲變得更好玩!】
整體而言, 沒有出現很奇怪的詞,但有一些如“國旗”, “中國民國”, “中國”,似乎跟政治有些關係
從原評論中查看,可以發現此類詞大多出現於“絕地求生M”此款遊戲,遊戲分為國際版與台灣版,部分討論為此相關議題。
準備LIWC字典
positive = scan(file = "./data/dict/liwc/positive.txt", what=character(), sep=',',
encoding='utf-8',fileEncoding='utf-8')
Read 662 items
negative = scan(file = "./data/dict/liwc/negative.txt", what=character(), sep=',',
encoding='utf-8',fileEncoding='utf-8')
Read 1047 items
positive = data.frame(word = positive, sentiment = "positive", stringsAsFactors = FALSE)
negative = data.frame(word = negative, sentiment = "negative", stringsAsFactors = FALSE)
liwc_ch = rbind(positive, negative) %>%
filter(word != "遊戲")
繪製每個遊戲,正負情緒字排行圖
tokens %>%
inner_join(liwc_ch) %>%
group_by(gameTitle, sentiment) %>% # 群組化後,正負資料各取n筆
count(word, sort = T) %>%
top_n(5) %>%
ungroup() %>%
mutate(n = ifelse(sentiment == "positive", 1, -1) * n) %>% # 負面情緒轉成-n
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n, fill = gameTitle)) +
geom_col(show.legend = FALSE) +
facet_wrap(~gameTitle, scales = "free") +
labs(y = "Contribution to sentiment", x = NULL) +
chi_text_theme +
coord_flip()

由上圖看來,大部份遊戲中,玩家評論正面情緒的數量遠大於負面情緒
繪製每個遊戲,依日期排序之情緒變化
tokens_game_sentiment = tokens %>%
inner_join(liwc_ch) %>%
group_by(gameRank) %>%
count(date, sentiment) %>% # 根據日期 + 情緒,計算次數
spread(sentiment, n) %>% # 展開欄位
mutate(positive = replace_na(positive, 0)) %>% # 取代na 為0
mutate(negative = replace_na(negative, 0)) %>%
mutate(sentiment = positive - negative) %>% # 計算正負情緒
ungroup()
tokens_game_sentiment
# 由於部份遊戲的資料較少,畫面同一張圖並不容易解讀
# 故各圖繪製一張
tokens_game_sentiment %>%
ggplot() +
geom_line(aes(x = date, y = sentiment, colour=gameRank)) +
scale_x_date(date_labels = "%m%d") +
facet_wrap(~gameRank, scales = "free") +
chi_text_theme +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

上圖中,部份遊戲的評論極不平均(如2, 4, 7, 11, 12) 等
以7-盛唐幻夜來查看,4/17因為有人發布-九大職業攻略介紹、角色定位、遊戲介紹的影片,因此推斷有可能此遊戲上架(開放)後,玩家才上去留言,造成日期排序之情緒變化,內容極不平均。
不分遊戲的情況下,星評對應的情緒字
tokens_ratings = tokens %>%
inner_join(liwc_ch) %>% # 只保留跟情緒相關的詞
group_by(ratings) %>%
count(word, sort = T) %>%
top_n(10, n) %>%
ungroup() %>%
inner_join(liwc_ch) %>% # 組合出sentiment
mutate(score = ifelse(sentiment == "positive", 1, -1) * n) %>% # 根據sentiment 算出分數
mutate(word = reorder(word, score)) # 根據分數進行排列
tokens_ratings
# 每個群組(ratings) 繪製一張圖
tokens_ratings %>%
ggplot(aes(x = word, score, fill = ratings)) +
geom_col(show.legend = FALSE) +
facet_wrap(~ratings, scales = "free") +
labs(y = "Score=Count*Sentiment", x = NULL) +
chi_text_theme +
coord_flip()

從上圖可以看出各星評中,較常出現的詞 星評低的情況下,正負面情緒的詞出現的次數較為接近; 星評越高的情況下,負面情緒的詞出現的少。
透過tf-idf 來檢視詞的分佈
game_words = tokens %>%
count(gameRank, word, sort = TRUE)
total_words = game_words %>%
group_by(gameRank) %>%
summarize(total = sum(n))
game_words = left_join(game_words, total_words)
# 計算tf-idf
game_words = game_words %>%
bind_tf_idf(word, gameRank, n)
# 繪製較高tf-idf
# 由於資料量擠在同一張圖上太密,分多次繪製
high_tf_idf = game_words %>%
arrange(desc(tf_idf)) %>%
mutate(word = factor(word, levels = rev(unique(word)))) %>%
group_by(gameRank) %>%
top_n(10) %>%
ungroup()
high_tf_idf
paint_tf_idf = function(data) {
data %>%
ggplot(aes(word, tf_idf, fill = gameRank)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y = "tf-idf") +
facet_wrap(~gameRank, ncol = 2, scales = "free") +
chi_text_theme +
coord_flip()
}
paint_tf_idf(
high_tf_idf %>%
filter(gameRank %in% 1:4)
)

paint_tf_idf(
high_tf_idf %>%
filter(gameRank %in% 5:8)
)

paint_tf_idf(
high_tf_idf %>%
filter(gameRank %in% 9:12)
)

上述3張圖,呈現各遊戲內,較高的tf-idf 值之對應文字 tf 值愈高,其單詞愈重要,就7-《盛唐幻夜》來說其為大馬女星林明禎擔任遊戲代言人,遊戲是以同名電視劇《盛唐幻夜》為基礎打造的遊戲。時代背景設定為中國歷史上最繁華的唐朝,玩家在遊戲中感受大唐盛世與御劍飛行等樂趣。玩家與夥伴一步步揭開唐代懸幻離奇的神秘面紗;此款遊戲讓玩家可以收集眾角色,成為自己闖蕩盛唐江湖的好幫手。遊戲共有九大職業,因此「明禎」、「職業」、「摸索」相對於情緒詞來說是普遍有較高的tf-idf 值。
Topic Modeling
# 以不分遊戲的情況下,進行玩家評論的主題查找
lda = tokens %>%
# dtm 轉換需要3個欄位:document, term, count
mutate(artId = group_indices(., name)) %>% # 準備cast_dtm需要的欄位
count(artId, word) %>% # 準備cast_dtm需要的欄位
cast_dtm(artId, word, n) %>% # 轉成dtm
topicmodels::LDA(k = 6, control = list(seed = 1234)) # 計算LDA
lda
A LDA_VEM topic model with 6 topics.
# Word-topic probabilities
topics = tidy(lda, matrix = "beta") # 主題-單字的機率
topics
# 繪製每個主題的常見單字
top_terms = topics %>%
group_by(topic) %>%
top_n(18, beta) %>%
ungroup() %>%
arrange(topic, -beta)
top_terms
top_terms %>%
mutate(term = reorder(term, beta)) %>%
ggplot(aes(term, beta, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free") +
theme(text = element_text(family = "Heiti TC Light")) +
coord_flip()

在主題切分時,用2,4,6個主題的情況下;各主題似乎看不出來較為明顯的差異。
猜測是由於討論的內容類似度太高
因而沒有明顯的主題差異
LS0tCnRpdGxlOiAiR29vZ2xlUGxheSDlhY3osrvpgYrmiLLmloflrZfliIbmnpAiCmF1dGhvcjog56ys5LiJ57WEPGJyLz5OMDY0MDIwMDE1IOmQmOaYjuW/lzxici8+TjA2NDIyMDAwNyDpmbPmhaflgKk8YnIvPk4wNjQyMjAwMDkg6Kyd5Yex5aiBPGJyLz5OMDY0MjIwMDI2CiAg5YqJ5b+X5pS/CmRhdGU6ICIyMDE5LzA0LzIxIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBubwogICAgICBzbW9vdGhfc2Nyb2xsOiBubwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKYWJzdHJhY3Q6ICcnCi0tLQoKIyBBLiDli5XmqZ/lkozliIbmnpDnm67nmoQKQW5kb3JpZCDkvZzmpa3ns7vntbHngrogR29vZ2xlIFBsYXkg55Sf5oWL57O75Lit55qE6YeN6KaB6Zec6Y215LmL5LiA77yM5LuK5bm05Lmf5q2j5byP6YKB5ZCR56ysIDExIOW5tO+8jOebruWJjeWFqOeQg+W3suaciei2hemBjiAyMCDlhITlgIvmtLvouo3nmoQgQW5kcm9pZCDoo53nva7jgILlnKggMjAxNyDlubQgNSDmnIjliLAgMjAxOCDlubQgNSDmnIjplpPvvIxHb29nbGUgUGxheSDkuIrkvoboh6ogMjE1IOWAi+Wci+WutumBiuaIsuiIh+aHieeUqOeoi+W8j+e0r+epjeS4i+i8ieasoeaVuOWwh+i/kSAxLDAwMCDlhITvvJvmm77kuIvovInpgY7oh7PlsJHkuIDmrL7pgYrmiLLnmoQgQW5kcm9pZCDkvb/nlKjogIXkurrmlbjlop7liqDkuobkuIDlgI3lpJrvvIzlhbbkuK3ov5EgNDAl55qE5oiQ6ZW35L6G6Ieq5paw6IiI5biC5aC077yM5YyF5ous5be06KW/44CB5Y2w5bqm44CB5Y2w5bC85ZKM5aKo6KW/5ZOl44CC6ICM5Y+w54Gj5pivIEdvb2dsZSBQbGF5IOWFqOeQg+WJjeS6lOWkp+W4guWgtO+8jOmAmeS5n+S7o+ihqOWPsOeBo+WcqOihjOWLleS4lueVjOS4reS9jeWxheWFqOeQg+mgmOWFiOWcsOS9jeOAguWcqEdvb2dsZVBsYXkg5LiK5q+P5pel55qG5pyJ54K65pW45LiN5bCR55qE5paw5ZOB6YGK5oiy5LiK5p6277ybPGJyLz4K5L2G6YGK5oiy6aGe5Yil55qE54ax6ZaA5o6S6KGM5qac55qE6K6K5YyW5bmF5bqm5aeL57WC5b6I5bCP77yb5qC55pOa6YGK5oiy6ZaL55m86ICFRGF2aWQg6KGo56S677yM44CMR29vZ2xlIFBsYXkg5pyA5pyJ5bmr5Yqp55qE5Zyw5pa577yM5bCx5piv546p5a626KmV6KuW55qE6YOo5YiG44CC6Ieq5bex6YGK5oiy5LiK5biC5Lul5L6G77yM5q+P5aSp6YO95pyD6ZaL546p5a626KmV6Kqe5L6G55yL77yM5pyD6ZyA6KaB546p5a625L2/55So5b6M57aT6amX77yM6YCZ5bCN6Ieq5bey5Zyo5L2c6YGK5oiy5b6I6YeN6KaB44CCR29vZ2xlIOWNs+aZguWPjeaHiemAn+W6puW+iOW/q++8jOmChOacieWNs+aZgue/u+aHie+8jOmAo+mBoOWcqOW3tOilv+eahOeOqeWutuaEj+imi++8jOS5n+WPr+S7pee/u+aIkOS4reiuk+iHquW3seS6huino+S7luWAkeeahOW7uuitsO+8jOiuk+iHquW3seWPr+S7peWcqOW+jOWPsOW+iOa4healmueci+WIsO+8jOW5q+WKqeecn+eahOW+iOWkp+OAguOAjQo8YnIvPgrlm6DmraQK5oiR5YCR5oOz5b6e546p5a625bCN5pa86YGK5oiy55qE6KmV6KuW5Lit5bCL5om+5LiL5YiX5LqM6aCF5Zug57Sg77yaPGJyLz4KKioxLiDlvp7njqnlrrboqZXoq5bkvobmjqLoqI7mloflrZfmg4Xnt5LnmoTororljJY8YnIvPioqCioqMi4g5b6e546p5a626KmV6KuW5om+5Ye65Li76aGM5qih5Z6LKio8YnIvPgoKIyBCLiDos4fmlpnpm4bnmoTmj4/ov7AK6LOH5paZ5L6G5rqQ54K65Y+w54Gj5Y2AR29vZ2xlUGxheSDlhY3osrvnhrHploDpgYrmiLLmjpLooYzmppzliY0xMiDlkI3nmoTnjqnlrrboqZXoq5bjgII8YnIvPgpHb29nbGVQbGF5IOeahOeOqeWutuipleirluizh+aWmeacieS4i+WIl+eJueaApzxici8+CmEuIOmBiuaIsuabtOeJiOW+jOS7jeeEtuS/neeVmTxici8+CmIuIOipleirluW/hemgiOWcqOipsuWNgOS4i+i8iemBiuaIsuW+jOaJjeiDveaSsOWvqzxici8+CgrkuIvlnJbngrros4fmlpnmipPlj5bmmYLvvIzpgYrmiLLmjpLooYzmppzkuYvmiKrlnJY8YnIvPgohW2F2YXRhcl0oL1VzZXJzL3ppYy9EZXNrdG9wL2dvb2dsZV9nYW1lX21pbmluZy9wMS5wbmcpCgros4fmlpnmipPlj5bmlrnlvI88YnIvPgrlj4PogIPvvJpbR29vZ2xlUGxheS1SZXZpZXctQ3Jhd2xlcl0oaHR0cHM6Ly9naXRodWIuY29tL3lhbmdjaGVueGkvR29vZ2xlUGxheS1SZXZpZXctQ3Jhd2xlcikK5L2/55So5pa55byP5aaC5LiL5ZyWPGJyLz4KIVthdmF0YXJdKC9Vc2Vycy96aWMvRGVza3RvcC9nb29nbGVfZ2FtZV9taW5pbmcvcDMucG5nKQoKIyBDLiDos4fmlpnnmoTliIbmnpDpgY7nqIsKIyBELiDoppboprrljJbnmoTliIbmnpDntZDmnpzoiIfop6Pph4sKCiMjIOezu+e1seWPg+aVuOioreWumgpgYGB7cn0KU3lzLnNldGxvY2FsZShjYXRlZ29yeSA9ICJMQ19BTEwiLCBsb2NhbGUgPSAiemhfVFcuVVRGLTgiKSAjIOmBv+WFjeS4reaWh+S6gueivApgYGAKCiMjIOWuieijnemcgOimgeeahHBhY2thZ2VzCmBgYHtyfQpwYWNrYWdlcyA9IGMoInRpZHl0ZXh0IiwiZHBseXIiLCAiamllYmFSIiwgInN0cmluZ3IiLCAid29yZGNsb3VkMiIsICJnZ3Bsb3QyIiwgInRpZHlyIiwgIk5MUCIsICJnZ3JhcGgiKQpleGlzdGluZyA9IGFzLmNoYXJhY3RlcihpbnN0YWxsZWQucGFja2FnZXMoKVssMV0pCmZvcihwa2cgaW4gcGFja2FnZXNbIShwYWNrYWdlcyAlaW4lIGV4aXN0aW5nKV0pIGluc3RhbGwucGFja2FnZXMocGtnKQpgYGAKCiMjIOi8ieWFpeWll+S7tgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGppZWJhUikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHdvcmRjbG91ZDIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5cikgIyBzcHJlYWQKbGlicmFyeShOTFApICMgbmdyYW1zCmxpYnJhcnkoZ2dyYXBoKSAjIGJpZ3JhbSBuZXR3b3JrCmBgYAoKIyMg6Kit5a6a5bel5L2c55uu6YyEICjmlrnkvr/kuYvlvozoroDmqpTmlLnnm7jlsI3ot6/lvpHmkrDlr6spCmBgYHtyfQpzZXR3ZCgiL1VzZXJzL3ppYy9EZXNrdG9wL2dvb2dsZV9nYW1lX21pbmluZyIpCmNoaV90ZXh0X3RoZW1lID0gdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkgIyDlrprnvqnkuK3mloflrZfkuLvpoYwKYGBgCgojIyDoroDlj5bmiYDmnInos4fmlpnmqpQKYGBge3J9CmZpbGVzID0gbGlzdC5maWxlcygiLi9kYXRhL0dvb2dsZVBsYXlHYW1lcyIsIGZ1bGwubmFtZXM9VCkgIyDliJflh7rmiYDmnInos4fmlpnmqpQKZGF0YS5saXN0ID0gbGFwcGx5KGZpbGVzLCBmdW5jdGlvbih4KSB7CiAgZGYgPSByZWFkLmNzdih4LCBzdHJpbmdzQXNGYWN0b3JzID0gRikgIyDoroDlj5bos4fmlpnmqpQKICBkZiRnYW1lVGl0bGUgPSBiYXNlbmFtZSh4KSAjIOWwh+aqlOahiOWQjeeoseimlueCumdhbWVUaXRsZQogIHJldHVybihkZikKICB9KQpzb3VyY2VfZGYgPSBkby5jYWxsKCJyYmluZCIsIGRhdGEubGlzdCkgIyDlkIjkvbXos4fmlpnoh7NkZgoKIyDmrITkvY3mlbTnkIYKc291cmNlX2RmJGdhbWVUaXRsZSA9IHN0cl9yZXBsYWNlKHNvdXJjZV9kZiRnYW1lVGl0bGUsICJyZXN1bHRfIiwgIiIpICMg5Y675o6J5YmN57a0CnNvdXJjZV9kZiRnYW1lVGl0bGUgPSBzdHJfcmVwbGFjZShzb3VyY2VfZGYkZ2FtZVRpdGxlLCAiLmNzdiIsICIiKSAjIOWOu+aOieWJr+aqlOWQjQpzb3VyY2VfZGYgPSBzZXBhcmF0ZShzb3VyY2VfZGYsIGdhbWVUaXRsZSwgYygiZ2FtZVJhbmsiLCAiZ2FtZVRpdGxlIiksIHNlcCA9ICJfIiwgY29udmVydCA9IFRSVUUpCnNvdXJjZV9kZiRkYXRlID0gYXMuRGF0ZShzb3VyY2VfZGYkZGF0ZSwgIiVZ5bm0JW3mnIglZOaXpSIpCnNvdXJjZV9kZiRnYW1lUmFuayA9IGFzLmZhY3Rvcihzb3VyY2VfZGYkZ2FtZVJhbmspICMg6L2J5oiQZmFjdG9y77yM5LmL5b6M5ZyW5b2i57mq6KO95pmC6aGP6Imy5q+U6LyD5YiG6ZaLCnNvdXJjZV9kZiRyYXRpbmdzID0gYXMuZmFjdG9yKHNvdXJjZV9kZiRyYXRpbmdzKQoKIyDos4fmlpnmuIXnkIYKZGF0YV9jbGVhbmVkID0gc291cmNlX2RmICU+JQogIG11dGF0ZShjb21tZW50ID0gc3RyX3JlcGxhY2UoY29tbWVudCwgIihodHRwfGh0dHBzKTovLy4qIiwgIiIpKSAlPiUgIyDljrvpmaTntrLlnYAKICBtdXRhdGUoY29tbWVudCA9IHN0cl9yZXBsYWNlX2FsbChjb21tZW50LCAiW++8iCAwLTkuJe+8iV0rIiwiICIpKSAlPiUgIyDljrvpmaTmlbjlrZcKICBtdXRhdGUoY29tbWVudCA9IHN0cl9yZXBsYWNlX2FsbChjb21tZW50LCAiWyAgPyEuICwnXSsiLCIgIikpICU+JSAjIOWOu+mZpOaomem7nuespuiZnwogIG11dGF0ZShjb21tZW50ID0gc3RyX3JlcGxhY2VfYWxsKGNvbW1lbnQsICJcXHMrIiwiICIpKSAlPiUgIyDljrvpmaTpgKPnuoznqbrnmb0KICBmaWx0ZXIobmNoYXIoY29tbWVudCkgPiAwKQoKZGF0YV9jbGVhbmVkCmBgYAoKPiDos4fmlpnmrITkvY3oqqrmmI48YnIvPgo+IG5hbWU6IOeVmeipleirlueahOeOqeWutuWQjeeosTxici8+Cj4gcmF0aW5nczog55WZ6KmV6KuW5pmC57Wm55qE5pif6KmVPGJyLz4KPiBkYXRlOiDnlZnoqZXoq5bnmoTmmYLplpM8YnIvPgo+IGhlbHBmdWwudm90ZTog5aSa5bCR5Lq65bCN5q2k6KmV6KuW5oyJ6K6aPGJyLz4KPiBjb21tZW50OiDoqZXoq5blhaflrrk8YnIvPgohW2F2YXRhcl0oL1VzZXJzL3ppYy9EZXNrdG9wL2dvb2dsZV9nYW1lX21pbmluZy9wMi5wbmcpCgojIyDmqqLoppblkITpgYrmiLLnmoToqI7oq5bmlbjph48sIOWPiuizh+aWmeWNgOmWkwpgYGB7cn0KZGF0YV9jbGVhbmVkICU+JQogIGNvdW50KGdhbWVSYW5rKSAlPiUKICBnZ3Bsb3QoYWVzKGdhbWVSYW5rLCBuKSkgKwogIGdlb21fY29sKCkgKwogIHlsYWIoImNvdW50IikgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gMToxMikgKwogIGNoaV90ZXh0X3RoZW1lCgojIOaqouimluizh+aWmeWNgOmWkwpkYXRhLmZyYW1lKAogIG1pbkRhdGUgPSBtaW4oc291cmNlX2RmJGRhdGUpLAogIG1heERhdGUgPSBtYXgoc291cmNlX2RmJGRhdGUpKQpgYGAKCj4g5LiK5ZyW5Lit77yMeCDou7jngrrmjpLooYzmppzlkI3mrKHvvIx5IOi7uOeCuuipleirluaVuOmHjzxici8+Cj4g55Sx5LiK5ZyW55yL5L6G77yM6YGK5oiy55qE6KmV6KuW5pW46YeP6IiH5o6S6KGM5qac5ZCN5qyh5Lim54Sh5piO6aGv6Zec5L+C44CCPGJyLz4KPiDmlbTku73pgYrmiLLos4fmlpnljYDplpPngroyMDE5LTAzLTI4IOiHsyAyMDE5LTA0LTE5CgojIyDmupblgplqaWViYSDmlrfoqZ7lh73lvI8K55Sx5pa86LOH5paZ5pyJ5Lit5paHL+iLseaWh++8jOaVheaOoWppZWJhIOmAsuihjOaWt+ipnih1bm5lc3RfdG9rZW4pCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmppZWJhX3Rva2VuaXplciA9IHdvcmtlcigpCiMg5YuV5oWL5paw5aKe6Ieq6KiC6Kme5b2ZCm5ld191c2VyX3dvcmQoamllYmFfdG9rZW5pemVyLCBjKCIiKSkKIyDlrprnvqnmlrfoqZ7lh73lvI8KY2hpX3Rva2VuaXplciA8LSBmdW5jdGlvbih0KSB7CiAgbGFwcGx5KHQsIGZ1bmN0aW9uKHgpIHsKICAgIHRyeUNhdGNoKHsKICAgICAgdG9rZW5zIDwtIHNlZ21lbnQoeCwgamllYmFfdG9rZW5pemVyKQogICAgICB0b2tlbnMgPC0gdG9rZW5zW25jaGFyKHRva2Vucyk+MV0KICAgICAgcmV0dXJuKHRva2VucykKICAgIH0sCiAgICAjIOmBh+WIsCBlcnJvciDmmYLnmoToh6roqILomZXnkIblh73mlbgKICAgIGVycm9yID0gZnVuY3Rpb24obXNnKSB7CiAgICAgIG1lc3NhZ2UoeCkKICAgICAgcmV0dXJuKE5BKQogICAgfSkKICB9KQp9CmBgYAoKCiMjIOmAj+mBjuiHquWumue+qeeahGppZWJhIOmAsuihjOWwjeizh+aWmemAsuihjHVubmVzdOOAgui9ieaIkHRpZHkg5qC85byPCmBgYHtyfQp0b2tlbnMgPSBkYXRhX2NsZWFuZWQgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgY29tbWVudCwgdG9rZW49Y2hpX3Rva2VuaXplcikKYGBgCgojIyDnuaroo73lh7rnj77mrKHmlbjovIPpq5jnmoToqZ4KYGBge3J9CnRva2VucyAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgJT4lICMg6KiI566X6Kme6aC7CiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICB0b3BfbigyMCwgbikgJT4lCiAgZ2dwbG90KGFlcyh3b3JkLCBuKSkgKwogIGdlb21fY29sKCkgKwogIHhsYWIoTlVMTCkgKwogIGNoaV90ZXh0X3RoZW1lICsgCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMg6YCP6YGO5paH5a2X6Zuy6KeA5a+f5pa36Kme57WQ5p6cCmBgYHtyfQp0b2tlbnMgJT4lCiAgY291bnQod29yZCkgJT4lCiAgZmlsdGVyKG4gPiAyNSkgJT4lCiAgd29yZGNsb3VkMihzaXplID0gLjYpICMgc2l6ZT0uOCwg6YG/5YWN5Zyocm5vdGVib29rIOS4remBjuWkp+eahOaWh+Wtl+acqua4suafkwpgYGAKCj4g5b6e5LiK6L+w57WQ5p6c55yL5L6G44CM6YGK5oiy44CN5ZKM44CM5aW9546p44CN5piv5YWp5YCL5Ye654++5pyA6auY55qE6Kme77yM5Ymb5aW96LefR29vZ2xlIFBsYXkg6YGK5oiy5oeJ55So56iL5byP55qE5Li76KaB6ZaL55m86Ki05rGC5LiA5qij44CQ6K6T6YGK5oiy6K6K5b6X5pu05aW9546p77yB44CRIDxici8+Cj4g5pW06auU6ICM6KiA77yMIOaykuacieWHuuePvuW+iOWlh+aAqueahOipnu+8jOS9huacieS4gOS6m+WmgiLlnIvml5ciLCAi5Lit5ZyL5rCR5ZyLIiwgIuS4reWciyLvvIzkvLzkuY7ot5/mlL/msrvmnInkupvpl5zkv4IgPGJyLz4KPiDlvp7ljp/oqZXoq5bkuK3mn6XnnIvvvIzlj6/ku6Xnmbznj77mraTpoZ7oqZ7lpKflpJrlh7rnj77mlrwi57WV5Zyw5rGC55SfTSLmraTmrL7pgYrmiLLvvIzpgYrmiLLliIbngrrlnIvpmpvniYjoiIflj7DngaPniYjvvIzpg6jliIboqI7oq5bngrrmraTnm7jpl5zorbDpoYzjgIIKCiMjIOa6luWCmUxJV0PlrZflhbgKYGBge3J9CnBvc2l0aXZlID0gc2NhbihmaWxlID0gIi4vZGF0YS9kaWN0L2xpd2MvcG9zaXRpdmUudHh0Iiwgd2hhdD1jaGFyYWN0ZXIoKSwgc2VwPScsJywgCiAgICAgICAgICAgICAgICAgZW5jb2Rpbmc9J3V0Zi04JyxmaWxlRW5jb2Rpbmc9J3V0Zi04JykKbmVnYXRpdmUgPSBzY2FuKGZpbGUgPSAiLi9kYXRhL2RpY3QvbGl3Yy9uZWdhdGl2ZS50eHQiLCB3aGF0PWNoYXJhY3RlcigpLCBzZXA9JywnLCAKICAgICAgICAgICAgICAgICBlbmNvZGluZz0ndXRmLTgnLGZpbGVFbmNvZGluZz0ndXRmLTgnKQpwb3NpdGl2ZSA9IGRhdGEuZnJhbWUod29yZCA9IHBvc2l0aXZlLCBzZW50aW1lbnQgPSAicG9zaXRpdmUiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCm5lZ2F0aXZlID0gZGF0YS5mcmFtZSh3b3JkID0gbmVnYXRpdmUsIHNlbnRpbWVudCA9ICJuZWdhdGl2ZSIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKbGl3Y19jaCA9IHJiaW5kKHBvc2l0aXZlLCBuZWdhdGl2ZSkgJT4lIAogIGZpbHRlcih3b3JkICE9ICLpgYrmiLIiKQpgYGAKCiMjIOe5quijveavj+WAi+mBiuaIsu+8jOato+iyoOaDhee3kuWtl+aOkuihjOWclgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp0b2tlbnMgJT4lCiAgaW5uZXJfam9pbihsaXdjX2NoKSAlPiUKICBncm91cF9ieShnYW1lVGl0bGUsIHNlbnRpbWVudCkgJT4lICMg576k57WE5YyW5b6M77yM5q2j6LKg6LOH5paZ5ZCE5Y+WbuethgogIGNvdW50KHdvcmQsIHNvcnQgPSBUKSAlPiUKICB0b3Bfbig1KSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKG4gPSBpZmVsc2Uoc2VudGltZW50ID09ICJwb3NpdGl2ZSIsIDEsIC0xKSAqIG4pICU+JSAjIOiyoOmdouaDhee3kui9ieaIkC1uCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBnYW1lVGl0bGUpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofmdhbWVUaXRsZSwgc2NhbGVzID0gImZyZWUiKSArCiAgbGFicyh5ID0gIkNvbnRyaWJ1dGlvbiB0byBzZW50aW1lbnQiLCB4ID0gTlVMTCkgKwogIGNoaV90ZXh0X3RoZW1lICsgCiAgY29vcmRfZmxpcCgpICAKYGBgCgo+IOeUseS4iuWclueci+S+hu+8jOWkp+mDqOS7vemBiuaIsuS4re+8jOeOqeWutuipleirluato+mdouaDhee3kueahOaVuOmHj+mBoOWkp+aWvOiyoOmdouaDhee3kgoKIyMg57mq6KO95q+P5YCL6YGK5oiy77yM5L6d5pel5pyf5o6S5bqP5LmL5oOF57eS6K6K5YyWCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnRva2Vuc19nYW1lX3NlbnRpbWVudCA9IHRva2VucyAlPiUKICBpbm5lcl9qb2luKGxpd2NfY2gpICU+JQogIGdyb3VwX2J5KGdhbWVSYW5rKSAlPiUKICBjb3VudChkYXRlLCBzZW50aW1lbnQpICU+JSAjIOagueaTmuaXpeacnyArIOaDhee3ku+8jOioiOeul+asoeaVuAogIHNwcmVhZChzZW50aW1lbnQsIG4pICU+JSAjIOWxlemWi+ashOS9jQogIG11dGF0ZShwb3NpdGl2ZSA9IHJlcGxhY2VfbmEocG9zaXRpdmUsIDApKSAlPiUgIyDlj5bku6NuYSDngrowCiAgbXV0YXRlKG5lZ2F0aXZlID0gcmVwbGFjZV9uYShuZWdhdGl2ZSwgMCkpICU+JQogIG11dGF0ZShzZW50aW1lbnQgPSBwb3NpdGl2ZSAtIG5lZ2F0aXZlKSAlPiUgIyDoqIjnrpfmraPosqDmg4Xnt5IKICB1bmdyb3VwKCkgCgp0b2tlbnNfZ2FtZV9zZW50aW1lbnQKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIOeUseaWvOmDqOS7vemBiuaIsueahOizh+aWmei8g+Wwke+8jOeVq+mdouWQjOS4gOW8teWcluS4puS4jeWuueaYk+ino+iugAojIOaVheWQhOWclue5quijveS4gOW8tQp0b2tlbnNfZ2FtZV9zZW50aW1lbnQgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoeCA9IGRhdGUsIHkgPSBzZW50aW1lbnQsIGNvbG91cj1nYW1lUmFuaykpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJW0lZCIpICsKICBmYWNldF93cmFwKH5nYW1lUmFuaywgc2NhbGVzID0gImZyZWUiKSArCiAgY2hpX3RleHRfdGhlbWUgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCj4g5LiK5ZyW5Lit77yM6YOo5Lu96YGK5oiy55qE6KmV6KuW5qW15LiN5bmz5Z2HKOWmgjIsIDQsIDcsIDExLCAxMikg562JPGJyLz4KPiDku6U3Leebm+WUkOW5u+WknOS+huafpeeci++8jDQvMTflm6DngrrmnInkurrnmbzluIMt5Lmd5aSn6IG35qWt5pS755Wl5LuL57S544CB6KeS6Imy5a6a5L2N44CB6YGK5oiy5LuL57S555qE5b2x54mH77yM5Zug5q2k5o6o5pa35pyJ5Y+v6IO95q2k6YGK5oiy5LiK5p62KOmWi+aUvinlvozvvIznjqnlrrbmiY3kuIrljrvnlZnoqIDvvIzpgKDmiJDml6XmnJ/mjpLluo/kuYvmg4Xnt5LororljJbvvIzlhaflrrnmpbXkuI3lubPlnYfjgIIKCiMjIOS4jeWIhumBiuaIsueahOaDheazgeS4i++8jOaYn+ipleWwjeaHieeahOaDhee3kuWtlwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp0b2tlbnNfcmF0aW5ncyA9IHRva2VucyAlPiUKICBpbm5lcl9qb2luKGxpd2NfY2gpICU+JSAjIOWPquS/neeVmei3n+aDhee3kuebuOmXnOeahOipngogIGdyb3VwX2J5KHJhdGluZ3MpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUKSAlPiUKICB0b3BfbigxMCwgbikgJT4lIAogIHVuZ3JvdXAoKSAlPiUKICBpbm5lcl9qb2luKGxpd2NfY2gpICU+JSAjIOe1hOWQiOWHunNlbnRpbWVudAogIG11dGF0ZShzY29yZSA9IGlmZWxzZShzZW50aW1lbnQgPT0gInBvc2l0aXZlIiwgMSwgLTEpICogbikgJT4lICMg5qC55pOac2VudGltZW50IOeul+WHuuWIhuaVuAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBzY29yZSkpICMg5qC55pOa5YiG5pW46YCy6KGM5o6S5YiXCnRva2Vuc19yYXRpbmdzCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyDmr4/lgIvnvqTntYQocmF0aW5ncykg57mq6KO95LiA5by15ZyWCnRva2Vuc19yYXRpbmdzICU+JQogIGdncGxvdChhZXMoeCA9IHdvcmQsIHNjb3JlLCBmaWxsID0gcmF0aW5ncykpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+cmF0aW5ncywgc2NhbGVzID0gImZyZWUiKSArCiAgbGFicyh5ID0gIlNjb3JlPUNvdW50KlNlbnRpbWVudCIsIHggPSBOVUxMKSArCiAgY2hpX3RleHRfdGhlbWUgKwogIGNvb3JkX2ZsaXAoKSAgCmBgYAoKPiDlvp7kuIrlnJblj6/ku6XnnIvlh7rlkITmmJ/oqZXkuK3vvIzovIPluLjlh7rnj77nmoToqZ4KPiDmmJ/oqZXkvY7nmoTmg4Xms4HkuIvvvIzmraPosqDpnaLmg4Xnt5LnmoToqZ7lh7rnj77nmoTmrKHmlbjovIPngrrmjqXov5HvvJsKPiDmmJ/oqZXotorpq5jnmoTmg4Xms4HkuIvvvIzosqDpnaLmg4Xnt5LnmoToqZ7lh7rnj77nmoTlsJHjgIIKCiMjIOmAj+mBjnRmLWlkZiDkvobmqqLoppboqZ7nmoTliIbkvYgKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2FtZV93b3JkcyA9IHRva2VucyAlPiUKICBjb3VudChnYW1lUmFuaywgd29yZCwgc29ydCA9IFRSVUUpCgp0b3RhbF93b3JkcyA9IGdhbWVfd29yZHMgJT4lIAogIGdyb3VwX2J5KGdhbWVSYW5rKSAlPiUKICBzdW1tYXJpemUodG90YWwgPSBzdW0obikpCgpnYW1lX3dvcmRzID0gbGVmdF9qb2luKGdhbWVfd29yZHMsIHRvdGFsX3dvcmRzKQoKIyDoqIjnrpd0Zi1pZGYKZ2FtZV93b3JkcyA9IGdhbWVfd29yZHMgJT4lCiAgYmluZF90Zl9pZGYod29yZCwgZ2FtZVJhbmssIG4pCgojIOe5quijvei8g+mrmHRmLWlkZgojIOeUseaWvOizh+aWmemHj+aToOWcqOWQjOS4gOW8teWcluS4iuWkquWvhu+8jOWIhuWkmuasoee5quijvQpoaWdoX3RmX2lkZiA9IGdhbWVfd29yZHMgJT4lCiAgYXJyYW5nZShkZXNjKHRmX2lkZikpICU+JQogIG11dGF0ZSh3b3JkID0gZmFjdG9yKHdvcmQsIGxldmVscyA9IHJldih1bmlxdWUod29yZCkpKSkgJT4lIAogIGdyb3VwX2J5KGdhbWVSYW5rKSAlPiUgCiAgdG9wX24oMTApICU+JSAKICB1bmdyb3VwKCkKaGlnaF90Zl9pZGYKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwYWludF90Zl9pZGYgPSBmdW5jdGlvbihkYXRhKSB7CiAgZGF0YSAlPiUKICAgIGdncGxvdChhZXMod29yZCwgdGZfaWRmLCBmaWxsID0gZ2FtZVJhbmspKSArCiAgICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBsYWJzKHggPSBOVUxMLCB5ID0gInRmLWlkZiIpICsKICAgIGZhY2V0X3dyYXAofmdhbWVSYW5rLCBuY29sID0gMiwgc2NhbGVzID0gImZyZWUiKSArCiAgICBjaGlfdGV4dF90aGVtZSArCiAgICBjb29yZF9mbGlwKCkgCn0KCnBhaW50X3RmX2lkZigKICBoaWdoX3RmX2lkZiAlPiUKICAgIGZpbHRlcihnYW1lUmFuayAlaW4lIDE6NCkKKQoKcGFpbnRfdGZfaWRmKAogIGhpZ2hfdGZfaWRmICU+JQogICAgZmlsdGVyKGdhbWVSYW5rICVpbiUgNTo4KQopCgpwYWludF90Zl9pZGYoCiAgaGlnaF90Zl9pZGYgJT4lCiAgICBmaWx0ZXIoZ2FtZVJhbmsgJWluJSA5OjEyKQopCmBgYAoKPiDkuIrov7Az5by15ZyW77yM5ZGI54++5ZCE6YGK5oiy5YWn77yM6LyD6auY55qEdGYtaWRmIOWAvOS5i+WwjeaHieaWh+Wtlwp0ZiDlgLzmhIjpq5jvvIzlhbbllq7oqZ7mhIjph43opoHvvIzlsLE3LeOAiuebm+WUkOW5u+WknOOAi+S+huiqquWFtueCuuWkp+mmrOWls+aYn+ael+aYjuemjuaTlOS7u+mBiuaIsuS7o+iogOS6uu+8jOmBiuaIsuaYr+S7peWQjOWQjembu+imluWKh+OAiuebm+WUkOW5u+WknOOAi+eCuuWfuuekjuaJk+mAoOeahOmBiuaIsuOAguaZguS7o+iDjOaZr+ioreWumueCuuS4reWci+att+WPsuS4iuacgOe5geiPr+eahOWUkOacne+8jOeOqeWutuWcqOmBiuaIsuS4reaEn+WPl+Wkp+WUkOebm+S4luiIh+W+oeWKjemjm+ihjOetieaogui2o+OAgueOqeWutuiIh+WkpeS8tOS4gOatpeatpeaPremWi+WUkOS7o+aHuOW5u+mbouWlh+eahOelnuenmOmdoue0l++8m+atpOasvumBiuaIsuiuk+eOqeWutuWPr+S7peaUtumbhuecvuinkuiJsu+8jOaIkOeCuuiHquW3semXluiVqeebm+WUkOaxn+a5lueahOWlveW5q+aJi+OAgumBiuaIsuWFseacieS5neWkp+iBt+alre+8jOWboOatpOOAjOaYjuemjuOAjeOAgeOAjOiBt+alreOAjeOAgeOAjOaRuOe0ouOAjeebuOWwjeaWvOaDhee3kuipnuS+huiqquaYr+aZrumBjeaciei8g+mrmOeahHRmLWlkZiDlgLzjgIIKCiMjIFRvcGljIE1vZGVsaW5nCmBgYHtyfQojIOS7peS4jeWIhumBiuaIsueahOaDheazgeS4i++8jOmAsuihjOeOqeWutuipleirlueahOS4u+mhjOafpeaJvgpsZGEgPSB0b2tlbnMgJT4lIAogICMgZHRtIOi9ieaPm+mcgOimgTPlgIvmrITkvY3vvJpkb2N1bWVudCwgdGVybSwgY291bnQKICBtdXRhdGUoYXJ0SWQgPSBncm91cF9pbmRpY2VzKC4sIG5hbWUpKSAlPiUgIyDmupblgpljYXN0X2R0bemcgOimgeeahOashOS9jQogIGNvdW50KGFydElkLCB3b3JkKSAlPiUgIyDmupblgpljYXN0X2R0bemcgOimgeeahOashOS9jQogIGNhc3RfZHRtKGFydElkLCB3b3JkLCBuKSAlPiUgIyDovYnmiJBkdG0KICB0b3BpY21vZGVsczo6TERBKGsgPSA2LCBjb250cm9sID0gbGlzdChzZWVkID0gMTIzNCkpICMg6KiI566XTERBCmxkYQpgYGAKCmBgYHtyfQojIFdvcmQtdG9waWMgcHJvYmFiaWxpdGllcwp0b3BpY3MgPSB0aWR5KGxkYSwgbWF0cml4ID0gImJldGEiKSAjIOS4u+mhjC3llq7lrZfnmoTmqZ/njocKCnRvcGljcwpgYGAKCmBgYHtyfQojIOe5quijveavj+WAi+S4u+mhjOeahOW4uOimi+WWruWtlwp0b3BfdGVybXMgPSB0b3BpY3MgJT4lCiAgZ3JvdXBfYnkodG9waWMpICU+JQogIHRvcF9uKDE4LCBiZXRhKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpCgp0b3BfdGVybXMKYGBgCgpgYGB7cn0KdG9wX3Rlcm1zICU+JQogIG11dGF0ZSh0ZXJtID0gcmVvcmRlcih0ZXJtLCBiZXRhKSkgJT4lCiAgZ2dwbG90KGFlcyh0ZXJtLCBiZXRhLCBmaWxsID0gZmFjdG9yKHRvcGljKSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKSArICAKICBjb29yZF9mbGlwKCkKYGBgCgo+IOWcqOS4u+mhjOWIh+WIhuaZgu+8jOeUqDLvvIw077yMNuWAi+S4u+mhjOeahOaDheazgeS4i++8m+WQhOS4u+mhjOS8vOS5jueci+S4jeWHuuS+hui8g+eCuuaYjumhr+eahOW3rueVsOOAgjxici8+Cj4g54yc5ris5piv55Sx5pa86KiO6KuW55qE5YWn5a656aGe5Ly85bqm5aSq6auYPGJyLz4KPiDlm6DogIzmspLmnInmmI7poa/nmoTkuLvpoYzlt67nlbAKCiMgRS4g57WQ6KuWCue4vee1kOS7peS4iueahOWIhuaekO+8jOaIkeWAkeWPr+S7peW+l+WIsOS7peS4i+e1kOirlu+8mjxici8+CjEpIEdvb2dsZSBQbGF5IFN0b3Jl5Lit6YGK5oiy55qE6KmV6KuW5pW46YeP6IiH5o6S6KGM5qac5ZCN5qyh5Lim54Sh5piO6aGv6Zec5L+C44CCPGJyLz4KPGJyLz4KMikg5aSn6YOo5Lu96YGK5oiy5Lit77yM546p5a626KmV6KuW5q2j6Z2i5oOF57eS55qE5pW46YeP6YGg5aSn5pa86LKg6Z2i5oOF57eSPGJyLz4KPGJyLz4KMykgR29vZ2xlUGxheSDnmoToqZXoq5bvvIzpgYrmiLLmm7TniYjlvozku43nhLbkv53nlZnvvJvoqZXoq5blv4XpoIjlnKjoqbLljYDkuIvovInpgYrmiLLlvoznjqnlrrbmiY3og73kuIrljrvnlZnoqIDvvIzlm6DmraTmnIPpgKDmiJDml6XmnJ/mjpLluo/kuYvmg4Xnt5LororljJbvvIzlhaflrrnmpbXkuI3lubPlnYfjgII8YnIvPgo8YnIvPgo0KeS4gOiIrOS+huiqqueUqOaItuabtOWCvuWQkeaWvOS4i+i8ieipleirluWkmueahGFwcOOAguipleirluiDveWkoOS/g+mAsuS4i+i8iemHj+eahOaPkOWNh+OAgumBiuaIsuWbnumli+S4jeS4gO+8jDUw77yF54K65q2j6Z2i77yMNTDvvIXngrrosqDpnaLlm57ppYvjgILlm6DmraTlnKjoqZXoq5blhY3osrthcHDogIzpnZ7ku5josrvmh4nnlKjnqIvlvI/mmYLvvIzkuZ/oqLHkvb/nlKjogIXororlvpfmm7TliqDoi5vliLs8YnIvPgo8YnIvPgo8YnIvPgrnpL7nvqTou5/pq5Tml6XmvLjngrrmt7HlhaXkurrlgJHnmoTml6XluLjnlJ/mtLvvvIzogIzpgYrmiLLnmoTnpL7nvqTmm7TmmK/lpoLmraTjgILpmqjokZfkuIDlgIvpgYrmiLLnmoTmjqjlh7rvvIzluLbkvobnmoTmmK/lpKfph4/nmoTliIbmnpDmlbjmk5rlkoznjqnlrrboqZXoq5bvvIzmnInnmoTmmK/nnJ/mraPnmoTmraPpnaLoqZXlg7nvvIzoqZXoq5blvJXkurrlhaXli53nmoTpgYrmiLLliofmg4XjgIHpm4TlgYnlo6/pl4rnmoTpgYrmiLLloLTmma/nrYnjgILmnInnmoTliYfmmK/osqDpnaLoqZXlg7nvvIzoq5bov7DokZfpgYrmiLLnmoTnvLrpu57lj4rns7vntbHpjK/oqqTomZXnrYnnoLTlo57pgYrmiLLpq5TpqZfnmoTnqK7nqK7jgILmnInnmoTliYfmmK/nnIvkvLzkuK3mgKfnmoToqZXoq5bvvIznnIvkvLzlrqLop4DnmoTnnIvms5Xog4zlvozvvIzluLbmnInoq7fliLrvvIzmmpfllrvnrYnkuLvop4Dmg4Xnt5LjgII8YnIvPiDkuIrov7DpgJnkupvoqIDoq5blsI3mtojosrvogIXjgIHpgYrmiLLnmoTplovnmbzllYblj4rnh5/pgYvllYbkvoboqqrmnInokZfkuIDlrprnmoTlj4PogIPlg7nlgLzvvIzntZDlkIjlhbbku5bmnInpl5zmlbjmk5rvvIzlpoLmmJ/ntJrjgIHoqZXoq5blhaflrrnjgIHmg4Xnt5LlrZfnmoTlsI3mh4nnrYnpgLLooYzliIbmnpDvvIzmm7Tlj6/ku6XlvpfliLDlhajmlrnkvY3nmoTovL/oq5bmqqLmuKzjgII8YnIvPgoKCg==