動機與分析目的
(1)背景動機 : 最近華航機師染疫,到處趴趴走,去過清真寺等地點,造成民眾恐慌,多人必須隔離檢疫,台科大的學生甚至因此停課!👀😡

(2)研究目的: 因此以PTT 八卦版中的討論情況,來分析民眾針對此事件的看法與反應,進行探討研究。
(3)資料來源 : PTT八卦版(2020/10/28~2021/4/27),透過文字分析平台,關鍵字【華航】
1.安裝package
Sys.setlocale(category = "LC_ALL", locale = "zh_TW.UTF-8") # 避免中文亂碼
packages = c("dplyr", "tidytext", "stringr", "wordcloud2", "ggplot2",'readr','data.table','reshape2','wordcloud','scales','widyr','igraph','ggraph','tidyr','NLP')
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)
library(dplyr)
library(stringr)
library(tidytext)
library(wordcloud2)
library(data.table)
library(ggplot2)
library(reshape2)
library(wordcloud)
library(readr)
library(scales)
library(jiebaR)
library(widyr)
library(igraph)
library(ggraph)
library(lubridate)
library(NLP)
library(tidyr)
library(devtools)
Error in get(genname, envir = envir) : 找不到物件 'testthat_print'
2.資料收集:PTT八卦版,2020/10/28 ~ 2021/04/27
利用平台抓取關鍵字:華航,然後匯入資料(時間+8小時)
MetaData = fread('./aaaa_articleMetaData.csv',encoding = 'UTF-8')
Reviews = fread('./aaaa_articleReviews.csv',encoding = 'UTF-8')
MetaData = MetaData %>% mutate(date_total=paste(artDate,artTime,sep = " "))#由於資料是格林威治時間,和台灣時間相差八小時,時間必須+8
MetaData$date_total = as.POSIXct(MetaData$date_total,format = "%Y/%m/%d %H:%M:%S")
MetaData$date_total = MetaData$date_total + 28800
MetaData$artDate=as_date(MetaData$date_total)
MetaData$artDate= MetaData$artDate%>% as.Date("%Y/%m/%d")
Reviews = Reviews %>% mutate(date_total=paste(artDate,artTime,sep = " "))
Reviews$date_total = as.POSIXct(Reviews$date_total,format = "%Y/%m/%d %H:%M:%S")
Reviews$date_total = Reviews$date_total + 28800
Reviews$artDate=as_date(Reviews$date_total)
Reviews$artDate= Reviews$artDate%>% as.Date("%Y/%m/%d")
MetaData$artDate= MetaData$artDate %>% as.Date("%Y/%m/%d")
MetaData %>%
group_by(artDate) %>%
summarise(count = n()) %>%
ggplot()+
geom_line(color = "blue",aes(x=artDate,y=count))+
geom_vline(xintercept = c(as.numeric(as.Date("2020-12-15")),
as.numeric(as.Date("2021-04-23"))), col='red', size = 0.8) +
scale_x_date(labels = date_format("%Y/%m/%d"))+ggtitle("華航討論文章數") +theme(text = element_text(family='STHeitiTC-Light'))+xlab("日期")+ylab("數量")

得知:
(1)2020/12/15討論文章數最多,其次是2021/04/23
(2)2020/12/15 [新聞]華航公布777F新塗裝CARGO內藏台灣圖樣與china的文字,可能會與中國搞混,造成意識形態混亂的問題,引發熱烈討論。
(3)2020/04/23[新聞]確診的華航印尼籍機師到清真寺參加活動,當日活動參與人數逾400人
3.資料清理
首先把推文和內容的資料合併
##用於資料清理
Reviews2 = left_join(MetaData, Reviews[,c("artUrl", "cmtContent")], by = "artUrl")
#設定斷詞器
user<- scan(file = "./user_dict.txt", what=character(),sep='\n',
encoding='utf-8',fileEncoding='utf-8',quiet = T)
stop_words <- scan(file = "./stop_words.txt", what=character(),sep='\n',
encoding='utf-8',fileEncoding='utf-8')
Read 1281 items
jieba_tokenizer = worker()
new_user_word(jieba_tokenizer, c(user))
[1] TRUE
# 設定斷詞function
gossip_tokenizer <- function(t) {
lapply(t, function(x) {
tokens <- segment(x, jieba_tokenizer)
tokens <- tokens[!tokens %in% stop_words]
return(tokens)
})
}
把文章和留言的斷詞結果併在一起
MToken <- MetaData %>% unnest_tokens(word, sentence, token = gossip_tokenizer)
RToken <- Reviews2 %>% unnest_tokens(word, cmtContent, token = gossip_tokenizer)
data <- rbind(MToken[,c("artDate","artUrl", "word")],RToken[,c("artDate","artUrl", "word")])
格式化日期
data$artDate <- as.Date(data$artDate)
data_select = data %>%
filter(!grepl('[[:punct:]]',word)) %>% # 去標點符號
filter(!grepl("['^0-9a-z']",word)) %>% # 去英文、數字
filter(nchar(.$word)>1)
查看篇數最多的那兩天裡面最常出現的詞彙
gossip_tokens_by_date <- data_select %>%
count(artDate, word, sort = TRUE)
plot_merge <- gossip_tokens_by_date %>%
filter(artDate == as.Date("2020-12-15") |
artDate == as.Date("2021-04-23")) %>%
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

4.文字雲
接下來我們來討論在這半年中,八卦版對華航的討論為何,算出全部字的詞頻後,畫出文字雲
set.seed(100)
data_select %>%
select(word) %>%
group_by(word) %>%
summarise(count=n()) %>% # 算字詞單篇總數用summarise
filter(word != "華航" & word != "台灣") %>%
arrange(desc(count)) %>%
head(120)%>% wordcloud2()->ppp

一些出現頻率比較高的如 : 機師、中國、長榮、英國、確診、口罩、防疫……
- 機師:4/23時去清真寺的消息
- 中國:在新冠肺炎、華航改名的討論時,常會一起出現
- 長榮:常與華航一起做比較,如:疫苗的施打率(長榮比華航多)
- 英國:變種病毒的來源
- 確診、口罩、來源:疫情期間常討論的話題
5.情緒分析
使用LIWC字典
P = read_file("./liwc/positive.txt") # 正向字典txt檔
N = read_file("./liwc/negative.txt") # 負向字典txt檔
P = strsplit(P, ",")[[1]]
N = strsplit(N, ",")[[1]]
P = data.frame(word = P, sentiment = "positive") #664
N = data.frame(word = N, sentiment = "negative") #1047
LIWC = rbind(P, N)
算出每天情緒總和(sentiment_count),並畫出日期波動圖
sentiment_count = data_select %>%
select(artDate,word) %>%
inner_join(LIWC) %>%
group_by(artDate,sentiment) %>%
summarise(count=n()) %>%
arrange(desc(count))
Joining, by = "word"
`summarise()` has grouped output by 'artDate'. You can override using the `.groups` argument.
#range(sentiment_count$artDate) #"2020-10-28" "2021-04-26"
#設定y軸刻度
datebreaks = seq(as.Date("2020-10-28"), as.Date("2021-04-26"),by = "1 month")
#沒有線的情緒分數
sentiment_count %>%
ggplot()+
geom_line(aes(x=artDate,y=count,colour=sentiment))+
scale_x_date(breaks = datebreaks)+
theme(axis.text.x = element_text(angle = 30, hjust = 1))+ggtitle("情緒分佈") +theme(text = element_text(family='STHeitiTC-Light'))+xlab("日期")+ylab("數量")

