Ch.0 : 資料取得及觀念複習
1. 資料取得及套件載入
載入的資料是由中山大學管理學院文字分析平台取得,在平台資料輸出區塊選擇「文章+詞彙+詞頻」選項,即可取得相同格式之csv檔案。
資料簡介
本資料為2019/01/26 ~ 2019/03/08,將PTT武漢肺炎討論專版自01/26開版以來之資料,透過文字分析平台整理,得到4738篇文章。
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","ggplot2", "data.table", "scales")
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)
載入需要的packages以及資料
require(dplyr)
require(ggplot2)
require(data.table)
require(scales)
require(wordcloud2)
載入自平台下載下來的資料
csv <- fread("./data/nCoV2019_artWordFreq.csv", encoding = "UTF-8")
csv$artDate = csv$artDate %>% as.Date("%Y/%m/%d")
str(csv)
Classes ‘data.table’ and 'data.frame': 447662 obs. of 6 variables:
$ artTitle: chr "[新聞]澎湖傳疑似感染武漢肺炎4人負壓病房隔" "[新聞]澎湖傳疑似感染武漢肺炎4人負壓病房隔" "[新聞]澎湖傳疑似感染武漢肺炎4人負壓病房隔" "[新聞]澎湖傳疑似感染武漢肺炎4人負壓病房隔" ...
$ artDate : Date, format: "2020-01-25" "2020-01-25" "2020-01-25" "2020-01-25" ...
$ artTime : chr "20:28:07" "20:28:07" "20:28:07" "20:28:07" ...
$ artUrl : chr "https://www.ptt.cc/bbs/nCoV2019/M.1579984089.A.535.html" "https://www.ptt.cc/bbs/nCoV2019/M.1579984089.A.535.html" "https://www.ptt.cc/bbs/nCoV2019/M.1579984089.A.535.html" "https://www.ptt.cc/bbs/nCoV2019/M.1579984089.A.535.html" ...
$ word : chr "澎湖" "通報" "女性" "分院" ...
$ count : int 7 4 4 3 3 2 2 2 2 2 ...
- attr(*, ".internal.selfref")=<externalptr>
資料預設之日期欄位是“chr”格式,在畫圖前我們須先將其轉為“date”格式,轉換後可以透過str指令來確認各欄位型態。
資料欄位
- artTitle: 文章之標題,注意:不同文章可能會有完全相同的標題。
- artDate: 文章發佈之日期。
- artTime: 文章發佈之時間。
- artUrl: 文章之網址,每篇文章之網址為獨一無二的,可用來辨識相同標題之不同文章。
- word: 詞彙。
- count: 詞頻。
Ch.1 日期折線圖
這個章節的目的是計算出每一天文章的發表數量,可以看出特定主題討論的熱度。
資料處理
data <- csv %>%
select(artDate, artUrl) %>%
distinct()
select(): 我們只需要文章以及日期兩個欄位即可,其他欄位不需要。
distinct(): 一篇文章有很多個詞彙,所以會有很多列,但我們只需要一篇文章保留一個列即可。
article_count_by_date <- data %>%
group_by(artDate) %>%
summarise(count = n())
head(article_count_by_date, 20)
按照日期分群,計算每天共有幾篇討論文章。
plot_date <-
# data
article_count_by_date %>%
# aesthetics
ggplot(aes(x = artDate, y = count)) +
# geometrics
geom_line(color = "#00AFBB", size = 2) +
geom_vline(xintercept = as.numeric(as.Date("2020-02-12")), col='red') +
# coordinates
scale_x_date(labels = date_format("%Y/%m/%d")) +
ggtitle("武漢肺炎 討論文章數") +
xlab("日期") +
ylab("數量") +
# theme
theme(text = element_text(family = "Heiti TC Light")) #加入中文字型設定,避免中文字顯示錯誤。
plot_date

從上圖中可以看到關於「武漢肺炎」的討論從開版以來,討論文章數有逐漸增加的趨勢。
Ch.2 文字雲
接下來我們來大略觀察討論的內容為何,使用的方式為文字雲。
data <- csv %>%
group_by(word) %>%
summarise(sum = sum(count)) %>%
arrange(desc(sum))
先將資料集中所有文章按照文字進行分群,計算每一個字的總詞頻。
head(data)
結果為總詞頻最多的字。
data %>% filter(sum > 500) %>% wordcloud2()
將整理好的資料直接送入wordcloud2 function 即可得到文字雲。此套件為互動式介面,使用滑鼠移動到特定的詞彙,畫面會同時顯示詞彙以及對應的詞頻。
按照日期進行區分
在Ch.1中的日期折線圖中,我們發現在2/12前後討論數量有一波轉折,我們來看看2/12前後的討論內容是否有不同的地方。
data_before <- csv %>% filter(artDate <= "2020-02-12")
data_after <- csv %>% filter(artDate > "2020-02-12")
按照日期切分資料
data_before <- data_before %>%
group_by(word) %>%
summarise(sum = sum(count)) %>%
arrange(desc(sum))
data_after <- data_after %>%
group_by(word) %>%
summarise(sum = sum(count)) %>%
arrange(desc(sum))
與Ch.2相同的資料處理。
plot_before <- data_before %>% filter(sum > 300) %>% wordcloud2()
#plot_before

