動機與分析目的

因為最近網紅是個很熱門的職業,不管老幼婦孺,只要敢展現自我、發揮創意,人人都有機會成為網紅。我們想探討以“館長”這個人格特質很突出,又在ptt討論熱度很高的網紅,是留給人們什麼的印象,他又在討論什麼才會引起大家那麼多的關注。

前置作業

資料取得及套件載入

載入的資料是由中山大學管理學院文字分析平台取得,在平台資料選擇下載原始資料所取得之csv檔案。

資料簡介

本資料為2019/01/01 ~ 2019/04/12 PTT八卦版之資料,透過文字分析平台檢索「館長」、「陳之漢」兩個關鍵字,共搜尋到646篇文章。

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("dplyr", "tidytext", "jiebaR", "gutenbergr", "stringr", "wordcloud2", "ggplot2", "tidyr", "scales", "widyr", "readr", "reshape2", "NLP", "ggraph", "igraph", "tm", "data.table", "quanteda", "Matrix", "slam", "Rtsne", "randomcoloR", "wordcloud", "topicmodels", "LDAvis", "webshot", "htmlwidgets","servr")
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)
require(dplyr)
require(tidytext)
require(jiebaR)
require(gutenbergr)
require(stringr)
require(wordcloud2)
require(ggplot2)
require(tidyr)
require(scales)
require(widyr)
require(readr)
require(reshape2)
require(NLP)
require(ggraph)
require(igraph)
require(tm)
require(data.table)
require(quanteda)
require(Matrix)
require(slam)
require(Rtsne)
require(randomcoloR)
require(wordcloud)
require(topicmodels)
require(LDAvis)
require(webshot)
require(htmlwidgets)
require(servr)

資料載入

g_csv <- fread("guan_jang_data.csv", encoding = "UTF-8", header = TRUE)
g_csv <- g_csv %>% 
  filter(artUrl != "https://www.ptt.cc/bbs/Gossiping/M.1547888391.A.836.html")
g_csv$artDate = g_csv$artDate %>% as.Date("%Y/%m/%d")

預覽資料

head(g_csv)

日期折線圖

計算出每一天文章的發表數量,看出討論「館長」的熱度。

資料處理

g_date <- g_csv %>% 
  select(artDate, artUrl) %>% 
  distinct()
article_count_by_date <- g_date %>% 
  group_by(artDate) %>% 
  summarise(count = n())
article_count_by_date %>% 
  arrange(desc(count))%>% 
  top_n(10)
Selecting by count

討論篇數最多的前10天。

date_plot <- article_count_by_date %>% 
  ggplot(aes(x = artDate, y = count)) +
  geom_line(color = "purple", size = 1.5) + 
  geom_vline(xintercept = c(as.numeric(as.Date("2019-01-05")),
                            as.numeric(as.Date("2019-01-16")),
                            as.numeric(as.Date("2019-03-04")),
                            as.numeric(as.Date("2019-03-10")), 
                            as.numeric(as.Date("2019-04-09"))), col='red', size = 1) + 
  scale_x_date(labels = date_format("%Y/%m/%d")) +
  ggtitle("「館長」討論文章數") + 
  xlab("日期") + 
  ylab("數量") +
  theme(text = element_text(family = "Heiti TC Light"))
date_plot

從上圖中可以看到關於「館長」的討論在1/05, 1/16, 3/04, 3/10, 4/09 出現高點。
1/05: [問卦]館長嘴斷食,究竟哪邊對? [爆卦]館長:肏你媽有種現在就打過來啦
1/16: [新聞]館長促阿北2020選總統 柯P:我要再想想 [爆卦]館長正在跟柯文哲直播談虐童案
3/04: [新聞]「叫小賀!」孫安佐單挑館長影片曝光眼 [問卦]館長打得贏甄子丹嗎
3/07: 館長:統促黨3/10號要來林口館罵三字經!!!
3/10: [問卦]館長譙統促黨髒話本來就理虧,不是嗎? [新聞]統促黨嗆館長打一場 「簽生死狀,條件你
4/09: [新聞]與館長談統獨賴清德:統一就像斯斯有兩 [新聞]館長對決美國智庫?蔡賴今晚熱身賽

文字雲

接下來我們來大略觀察討論的內容為何,使用的方式為文字雲。

斷詞、停用詞使用

jieba_tokenizer <- worker(user="k_dict.txt", stop_word = "stop_words.txt")
g_tokenizer <- function(t) {
  lapply(t, function(x) {
    tokens <- segment(x, jieba_tokenizer)
    tokens <- tokens[nchar(tokens)>1]
    return(tokens)
  })
}
g_tokens <- g_csv %>% 
  unnest_tokens(word, sentence, token=g_tokenizer) %>% 
  select(-artTime, -artUrl)
g_tokens_count <- g_tokens %>% 
  group_by(word) %>% 
  summarise(sum = n()) %>% 
  arrange(desc(sum))
head(g_tokens_count)

結果為詞出現最多的字。

移除「館長」

wordc_plot <- g_tokens_count %>% 
  filter(word != "館長") %>% 
  filter(sum > 20) %>% 
  wordcloud2()
wordc_plot

長條圖

長條圖可以查看精確的「最常出現詞彙」。

查看篇數最多的五天中,最常出現的詞彙。

g_tokens_by_date <- g_tokens %>% 
  count(artDate, word, sort = TRUE)
  
plot_merge <- g_tokens_by_date %>% 
  filter(word != "館長" & word != "直播") %>% 
  filter(artDate == as.Date("2019-01-05") | 
         artDate == as.Date("2019-01-16") | 
         artDate == as.Date("2019-03-04") |
         artDate == as.Date("2019-03-10") | 
         artDate == as.Date("2019-04-09")) %>% 
  group_by(artDate) %>% 
  top_n(7, n) %>% 
  ungroup() %>% 
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(x=word, y=n, fill = artDate)) +
  geom_col(show.legend = FALSE) +
  labs(x = NULL, y = NULL) +
  facet_wrap(~artDate, scales="free", ncol = 2) + 
  coord_flip()+
  theme(text = element_text(family = "Heiti TC Light"))
plot_merge

前面通過篇數找出的文章篇數高點的標題 1/05, 1/16, 3/04, 3/10, 4/09 。
1/05: [問卦]館長嘴斷食,究竟哪邊對? [爆卦]館長:肏你媽有種現在就打過來啦
1/16: [新聞]館長促阿北2020選總統 柯P:我要再想想 [爆卦]館長正在跟柯文哲直播談虐童案
3/04: [新聞]「叫小賀!」孫安佐單挑館長影片曝光眼 [問卦]館長打得贏甄子丹嗎
3/10: [問卦]館長譙統促黨髒話本來就理虧,不是嗎? [新聞]統促黨嗆館長打一場 「簽生死狀,條件你
4/09: [新聞]與館長談統獨賴清德:統一就像斯斯有兩 [新聞]館長對決美國智庫?蔡賴今晚熱身賽

計算tf-idf

以文章區格document

g_tokens_by_art <- g_tokens %>% 
  filter(!str_detect(word, regex("[0-9]"))) %>%
  count(artTitle, word, sort = TRUE)
g_total_words_by_art <- g_tokens_by_art %>% 
  group_by(artTitle) %>% 
  summarize(total = sum(n)) %>% 
  arrange(desc(total))
g_tokens_by_art <- left_join(g_tokens_by_art, g_total_words_by_art)
Joining, by = "artTitle"

過濾掉文章長度少於20個詞的

g_words_tf_idf <- g_tokens_by_art %>%
  bind_tf_idf(word, artTitle, n) 
g_words_tf_idf %>% 
  filter(total > 20) %>% 
  arrange(desc(tf_idf))

文章本文:
背心尊者有強大的背心能力
平常館長也很常穿背心
不過我觀察館長穿的是寬鬆類背心
背心尊者穿的是緊身類背心
雖然是不同背心
但同樣都是背心愛好者
手下的教練 也是有背心軍團的資格
館長根本是真人版的背心尊者吧
大家覺得呢

文章總長度大於100個詞

g_words_tf_idf %>% 
  filter(total > 100) %>% 
  arrange(desc(tf_idf))

用日期來區隔document

g_tokens_by_date <- g_tokens %>% 
  filter(!str_detect(word, regex("[0-9]"))) %>%
  count(artDate, word, sort = TRUE)
g_total_words_by_date <- g_tokens_by_date %>% 
  group_by(artDate) %>% 
  summarize(total = sum(n)) %>% 
  arrange(desc(total))
g_tokens_by_date <- left_join(g_tokens_by_date, g_total_words_by_date)
Joining, by = "artDate"
g_words_tf_idf_date <- g_tokens_by_date %>%
  bind_tf_idf(word, artDate, n) 
g_words_tf_idf_date %>% 
  filter(total > 20) %>% 
  group_by(artDate) %>% 
  top_n(1) %>% 
  arrange(artDate)
Selecting by tf_idf

找出前面五個日期篇數高點

g_words_tf_idf_date %>% 
  filter(total > 20) %>% 
  filter(artDate == as.Date("2019-01-05") | 
         artDate == as.Date("2019-01-16") | 
         artDate == as.Date("2019-03-04") |
         artDate == as.Date("2019-03-10") | 
         artDate == as.Date("2019-04-09")) %>% 
  group_by(artDate) %>%  
  top_n(1) %>% 
  arrange(artDate)
