主題

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

一、動機與分析目的

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

1.資料集描述

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

二、前置作業

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

1.安裝需要的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)
install.packages('knitr')

2.將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)

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

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

-- Column specification ----------------------------------------------------------------------------------------
cols(
  artTitle = col_character(),
  artDate = col_date(format = ""),
  artTime = col_time(format = ""),
  artUrl = col_character(),
  word = col_character(),
  count = col_double()
)
rd2 <- read_csv("太魯閣事件_articleMetaData.csv")

-- Column specification ----------------------------------------------------------------------------------------
cols(
  artTitle = col_character(),
  artDate = col_date(format = ""),
  artTime = col_time(format = ""),
  artUrl = col_character(),
  artPoster = col_character(),
  artCat = col_character(),
  commentNum = col_double(),
  push = col_double(),
  boo = col_double(),
  sentence = col_character()
)
rd$artDate <- rd$artDate %>% as.Date("%Y/%m/%d")
rd

4.初始化斷詞引擎

# 加入自定義的字典
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)
    }
  })
}

三、折線圖

1.資料處理

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

2.太魯閣事件在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

四、文字雲

1.資料處理

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

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

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

五、常出現的詞彙

1.資料處理

rd_tokens <- rd %>%
  select(-artTime, -artUrl)
head(rd_tokens)
rd_tokens_by_date <- rd_tokens %>% 
  count(artDate, word, sort = TRUE) %>%
  filter(n > 5)
rd_tokens_by_date
stop_words <- scan(file = "dict/stop_words.txt", what=character(),sep='\n', 
                   encoding='utf-8',fileEncoding='utf-8')

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

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

六、情緒分析

1.載入情緒分析字典

# 正向字典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) 
Joining, by = "word"
Joining, by = "word"
sentiment_count = rd_tokens_by_date %>%
  select(artDate,word,n) %>%
  inner_join(LIWC) %>% 
  group_by(artDate,sentiment) %>%
  summarise(count=sum(n))
Joining, by = "word"

3.太魯閣事件在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"))  
<ScaleContinuousDate>
 Range:  
 Limits:    0 --    1
rd_tokens_all <- rd2 %>%
  unnest_tokens(word, sentence, token=chi_tokenizer) %>% 
  select(-artTime)

4.太魯閣事件在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()
Joining, by = "word"

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

5.太魯閣事件在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

6.太魯閣事件在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)
Joining, by = "artUrl"
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))
Selecting by tf_idf
# 選每篇文章,tf-idf最大的十個詞,
# 並查看每個詞被選中的次數
rd_words_tf_idf %>% 
  group_by(artUrl) %>%
  top_n(10) %>%
  arrange(desc(artUrl)) %>%
  ungroup() %>%
  count(word, sort=TRUE)
Selecting by tf_idf
# 計算兩個詞彙間的相關性
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)

8.太魯閣事件在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())
Selecting by correlation

七、共線相關圖