2/12 之前的文字雲(html中會顯示不出來第一張以後的文字雲,請將程式碼下載下來即可成功繪出)
plot_after <- data_after %>% filter(sum > 300) %>% wordcloud2()
#plot_after

2/12之後的文字雲(html中會顯示不出來第一張以後的文字雲,請將程式碼下載下來即可成功繪出)
觀察兩張圖片中出現的國家可以發現,在2/12以前,有出現「中國」、「台灣」、「美國」、「日本」、「香港」。 在2/12以後,開始出現「韓國」、「南韓」、「大邱」、「伊朗」等關鍵字。大致與疾病爆發的先後順序一致。
練習練習~
可以發現本次資料集內有許多新聞用語,因為武漢肺炎版上有許多人轉貼新聞。
那麼現在請各位將所列的幾個關鍵字移除後重新繪製文字雲吧!
新聞關鍵字:發稿、新聞、原文、記者、發稿、撰稿者、連結、完整標題、今天、不是、目前、表示
### Code Here ###
Ch3. 長條圖
文字雲可以直覺看出較常提到的字,但如果想得到精確的「最常出現詞彙」,我們則可以透過長條圖來查看。
data <- rbind(data_before %>% mutate(type="before"), data_after %>% mutate(type="after"))
將2/12前後的資料加入一個欄位標示後合併起來。
head(data)
除了詞彙及詞頻以外,還多了一個type欄位來區分2/12以前或是以後。
plot_merge <- data %>%
group_by(type) %>%
top_n(10, sum) %>%
ungroup() %>%
mutate(word = reorder(word, sum)) %>%
ggplot(aes(x=word, y=sum, fill = type)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y="詞頻") +
facet_wrap(~type, ncol = 1, scales="free") +
coord_flip()+
theme(text = element_text(family = "Heiti TC Light"))
plot_merge

由上圖可以看到,討論的內容在2/12前後大致相同。
plot_merge <- data %>%
group_by(type) %>%
top_n(50, sum) %>%
ungroup() %>%
#filter(!(duplicated(word)| duplicated(word, fromLast = TRUE))) #%>%
group_by(word) %>%
filter(n()==1) %>%
ungroup() %>%
mutate(word = reorder(word, sum)) %>%
ggplot(aes(word, sum, fill = type)) +
geom_col(show.legend = FALSE) +
labs(x = NULL, y="總和") +
facet_wrap(~type, ncol = 1, scales="free") +
coord_flip()+
theme(text = element_text(family = "Heiti TC Light"))
plot_merge

將重複的詞彙移除後,可以看到在2/12前與2/12後的討論差異:
1. 國家不同
2. 隨著疫情蔓延,出現更多死亡
3. 最初的「入境」管制議題,到後來的「社區」傳播議題。
Ch.4 情緒折線圖
透過文字分析平台可以輸出每篇文章的情緒分數,在資料預覽頁面選擇「文章+情緒」選項即可得到資料。
載入資料
csv_sen <- fread("./data/nCoV2019_artSen.csv", encoding = "UTF-8")
head(csv_sen)
資料欄位介紹:
1. artTitle: 文章之標題,注意:不同文章可能會有完全相同的標題。
2. artDate: 文章發佈之日期。
3. artTime: 文章發佈之時間。
4. artUrl: 文章之網址,每篇文章之網址為獨一無二的,可用來辨識相同標題之不同文章。
5. positive_emotion_grade: 本篇文章出現多少次正面情緒詞彙。
6. negative_emotion_grade: 本篇文章出現多少次負面情緒詞彙。
7. neutral_emotion_grade: 本篇文章出現多少次中性情緒詞彙。
csv_sen$artDate = csv_sen$artDate %>% as.Date("%Y/%m/%d")
str(csv_sen)
Classes ‘data.table’ and 'data.frame': 4738 obs. of 7 variables:
$ artTitle : chr "[新聞]澎湖傳疑似感染武漢肺炎4人負壓病房隔" "[新聞]新加坡累積確診至4人" "[討論]出門該注意哪些重點?" "[閒聊]這個板沒有板規嗎?" ...
$ artDate : Date, format: "2020-01-25" "2020-01-25" "2020-01-25" "2020-01-25" ...
$ artTime : chr "20:28:07" "20:32:36" "20:44:18" "21:56:41" ...
$ artUrl : chr "https://www.ptt.cc/bbs/nCoV2019/M.1579984089.A.535.html" "https://www.ptt.cc/bbs/nCoV2019/M.1579984359.A.6D7.html" "https://www.ptt.cc/bbs/nCoV2019/M.1579985060.A.ADD.html" "https://www.ptt.cc/bbs/nCoV2019/M.1579989403.A.239.html" ...
$ positive_emotion_grade: int 2 0 0 0 1 0 5 5 10 1 ...
$ negative_emotion_grade: int 0 0 0 0 0 0 11 1 6 4 ...
$ neutral_emotion_grade : int 1 0 0 0 0 0 3 0 0 0 ...
- attr(*, ".internal.selfref")=<externalptr>
與Ch.1相同,資料預設日期格式為“chr”,我們需要先將其轉為“date”格式。
data_sen <- csv_sen %>%
group_by(artDate) %>%
summarise(positive = sum(positive_emotion_grade), negative = sum(negative_emotion_grade), neutral = sum(neutral_emotion_grade))
head(data_sen)
將資料按照日期分群後,加總每天的三種情緒分數,並進行標準化。
data_sen %>% ggplot(aes(x= artDate)) +
geom_line(aes(y = positive, colour = "red")) +
geom_line(aes(y = negative, colour = "blue")) +
geom_line(aes(y = neutral, colour = "yellow")) +
scale_x_date(labels = date_format("%Y/%m/%d")) +
scale_color_discrete(name="情緒種類", labels = c("positive","negative","neutral")) +
ggtitle("武漢肺炎 討論情緒") +
xlab("日期") +
ylab("分數") +
theme(text = element_text(family = "Heiti TC Light"))