Selecting by tf_idf

前面通過篇數找出的文章篇數高點的標題 1/05, 1/16, 3/04, 3/10, 4/09 。
1/05: [問卦]館長嘴斷食,究竟哪邊對? [爆卦]館長:肏你媽有種現在就打過來啦
1/16: [新聞]館長促阿北2020選總統 柯P:我要再想想 [爆卦]館長正在跟柯文哲直播談虐童案
3/04: [新聞]「叫小賀!」孫安佐單挑館長影片曝光眼 [問卦]館長打得贏甄子丹嗎
3/10: [問卦]館長譙統促黨髒話本來就理虧,不是嗎? [新聞]統促黨嗆館長打一場 「簽生死狀,條件你
4/09: [新聞]與館長談統獨賴清德:統一就像斯斯有兩 [新聞]館長對決美國智庫?蔡賴今晚熱身賽

前後五個字彙

可看出常出現在「館長」附近的字。

ngram_11 <- function(t) {
  lapply(t, function(x) {
    tokens <- segment(x, jieba_tokenizer)
    ngram <- ngrams(tokens, 11)
    ngram <- lapply(ngram, paste, collapse = " ")
    unlist(ngram)
  })
}
g_ngram_11 <- g_csv %>%
  select(artUrl, sentence) %>%
  unnest_tokens(ngram, sentence, token = ngram_11) %>%
  filter(!str_detect(ngram, regex("[0-9a-zA-Z]")))
g_ngrams_11_separated <- g_ngram_11 %>%
  separate(ngram, paste0("word", c(1:11),sep=""), sep = " ")
g_ngrams_11_separated
g_check_words <- g_ngrams_11_separated %>%
  filter((word6 == "館長"))
g_check_words
g_check_words_count <- g_check_words %>%
  melt(id.vars = "artUrl", measure.vars = paste0("word", c(1:11),sep="")) %>%
  rename(word=value) %>%
  filter(variable!="word6") %>%
  filter(!(word %in% stop_words), nchar(word)>1) %>%
  count(word, sort = TRUE)
g_check_words_count %>%
  arrange(desc(abs(n))) %>%
  head(15) %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = n > 0)) +
  geom_col(show.legend = FALSE) +
  xlab("出現在「館長」附近的字") +
  ylab("出現次數") +
  coord_flip()+ 
  theme(text = element_text(family = "Heiti TC Light"))

Word Correlation

g_words_by_art <- g_csv %>%
  unnest_tokens(word, sentence, token=g_tokenizer) %>%
  filter(!str_detect(word, regex("[0-9]"))) %>%
  count(artUrl, word, sort = TRUE)
g_word_pairs <- g_words_by_art %>%
  pairwise_count(word, artUrl, sort = TRUE)
g_word_pairs
g_word_cors <- g_words_by_art %>%
  group_by(word) %>%
  filter(n() >= 20) %>%
  pairwise_cor(word, artUrl, sort = TRUE)
g_word_cors %>%
  filter(item1 == "館長")

詞彙之間相關性

seed_words <- c("新聞", "綜合", "appledaily")
threshold <- 0.65
remove_words <- g_word_cors %>%
                filter((item1 %in% seed_words|item2 %in% seed_words), correlation>threshold) %>%
                .$item1 %>%
                unique()
set.seed(2017)
g_word_cors_new <- g_word_cors %>%
                filter(!(item1 %in% remove_words|item2 %in% remove_words))
g_word_cors_new %>%
  filter(correlation > .4) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = correlation), show.legend = FALSE) + 
  geom_node_point(color = "lightblue", size = 3) +
  geom_node_text(aes(label = name), repel = TRUE, family = "Heiti TC Light") +
  theme_void()

分群

透過詞彙平均tf-idf,去除部分不重要的字

term_avg_tfidf <- g_words_tf_idf %>% 
  group_by(word) %>% 
  summarise(tfidf_avg = mean(tf_idf))
term_avg_tfidf$tfidf_avg %>% summary
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
0.0001514 0.0325254 0.0521481 0.0988115 0.1138974 2.1033061 
term_remove=term_avg_tfidf %>%  
  filter(tfidf_avg<0.0325254) %>% 
  .$word
term_remove %>% head
[1] "阿嘎"   "阿共嚇" "啊災"   "挨告"   "愛民"   "愛鄉"  
g_dtm = g_words_tf_idf %>%
  filter(!word %in% term_remove) %>%
  cast_dtm(document=artTitle,term=word,value= n)
g_dtm
<<DocumentTermMatrix (documents: 550, terms: 8704)>>
Non-/sparse entries: 22402/4764798
Sparsity           : 100%
Maximal term length: 13
Weighting          : term frequency (tf)
g_dtm_matrix = g_dtm %>% as.data.frame.matrix 
g_dtm_matrix[1:10,1:20]

層級式分群

library(doParallel)
Loading required package: foreach
Loading required package: iterators
Loading required package: parallel
clust = makeCluster(detectCores())
registerDoParallel(clust); getDoParWorkers()
[1] 4
t0 = Sys.time()
d = g_dtm_matrix %>%
  dist(method="euclidean")  #歐式距離,算文章與文章之間的距離
Sys.time() - t0
Time difference of 8.371428 secs
hc = hclust(d, method='ward.D')  
plot(hc, labels = FALSE, xlab = NULL)
rect.hclust(hc, k = 2, border="red")

kg = cutree(hc, k = 2)
L = split(g_dtm_matrix, kg)
L$`1`[1:10,1:10]
sapply(L, function(x) x%>% colMeans %>% sort %>% tail %>% names)
     1        2     
[1,] "賴清德" "影片"
[2,] "統促黨" "健身"
[3,] "總統"   "看到"
[4,] "完整"   "艾瑪"
[5,] "中國"   "台灣"
[6,] "台灣"   "八卦"

在二維平面圖上以文字雲分析不同群的字

# t0 = Sys.time()
# n = 2000 #n個字
# tsne = g_dtm[, 1:n] %>% as.data.frame.matrix %>%
#   scale %>% t %>% Rtsne(
#     check_duplicates = FALSE, theta=0.0, max_iter=3200)
# Sys.time()-t0
# Y = tsne$Y              # tSNE coordinates
# d_Y = dist(Y)             # distance matrix
# hc_Y = hclust(d_Y )          # hi-clustering
# plot(hc_Y,label=F)
# rect.hclust(hc_Y, k=10, border="red")
# K = 10                            # number of clusters
# g = cutree(hc_Y,K)                # cut into K clusters
# table(g) %>% as.vector %>% sort   # sizes of clusters
# wc = col_sums(g_dtm[,1:n]) #n個字
# colors = distinctColorPalette(K)
# png("./g.png", width=3200, height=1800)#輸出圖片到路徑下
# textplot(
#   Y[,1], Y[,2], colnames(g_dtm)[1:n], show=F,
#   col=colors[g],
#   cex= 0.3 + 1.25 * sqrt(wc/mean(wc)),
#   font=2, family = "Heiti TC Light")
# dev.off()

建立LDA模型

統計每篇文章詞頻

g_artid <- g_tokens %>%
  filter(!str_detect(word, regex("[0-9a-zA-Z]"))) %>% 
  count(artTitle, word) %>% 
  rename(count=n) %>% 
  mutate(artId = group_indices(., artTitle))
g_artid
reserved_word <- g_artid %>% 
  group_by(word) %>% 
  count() %>% 
  filter(n > 5) %>% 
  unlist()
g_artid <- g_artid %>% 
  filter(word %in% reserved_word)

轉換為DTM

g_com_dtm <- g_artid %>% cast_dtm(artId, word, count)
g_com_dtm
<<DocumentTermMatrix (documents: 550, terms: 953)>>
Non-/sparse entries: 13381/510769
Sparsity           : 97%
Maximal term length: 6
Weighting          : term frequency (tf)

轉為分成兩群的LDA

g_lda <- LDA(g_com_dtm, k = 2, control = list(seed = 1234))

\(\phi\) Matrix

查看\(\phi\) matrix (topic * term)

g_topics <- tidy(g_lda, matrix = "beta")
g_topics

看分出來的兩個topic中,最常出現的詞

g_top_terms <- g_topics %>%
  group_by(topic) %>%
  top_n(10, beta) %>%
  ungroup() %>%
  arrange(topic, -beta)
remove_words <- c("館長", "直播", "陳之漢", "台灣")
g_top_terms <- g_topics %>%
  filter(! term %in% remove_words) %>% 
  group_by(topic) %>%
  top_n(10, beta) %>%
  ungroup() %>%
  arrange(topic, -beta)
g_top_terms %>%
  mutate(term = reorder(term, beta)) %>%
  ggplot(aes(term, beta, fill = factor(topic))) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ topic, scales = "free") +
  coord_flip() +
  theme(text = element_text(family = "Heiti TC Light"))

可看出在只分為兩個主題的情況下,結果並不是很明確。因為在主題一中,除了健身房本身的用詞外,還有統促黨被歸類在一起。 而主題二則明顯與政治與統獨相關。

兩主題之間相差最大的詞彙(topic2/topic1)

