Encoding to UTF-8
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"



Install essential package
packages = c("dplyr", "tidytext", "stringr", "wordcloud2", "ggplot2",'readr','data.table','reshape2','wordcloud','tidyr','scales','rvest','magrittr','RCurl','XML','slam')
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)



Loading library
library(dplyr)
library(magrittr)
library(ggplot2)
library(wordcloud)
library(scales)
library(readr)
library(jiebaR)



Loading data (mobile01)
P <- read_csv("/Volumes/GoogleDrive/Team\ Drives/THESIS/案例構思/巨力搬家/Data\ Collection/爬蟲資料/mobile01/MHmb01.csv")
Parsed with column specification:
cols(
  artTitle = col_character(),
  artDate = col_character(),
  artTime = col_time(format = ""),
  artContent = col_character(),
  artReply = col_double()
)
P$text = P$artContent
Loading JiebaR package and setup stop words dictionary
library(jiebaR)
userwd = c("搬家公司","崔媽媽","康福","巨力","大吉旺","搬家","乙久利","康福搬家","巨力搬家","崔媽媽基金會","不加價","不亂加價","崔媽媽網站","舊傢俱")
cc = worker()
new_user_word(cc,userwd,tags=rep('n',length(userwd)))
[1] TRUE
stopwd = c(readLines("/Volumes/GoogleDrive/Team\ Drives/THESIS/案例構思/巨力搬家/Data\ Collection/爬蟲資料/dict/stop_words.txt",encoding="UTF-8"),
           "真的","com","XD","imgur","jpg","www","http","i",
           "html","bbs","請問","https","po","ptt","cc","Contacts",
           "文章","謝謝","之前","網址","想說","知道","問題",
           "一下","現在","後","再","人","喔","分享","有點","最近",
           "推薦","好像","應該","太","放","已經","看看",
           "看到","  一直","發現","推","這款","耶","今天","之後",
           "超","一點","小","原","有沒有","建議","一個","找",
           "戴","買","好","比較","覺得","說","想","真的","可能",
           "就是","因為","所以","如果","也是","一個","真的","後來",
           "時","完","幫","先","搬","請","一車","參考","一次","一台",
           "一些","一家","一趟","兩次","一定","這是","這家","至少",
           "寫","所有","搬過","本來","是否","前","噸","一直","約","元",
           "月","台北","台南","這次","中","台","算","吋","次","公",
           "最","家","高","當時","免","問","囉","無","找過","記得",
           "辦法","順利","部分","那種","感謝","幾次","送","整個",
           "新竹","有人","只能","只","做","不知","OK","台中","我家",
           "不到","還要","開","走","點","府","估","真是","這種",
           "不用","直接","還會","公司","錢","車","原本","載","舊",
           "當初","當天","最後","下","已","一人","一間","事情","地方",
           "台南","搬運","搬到","需要","無法","改","以上","兩個","X",
           "最好","要求","一起","老闆","幾個","放在","給我","去年",
           "感覺","事","卻","找到","以後","希望","重點","給你","還好",
           "遇到","通常","這間","上次","家裡","回頭","剩下","桃園",
           "縣市","高雄","完全","阿姨","選擇","像是","不錯","方面","裡面",
           "第五次","主要","住","歲","花","B","算是","收","就要","兩三個",
           "能夠","再來","相關","不想","男朋友","寄","男","感到","認為","崁",
           "年","一天","用到","過去","想要","今年","很大","這裡","繼續","箱",
           "之外","求","整體而言","進行","原先","一個月","南","左右","回去",
           "我要","板橋","説","第一次","家樂福","挑","一塊","最大","搬出去",
           "上面","透過","巨力搬家","巨力","原因","來說","打開","有太多","過來",
           "妹妹","智慧","box","輸入","傳統","中繼站","信義","子","不收",
           "有時候","是從","小東西","不錯","謝謝")
於 '/Volumes/GoogleDrive/Team Drives/THESIS/案例構思/巨力搬家/Data Collection/爬蟲資料/dict/stop_words.txt' 找到不完整的最後一列

Descriptive Statistics



Select artDate
P$artDate= P$artDate %>% as.Date("%Y/%m/%d")
data = P %>% dplyr::select(artDate)



Change format
data$artDate= data$artDate %>% as.Date("%Y/%m/%d")



Grouping date
data <- data %>% 
  group_by(artDate) %>% 
  summarise(count = n())



Line graph of articles
plot_date <- data %>% ggplot(aes(x = artDate, y = count)) +
  geom_line(color = "#00AFBB", size = 1) + 
  scale_x_date(labels = date_format("%Y")) +
  ggtitle("搬家-討論文章數(Mobile01)") + 
  xlab("Year") + 
  ylab("Count") + 
  theme(text = element_text(family = "Heiti TC Light")) 

plot_date



Barplot (num of words)
library(slam); library(tm); library(tmcn); library(rJava); library(SnowballC); library(jiebaR)

ii = jj = vv =NULL
for(i in 1:length(P$text)) {
  x = segment(P$text[i], cc)
  x = x[! grepl("[0-9]+",x)]
  x = table(x[! x %in% stopwd])
  ii = c(ii, rep(i,length(x)))
  jj = c(jj, names(x))
  vv = c(vv, as.vector(x))
}
jj = as.factor(jj)

l = levels(jj)
dtm = simple_triplet_matrix(ii,as.integer(jj),vv,
             dimnames=list(as.character(1:length(P$text)),l))