由上圖觀察可得2020/12/15、2020/04/23,情緒波動比較大
畫出2020/12/15、2020/04/23日期線
sentiment_count %>%
ggplot()+
geom_line(aes(x=artDate,y=count,colour=sentiment))+
scale_x_date(breaks = datebreaks)+
theme(axis.text.x = element_text(angle = 30, hjust = 1))+
geom_vline(xintercept = c(as.numeric(as.Date("2021-04-23")),
as.numeric(as.Date("2020-12-14"))), col='blue', size = 1)

在討論到華航時,幾乎都是負面情緒大於正面情緒
這兩日最常出現的正負面情緒字
data_sentiment <- data_select %>%
filter(artDate == as.Date("2020-12-15") |
artDate == as.Date("2021-04-23") ) %>%
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) +
facet_wrap(~sentiment, scales = "free_y") +
labs(y = "Contribution to sentiment",
x = NULL) +
theme(text=element_text(size=14,family = 'STHeitiTC-Light'))+
coord_flip()
Joining, by = "word"
`summarise()` has grouped output by 'word'. You can override using the `.groups` argument.

正負情緒文字雲
par(family=("Heiti TC Light"))
data_sentiment$data %>%
acast(word ~ sentiment, value.var = "count", fill = 0) %>%
comparison.cloud(
colors = c("salmon", "#72bcd4"), # positive negative
max.words = 50)

分析2021/04/23前後五天的情緒
sentiment_count %>% filter(artDate<=as.Date("2021-04-25",format="%Y-%m-%d"))%>%
# 標準化的部分
group_by(artDate) %>%
mutate(ratio = count/sum(count)) %>%
# 畫圖的部分
ggplot()+
geom_line(aes(x=artDate,y=ratio,colour=sentiment))+
scale_x_date(labels = date_format("%m/%d"),
limits = as.Date(c('2021-04-20','2021-04-25'))
)+
# 加上標示日期的線
geom_vline(aes(xintercept = as.numeric(artDate[which(sentiment_count$artDate == as.Date('2021-04-23'))[1]])),colour = "black",linetype=4)

可以看到4/23事件爆發後,由於指揮中心持續公布新的染疫者足跡地點,所以負面情緒越來越高漲,正面情緒比例一直下降,代表民眾真的很憤怒也很恐慌!
6.TF-IDF
計算每一篇文章的詞數
gossip_word = data_select %>% count(artUrl, word, sort = TRUE)
total_words = gossip_word %>%
group_by(artUrl) %>%
summarize(total = sum(n)) %>%
arrange(desc(total))
total_words
合併需要的資料欄位,計算詞彙的 tf-idf 值
gossip_word = left_join(gossip_word, total_words)
Joining, by = "artUrl"
# 以每篇文章爲單位,計算每個詞彙的 tf-idf 值
gossip_words_tf_idf = gossip_word %>%
bind_tf_idf(word, artUrl, n) %>%
group_by(artUrl) %>%
slice_max(tf_idf, n=5) %>%
arrange(desc(artUrl))
gossip_words_tf_idf
計算整個文集中 tf-idf 值高的字
gossip_words_tf_idf %>%
group_by(artUrl) %>%
slice_max(tf_idf, n=10) %>%
ungroup() %>%
count(word, sort=TRUE)
- 機師:染疫事件的主角
- 英國:變種病毒
- 禮拜五:染疫事件爆發4/23是星期五
計算兩個詞彙同時出現的總次數
移除PTT貼新聞時會出現的格式
word_pairs <- gossip_word %>%
filter(word!="新聞標題" & word!="來源" & word!="違者" & word!="刪除"& word!="署名"& word!="連結"& word!="請放"& word!="完整"& word!="內文"&word!="備註"& word!="媒體"& word!="記者")%>%
pairwise_count(word, artUrl, sort = TRUE)
`distinct_()` was deprecated in dplyr 0.7.0.
Please use `distinct()` instead.
See vignette('programming') for more help`tbl_df()` was deprecated in dplyr 1.0.0.
Please use `tibble::as_tibble()` instead.
算出字詞的相關性
word_cors <- gossip_word %>%
filter(word!="新聞標題" & word!="來源" & word!="違者" & word!="刪除"& word!="署名"& word!="連結"& word!="請放"& word!="完整"& word!="內文"&word!="備註"& word!="媒體"& word!="記者")%>%
group_by(word) %>%
filter(n() >= 10) %>%
pairwise_cor(word, artUrl, sort = TRUE)
word_cors
7.bigram
Metadata2 <- MetaData %>%
mutate(sentence=gsub("[\n]{2,}", "。", sentence)) %>% #換行、空格都用句號取代
mutate(sentence=gsub("\n", "", sentence)) %>%
mutate(sentence=gsub("http(s)?[-:\\/A-Za-z0-9\\.]+", " ", sentence))
Metadata2
移除PTT貼新聞時會出現的格式用字
Metadata2 = Metadata2 %>%
mutate(sentence=gsub("媒體來源|記者署名|完整新聞標題|完整新聞內文|完整新聞連結|(或短網址)|備註|備註請放最後面|違者新聞文章刪除", "", sentence))
bigram function
jieba_bigram <- function(t) {
lapply(t, function(x) {
if(nchar(x)>1){
tokens <- segment(x, jieba_tokenizer)
bigram<- ngrams(tokens, 2)
bigram <- lapply(bigram, paste, collapse = " ")
unlist(bigram)
}
})
}
執行bigram分詞
data_bigram <- Metadata2 %>%
unnest_tokens(bigram, sentence, token = jieba_bigram)
#data_bigram
data_bigram %>%
filter(!str_detect(bigram, regex("[0-9a-zA-Z]"))) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!(word1 %in% stop_words), !(word2 %in% stop_words)) %>%
count(word1, word2, sort = TRUE) %>%
unite_("bigram", c("word1","word2"), sep=" ")
8.Trigram
trigram function
jieba_trigram <- function(t) {
lapply(t, function(x) {
if(nchar(x)>1){
tokens <- segment(x, jieba_tokenizer)
ngram<- ngrams(unlist(tokens), 3)
ngram <- lapply(ngram, paste, collapse = " ")
unlist(ngram)
}
})
}
執行trigram分詞
data_trigram <- Metadata2 %>%
unnest_tokens(ngrams, sentence, token = jieba_trigram)
#data_trigram
data_trigram %>%
filter(!str_detect(ngrams, regex("[0-9a-zA-Z]"))) %>%
separate(ngrams, c("word1", "word2", "word3"), sep = " ") %>%
filter(!(word1 %in% stop_words), !(word2 %in% stop_words), !(word3 %in% stop_words)) %>%
count(word1, word2, word3, sort = TRUE) %>%
unite_("ngrams", c("word1", "word2", "word3"), sep=" ")
9.共線圖
畫出共線圖(correlation > 0.5)
set.seed(666)
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, family = "Heiti TC Light") + #加入中文字型設定,避免中文字顯示錯誤。
theme_void()

