主題

分析PTT八卦版對太魯閣號出軌事件的文字資料

動機與分析目的

  • 背景與動機
    • 清明連假正是大家準備開心祭祖或是出遊的日子,大眾交通工具成為提供大家往返的工具,尤其是台鐵鐵路運輸的環島交通網,更是往來西岸與東岸最便利的方式,連假的第一天是交通最繁忙的一天,台鐵的太魯閣號卻因為施工單位的疏忽發生了嚴重的出軌意外,造成247輕重傷、49人死亡的悲劇;這場意外究竟是單純外包施工廠商,抑或是積習已久的台灣鐵路公司監督不周所造成的。
  • 研究目的
    1. 了解民眾對於太魯閣號事件的態度。
    2. 網民認為太魯閣號的責任歸屬。
    3. 太魯閣號出軌事件後該做的事。

資料集描述

  • 資料來源:中山大學管理學院文字分析平台收集PT T八卦版文章取得之原始csv檔案。
  • 資料集:PPT八卦版。
  • 資料日期區間:2021.03.31~2021.04.14。
  • 資料的關鍵字:檢索「台鐵」、「李義祥」、「太魯閣」、「工程車」、「義祥」、「出軌」六個關鍵字,共搜尋出1485篇文章。

ch 01前置作業

Sys.setlocale(category = "LC_ALL", locale = "zh_TW.UTF-8") # 避免中文亂碼

安裝需要的packages

packages = c("readr", "dplyr", "stringr", "jiebaR", "tidytext", "NLP", "readr", "tidyr", "ggplot2", "ggraph", "igraph", "scales", "reshape2", "widyr")
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)

將require及library載入

require(data.table)
require(dplyr)
require(readr)
require(dplyr)
require(stringr)
require(jiebaR)
require(tidytext)
require(NLP)
require(tidyr)
require(ggplot2)
require(ggraph)
require(igraph)
require(scales)
require(reshape2)
require(widyr)

library(data.table)
require(wordcloud2)
require(lubridate)
require(htmlwidgets)
require(webshot)
require(plotly)
require( RColorBrewer)

require(servr)
require(tm)
require(data.table)
require(stringr)
library(topicmodels)
require(LDAvis)
require(webshot)

載入自平台下載下來的資料

rd <- read_csv("太魯閣事件_artWordFreq.csv")
rd2 <- read_csv("太魯閣事件_articleMetaData.csv")

rd$artDate <- rd$artDate %>% as.Date("%Y/%m/%d")
rd

ch 02 折線圖

資料處理

data <- rd %>% 
  dplyr::select(artDate, artUrl) %>% 
  distinct()
article_count_by_date <- data %>% 
  group_by(artDate) %>% 
  summarise(count = n())
head(article_count_by_date, 20)

太魯閣事件在PTT八卦版3/31~4/14聲量折線圖

plot_date <- 
  # data
  article_count_by_date %>% 
  # aesthetics
  ggplot(aes(x = artDate, y = count)) +
  # geometrics
  geom_line(color = "#00AFBB", size = 1) + 
  # coordinates
  scale_x_date(labels = date_format("%Y/%m/%d")) +
  ggtitle("PTT 八卦版 討論文章數") + 
  xlab("日期") + 
  ylab("數量") + 
  # theme
  theme() #加入中文字型設定,避免中文字顯示錯誤。

plot_date

ch 03 文字雲

資料處理

data <- rd %>% 
  group_by(word) %>% 
  summarise(sum = sum(count), .groups = 'drop') %>% 
  arrange(desc(sum))
head(data)

太魯閣事件在PTT八卦版3/31~4/14文字雲

data %>% filter(sum > 50) %>% wordcloud2()

ch 04 常出現的詞彙

資料處理

rd_tokens <- rd %>%
  select(-artTime, -artUrl)
head(rd_tokens)
rd_tokens_by_date <- rd_tokens %>% 
  count(artDate, word, sort = TRUE) %>%
  filter(n > 5)

太魯閣事件在PTT八卦版4/2~4/10每天最常見的10個詞彙

stop_words <- scan(file = "dict/stop_words.txt", what=character(),sep='\n', 
                   encoding='utf-8',fileEncoding='utf-8')
plot_merge <- rd_tokens_by_date %>% 
  filter(!(word %in% stop_words) & !(word %in% "台鐵")) %>%
  filter(artDate == as.Date("2021-04-02") | 
         artDate == as.Date("2021-04-03") | 
         artDate == as.Date("2021-04-04") |
         artDate == as.Date("2021-04-05") | 
         artDate == as.Date("2021-04-06") | 
         artDate == as.Date("2021-04-07") | 
         artDate == as.Date("2021-04-08") | 
         artDate == as.Date("2021-04-09") | 
         artDate == as.Date("2021-04-10")) %>% 
  group_by(artDate) %>% 
  top_n(10, 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 = 5) + 
  coord_flip()+
  theme(text = element_text())
plot_merge

ch 05 情緒分析

載入情緒分析字典

# 正向字典txt檔
# 以,將字分隔
P <- read_file("dict/positive.txt")

# 負向字典txt檔
N <- read_file("dict/negative.txt")
#將字串依,分割
#strsplit回傳list , 我們取出list中的第一個元素
P = strsplit(P, ",")[[1]]
N = strsplit(N, ",")[[1]]

# 建立dataframe 有兩個欄位word,sentiments,word欄位內容是字典向量
P = data.frame(word = P, sentiment = "positive")
N = data.frame(word = N, sentiment = "negative")
LIWC = rbind(P, N)
rd_tokens_by_date %>%
  inner_join(LIWC) %>%
  select(word) %>%
  inner_join(LIWC) 
sentiment_count = rd_tokens_by_date %>%
  select(artDate,word,n) %>%
  inner_join(LIWC) %>% 
  group_by(artDate,sentiment) %>%
  summarise(count=sum(n))

初始化斷詞引擎

# 加入自定義的字典
jieba_tokenizer <- worker(user="dict/user_dict.txt", stop_word = "dict/stop_words.txt")