練習練習~
剛剛我們將資料按照日期分群後,加總計算了每天的三種情緒分數。 但是我們可以發現每天的文章數量造成辭彙的數量不一樣,所以情緒圖的走勢會有很大的起伏。 請各位將每日的情緒總值進行標準化後再畫一次情緒的走勢圖。
公式:
positive = positive / (positive + negative + neutral)
negative = negative / (positive + negative + neutral)
neutral = neutral / (positive + negative + neutral)
hint:剛剛summarise那邊可以順便計算每日的情緒詞總數
hint2:最後會用到mutate喔
### Code Here ###
LS0tCnRpdGxlOiAi5Lul5paH5a2X5YiG5p6Q5bmz5Y+w542y5Y+W5LmL6LOH5paZ6YCy6KGM5Z+65pys57mq5ZyW5YiG5p6QIgphdXRob3I6ICJLdW4tSHNpYW5nIENoZW4iCmRhdGU6ICIyMDIwLzAzLzA1IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAphYnN0cmFjdDogIuS9v+eUqOaWh+Wtl+WIhuaekOW5s+WPsOi8uOWHuuS5i+izh+aWme+8jOS7pSdkcGx5ciflj4onZ2dwbG90MiflpZfku7bpgLLooYzln7rmnKzos4fmlpnoppboprrljJYiCi0tLQojIENoLjAgOiDos4fmlpnlj5blvpflj4rop4Dlv7XopIfnv5IKIyMgMS4g6LOH5paZ5Y+W5b6X5Y+K5aWX5Lu26LyJ5YWlCj4g6LyJ5YWl55qE6LOH5paZ5piv55Sx5Lit5bGx5aSn5a24566h55CG5a246Zmi5paH5a2X5YiG5p6Q5bmz5Y+w5Y+W5b6X77yM5Zyo5bmz5Y+w6LOH5paZ6Ly45Ye65Y2A5aGK6YG45pOH44CM5paH56ugK+ipnuW9mSvoqZ7poLvjgI3pgbjpoIXvvIzljbPlj6/lj5blvpfnm7jlkIzmoLzlvI/kuYtjc3bmqpTmoYjjgIIKCiMjIyDos4fmlpnnsKHku4sKPiDmnKzos4fmlpnngroyMDE5LzAxLzI2IH4gMjAxOS8wMy8wOO+8jOWwh1BUVOatpua8ouiCuueCjuiojuirluWwiOeJiOiHqjAxLzI26ZaL54mI5Lul5L6G5LmL6LOH5paZ77yM6YCP6YGO5paH5a2X5YiG5p6Q5bmz5Y+w5pW055CG77yM5b6X5YiwNDczOOevh+aWh+eroOOAggoKYGBge3J9ClN5cy5zZXRsb2NhbGUoY2F0ZWdvcnkgPSAiTENfQUxMIiwgbG9jYWxlID0gInpoX1RXLlVURi04IikgIyDpgb/lhY3kuK3mlofkuoLnorwKYGBgCgojIyMg5a6J6KOd6ZyA6KaB55qEcGFja2FnZXMKYGBge3J9CnBhY2thZ2VzID0gYygiZHBseXIiLCJnZ3Bsb3QyIiwgImRhdGEudGFibGUiLCAic2NhbGVzIikKZXhpc3RpbmcgPSBhcy5jaGFyYWN0ZXIoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKQpmb3IocGtnIGluIHBhY2thZ2VzWyEocGFja2FnZXMgJWluJSBleGlzdGluZyldKSBpbnN0YWxsLnBhY2thZ2VzKHBrZykKYGBgCgojIyMg6LyJ5YWl6ZyA6KaB55qEcGFja2FnZXPku6Xlj4ros4fmlpkKYGBge3IgZWNobyA9IFQsIHJlc3VsdHMgPSAnaGlkZSd9CnJlcXVpcmUoZHBseXIpCnJlcXVpcmUoZ2dwbG90MikKcmVxdWlyZShkYXRhLnRhYmxlKQpyZXF1aXJlKHNjYWxlcykKcmVxdWlyZSh3b3JkY2xvdWQyKQpgYGAKCiMjIyDovInlhaXoh6rlubPlj7DkuIvovInkuIvkvobnmoTos4fmlpkKYGBge3J9CmNzdiA8LSBmcmVhZCgiLi9kYXRhL25Db1YyMDE5X2FydFdvcmRGcmVxLmNzdiIsIGVuY29kaW5nID0gIlVURi04IikKY3N2JGFydERhdGUgPSBjc3YkYXJ0RGF0ZSAlPiUgYXMuRGF0ZSgiJVkvJW0vJWQiKQpzdHIoY3N2KQpgYGAKPiDos4fmlpnpoJDoqK3kuYvml6XmnJ/mrITkvY3mmK8iY2hyIuagvOW8j++8jOWcqOeVq+WcluWJjeaIkeWAkemgiOWFiOWwh+WFtui9ieeCuiJkYXRlIuagvOW8j++8jOi9ieaPm+W+jOWPr+S7pemAj+mBjnN0cuaMh+S7pOS+hueiuuiqjeWQhOashOS9jeWei+aFi+OAggoKIyMjIOaqouimluWJjTbnrYbos4fmlpkKYGBge3J9CmhlYWQoY3N2KQpgYGAKCiMjIyDos4fmlpnmrITkvY0KPiAxLiBhcnRUaXRsZTog5paH56ug5LmL5qiZ6aGM77yM5rOo5oSPOuS4jeWQjOaWh+eroOWPr+iDveacg+acieWujOWFqOebuOWQjOeahOaomemhjOOAggoyLiBhcnREYXRlOiDmlofnq6DnmbzkvYjkuYvml6XmnJ/jgIIKMy4gYXJ0VGltZTog5paH56ug55m85L2I5LmL5pmC6ZaT44CCCjQuIGFydFVybDog5paH56ug5LmL57ay5Z2A77yM5q+P56+H5paH56ug5LmL57ay5Z2A54K6542o5LiA54Sh5LqM55qE77yM5Y+v55So5L6G6L6o6K2Y55u45ZCM5qiZ6aGM5LmL5LiN5ZCM5paH56ug44CCCjUuIHdvcmQ6IOipnuW9meOAggo2LiBjb3VudDog6Kme6aC744CCCgojIENoLjEg5pel5pyf5oqY57ea5ZyWCj4g6YCZ5YCL56ug56+A55qE55uu55qE5piv6KiI566X5Ye65q+P5LiA5aSp5paH56ug55qE55m86KGo5pW46YeP77yM5Y+v5Lul55yL5Ye654m55a6a5Li76aGM6KiO6KuW55qE54ax5bqm44CCCgojIyDos4fmlpnomZXnkIYKCmBgYHtyfQpkYXRhIDwtIGNzdiAlPiUgCiAgc2VsZWN0KGFydERhdGUsIGFydFVybCkgJT4lIAogIGRpc3RpbmN0KCkKYGBgCj4gc2VsZWN0KCk6IOaIkeWAkeWPqumcgOimgeaWh+eroOS7peWPiuaXpeacn+WFqeWAi+ashOS9jeWNs+WPr++8jOWFtuS7luashOS9jeS4jemcgOimgeOAgjxicj4KPiBkaXN0aW5jdCgpOiDkuIDnr4fmlofnq6DmnInlvojlpJrlgIvoqZ7lvZnvvIzmiYDku6XmnIPmnInlvojlpJrliJfvvIzkvYbmiJHlgJHlj6rpnIDopoHkuIDnr4fmlofnq6Dkv53nlZnkuIDlgIvliJfljbPlj6/jgIIKCgpgYGB7cn0KYXJ0aWNsZV9jb3VudF9ieV9kYXRlIDwtIGRhdGEgJT4lIAogIGdyb3VwX2J5KGFydERhdGUpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpCgpoZWFkKGFydGljbGVfY291bnRfYnlfZGF0ZSwgMjApCmBgYAo+IOaMieeFp+aXpeacn+WIhue+pO+8jOioiOeul+avj+WkqeWFseacieW5vuevh+iojuirluaWh+eroOOAggoKYGBge3J9CnBsb3RfZGF0ZSA8LSAKICAjIGRhdGEKICBhcnRpY2xlX2NvdW50X2J5X2RhdGUgJT4lIAogICMgYWVzdGhldGljcwogIGdncGxvdChhZXMoeCA9IGFydERhdGUsIHkgPSBjb3VudCkpICsKICAjIGdlb21ldHJpY3MKICBnZW9tX2xpbmUoY29sb3IgPSAiIzAwQUZCQiIsIHNpemUgPSAyKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAyMC0wMi0xMiIpKSwgY29sPSdyZWQnKSArIAogICMgY29vcmRpbmF0ZXMKICBzY2FsZV94X2RhdGUobGFiZWxzID0gZGF0ZV9mb3JtYXQoIiVZLyVtLyVkIikpICsKICBnZ3RpdGxlKCLmrabmvKLogrrngo4g6KiO6KuW5paH56ug5pW4IikgKyAKICB4bGFiKCLml6XmnJ8iKSArIAogIHlsYWIoIuaVuOmHjyIpICsgCiAgIyB0aGVtZQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikpICPliqDlhaXkuK3mloflrZflnovoqK3lrprvvIzpgb/lhY3kuK3mloflrZfpoa/npLrpjK/oqqTjgIIKCnBsb3RfZGF0ZQpgYGAKPiDlvp7kuIrlnJbkuK3lj6/ku6XnnIvliLDpl5zmlrzjgIzmrabmvKLogrrngo7jgI3nmoToqI7oq5blvp7plovniYjku6XkvobvvIzoqI7oq5bmlofnq6DmlbjmnInpgJDmvLjlop7liqDnmoTotqjli6LjgIIKCiMgQ2guMiDmloflrZfpm7IKPiDmjqXkuIvkvobmiJHlgJHkvoblpKfnlaXop4Dlr5/oqI7oq5bnmoTlhaflrrnngrrkvZXvvIzkvb/nlKjnmoTmlrnlvI/ngrrmloflrZfpm7LjgIIKCmBgYHtyfQpkYXRhIDwtIGNzdiAlPiUgCiAgZ3JvdXBfYnkod29yZCkgJT4lIAogIHN1bW1hcmlzZShzdW0gPSBzdW0oY291bnQpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHN1bSkpCmBgYAo+IOWFiOWwh+izh+aWmembhuS4reaJgOacieaWh+eroOaMieeFp+aWh+Wtl+mAsuihjOWIhue+pO+8jOioiOeul+avj+S4gOWAi+Wtl+eahOe4veipnumgu+OAggoKYGBge3J9CmhlYWQoZGF0YSkKYGBgCj4g57WQ5p6c54K657i96Kme6aC75pyA5aSa55qE5a2X44CCCgpgYGB7cn0KZGF0YSAlPiUgZmlsdGVyKHN1bSA+IDUwMCkgJT4lIHdvcmRjbG91ZDIoKQpgYGAKPiDlsIfmlbTnkIblpb3nmoTos4fmlpnnm7TmjqXpgIHlhaV3b3JkY2xvdWQyIGZ1bmN0aW9uIOWNs+WPr+W+l+WIsOaWh+Wtl+mbsuOAguatpOWll+S7tueCuuS6kuWLleW8j+S7i+mdou+8jOS9v+eUqOa7kem8oOenu+WLleWIsOeJueWumueahOipnuW9me+8jOeVq+mdouacg+WQjOaZgumhr+ekuuipnuW9meS7peWPiuWwjeaHieeahOipnumgu+OAggoKIyMg5oyJ54Wn5pel5pyf6YCy6KGM5Y2A5YiGCj4g5ZyoQ2guMeS4reeahOaXpeacn+aKmOe3muWcluS4re+8jOaIkeWAkeeZvOePvuWcqDIvMTLliY3lvozoqI7oq5bmlbjph4/mnInkuIDms6LovYnmipjvvIzmiJHlgJHkvobnnIvnnIsyLzEy5YmN5b6M55qE6KiO6KuW5YWn5a655piv5ZCm5pyJ5LiN5ZCM55qE5Zyw5pa544CCCgpgYGB7cn0KZGF0YV9iZWZvcmUgPC0gY3N2ICU+JSBmaWx0ZXIoYXJ0RGF0ZSA8PSAiMjAyMC0wMi0xMiIpCmRhdGFfYWZ0ZXIgPC0gY3N2ICU+JSBmaWx0ZXIoYXJ0RGF0ZSA+ICIyMDIwLTAyLTEyIikKYGBgCj4g5oyJ54Wn5pel5pyf5YiH5YiG6LOH5paZCgpgYGB7cn0KZGF0YV9iZWZvcmUgPC0gZGF0YV9iZWZvcmUgJT4lIAogIGdyb3VwX2J5KHdvcmQpICU+JSAKICBzdW1tYXJpc2Uoc3VtID0gc3VtKGNvdW50KSkgJT4lIAogIGFycmFuZ2UoZGVzYyhzdW0pKQoKZGF0YV9hZnRlciA8LSBkYXRhX2FmdGVyICU+JSAKICBncm91cF9ieSh3b3JkKSAlPiUgCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShjb3VudCkpICU+JSAKICBhcnJhbmdlKGRlc2Moc3VtKSkKYGBgCj4g6IiHQ2guMuebuOWQjOeahOizh+aWmeiZleeQhuOAggoKYGBge3J9CnBsb3RfYmVmb3JlIDwtIGRhdGFfYmVmb3JlICU+JSBmaWx0ZXIoc3VtID4gMzAwKSAlPiUgd29yZGNsb3VkMigpCiNwbG90X2JlZm9yZQpgYGAKIVtdKHdvcmRjbG91ZDEucG5nKQoKPiAyLzEyIOS5i+WJjeeahOaWh+Wtl+mbsihodG1s5Lit5pyD6aGv56S65LiN5Ye65L6G56ys5LiA5by15Lul5b6M55qE5paH5a2X6Zuy77yM6KuL5bCH56iL5byP56K85LiL6LyJ5LiL5L6G5Y2z5Y+v5oiQ5Yqf57mq5Ye6KQoKYGBge3J9CnBsb3RfYWZ0ZXIgPC0gZGF0YV9hZnRlciAlPiUgZmlsdGVyKHN1bSA+IDMwMCkgJT4lIHdvcmRjbG91ZDIoKQojcGxvdF9hZnRlcgpgYGAKIVtdKHdvcmRjbG91ZDIucG5nKQoKPiAyLzEy5LmL5b6M55qE5paH5a2X6ZuyKGh0bWzkuK3mnIPpoa/npLrkuI3lh7rkvobnrKzkuIDlvLXku6XlvoznmoTmloflrZfpm7LvvIzoq4vlsIfnqIvlvI/norzkuIvovInkuIvkvobljbPlj6/miJDlip/nuarlh7opCgo+IOingOWvn+WFqeW8teWclueJh+S4reWHuuePvueahOWci+WutuWPr+S7peeZvOePvu+8jOWcqDIvMTLku6XliY3vvIzmnInlh7rnj77jgIzkuK3lnIvjgI3jgIHjgIzlj7DngaPjgI3jgIHjgIznvo7lnIvjgI3jgIHjgIzml6XmnKzjgI3jgIHjgIzpppnmuK/jgI3jgIIg5ZyoMi8xMuS7peW+jO+8jOmWi+Wni+WHuuePvuOAjOmfk+Wci+OAjeOAgeOAjOWNl+mfk+OAjeOAgeOAjOWkp+mCseOAjeOAgeOAjOS8iuacl+OAjeetiemXnOmNteWtl+OAguWkp+iHtOiIh+eWvueXheeIhueZvOeahOWFiOW+jOmghuW6j+S4gOiHtOOAggoKIyMg57e057+S57e057+S772eCj4g5Y+v5Lul55m854++5pys5qyh6LOH5paZ6ZuG5YWn5pyJ6Kix5aSa5paw6IGe55So6Kqe77yM5Zug54K65q2m5ryi6IK654KO54mI5LiK5pyJ6Kix5aSa5Lq66L2J6LK85paw6IGe44CCPGJyPgrpgqPpurznj77lnKjoq4vlkITkvY3lsIfmiYDliJfnmoTlub7lgIvpl5zpjbXlrZfnp7vpmaTlvozph43mlrDnuaroo73mloflrZfpm7LlkKfvvIE8YnI+CuaWsOiBnumXnOmNteWtl++8mueZvOeov+OAgeaWsOiBnuOAgeWOn+aWh+OAgeiomOiAheOAgeeZvOeov+OAgeaSsOeov+iAheOAgemAo+e1kOOAgeWujOaVtOaomemhjOOAgeS7iuWkqeOAgeS4jeaYr+OAgeebruWJjeOAgeihqOekugoKYGBge3J9CiMjIyBDb2RlIEhlcmUgIyMjCmBgYAoKIyBDaDMuIOmVt+aineWclgo+IOaWh+Wtl+mbsuWPr+S7peebtOimuueci+WHuui8g+W4uOaPkOWIsOeahOWtl++8jOS9huWmguaenOaDs+W+l+WIsOeyvueiuueahOOAjOacgOW4uOWHuuePvuipnuW9meOAje+8jOaIkeWAkeWJh+WPr+S7pemAj+mBjumVt+aineWcluS+huafpeeci+OAggoKYGBge3J9CmRhdGEgPC0gcmJpbmQoZGF0YV9iZWZvcmUgJT4lIG11dGF0ZSh0eXBlPSJiZWZvcmUiKSwgZGF0YV9hZnRlciAlPiUgbXV0YXRlKHR5cGU9ImFmdGVyIikpCmBgYAo+IOWwhzIvMTLliY3lvoznmoTos4fmlpnliqDlhaXkuIDlgIvmrITkvY3mqJnnpLrlvozlkIjkvbXotbfkvobjgIIKCmBgYHtyfQpoZWFkKGRhdGEpCmBgYAo+IOmZpOS6huipnuW9meWPiuipnumgu+S7peWklu+8jOmChOWkmuS6huS4gOWAi3R5cGXmrITkvY3kvobljYDliIYyLzEy5Lul5YmN5oiW5piv5Lul5b6M44CCCgpgYGB7cn0KcGxvdF9tZXJnZSA8LSBkYXRhICU+JSAKICBncm91cF9ieSh0eXBlKSAlPiUgCiAgdG9wX24oMTAsIHN1bSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIHN1bSkpICU+JQogIGdncGxvdChhZXMoeD13b3JkLCB5PXN1bSwgZmlsbCA9IHR5cGUpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeCA9IE5VTEwsIHk9IuipnumguyIpICsKICBmYWNldF93cmFwKH50eXBlLCBuY29sID0gMSwgc2NhbGVzPSJmcmVlIikgKyAKICBjb29yZF9mbGlwKCkrCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkKCnBsb3RfbWVyZ2UKYGBgCj4g55Sx5LiK5ZyW5Y+v5Lul55yL5Yiw77yM6KiO6KuW55qE5YWn5a655ZyoMi8xMuWJjeW+jOWkp+iHtOebuOWQjOOAggoKYGBge3J9CnBsb3RfbWVyZ2UgPC0gZGF0YSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lIAogIHRvcF9uKDUwLCBzdW0pICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgI2ZpbHRlcighKGR1cGxpY2F0ZWQod29yZCl8IGR1cGxpY2F0ZWQod29yZCwgZnJvbUxhc3QgPSBUUlVFKSkpICMlPiUgCiAgZ3JvdXBfYnkod29yZCkgJT4lCiAgZmlsdGVyKG4oKT09MSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgc3VtKSkgJT4lIAogIGdncGxvdChhZXMod29yZCwgc3VtLCBmaWxsID0gdHlwZSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgbGFicyh4ID0gTlVMTCwgeT0i57i95ZKMIikgKwogIGZhY2V0X3dyYXAofnR5cGUsIG5jb2wgPSAxLCBzY2FsZXM9ImZyZWUiKSArIAogIGNvb3JkX2ZsaXAoKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKQoKcGxvdF9tZXJnZQpgYGAKPiDlsIfph43opIfnmoToqZ7lvZnnp7vpmaTlvozvvIzlj6/ku6XnnIvliLDlnKgyLzEy5YmN6IiHMi8xMuW+jOeahOiojuirluW3rueVsO+8mjxicj4KMS4g5ZyL5a625LiN5ZCMPGJyPgoyLiDpmqjokZfnlqvmg4XolJPlu7bvvIzlh7rnj77mm7TlpJrmrbvkuqE8YnI+CjMuIOacgOWIneeahOOAjOWFpeWig+OAjeeuoeWItuitsOmhjO+8jOWIsOW+jOS+hueahOOAjOekvuWNgOOAjeWCs+aSreitsOmhjOOAggoKIyBDaC40IOaDhee3kuaKmOe3muWclgo+IOmAj+mBjuaWh+Wtl+WIhuaekOW5s+WPsOWPr+S7pei8uOWHuuavj+evh+aWh+eroOeahOaDhee3kuWIhuaVuO+8jOWcqOizh+aWmemgkOimvemggemdoumBuOaTh+OAjOaWh+eroCvmg4Xnt5LjgI3pgbjpoIXljbPlj6/lvpfliLDos4fmlpnjgIIKCiMjIOi8ieWFpeizh+aWmQpgYGB7cn0KY3N2X3NlbiA8LSBmcmVhZCgiLi9kYXRhL25Db1YyMDE5X2FydFNlbi5jc3YiLCBlbmNvZGluZyA9ICJVVEYtOCIpCmhlYWQoY3N2X3NlbikKYGBgCj4g6LOH5paZ5qyE5L2N5LuL57S577yaPGJyPgo+IDEuIGFydFRpdGxlOiDmlofnq6DkuYvmqJnpoYzvvIzms6jmhI865LiN5ZCM5paH56ug5Y+v6IO95pyD5pyJ5a6M5YWo55u45ZCM55qE5qiZ6aGM44CCPGJyPgo+IDIuIGFydERhdGU6IOaWh+eroOeZvOS9iOS5i+aXpeacn+OAgjxicj4KPiAzLiBhcnRUaW1lOiDmlofnq6DnmbzkvYjkuYvmmYLplpPjgII8YnI+Cj4gNC4gYXJ0VXJsOiDmlofnq6DkuYvntrLlnYDvvIzmr4/nr4fmlofnq6DkuYvntrLlnYDngrrnjajkuIDnhKHkuoznmoTvvIzlj6/nlKjkvobovqjorZjnm7jlkIzmqJnpoYzkuYvkuI3lkIzmlofnq6DjgII8YnI+Cj4gNS4gcG9zaXRpdmVfZW1vdGlvbl9ncmFkZTog5pys56+H5paH56ug5Ye654++5aSa5bCR5qyh5q2j6Z2i5oOF57eS6Kme5b2Z44CCPGJyPgo+IDYuIG5lZ2F0aXZlX2Vtb3Rpb25fZ3JhZGU6IOacrOevh+aWh+eroOWHuuePvuWkmuWwkeasoeiyoOmdouaDhee3kuipnuW9meOAgjxicj4KPiA3LiBuZXV0cmFsX2Vtb3Rpb25fZ3JhZGU6IOacrOevh+aWh+eroOWHuuePvuWkmuWwkeasoeS4reaAp+aDhee3kuipnuW9meOAggoKYGBge3J9CmNzdl9zZW4kYXJ0RGF0ZSA9IGNzdl9zZW4kYXJ0RGF0ZSAlPiUgYXMuRGF0ZSgiJVkvJW0vJWQiKQpzdHIoY3N2X3NlbikKYGBgCj4g6IiHQ2guMeebuOWQjO+8jOizh+aWmemgkOioreaXpeacn+agvOW8j+eCuiJjaHIi77yM5oiR5YCR6ZyA6KaB5YWI5bCH5YW26L2J54K6ImRhdGUi5qC85byP44CCCgpgYGB7cn0KZGF0YV9zZW4gPC0gY3N2X3NlbiAlPiUgCiAgZ3JvdXBfYnkoYXJ0RGF0ZSkgJT4lIAogIHN1bW1hcmlzZShwb3NpdGl2ZSA9IHN1bShwb3NpdGl2ZV9lbW90aW9uX2dyYWRlKSwgbmVnYXRpdmUgPSBzdW0obmVnYXRpdmVfZW1vdGlvbl9ncmFkZSksIG5ldXRyYWwgPSBzdW0obmV1dHJhbF9lbW90aW9uX2dyYWRlKSkKCmhlYWQoZGF0YV9zZW4pCmBgYAo+IOWwh+izh+aWmeaMieeFp+aXpeacn+WIhue+pOW+jO+8jOWKoOe4veavj+WkqeeahOS4ieeoruaDhee3kuWIhuaVuO+8jOS4pumAsuihjOaomea6luWMluOAggoKYGBge3J9CmRhdGFfc2VuICU+JSBnZ3Bsb3QoYWVzKHg9IGFydERhdGUpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gcG9zaXRpdmUsIGNvbG91ciA9ICJyZWQiKSkgKwogIGdlb21fbGluZShhZXMoeSA9IG5lZ2F0aXZlLCBjb2xvdXIgPSAiYmx1ZSIpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gbmV1dHJhbCwgY29sb3VyID0gInllbGxvdyIpKSArIAogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJVkvJW0vJWQiKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWU9IuaDhee3kueorumhniIsIGxhYmVscyA9IGMoInBvc2l0aXZlIiwibmVnYXRpdmUiLCJuZXV0cmFsIikpICsgCiAgZ2d0aXRsZSgi5q2m5ryi6IK654KOIOiojuirluaDhee3kiIpICsgCiAgeGxhYigi5pel5pyfIikgKyAKICB5bGFiKCLliIbmlbgiKSArIAogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikpCmBgYAoKCiMjIOe3tOe/kue3tOe/ku+9ngo+IOWJm+WJm+aIkeWAkeWwh+izh+aWmeaMieeFp+aXpeacn+WIhue+pOW+jO+8jOWKoOe4veioiOeul+S6huavj+WkqeeahOS4ieeoruaDhee3kuWIhuaVuOOAggrkvYbmmK/miJHlgJHlj6/ku6Xnmbznj77mr4/lpKnnmoTmlofnq6Dmlbjph4/pgKDmiJDovq3lvZnnmoTmlbjph4/kuI3kuIDmqKPvvIzmiYDku6Xmg4Xnt5LlnJbnmoTotbDli6LmnIPmnInlvojlpKfnmoTotbfkvI/jgIIK6KuL5ZCE5L2N5bCH5q+P5pel55qE5oOF57eS57i95YC86YCy6KGM5qiZ5rqW5YyW5b6M5YaN55Wr5LiA5qyh5oOF57eS55qE6LWw5Yui5ZyW44CCPGJyPjxicj4K5YWs5byP77yaPGJyPgpwb3NpdGl2ZSA9IHBvc2l0aXZlIC8gKHBvc2l0aXZlICsgbmVnYXRpdmUgKyBuZXV0cmFsKTxicj4KbmVnYXRpdmUgPSBuZWdhdGl2ZSAvIChwb3NpdGl2ZSArIG5lZ2F0aXZlICsgbmV1dHJhbCk8YnI+Cm5ldXRyYWwgPSBuZXV0cmFsIC8gKHBvc2l0aXZlICsgbmVnYXRpdmUgKyBuZXV0cmFsKTxicj48YnI+CmhpbnTvvJrliZvliZtzdW1tYXJpc2XpgqPpgorlj6/ku6XpoIbkvr/oqIjnrpfmr4/ml6XnmoTmg4Xnt5LoqZ7nuL3mlbg8YnI+CmhpbnQy77ya5pyA5b6M5pyD55So5YiwbXV0YXRl5ZaUCgpgYGB7cn0KIyMjIENvZGUgSGVyZSAjIyMKYGBgCgoKCgo=