beta_spread <- g_topics %>%
  mutate(topic = paste0("topic", topic)) %>%
  spread(topic, beta) %>%
  filter(topic1 > .0004 | topic2 > .0004 ) %>%
  mutate(log_ratio = log2(topic2 / topic1))
g_topic_ratio <- rbind(beta_spread %>% 
                         top_n(10,wt = log_ratio), 
                       beta_spread %>% 
                         top_n(-10, log_ratio)) %>%
  arrange(log_ratio)
g_topic_ratio %>% 
  ggplot(aes(x = reorder(term, log_ratio), y = log_ratio)) +
  geom_bar(stat="identity") + 
  xlab("Word")+
  coord_flip() +
  theme(text = element_text(family = "Heiti TC Light"))

正越大表示越傾向主題二,負越大越傾向主題一,可看出與先前的評論相同。
主題一傾向與健身房相關,主題二與政治相關。

\(\theta\) matrix (document * topic)

查看\(\theta\) matrix

g_documents <- tidy(g_lda, matrix="gamma")
g_documents

查看最被確認在兩個主題中的前十篇文章。

g_documents$document<- g_documents$document %>% as.integer()
g_documents %>% 
  group_by(topic) %>% 
  top_n(10,gamma) %>% 
  arrange(topic) %>% 
  inner_join(g_artid %>% distinct(artTitle,artId), by=c("document" = "artId")) %>% 
  select(topic, artTitle, gamma)

也可看出與先前所下的結論相近,主題一有健身房相關與統促黨,另外可看到與高雄市政府相關事件。
主題二則多為政治與統獨相關議題。

LDAvis

只分為兩個主題出來的結果並不是很明確,這裡改成分為三個主題。

topicmodels_json_ldavis <- function(fitted, doc_term){
    require(LDAvis)
    require(slam)
    phi <- as.matrix(posterior(fitted)$terms)
    theta <- as.matrix(posterior(fitted)$topics)
    vocab <- colnames(phi)
    term_freq <- slam::col_sums(doc_term)
    json_lda <- LDAvis::createJSON(phi = phi, theta = theta,
                            vocab = vocab,
                            doc.length = as.vector(table(doc_term$i)),
                            term.frequency = term_freq)
    return(json_lda)
}
g_ldavis <- LDA(g_com_dtm, k = 3, control = list(seed = 1234))
json_res <- topicmodels_json_ldavis(g_ldavis,g_com_dtm)
serVis(json_res, open.browser = T)
To stop the server, run servr::daemon_stop(1) or restart your R session
Serving the directory /private/var/folders/x1/z5l5bj0d1bx64tl585rmpz4w0000gn/T/RtmpOv7c4q/file78c6fec31fc at http://127.0.0.1:4321

與健身房相關。

與政治和統獨相關。

與統促黨相關。

在分成三個主題的設定下,將統促黨相關的詞從原先與健身房相關的詞中,獨立成一個新的主題。

分析館長熱度歷久不衰的原因

date_plot

持續對大家(鄉民)有興趣的議題發表看法。

透過直播談論政治議題或健身房相關事件。

g_csv %>% 
  select(artTitle, commentNum, push, boo) %>% 
  filter(commentNum >= 20) %>% 
  mutate(p_ratio = push/commentNum, b_ratio = boo/commentNum) %>% 
  arrange(-p_ratio)

大家對於館長政治立場相關的發言,推文的比例都是偏高的,可見很合鄉民的胃口。

結論

館長在PPT上討論度每天都維持大於1篇的文章數, 而在這些文章中,可以發現會引起鄉民討論主要是館長的直播內容。 館長在直播中大部分是在談政治議題,以及平常的時事, 由分析中可以發現,政治議題最能夠激起鄉民的討論,例如:統促黨、統一、中國、韓國瑜…等等 反倒是健身房討論度較少。