1.太魯閣事件在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/lh7rou4zkuovku7bnmoTmloflrZfos4fmlpkNCg0KIyDkuIDjgIHli5XmqZ/oiIfliIbmnpDnm67nmoQNCi0g6IOM5pmv6IiH5YuV5qmfDQogICsg5riF5piO6YCj5YGH5q2j5piv5aSn5a625rqW5YKZ6ZaL5b+D56Wt56WW5oiW5piv5Ye66YGK55qE5pel5a2Q77yM5aSn55y+5Lqk6YCa5bel5YW35oiQ54K65o+Q5L6b5aSn5a625b6A6L+U55qE5bel5YW377yM5bCk5YW25piv5Y+w6ZC16ZC16Lev6YGL6Ly455qE55Kw5bO25Lqk6YCa57ay77yM5pu05piv5b6A5L6G6KW/5bK46IiH5p2x5bK45pyA5L6/5Yip55qE5pa55byP77yM6YCj5YGH55qE56ys5LiA5aSp5piv5Lqk6YCa5pyA57mB5b+Z55qE5LiA5aSp77yM5Y+w6ZC155qE5aSq6a2v6Zaj6Jmf5Y275Zug54K65pa95bel5Zau5L2N55qE55aP5b+955m855Sf5LqG5Zq06YeN55qE5Ye66LuM5oSP5aSW77yM6YCg5oiQMjQ36LyV6YeN5YK344CBNDnkurrmrbvkuqHnmoTmgrLliofvvJvpgJnloLTmhI/lpJbnqbbnq5/mmK/llq7ntJTlpJbljIXmlr3lt6Xlu6DllYbvvIzmipHmiJbmmK/nqY3nv5Llt7LkuYXnmoTlj7DngaPpkLXot6/lhazlj7jnm6PnnaPkuI3lkajmiYDpgKDmiJDnmoTjgIINCg0KKyDnoJTnqbbnm67nmoQNCiAgIDEuIOS6huino+awkeecvuWwjeaWvOWkqumtr+mWo+iZn+S6i+S7tueahOaFi+W6puOAgjwvYnI+DQogICAyLiDntrLmsJHoqo3ngrrlpKrpra/plqPomZ/nmoTosqzku7vmrbjlsazjgII8L2JyPg0KICAgMy4g5aSq6a2v6Zaj6Jmf5Ye66LuM5LqL5Lu25b6M6Kmy5YGa55qE5LqL44CCPC9icj4NCg0KIyMgMS7os4fmlpnpm4bmj4/ov7ANCisg6LOH5paZ5L6G5rqQ77ya5Lit5bGx5aSn5a24566h55CG5a246Zmi5paH5a2X5YiG5p6Q5bmz5Y+w5pS26ZuGUFQgVOWFq+WNpueJiOaWh+eroOWPluW+l+S5i+WOn+Wni2NzduaqlOahiOOAgg0KKyDos4fmlpnpm4bvvJpQUFTlhavljabniYjjgIINCisg6LOH5paZ5pel5pyf5Y2A6ZaT77yaMjAyMS4wMy4zMX4yMDIxLjA0LjE044CCDQorIOizh+aWmeeahOmXnOmNteWtlzrmqqLntKLjgIzlj7DpkLXjgI3jgIHjgIzmnY7nvqnnpaXjgI3jgIHjgIzlpKrpra/plqPjgI3jgIHjgIzlt6XnqIvou4rjgI3jgIHjgIznvqnnpaXjgI3jgIHjgIzlh7rou4zjgI3lha3lgIvpl5zpjbXlrZfvvIzlhbHmkJzlsIvlh7oxNDg156+H5paH56ug44CCDQoNCiMg5LqM44CB5YmN572u5L2c5qWtDQpgYGB7cn0NClN5cy5zZXRsb2NhbGUoY2F0ZWdvcnkgPSAiTENfQUxMIiwgbG9jYWxlID0gInpoX1RXLlVURi04IikgIyDpgb/lhY3kuK3mlofkuoLnorwNCmBgYA0KDQojIyAxLuWuieijnemcgOimgeeahHBhY2thZ2VzDQpgYGB7cn0NCnBhY2thZ2VzID0gYygicmVhZHIiLCAiZHBseXIiLCAic3RyaW5nciIsICJqaWViYVIiLCAidGlkeXRleHQiLCAiTkxQIiwgInJlYWRyIiwgInRpZHlyIiwgImdncGxvdDIiLCAiZ2dyYXBoIiwgImlncmFwaCIsICJzY2FsZXMiLCAicmVzaGFwZTIiLCAid2lkeXIiKQ0KZXhpc3RpbmcgPSBhcy5jaGFyYWN0ZXIoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKQ0KZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpDQppbnN0YWxsLnBhY2thZ2VzKCdrbml0cicpDQpgYGANCg0KIyMgMi7lsIdyZXF1aXJl5Y+KbGlicmFyeei8ieWFpQ0KYGBge3J9DQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKGRwbHlyKQ0KcmVxdWlyZShyZWFkcikNCnJlcXVpcmUoZHBseXIpDQpyZXF1aXJlKHN0cmluZ3IpDQpyZXF1aXJlKGppZWJhUikNCnJlcXVpcmUodGlkeXRleHQpDQpyZXF1aXJlKE5MUCkNCnJlcXVpcmUodGlkeXIpDQpyZXF1aXJlKGdncGxvdDIpDQpyZXF1aXJlKGdncmFwaCkNCnJlcXVpcmUoaWdyYXBoKQ0KcmVxdWlyZShzY2FsZXMpDQpyZXF1aXJlKHJlc2hhcGUyKQ0KcmVxdWlyZSh3aWR5cikNCg0KbGlicmFyeShkYXRhLnRhYmxlKQ0KcmVxdWlyZSh3b3JkY2xvdWQyKQ0KcmVxdWlyZShsdWJyaWRhdGUpDQpyZXF1aXJlKGh0bWx3aWRnZXRzKQ0KcmVxdWlyZSh3ZWJzaG90KQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKFJDb2xvckJyZXdlcikNCg0KcmVxdWlyZShzZXJ2cikNCnJlcXVpcmUodG0pDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKHN0cmluZ3IpDQpsaWJyYXJ5KHRvcGljbW9kZWxzKQ0KcmVxdWlyZShMREF2aXMpDQpyZXF1aXJlKHdlYnNob3QpDQpgYGANCg0KDQojIyAzLui8ieWFpeiHquW5s+WPsOS4i+i8ieS4i+S+hueahOizh+aWmQ0KYGBge3J9DQpyZCA8LSByZWFkX2Nzdigi5aSq6a2v6Zaj5LqL5Lu2X2FydFdvcmRGcmVxLmNzdiIpDQpyZDIgPC0gcmVhZF9jc3YoIuWkqumtr+mWo+S6i+S7tl9hcnRpY2xlTWV0YURhdGEuY3N2IikNCg0KcmQkYXJ0RGF0ZSA8LSByZCRhcnREYXRlICU+JSBhcy5EYXRlKCIlWS8lbS8lZCIpDQpyZA0KYGBgDQojIyA0LuWIneWni+WMluaWt+ipnuW8leaTjg0KYGBge3J9DQojIOWKoOWFpeiHquWumue+qeeahOWtl+WFuA0KamllYmFfdG9rZW5pemVyIDwtIHdvcmtlcih1c2VyPSJkaWN0L3VzZXJfZGljdC50eHQiLCBzdG9wX3dvcmQgPSAiZGljdC9zdG9wX3dvcmRzLnR4dCIpDQoNCiMg6Kit5a6a5pa36KmeZnVuY3Rpb24NCmNoaV90b2tlbml6ZXIgPC0gZnVuY3Rpb24odCkgew0KICBsYXBwbHkodCwgZnVuY3Rpb24oeCkgew0KICAgIGlmKG5jaGFyKHgpPjEpew0KICAgICAgdG9rZW5zIDwtIHNlZ21lbnQoeCwgamllYmFfdG9rZW5pemVyKQ0KICAgICAgIyDljrvmjonlrZfkuLLplbfluqbniLIx55qE6Kme5b2ZDQogICAgICB0b2tlbnMgPC0gdG9rZW5zW25jaGFyKHRva2Vucyk+MV0NCiAgICAgIHJldHVybih0b2tlbnMpDQogICAgfQ0KICB9KQ0KfQ0KYGBgDQoNCiMg5LiJ44CB5oqY57ea5ZyWDQojIyAxLuizh+aWmeiZleeQhg0KYGBge3J9DQpkYXRhIDwtIHJkICU+JSANCiAgZHBseXI6OnNlbGVjdChhcnREYXRlLCBhcnRVcmwpICU+JSANCiAgZGlzdGluY3QoKQ0KYGBgDQoNCmBgYHtyfQ0KYXJ0aWNsZV9jb3VudF9ieV9kYXRlIDwtIGRhdGEgJT4lIA0KICBncm91cF9ieShhcnREYXRlKSAlPiUgDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkNCmBgYA0KDQpgYGB7cn0NCmhlYWQoYXJ0aWNsZV9jb3VudF9ieV9kYXRlLCAyMCkNCmBgYA0KDQoNCiMjIDIu5aSq6a2v6Zaj5LqL5Lu25ZyoUFRU5YWr5Y2m54mIMy8zMX40LzE06IGy6YeP5oqY57ea5ZyWDQpgYGB7cn0NCnBsb3RfZGF0ZSA8LSANCiAgIyBkYXRhDQogIGFydGljbGVfY291bnRfYnlfZGF0ZSAlPiUgDQogICMgYWVzdGhldGljcw0KICBnZ3Bsb3QoYWVzKHggPSBhcnREYXRlLCB5ID0gY291bnQpKSArDQogICMgZ2VvbWV0cmljcw0KICBnZW9tX2xpbmUoY29sb3IgPSAiIzAwQUZCQiIsIHNpemUgPSAxKSArIA0KICAjIGNvb3JkaW5hdGVzDQogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJVkvJW0vJWQiKSkgKw0KICBnZ3RpdGxlKCJQVFQg5YWr5Y2m54mIIOiojuirluaWh+eroOaVuCIpICsgDQogIHhsYWIoIuaXpeacnyIpICsgDQogIHlsYWIoIuaVuOmHjyIpICsgDQogICMgdGhlbWUNCiAgdGhlbWUoKSAj5Yqg5YWl5Lit5paH5a2X5Z6L6Kit5a6a77yM6YG/5YWN5Lit5paH5a2X6aGv56S66Yyv6Kqk44CCDQoNCnBsb3RfZGF0ZQ0KYGBgDQoNCiMg5Zub44CB5paH5a2X6ZuyDQojIyAxLuizh+aWmeiZleeQhg0KYGBge3J9DQpkYXRhIDwtIHJkICU+JSANCiAgZ3JvdXBfYnkod29yZCkgJT4lIA0KICBzdW1tYXJpc2Uoc3VtID0gc3VtKGNvdW50KSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICBhcnJhbmdlKGRlc2Moc3VtKSkNCmBgYA0KDQpgYGB7cn0NCmhlYWQoZGF0YSkNCmBgYA0KDQojIyAyLuWkqumtr+mWo+S6i+S7tuWcqFBUVOWFq+WNpueJiDMvMzF+NC8xNOaWh+Wtl+mbsg0KYGBge3J9DQpkYXRhICU+JSBmaWx0ZXIoc3VtID4gNTApICU+JSB3b3JkY2xvdWQyKCkNCmBgYA0KDQoNCiMg5LqU44CB5bi45Ye654++55qE6Kme5b2ZDQojIyAxLuizh+aWmeiZleeQhg0KYGBge3J9DQpyZF90b2tlbnMgPC0gcmQgJT4lDQogIHNlbGVjdCgtYXJ0VGltZSwgLWFydFVybCkNCmhlYWQocmRfdG9rZW5zKQ0KYGBgDQoNCg0KYGBge3J9DQpyZF90b2tlbnNfYnlfZGF0ZSA8LSByZF90b2tlbnMgJT4lIA0KICBjb3VudChhcnREYXRlLCB3b3JkLCBzb3J0ID0gVFJVRSkgJT4lDQogIGZpbHRlcihuID4gNSkNCnJkX3Rva2Vuc19ieV9kYXRlDQpgYGANCmBgYHtyfQ0Kc3RvcF93b3JkcyA8LSBzY2FuKGZpbGUgPSAiZGljdC9zdG9wX3dvcmRzLnR4dCIsIHdoYXQ9Y2hhcmFjdGVyKCksc2VwPSdcbicsIA0KICAgICAgICAgICAgICAgICAgIGVuY29kaW5nPSd1dGYtOCcsZmlsZUVuY29kaW5nPSd1dGYtOCcpDQpgYGANCg0KIyMgMi7lpKrpra/plqPkuovku7blnKhQVFTlhavljabniYg0LzJ+NC8xMOavj+WkqeacgOW4uOimi+eahDEw5YCL6Kme5b2ZDQpgYGB7cn0NCnBsb3RfbWVyZ2UgPC0gcmRfdG9rZW5zX2J5X2RhdGUgJT4lIA0KICBmaWx0ZXIoISh3b3JkICVpbiUgc3RvcF93b3JkcykgJiAhKHdvcmQgJWluJSAi5Y+w6ZC1IikpICU+JQ0KICBmaWx0ZXIoYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTAyIikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wMyIpIHwgDQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDQiKSB8DQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDUiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA2IikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wNyIpIHwgDQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDgiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA5IikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0xMCIpKSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUpICU+JSANCiAgdG9wX24oMTAsIG4pICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh4PXdvcmQsIHk9biwgZmlsbCA9IGFydERhdGUpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgZmFjZXRfd3JhcCh+YXJ0RGF0ZSwgc2NhbGVzPSJmcmVlIiwgbmNvbCA9IDUpICsgDQogIGNvb3JkX2ZsaXAoKSsNCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dCgpKQ0KcGxvdF9tZXJnZQ0KYGBgDQoNCg0KIyDlha3jgIHmg4Xnt5LliIbmnpANCiMjIDEu6LyJ5YWl5oOF57eS5YiG5p6Q5a2X5YW4DQpgYGB7cn0NCiMg5q2j5ZCR5a2X5YW4dHh05qqUDQojIOS7pSzlsIflrZfliIbpmpQNClAgPC0gcmVhZF9maWxlKCJkaWN0L3Bvc2l0aXZlLnR4dCIpDQoNCiMg6LKg5ZCR5a2X5YW4dHh05qqUDQpOIDwtIHJlYWRfZmlsZSgiZGljdC9uZWdhdGl2ZS50eHQiKQ0KYGBgDQoNCmBgYHtyfQ0KI+Wwh+Wtl+S4suS+nSzliIblibINCiNzdHJzcGxpdOWbnuWCs2xpc3QgLCDmiJHlgJHlj5blh7psaXN05Lit55qE56ys5LiA5YCL5YWD57SgDQpQID0gc3Ryc3BsaXQoUCwgIiwiKVtbMV1dDQpOID0gc3Ryc3BsaXQoTiwgIiwiKVtbMV1dDQoNCiMg5bu656uLZGF0YWZyYW1lIOacieWFqeWAi+ashOS9jXdvcmQsc2VudGltZW50c++8jHdvcmTmrITkvY3lhaflrrnmmK/lrZflhbjlkJHph48NClAgPSBkYXRhLmZyYW1lKHdvcmQgPSBQLCBzZW50aW1lbnQgPSAicG9zaXRpdmUiKQ0KTiA9IGRhdGEuZnJhbWUod29yZCA9IE4sIHNlbnRpbWVudCA9ICJuZWdhdGl2ZSIpDQpgYGANCg0KYGBge3J9DQpMSVdDID0gcmJpbmQoUCwgTikNCmBgYA0KDQpgYGB7cn0NCnJkX3Rva2Vuc19ieV9kYXRlICU+JQ0KICBpbm5lcl9qb2luKExJV0MpICU+JQ0KICBzZWxlY3Qod29yZCkgJT4lDQogIGlubmVyX2pvaW4oTElXQykgDQpgYGANCg0KYGBge3J9DQpzZW50aW1lbnRfY291bnQgPSByZF90b2tlbnNfYnlfZGF0ZSAlPiUNCiAgc2VsZWN0KGFydERhdGUsd29yZCxuKSAlPiUNCiAgaW5uZXJfam9pbihMSVdDKSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUsc2VudGltZW50KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50PXN1bShuKSkNCmBgYA0KDQoNCg0KIyMgMy7lpKrpra/plqPkuovku7blnKhQVFTlhavljabniYgzLzMxfjQvMTTmraPosqDpnaLmg4Xnt5LogbLph4/mipjnt5rlnJYNCmBgYHtyfQ0KDQpzZW50aW1lbnRfY291bnQgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4PWFydERhdGUseT1jb3VudCxjb2xvdXI9c2VudGltZW50KSkgKw0KICBsYWJzKHg9TlVMTCx5PSLmlbjph48iKQ0KDQogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJW0vJWQiKSkgIA0KYGBgDQpgYGB7cn0NCnJkX3Rva2Vuc19hbGwgPC0gcmQyICU+JQ0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIHNlbnRlbmNlLCB0b2tlbj1jaGlfdG9rZW5pemVyKSAlPiUgDQogIHNlbGVjdCgtYXJ0VGltZSkNCmBgYA0KDQojIyA0LuWkqumtr+mWo+S6i+S7tuWcqFBUVOWFq+WNpueJiDQvMn40LzjmraPosqDmg4Xnt5Lplbfmop3lnJYNCmBgYHtyfQ0KcmRfdG9rZW5zX2FsbCAlPiUNCiAgZmlsdGVyKGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wMiIpIHwNCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0wMyIpIHwgDQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDQtMDQiKSB8IA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA1IikgfA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA2IikgfA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA3IikgfA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA0LTA4IikgKSAlPiUgDQogIGlubmVyX2pvaW4oTElXQykgJT4lDQogIGdyb3VwX2J5KHdvcmQsc2VudGltZW50KSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGNvdW50ID0gbigpDQogICkgJT4lIGRhdGEuZnJhbWUoKSAlPiUgDQogIHRvcF9uKDMwLHd0ID0gY291bnQpICU+JQ0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgY291bnQpKSAlPiUNCiAgZ2dwbG90KGFlcyh3b3JkLCBjb3VudCwgZmlsbCA9IHNlbnRpbWVudCkpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBsYWJzKHg9ICLmloflrZciLCB5PSLmlbjph48iKSArDQogIGZhY2V0X3dyYXAofnNlbnRpbWVudCwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNCkpKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCm5ncmFtXzExIDwtIGZ1bmN0aW9uKHQpIHsNCiAgbGFwcGx5KHQsIGZ1bmN0aW9uKHgpIHsNCiAgICB0b2tlbnMgPC0gc2VnbWVudCh4LCBqaWViYV90b2tlbml6ZXIpDQogICAgbmdyYW0gPC0gbmdyYW1zKHRva2VucywgMTEpDQogICAgbmdyYW0gPC0gbGFwcGx5KG5ncmFtLCBwYXN0ZSwgY29sbGFwc2UgPSAiICIpDQogICAgdW5saXN0KG5ncmFtKQ0KICB9KQ0KfQ0KZ19uZ3JhbV8xMSA8LSByZDIgJT4lDQogIHNlbGVjdChhcnRVcmwsIHNlbnRlbmNlKSAlPiUNCiAgdW5uZXN0X3Rva2VucyhuZ3JhbSwgc2VudGVuY2UsIHRva2VuID0gbmdyYW1fMTEpICU+JQ0KICBmaWx0ZXIoIXN0cl9kZXRlY3QobmdyYW0sIHJlZ2V4KCJbMC05YS16QS1aXSIpKSkNCmdfbmdyYW1zXzExX3NlcGFyYXRlZCA8LSBnX25ncmFtXzExICU+JQ0KICBzZXBhcmF0ZShuZ3JhbSwgcGFzdGUwKCJ3b3JkIiwgYygxOjExKSxzZXA9IiIpLCBzZXAgPSAiICIpDQpoZWFkKGdfbmdyYW1zXzExX3NlcGFyYXRlZCkNCmBgYA0KDQpgYGB7cn0NCmdfY2hlY2tfd29yZHMgPC0gZ19uZ3JhbXNfMTFfc2VwYXJhdGVkICU+JQ0KICBmaWx0ZXIoKHdvcmQ2ID09ICLlpKrpra/plqMiKSkNCmdfY2hlY2tfd29yZHMNCmBgYA0KDQojIyA1LuWkqumtr+mWo+S6i+S7tuWcqFBUVOWFq+WNpueJiOWHuuePvuWcqOOAjOWkqumtr+mWo+OAjemZhOi/keeahOWtlw0KYGBge3J9DQpnX2NoZWNrX3dvcmRzX2NvdW50IDwtIGdfY2hlY2tfd29yZHMgJT4lDQogIG1lbHQoaWQudmFycyA9ICJhcnRVcmwiLCBtZWFzdXJlLnZhcnMgPSBwYXN0ZTAoIndvcmQiLCBjKDE6MTEpLHNlcD0iIikpICU+JQ0KICByZW5hbWUod29yZD12YWx1ZSkgJT4lDQogIGZpbHRlcih2YXJpYWJsZSE9IndvcmQ2IikgJT4lDQogIGZpbHRlcighKHdvcmQgJWluJSBzdG9wX3dvcmRzKSwgbmNoYXIod29yZCk+MSkgJT4lDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQ0KZ19jaGVja193b3Jkc19jb3VudCAlPiUNCiAgYXJyYW5nZShkZXNjKGFicyhuKSkpICU+JQ0KICBoZWFkKDE1KSAlPiUNCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh3b3JkLCBuLCBmaWxsID0gbiA+IDApKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgeGxhYigi5Ye654++5Zyo44CM5aSq6a2v6Zaj44CN6ZmE6L+R55qE5a2XIikgKw0KICB5bGFiKCLlh7rnj77mrKHmlbgiKSArDQogIGNvb3JkX2ZsaXAoKSsgDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoKSkNCmBgYA0KDQpgYGB7cn0NCm5ncmFtXzExIDwtIGZ1bmN0aW9uKHQpIHsNCiAgbGFwcGx5KHQsIGZ1bmN0aW9uKHgpIHsNCiAgICB0b2tlbnMgPC0gc2VnbWVudCh4LCBqaWViYV90b2tlbml6ZXIpDQogICAgbmdyYW0gPC0gbmdyYW1zKHRva2VucywgMTEpDQogICAgbmdyYW0gPC0gbGFwcGx5KG5ncmFtLCBwYXN0ZSwgY29sbGFwc2UgPSAiICIpDQogICAgdW5saXN0KG5ncmFtKQ0KICB9KQ0KfQ0KZ19uZ3JhbV8xMSA8LSByZDIgJT4lDQogIHNlbGVjdChhcnRVcmwsIHNlbnRlbmNlKSAlPiUNCiAgdW5uZXN0X3Rva2VucyhuZ3JhbSwgc2VudGVuY2UsIHRva2VuID0gbmdyYW1fMTEpICU+JQ0KICBmaWx0ZXIoIXN0cl9kZXRlY3QobmdyYW0sIHJlZ2V4KCJbMC05YS16QS1aXSIpKSkNCmdfbmdyYW1zXzExX3NlcGFyYXRlZCA8LSBnX25ncmFtXzExICU+JQ0KICBzZXBhcmF0ZShuZ3JhbSwgcGFzdGUwKCJ3b3JkIiwgYygxOjExKSxzZXA9IiIpLCBzZXAgPSAiICIpDQpnX25ncmFtc18xMV9zZXBhcmF0ZWQNCmBgYA0KDQpgYGB7cn0NCmdfY2hlY2tfd29yZHMgPC0gZ19uZ3JhbXNfMTFfc2VwYXJhdGVkICU+JQ0KICBmaWx0ZXIoKHdvcmQ2ID09ICLlj7DpkLUiKSkNCmdfY2hlY2tfd29yZHMNCmBgYA0KDQojIyA2LuWkqumtr+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+JSANCiAgaGVhZCg1KQ0KYGBgDQoNCmBgYHtyfQ0KIyDoiIflj7DpkLXnm7jpl5zmgKfpq5jnmoToqZ7lvZkNCndvcmRfY29ycyAlPiUNCiAgZmlsdGVyKGl0ZW0xID09ICLlj7DpkLUiKSAlPiUgDQogIGhlYWQoNSkNCmBgYA0KDQojIyA4LuWkqumtr+mWo+S6i+S7tuWcqFBUVOWFq+WNpueJiOWHuuePvuWcqOOAjCAi5Y+w6ZC1IiwgIuWkqumtr+mWoyIsICLmlL/lupwiLCAi576p56WlIiDjgI3nm7jpl5zmgKfmnIDpq5jnmoQgMTAg5YCL6Kme5b2ZDQpgYGB7cn0NCiMg5YiG5Yil5bCL5om+6IiHICLlj7DpkLUiLCAi5aSq6a2v6ZajIiwgIuaUv+W6nCIsICLnvqnnpaUiIOebuOmXnOaAp+acgOmrmOeahCAxMCDlgIvoqZ7lvZkNCndvcmRfY29ycyAlPiUNCiAgZmlsdGVyKGl0ZW0xICVpbiUgYygi5Y+w6ZC1IiwgIuWkqumtr+mWoyIsICLmlL/lupwiLCAi576p56WlIikpICU+JQ0KICBncm91cF9ieShpdGVtMSkgJT4lDQogIHRvcF9uKDEwKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUoaXRlbTIgPSByZW9yZGVyKGl0ZW0yLCBjb3JyZWxhdGlvbikpICU+JQ0KICBnZ3Bsb3QoYWVzKGl0ZW0yLCBjb3JyZWxhdGlvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh4PU5VTEwseT1OVUxMKSArIA0KICBmYWNldF93cmFwKH4gaXRlbTEsIHNjYWxlcyA9ICJmcmVlIikgKw0KICBjb29yZF9mbGlwKCkrIA0KICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KCkpDQpgYGANCg0KDQoNCiMg5LiD44CB5YWx57ea55u46Zec5ZyWDQojIyAxLuWkqumtr+mWo+S6i+S7tuWcqFBUVOWFq+WNpueJiOWFsee3muebuOmXnOWclg0KYGBge3J9DQojIOmhr+ekuuebuOmXnOaAp+Wkp+aWvDAuNOeahOe1hOWQiA0Kc2V0LnNlZWQoMjAyMCkNCndvcmRfY29ycyAlPiUNCiAgZmlsdGVyKGNvcnJlbGF0aW9uID4gMC40KSAlPiUNCiAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKCkgJT4lDQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArDQogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gY29ycmVsYXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGdlb21fbm9kZV9wb2ludChjb2xvciA9ICJsaWdodGJsdWUiLCBzaXplID0gMykgKw0KICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWwgPSBUUlVFKSArICPliqDlhaXkuK3mloflrZflnovoqK3lrprvvIzpgb/lhY3kuK3mloflrZfpoa/npLrpjK/oqqTjgIINCiAgdGhlbWVfdm9pZCgpDQpgYGANCg0KYGBge3J9DQojIOmhr+ekuuebuOmXnOaAp+Wkp+aWvDAuNeeahOe1hOWQiA0Kc2V0LnNlZWQoMjAyMCkNCg0Kd29yZF9jb3JzICU+JQ0KICBmaWx0ZXIoY29ycmVsYXRpb24gPiAwLjUpICU+JQ0KICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUNCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBjb3JyZWxhdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gImxpZ2h0Ymx1ZSIsIHNpemUgPSAzKSArDQogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbCA9IFRSVUUpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCg0KDQojIOWFq+OAgee1kOirlg0KPuW+nuS7peS4iueahOWIhuaekOe1kOaenOWPr+eci+WHuuWcqOaVtOWAi+S6i+S7tuS4re+8jOWkp+ecvuWwjeatpOS6i+S7tueahOiyoOmdouaDhee3kuWni+e1gumrmOaWvOato+mdouaDhee3ku+8jOiyoOmdouaDhee3kuS4u+imgea6kOiHquaWvOWPsOmQteiAgeiIiumshuaVo+eahOWumOWDmue1hOe5lOaWh+WMluWSjOaUv+W6nOWwjeaWvOaJv+WMheWVhueahOS4jeeVtuebo+edo++8jOaYjuefpee+qeelpeW3pealreekvuWJjeenkee0r+e0r+WNu+S+neiIiuWwh+aomeahiOWkluWMhee1puipsuWFrOWPuO+8jOiAjOato+mdouaDhee3kuWJh+aYr+Wkp+ecvuW4jOacm+WPsOmQteiDveWkoOaViOazlemrmOmQteWwjeWPsOmQtemAsuihjOaUuemdqe+8jOWwh+e1hOe5lOawkeeHn+WMluaIluWFrOWPuOWMlu+8jOmBv+WFjeacquS+huWGjeacieWQjOaoo+S6i+S7tueZvOeUn+OAgg0KDQo=