畫出共線圖(correlation > 0.7)
set.seed(666)
word_cors %>%
filter(correlation > 0.7 ) %>%
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()

10.結論
大部分民眾對於華航議題都處於負面情緒,12月左右都是在討論華航改名、飛機新塗裝的議題。4/23機師染疫風波發生之後,其染疫足跡擴及更多人,造成民眾的恐慌和憤怒,負面情緒更為高漲。
11.小發現
正常來說,當討論情緒都是負面的時候,一家公司的股價應該會下跌,但華航反而上漲,這是我們有趣的小發現:ptt反指標,嘻嘻😁😎
2020/12/15華航股價:11.70TWD

2021/04/23華航股價:20.40TWD😱

LS0tCnRpdGxlOiAi56S+576k5aqS6auU5YiG5p6Q5pyf5Lit5aCx5ZGK77ya5YiG5p6Q6I+v6Iiq5qmf5bir5p+T55ar6La06La06LWw5LqL5Lu2IgphdXRob3I6ICLnrKzkupTntYQg57WE5ZOh77yaTTA5NDAyMDA1MOWQs+S9qeeOsiBNMDk0MDIwMDYy5p6X5r+s57SYIE0wOTQwMjAwMzbpu4PlvIjmmbQiCmRhdGU6ICIyMDIxLzA1LzA0IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgdGhlbWU6IGZsYXRseQogICAgY3NzOiBzdHlsZS5jc3MKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMg5YuV5qmf6IiH5YiG5p6Q55uu55qECj4gKDEp6IOM5pmv5YuV5qmfIDog5pyA6L+R6I+v6Iiq5qmf5bir5p+T55ar77yM5Yiw6JmV6La06La06LWw77yM5Y676YGO5riF55yf5a+6562J5Zyw6bue77yM6YCg5oiQ5rCR55y+5oGQ5oWM77yM5aSa5Lq65b+F6aCI6ZqU6Zui5qqi55ar77yM5Y+w56eR5aSn55qE5a2455Sf55Sa6Iez5Zug5q2k5YGc6KqyIWByICJcVTFGNDQwImBgciAiXFUxRjYyMSJgCjxicj48YnI+CiFbXShhYWEucG5nKTxicj48YnI+CigyKeeglOeptuebrueahDog5Zug5q2k5LulUFRUIOWFq+WNpueJiOS4reeahOiojuirluaDheazge+8jOS+huWIhuaekOawkeecvumHneWwjeatpOS6i+S7tueahOeci+azleiIh+WPjeaHie+8jOmAsuihjOaOouiojueglOeptuOAgjxicj4KKDMp6LOH5paZ5L6G5rqQIDogUFRU5YWr5Y2m54mIKDIwMjAvMTAvMjh+MjAyMS80LzI3Ke+8jOmAj+mBjuaWh+Wtl+WIhuaekOW5s+WPsO+8jOmXnOmNteWtl+OAkOiPr+iIquOAkQoKIyAxLuWuieijnXBhY2thZ2UKCmBgYHtyIGVjaG8gPSBULCByZXN1bHRzID0gJ2hpZGUnfQpTeXMuc2V0bG9jYWxlKGNhdGVnb3J5ID0gIkxDX0FMTCIsIGxvY2FsZSA9ICJ6aF9UVy5VVEYtOCIpICMg6YG/5YWN5Lit5paH5LqC56K8CmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0KcGFja2FnZXMgPSBjKCJkcGx5ciIsICJ0aWR5dGV4dCIsICJzdHJpbmdyIiwgIndvcmRjbG91ZDIiLCAiZ2dwbG90MiIsJ3JlYWRyJywnZGF0YS50YWJsZScsJ3Jlc2hhcGUyJywnd29yZGNsb3VkJywnc2NhbGVzJywnd2lkeXInLCdpZ3JhcGgnLCdnZ3JhcGgnLCd0aWR5cicsJ05MUCcpCmV4aXN0aW5nID0gYXMuY2hhcmFjdGVyKGluc3RhbGxlZC5wYWNrYWdlcygpWywxXSkKZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpCmBgYAoKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbGlicmFyeShkcGx5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHdvcmRjbG91ZDIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShyZWFkcikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoamllYmFSKQpsaWJyYXJ5KHdpZHlyKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KE5MUCkKbGlicmFyeSh0aWR5cikKbGlicmFyeShkZXZ0b29scykKYGBgCgojIDIu6LOH5paZ5pS26ZuG77yaUFRU5YWr5Y2m54mI77yMMjAyMC8xMC8yOCB+IDIwMjEvMDQvMjcKCiMjIyDliKnnlKjlubPlj7DmipPlj5bpl5zpjbXlrZc66I+v6Iiq77yM54S25b6M5Yyv5YWl6LOH5paZKOaZgumWkys45bCP5pmCKQpgYGB7cn0KTWV0YURhdGEgPSBmcmVhZCgnLi9hYWFhX2FydGljbGVNZXRhRGF0YS5jc3YnLGVuY29kaW5nID0gJ1VURi04JykKUmV2aWV3cyAgPSBmcmVhZCgnLi9hYWFhX2FydGljbGVSZXZpZXdzLmNzdicsZW5jb2RpbmcgPSAnVVRGLTgnKQoKTWV0YURhdGEgPSBNZXRhRGF0YSAlPiUgbXV0YXRlKGRhdGVfdG90YWw9cGFzdGUoYXJ0RGF0ZSxhcnRUaW1lLHNlcCA9ICIgIikpI+eUseaWvOizh+aWmeaYr+agvOael+Wogeayu+aZgumWk++8jOWSjOWPsOeBo+aZgumWk+ebuOW3ruWFq+Wwj+aZgu+8jOaZgumWk+W/hemgiCs4Ck1ldGFEYXRhJGRhdGVfdG90YWwgPSBhcy5QT1NJWGN0KE1ldGFEYXRhJGRhdGVfdG90YWwsZm9ybWF0ID0gIiVZLyVtLyVkICVIOiVNOiVTIikKTWV0YURhdGEkZGF0ZV90b3RhbCA9IE1ldGFEYXRhJGRhdGVfdG90YWwgKyAyODgwMApNZXRhRGF0YSRhcnREYXRlPWFzX2RhdGUoTWV0YURhdGEkZGF0ZV90b3RhbCkKTWV0YURhdGEkYXJ0RGF0ZT0gTWV0YURhdGEkYXJ0RGF0ZSU+JSBhcy5EYXRlKCIlWS8lbS8lZCIpCgpSZXZpZXdzID0gUmV2aWV3cyAlPiUgbXV0YXRlKGRhdGVfdG90YWw9cGFzdGUoYXJ0RGF0ZSxhcnRUaW1lLHNlcCA9ICIgIikpClJldmlld3MkZGF0ZV90b3RhbCA9IGFzLlBPU0lYY3QoUmV2aWV3cyRkYXRlX3RvdGFsLGZvcm1hdCA9ICIlWS8lbS8lZCAlSDolTTolUyIpClJldmlld3MkZGF0ZV90b3RhbCA9IFJldmlld3MkZGF0ZV90b3RhbCArIDI4ODAwClJldmlld3MkYXJ0RGF0ZT1hc19kYXRlKFJldmlld3MkZGF0ZV90b3RhbCkKUmV2aWV3cyRhcnREYXRlPSBSZXZpZXdzJGFydERhdGUlPiUgYXMuRGF0ZSgiJVkvJW0vJWQiKQpgYGAKCgpgYGB7cn0KTWV0YURhdGEkYXJ0RGF0ZT0gTWV0YURhdGEkYXJ0RGF0ZSAlPiUgYXMuRGF0ZSgiJVkvJW0vJWQiKQpNZXRhRGF0YSAlPiUKICBncm91cF9ieShhcnREYXRlKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQogIGdncGxvdCgpKwogICAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLGFlcyh4PWFydERhdGUseT1jb3VudCkpKwogICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAyMC0xMi0xNSIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAyMS0wNC0yMyIpKSksIGNvbD0ncmVkJywgc2l6ZSA9IDAuOCkgKwogICAgc2NhbGVfeF9kYXRlKGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlWS8lbS8lZCIpKStnZ3RpdGxlKCLoj6/oiKroqI7oq5bmlofnq6DmlbgiKSArdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHk9J1NUSGVpdGlUQy1MaWdodCcpKSt4bGFiKCLml6XmnJ8iKSt5bGFiKCLmlbjph48iKQpgYGAKCiMjIyDlvpfnn6U6IAo+ICgxKTIwMjAvMTIvMTXoqI7oq5bmlofnq6DmlbjmnIDlpJrvvIzlhbbmrKHmmK8yMDIxLzA0LzIzPGJyPgo+ICgyKTIwMjAvMTIvMTUgW+aWsOiBnl3oj6/oiKrlhazluIM3NzdG5paw5aGX6KOdQ0FSR0/lhafol4/lj7DngaPlnJbmqKPoiIdjaGluYeeahOaWh+Wtl++8jOWPr+iDveacg+iIh+S4reWci+aQnua3t++8jOmAoOaIkOaEj+itmOW9ouaFi+a3t+S6gueahOWVj+mhjO+8jOW8leeZvOeGseeDiOiojuirluOAgjxicj4KPiAoMykyMDIwLzA0LzIzW+aWsOiBnl3norroqLrnmoToj6/oiKrljbDlsLznsY3mqZ/luKvliLDmuIXnnJ/lr7rlj4PliqDmtLvli5XvvIznlbbml6XmtLvli5Xlj4PoiIfkurrmlbjpgL40MDDkuro8YnI+CgojIyAzLuizh+aWmea4heeQhgojIyMg6aaW5YWI5oqK5o6o5paH5ZKM5YWn5a6555qE6LOH5paZ5ZCI5L21CmBgYHtyfQojI+eUqOaWvOizh+aWmea4heeQhgpSZXZpZXdzMiA9IGxlZnRfam9pbihNZXRhRGF0YSwgUmV2aWV3c1ssYygiYXJ0VXJsIiwgImNtdENvbnRlbnQiKV0sIGJ5ID0gImFydFVybCIpCiPoqK3lrprmlrfoqZ7lmagKdXNlcjwtIHNjYW4oZmlsZSA9ICIuL3VzZXJfZGljdC50eHQiLCB3aGF0PWNoYXJhY3RlcigpLHNlcD0nXG4nLCAKICAgICAgICAgICAgICAgICAgIGVuY29kaW5nPSd1dGYtOCcsZmlsZUVuY29kaW5nPSd1dGYtOCcscXVpZXQgPSBUKQpzdG9wX3dvcmRzIDwtIHNjYW4oZmlsZSA9ICIuL3N0b3Bfd29yZHMudHh0Iiwgd2hhdD1jaGFyYWN0ZXIoKSxzZXA9J1xuJywgCiAgICAgICAgICAgICAgICAgICBlbmNvZGluZz0ndXRmLTgnLGZpbGVFbmNvZGluZz0ndXRmLTgnKQoKamllYmFfdG9rZW5pemVyID0gd29ya2VyKCkKbmV3X3VzZXJfd29yZChqaWViYV90b2tlbml6ZXIsIGModXNlcikpCiMg6Kit5a6a5pa36KmeZnVuY3Rpb24KZ29zc2lwX3Rva2VuaXplciA8LSBmdW5jdGlvbih0KSB7CiAgICBsYXBwbHkodCwgZnVuY3Rpb24oeCkgewogICAgICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikKICAgICAgICB0b2tlbnMgPC0gdG9rZW5zWyF0b2tlbnMgJWluJSBzdG9wX3dvcmRzXQogICAgICAgIHJldHVybih0b2tlbnMpCiAgICB9KQp9CgpgYGAKCiMjIyDmiormlofnq6DlkoznlZnoqIDnmoTmlrfoqZ7ntZDmnpzkvbXlnKjkuIDotbcKYGBge3J9Ck1Ub2tlbiA8LSBNZXRhRGF0YSAlPiUgdW5uZXN0X3Rva2Vucyh3b3JkLCBzZW50ZW5jZSwgdG9rZW4gPSBnb3NzaXBfdG9rZW5pemVyKQpSVG9rZW4gPC0gUmV2aWV3czIgJT4lIHVubmVzdF90b2tlbnMod29yZCwgY210Q29udGVudCwgdG9rZW4gPSBnb3NzaXBfdG9rZW5pemVyKQpkYXRhIDwtIHJiaW5kKE1Ub2tlblssYygiYXJ0RGF0ZSIsImFydFVybCIsICJ3b3JkIildLFJUb2tlblssYygiYXJ0RGF0ZSIsImFydFVybCIsICJ3b3JkIildKSAKYGBgCgoKIyMjIOagvOW8j+WMluaXpeacnwpgYGB7cn0KZGF0YSRhcnREYXRlIDwtIGFzLkRhdGUoZGF0YSRhcnREYXRlKQpkYXRhX3NlbGVjdCA9IGRhdGEgJT4lIAogICAgZmlsdGVyKCFncmVwbCgnW1s6cHVuY3Q6XV0nLHdvcmQpKSAlPiUgIyDljrvmqJnpu57nrKbomZ8KICAgIGZpbHRlcighZ3JlcGwoIlsnXjAtOWEteiddIix3b3JkKSkgJT4lICMg5Y676Iux5paH44CB5pW45a2XCiAgICBmaWx0ZXIobmNoYXIoLiR3b3JkKT4xKQpgYGAKCgojIyMg5p+l55yL56+H5pW45pyA5aSa55qE6YKj5YWp5aSp6KOh6Z2i5pyA5bi45Ye654++55qE6Kme5b2ZCmBgYHtyfQpnb3NzaXBfdG9rZW5zX2J5X2RhdGUgPC0gZGF0YV9zZWxlY3QgJT4lIAogIGNvdW50KGFydERhdGUsIHdvcmQsIHNvcnQgPSBUUlVFKQpwbG90X21lcmdlIDwtIGdvc3NpcF90b2tlbnNfYnlfZGF0ZSAlPiUgCiAgZmlsdGVyKGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMC0xMi0xNSIpIHwgCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0yMyIpKSAlPiUgCiAgZ3JvdXBfYnkoYXJ0RGF0ZSkgJT4lIAogIHRvcF9uKDcsIG4pICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXdvcmQsIHk9biwgZmlsbCA9IGFydERhdGUpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCiAgZmFjZXRfd3JhcCh+YXJ0RGF0ZSwgc2NhbGVzPSJmcmVlIiwgbmNvbCA9IDIpICsgCiAgY29vcmRfZmxpcCgpKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikpCnBsb3RfbWVyZ2UKCmBgYAoKCiMjIDQu5paH5a2X6ZuyCiMjIyDmjqXkuIvkvobmiJHlgJHkvoboqI7oq5blnKjpgJnljYrlubTkuK3vvIzlhavljabniYjlsI3oj6/oiKrnmoToqI7oq5bngrrkvZXvvIznrpflh7rlhajpg6jlrZfnmoToqZ7poLvlvozvvIznlavlh7rmloflrZfpm7IKYGBge3J9CnNldC5zZWVkKDEwMCkKZGF0YV9zZWxlY3QgJT4lCiAgICBzZWxlY3Qod29yZCkgJT4lCiAgICBncm91cF9ieSh3b3JkKSAlPiUKICAgIHN1bW1hcmlzZShjb3VudD1uKCkpICU+JSAgIyDnrpflrZfoqZ7llq7nr4fnuL3mlbjnlKhzdW1tYXJpc2UKICAgIGZpbHRlcih3b3JkICE9ICLoj6/oiKoiICYgd29yZCAhPSAi5Y+w54GjIikgJT4lCiAgICBhcnJhbmdlKGRlc2MoY291bnQpKSAlPiUgCiAgICBoZWFkKDEyMCklPiUgd29yZGNsb3VkMigpLT5wcHAKYGBgCiFbXShwcHAucG5nKQoKIyMjIyDkuIDkupvlh7rnj77poLvnjofmr5TovIPpq5jnmoTlpoIgOiDmqZ/luKvjgIHkuK3lnIvjgIHplbfmpq7jgIHoi7HlnIvjgIHnorroqLrjgIHlj6PnvanjgIHpmLLnlqsuLi4uLi4KKyDmqZ/luKvvvJo0LzIz5pmC5Y675riF55yf5a+655qE5raI5oGvCisg5Lit5ZyL77ya5Zyo5paw5Yag6IK654KO44CB6I+v6Iiq5pS55ZCN55qE6KiO6KuW5pmC77yM5bi45pyD5LiA6LW35Ye654++Cisg6ZW35qau77ya5bi46IiH6I+v6Iiq5LiA6LW35YGa5q+U6LyD77yM5aaC77ya55ar6IuX55qE5pa95omT546HKOmVt+amruavlOiPr+iIquWkmikKKyDoi7HlnIvvvJrorornqK7nl4Xmr5LnmoTkvobmupAKKyDnorroqLrjgIHlj6PnvanjgIHkvobmupDvvJrnlqvmg4XmnJ/plpPluLjoqI7oq5bnmoToqbHpoYwKCiMjIDUu5oOF57eS5YiG5p6QCiMjIyDkvb/nlKhMSVdD5a2X5YW4CmBgYHtyfQpQID0gcmVhZF9maWxlKCIuL2xpd2MvcG9zaXRpdmUudHh0IikgIyDmraPlkJHlrZflhbh0eHTmqpQKTiA9IHJlYWRfZmlsZSgiLi9saXdjL25lZ2F0aXZlLnR4dCIpICMg6LKg5ZCR5a2X5YW4dHh05qqUClAgPSBzdHJzcGxpdChQLCAiLCIpW1sxXV0KTiA9IHN0cnNwbGl0KE4sICIsIilbWzFdXQpQID0gZGF0YS5mcmFtZSh3b3JkID0gUCwgc2VudGltZW50ID0gInBvc2l0aXZlIikgIzY2NApOID0gZGF0YS5mcmFtZSh3b3JkID0gTiwgc2VudGltZW50ID0gIm5lZ2F0aXZlIikgIzEwNDcKTElXQyA9IHJiaW5kKFAsIE4pCmBgYAoKIyMjIOeul+WHuuavj+WkqeaDhee3kue4veWSjChzZW50aW1lbnRfY291bnQp77yM5Lim55Wr5Ye65pel5pyf5rOi5YuV5ZyWCmBgYHtyfQpzZW50aW1lbnRfY291bnQgPSBkYXRhX3NlbGVjdCAlPiUKICAgIHNlbGVjdChhcnREYXRlLHdvcmQpICU+JQogICAgaW5uZXJfam9pbihMSVdDKSAlPiUgCiAgICBncm91cF9ieShhcnREYXRlLHNlbnRpbWVudCkgJT4lCiAgICBzdW1tYXJpc2UoY291bnQ9bigpKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoY291bnQpKQojcmFuZ2Uoc2VudGltZW50X2NvdW50JGFydERhdGUpICMiMjAyMC0xMC0yOCIgIjIwMjEtMDQtMjYiCiPoqK3lrpp56Lu45Yi75bqmCmRhdGVicmVha3MgPSBzZXEoYXMuRGF0ZSgiMjAyMC0xMC0yOCIpLCBhcy5EYXRlKCIyMDIxLTA0LTI2IiksYnkgPSAiMSBtb250aCIpCiPmspLmnInnt5rnmoTmg4Xnt5LliIbmlbgKc2VudGltZW50X2NvdW50ICU+JQogICAgZ2dwbG90KCkrCiAgICBnZW9tX2xpbmUoYWVzKHg9YXJ0RGF0ZSx5PWNvdW50LGNvbG91cj1zZW50aW1lbnQpKSsKICAgIHNjYWxlX3hfZGF0ZShicmVha3MgPSBkYXRlYnJlYWtzKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpK2dndGl0bGUoIuaDhee3kuWIhuS9iCIpICt0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseT0nU1RIZWl0aVRDLUxpZ2h0JykpK3hsYWIoIuaXpeacnyIpK3lsYWIoIuaVuOmHjyIpCgpgYGAKCiMjIyMg55Sx5LiK5ZyW6KeA5a+f5Y+v5b6XMjAyMC8xMi8xNeOAgTIwMjAvMDQvMjPvvIzmg4Xnt5Lms6Lli5Xmr5TovIPlpKcKCgojIyMg55Wr5Ye6MjAyMC8xMi8xNeOAgTIwMjAvMDQvMjPml6XmnJ/nt5oKYGBge3J9CnNlbnRpbWVudF9jb3VudCAlPiUKICAgIGdncGxvdCgpKwogICAgZ2VvbV9saW5lKGFlcyh4PWFydERhdGUseT1jb3VudCxjb2xvdXI9c2VudGltZW50KSkrCiAgICBzY2FsZV94X2RhdGUoYnJlYWtzID0gZGF0ZWJyZWFrcykrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoYXMubnVtZXJpYyhhcy5EYXRlKCIyMDIxLTA0LTIzIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKGFzLkRhdGUoIjIwMjAtMTItMTQiKSkpLCBjb2w9J2JsdWUnLCBzaXplID0gMSkKYGBgCgojIyMjIOWcqOiojuirluWIsOiPr+iIquaZgu+8jOW5vuS5jumDveaYr+iyoOmdouaDhee3kuWkp+aWvOato+mdouaDhee3kgoKIyMjIOmAmeWFqeaXpeacgOW4uOWHuuePvueahOato+iyoOmdouaDhee3kuWtlwpgYGB7cn0KZGF0YV9zZW50aW1lbnQgPC0gZGF0YV9zZWxlY3QgJT4lCiAgZmlsdGVyKGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMC0xMi0xNSIpIHwgCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNC0yMyIpICkgJT4lIAogIGlubmVyX2pvaW4oTElXQykgJT4lCiAgZ3JvdXBfYnkod29yZCxzZW50aW1lbnQpICU+JQogIHN1bW1hcmlzZSgKICAgIGNvdW50ID0gbigpCiAgKSAlPiUgZGF0YS5mcmFtZSgpICU+JSAKICB0b3BfbigzMCx3dCA9IGNvdW50KSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBjb3VudCkpICU+JQogIGdncGxvdChhZXMod29yZCwgY291bnQsIGZpbGwgPSBzZW50aW1lbnQpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofnNlbnRpbWVudCwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHkgPSAiQ29udHJpYnV0aW9uIHRvIHNlbnRpbWVudCIsCiAgICAgICB4ID0gTlVMTCkgKwogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTQsZmFtaWx5ID0gJ1NUSGVpdGlUQy1MaWdodCcpKSsKICBjb29yZF9mbGlwKCkKZGF0YV9zZW50aW1lbnQKYGBgCgojIyMg5q2j6LKg5oOF57eS5paH5a2X6ZuyCmBgYHtyfQpwYXIoZmFtaWx5PSgiSGVpdGkgVEMgTGlnaHQiKSkKZGF0YV9zZW50aW1lbnQkZGF0YSAlPiUKICBhY2FzdCh3b3JkIH4gc2VudGltZW50LCB2YWx1ZS52YXIgPSAiY291bnQiLCBmaWxsID0gMCkgJT4lCiAgY29tcGFyaXNvbi5jbG91ZCgKICAgIGNvbG9ycyA9IGMoInNhbG1vbiIsICIjNzJiY2Q0IiksICMgcG9zaXRpdmUgbmVnYXRpdmUKICAgICAgICAgICAgICAgICAgIG1heC53b3JkcyA9IDUwKQpgYGAKCiMjIyDliIbmnpAyMDIxLzA0LzIz5YmN5b6M5LqU5aSp55qE5oOF57eSCmBgYHtyfQpzZW50aW1lbnRfY291bnQgJT4lICBmaWx0ZXIoYXJ0RGF0ZTw9YXMuRGF0ZSgiMjAyMS0wNC0yNSIsZm9ybWF0PSIlWS0lbS0lZCIpKSU+JQogICMg5qiZ5rqW5YyW55qE6YOo5YiGCiAgZ3JvdXBfYnkoYXJ0RGF0ZSkgJT4lCiAgbXV0YXRlKHJhdGlvID0gY291bnQvc3VtKGNvdW50KSkgJT4lCiAgIyDnlavlnJbnmoTpg6jliIYKICBnZ3Bsb3QoKSsKICBnZW9tX2xpbmUoYWVzKHg9YXJ0RGF0ZSx5PXJhdGlvLGNvbG91cj1zZW50aW1lbnQpKSsKICBzY2FsZV94X2RhdGUobGFiZWxzID0gZGF0ZV9mb3JtYXQoIiVtLyVkIiksCiAgICAgICAgICAgICAgIGxpbWl0cyA9IGFzLkRhdGUoYygnMjAyMS0wNC0yMCcsJzIwMjEtMDQtMjUnKSkKICAgICAgICAgICAgICAgKSsKICAjIOWKoOS4iuaomeekuuaXpeacn+eahOe3mgogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBhcy5udW1lcmljKGFydERhdGVbd2hpY2goc2VudGltZW50X2NvdW50JGFydERhdGUgPT0gYXMuRGF0ZSgnMjAyMS0wNC0yMycpKVsxXV0pKSxjb2xvdXIgPSAiYmxhY2siLGxpbmV0eXBlPTQpCmBgYAojIyMjIOWPr+S7peeci+WIsDQvMjPkuovku7bniIbnmbzlvozvvIznlLHmlrzmjIfmj67kuK3lv4PmjIHnuozlhazluIPmlrDnmoTmn5PnlqvogIXotrPot6HlnLDpu57vvIzmiYDku6XosqDpnaLmg4Xnt5Lotorkvobotorpq5jmvLLvvIzmraPpnaLmg4Xnt5Lmr5TkvovkuIDnm7TkuIvpmY3vvIzku6PooajmsJHnnL7nnJ/nmoTlvojmhqTmgJLkuZ/lvojmgZDmhYzvvIEKCiMjIDYuVEYtSURGCiMjIyDoqIjnrpfmr4/kuIDnr4fmlofnq6DnmoToqZ7mlbgKYGBge3J9Cmdvc3NpcF93b3JkID0gZGF0YV9zZWxlY3QgJT4lIGNvdW50KGFydFVybCwgd29yZCwgc29ydCA9IFRSVUUpCnRvdGFsX3dvcmRzID0gZ29zc2lwX3dvcmQgJT4lIAogICAgZ3JvdXBfYnkoYXJ0VXJsKSAlPiUgCiAgICBzdW1tYXJpemUodG90YWwgPSBzdW0obikpICU+JSAKICAgIGFycmFuZ2UoZGVzYyh0b3RhbCkpCnRvdGFsX3dvcmRzCmBgYAoKIyMjIOWQiOS9temcgOimgeeahOizh+aWmeashOS9je+8jOioiOeul+ipnuW9meeahCB0Zi1pZGYg5YC8CmBgYHtyfQpnb3NzaXBfd29yZCA9IGxlZnRfam9pbihnb3NzaXBfd29yZCwgdG90YWxfd29yZHMpCiMg5Lul5q+P56+H5paH56ug54iy5Zau5L2N77yM6KiI566X5q+P5YCL6Kme5b2Z55qEIHRmLWlkZiDlgLwKZ29zc2lwX3dvcmRzX3RmX2lkZiA9IGdvc3NpcF93b3JkICU+JQogICAgYmluZF90Zl9pZGYod29yZCwgYXJ0VXJsLCBuKSAlPiUgCiAgICBncm91cF9ieShhcnRVcmwpICU+JQogICAgc2xpY2VfbWF4KHRmX2lkZiwgbj01KSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoYXJ0VXJsKSkKZ29zc2lwX3dvcmRzX3RmX2lkZgpgYGAKCiMjIyDoqIjnrpfmlbTlgIvmlofpm4bkuK0gdGYtaWRmIOWAvOmrmOeahOWtlwpgYGB7cn0KZ29zc2lwX3dvcmRzX3RmX2lkZiAlPiUgCiAgZ3JvdXBfYnkoYXJ0VXJsKSAlPiUKICBzbGljZV9tYXgodGZfaWRmLCBuPTEwKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgY291bnQod29yZCwgc29ydD1UUlVFKQpgYGAKKyDmqZ/luKvvvJrmn5Pnlqvkuovku7bnmoTkuLvop5IKKyDoi7HlnIvvvJrorornqK7nl4Xmr5IKKyDnpq7mi5zkupTvvJrmn5Pnlqvkuovku7bniIbnmbw0LzIz5piv5pif5pyf5LqUCgoKIyMjIOioiOeul+WFqeWAi+ipnuW9meWQjOaZguWHuuePvueahOe4veasoeaVuArnp7vpmaRQVFTosrzmlrDogZ7mmYLmnIPlh7rnj77nmoTmoLzlvI8KYGBge3J9CndvcmRfcGFpcnMgPC0gZ29zc2lwX3dvcmQgJT4lCiAgICBmaWx0ZXIod29yZCE9IuaWsOiBnuaomemhjCIgJiB3b3JkIT0i5L6G5rqQIiAmIHdvcmQhPSLpgZXogIUiICYgd29yZCE9IuWIqumZpCImIHdvcmQhPSLnvbLlkI0iJiB3b3JkIT0i6YCj57WQIiYgd29yZCE9Iuiri+aUviImIHdvcmQhPSLlrozmlbQiJiB3b3JkIT0i5YWn5paHIiZ3b3JkIT0i5YKZ6Ki7IiYgd29yZCE9IuWqkumrlCImIHdvcmQhPSLoqJjogIUiKSU+JQogICAgcGFpcndpc2VfY291bnQod29yZCwgYXJ0VXJsLCBzb3J0ID0gVFJVRSkKd29yZF9wYWlycwoKYGBgCgojIyMg566X5Ye65a2X6Kme55qE55u46Zec5oCnCmBgYHtyfQp3b3JkX2NvcnMgPC0gZ29zc2lwX3dvcmQgJT4lCiAgICBmaWx0ZXIod29yZCE9IuaWsOiBnuaomemhjCIgJiB3b3JkIT0i5L6G5rqQIiAmIHdvcmQhPSLpgZXogIUiICYgd29yZCE9IuWIqumZpCImIHdvcmQhPSLnvbLlkI0iJiB3b3JkIT0i6YCj57WQIiYgIHdvcmQhPSLoq4vmlL4iJiB3b3JkIT0i5a6M5pW0IiYgd29yZCE9IuWFp+aWhyImd29yZCE9IuWCmeiouyImIHdvcmQhPSLlqpLpq5QiJiB3b3JkIT0i6KiY6ICFIiklPiUgCiAgICBncm91cF9ieSh3b3JkKSAlPiUKICAgIGZpbHRlcihuKCkgPj0gMTApICU+JQogICAgcGFpcndpc2VfY29yKHdvcmQsIGFydFVybCwgc29ydCA9IFRSVUUpCndvcmRfY29ycwpgYGAKCiMjIDcuYmlncmFtCmBgYHtyfQpNZXRhZGF0YTIgPC0gTWV0YURhdGEgJT4lIAogIG11dGF0ZShzZW50ZW5jZT1nc3ViKCJbXG5dezIsfSIsICLjgIIiLCBzZW50ZW5jZSkpICU+JSAj5o+b6KGM44CB56m65qC86YO955So5Y+l6Jmf5Y+W5LujCiAgbXV0YXRlKHNlbnRlbmNlPWdzdWIoIlxuIiwgIiIsIHNlbnRlbmNlKSkgJT4lIAogIG11dGF0ZShzZW50ZW5jZT1nc3ViKCJodHRwKHMpP1stOlxcL0EtWmEtejAtOVxcLl0rIiwgIiAiLCBzZW50ZW5jZSkpCk1ldGFkYXRhMgpgYGAKCuenu+mZpFBUVOiyvOaWsOiBnuaZguacg+WHuuePvueahOagvOW8j+eUqOWtlwpgYGB7cn0KTWV0YWRhdGEyID0gTWV0YWRhdGEyICU+JSAKICBtdXRhdGUoc2VudGVuY2U9Z3N1Yigi5aqS6auU5L6G5rqQfOiomOiAhee9suWQjXzlrozmlbTmlrDogZ7mqJnpoYx85a6M5pW05paw6IGe5YWn5paHfOWujOaVtOaWsOiBnumAo+e1kHwo5oiW55+t57ay5Z2AKXzlgpnoqLt85YKZ6Ki76KuL5pS+5pyA5b6M6Z2ifOmBleiAheaWsOiBnuaWh+eroOWIqumZpCIsICIiLCBzZW50ZW5jZSkpCmBgYAoKYmlncmFtIGZ1bmN0aW9uCmBgYHtyfQoKamllYmFfYmlncmFtIDwtIGZ1bmN0aW9uKHQpIHsKICBsYXBwbHkodCwgZnVuY3Rpb24oeCkgewogICAgaWYobmNoYXIoeCk+MSl7CiAgICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikKICAgICAgYmlncmFtPC0gbmdyYW1zKHRva2VucywgMikKICAgICAgYmlncmFtIDwtIGxhcHBseShiaWdyYW0sIHBhc3RlLCBjb2xsYXBzZSA9ICIgIikKICAgICAgdW5saXN0KGJpZ3JhbSkKICAgIH0KICB9KQp9CmBgYAoK5Z+36KGMYmlncmFt5YiG6KmeCmBgYHtyfQpkYXRhX2JpZ3JhbSA8LSBNZXRhZGF0YTIgJT4lCiAgdW5uZXN0X3Rva2VucyhiaWdyYW0sIHNlbnRlbmNlLCB0b2tlbiA9IGppZWJhX2JpZ3JhbSkKI2RhdGFfYmlncmFtCgpkYXRhX2JpZ3JhbSAlPiUKICBmaWx0ZXIoIXN0cl9kZXRlY3QoYmlncmFtLCByZWdleCgiWzAtOWEtekEtWl0iKSkpICU+JQogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgCiAgZmlsdGVyKCEod29yZDEgJWluJSBzdG9wX3dvcmRzKSwgISh3b3JkMiAlaW4lIHN0b3Bfd29yZHMpKSAlPiUKICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKSAlPiUKICB1bml0ZV8oImJpZ3JhbSIsIGMoIndvcmQxIiwid29yZDIiKSwgc2VwPSIgIikKYGBgCgoKIyMgOC5UcmlncmFtCnRyaWdyYW0gZnVuY3Rpb24KYGBge3J9CmppZWJhX3RyaWdyYW0gPC0gZnVuY3Rpb24odCkgewogIGxhcHBseSh0LCBmdW5jdGlvbih4KSB7CiAgICBpZihuY2hhcih4KT4xKXsKICAgICAgdG9rZW5zIDwtIHNlZ21lbnQoeCwgamllYmFfdG9rZW5pemVyKQogICAgICBuZ3JhbTwtIG5ncmFtcyh1bmxpc3QodG9rZW5zKSwgMykKICAgICAgbmdyYW0gPC0gbGFwcGx5KG5ncmFtLCBwYXN0ZSwgY29sbGFwc2UgPSAiICIpCiAgICAgIHVubGlzdChuZ3JhbSkKICAgIH0KICB9KQp9CmBgYAoK5Z+36KGMdHJpZ3JhbeWIhuipngpgYGB7cn0KZGF0YV90cmlncmFtIDwtIE1ldGFkYXRhMiAlPiUKICB1bm5lc3RfdG9rZW5zKG5ncmFtcywgc2VudGVuY2UsIHRva2VuID0gamllYmFfdHJpZ3JhbSkKI2RhdGFfdHJpZ3JhbQoKZGF0YV90cmlncmFtICU+JQogIGZpbHRlcighc3RyX2RldGVjdChuZ3JhbXMsIHJlZ2V4KCJbMC05YS16QS1aXSIpKSkgJT4lCiAgc2VwYXJhdGUobmdyYW1zLCBjKCJ3b3JkMSIsICJ3b3JkMiIsICJ3b3JkMyIpLCBzZXAgPSAiICIpICU+JSAKICBmaWx0ZXIoISh3b3JkMSAlaW4lIHN0b3Bfd29yZHMpLCAhKHdvcmQyICVpbiUgc3RvcF93b3JkcyksICEod29yZDMgJWluJSBzdG9wX3dvcmRzKSkgJT4lCiAgY291bnQod29yZDEsIHdvcmQyLCB3b3JkMywgc29ydCA9IFRSVUUpICU+JQogIHVuaXRlXygibmdyYW1zIiwgYygid29yZDEiLCAid29yZDIiLCAid29yZDMiKSwgc2VwPSIgIikKYGBgCgoKIyMgOS7lhbHnt5rlnJYK55Wr5Ye65YWx57ea5ZyWKGNvcnJlbGF0aW9uID4gMC41KQpgYGB7cn0Kc2V0LnNlZWQoNjY2KQp3b3JkX2NvcnMgJT4lCiAgICBmaWx0ZXIoY29ycmVsYXRpb24gPiAwLjUgKSAlPiUKICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogICAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gY29ycmVsYXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibGlnaHRibHVlIiwgc2l6ZSA9IDMpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbCA9IFRSVUUsIGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpICsgI+WKoOWFpeS4reaWh+Wtl+Wei+ioreWumu+8jOmBv+WFjeS4reaWh+Wtl+mhr+ekuumMr+iqpOOAggogICAgdGhlbWVfdm9pZCgpCmBgYAoK55Wr5Ye65YWx57ea5ZyWKGNvcnJlbGF0aW9uID4gMC43KQpgYGB7cn0Kc2V0LnNlZWQoNjY2KQp3b3JkX2NvcnMgJT4lCiAgICBmaWx0ZXIoY29ycmVsYXRpb24gPiAwLjcgKSAlPiUKICAgIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogICAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gY29ycmVsYXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibGlnaHRibHVlIiwgc2l6ZSA9IDMpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbCA9IFRSVUUsIGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpICsgI+WKoOWFpeS4reaWh+Wtl+Wei+ioreWumu+8jOmBv+WFjeS4reaWh+Wtl+mhr+ekuumMr+iqpOOAggogICAgdGhlbWVfdm9pZCgpCmBgYAoKIyMgMTAu57WQ6KuWCj4g5aSn6YOo5YiG5rCR55y+5bCN5pa86I+v6Iiq6K2w6aGM6YO96JmV5pa86LKg6Z2i5oOF57eS77yMMTLmnIjlt6blj7Ppg73mmK/lnKjoqI7oq5boj6/oiKrmlLnlkI3jgIHpo5vmqZ/mlrDloZfoo53nmoTorbDpoYzjgII0LzIz5qmf5bir5p+T55ar6aKo5rOi55m855Sf5LmL5b6M77yM5YW25p+T55ar6Laz6Leh5pO05Y+K5pu05aSa5Lq677yM6YCg5oiQ5rCR55y+55qE5oGQ5oWM5ZKM5oak5oCS77yM6LKg6Z2i5oOF57eS5pu054K66auY5ryy44CCCgojIyAxMS7lsI/nmbznj74KPuato+W4uOS+huiqqu+8jOeVtuiojuirluaDhee3kumDveaYr+iyoOmdoueahOaZguWAme+8jOS4gOWutuWFrOWPuOeahOiCoeWDueaHieipsuacg+S4i+i3jO+8jOS9huiPr+iIquWPjeiAjOS4iua8su+8jOmAmeaYr+aIkeWAkeaciei2o+eahOWwj+eZvOePvu+8mnB0dOWPjeaMh+aome+8jOWYu+WYu2ByICJcVTFGNjAxImBgciAiXFUxRjYwRSJgCgoKIyMjIyAyMDIwLzEyLzE16I+v6Iiq6IKh5YO577yaMTEuNzBUV0QKIVtdKDEucG5nKTxicj4KCiMjIyMgMjAyMS8wNC8yM+iPr+iIquiCoeWDue+8mjIwLjQwVFdEYHIgIlxVMUY2MzEiYAohW10oMi5wbmcpCgoK