LS0tCnRpdGxlOiAi56S+576k5aqS6auU5pyf5Lit5aCx5ZGKIC0gUFRU5YWr5Y2m54mI77ya6aSo6ZW355qE6KiO6KuW5YiG5p6QIgphdXRob3I6ICLnrKzkuIPntYQg57WE5ZOh77ya6Zmz55Co57+U44CB6JSh5a6X6Ku644CB5p6X5oSP5amV44CB546L5r6k5oGpIgpkYXRlOiAiMjAxOS8wNC8xMiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CmFic3RyYWN0OiAiIgotLS0KIyDli5XmqZ/oiIfliIbmnpDnm67nmoQKPiDlm6DngrrmnIDov5HntrLntIXmmK/lgIvlvojnhrHploDnmoTogbfmpa3vvIzkuI3nrqHogIHlubzlqablrbrvvIzlj6ropoHmlaLlsZXnj77oh6rmiJHjgIHnmbzmj67libXmhI/vvIzkurrkurrpg73mnInmqZ/mnIPmiJDngrrntrLntIXjgILmiJHlgJHmg7PmjqLoqI7ku6Ui6aSo6ZW3IumAmeWAi+S6uuagvOeJueizquW+iOeqgeWHuu+8jOWPiOWcqHB0dOiojuirlueGseW6puW+iOmrmOeahOe2sue0he+8jOaYr+eVmee1puS6uuWAkeS7gOm6vOeahOWNsOixoe+8jOS7luWPiOWcqOiojuirluS7gOm6vOaJjeacg+W8lei1t+Wkp+WutumCo+m6vOWkmueahOmXnOazqOOAggoKIyDliY3nva7kvZzmpa0KCiMjIOizh+aWmeWPluW+l+WPiuWll+S7tui8ieWFpQo+IOi8ieWFpeeahOizh+aWmeaYr+eUseS4reWxseWkp+WtuOeuoeeQhuWtuOmZouaWh+Wtl+WIhuaekOW5s+WPsOWPluW+l++8jOWcqOW5s+WPsOizh+aWmemBuOaTh+S4i+i8ieWOn+Wni+izh+aWmeaJgOWPluW+l+S5i2NzduaqlOahiOOAggoKIyMjIOizh+aWmeewoeS7iwo+IOacrOizh+aWmeeCujIwMTkvMDEvMDEgfiAyMDE5LzA0LzEyIFBUVOWFq+WNpueJiOS5i+izh+aWme+8jOmAj+mBjuaWh+Wtl+WIhuaekOW5s+WPsOaqoue0ouOAjOmkqOmVt+OAjeOAgeOAjOmZs+S5i+a8ouOAjeWFqeWAi+mXnOmNteWtl++8jOWFseaQnOWwi+WIsDY0Nuevh+aWh+eroOOAggoKYGBge3J9ClN5cy5zZXRsb2NhbGUoY2F0ZWdvcnkgPSAiTENfQUxMIiwgbG9jYWxlID0gInpoX1RXLlVURi04IikgIyDpgb/lhY3kuK3mlofkuoLnorwKYGBgCgojIyDlronoo53pnIDopoHnmoRwYWNrYWdlcwpgYGB7cn0KcGFja2FnZXMgPSBjKCJkcGx5ciIsICJ0aWR5dGV4dCIsICJqaWViYVIiLCAiZ3V0ZW5iZXJnciIsICJzdHJpbmdyIiwgIndvcmRjbG91ZDIiLCAiZ2dwbG90MiIsICJ0aWR5ciIsICJzY2FsZXMiLCAid2lkeXIiLCAicmVhZHIiLCAicmVzaGFwZTIiLCAiTkxQIiwgImdncmFwaCIsICJpZ3JhcGgiLCAidG0iLCAiZGF0YS50YWJsZSIsICJxdWFudGVkYSIsICJNYXRyaXgiLCAic2xhbSIsICJSdHNuZSIsICJyYW5kb21jb2xvUiIsICJ3b3JkY2xvdWQiLCAidG9waWNtb2RlbHMiLCAiTERBdmlzIiwgIndlYnNob3QiLCAiaHRtbHdpZGdldHMiLCJzZXJ2ciIpCmV4aXN0aW5nID0gYXMuY2hhcmFjdGVyKGluc3RhbGxlZC5wYWNrYWdlcygpWywxXSkKZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpCmBgYAoKYGBge3J9CnJlcXVpcmUoZHBseXIpCnJlcXVpcmUodGlkeXRleHQpCnJlcXVpcmUoamllYmFSKQpyZXF1aXJlKGd1dGVuYmVyZ3IpCnJlcXVpcmUoc3RyaW5ncikKcmVxdWlyZSh3b3JkY2xvdWQyKQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUodGlkeXIpCnJlcXVpcmUoc2NhbGVzKQpyZXF1aXJlKHdpZHlyKQpyZXF1aXJlKHJlYWRyKQpyZXF1aXJlKHJlc2hhcGUyKQpyZXF1aXJlKE5MUCkKcmVxdWlyZShnZ3JhcGgpCnJlcXVpcmUoaWdyYXBoKQpyZXF1aXJlKHRtKQpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUocXVhbnRlZGEpCnJlcXVpcmUoTWF0cml4KQpyZXF1aXJlKHNsYW0pCnJlcXVpcmUoUnRzbmUpCnJlcXVpcmUocmFuZG9tY29sb1IpCnJlcXVpcmUod29yZGNsb3VkKQpyZXF1aXJlKHRvcGljbW9kZWxzKQpyZXF1aXJlKExEQXZpcykKcmVxdWlyZSh3ZWJzaG90KQpyZXF1aXJlKGh0bWx3aWRnZXRzKQpyZXF1aXJlKHNlcnZyKQpgYGAKCiMjIOizh+aWmei8ieWFpQpgYGB7cn0KZ19jc3YgPC0gZnJlYWQoImd1YW5famFuZ19kYXRhLmNzdiIsIGVuY29kaW5nID0gIlVURi04IiwgaGVhZGVyID0gVFJVRSkKZ19jc3YgPC0gZ19jc3YgJT4lIAogIGZpbHRlcihhcnRVcmwgIT0gImh0dHBzOi8vd3d3LnB0dC5jYy9iYnMvR29zc2lwaW5nL00uMTU0Nzg4ODM5MS5BLjgzNi5odG1sIikKZ19jc3YkYXJ0RGF0ZSA9IGdfY3N2JGFydERhdGUgJT4lIGFzLkRhdGUoIiVZLyVtLyVkIikKYGBgCgojIyDpoJDopr3os4fmlpkKYGBge3J9CmhlYWQoZ19jc3YpCmBgYAoKIyDml6XmnJ/mipjnt5rlnJYKPiDoqIjnrpflh7rmr4/kuIDlpKnmlofnq6DnmoTnmbzooajmlbjph4/vvIznnIvlh7roqI7oq5bjgIzppKjplbfjgI3nmoTnhrHluqbjgIIKCiMjIOizh+aWmeiZleeQhgpgYGB7cn0KZ19kYXRlIDwtIGdfY3N2ICU+JSAKICBzZWxlY3QoYXJ0RGF0ZSwgYXJ0VXJsKSAlPiUgCiAgZGlzdGluY3QoKQoKYXJ0aWNsZV9jb3VudF9ieV9kYXRlIDwtIGdfZGF0ZSAlPiUgCiAgZ3JvdXBfYnkoYXJ0RGF0ZSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkKCmFydGljbGVfY291bnRfYnlfZGF0ZSAlPiUgCiAgYXJyYW5nZShkZXNjKGNvdW50KSklPiUgCiAgdG9wX24oMTApCmBgYAo+IOiojuirluevh+aVuOacgOWkmueahOWJjTEw5aSp44CCCgpgYGB7cn0KZGF0ZV9wbG90IDwtIGFydGljbGVfY291bnRfYnlfZGF0ZSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gYXJ0RGF0ZSwgeSA9IGNvdW50KSkgKwogIGdlb21fbGluZShjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMS41KSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoYXMubnVtZXJpYyhhcy5EYXRlKCIyMDE5LTAxLTA1IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhhcy5EYXRlKCIyMDE5LTAxLTE2IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhhcy5EYXRlKCIyMDE5LTAzLTA0IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhhcy5EYXRlKCIyMDE5LTAzLTEwIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAxOS0wNC0wOSIpKSksIGNvbD0ncmVkJywgc2l6ZSA9IDEpICsgCiAgc2NhbGVfeF9kYXRlKGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWS8lbS8lZCIpKSArCiAgZ2d0aXRsZSgi44CM6aSo6ZW344CN6KiO6KuW5paH56ug5pW4IikgKyAKICB4bGFiKCLml6XmnJ8iKSArIAogIHlsYWIoIuaVuOmHjyIpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKQpkYXRlX3Bsb3QKYGBgCgo+IOW+nuS4iuWcluS4reWPr+S7peeci+WIsOmXnOaWvOOAjOmkqOmVt+OAjeeahOiojuirluWcqDEvMDUsIDEvMTYsIDMvMDQsIDMvMTAsIDQvMDkg5Ye654++6auY6bue44CCPGJyPgo+IDEvMDU6IFvllY/ljaZd6aSo6ZW35Zi05pa36aOf77yM56m256uf5ZOq6YKK5bCN77yfICAgICAgICAgICAgICAgW+eIhuWNpl3ppKjplbc66IKP5L2g5aq95pyJ56iu54++5Zyo5bCx5omT6YGO5L6G5ZWmPGJyPgo+IDEvMTY6IFvmlrDogZ5d6aSo6ZW35L+D6Zi/5YyXMjAyMOmBuOe4vee1seOAgOafr1A65oiR6KaB5YaN5oOz5oOzICAgW+eIhuWNpl3ppKjplbfmraPlnKjot5/mn6/mloflk7Lnm7Tmkq3oq4fomZDnq6XmoYg8YnI+Cj4gMy8wNDogW+aWsOiBnl3jgIzlj6vlsI/os4DvvIHjgI3lravlronkvZDllq7mjJHppKjplbflvbHniYfmm53lhYnnnLwgICBb5ZWP5Y2mXemkqOmVt+aJk+W+l+i0j+eUhOWtkOS4ueWXjjxicj4KPiAzLzA3OiDppKjplbc657Wx5L+D6buoMy8xMOiZn+imgeS+huael+WPo+mkqOe9teS4ieWtl+e2kyEhITxicj4KPiAzLzEwOiBb5ZWP5Y2mXemkqOmVt+itmee1seS/g+m7qOmrkuipseacrOS+huWwseeQhuiZp++8jOS4jeaYr+WXju+8nyAgIFvmlrDogZ5d57Wx5L+D6buo5ZeG6aSo6ZW35omT5LiA5aC044CA44CM57C955Sf5q2754uA77yM5qKd5Lu25L2gPGJyPgo+IDQvMDk6IFvmlrDogZ5d6IiH6aSo6ZW36KuH57Wx542o6LO05riF5b6377ya57Wx5LiA5bCx5YOP5pav5pav5pyJ5YWpICAgW+aWsOiBnl3ppKjplbflsI3msbrnvo7lnIvmmbrluqvvvJ/olKHos7Tku4rmmZrnhrHouqvos708YnI+CgojIOaWh+Wtl+mbsgo+IOaOpeS4i+S+huaIkeWAkeS+huWkp+eVpeingOWvn+iojuirlueahOWFp+WuueeCuuS9le+8jOS9v+eUqOeahOaWueW8j+eCuuaWh+Wtl+mbsuOAggoKIyMg5pa36Kme44CB5YGc55So6Kme5L2/55SoCmBgYHtyfQpqaWViYV90b2tlbml6ZXIgPC0gd29ya2VyKHVzZXI9ImtfZGljdC50eHQiLCBzdG9wX3dvcmQgPSAic3RvcF93b3Jkcy50eHQiKQoKZ190b2tlbml6ZXIgPC0gZnVuY3Rpb24odCkgewogIGxhcHBseSh0LCBmdW5jdGlvbih4KSB7CiAgICB0b2tlbnMgPC0gc2VnbWVudCh4LCBqaWViYV90b2tlbml6ZXIpCiAgICB0b2tlbnMgPC0gdG9rZW5zW25jaGFyKHRva2Vucyk+MV0KICAgIHJldHVybih0b2tlbnMpCiAgfSkKfQpgYGAKCmBgYHtyfQpnX3Rva2VucyA8LSBnX2NzdiAlPiUgCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBzZW50ZW5jZSwgdG9rZW49Z190b2tlbml6ZXIpICU+JSAKICBzZWxlY3QoLWFydFRpbWUsIC1hcnRVcmwpCgpnX3Rva2Vuc19jb3VudCA8LSBnX3Rva2VucyAlPiUgCiAgZ3JvdXBfYnkod29yZCkgJT4lIAogIHN1bW1hcmlzZShzdW0gPSBuKCkpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtKSkKCmhlYWQoZ190b2tlbnNfY291bnQpCmBgYAo+IOe1kOaenOeCuuipnuWHuuePvuacgOWkmueahOWtl+OAggoKIyMg56e76Zmk44CM6aSo6ZW344CNCmBgYHtyfQp3b3JkY19wbG90IDwtIGdfdG9rZW5zX2NvdW50ICU+JSAKICBmaWx0ZXIod29yZCAhPSAi6aSo6ZW3IikgJT4lIAogIGZpbHRlcihzdW0gPiAyMCkgJT4lIAogIHdvcmRjbG91ZDIoKQp3b3JkY19wbG90CmBgYAoKIyDplbfmop3lnJYKPiDplbfmop3lnJblj6/ku6Xmn6XnnIvnsr7norrnmoTjgIzmnIDluLjlh7rnj77oqZ7lvZnjgI3jgIIKCiMjIOafpeeci+evh+aVuOacgOWkmueahOS6lOWkqeS4re+8jOacgOW4uOWHuuePvueahOipnuW9meOAggpgYGB7cn0KZ190b2tlbnNfYnlfZGF0ZSA8LSBnX3Rva2VucyAlPiUgCiAgY291bnQoYXJ0RGF0ZSwgd29yZCwgc29ydCA9IFRSVUUpCiAgCnBsb3RfbWVyZ2UgPC0gZ190b2tlbnNfYnlfZGF0ZSAlPiUgCiAgZmlsdGVyKHdvcmQgIT0gIumkqOmVtyIgJiB3b3JkICE9ICLnm7Tmkq0iKSAlPiUgCiAgZmlsdGVyKGFydERhdGUgPT0gYXMuRGF0ZSgiMjAxOS0wMS0wNSIpIHwgCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAxOS0wMS0xNiIpIHwgCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAxOS0wMy0wNCIpIHwKICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDE5LTAzLTEwIikgfCAKICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDE5LTA0LTA5IikpICU+JSAKICBncm91cF9ieShhcnREYXRlKSAlPiUgCiAgdG9wX24oNywgbikgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHg9d29yZCwgeT1uLCBmaWxsID0gYXJ0RGF0ZSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsKICBmYWNldF93cmFwKH5hcnREYXRlLCBzY2FsZXM9ImZyZWUiLCBuY29sID0gMikgKyAKICBjb29yZF9mbGlwKCkrCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkKcGxvdF9tZXJnZQpgYGAKCj4g5YmN6Z2i6YCa6YGO56+H5pW45om+5Ye655qE5paH56ug56+H5pW46auY6bue55qE5qiZ6aGMIDEvMDUsIDEvMTYsIDMvMDQsIDMvMTAsIDQvMDkg44CCPGJyPgo+IDEvMDU6IFvllY/ljaZd6aSo6ZW35Zi05pa36aOf77yM56m256uf5ZOq6YKK5bCN77yfICAgICAgICAgICAgICAgW+eIhuWNpl3ppKjplbc66IKP5L2g5aq95pyJ56iu54++5Zyo5bCx5omT6YGO5L6G5ZWmPGJyPgo+IDEvMTY6IFvmlrDogZ5d6aSo6ZW35L+D6Zi/5YyXMjAyMOmBuOe4vee1seOAgOafr1A65oiR6KaB5YaN5oOz5oOzICAgW+eIhuWNpl3ppKjplbfmraPlnKjot5/mn6/mloflk7Lnm7Tmkq3oq4fomZDnq6XmoYg8YnI+Cj4gMy8wNDogW+aWsOiBnl3jgIzlj6vlsI/os4DvvIHjgI3lravlronkvZDllq7mjJHppKjplbflvbHniYfmm53lhYnnnLwgICBb5ZWP5Y2mXemkqOmVt+aJk+W+l+i0j+eUhOWtkOS4ueWXjjxicj4KPiAzLzEwOiBb5ZWP5Y2mXemkqOmVt+itmee1seS/g+m7qOmrkuipseacrOS+huWwseeQhuiZp++8jOS4jeaYr+WXju+8nyAgIFvmlrDogZ5d57Wx5L+D6buo5ZeG6aSo6ZW35omT5LiA5aC044CA44CM57C955Sf5q2754uA77yM5qKd5Lu25L2gPGJyPgo+IDQvMDk6IFvmlrDogZ5d6IiH6aSo6ZW36KuH57Wx542o6LO05riF5b6377ya57Wx5LiA5bCx5YOP5pav5pav5pyJ5YWpICAgW+aWsOiBnl3ppKjplbflsI3msbrnvo7lnIvmmbrluqvvvJ/olKHos7Tku4rmmZrnhrHouqvos708YnI+CgojIOioiOeul3RmLWlkZgoKIyMg5Lul5paH56ug5Y2A5qC8ZG9jdW1lbnQKYGBge3J9CmdfdG9rZW5zX2J5X2FydCA8LSBnX3Rva2VucyAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsIHJlZ2V4KCJbMC05XSIpKSkgJT4lCiAgY291bnQoYXJ0VGl0bGUsIHdvcmQsIHNvcnQgPSBUUlVFKQpnX3RvdGFsX3dvcmRzX2J5X2FydCA8LSBnX3Rva2Vuc19ieV9hcnQgJT4lIAogIGdyb3VwX2J5KGFydFRpdGxlKSAlPiUgCiAgc3VtbWFyaXplKHRvdGFsID0gc3VtKG4pKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkKZ190b2tlbnNfYnlfYXJ0IDwtIGxlZnRfam9pbihnX3Rva2Vuc19ieV9hcnQsIGdfdG90YWxfd29yZHNfYnlfYXJ0KQpgYGAKCiMjIyDpgY7mv77mjonmlofnq6DplbfluqblsJHmlrwyMOWAi+ipnueahApgYGB7cn0KZ193b3Jkc190Zl9pZGYgPC0gZ190b2tlbnNfYnlfYXJ0ICU+JQogIGJpbmRfdGZfaWRmKHdvcmQsIGFydFRpdGxlLCBuKSAKZ193b3Jkc190Zl9pZGYgJT4lIAogIGZpbHRlcih0b3RhbCA+IDIwKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRmX2lkZikpCmBgYAoKPiDmlofnq6DmnKzmlofvvJo8YnI+CuiDjOW/g+WwiuiAheacieW8t+Wkp+eahOiDjOW/g+iDveWKmyA8YnI+CuW5s+W4uOmkqOmVt+S5n+W+iOW4uOepv+iDjOW/gyA8YnI+CuS4jemBjuaIkeingOWvn+mkqOmVt+epv+eahOaYr+WvrOmshumhnuiDjOW/gyA8YnI+CuiDjOW/g+WwiuiAheepv+eahOaYr+e3iui6q+mhnuiDjOW/gyA8YnI+CumblueEtuaYr+S4jeWQjOiDjOW/gyA8YnI+CuS9huWQjOaoo+mDveaYr+iDjOW/g+aEm+WlveiAhSA8YnI+CuaJi+S4i+eahOaVmee3tCDkuZ/mmK/mnInog4zlv4Pou43lnJjnmoTos4fmoLwgPGJyPgrppKjplbfmoLnmnKzmmK/nnJ/kurrniYjnmoTog4zlv4PlsIrogIXlkKcgPGJyPgrlpKflrrboprrlvpflkaIKCiMjIyDmlofnq6DnuL3plbfluqblpKfmlrwxMDDlgIvoqZ4KYGBge3J9Cmdfd29yZHNfdGZfaWRmICU+JSAKICBmaWx0ZXIodG90YWwgPiAxMDApICU+JSAKICBhcnJhbmdlKGRlc2ModGZfaWRmKSkKYGBgCgojIyDnlKjml6XmnJ/kvobljYDpmpRkb2N1bWVudApgYGB7cn0KZ190b2tlbnNfYnlfZGF0ZSA8LSBnX3Rva2VucyAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsIHJlZ2V4KCJbMC05XSIpKSkgJT4lCiAgY291bnQoYXJ0RGF0ZSwgd29yZCwgc29ydCA9IFRSVUUpCmdfdG90YWxfd29yZHNfYnlfZGF0ZSA8LSBnX3Rva2Vuc19ieV9kYXRlICU+JSAKICBncm91cF9ieShhcnREYXRlKSAlPiUgCiAgc3VtbWFyaXplKHRvdGFsID0gc3VtKG4pKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkKZ190b2tlbnNfYnlfZGF0ZSA8LSBsZWZ0X2pvaW4oZ190b2tlbnNfYnlfZGF0ZSwgZ190b3RhbF93b3Jkc19ieV9kYXRlKQpnX3dvcmRzX3RmX2lkZl9kYXRlIDwtIGdfdG9rZW5zX2J5X2RhdGUgJT4lCiAgYmluZF90Zl9pZGYod29yZCwgYXJ0RGF0ZSwgbikgCmdfd29yZHNfdGZfaWRmX2RhdGUgJT4lIAogIGZpbHRlcih0b3RhbCA+IDIwKSAlPiUgCiAgZ3JvdXBfYnkoYXJ0RGF0ZSkgJT4lIAogIHRvcF9uKDEpICU+JSAKICBhcnJhbmdlKGFydERhdGUpCmBgYAoKIyMjIOaJvuWHuuWJjemdouS6lOWAi+aXpeacn+evh+aVuOmrmOm7ngpgYGB7cn0KZ193b3Jkc190Zl9pZGZfZGF0ZSAlPiUgCiAgZmlsdGVyKHRvdGFsID4gMjApICU+JSAKICBmaWx0ZXIoYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDE5LTAxLTA1IikgfCAKICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDE5LTAxLTE2IikgfCAKICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDE5LTAzLTA0IikgfAogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMTktMDMtMTAiKSB8IAogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMTktMDQtMDkiKSkgJT4lIAogIGdyb3VwX2J5KGFydERhdGUpICU+JSAgCiAgdG9wX24oMSkgJT4lIAogIGFycmFuZ2UoYXJ0RGF0ZSkKYGBgCgo+IOWJjemdoumAmumBjuevh+aVuOaJvuWHuueahOaWh+eroOevh+aVuOmrmOm7nueahOaomemhjCAxLzA1LCAxLzE2LCAzLzA0LCAzLzEwLCA0LzA5IOOAgjxicj4KPiAxLzA1OiBb5ZWP5Y2mXemkqOmVt+WYtOaWt+mjn++8jOeptuern+WTqumCiuWwje+8nyAgICAgICAgICAgICAgIFvniIbljaZd6aSo6ZW3OuiCj+S9oOWqveacieeoruePvuWcqOWwseaJk+mBjuS+huWVpjxicj4KPiAxLzE2OiBb5paw6IGeXemkqOmVt+S/g+mYv+WMlzIwMjDpgbjnuL3ntbHjgIDmn69QOuaIkeimgeWGjeaDs+aDsyAgIFvniIbljaZd6aSo6ZW35q2j5Zyo6Lef5p+v5paH5ZOy55u05pKt6KuH6JmQ56ul5qGIPGJyPgo+IDMvMDQ6IFvmlrDogZ5d44CM5Y+r5bCP6LOA77yB44CN5a2r5a6J5L2Q5Zau5oyR6aSo6ZW35b2x54mH5pud5YWJ55y8ICAgW+WVj+WNpl3ppKjplbfmiZPlvpfotI/nlITlrZDkuLnll448YnI+Cj4gMy8xMDogW+WVj+WNpl3ppKjplbforZnntbHkv4Ppu6jpq5LoqbHmnKzkvoblsLHnkIbomafvvIzkuI3mmK/ll47vvJ8gICBb5paw6IGeXee1seS/g+m7qOWXhumkqOmVt+aJk+S4gOWgtOOAgOOAjOewveeUn+atu+eLgO+8jOaineS7tuS9oDxicj4KPiA0LzA5OiBb5paw6IGeXeiIh+mkqOmVt+irh+e1seeNqOiztOa4heW+t++8mue1seS4gOWwseWDj+aWr+aWr+acieWFqSAgIFvmlrDogZ5d6aSo6ZW35bCN5rG6576O5ZyL5pm65bqr77yf6JSh6LO05LuK5pma54ax6Lqr6LO9PGJyPgoKIyDliY3lvozkupTlgIvlrZflvZkKPiDlj6/nnIvlh7rluLjlh7rnj77lnKjjgIzppKjplbfjgI3pmYTov5HnmoTlrZfjgIIKCmBgYHtyfQpuZ3JhbV8xMSA8LSBmdW5jdGlvbih0KSB7CiAgbGFwcGx5KHQsIGZ1bmN0aW9uKHgpIHsKICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikKICAgIG5ncmFtIDwtIG5ncmFtcyh0b2tlbnMsIDExKQogICAgbmdyYW0gPC0gbGFwcGx5KG5ncmFtLCBwYXN0ZSwgY29sbGFwc2UgPSAiICIpCiAgICB1bmxpc3QobmdyYW0pCiAgfSkKfQpgYGAKCmBgYHtyfQpnX25ncmFtXzExIDwtIGdfY3N2ICU+JQogIHNlbGVjdChhcnRVcmwsIHNlbnRlbmNlKSAlPiUKICB1bm5lc3RfdG9rZW5zKG5ncmFtLCBzZW50ZW5jZSwgdG9rZW4gPSBuZ3JhbV8xMSkgJT4lCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KG5ncmFtLCByZWdleCgiWzAtOWEtekEtWl0iKSkpCmdfbmdyYW1zXzExX3NlcGFyYXRlZCA8LSBnX25ncmFtXzExICU+JQogIHNlcGFyYXRlKG5ncmFtLCBwYXN0ZTAoIndvcmQiLCBjKDE6MTEpLHNlcD0iIiksIHNlcCA9ICIgIikKZ19uZ3JhbXNfMTFfc2VwYXJhdGVkCmBgYAoKYGBge3J9CmdfY2hlY2tfd29yZHMgPC0gZ19uZ3JhbXNfMTFfc2VwYXJhdGVkICU+JQogIGZpbHRlcigod29yZDYgPT0gIumkqOmVtyIpKQpnX2NoZWNrX3dvcmRzCmBgYAoKYGBge3J9CmdfY2hlY2tfd29yZHNfY291bnQgPC0gZ19jaGVja193b3JkcyAlPiUKICBtZWx0KGlkLnZhcnMgPSAiYXJ0VXJsIiwgbWVhc3VyZS52YXJzID0gcGFzdGUwKCJ3b3JkIiwgYygxOjExKSxzZXA9IiIpKSAlPiUKICByZW5hbWUod29yZD12YWx1ZSkgJT4lCiAgZmlsdGVyKHZhcmlhYmxlIT0id29yZDYiKSAlPiUKICBmaWx0ZXIoISh3b3JkICVpbiUgc3RvcF93b3JkcyksIG5jaGFyKHdvcmQpPjEpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQoKZ19jaGVja193b3Jkc19jb3VudCAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKG4pKSkgJT4lCiAgaGVhZCgxNSkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBuID4gMCkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgeGxhYigi5Ye654++5Zyo44CM6aSo6ZW344CN6ZmE6L+R55qE5a2XIikgKwogIHlsYWIoIuWHuuePvuasoeaVuCIpICsKICBjb29yZF9mbGlwKCkrIAogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikpCmBgYAoKIyBXb3JkIENvcnJlbGF0aW9uCmBgYHtyfQpnX3dvcmRzX2J5X2FydCA8LSBnX2NzdiAlPiUKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHNlbnRlbmNlLCB0b2tlbj1nX3Rva2VuaXplcikgJT4lCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsIHJlZ2V4KCJbMC05XSIpKSkgJT4lCiAgY291bnQoYXJ0VXJsLCB3b3JkLCBzb3J0ID0gVFJVRSkKZ193b3JkX3BhaXJzIDwtIGdfd29yZHNfYnlfYXJ0ICU+JQogIHBhaXJ3aXNlX2NvdW50KHdvcmQsIGFydFVybCwgc29ydCA9IFRSVUUpCmdfd29yZF9wYWlycwpgYGAKCmBgYHtyfQpnX3dvcmRfY29ycyA8LSBnX3dvcmRzX2J5X2FydCAlPiUKICBncm91cF9ieSh3b3JkKSAlPiUKICBmaWx0ZXIobigpID49IDIwKSAlPiUKICBwYWlyd2lzZV9jb3Iod29yZCwgYXJ0VXJsLCBzb3J0ID0gVFJVRSkKZ193b3JkX2NvcnMgJT4lCiAgZmlsdGVyKGl0ZW0xID09ICLppKjplbciKQpgYGAKCiMjIOipnuW9meS5i+mWk+ebuOmXnOaApwpgYGB7cn0Kc2VlZF93b3JkcyA8LSBjKCLmlrDogZ4iLCAi57ac5ZCIIiwgImFwcGxlZGFpbHkiKQp0aHJlc2hvbGQgPC0gMC42NQpyZW1vdmVfd29yZHMgPC0gZ193b3JkX2NvcnMgJT4lCiAgICAgICAgICAgICAgICBmaWx0ZXIoKGl0ZW0xICVpbiUgc2VlZF93b3Jkc3xpdGVtMiAlaW4lIHNlZWRfd29yZHMpLCBjb3JyZWxhdGlvbj50aHJlc2hvbGQpICU+JQogICAgICAgICAgICAgICAgLiRpdGVtMSAlPiUKICAgICAgICAgICAgICAgIHVuaXF1ZSgpCgpzZXQuc2VlZCgyMDE3KQpnX3dvcmRfY29yc19uZXcgPC0gZ193b3JkX2NvcnMgJT4lCiAgICAgICAgICAgICAgICBmaWx0ZXIoIShpdGVtMSAlaW4lIHJlbW92ZV93b3Jkc3xpdGVtMiAlaW4lIHJlbW92ZV93b3JkcykpCmdfd29yZF9jb3JzX25ldyAlPiUKICBmaWx0ZXIoY29ycmVsYXRpb24gPiAuNCkgJT4lCiAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKCkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsKICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IGNvcnJlbGF0aW9uKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibGlnaHRibHVlIiwgc2l6ZSA9IDMpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWwgPSBUUlVFLCBmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSArCiAgdGhlbWVfdm9pZCgpCmBgYAoKIyDliIbnvqQKCiMjIOmAj+mBjuipnuW9meW5s+Wdh3RmLWlkZu+8jOWOu+mZpOmDqOWIhuS4jemHjeimgeeahOWtlwpgYGB7cn0KdGVybV9hdmdfdGZpZGYgPC0gZ193b3Jkc190Zl9pZGYgJT4lIAogIGdyb3VwX2J5KHdvcmQpICU+JSAKICBzdW1tYXJpc2UodGZpZGZfYXZnID0gbWVhbih0Zl9pZGYpKQp0ZXJtX2F2Z190ZmlkZiR0ZmlkZl9hdmcgJT4lIHN1bW1hcnkKYGBgCgpgYGB7cn0KdGVybV9yZW1vdmU9dGVybV9hdmdfdGZpZGYgJT4lICAKICBmaWx0ZXIodGZpZGZfYXZnPDAuMDMyNTI1NCkgJT4lIAogIC4kd29yZAp0ZXJtX3JlbW92ZSAlPiUgaGVhZApgYGAKCmBgYHtyfQpnX2R0bSA9IGdfd29yZHNfdGZfaWRmICU+JQogIGZpbHRlcighd29yZCAlaW4lIHRlcm1fcmVtb3ZlKSAlPiUKICBjYXN0X2R0bShkb2N1bWVudD1hcnRUaXRsZSx0ZXJtPXdvcmQsdmFsdWU9IG4pCmdfZHRtCmBgYAoKYGBge3J9CmdfZHRtX21hdHJpeCA9IGdfZHRtICU+JSBhcy5kYXRhLmZyYW1lLm1hdHJpeCAKZ19kdG1fbWF0cml4WzE6MTAsMToyMF0KYGBgCgojIOWxpOe0muW8j+WIhue+pApgYGB7cn0KbGlicmFyeShkb1BhcmFsbGVsKQpjbHVzdCA9IG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkpCnJlZ2lzdGVyRG9QYXJhbGxlbChjbHVzdCk7IGdldERvUGFyV29ya2VycygpCmBgYAoKYGBge3J9CnQwID0gU3lzLnRpbWUoKQpkID0gZ19kdG1fbWF0cml4ICU+JQogIGRpc3QobWV0aG9kPSJldWNsaWRlYW4iKSAgI+atkOW8j+i3nembou+8jOeul+aWh+eroOiIh+aWh+eroOS5i+mWk+eahOi3nembogpTeXMudGltZSgpIC0gdDAKYGBgCgpgYGB7cn0KaGMgPSBoY2x1c3QoZCwgbWV0aG9kPSd3YXJkLkQnKSAgCnBsb3QoaGMsIGxhYmVscyA9IEZBTFNFLCB4bGFiID0gTlVMTCkKcmVjdC5oY2x1c3QoaGMsIGsgPSAyLCBib3JkZXI9InJlZCIpCmBgYAoKYGBge3J9CmtnID0gY3V0cmVlKGhjLCBrID0gMikKTCA9IHNwbGl0KGdfZHRtX21hdHJpeCwga2cpCkwkYDFgWzE6MTAsMToxMF0KYGBgCgpgYGB7cn0Kc2FwcGx5KEwsIGZ1bmN0aW9uKHgpIHglPiUgY29sTWVhbnMgJT4lIHNvcnQgJT4lIHRhaWwgJT4lIG5hbWVzKQpgYGAKCiMg5Zyo5LqM57at5bmz6Z2i5ZyW5LiK5Lul5paH5a2X6Zuy5YiG5p6Q5LiN5ZCM576k55qE5a2XCmBgYHtyfQojIHQwID0gU3lzLnRpbWUoKQojIG4gPSAyMDAwICNu5YCL5a2XCiMgdHNuZSA9IGdfZHRtWywgMTpuXSAlPiUgYXMuZGF0YS5mcmFtZS5tYXRyaXggJT4lCiMgICBzY2FsZSAlPiUgdCAlPiUgUnRzbmUoCiMgICAgIGNoZWNrX2R1cGxpY2F0ZXMgPSBGQUxTRSwgdGhldGE9MC4wLCBtYXhfaXRlcj0zMjAwKQojIFN5cy50aW1lKCktdDAKYGBgCgpgYGB7cn0KIyBZID0gdHNuZSRZICAgICAgICAgICAgICAjIHRTTkUgY29vcmRpbmF0ZXMKIyBkX1kgPSBkaXN0KFkpICAgICAgICAgICAgICMgZGlzdGFuY2UgbWF0cml4CiMgaGNfWSA9IGhjbHVzdChkX1kgKSAgICAgICAgICAjIGhpLWNsdXN0ZXJpbmcKIyBwbG90KGhjX1ksbGFiZWw9RikKIyByZWN0LmhjbHVzdChoY19ZLCBrPTEwLCBib3JkZXI9InJlZCIpCmBgYAoKYGBge3J9CiMgSyA9IDEwICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbnVtYmVyIG9mIGNsdXN0ZXJzCiMgZyA9IGN1dHJlZShoY19ZLEspICAgICAgICAgICAgICAgICMgY3V0IGludG8gSyBjbHVzdGVycwojIHRhYmxlKGcpICU+JSBhcy52ZWN0b3IgJT4lIHNvcnQgICAjIHNpemVzIG9mIGNsdXN0ZXJzCmBgYAoKYGBge3J9CiMgd2MgPSBjb2xfc3VtcyhnX2R0bVssMTpuXSkgI27lgIvlrZcKIyBjb2xvcnMgPSBkaXN0aW5jdENvbG9yUGFsZXR0ZShLKQojIHBuZygiLi9nLnBuZyIsIHdpZHRoPTMyMDAsIGhlaWdodD0xODAwKSPovLjlh7rlnJbniYfliLDot6/lvpHkuIsKIyB0ZXh0cGxvdCgKIyAgIFlbLDFdLCBZWywyXSwgY29sbmFtZXMoZ19kdG0pWzE6bl0sIHNob3c9RiwKIyAgIGNvbD1jb2xvcnNbZ10sCiMgICBjZXg9IDAuMyArIDEuMjUgKiBzcXJ0KHdjL21lYW4od2MpKSwKIyAgIGZvbnQ9MiwgZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikKIyBkZXYub2ZmKCkKYGBgCgohW10oZy5wbmcpCgojIOW7uueri0xEQeaooeWeiwoKIyMg57Wx6KiI5q+P56+H5paH56ug6Kme6aC7CmBgYHtyfQpnX2FydGlkIDwtIGdfdG9rZW5zICU+JQogIGZpbHRlcighc3RyX2RldGVjdCh3b3JkLCByZWdleCgiWzAtOWEtekEtWl0iKSkpICU+JSAKICBjb3VudChhcnRUaXRsZSwgd29yZCkgJT4lIAogIHJlbmFtZShjb3VudD1uKSAlPiUgCiAgbXV0YXRlKGFydElkID0gZ3JvdXBfaW5kaWNlcyguLCBhcnRUaXRsZSkpCmdfYXJ0aWQKYGBgCgpgYGB7cn0KcmVzZXJ2ZWRfd29yZCA8LSBnX2FydGlkICU+JSAKICBncm91cF9ieSh3b3JkKSAlPiUgCiAgY291bnQoKSAlPiUgCiAgZmlsdGVyKG4gPiA1KSAlPiUgCiAgdW5saXN0KCkKZ19hcnRpZCA8LSBnX2FydGlkICU+JSAKICBmaWx0ZXIod29yZCAlaW4lIHJlc2VydmVkX3dvcmQpCmBgYAoKIyMg6L2J5o+b54K6RFRNCmBgYHtyfQpnX2NvbV9kdG0gPC0gZ19hcnRpZCAlPiUgY2FzdF9kdG0oYXJ0SWQsIHdvcmQsIGNvdW50KQpnX2NvbV9kdG0KYGBgCgojIyDovYnngrrliIbmiJDlhannvqTnmoRMREEKYGBge3J9CmdfbGRhIDwtIExEQShnX2NvbV9kdG0sIGsgPSAyLCBjb250cm9sID0gbGlzdChzZWVkID0gMTIzNCkpCmBgYAoKIyMgJFxwaGkkIE1hdHJpeAoKIyMjIOafpeeciyRccGhpJCBtYXRyaXggKHRvcGljICogdGVybSkKCmBgYHtyfQpnX3RvcGljcyA8LSB0aWR5KGdfbGRhLCBtYXRyaXggPSAiYmV0YSIpCmdfdG9waWNzCmBgYAoKIyMjIOeci+WIhuWHuuS+hueahOWFqeWAi3RvcGlj5Lit77yM5pyA5bi45Ye654++55qE6KmeCmBgYHtyfQpnX3RvcF90ZXJtcyA8LSBnX3RvcGljcyAlPiUKICBncm91cF9ieSh0b3BpYykgJT4lCiAgdG9wX24oMTAsIGJldGEpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKHRvcGljLCAtYmV0YSkKCnJlbW92ZV93b3JkcyA8LSBjKCLppKjplbciLCAi55u05pKtIiwgIumZs+S5i+a8oiIsICLlj7DngaMiKQoKZ190b3BfdGVybXMgPC0gZ190b3BpY3MgJT4lCiAgZmlsdGVyKCEgdGVybSAlaW4lIHJlbW92ZV93b3JkcykgJT4lIAogIGdyb3VwX2J5KHRvcGljKSAlPiUKICB0b3BfbigxMCwgYmV0YSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQoKZ190b3BfdGVybXMgJT4lCiAgbXV0YXRlKHRlcm0gPSByZW9yZGVyKHRlcm0sIGJldGEpKSAlPiUKICBnZ3Bsb3QoYWVzKHRlcm0sIGJldGEsIGZpbGwgPSBmYWN0b3IodG9waWMpKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKH4gdG9waWMsIHNjYWxlcyA9ICJmcmVlIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkKYGBgCj4g5Y+v55yL5Ye65Zyo5Y+q5YiG54K65YWp5YCL5Li76aGM55qE5oOF5rOB5LiL77yM57WQ5p6c5Lim5LiN5piv5b6I5piO56K644CC5Zug54K65Zyo5Li76aGM5LiA5Lit77yM6Zmk5LqG5YGl6Lqr5oi/5pys6Lqr55qE55So6Kme5aSW77yM6YKE5pyJ57Wx5L+D6buo6KKr5q246aGe5Zyo5LiA6LW344CCCj4g6ICM5Li76aGM5LqM5YmH5piO6aGv6IiH5pS/5rK76IiH57Wx542o55u46Zec44CCCgojIyMg5YWp5Li76aGM5LmL6ZaT55u45beu5pyA5aSn55qE6Kme5b2ZKHRvcGljMi90b3BpYzEpCmBgYHtyfQpiZXRhX3NwcmVhZCA8LSBnX3RvcGljcyAlPiUKICBtdXRhdGUodG9waWMgPSBwYXN0ZTAoInRvcGljIiwgdG9waWMpKSAlPiUKICBzcHJlYWQodG9waWMsIGJldGEpICU+JQogIGZpbHRlcih0b3BpYzEgPiAuMDAwNCB8IHRvcGljMiA+IC4wMDA0ICkgJT4lCiAgbXV0YXRlKGxvZ19yYXRpbyA9IGxvZzIodG9waWMyIC8gdG9waWMxKSkKCmdfdG9waWNfcmF0aW8gPC0gcmJpbmQoYmV0YV9zcHJlYWQgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgdG9wX24oMTAsd3QgPSBsb2dfcmF0aW8pLCAKICAgICAgICAgICAgICAgICAgICAgICBiZXRhX3NwcmVhZCAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfbigtMTAsIGxvZ19yYXRpbykpICU+JQogIGFycmFuZ2UobG9nX3JhdGlvKQoKZ190b3BpY19yYXRpbyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcih0ZXJtLCBsb2dfcmF0aW8pLCB5ID0gbG9nX3JhdGlvKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyAKICB4bGFiKCJXb3JkIikrCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKQpgYGAKPiDmraPotorlpKfooajnpLrotorlgr7lkJHkuLvpoYzkuozvvIzosqDotorlpKfotorlgr7lkJHkuLvpoYzkuIDvvIzlj6/nnIvlh7roiIflhYjliY3nmoToqZXoq5bnm7jlkIzjgII8YnI+Cj4g5Li76aGM5LiA5YK+5ZCR6IiH5YGl6Lqr5oi/55u46Zec77yM5Li76aGM5LqM6IiH5pS/5rK755u46Zec44CCCgojIyAkXHRoZXRhJCBtYXRyaXggIChkb2N1bWVudCAqIHRvcGljKQoKIyMjIOafpeeciyRcdGhldGEkIG1hdHJpeApgYGB7cn0KZ19kb2N1bWVudHMgPC0gdGlkeShnX2xkYSwgbWF0cml4PSJnYW1tYSIpCmdfZG9jdW1lbnRzCmBgYAoKIyMjIOafpeeci+acgOiiq+eiuuiqjeWcqOWFqeWAi+S4u+mhjOS4reeahOWJjeWNgeevh+aWh+eroOOAggpgYGB7cn0KZ19kb2N1bWVudHMkZG9jdW1lbnQ8LSBnX2RvY3VtZW50cyRkb2N1bWVudCAlPiUgYXMuaW50ZWdlcigpCmdfZG9jdW1lbnRzICU+JSAKICBncm91cF9ieSh0b3BpYykgJT4lIAogIHRvcF9uKDEwLGdhbW1hKSAlPiUgCiAgYXJyYW5nZSh0b3BpYykgJT4lIAogIGlubmVyX2pvaW4oZ19hcnRpZCAlPiUgZGlzdGluY3QoYXJ0VGl0bGUsYXJ0SWQpLCBieT1jKCJkb2N1bWVudCIgPSAiYXJ0SWQiKSkgJT4lIAogIHNlbGVjdCh0b3BpYywgYXJ0VGl0bGUsIGdhbW1hKQpgYGAKCj4g5Lmf5Y+v55yL5Ye66IiH5YWI5YmN5omA5LiL55qE57WQ6KuW55u46L+R77yM5Li76aGM5LiA5pyJ5YGl6Lqr5oi/55u46Zec6IiH57Wx5L+D6buo77yM5Y+m5aSW5Y+v55yL5Yiw6IiH6auY6ZuE5biC5pS/5bqc55u46Zec5LqL5Lu244CCPGJyPgo+IOS4u+mhjOS6jOWJh+WkmueCuuaUv+ayu+iIh+e1seeNqOebuOmXnOitsOmhjOOAggoKIyBMREF2aXMKPiDlj6rliIbngrrlhanlgIvkuLvpoYzlh7rkvobnmoTntZDmnpzkuKbkuI3mmK/lvojmmI7norrvvIzpgJnoo6HmlLnmiJDliIbngrrkuInlgIvkuLvpoYzjgIIKCmBgYHtyfQp0b3BpY21vZGVsc19qc29uX2xkYXZpcyA8LSBmdW5jdGlvbihmaXR0ZWQsIGRvY190ZXJtKXsKICAgIHJlcXVpcmUoTERBdmlzKQogICAgcmVxdWlyZShzbGFtKQoKICAgIHBoaSA8LSBhcy5tYXRyaXgocG9zdGVyaW9yKGZpdHRlZCkkdGVybXMpCiAgICB0aGV0YSA8LSBhcy5tYXRyaXgocG9zdGVyaW9yKGZpdHRlZCkkdG9waWNzKQogICAgdm9jYWIgPC0gY29sbmFtZXMocGhpKQogICAgdGVybV9mcmVxIDwtIHNsYW06OmNvbF9zdW1zKGRvY190ZXJtKQoKICAgIGpzb25fbGRhIDwtIExEQXZpczo6Y3JlYXRlSlNPTihwaGkgPSBwaGksIHRoZXRhID0gdGhldGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2b2NhYiA9IHZvY2FiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9jLmxlbmd0aCA9IGFzLnZlY3Rvcih0YWJsZShkb2NfdGVybSRpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJtLmZyZXF1ZW5jeSA9IHRlcm1fZnJlcSkKICAgIHJldHVybihqc29uX2xkYSkKfQpgYGAKCmBgYHtyfQpnX2xkYXZpcyA8LSBMREEoZ19jb21fZHRtLCBrID0gMywgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDEyMzQpKQoKanNvbl9yZXMgPC0gdG9waWNtb2RlbHNfanNvbl9sZGF2aXMoZ19sZGF2aXMsZ19jb21fZHRtKQoKc2VyVmlzKGpzb25fcmVzLCBvcGVuLmJyb3dzZXIgPSBUKQpgYGAKIVtdKHRvcGljMS5wbmcpCgo+IOiIh+WBpei6q+aIv+ebuOmXnOOAggoKIVtdKHRvcGljMi5wbmcpCgo+IOiIh+aUv+ayu+WSjOe1seeNqOebuOmXnOOAggoKIVtdKHRvcGljMy5wbmcpCgo+IOiIh+e1seS/g+m7qOebuOmXnOOAggoKPiDlnKjliIbmiJDkuInlgIvkuLvpoYznmoToqK3lrprkuIvvvIzlsIfntbHkv4Ppu6jnm7jpl5znmoToqZ7lvp7ljp/lhYjoiIflgaXouqvmiL/nm7jpl5znmoToqZ7kuK3vvIznjajnq4vmiJDkuIDlgIvmlrDnmoTkuLvpoYzjgIIKCiMg5YiG5p6Q6aSo6ZW354ax5bqm5q235LmF5LiN6KGw55qE5Y6f5ZugCgpgYGB7cn0KZGF0ZV9wbG90CmBgYAo+IOaMgee6jOWwjeWkp+WutijphInmsJEp5pyJ6IiI6Laj55qE6K2w6aGM55m86KGo55yL5rOV44CCCgohW10od29yZGNsb3VkLnBuZykKCj4g6YCP6YGO55u05pKt6KuH6KuW5pS/5rK76K2w6aGM5oiW5YGl6Lqr5oi/55u46Zec5LqL5Lu244CCCgpgYGB7cn0KZ19jc3YgJT4lIAogIHNlbGVjdChhcnRUaXRsZSwgY29tbWVudE51bSwgcHVzaCwgYm9vKSAlPiUgCiAgZmlsdGVyKGNvbW1lbnROdW0gPj0gMjApICU+JSAKICBtdXRhdGUocF9yYXRpbyA9IHB1c2gvY29tbWVudE51bSwgYl9yYXRpbyA9IGJvby9jb21tZW50TnVtKSAlPiUgCiAgYXJyYW5nZSgtcF9yYXRpbykKYGBgCj4g5aSn5a625bCN5pa86aSo6ZW35pS/5rK756uL5aC055u46Zec55qE55m86KiA77yM5o6o5paH55qE5q+U5L6L6YO95piv5YGP6auY55qE77yM5Y+v6KaL5b6I5ZCI6YSJ5rCR55qE6IOD5Y+j44CCCgojIOe1kOirlgo+IOmkqOmVt+WcqFBQVOS4iuiojuirluW6puavj+WkqemDvee2reaMgeWkp+aWvDHnr4fnmoTmlofnq6DmlbjvvIwKPiDogIzlnKjpgJnkupvmlofnq6DkuK3vvIzlj6/ku6Xnmbznj77mnIPlvJXotbfphInmsJHoqI7oq5bkuLvopoHmmK/ppKjplbfnmoTnm7Tmkq3lhaflrrnjgIIKPiDppKjplbflnKjnm7Tmkq3kuK3lpKfpg6jliIbmmK/lnKjoq4fmlL/msrvorbDpoYzvvIzku6Xlj4rlubPluLjnmoTmmYLkuovvvIwKPiDnlLHliIbmnpDkuK3lj6/ku6Xnmbznj77vvIzmlL/msrvorbDpoYzmnIDog73lpKDmv4DotbfphInmsJHnmoToqI7oq5bvvIzkvovlpoI657Wx5L+D6buo44CB57Wx5LiA44CB5Lit5ZyL44CB6Z+T5ZyL55GcLi4u562J562JCj4g5Y+N5YCS5piv5YGl6Lqr5oi/6KiO6KuW5bqm6LyD5bCR44CCCgoKCgo=