# 設定斷詞function
chi_tokenizer <- function(t) {
  lapply(t, function(x) {
    if(nchar(x)>1){
      tokens <- segment(x, jieba_tokenizer)
      # 去掉字串長度爲1的詞彙
      tokens <- tokens[nchar(tokens)>1]
      return(tokens)
    }
  })
}

太魯閣事件在PTT八卦版3/31~4/14正負面情緒聲量折線圖


sentiment_count %>%
  ggplot() +
  geom_line(aes(x=artDate,y=count,colour=sentiment)) +
  labs(x=NULL,y="數量")

  scale_x_date(labels = date_format("%m/%d"))  
rd_tokens_all <- rd2 %>%
  unnest_tokens(word, sentence, token=chi_tokenizer) %>% 
  select(-artTime)

太魯閣事件在PTT八卦版4/2~4/8正負情緒長條圖

rd_tokens_all %>%
  filter(artDate == as.Date("2021-04-02") |
         artDate == as.Date("2021-04-03") | 
         artDate == as.Date("2021-04-04") | 
         artDate == as.Date("2021-04-05") |
         artDate == as.Date("2021-04-06") |
         artDate == as.Date("2021-04-07") |
         artDate == as.Date("2021-04-08") ) %>% 
  inner_join(LIWC) %>%
  group_by(word,sentiment) %>%
  summarise(
    count = n()
  ) %>% data.frame() %>% 
  top_n(30,wt = count) %>%
  ungroup() %>% 
  mutate(word = reorder(word, count)) %>%
  ggplot(aes(word, count, fill = sentiment)) +
  geom_col(show.legend = FALSE) +
  labs(x= "文字", y="數量") +
  facet_wrap(~sentiment, scales = "free_y") +
  theme(text=element_text(size=14))+
  coord_flip()
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 <- rd2 %>%
  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 = " ")
head(g_ngrams_11_separated)
g_check_words <- g_ngrams_11_separated %>%
  filter((word6 == "太魯閣"))
g_check_words

太魯閣事件在PTT八卦版出現在「太魯閣」附近的字

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())
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 <- rd2 %>%
  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

太魯閣事件在PTT八卦版出現在「台鐵」附近的字

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())
# 進行斷詞,並計算各詞彙在各文章中出現的次數
rd_words <- rd2 %>%
  unnest_tokens(word, sentence, token=chi_tokenizer) %>%
  filter(!str_detect(word, regex("[0-9a-zA-Z]"))) %>%
  count(artUrl, word, sort = TRUE)
head(rd_words)
# 計算每篇文章包含的詞數
total_words <- rd_words %>% 
  group_by(artUrl) %>% 
  summarize(total = sum(n))
head(total_words)
# 合併 mask_words(每個詞彙在每個文章中出現的次數)
# 與 total_words(每篇文章的詞數)
# 新增各個詞彙在所有詞彙中的總數欄位
rd_words <- left_join(rd_words, total_words)
head(rd_words)
# 以每篇文章爲單位,計算每個詞彙在的tf-idf值
rd_words_tf_idf <- rd_words %>%
  bind_tf_idf(word, artUrl, n)
#rd_words_tf_idf
# 選出每篇文章,tf-idf最大的十個詞
rd_words_tf_idf %>% 
  group_by(artUrl) %>%
  top_n(10) %>%
  arrange(desc(artUrl))
# 選每篇文章,tf-idf最大的十個詞,
# 並查看每個詞被選中的次數
rd_words_tf_idf %>% 
  group_by(artUrl) %>%
  top_n(10) %>%
  arrange(desc(artUrl)) %>%
  ungroup() %>%
  count(word, sort=TRUE)
# 計算兩個詞彙間的相關性
stop_words <- scan(file = "dict/stop_words.txt", what=character(),sep='\n', 
                   encoding='utf-8',fileEncoding='utf-8')
word_cors <- rd_words %>%
  group_by(word) %>%
  filter(n() >= 20) %>%
  filter(!(word %in% stop_words)&&!(word %in% "記者")) %>%
  pairwise_cor(word, artUrl, sort = TRUE)

#word_cors
# 與太魯閣相關性高的詞彙
word_cors %>%
  filter(item1 == "太魯閣") %>% 
  head(5)
# 與義祥相關性高的詞彙
word_cors %>%
  filter(item1 == "義祥") %>% 
  head(5)
# 與台鐵相關性高的詞彙
word_cors %>%
  filter(item1 == "台鐵") %>% 
  head(5)

太魯閣事件在PTT八卦版出現在「 “台鐵”, “太魯閣”, “政府”, “義祥” 」相關性最高的 10 個詞彙

# 分別尋找與 "台鐵", "太魯閣", "政府", "義祥" 相關性最高的 10 個詞彙
word_cors %>%
  filter(item1 %in% c("台鐵", "太魯閣", "政府", "義祥")) %>%
  group_by(item1) %>%
  top_n(10) %>%
  ungroup() %>%
  mutate(item2 = reorder(item2, correlation)) %>%
  ggplot(aes(item2, correlation)) +
  geom_bar(stat = "identity") +
  labs(x=NULL,y=NULL) + 
  facet_wrap(~ item1, scales = "free") +
  coord_flip()+ 
  theme(text = element_text())

ch 06 共線相關圖

太魯閣事件在PTT八卦版共線相關圖

# 顯示相關性大於0.4的組合
set.seed(2020)
word_cors %>%
  filter(correlation > 0.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) + #加入中文字型設定,避免中文字顯示錯誤。
  theme_void()
# 顯示相關性大於0.5的組合
set.seed(2020)

word_cors %>%
  filter(correlation > 0.5) %>%
  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) +
  theme_void()

結論

在整個事件中,大眾認為太魯閣號的責任應歸咎於台鐵和政府,並希望在太魯閣事件後台鐵能效法高鐵將公司民營化或公司化,避免未來再有憾事發生。