dim(dtm)
[1]  668 5128
save(dtm, file="MHmb01.rdata")
dtm = dtm[, order(col_sums(dtm), decreasing=T)]
col_sums(dtm)[1:40] %>% barplot(las=2, family = "Heiti TC Light")



Hierarchical Clusters (binary distance)
library(MASS)
library(wordcloud)
colors = c('gold','purple','cyan','red','orange3','gray',
           'pink','green','darkgreen','blue','brown','magenta','deepskyblue3')

n = 200; a = 5
bd = dist(t(dtm[,a:n]),method="binary")
# bd = dist(t(dtm[,a:n]))
mds =  isoMDS(bd + 10^(-6))
initial  value 59.142909 
iter   5 value 40.719314
iter  10 value 38.621203
iter  15 value 37.973174
iter  20 value 37.555401
final  value 37.351868 
converged
hc = hclust(bd,method="ward.D2")
plot(hc, family = "Heiti TC Light") 


k=12
plot(hc,cex=0.7,main="Hierarchical Clusters (Binary Distance)",
     sub="",ylab="",xlab="Jaccard (Binary) Distance",
     cex.axis=0.6,cex.lab=0.8,cex.main=1, family = "Heiti TC Light")
rect.hclust(hc, k=k, border="pink")



Word Cloud
gp = cutree(hc, k=k); table(gp)
gp
 1  2  3  4  5  6  7  8  9 10 11 12 
64 21 23  7 10 17 10 13 12  7  6  6 
wc = col_sums(dtm[,a:n])
p0 = par(mar=c(1,1,1,1))
textplot(mds$points[,1],mds$points[,2],colnames(dtm)[a:n],
         show=F, col=colors[gp],cex=1.5*sqrt(wc/mean(wc)),
         font=2,axes=F, family = "Microsoft JhengHei"); par(p0)



### Sentiment Analysis

Loading Chinese Texting needed packages
# install.packages('chinese.misc')
library(chinese.misc)
library(tm)
library(jiebaR)
library(Matrix)
library(readr)
library(tidytext)
library(tidyr)



Reload essential dataset
P = read.csv("MHmb01.csv")
P$artContent = as.character(P$artContent)



Loading customize dict in Jieba
jieba_tokenizer <- worker(user="dict/MH_words.dict")



##### Segmentation

# Setup segment function
MH_tokenizer <- function(t) {
  lapply(t, function(x) {
    tokens <- segment(x, jieba_tokenizer)
    return(tokens)
  })
}

tokens = P %>% 
  unnest_tokens(word, artContent, token = MH_tokenizer)



Count for the amount of words in corpus

tokens = tokens %>%
  dplyr::select(artDate, word) %>%
  group_by(artDate, word) %>%
  mutate(count = n()) %>%
  ungroup() %>%
  distinct() # 己經統計過數量;去除重複資料

tokens



LIWC dict (positive, negative)
p <- read_file("/Volumes/GoogleDrive/Team\ Drives/THESIS/案例構思/巨力搬家/Data\ Collection/爬蟲資料/dict/MH_positive.txt")
n <- read_file("/Volumes/GoogleDrive/Team\ Drives/THESIS/案例構思/巨力搬家/Data\ Collection/爬蟲資料/dict/MH_negative.txt")
positive <- strsplit(p, "[,]")[[1]]
negative <- strsplit(n, "[,]")[[1]]
positive <- data.frame(word = positive, sentiments = "positive")
negative <- data.frame(word = negative, sentiemtns = "negative")
colnames(negative) = c("word","sentiment")
colnames(positive) = c("word","sentiment")
LIWC_ch <- rbind(positive, negative) %>% distinct()

LIWC_ch



Join corpus with LIWC (ot make sure the word is belongs to positive or negative)
senti_tokens = tokens %>% inner_join(LIWC_ch) 
Joining, by = "word"
Column `word` joining character vector and factor, coercing into character vector
head(senti_tokens) 



Find out all date in time period
all_dates <- 
  expand.grid(seq(as.Date(min(data$artDate)), as.Date(max(data$artDate)), by="day"), c("positive", "negative"))
head(all_dates)



Line chart of sentiment (positive, negative)

senti_tokens$artDate = as.Date(senti_tokens$artDate)

plot_table <- senti_tokens %>%
  inner_join(LIWC_ch) %>% 
  group_by(artDate,sentiment) %>%
  summarise(count = sum(count))
Joining, by = c("word", "sentiment")
Column `word` joining character vector and factor, coercing into character vector
plot_table %>%
  ggplot() +
  geom_line(aes(x = artDate, y = count, colour = sentiment)) +
  xlab("Year") + ylab("Count")



Histogram of sentiment (positive, negative)
senti_by_date_LIWC <- senti_tokens %>% 
  inner_join(LIWC_ch) %>%
  group_by(artDate, sentiment) %>%
  summarise(n=sum(count)) %>%
  spread(sentiment, n, fill = 0) %>%
  mutate(sentiment = positive - negative) %>%
  mutate(method='LIWC') 
Joining, by = c("word", "sentiment")
Column `word` joining character vector and factor, coercing into character vector
senti_by_date_LIWC %>%
  ggplot(aes(x = artDate,y=sentiment,fill = method)) +
  geom_col(show.legend = FALSE) +
  scale_x_date(labels = date_format("20%y")) +
  facet_wrap(~method, ncol = 1, scales = "fixed") +
  geom_text(aes(label = sentiment))