LS0tDQp0aXRsZTogIuWIhuaekFBUVOWFq+WNpueJiOWwjeWkqumtr+mWo+iZn+WHuui7jOS6i+S7tueahOaWh+Wtl+izh+aWmSINCmF1dGhvcjogIk4wOTQwMjAwMTcg5p6X56WQ5pawLCBOMDk0MDIwMDM0IOiUoeiKuOW5sywgTjA5NDAyMDAzMiDphJLlsrHkvZEsIE4wOTQwMjAwMDEg5a6L5piO5q+FIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICBjc3M6IHN0eWxlLmNzcw0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCiMjIOS4u+mhjA0KPiDliIbmnpBQVFTlhavljabniYjlsI3lpKrpra/plqPomZ/lh7rou4zkuovku7bnmoTmloflrZfos4fmlpkNCg0KIyDli5XmqZ/oiIfliIbmnpDnm67nmoQNCi0g6IOM5pmv6IiH5YuV5qmfDQogICsg5riF5piO6YCj5YGH5q2j5piv5aSn5a625rqW5YKZ6ZaL5b+D56Wt56WW5oiW5piv5Ye66YGK55qE5pel5a2Q77yM5aSn55y+5Lqk6YCa5bel5YW35oiQ54K65o+Q5L6b5aSn5a625b6A6L+U55qE5bel5YW377yM5bCk5YW25piv5Y+w6ZC16ZC16Lev6YGL6Ly455qE55Kw5bO25Lqk6YCa57ay77yM5pu05piv5b6A5L6G6KW/5bK46IiH5p2x5bK45pyA5L6/5Yip55qE5pa55byP77yM6YCj5YGH55qE56ys5LiA5aSp5piv5Lqk6YCa5pyA57mB5b+Z55qE5LiA5aSp77yM5Y+w6ZC155qE5aSq6a2v6Zaj6Jmf5Y275Zug54K65pa95bel5Zau5L2N55qE55aP5b+955m855Sf5LqG5Zq06YeN55qE5Ye66LuM5oSP5aSW77yM6YCg5oiQMjQ36LyV6YeN5YK344CBNDnkurrmrbvkuqHnmoTmgrLliofvvJvpgJnloLTmhI/lpJbnqbbnq5/mmK/llq7ntJTlpJbljIXmlr3lt6Xlu6DllYbvvIzmipHmiJbmmK/nqY3nv5Llt7LkuYXnmoTlj7DngaPpkLXot6/lhazlj7jnm6PnnaPkuI3lkajmiYDpgKDmiJDnmoTjgIINCg0KKyDnoJTnqbbnm67nmoQNCiAgIDEuIOS6huino+awkeecvuWwjeaWvOWkqumtr+mWo+iZn+S6i+S7tueahOaFi+W6puOAgjwvYnI+DQogICAyLiDntrLmsJHoqo3ngrrlpKrpra/plqPomZ/nmoTosqzku7vmrbjlsazjgII8L2JyPg0KICAgMy4g5aSq6a2v6Zaj6Jmf5Ye66LuM5LqL5Lu25b6M6Kmy5YGa55qE5LqL44CCPC9icj4NCg0KIyMg6LOH5paZ6ZuG5o+P6L+wDQorIOizh+aWmeS+hua6kO+8muS4reWxseWkp+WtuOeuoeeQhuWtuOmZouaWh+Wtl+WIhuaekOW5s+WPsOaUtumbhlBUIFTlhavljabniYjmlofnq6Dlj5blvpfkuYvljp/lp4tjc3bmqpTmoYjjgIINCisg6LOH5paZ6ZuG77yaUFBU5YWr5Y2m54mI44CCDQorIOizh+aWmeaXpeacn+WNgOmWk++8mjIwMjEuMDMuMzF+MjAyMS4wNC4xNOOAgg0KKyDos4fmlpnnmoTpl5zpjbXlrZc65qqi57Si44CM5Y+w6ZC144CN44CB44CM5p2O576p56Wl44CN44CB44CM5aSq6a2v6Zaj44CN44CB44CM5bel56iL6LuK44CN44CB44CM576p56Wl44CN44CB44CM5Ye66LuM44CN5YWt5YCL6Zec6Y215a2X77yM5YWx5pCc5bCL5Ye6MTQ4Neevh+aWh+eroOOAgg0KDQojIGNoIDAx5YmN572u5L2c5qWtDQpgYGB7cn0NClN5cy5zZXRsb2NhbGUoY2F0ZWdvcnkgPSAiTENfQUxMIiwgbG9jYWxlID0gInpoX1RXLlVURi04IikgIyDpgb/lhY3kuK3mlofkuoLnorwNCmBgYA0KDQojIyDlronoo53pnIDopoHnmoRwYWNrYWdlcw0KYGBge3J9DQpwYWNrYWdlcyA9IGMoInJlYWRyIiwgImRwbHlyIiwgInN0cmluZ3IiLCAiamllYmFSIiwgInRpZHl0ZXh0IiwgIk5MUCIsICJyZWFkciIsICJ0aWR5ciIsICJnZ3Bsb3QyIiwgImdncmFwaCIsICJpZ3JhcGgiLCAic2NhbGVzIiwgInJlc2hhcGUyIiwgIndpZHlyIikNCmV4aXN0aW5nID0gYXMuY2hhcmFjdGVyKGluc3RhbGxlZC5wYWNrYWdlcygpWywxXSkNCmZvcihwa2cgaW4gcGFja2FnZXNbIShwYWNrYWdlcyAlaW4lIGV4aXN0aW5nKV0pIGluc3RhbGwucGFja2FnZXMocGtnKQ0KYGBgDQoNCiMjIOWwh3JlcXVpcmXlj4psaWJyYXJ56LyJ5YWlDQpgYGB7cn0NCnJlcXVpcmUoZGF0YS50YWJsZSkNCnJlcXVpcmUoZHBseXIpDQpyZXF1aXJlKHJlYWRyKQ0KcmVxdWlyZShkcGx5cikNCnJlcXVpcmUoc3RyaW5ncikNCnJlcXVpcmUoamllYmFSKQ0KcmVxdWlyZSh0aWR5dGV4dCkNCnJlcXVpcmUoTkxQKQ0KcmVxdWlyZSh0aWR5cikNCnJlcXVpcmUoZ2dwbG90MikNCnJlcXVpcmUoZ2dyYXBoKQ0KcmVxdWlyZShpZ3JhcGgpDQpyZXF1aXJlKHNjYWxlcykNCnJlcXVpcmUocmVzaGFwZTIpDQpyZXF1aXJlKHdpZHlyKQ0KDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpyZXF1aXJlKHdvcmRjbG91ZDIpDQpyZXF1aXJlKGx1YnJpZGF0ZSkNCnJlcXVpcmUoaHRtbHdpZGdldHMpDQpyZXF1aXJlKHdlYnNob3QpDQpyZXF1aXJlKHBsb3RseSkNCnJlcXVpcmUoIFJDb2xvckJyZXdlcikNCg0KcmVxdWlyZShzZXJ2cikNCnJlcXVpcmUodG0pDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKHN0cmluZ3IpDQpsaWJyYXJ5KHRvcGljbW9kZWxzKQ0KcmVxdWlyZShMREF2aXMpDQpyZXF1aXJlKHdlYnNob3QpDQpgYGANCg0KIyMg6LyJ5YWl6Ieq5bmz5Y+w5LiL6LyJ5LiL5L6G55qE6LOH5paZDQpgYGB7cn0NCnJkIDwtIHJlYWRfY3N2KCLlpKrpra/plqPkuovku7ZfYXJ0V29yZEZyZXEuY3N2IikNCnJkMiA8LSByZWFkX2Nzdigi5aSq6a2v6Zaj5LqL5Lu2X2FydGljbGVNZXRhRGF0YS5jc3YiKQ0KDQpyZCRhcnREYXRlIDwtIHJkJGFydERhdGUgJT4lIGFzLkRhdGUoIiVZLyVtLyVkIikNCnJkDQpgYGANCg0KDQojIGNoIDAyIOaKmOe3muWclg0KIyMg6LOH5paZ6JmV55CGDQpgYGB7cn0NCmRhdGEgPC0gcmQgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGFydERhdGUsIGFydFVybCkgJT4lIA0KICBkaXN0aW5jdCgpDQpgYGANCg0KYGBge3J9DQphcnRpY2xlX2NvdW50X2J5X2RhdGUgPC0gZGF0YSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUpICU+JSANCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChhcnRpY2xlX2NvdW50X2J5X2RhdGUsIDIwKQ0KYGBgDQoNCg0KIyMg5aSq6a2v6Zaj5LqL5Lu25ZyoUFRU5YWr5Y2m54mIMy8zMX40LzE06IGy6YeP5oqY57ea5ZyWDQpgYGB7cn0NCnBsb3RfZGF0ZSA8LSANCiAgIyBkYXRhDQogIGFydGljbGVfY291bnRfYnlfZGF0ZSAlPiUgDQogICMgYWVzdGhldGljcw0KICBnZ3Bsb3QoYWVzKHggPSBhcnREYXRlLCB5ID0gY291bnQpKSArDQogICMgZ2VvbWV0cmljcw0KICBnZW9tX2xpbmUoY29sb3IgPSAiIzAwQUZCQiIsIHNpemUgPSAxKSArIA0KICAjIGNvb3JkaW5hdGVzDQogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJVkvJW0vJWQiKSkgKw0KICBnZ3RpdGxlKCJQVFQg5YWr5Y2m54mIIOiojuirluaWh+eroOaVuCIpICsgDQogIHhsYWIoIuaXpeacnyIpICsgDQogIHlsYWIoIuaVuOmHjyIpICsgDQogICMgdGhlbWUNCiAgdGhlbWUoKSAj5Yqg5YWl5Lit5paH5a2X5Z6L6Kit5a6a77yM6YG/5YWN5Lit5paH5a2X6aGv56S66Yyv6Kqk44CCDQoNCnBsb3RfZGF0ZQ0KYGBgDQoNCiMgY2ggMDMg5paH5a2X6ZuyDQojIyDos4fmlpnomZXnkIYNCmBgYHtyfQ0KZGF0YSA8LSByZCAlPiUgDQogIGdyb3VwX2J5KHdvcmQpICU+JSANCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShjb3VudCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgYXJyYW5nZShkZXNjKHN1bSkpDQpgYGANCg0KYGBge3J9DQpoZWFkKGRhdGEpDQpgYGANCg0KIyMg5aSq6a2v6Zaj5LqL5Lu25ZyoUFRU5YWr5Y2m54mIMy8zMX40LzE05paH5a2X6ZuyDQpgYGB7cn0NCmRhdGEgJT4lIGZpbHRlcihzdW0gPiA1MCkgJT4lIHdvcmRjbG91ZDIoKQ0KYGBgDQoNCg0KIyBjaCAwNCDluLjlh7rnj77nmoToqZ7lvZkNCiMjIOizh+aWmeiZleeQhg0KYGBge3J9DQpyZF90b2tlbnMgPC0gcmQgJT4lDQogIHNlbGVjdCgtYXJ0VGltZSwgLWFydFVybCkNCmhlYWQocmRfdG9rZW5zKQ0KYGBgDQoNCg0KYGBge3J9DQpyZF90b2tlbnNfYnlfZGF0ZSA8LSByZF90b2tlbnMgJT4lIA0KICBjb3VudChhcnREYXRlLCB3b3JkLCBzb3J0ID0gVFJVRSkgJT4lDQogIGZpbHRlcihuID4gNSkNCmBgYA0KDQojIyDlpKrpra/plqPkuovku7blnKhQVFTlhavljabniYg0LzJ+NC8xMOavj+WkqeacgOW4uOimi+eahDEw5YCL6Kme5b2ZDQpgYGB7cn0NCnN0b3Bfd29yZHMgPC0gc2NhbihmaWxlID0gImRpY3Qvc3RvcF93b3Jkcy50eHQiLCB3aGF0PWNoYXJhY3RlcigpLHNlcD0nXG4nLCANCiAgICAgICAgICAgICAgICAgICBlbmNvZGluZz0ndXRmLTgnLGZpbGVFbmNvZGluZz0ndXRmLTgnKQ0KcGxvdF9tZXJnZSA8LSByZF90b2tlbnNfYnlfZGF0ZSAlPiUgDQogIGZpbHRlcighKHdvcmQgJWluJSBzdG9wX3dvcmRzKSAmICEod29yZCAlaW4lICLlj7DpkLUiKSkgJT4lDQogIGZpbHRlcihhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDIiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTAzIikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wNCIpIHwNCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wNSIpIHwgDQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDYiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA3IikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wOCIpIHwgDQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDkiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTEwIikpICU+JSANCiAgZ3JvdXBfYnkoYXJ0RGF0ZSkgJT4lIA0KICB0b3BfbigxMCwgbikgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9d29yZCwgeT1uLCBmaWxsID0gYXJ0RGF0ZSkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICBmYWNldF93cmFwKH5hcnREYXRlLCBzY2FsZXM9ImZyZWUiLCBuY29sID0gNSkgKyANCiAgY29vcmRfZmxpcCgpKw0KICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KCkpDQpwbG90X21lcmdlDQpgYGANCg0KDQojIGNoIDA1IOaDhee3kuWIhuaekA0KIyMg6LyJ5YWl5oOF57eS5YiG5p6Q5a2X5YW4DQpgYGB7cn0NCiMg5q2j5ZCR5a2X5YW4dHh05qqUDQojIOS7pSzlsIflrZfliIbpmpQNClAgPC0gcmVhZF9maWxlKCJkaWN0L3Bvc2l0aXZlLnR4dCIpDQoNCiMg6LKg5ZCR5a2X5YW4dHh05qqUDQpOIDwtIHJlYWRfZmlsZSgiZGljdC9uZWdhdGl2ZS50eHQiKQ0KYGBgDQoNCmBgYHtyfQ0KI+Wwh+Wtl+S4suS+nSzliIblibINCiNzdHJzcGxpdOWbnuWCs2xpc3QgLCDmiJHlgJHlj5blh7psaXN05Lit55qE56ys5LiA5YCL5YWD57SgDQpQID0gc3Ryc3BsaXQoUCwgIiwiKVtbMV1dDQpOID0gc3Ryc3BsaXQoTiwgIiwiKVtbMV1dDQoNCiMg5bu656uLZGF0YWZyYW1lIOacieWFqeWAi+ashOS9jXdvcmQsc2VudGltZW50c++8jHdvcmTmrITkvY3lhaflrrnmmK/lrZflhbjlkJHph48NClAgPSBkYXRhLmZyYW1lKHdvcmQgPSBQLCBzZW50aW1lbnQgPSAicG9zaXRpdmUiKQ0KTiA9IGRhdGEuZnJhbWUod29yZCA9IE4sIHNlbnRpbWVudCA9ICJuZWdhdGl2ZSIpDQpgYGANCg0KYGBge3J9DQpMSVdDID0gcmJpbmQoUCwgTikNCmBgYA0KDQpgYGB7cn0NCnJkX3Rva2Vuc19ieV9kYXRlICU+JQ0KICBpbm5lcl9qb2luKExJV0MpICU+JQ0KICBzZWxlY3Qod29yZCkgJT4lDQogIGlubmVyX2pvaW4oTElXQykgDQpgYGANCg0KYGBge3J9DQpzZW50aW1lbnRfY291bnQgPSByZF90b2tlbnNfYnlfZGF0ZSAlPiUNCiAgc2VsZWN0KGFydERhdGUsd29yZCxuKSAlPiUNCiAgaW5uZXJfam9pbihMSVdDKSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUsc2VudGltZW50KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50PXN1bShuKSkNCmBgYA0KDQojIyDliJ3lp4vljJbmlrfoqZ7lvJXmk44NCmBgYHtyfQ0KIyDliqDlhaXoh6rlrprnvqnnmoTlrZflhbgNCmppZWJhX3Rva2VuaXplciA8LSB3b3JrZXIodXNlcj0iZGljdC91c2VyX2RpY3QudHh0Iiwgc3RvcF93b3JkID0gImRpY3Qvc3RvcF93b3Jkcy50eHQiKQ0KDQojIOioreWumuaWt+ipnmZ1bmN0aW9uDQpjaGlfdG9rZW5pemVyIDwtIGZ1bmN0aW9uKHQpIHsNCiAgbGFwcGx5KHQsIGZ1bmN0aW9uKHgpIHsNCiAgICBpZihuY2hhcih4KT4xKXsNCiAgICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikNCiAgICAgICMg5Y675o6J5a2X5Liy6ZW35bqm54iyMeeahOipnuW9mQ0KICAgICAgdG9rZW5zIDwtIHRva2Vuc1tuY2hhcih0b2tlbnMpPjFdDQogICAgICByZXR1cm4odG9rZW5zKQ0KICAgIH0NCiAgfSkNCn0NCmBgYA0KDQojIyDlpKrpra/plqPkuovku7blnKhQVFTlhavljabniYgzLzMxfjQvMTTmraPosqDpnaLmg4Xnt5LogbLph4/mipjnt5rlnJYNCmBgYHtyfQ0KDQpzZW50aW1lbnRfY291bnQgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4PWFydERhdGUseT1jb3VudCxjb2xvdXI9c2VudGltZW50KSkgKw0KICBsYWJzKHg9TlVMTCx5PSLmlbjph48iKQ0KDQogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJW0vJWQiKSkgIA0KYGBgDQpgYGB7cn0NCnJkX3Rva2Vuc19hbGwgPC0gcmQyICU+JQ0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIHNlbnRlbmNlLCB0b2tlbj1jaGlfdG9rZW5pemVyKSAlPiUgDQogIHNlbGVjdCgtYXJ0VGltZSkNCmBgYA0KDQojIyDlpKrpra/plqPkuovku7blnKhQVFTlhavljabniYg0LzJ+NC845q2j6LKg5oOF57eS6ZW35qKd5ZyWDQpgYGB7cn0NCnJkX3Rva2Vuc19hbGwgJT4lDQogIGZpbHRlcihhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDIiKSB8DQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDMiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA0IikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wNSIpIHwNCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wNiIpIHwNCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wNyIpIHwNCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wOCIpICkgJT4lIA0KICBpbm5lcl9qb2luKExJV0MpICU+JQ0KICBncm91cF9ieSh3b3JkLHNlbnRpbWVudCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBjb3VudCA9IG4oKQ0KICApICU+JSBkYXRhLmZyYW1lKCkgJT4lIA0KICB0b3BfbigzMCx3dCA9IGNvdW50KSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIGNvdW50KSkgJT4lDQogIGdncGxvdChhZXMod29yZCwgY291bnQsIGZpbGwgPSBzZW50aW1lbnQpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgbGFicyh4PSAi5paH5a2XIiwgeT0i5pW46YePIikgKw0KICBmYWNldF93cmFwKH5zZW50aW1lbnQsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KDQoNCg0KYGBge3J9DQpuZ3JhbV8xMSA8LSBmdW5jdGlvbih0KSB7DQogIGxhcHBseSh0LCBmdW5jdGlvbih4KSB7DQogICAgdG9rZW5zIDwtIHNlZ21lbnQoeCwgamllYmFfdG9rZW5pemVyKQ0KICAgIG5ncmFtIDwtIG5ncmFtcyh0b2tlbnMsIDExKQ0KICAgIG5ncmFtIDwtIGxhcHBseShuZ3JhbSwgcGFzdGUsIGNvbGxhcHNlID0gIiAiKQ0KICAgIHVubGlzdChuZ3JhbSkNCiAgfSkNCn0NCmdfbmdyYW1fMTEgPC0gcmQyICU+JQ0KICBzZWxlY3QoYXJ0VXJsLCBzZW50ZW5jZSkgJT4lDQogIHVubmVzdF90b2tlbnMobmdyYW0sIHNlbnRlbmNlLCB0b2tlbiA9IG5ncmFtXzExKSAlPiUNCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KG5ncmFtLCByZWdleCgiWzAtOWEtekEtWl0iKSkpDQpnX25ncmFtc18xMV9zZXBhcmF0ZWQgPC0gZ19uZ3JhbV8xMSAlPiUNCiAgc2VwYXJhdGUobmdyYW0sIHBhc3RlMCgid29yZCIsIGMoMToxMSksc2VwPSIiKSwgc2VwID0gIiAiKQ0KaGVhZChnX25ncmFtc18xMV9zZXBhcmF0ZWQpDQpgYGANCg0KYGBge3J9DQpnX2NoZWNrX3dvcmRzIDwtIGdfbmdyYW1zXzExX3NlcGFyYXRlZCAlPiUNCiAgZmlsdGVyKCh3b3JkNiA9PSAi5aSq6a2v6ZajIikpDQpnX2NoZWNrX3dvcmRzDQpgYGANCg0KIyMg5aSq6a2v6Zaj5LqL5Lu25ZyoUFRU5YWr5Y2m54mI5Ye654++5Zyo44CM5aSq6a2v6Zaj44CN6ZmE6L+R55qE5a2XDQpgYGB7cn0NCmdfY2hlY2tfd29yZHNfY291bnQgPC0gZ19jaGVja193b3JkcyAlPiUNCiAgbWVsdChpZC52YXJzID0gImFydFVybCIsIG1lYXN1cmUudmFycyA9IHBhc3RlMCgid29yZCIsIGMoMToxMSksc2VwPSIiKSkgJT4lDQogIHJlbmFtZSh3b3JkPXZhbHVlKSAlPiUNCiAgZmlsdGVyKHZhcmlhYmxlIT0id29yZDYiKSAlPiUNCiAgZmlsdGVyKCEod29yZCAlaW4lIHN0b3Bfd29yZHMpLCBuY2hhcih3b3JkKT4xKSAlPiUNCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpDQpnX2NoZWNrX3dvcmRzX2NvdW50ICU+JQ0KICBhcnJhbmdlKGRlc2MoYWJzKG4pKSkgJT4lDQogIGhlYWQoMTUpICU+JQ0KICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQ0KICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBuID4gMCkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICB4bGFiKCLlh7rnj77lnKjjgIzlpKrpra/plqPjgI3pmYTov5HnmoTlrZciKSArDQogIHlsYWIoIuWHuuePvuasoeaVuCIpICsNCiAgY29vcmRfZmxpcCgpKyANCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dCgpKQ0KYGBgDQoNCmBgYHtyfQ0KbmdyYW1fMTEgPC0gZnVuY3Rpb24odCkgew0KICBsYXBwbHkodCwgZnVuY3Rpb24oeCkgew0KICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikNCiAgICBuZ3JhbSA8LSBuZ3JhbXModG9rZW5zLCAxMSkNCiAgICBuZ3JhbSA8LSBsYXBwbHkobmdyYW0sIHBhc3RlLCBjb2xsYXBzZSA9ICIgIikNCiAgICB1bmxpc3QobmdyYW0pDQogIH0pDQp9DQpnX25ncmFtXzExIDwtIHJkMiAlPiUNCiAgc2VsZWN0KGFydFVybCwgc2VudGVuY2UpICU+JQ0KICB1bm5lc3RfdG9rZW5zKG5ncmFtLCBzZW50ZW5jZSwgdG9rZW4gPSBuZ3JhbV8xMSkgJT4lDQogIGZpbHRlcighc3RyX2RldGVjdChuZ3JhbSwgcmVnZXgoIlswLTlhLXpBLVpdIikpKQ0KZ19uZ3JhbXNfMTFfc2VwYXJhdGVkIDwtIGdfbmdyYW1fMTEgJT4lDQogIHNlcGFyYXRlKG5ncmFtLCBwYXN0ZTAoIndvcmQiLCBjKDE6MTEpLHNlcD0iIiksIHNlcCA9ICIgIikNCmdfbmdyYW1zXzExX3NlcGFyYXRlZA0KYGBgDQoNCmBgYHtyfQ0KZ19jaGVja193b3JkcyA8LSBnX25ncmFtc18xMV9zZXBhcmF0ZWQgJT4lDQogIGZpbHRlcigod29yZDYgPT0gIuWPsOmQtSIpKQ0KZ19jaGVja193b3Jkcw0KYGBgDQoNCiMjIOWkqumtr+mWo+S6i+S7tuWcqFBUVOWFq+WNpueJiOWHuuePvuWcqOOAjOWPsOmQteOAjemZhOi/keeahOWtlw0KYGBge3J9DQpnX2NoZWNrX3dvcmRzX2NvdW50IDwtIGdfY2hlY2tfd29yZHMgJT4lDQogIG1lbHQoaWQudmFycyA9ICJhcnRVcmwiLCBtZWFzdXJlLnZhcnMgPSBwYXN0ZTAoIndvcmQiLCBjKDE6MTEpLHNlcD0iIikpICU+JQ0KICByZW5hbWUod29yZD12YWx1ZSkgJT4lDQogIGZpbHRlcih2YXJpYWJsZSE9IndvcmQ2IikgJT4lDQogIGZpbHRlcighKHdvcmQgJWluJSBzdG9wX3dvcmRzKSwgbmNoYXIod29yZCk+MSkgJT4lDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQ0KZ19jaGVja193b3Jkc19jb3VudCAlPiUNCiAgYXJyYW5nZShkZXNjKGFicyhuKSkpICU+JQ0KICBoZWFkKDE1KSAlPiUNCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh3b3JkLCBuLCBmaWxsID0gbiA+IDApKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgeGxhYigi5Ye654++5Zyo44CM5Y+w6ZC144CN6ZmE6L+R55qE5a2XIikgKw0KICB5bGFiKCLlh7rnj77mrKHmlbgiKSArDQogIGNvb3JkX2ZsaXAoKSsgDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoKSkNCmBgYA0KDQpgYGB7cn0NCiMg6YCy6KGM5pa36Kme77yM5Lim6KiI566X5ZCE6Kme5b2Z5Zyo5ZCE5paH56ug5Lit5Ye654++55qE5qyh5pW4DQpyZF93b3JkcyA8LSByZDIgJT4lDQogIHVubmVzdF90b2tlbnMod29yZCwgc2VudGVuY2UsIHRva2VuPWNoaV90b2tlbml6ZXIpICU+JQ0KICBmaWx0ZXIoIXN0cl9kZXRlY3Qod29yZCwgcmVnZXgoIlswLTlhLXpBLVpdIikpKSAlPiUNCiAgY291bnQoYXJ0VXJsLCB3b3JkLCBzb3J0ID0gVFJVRSkNCmhlYWQocmRfd29yZHMpDQpgYGANCg0KYGBge3J9DQojIOioiOeul+avj+evh+aWh+eroOWMheWQq+eahOipnuaVuA0KdG90YWxfd29yZHMgPC0gcmRfd29yZHMgJT4lIA0KICBncm91cF9ieShhcnRVcmwpICU+JSANCiAgc3VtbWFyaXplKHRvdGFsID0gc3VtKG4pKQ0KaGVhZCh0b3RhbF93b3JkcykNCmBgYA0KDQpgYGB7cn0NCiMg5ZCI5L21IG1hc2tfd29yZHPvvIjmr4/lgIvoqZ7lvZnlnKjmr4/lgIvmlofnq6DkuK3lh7rnj77nmoTmrKHmlbjvvIkNCiMg6IiHIHRvdGFsX3dvcmRz77yI5q+P56+H5paH56ug55qE6Kme5pW477yJDQojIOaWsOWinuWQhOWAi+ipnuW9meWcqOaJgOacieipnuW9meS4reeahOe4veaVuOashOS9jQ0KcmRfd29yZHMgPC0gbGVmdF9qb2luKHJkX3dvcmRzLCB0b3RhbF93b3JkcykNCmBgYA0KDQpgYGB7cn0NCmhlYWQocmRfd29yZHMpDQpgYGANCg0KYGBge3J9DQojIOS7peavj+evh+aWh+eroOeIsuWWruS9je+8jOioiOeul+avj+WAi+ipnuW9meWcqOeahHRmLWlkZuWAvA0KcmRfd29yZHNfdGZfaWRmIDwtIHJkX3dvcmRzICU+JQ0KICBiaW5kX3RmX2lkZih3b3JkLCBhcnRVcmwsIG4pDQojcmRfd29yZHNfdGZfaWRmDQpgYGANCg0KYGBge3J9DQojIOmBuOWHuuavj+evh+aWh+eroO+8jHRmLWlkZuacgOWkp+eahOWNgeWAi+ipng0KcmRfd29yZHNfdGZfaWRmICU+JSANCiAgZ3JvdXBfYnkoYXJ0VXJsKSAlPiUNCiAgdG9wX24oMTApICU+JQ0KICBhcnJhbmdlKGRlc2MoYXJ0VXJsKSkNCmBgYA0KDQpgYGB7cn0NCiMg6YG45q+P56+H5paH56ug77yMdGYtaWRm5pyA5aSn55qE5Y2B5YCL6Kme77yMDQojIOS4puafpeeci+avj+WAi+ipnuiiq+mBuOS4reeahOasoeaVuA0KcmRfd29yZHNfdGZfaWRmICU+JSANCiAgZ3JvdXBfYnkoYXJ0VXJsKSAlPiUNCiAgdG9wX24oMTApICU+JQ0KICBhcnJhbmdlKGRlc2MoYXJ0VXJsKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgY291bnQod29yZCwgc29ydD1UUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KIyDoqIjnrpflhanlgIvoqZ7lvZnplpPnmoTnm7jpl5zmgKcNCnN0b3Bfd29yZHMgPC0gc2NhbihmaWxlID0gImRpY3Qvc3RvcF93b3Jkcy50eHQiLCB3aGF0PWNoYXJhY3RlcigpLHNlcD0nXG4nLCANCiAgICAgICAgICAgICAgICAgICBlbmNvZGluZz0ndXRmLTgnLGZpbGVFbmNvZGluZz0ndXRmLTgnKQ0Kd29yZF9jb3JzIDwtIHJkX3dvcmRzICU+JQ0KICBncm91cF9ieSh3b3JkKSAlPiUNCiAgZmlsdGVyKG4oKSA+PSAyMCkgJT4lDQogIGZpbHRlcighKHdvcmQgJWluJSBzdG9wX3dvcmRzKSYmISh3b3JkICVpbiUgIuiomOiAhSIpKSAlPiUNCiAgcGFpcndpc2VfY29yKHdvcmQsIGFydFVybCwgc29ydCA9IFRSVUUpDQoNCiN3b3JkX2NvcnMNCmBgYA0KDQpgYGB7cn0NCiMg6IiH5aSq6a2v6Zaj55u46Zec5oCn6auY55qE6Kme5b2ZDQp3b3JkX2NvcnMgJT4lDQogIGZpbHRlcihpdGVtMSA9PSAi5aSq6a2v6ZajIikgJT4lIA0KICBoZWFkKDUpDQpgYGANCg0KYGBge3J9DQojIOiIh+e+qeelpeebuOmXnOaAp+mrmOeahOipnuW9mQ0Kd29yZF9jb3JzICU+JQ0KICBmaWx0ZXIoaXRlbTEgPT0gIue+qeelpSIpICU+JSANCiAgaGVhZCg1KQ0KYGBgDQoNCmBgYHtyfQ0KIyDoiIflj7DpkLXnm7jpl5zmgKfpq5jnmoToqZ7lvZkNCndvcmRfY29ycyAlPiUNCiAgZmlsdGVyKGl0ZW0xID09ICLlj7DpkLUiKSAlPiUgDQogIGhlYWQoNSkNCmBgYA0KDQojIyDlpKrpra/plqPkuovku7blnKhQVFTlhavljabniYjlh7rnj77lnKjjgIwgIuWPsOmQtSIsICLlpKrpra/plqMiLCAi5pS/5bqcIiwgIue+qeelpSIg44CN55u46Zec5oCn5pyA6auY55qEIDEwIOWAi+ipnuW9mQ0KYGBge3J9DQojIOWIhuWIpeWwi+aJvuiIhyAi5Y+w6ZC1IiwgIuWkqumtr+mWoyIsICLmlL/lupwiLCAi576p56WlIiDnm7jpl5zmgKfmnIDpq5jnmoQgMTAg5YCL6Kme5b2ZDQp3b3JkX2NvcnMgJT4lDQogIGZpbHRlcihpdGVtMSAlaW4lIGMoIuWPsOmQtSIsICLlpKrpra/plqMiLCAi5pS/5bqcIiwgIue+qeelpSIpKSAlPiUNCiAgZ3JvdXBfYnkoaXRlbTEpICU+JQ0KICB0b3BfbigxMCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKGl0ZW0yID0gcmVvcmRlcihpdGVtMiwgY29ycmVsYXRpb24pKSAlPiUNCiAgZ2dwbG90KGFlcyhpdGVtMiwgY29ycmVsYXRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnMoeD1OVUxMLHk9TlVMTCkgKyANCiAgZmFjZXRfd3JhcCh+IGl0ZW0xLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgY29vcmRfZmxpcCgpKyANCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dCgpKQ0KYGBgDQoNCg0KDQojIGNoIDA2IOWFsee3muebuOmXnOWclg0KIyMg5aSq6a2v6Zaj5LqL5Lu25ZyoUFRU5YWr5Y2m54mI5YWx57ea55u46Zec5ZyWDQpgYGB7cn0NCiMg6aGv56S655u46Zec5oCn5aSn5pa8MC4055qE57WE5ZCIDQpzZXQuc2VlZCgyMDIwKQ0Kd29yZF9jb3JzICU+JQ0KICBmaWx0ZXIoY29ycmVsYXRpb24gPiAwLjQpICU+JQ0KICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUNCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBjb3JyZWxhdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSAzKSArDQogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbCA9IFRSVUUpICsgI+WKoOWFpeS4reaWh+Wtl+Wei+ioreWumu+8jOmBv+WFjeS4reaWh+Wtl+mhr+ekuumMr+iqpOOAgg0KICB0aGVtZV92b2lkKCkNCmBgYA0KDQpgYGB7cn0NCiMg6aGv56S655u46Zec5oCn5aSn5pa8MC4155qE57WE5ZCIDQpzZXQuc2VlZCgyMDIwKQ0KDQp3b3JkX2NvcnMgJT4lDQogIGZpbHRlcihjb3JyZWxhdGlvbiA+IDAuNSkgJT4lDQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQ0KICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKw0KICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IGNvcnJlbGF0aW9uKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibGlnaHRibHVlIiwgc2l6ZSA9IDMpICsNCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSkgKw0KICB0aGVtZV92b2lkKCkNCmBgYA0KDQoNCiMg57WQ6KuWDQo+5Zyo5pW05YCL5LqL5Lu25Lit77yM5aSn55y+6KqN54K65aSq6a2v6Zaj6Jmf55qE6LKs5Lu75oeJ5q245ZKO5pa85Y+w6ZC15ZKM5pS/5bqc77yM5Lim5biM5pyb5Zyo5aSq6a2v6Zaj5LqL5Lu25b6M5Y+w6ZC16IO95pWI5rOV6auY6ZC15bCH5YWs5Y+45rCR54ef5YyW5oiW5YWs5Y+45YyW77yM6YG/5YWN5pyq5L6G5YaN5pyJ5oa+5LqL55m855Sf44CCDQoNCg==