Common sentiment words in LIWC dict (positive, negative)
tokens %>% 
  inner_join(LIWC_ch) %>%
  group_by(sentiment) %>%
  top_n(20, 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 = 8)) +
  coord_flip() + 
  theme(text = element_text(family = "Heiti TC Light")) 
Joining, by = "word"
Column `word` joining character vector and factor, coercing into character vector



Delete unrelated words (if needed)
tokens <- tokens %>%
  filter(word!='推') %>%
  filter(word!='怕') %>%
  filter(word!='謝謝') %>%
  filter(word!='感謝') %>%
  filter(word!='不錯') %>%
  filter(word!='才能') %>%
  filter(word!='值得')



LS0tCnRpdGxlOiAi5Y+w54Gj5pCs5a6255Si5qWt5paH5a2X5YiG5p6Q77yITW9iaWxlMDHvvIkvIFRleHQgTWluaW5nIG9mIE1vdmluZyBJbmR1c3RyeSBpbiBUYWl3YW4iCmF1dGhvcjogIkthcmVuIFlhbmcg5qWK5Yex5YCrIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgo8YnI+Cjxicj4KCiMjIyMjIEVuY29kaW5nIHRvIFVURi04CmBgYHtyfQpTeXMuc2V0bG9jYWxlKGNhdGVnb3J5ID0gIkxDX0FMTCIsIGxvY2FsZSA9ICJ6aF9UVy5VVEYtOCIpCmBgYAoKPGJyPgo8YnI+CgojIyMjIyBJbnN0YWxsIGVzc2VudGlhbCBwYWNrYWdlCmBgYHtyfQpwYWNrYWdlcyA9IGMoImRwbHlyIiwgInRpZHl0ZXh0IiwgInN0cmluZ3IiLCAid29yZGNsb3VkMiIsICJnZ3Bsb3QyIiwncmVhZHInLCdkYXRhLnRhYmxlJywncmVzaGFwZTInLCd3b3JkY2xvdWQnLCd0aWR5cicsJ3NjYWxlcycsJ3J2ZXN0JywnbWFncml0dHInLCdSQ3VybCcsJ1hNTCcsJ3NsYW0nKQpleGlzdGluZyA9IGFzLmNoYXJhY3RlcihpbnN0YWxsZWQucGFja2FnZXMoKVssMV0pCmZvcihwa2cgaW4gcGFja2FnZXNbIShwYWNrYWdlcyAlaW4lIGV4aXN0aW5nKV0pIGluc3RhbGwucGFja2FnZXMocGtnKQpgYGAKCjxicj4KPGJyPgoKIyMjIyMgTG9hZGluZyBsaWJyYXJ5CmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkod29yZGNsb3VkKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShyZWFkcikKbGlicmFyeShqaWViYVIpCmBgYAoKPGJyPgo8YnI+CgojIyMjIyBMb2FkaW5nIGRhdGEgKG1vYmlsZTAxKQpgYGB7cn0KUCA8LSByZWFkX2NzdigiL1ZvbHVtZXMvR29vZ2xlRHJpdmUvVGVhbVwgRHJpdmVzL1RIRVNJUy/moYjkvovmp4vmgJ0v5beo5Yqb5pCs5a62L0RhdGFcIENvbGxlY3Rpb24v54is6J+y6LOH5paZL21vYmlsZTAxL01IbWIwMS5jc3YiKQpQJHRleHQgPSBQJGFydENvbnRlbnQKYGBgCgoKCiMjIyMjIExvYWRpbmcgSmllYmFSIHBhY2thZ2UgYW5kIHNldHVwIHN0b3Agd29yZHMgZGljdGlvbmFyeQpgYGB7cn0KbGlicmFyeShqaWViYVIpCnVzZXJ3ZCA9IGMoIuaQrOWutuWFrOWPuCIsIuW0lOWqveWqvSIsIuW6t+emjyIsIuW3qOWKmyIsIuWkp+WQieaXuiIsIuaQrOWutiIsIuS5meS5heWIqSIsIuW6t+emj+aQrOWutiIsIuW3qOWKm+aQrOWutiIsIuW0lOWqveWqveWfuumHkeacgyIsIuS4jeWKoOWDuSIsIuS4jeS6guWKoOWDuSIsIuW0lOWqveWqvee2suermSIsIuiIiuWCouS/sSIpCmNjID0gd29ya2VyKCkKbmV3X3VzZXJfd29yZChjYyx1c2Vyd2QsdGFncz1yZXAoJ24nLGxlbmd0aCh1c2Vyd2QpKSkKCnN0b3B3ZCA9IGMocmVhZExpbmVzKCIvVm9sdW1lcy9Hb29nbGVEcml2ZS9UZWFtXCBEcml2ZXMvVEhFU0lTL+ahiOS+i+ani+aAnS/lt6jlipvmkKzlrrYvRGF0YVwgQ29sbGVjdGlvbi/niKzon7Los4fmlpkvZGljdC9zdG9wX3dvcmRzLnR4dCIsZW5jb2Rpbmc9IlVURi04IiksCiAgICAgICAgICAgIuecn+eahCIsImNvbSIsIlhEIiwiaW1ndXIiLCJqcGciLCJ3d3ciLCJodHRwIiwiaSIsCiAgICAgICAgICAgImh0bWwiLCJiYnMiLCLoq4vllY8iLCJodHRwcyIsInBvIiwicHR0IiwiY2MiLCJDb250YWN0cyIsCiAgICAgICAgICAgIuaWh+eroCIsIuisneisnSIsIuS5i+WJjSIsIue2suWdgCIsIuaDs+iqqiIsIuefpemBkyIsIuWVj+mhjCIsCiAgICAgICAgICAgIuS4gOS4iyIsIuePvuWcqCIsIuW+jCIsIuWGjSIsIuS6uiIsIuWWlCIsIuWIhuS6qyIsIuaciem7niIsIuacgOi/kSIsCiAgICAgICAgICAgIuaOqOiWpiIsIuWlveWDjyIsIuaHieipsiIsIuWkqiIsIuaUviIsIuW3sue2kyIsIueci+eciyIsCiAgICAgICAgICAgIueci+WIsCIsIiAg5LiA55u0Iiwi55m854++Iiwi5o6oIiwi6YCZ5qy+Iiwi6IC2Iiwi5LuK5aSpIiwi5LmL5b6MIiwKICAgICAgICAgICAi6LaFIiwi5LiA6bueIiwi5bCPIiwi5Y6fIiwi5pyJ5rKS5pyJIiwi5bu66K2wIiwi5LiA5YCLIiwi5om+IiwKICAgICAgICAgICAi5oi0Iiwi6LK3Iiwi5aW9Iiwi5q+U6LyDIiwi6Ka65b6XIiwi6KqqIiwi5oOzIiwi55yf55qEIiwi5Y+v6IO9IiwKICAgICAgICAgICAi5bCx5pivIiwi5Zug54K6Iiwi5omA5LulIiwi5aaC5p6cIiwi5Lmf5pivIiwi5LiA5YCLIiwi55yf55qEIiwi5b6M5L6GIiwKICAgICAgICAgICAi5pmCIiwi5a6MIiwi5bmrIiwi5YWIIiwi5pCsIiwi6KuLIiwi5LiA6LuKIiwi5Y+D6ICDIiwi5LiA5qyhIiwi5LiA5Y+wIiwKICAgICAgICAgICAi5LiA5LqbIiwi5LiA5a62Iiwi5LiA6LafIiwi5YWp5qyhIiwi5LiA5a6aIiwi6YCZ5pivIiwi6YCZ5a62Iiwi6Iez5bCRIiwKICAgICAgICAgICAi5a+rIiwi5omA5pyJIiwi5pCs6YGOIiwi5pys5L6GIiwi5piv5ZCmIiwi5YmNIiwi5Zm4Iiwi5LiA55u0Iiwi57SEIiwi5YWDIiwKICAgICAgICAgICAi5pyIIiwi5Y+w5YyXIiwi5Y+w5Y2XIiwi6YCZ5qyhIiwi5LitIiwi5Y+wIiwi566XIiwi5ZCLIiwi5qyhIiwi5YWsIiwKICAgICAgICAgICAi5pyAIiwi5a62Iiwi6auYIiwi55W25pmCIiwi5YWNIiwi5ZWPIiwi5ZuJIiwi54ShIiwi5om+6YGOIiwi6KiY5b6XIiwKICAgICAgICAgICAi6L6m5rOVIiwi6aCG5YipIiwi6YOo5YiGIiwi6YKj56iuIiwi5oSf6KydIiwi5bm+5qyhIiwi6YCBIiwi5pW05YCLIiwKICAgICAgICAgICAi5paw56u5Iiwi5pyJ5Lq6Iiwi5Y+q6IO9Iiwi5Y+qIiwi5YGaIiwi5LiN55+lIiwiT0siLCLlj7DkuK0iLCLmiJHlrrYiLAogICAgICAgICAgICLkuI3liLAiLCLpgoTopoEiLCLplosiLCLotbAiLCLpu54iLCLlupwiLCLkvLAiLCLnnJ/mmK8iLCLpgJnnqK4iLAogICAgICAgICAgICLkuI3nlKgiLCLnm7TmjqUiLCLpgoTmnIMiLCLlhazlj7giLCLpjKIiLCLou4oiLCLljp/mnKwiLCLovIkiLCLoiIoiLAogICAgICAgICAgICLnlbbliJ0iLCLnlbblpKkiLCLmnIDlvowiLCLkuIsiLCLlt7IiLCLkuIDkuroiLCLkuIDplpMiLCLkuovmg4UiLCLlnLDmlrkiLAogICAgICAgICAgICLlj7DljZciLCLmkKzpgYsiLCLmkKzliLAiLCLpnIDopoEiLCLnhKHms5UiLCLmlLkiLCLku6XkuIoiLCLlhanlgIsiLCLvvLgiLAogICAgICAgICAgICLmnIDlpb0iLCLopoHmsYIiLCLkuIDotbciLCLogIHpl4YiLCLlub7lgIsiLCLmlL7lnKgiLCLntabmiJEiLCLljrvlubQiLAogICAgICAgICAgICLmhJ/oproiLCLkuosiLCLljbsiLCLmib7liLAiLCLku6XlvowiLCLluIzmnJsiLCLph43pu54iLCLntabkvaAiLCLpgoTlpb0iLAogICAgICAgICAgICLpgYfliLAiLCLpgJrluLgiLCLpgJnplpMiLCLkuIrmrKEiLCLlrrboo6EiLCLlm57poK0iLCLliankuIsiLCLmoYPlnJIiLAogICAgICAgICAgICLnuKPluIIiLCLpq5jpm4QiLCLlrozlhagiLCLpmL/lp6giLCLpgbjmk4ciLCLlg4/mmK8iLCLkuI3pjK8iLCLmlrnpnaIiLCLoo6HpnaIiLAogICAgICAgICAgICLnrKzkupTmrKEiLCLkuLvopoEiLCLkvY8iLCLmrbIiLCLoirEiLCJCIiwi566X5pivIiwi5pS2Iiwi5bCx6KaBIiwi5YWp5LiJ5YCLIiwKICAgICAgICAgICAi6IO95aSgIiwi5YaN5L6GIiwi55u46ZecIiwi5LiN5oOzIiwi55S35pyL5Y+LIiwi5a+EIiwi55S3Iiwi5oSf5YiwIiwi6KqN54K6Iiwi5bSBIiwKICAgICAgICAgICAi5bm0Iiwi5LiA5aSpIiwi55So5YiwIiwi6YGO5Y67Iiwi5oOz6KaBIiwi5LuK5bm0Iiwi5b6I5aSnIiwi6YCZ6KOhIiwi57m857qMIiwi566xIiwKICAgICAgICAgICAi5LmL5aSWIiwi5rGCIiwi5pW06auU6ICM6KiAIiwi6YCy6KGMIiwi5Y6f5YWIIiwi5LiA5YCL5pyIIiwi5Y2XIiwi5bem5Y+zIiwi5Zue5Y67IiwKICAgICAgICAgICAi5oiR6KaBIiwi5p2/5qmLIiwi6KqsIiwi56ys5LiA5qyhIiwi5a625qiC56aPIiwi5oyRIiwi5LiA5aGKIiwi5pyA5aSnIiwi5pCs5Ye65Y67IiwKICAgICAgICAgICAi5LiK6Z2iIiwi6YCP6YGOIiwi5beo5Yqb5pCs5a62Iiwi5beo5YqbIiwi5Y6f5ZugIiwi5L6G6KqqIiwi5omT6ZaLIiwi5pyJ5aSq5aSaIiwi6YGO5L6GIiwKICAgICAgICAgICAi5aa55aa5Iiwi5pm65oWnIiwiYm94Iiwi6Ly45YWlIiwi5YKz57WxIiwi5Lit57m856uZIiwi5L+h576pIiwi5a2QIiwi5LiN5pS2IiwKICAgICAgICAgICAi5pyJ5pmC5YCZIiwi5piv5b6eIiwi5bCP5p2x6KW/Iiwi5LiN6YyvIiwi6Kyd6KydIikKYGBgCgoKIyMjIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MKCjxicj4KPGJyPgoKIyMjIyMgU2VsZWN0IGFydERhdGUKYGBge3J9ClAkYXJ0RGF0ZT0gUCRhcnREYXRlICU+JSBhcy5EYXRlKCIlWS8lbS8lZCIpCmRhdGEgPSBQICU+JSBkcGx5cjo6c2VsZWN0KGFydERhdGUpCmBgYAoKPGJyPgo8YnI+CgojIyMjIyBDaGFuZ2UgZm9ybWF0CmBgYHtyfQpkYXRhJGFydERhdGU9IGRhdGEkYXJ0RGF0ZSAlPiUgYXMuRGF0ZSgiJVkvJW0vJWQiKQpgYGAKCjxicj4KPGJyPgoKIyMjIyMgR3JvdXBpbmcgZGF0ZQpgYGB7cn0KZGF0YSA8LSBkYXRhICU+JSAKICBncm91cF9ieShhcnREYXRlKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQpgYGAKCjxicj4KPGJyPgoKIyMjIyMgTGluZSBncmFwaCBvZiBhcnRpY2xlcwpgYGB7cn0KcGxvdF9kYXRlIDwtIGRhdGEgJT4lIGdncGxvdChhZXMoeCA9IGFydERhdGUsIHkgPSBjb3VudCkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAiIzAwQUZCQiIsIHNpemUgPSAxKSArIAogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiJVkiKSkgKwogIGdndGl0bGUoIuaQrOWutu+8jeiojuirluaWh+eroOaVuO+8iE1vYmlsZTAx77yJIikgKyAKICB4bGFiKCJZZWFyIikgKyAKICB5bGFiKCJDb3VudCIpICsgCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkgCgpwbG90X2RhdGUKYGBgCgo8YnI+Cjxicj4KCiMjIyMjIEJhcnBsb3QgKG51bSBvZiB3b3JkcykKYGBge3J9CmxpYnJhcnkoc2xhbSk7IGxpYnJhcnkodG0pOyBsaWJyYXJ5KHRtY24pOyBsaWJyYXJ5KHJKYXZhKTsgbGlicmFyeShTbm93YmFsbEMpOyBsaWJyYXJ5KGppZWJhUikKCmlpID0gamogPSB2diA9TlVMTApmb3IoaSBpbiAxOmxlbmd0aChQJHRleHQpKSB7CiAgeCA9IHNlZ21lbnQoUCR0ZXh0W2ldLCBjYykKICB4ID0geFshIGdyZXBsKCJbMC05XSsiLHgpXQogIHggPSB0YWJsZSh4WyEgeCAlaW4lIHN0b3B3ZF0pCiAgaWkgPSBjKGlpLCByZXAoaSxsZW5ndGgoeCkpKQogIGpqID0gYyhqaiwgbmFtZXMoeCkpCiAgdnYgPSBjKHZ2LCBhcy52ZWN0b3IoeCkpCn0KamogPSBhcy5mYWN0b3IoamopCgpsID0gbGV2ZWxzKGpqKQpkdG0gPSBzaW1wbGVfdHJpcGxldF9tYXRyaXgoaWksYXMuaW50ZWdlcihqaiksdnYsCiAgICAgICAgICAgICBkaW1uYW1lcz1saXN0KGFzLmNoYXJhY3RlcigxOmxlbmd0aChQJHRleHQpKSxsKSkKZGltKGR0bSkKc2F2ZShkdG0sIGZpbGU9Ik1IbWIwMS5yZGF0YSIpCmR0bSA9IGR0bVssIG9yZGVyKGNvbF9zdW1zKGR0bSksIGRlY3JlYXNpbmc9VCldCmNvbF9zdW1zKGR0bSlbMTo0MF0gJT4lIGJhcnBsb3QobGFzPTIsIGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpCmBgYAoKPGJyPgo8YnI+CgojIyMjIyBIaWVyYXJjaGljYWwgQ2x1c3RlcnMgKGJpbmFyeSBkaXN0YW5jZSkKYGBge3J9CmxpYnJhcnkoTUFTUykKbGlicmFyeSh3b3JkY2xvdWQpCmNvbG9ycyA9IGMoJ2dvbGQnLCdwdXJwbGUnLCdjeWFuJywncmVkJywnb3JhbmdlMycsJ2dyYXknLAogICAgICAgICAgICdwaW5rJywnZ3JlZW4nLCdkYXJrZ3JlZW4nLCdibHVlJywnYnJvd24nLCdtYWdlbnRhJywnZGVlcHNreWJsdWUzJykKCm4gPSAyMDA7IGEgPSA1CmJkID0gZGlzdCh0KGR0bVssYTpuXSksbWV0aG9kPSJiaW5hcnkiKQojIGJkID0gZGlzdCh0KGR0bVssYTpuXSkpCm1kcyA9ICBpc29NRFMoYmQgKyAxMF4oLTYpKQpoYyA9IGhjbHVzdChiZCxtZXRob2Q9IndhcmQuRDIiKQpwbG90KGhjLCBmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSAKCms9MTIKcGxvdChoYyxjZXg9MC43LG1haW49IkhpZXJhcmNoaWNhbCBDbHVzdGVycyAoQmluYXJ5IERpc3RhbmNlKSIsCiAgICAgc3ViPSIiLHlsYWI9IiIseGxhYj0iSmFjY2FyZCAoQmluYXJ5KSBEaXN0YW5jZSIsCiAgICAgY2V4LmF4aXM9MC42LGNleC5sYWI9MC44LGNleC5tYWluPTEsIGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpCnJlY3QuaGNsdXN0KGhjLCBrPWssIGJvcmRlcj0icGluayIpCmBgYAoKPGJyPgo8YnI+CgojIyMjIyBXb3JkIENsb3VkCmBgYHtyfQpncCA9IGN1dHJlZShoYywgaz1rKTsgdGFibGUoZ3ApCndjID0gY29sX3N1bXMoZHRtWyxhOm5dKQpwMCA9IHBhcihtYXI9YygxLDEsMSwxKSkKdGV4dHBsb3QobWRzJHBvaW50c1ssMV0sbWRzJHBvaW50c1ssMl0sY29sbmFtZXMoZHRtKVthOm5dLAogICAgICAgICBzaG93PUYsIGNvbD1jb2xvcnNbZ3BdLGNleD0xLjUqc3FydCh3Yy9tZWFuKHdjKSksCiAgICAgICAgIGZvbnQ9MixheGVzPUYsIGZhbWlseSA9ICJNaWNyb3NvZnQgSmhlbmdIZWkiKTsgcGFyKHAwKQpgYGAKCjxicj4KPGJyPgojIyMgU2VudGltZW50IEFuYWx5c2lzCgojIyMjIyBMb2FkaW5nIENoaW5lc2UgVGV4dGluZyBuZWVkZWQgcGFja2FnZXMKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygnY2hpbmVzZS5taXNjJykKbGlicmFyeShjaGluZXNlLm1pc2MpCmxpYnJhcnkodG0pCmxpYnJhcnkoamllYmFSKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShyZWFkcikKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh0aWR5cikKYGBgCgo8YnI+Cjxicj4KCiMjIyMjIFJlbG9hZCBlc3NlbnRpYWwgZGF0YXNldCAKYGBge3J9ClAgPSByZWFkLmNzdigiTUhtYjAxLmNzdiIpClAkYXJ0Q29udGVudCA9IGFzLmNoYXJhY3RlcihQJGFydENvbnRlbnQpCmBgYAoKPGJyPgo8YnI+CgojIyMjIyBMb2FkaW5nIGN1c3RvbWl6ZSBkaWN0IGluIEppZWJhCmBgYHtyfQpqaWViYV90b2tlbml6ZXIgPC0gd29ya2VyKHVzZXI9ImRpY3QvTUhfd29yZHMuZGljdCIpCmBgYAoKPGJyPgo8YnI+CiMjIyMjIFNlZ21lbnRhdGlvbgpgYGB7cn0KIyBTZXR1cCBzZWdtZW50IGZ1bmN0aW9uCk1IX3Rva2VuaXplciA8LSBmdW5jdGlvbih0KSB7CiAgbGFwcGx5KHQsIGZ1bmN0aW9uKHgpIHsKICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikKICAgIHJldHVybih0b2tlbnMpCiAgfSkKfQoKdG9rZW5zID0gUCAlPiUgCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBhcnRDb250ZW50LCB0b2tlbiA9IE1IX3Rva2VuaXplcikKYGBgCgo8YnI+Cjxicj4KCiMgQ291bnQgZm9yIHRoZSBhbW91bnQgb2Ygd29yZHMgaW4gY29ycHVzCmBgYHtyfQp0b2tlbnMgPSB0b2tlbnMgJT4lCiAgZHBseXI6OnNlbGVjdChhcnREYXRlLCB3b3JkKSAlPiUKICBncm91cF9ieShhcnREYXRlLCB3b3JkKSAlPiUKICBtdXRhdGUoY291bnQgPSBuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBkaXN0aW5jdCgpICMg5bex57aT57Wx6KiI6YGO5pW46YeP77yb5Y676Zmk6YeN6KSH6LOH5paZCgp0b2tlbnMKYGBgCgo8YnI+Cjxicj4KCiMjIyMjIExJV0MgZGljdCAocG9zaXRpdmUsIG5lZ2F0aXZlKQpgYGB7cn0KcCA8LSByZWFkX2ZpbGUoIi9Wb2x1bWVzL0dvb2dsZURyaXZlL1RlYW1cIERyaXZlcy9USEVTSVMv5qGI5L6L5qeL5oCdL+W3qOWKm+aQrOWuti9EYXRhXCBDb2xsZWN0aW9uL+eIrOifsuizh+aWmS9kaWN0L01IX3Bvc2l0aXZlLnR4dCIpCm4gPC0gcmVhZF9maWxlKCIvVm9sdW1lcy9Hb29nbGVEcml2ZS9UZWFtXCBEcml2ZXMvVEhFU0lTL+ahiOS+i+ani+aAnS/lt6jlipvmkKzlrrYvRGF0YVwgQ29sbGVjdGlvbi/niKzon7Los4fmlpkvZGljdC9NSF9uZWdhdGl2ZS50eHQiKQpwb3NpdGl2ZSA8LSBzdHJzcGxpdChwLCAiWyxdIilbWzFdXQpuZWdhdGl2ZSA8LSBzdHJzcGxpdChuLCAiWyxdIilbWzFdXQpwb3NpdGl2ZSA8LSBkYXRhLmZyYW1lKHdvcmQgPSBwb3NpdGl2ZSwgc2VudGltZW50cyA9ICJwb3NpdGl2ZSIpCm5lZ2F0aXZlIDwtIGRhdGEuZnJhbWUod29yZCA9IG5lZ2F0aXZlLCBzZW50aWVtdG5zID0gIm5lZ2F0aXZlIikKY29sbmFtZXMobmVnYXRpdmUpID0gYygid29yZCIsInNlbnRpbWVudCIpCmNvbG5hbWVzKHBvc2l0aXZlKSA9IGMoIndvcmQiLCJzZW50aW1lbnQiKQpMSVdDX2NoIDwtIHJiaW5kKHBvc2l0aXZlLCBuZWdhdGl2ZSkgJT4lIGRpc3RpbmN0KCkKCkxJV0NfY2gKYGBgCgo8YnI+Cjxicj4KCiMjIyMjIEpvaW4gY29ycHVzIHdpdGggTElXQyAob3QgbWFrZSBzdXJlIHRoZSB3b3JkIGlzIGJlbG9uZ3MgdG8gcG9zaXRpdmUgb3IgbmVnYXRpdmUpCmBgYHtyfQpzZW50aV90b2tlbnMgPSB0b2tlbnMgJT4lIGlubmVyX2pvaW4oTElXQ19jaCkgCmhlYWQoc2VudGlfdG9rZW5zKSAKYGBgCgo8YnI+Cjxicj4KCiMjIyMjIEZpbmQgb3V0IGFsbCBkYXRlIGluIHRpbWUgcGVyaW9kCmBgYHtyfQphbGxfZGF0ZXMgPC0gCiAgZXhwYW5kLmdyaWQoc2VxKGFzLkRhdGUobWluKGRhdGEkYXJ0RGF0ZSkpLCBhcy5EYXRlKG1heChkYXRhJGFydERhdGUpKSwgYnk9ImRheSIpLCBjKCJwb3NpdGl2ZSIsICJuZWdhdGl2ZSIpKQpoZWFkKGFsbF9kYXRlcykKYGBgCgo8YnI+Cjxicj4KCiMgTGluZSBjaGFydCBvZiBzZW50aW1lbnQgKHBvc2l0aXZlLCBuZWdhdGl2ZSkKYGBge3J9CnNlbnRpX3Rva2VucyRhcnREYXRlID0gYXMuRGF0ZShzZW50aV90b2tlbnMkYXJ0RGF0ZSkKCnBsb3RfdGFibGUgPC0gc2VudGlfdG9rZW5zICU+JQogIGlubmVyX2pvaW4oTElXQ19jaCkgJT4lIAogIGdyb3VwX2J5KGFydERhdGUsc2VudGltZW50KSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBzdW0oY291bnQpKQoKCnBsb3RfdGFibGUgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoeCA9IGFydERhdGUsIHkgPSBjb3VudCwgY29sb3VyID0gc2VudGltZW50KSkgKwogIHhsYWIoIlllYXIiKSArIHlsYWIoIkNvdW50IikKYGBgCgo8YnI+Cjxicj4KCiMjIyMjIEhpc3RvZ3JhbSBvZiBzZW50aW1lbnQgKHBvc2l0aXZlLCBuZWdhdGl2ZSkKYGBge3J9CnNlbnRpX2J5X2RhdGVfTElXQyA8LSBzZW50aV90b2tlbnMgJT4lIAogIGlubmVyX2pvaW4oTElXQ19jaCkgJT4lCiAgZ3JvdXBfYnkoYXJ0RGF0ZSwgc2VudGltZW50KSAlPiUKICBzdW1tYXJpc2Uobj1zdW0oY291bnQpKSAlPiUKICBzcHJlYWQoc2VudGltZW50LCBuLCBmaWxsID0gMCkgJT4lCiAgbXV0YXRlKHNlbnRpbWVudCA9IHBvc2l0aXZlIC0gbmVnYXRpdmUpICU+JQogIG11dGF0ZShtZXRob2Q9J0xJV0MnKSAKCnNlbnRpX2J5X2RhdGVfTElXQyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcnREYXRlLHk9c2VudGltZW50LGZpbGwgPSBtZXRob2QpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX3hfZGF0ZShsYWJlbHMgPSBkYXRlX2Zvcm1hdCgiMjAleSIpKSArCiAgZmFjZXRfd3JhcCh+bWV0aG9kLCBuY29sID0gMSwgc2NhbGVzID0gImZpeGVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBzZW50aW1lbnQpKQpgYGAKCjxicj4KPGJyPgoKIyMjIyMgQ29tbW9uIHNlbnRpbWVudCB3b3JkcyBpbiBMSVdDIGRpY3QgKHBvc2l0aXZlLCBuZWdhdGl2ZSkKYGBge3J9CnRva2VucyAlPiUgCiAgaW5uZXJfam9pbihMSVdDX2NoKSAlPiUKICBncm91cF9ieShzZW50aW1lbnQpICU+JQogIHRvcF9uKDIwLCB3dCA9IGNvdW50KSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBjb3VudCkpICU+JQogIGdncGxvdChhZXMod29yZCwgY291bnQsIGZpbGwgPSBzZW50aW1lbnQpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofnNlbnRpbWVudCwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHkgPSAiQ29udHJpYnV0aW9uIHRvIHNlbnRpbWVudCIsCiAgICAgICB4ID0gTlVMTCkgKwogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgKwogIGNvb3JkX2ZsaXAoKSArIAogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikpIApgYGAKCjxicj4KPGJyPgoKIyMjIyMgRGVsZXRlIHVucmVsYXRlZCB3b3JkcyAoaWYgbmVlZGVkKQpgYGB7cn0KdG9rZW5zIDwtIHRva2VucyAlPiUKICBmaWx0ZXIod29yZCE9J+aOqCcpICU+JQogIGZpbHRlcih3b3JkIT0n5oCVJykgJT4lCiAgZmlsdGVyKHdvcmQhPSforJ3orJ0nKSAlPiUKICBmaWx0ZXIod29yZCE9J+aEn+isnScpICU+JQogIGZpbHRlcih3b3JkIT0n5LiN6YyvJykgJT4lCiAgZmlsdGVyKHdvcmQhPSfmiY3og70nKSAlPiUKICBmaWx0ZXIod29yZCE9J+WAvOW+lycpCmBgYAoKPGJyPgo8YnI+Cgo8c3R5bGU+Ci5jYXB0aW9uIHsKICBtYXJnaW4tdG9wOiAxMHB4Owp9CnAgY29kZSB7CiAgd2hpdGUtc3BhY2U6IGluaGVyaXQ7Cn0KcHJlIHsKICB3b3JkLWJyZWFrOiBub3JtYWw7CiAgd29yZC13cmFwOiBub3JtYWw7CiAgbGluZS1oZWlnaHQ6IDE7Cn0KcHJlIGNvZGUgewogIHdoaXRlLXNwYWNlOiBpbmhlcml0Owp9CnAsbGkgewogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOwp9CgoucnsKICBsaW5lLWhlaWdodDogMS4yOwp9Cgpib2R5ewogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOwp9CgpoMSxoMixoMyxoNCxoNXsKICBjb2xvcjogIzQ0NDQ0NDsKICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsKfQoKaDN7CiAgY29sb3I6ICM0NjgyODQ7CiAgYmFja2dyb3VuZDogI2ZmZTBiMzsKICBsaW5lLWhlaWdodDogMjsKICBmb250LXdlaWdodDogYm9sZDsKfQoKaDV7CiAgY29sb3I6ICM0NjgyODQ7CiAgYmFja2dyb3VuZDogI2ZmZmZlMDsKICBsaW5lLWhlaWdodDogMjsKICBmb250LXdlaWdodDogYm9sZDsKfQoKZW17CiAgY29sb3I6ICM0NjgyODQ7CiAgfQoKPC9zdHlsZT4=