主題

分析PTT八卦版對台灣停電事件的文字資料和社會網絡資料

一、動機與分析目的

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

1.資料集描述

  • 資料來源:中山大學管理學院文字分析平台收集PTT八卦版文章取得之原始csv檔案。
  • 資料集:PPT八卦版。
  • 資料日期區間:2021.05.13~2021.05.18。
  • 資料的關鍵字:檢索「停電」、「缺電」、「興達」、「電廠」、「興達電廠」五個關鍵字,共搜尋出1113篇文章。

二、前置作業

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

1.安裝需要的packages

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

2.將require及library載入

library(readr)
library(dplyr)
library(jiebaR)
library(tidyr)
library(tidytext)
library(igraph)
library(topicmodels)
library(stringr)
library(ggplot2)
library(reshape2)
library(wordcloud2)

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

posts <- read_csv("0612-1_articleMetaData.csv") # 文章 
reviews <- read_csv("0612-1_articleReviews.csv") # 回覆 
rd <- read_csv("0612-1_artWordPOSFreq.csv")
head(posts)
head(reviews)
head(rd)

4.文章斷句

# # 文章斷句("\n\n"取代成"。")
mask_meta <- posts %>%
               mutate(sentence=gsub("[\n]{2,}", "。", sentence))
# 
# # 以全形或半形 驚歎號、問號、分號 以及 全形句號 爲依據進行斷句
mask_sentences <- strsplit(mask_meta$sentence,"[。!;?!?;]")
# 
# # 將每句句子,與他所屬的文章連結配對起來,整理成一個dataframe
mask_sentences <- data.frame(
                        artUrl = rep(mask_meta$artUrl, sapply(mask_sentences, length)),
                        sentence = unlist(mask_sentences)
                       ) %>%
                       filter(!str_detect(sentence, regex("^(\t|\n| )*$")))
                       # 如果有\t或\n就去掉
 
 mask_sentences$sentence <- as.character(mask_sentences$sentence)
 mask_sentences

5.文章斷詞

# ## 文章斷詞
# # load mask_lexicon(特定要斷開的詞,像是user_dict)
mask_lexicon <- scan(file = "../dict/mask_lexicon.txt", what=character(),sep='\n',
                    encoding='utf-8',fileEncoding='utf-8')
# load stop words
stop_words <- scan(file = "../dict/stop_words.txt", what=character(),sep='\n',
                    encoding='utf-8',fileEncoding='utf-8')
# 
# # 使用默認參數初始化一個斷詞引擎
jieba_tokenizer = worker()
# 
# # 使用口罩字典重新斷詞
new_user_word(jieba_tokenizer, c(mask_lexicon))
# 
#tokenize function
chi_tokenizer <- function(t) {
  lapply(t, function(x) {
     if(nchar(x)>1){
       tokens <- segment(x, jieba_tokenizer)
       tokens <- tokens[!tokens %in% stop_words]
       # 去掉字串長度爲1的詞彙
       tokens <- tokens[nchar(tokens)>1]
       return(tokens)
     }
   })
 }
# 
# 
# # 用剛剛初始化的斷詞器把sentence斷開
 tokens <- mask_sentences %>%
     mutate(sentence = gsub("[[:punct:]]", "",sentence)) %>%
     mutate(sentence = gsub("[0-9a-zA-Z]", "",sentence)) %>%
     unnest_tokens(word, sentence, token=chi_tokenizer) %>%
   count(artUrl, word) %>% # 計算每篇文章出現的字頻
   rename(count=n)
 tokens
# save.image(file = "../data/token_result.rdata")

清理斷詞結果

。根據詞頻,選擇只出現3字以上的字
。整理成url,word,n的格式之後,就可以轉dtm

P.S. groupby by之後原本的字詞結構會不見,把詞頻另存在一個reserved_word裡面

freq = 3
# 依據字頻挑字
reserved_word <- tokens %>% 
  group_by(word) %>% 
  count() %>% 
  filter(n > freq) %>% 
  unlist()

mask_removed <- tokens %>% 
  filter(word %in% reserved_word)

#mask_dtm 裡面 nrow:幾篇文章 ; ncol:幾個字
mask_dtm <- mask_removed %>% cast_dtm(artUrl, word, count) 

三、折線圖

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.初始化斷詞引擎

# 加入自定義的字典
jieba_tokenizer <- worker(user="user_dict.txt", stop_word = "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)
    }
  })
}

rd_tokens_all <- posts %>%
  unnest_tokens(word, sentence, token=chi_tokenizer) %>% 
  select(-artTime)

3.台灣大停電事件在PTT八卦5/13~5/19聲量折線圖


plot_date <- 
  # data
  article_count_by_date %>% 
  # aesthetics
  ggplot(aes(x = artDate, y = count)) +
  # geometrics
  geom_line(color = "#00AFBB", size = 1) + 
  # 2021-01-20 紅線
  geom_vline(xintercept = as.numeric(as.Date("2021-05-13")), col='red', size = 1) + 
  # 2021-02-23 紅線
  geom_vline(xintercept = as.numeric(as.Date("2021-05-17")), col='red', size = 1) + 
  # coordinates

  ggtitle("Dcard 股票看板 討論文章數") + 
  xlab("日期") + 
  ylab("數量") + 
  # theme
  theme(text = element_text(family = "Heiti TC Light")) #加入中文字型設定,避免中文字顯示錯誤。

plot_date

四、文字雲

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

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

五、情緒分析

1.載入情緒分析字典

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

# 負向字典txt檔
N <- read_file("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 <- 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

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"
`summarise()` has grouped output by 'artDate'. You can override using the `.groups` argument.

2.台灣停電事件在PTT八卦版5/13~5/18正負面情緒聲量折線圖

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

NA

3.台灣停電事件在PTT八卦版5/13~5/8正負情緒長條圖

rd_tokens_all %>%
  filter(artDate == as.Date("2021-05-13") |
         artDate == as.Date("2021-05-14") | 
         artDate == as.Date("2021-05-15") | 
         artDate == as.Date("2021-05-16") |
         artDate == as.Date("2021-05-17") |
         artDate == as.Date("2021-05-18") ) %>% 
  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"
`summarise()` has grouped output by 'word'. You can override using the `.groups` argument.

六、LDA 主題分類

1.LDA 主題分析

# LDA分成6個主題
mask_lda <- LDA(mask_dtm, k = 6, control = list(seed = 12345))

2.取出代表字詞(term)


#removed_word = c("不是","每天","出來","覺得") 
removed_word = c("一下","不是") 
# 看各群的常用詞彙
tidy(mask_lda, matrix = "beta") %>% # 取出topic term beta值
  filter(! term %in% removed_word) %>% 
  group_by(topic) %>%
  top_n(10, beta) %>% # beta值前10的字
  ungroup() %>%
  mutate(topic = as.factor(topic),
         term = reorder_within(term, beta, topic)) %>%
  ggplot(aes(term, beta, fill = topic)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ topic, scales = "free") +
  coord_flip() +
  scale_x_reordered()

3.取出代表主題(topic)

# 在tidy function中使用參數"gamma"來取得 theta矩陣
mask_topics <- tidy(mask_lda, matrix="gamma") %>% # document topic gamma
                  group_by(document) %>%
                  top_n(1, wt=gamma)
mask_topics

4.資料內容探索

posts_topic <- merge(x = posts, y = mask_topics, by.x = "artUrl", by.y="document")

# 看一下各主題在說甚麼
set.seed(12345)

posts_topic %>% # 主題一
  filter(topic==1) %>%
  select(artTitle) %>%
  unique() %>%
  sample_n(10)


posts_topic %>% # 主題二
  filter(topic==2) %>%
  select(artTitle) %>%
  unique() %>%
  sample_n(10)

posts_topic %>% # 主題三
  filter(topic==3) %>%
  select(artTitle) %>%
  unique() %>%
  sample_n(10)

posts_topic %>% # 主題四
  filter(topic==4) %>%
  select(artTitle) %>%
  unique() %>%
  sample_n(10)


posts_topic %>% # 主題五
  filter(topic==5) %>%
  select(artTitle) %>%
  unique() %>%
  sample_n(10)

posts_topic %>% # 主題六
  filter(topic==6) %>%
  select(artTitle) %>%
  unique() %>%
  sample_n(10)

5.日期主題分布

posts_topic %>%
  mutate(artDate = as.Date(artDate)) %>% 
  group_by(artDate,topic) %>%
  summarise(sum =sum(topic)) %>%
  ggplot(aes(x= artDate,y=sum,fill=as.factor(topic))) +
  geom_col(position="fill") 
`summarise()` has grouped output by 'artDate'. You can override using the `.groups` argument.

posts_topic %>%
  group_by(artCat,topic) %>%
  summarise(sum = n())  %>%
  ggplot(aes(x= artCat,y=sum,fill=as.factor(topic))) +
  geom_col(position="dodge") 
`summarise()` has grouped output by 'artCat'. You can override using the `.groups` argument.

七、社群網路圖

1.資料合併

# 文章和留言
reviews <- reviews %>%
      select(artUrl, cmtPoster, cmtStatus, cmtContent)
posts_Reviews <- merge(x = posts, y = reviews, by = "artUrl")

# 把文章和topic
posts_Reviews <- merge(x = posts_Reviews, y = mask_topics, by.x = "artUrl", by.y="document")
Error in as.data.frame(y) : 找不到物件 'mask_topics'
link <- posts_Reviews %>% select(cmtPoster, artPoster, artUrl)
Error in select(., cmtPoster, artPoster, artUrl) : 
  找不到物件 'posts_Reviews'

2.基本網路圖

reviewNetwork <- graph_from_data_frame(d=link, directed=T)
Error in as.data.frame(d) : 找不到物件 'link'

3.資料篩選

# 看一下留言數大概都多少(方便後面篩選)
posts %>%
#  filter(commentNum<100) %>%
  ggplot(aes(x=commentNum)) + geom_histogram()

4.依據發文數或回覆數篩選post和review

# # 帳號發文篇數
post_count = posts %>%
  group_by(artPoster) %>%
  summarise(count = n()) %>%
  arrange(desc(count)) 
post_count
# 
# # 帳號回覆總數
review_count = reviews %>%
  group_by(cmtPoster) %>%
  summarise(count = n()) %>%
  arrange(desc(count)) 
review_count

# # 發文者
poster_select <- post_count %>% filter(count >= 2)
posts <- posts %>%  filter(posts$artPoster %in% poster_select$artPoster)
# 
# # 回覆者
reviewer_select <- review_count %>%  filter(count >= 20)
reviews <- reviews %>%  filter(reviews$cmtPoster %in% reviewer_select$cmtPoster)
# 檢視參與人數
length(unique(posts_Reviews$artPoster)) # 發文者數量 1143
[1] 911
length(unique(posts_Reviews$cmtPoster)) # 回覆者數量 14856
[1] 15224
allPoster <- c(posts_Reviews$artPoster, posts_Reviews$cmtPoster) # 總參與人數 15375
length(unique(allPoster))
[1] 15641
userList <- data.frame(user=unique(allPoster)) %>%
              mutate(type=ifelse(user%in%posts$artPoster, "poster", "replyer"))
head(userList,3)

5.以日期篩選社群

link <- posts_Reviews %>%
      group_by(cmtPoster, artUrl) %>% 
      filter(n()>3) %>% 
      filter(commentNum > 200) %>%
      filter(artCat=="Gossiping") %>% 
      filter(artDate == as.Date('2021-05-13')) %>%
      select(cmtPoster, artPoster, artUrl) %>% 
      unique()
link
filtered_user <- userList %>%
          filter(user%in%link$cmtPoster | user%in%link$artPoster) %>%
          arrange(desc(type))
head(filtered_user,3)
set.seed(487)
# v=filtered_user

reviewNetwork = degree(reviewNetwork) > 2
reviewNetwork <- graph_from_data_frame(d=link, v=filtered_user, directed=F)
plot(reviewNetwork, vertex.size=3, edge.arrow.size=0.3,vertex.label=NA)

set.seed(487)
V(reviewNetwork)$color <- ifelse(V(reviewNetwork)$type=="poster", "gold", "lightblue")
plot(reviewNetwork, vertex.size=3, edge.arrow.size=0.3,vertex.label=NA)

filter_degree = 4
set.seed(123)

# 設定 node 的 label/ color
labels <- degree(reviewNetwork) # 算出每個點的degree
V(reviewNetwork)$label <- names(labels)
V(reviewNetwork)$color <- ifelse(V(reviewNetwork)$type=="poster", "gold", "lightblue")

plot(
  reviewNetwork, 
  vertex.size=3, 
  edge.width=3, 
  vertex.label.dist=1,
  vertex.label=ifelse(degree(reviewNetwork) > filter_degree, V(reviewNetwork)$label, NA),vertex.label.font=2)

link <- posts_Reviews %>%
      group_by(cmtPoster, artUrl) %>% 
      filter(n()>3) %>% 
      filter(commentNum > 200) %>%
      filter(artCat=="Gossiping") %>% #HatePolitics / Gossiping
      filter(artDate == as.Date('2021-05-13')) %>%
      filter(topic == 2 | topic == 4) %>% 
      select(cmtPoster, artPoster, artUrl, topic) %>% 
      unique()
link
filtered_user <- userList %>%
          filter(user%in%link$cmtPoster | user%in%link$artPoster) %>%
          arrange(desc(type))
head(filtered_user,3)

6.使用者經常參與的文章種類

filter_degree = 13

# 建立網路關係
reviewNetwork <- graph_from_data_frame(d=link, v=filtered_user, directed=F)

# 依據使用者身份對點進行上色
labels <- degree(reviewNetwork)
V(reviewNetwork)$label <- names(labels)
V(reviewNetwork)$color <- ifelse(V(reviewNetwork)$type=="poster", "gold", "lightblue")

# 依據回覆發生的文章所對應的主題,對他們的關聯線進行上色
E(reviewNetwork)$color <- ifelse(E(reviewNetwork)$topic == "2", "palevioletred", "lightgreen")

# 畫出社群網路圖(degree>7的才畫出來)
set.seed(5432)
plot(reviewNetwork, vertex.size=3, edge.width=3, vertex.label.dist=1,
     vertex.label=ifelse(degree(reviewNetwork) > filter_degree, V(reviewNetwork)$label, NA),vertex.label.font=2)

# 加入標示
legend("bottomright", c("發文者","回文者"), pch=21, 
  col="#777777", pt.bg=c("gold","lightblue"), pt.cex=1, cex=1)
legend("topleft", c("批評調侃","報導相關"), 
       col=c("palevioletred", "lightgreen"), lty=1, cex=1)

7.使用者是否受到歡迎

filter_degree = 7 # 使用者degree

# 過濾留言者對發文者的推噓程度
link <- posts_Reviews %>%
      filter(artCat=="Gossiping") %>% 
      filter(commentNum > 100) %>%
      filter(cmtStatus!="→") %>%
      group_by(cmtPoster, artUrl) %>%
      filter( n() > 2) %>%
      ungroup() %>% 
      select(cmtPoster, artPoster, artUrl, cmtStatus) %>% 
      unique()

# 接下來把網路圖畫出來,跟前面做的事都一樣,因此不再細述

# 篩選link中有出現的使用者
filtered_user <- userList %>%
          filter(user%in%link$cmtPoster | user%in%link$artPoster) %>%
          arrange(desc(type))

# 建立網路關係
reviewNetwork <- graph_from_data_frame(d=link, v=filtered_user, directed=F)

# 依據使用者身份對點進行上色
labels <- degree(reviewNetwork)
V(reviewNetwork)$label <- names(labels)
V(reviewNetwork)$color <- ifelse(V(reviewNetwork)$type=="poster", "gold", "lightblue")


# 依據回覆發生的文章所對應的主題,對他們的關聯線進行上色
E(reviewNetwork)$color <- ifelse(E(reviewNetwork)$cmtStatus == "推", "lightgreen", "palevioletred")

# 畫出社群網路圖
set.seed(5432)
plot(reviewNetwork, vertex.size=2, edge.width=3, vertex.label.dist=1,
     vertex.label=ifelse(degree(reviewNetwork) > filter_degree, V(reviewNetwork)$label, NA),vertex.label.font=2)

# 加入標示
legend("bottomright", c("發文者","回文者"), pch=21,
  col="#777777", pt.bg=c("gold","lightblue"), pt.cex=1, cex=1)
legend("topleft", c("推","噓"), 
       col=c("lightgreen","palevioletred"), lty=1, cex=1)

八、總結

  1. 台灣停電事件的討論重點有哪些? 主要分為哪幾種風向?
    對於2021-05-21 ~ 2021-05-23收集的文章,大概可以分成嘲諷校正回歸、客觀討論校正回歸這兩種,其他還有著重討論確診個案足跡或和疫苗相關的討論等四種。討論重點多在於統計「數字」、「公布日期」等案例的計算方式。

  2. 目前風向最偏哪邊?
    客觀討論計算方式的文章不少,但嘲諷、八卦性質的文章居多。

  3. 討論校正回歸的社群網路如何分布?
    以社群文章數來看,批評嘲諷的網友較多,但從社群網路觀察發現,兩邊的貼文討論聲量都很高。

  4. 校正回歸的意見領袖有誰?網友的推噓狀態如何?
    因為資料選取的時間較短,只要幾篇回覆量高的貼文,就有機會成為社群中心,在八卦版上,以報導討論為主的意見領袖有 centre0130,回覆推噓皆有,調侃批評部分則有 hstf,網友大多正面推文。

LS0tDQp0aXRsZTogIuekvue+pOWqkumrlOWIhuaekCDmnJ/mnKvloLHlkYog5o6i6KiOcHR05YWr5Y2m5p2/5bCN5Y+w54Gj5YGc6Zu75LqL5Lu255qE55yL5rOVIg0KYXV0aG9yOiAi56ysMTnntYQiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIGNzczogc3R5bGUuY3NzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQojIyDkuLvpoYwNCj4g5YiG5p6QUFRU5YWr5Y2m54mI5bCN5Y+w54Gj5YGc6Zu75LqL5Lu255qE5paH5a2X6LOH5paZ5ZKM56S+5pyD57ay57Wh6LOH5paZDQoNCiMg5LiA44CB5YuV5qmf6IiH5YiG5p6Q55uu55qEDQotIOiDjOaZr+iIh+WLleapnw0KICArIOa4heaYjumAo+WBh+ato+aYr+Wkp+Wutua6luWCmemWi+W/g+elreelluaIluaYr+WHuumBiueahOaXpeWtkO+8jOWkp+ecvuS6pOmAmuW3peWFt+aIkOeCuuaPkOS+m+Wkp+WutuW+gOi/lOeahOW3peWFt++8jOWwpOWFtuaYr+WPsOmQtemQtei3r+mBi+i8uOeahOeSsOWztuS6pOmAmue2su+8jOabtOaYr+W+gOS+huilv+WyuOiIh+adseWyuOacgOS+v+WIqeeahOaWueW8j++8jOmAo+WBh+eahOesrOS4gOWkqeaYr+S6pOmAmuacgOe5geW/meeahOS4gOWkqe+8jOWPsOmQteeahOWkqumtr+mWo+iZn+WNu+WboOeCuuaWveW3peWWruS9jeeahOeWj+W/veeZvOeUn+S6huWatOmHjeeahOWHuui7jOaEj+Wklu+8jOmAoOaIkDI0N+i8lemHjeWCt+OAgTQ55Lq65q275Lqh55qE5oKy5YqH77yb6YCZ5aC05oSP5aSW56m256uf5piv5Zau57SU5aSW5YyF5pa95bel5bug5ZWG77yM5oqR5oiW5piv56mN57+S5bey5LmF55qE5Y+w54Gj6ZC16Lev5YWs5Y+455uj552j5LiN5ZGo5omA6YCg5oiQ55qE44CCDQoNCisg56CU56m255uu55qEDQogICAxLiDkuobop6PmsJHnnL7lsI3mlrzlpKrpra/plqPomZ/kuovku7bnmoTmhYvluqbjgII8L2JyPg0KICAgMi4g57ay5rCR6KqN54K65aSq6a2v6Zaj6Jmf55qE6LKs5Lu75q245bGs44CCPC9icj4NCiAgIDMuIOWkqumtr+mWo+iZn+WHuui7jOS6i+S7tuW+jOipsuWBmueahOS6i+OAgjwvYnI+DQoNCiMjIDEu6LOH5paZ6ZuG5o+P6L+wDQorIOizh+aWmeS+hua6kO+8muS4reWxseWkp+WtuOeuoeeQhuWtuOmZouaWh+Wtl+WIhuaekOW5s+WPsOaUtumbhlBUVOWFq+WNpueJiOaWh+eroOWPluW+l+S5i+WOn+Wni2NzduaqlOahiOOAgg0KKyDos4fmlpnpm4bvvJpQUFTlhavljabniYjjgIINCisg6LOH5paZ5pel5pyf5Y2A6ZaT77yaMjAyMS4wNS4xM34yMDIxLjA1LjE444CCDQorIOizh+aWmeeahOmXnOmNteWtlzrmqqLntKLjgIzlgZzpm7vjgI3jgIHjgIznvLrpm7vjgI3jgIHjgIzoiIjpgZTjgI3jgIHjgIzpm7vlu6DjgI3jgIHjgIzoiIjpgZTpm7vlu6DjgI3kupTlgIvpl5zpjbXlrZfvvIzlhbHmkJzlsIvlh7oxMTEz56+H5paH56ug44CCDQoNCg0KIyDkuozjgIHliY3nva7kvZzmpa0NCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NClN5cy5zZXRsb2NhbGUoY2F0ZWdvcnkgPSAiTENfQUxMIiwgbG9jYWxlID0gInpoX1RXLlVURi04IikgIyDpgb/lhY3kuK3mlofkuoLnorwNCmBgYA0KDQojIyAxLuWuieijnemcgOimgeeahHBhY2thZ2VzDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KcGFja2FnZXMgPSBjKCJyZWFkciIsICJkcGx5ciIsICJqaWViYVIiLCAidGlkeXIiLCAidGlkeXRleHQiLCAiaWdyYXBoIiwgInRvcGljbW9kZWxzIiwgImdncGxvdDIiLCAic3RyaW5nciIpDQpleGlzdGluZyA9IGFzLmNoYXJhY3RlcihpbnN0YWxsZWQucGFja2FnZXMoKVssMV0pDQpmb3IocGtnIGluIHBhY2thZ2VzWyEocGFja2FnZXMgJWluJSBleGlzdGluZyldKSBpbnN0YWxsLnBhY2thZ2VzKHBrZykNCmBgYA0KDQojIyAyLuWwh3JlcXVpcmXlj4psaWJyYXJ56LyJ5YWlDQpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoamllYmFSKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkodGlkeXRleHQpDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkodG9waWNtb2RlbHMpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeSh3b3JkY2xvdWQyKQ0KYGBgDQoNCg0KIyMgMy7ovInlhaXoh6rlubPlj7DkuIvovInkuIvkvobnmoTos4fmlpkNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQpwb3N0cyA8LSByZWFkX2NzdigiMDYxMi0xX2FydGljbGVNZXRhRGF0YS5jc3YiKSAjIOaWh+eroCANCnJldmlld3MgPC0gcmVhZF9jc3YoIjA2MTItMV9hcnRpY2xlUmV2aWV3cy5jc3YiKSAjIOWbnuimhiANCnJkIDwtIHJlYWRfY3N2KCIwNjEyLTFfYXJ0V29yZFBPU0ZyZXEuY3N2IikNCmhlYWQocG9zdHMpDQpoZWFkKHJldmlld3MpDQpoZWFkKHJkKQ0KYGBgDQoNCiMjIDQu5paH56ug5pa35Y+lDQpgYGB7cn0NCiMgIyDmlofnq6Dmlrflj6UoIlxuXG4i5Y+W5Luj5oiQIuOAgiIpDQptYXNrX21ldGEgPC0gcG9zdHMgJT4lDQogICAgICAgICAgICAgICBtdXRhdGUoc2VudGVuY2U9Z3N1YigiW1xuXXsyLH0iLCAi44CCIiwgc2VudGVuY2UpKQ0KIyANCiMgIyDku6XlhajlvaLmiJbljYrlvaIg6ama5q2O6Jmf44CB5ZWP6Jmf44CB5YiG6JmfIOS7peWPiiDlhajlvaLlj6XomZ8g54iy5L6d5pOa6YCy6KGM5pa35Y+lDQptYXNrX3NlbnRlbmNlcyA8LSBzdHJzcGxpdChtYXNrX21ldGEkc2VudGVuY2UsIlvjgILvvIHvvJvvvJ8hPztdIikNCiMgDQojICMg5bCH5q+P5Y+l5Y+l5a2Q77yM6IiH5LuW5omA5bGs55qE5paH56ug6YCj57WQ6YWN5bCN6LW35L6G77yM5pW055CG5oiQ5LiA5YCLZGF0YWZyYW1lDQptYXNrX3NlbnRlbmNlcyA8LSBkYXRhLmZyYW1lKA0KICAgICAgICAgICAgICAgICAgICAgICAgYXJ0VXJsID0gcmVwKG1hc2tfbWV0YSRhcnRVcmwsIHNhcHBseShtYXNrX3NlbnRlbmNlcywgbGVuZ3RoKSksDQogICAgICAgICAgICAgICAgICAgICAgICBzZW50ZW5jZSA9IHVubGlzdChtYXNrX3NlbnRlbmNlcykNCiAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKCFzdHJfZGV0ZWN0KHNlbnRlbmNlLCByZWdleCgiXihcdHxcbnwgKSokIikpKQ0KICAgICAgICAgICAgICAgICAgICAgICAjIOWmguaenOaciVx05oiWXG7lsLHljrvmjokNCiANCiBtYXNrX3NlbnRlbmNlcyRzZW50ZW5jZSA8LSBhcy5jaGFyYWN0ZXIobWFza19zZW50ZW5jZXMkc2VudGVuY2UpDQogbWFza19zZW50ZW5jZXMNCmBgYA0KDQoNCiMjIDUu5paH56ug5pa36KmeDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KIyAjIyDmlofnq6DmlrfoqZ4NCiMgIyBsb2FkIG1hc2tfbGV4aWNvbijnibnlrpropoHmlrfplovnmoToqZ7vvIzlg4/mmK91c2VyX2RpY3QpDQptYXNrX2xleGljb24gPC0gc2NhbihmaWxlID0gIi4uL2RpY3QvbWFza19sZXhpY29uLnR4dCIsIHdoYXQ9Y2hhcmFjdGVyKCksc2VwPSdcbicsDQogICAgICAgICAgICAgICAgICAgIGVuY29kaW5nPSd1dGYtOCcsZmlsZUVuY29kaW5nPSd1dGYtOCcpDQojIGxvYWQgc3RvcCB3b3Jkcw0Kc3RvcF93b3JkcyA8LSBzY2FuKGZpbGUgPSAiLi4vZGljdC9zdG9wX3dvcmRzLnR4dCIsIHdoYXQ9Y2hhcmFjdGVyKCksc2VwPSdcbicsDQogICAgICAgICAgICAgICAgICAgIGVuY29kaW5nPSd1dGYtOCcsZmlsZUVuY29kaW5nPSd1dGYtOCcpDQojIA0KIyAjIOS9v+eUqOm7mOiqjeWPg+aVuOWIneWni+WMluS4gOWAi+aWt+ipnuW8leaTjg0KamllYmFfdG9rZW5pemVyID0gd29ya2VyKCkNCiMgDQojICMg5L2/55So5Y+j572p5a2X5YW46YeN5paw5pa36KmeDQpuZXdfdXNlcl93b3JkKGppZWJhX3Rva2VuaXplciwgYyhtYXNrX2xleGljb24pKQ0KIyANCiN0b2tlbml6ZSBmdW5jdGlvbg0KY2hpX3Rva2VuaXplciA8LSBmdW5jdGlvbih0KSB7DQogIGxhcHBseSh0LCBmdW5jdGlvbih4KSB7DQogICAgIGlmKG5jaGFyKHgpPjEpew0KICAgICAgIHRva2VucyA8LSBzZWdtZW50KHgsIGppZWJhX3Rva2VuaXplcikNCiAgICAgICB0b2tlbnMgPC0gdG9rZW5zWyF0b2tlbnMgJWluJSBzdG9wX3dvcmRzXQ0KICAgICAgICMg5Y675o6J5a2X5Liy6ZW35bqm54iyMeeahOipnuW9mQ0KICAgICAgIHRva2VucyA8LSB0b2tlbnNbbmNoYXIodG9rZW5zKT4xXQ0KICAgICAgIHJldHVybih0b2tlbnMpDQogICAgIH0NCiAgIH0pDQogfQ0KIyANCiMgDQojICMg55So5Ymb5Ymb5Yid5aeL5YyW55qE5pa36Kme5Zmo5oqKc2VudGVuY2XmlrfplosNCiB0b2tlbnMgPC0gbWFza19zZW50ZW5jZXMgJT4lDQogICAgIG11dGF0ZShzZW50ZW5jZSA9IGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsc2VudGVuY2UpKSAlPiUNCiAgICAgbXV0YXRlKHNlbnRlbmNlID0gZ3N1YigiWzAtOWEtekEtWl0iLCAiIixzZW50ZW5jZSkpICU+JQ0KICAgICB1bm5lc3RfdG9rZW5zKHdvcmQsIHNlbnRlbmNlLCB0b2tlbj1jaGlfdG9rZW5pemVyKSAlPiUNCiAgIGNvdW50KGFydFVybCwgd29yZCkgJT4lICMg6KiI566X5q+P56+H5paH56ug5Ye654++55qE5a2X6aC7DQogICByZW5hbWUoY291bnQ9bikNCiB0b2tlbnMNCiMgc2F2ZS5pbWFnZShmaWxlID0gIi4uL2RhdGEvdG9rZW5fcmVzdWx0LnJkYXRhIikNCmBgYA0KDQoNCg0KDQojIyMjIOa4heeQhuaWt+ipnue1kOaenA0KDQrjgILmoLnmk5roqZ7poLvvvIzpgbjmk4flj6rlh7rnj74z5a2X5Lul5LiK55qE5a2XIDwvYnI+DQrjgILmlbTnkIbmiJB1cmwsd29yZCxu55qE5qC85byP5LmL5b6M77yM5bCx5Y+v5Lul6L2JZHRtIDwvYnI+DQoNClAuUy4gZ3JvdXBieSBieeS5i+W+jOWOn+acrOeahOWtl+ipnue1kOani+acg+S4jeimi++8jOaKiuipnumgu+WPpuWtmOWcqOS4gOWAi3Jlc2VydmVkX3dvcmToo6HpnaINCmBgYHtyfQ0KZnJlcSA9IDMNCiMg5L6d5pOa5a2X6aC75oyR5a2XDQpyZXNlcnZlZF93b3JkIDwtIHRva2VucyAlPiUgDQogIGdyb3VwX2J5KHdvcmQpICU+JSANCiAgY291bnQoKSAlPiUgDQogIGZpbHRlcihuID4gZnJlcSkgJT4lIA0KICB1bmxpc3QoKQ0KDQptYXNrX3JlbW92ZWQgPC0gdG9rZW5zICU+JSANCiAgZmlsdGVyKHdvcmQgJWluJSByZXNlcnZlZF93b3JkKQ0KDQojbWFza19kdG0g6KOh6Z2iIG5yb3c65bm+56+H5paH56ugIDsgbmNvbDrlub7lgIvlrZcNCm1hc2tfZHRtIDwtIG1hc2tfcmVtb3ZlZCAlPiUgY2FzdF9kdG0oYXJ0VXJsLCB3b3JkLCBjb3VudCkgDQpgYGANCg0KIyDkuInjgIHmipjnt5rlnJYNCiMjIDEu6LOH5paZ6JmV55CGDQpgYGB7cn0NCmRhdGEgPC0gcmQgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGFydERhdGUsIGFydFVybCkgJT4lIA0KICBkaXN0aW5jdCgpDQphcnRpY2xlX2NvdW50X2J5X2RhdGUgPC0gZGF0YSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUpICU+JSANCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQ0KaGVhZChhcnRpY2xlX2NvdW50X2J5X2RhdGUsIDIwKQ0KYGBgDQojIyAyLuWIneWni+WMluaWt+ipnuW8leaTjg0KYGBge3J9DQojIOWKoOWFpeiHquWumue+qeeahOWtl+WFuA0KamllYmFfdG9rZW5pemVyIDwtIHdvcmtlcih1c2VyPSJ1c2VyX2RpY3QudHh0Iiwgc3RvcF93b3JkID0gInN0b3Bfd29yZHMudHh0IikNCg0KIyDoqK3lrprmlrfoqZ5mdW5jdGlvbg0KY2hpX3Rva2VuaXplciA8LSBmdW5jdGlvbih0KSB7DQogIGxhcHBseSh0LCBmdW5jdGlvbih4KSB7DQogICAgaWYobmNoYXIoeCk+MSl7DQogICAgICB0b2tlbnMgPC0gc2VnbWVudCh4LCBqaWViYV90b2tlbml6ZXIpDQogICAgICAjIOWOu+aOieWtl+S4sumVt+W6pueIsjHnmoToqZ7lvZkNCiAgICAgIHRva2VucyA8LSB0b2tlbnNbbmNoYXIodG9rZW5zKT4xXQ0KICAgICAgcmV0dXJuKHRva2VucykNCiAgICB9DQogIH0pDQp9DQoNCnJkX3Rva2Vuc19hbGwgPC0gcG9zdHMgJT4lDQogIHVubmVzdF90b2tlbnMod29yZCwgc2VudGVuY2UsIHRva2VuPWNoaV90b2tlbml6ZXIpICU+JSANCiAgc2VsZWN0KC1hcnRUaW1lKQ0KDQpgYGANCg0KIyMgMy7lj7DngaPlpKflgZzpm7vkuovku7blnKhQVFTlhavljaY1LzEzfjUvMTnogbLph4/mipjnt5rlnJYNCmBgYHtyfQ0KDQpwbG90X2RhdGUgPC0gDQogICMgZGF0YQ0KICBhcnRpY2xlX2NvdW50X2J5X2RhdGUgJT4lIA0KICAjIGFlc3RoZXRpY3MNCiAgZ2dwbG90KGFlcyh4ID0gYXJ0RGF0ZSwgeSA9IGNvdW50KSkgKw0KICAjIGdlb21ldHJpY3MNCiAgZ2VvbV9saW5lKGNvbG9yID0gIiMwMEFGQkIiLCBzaXplID0gMSkgKyANCiAgIyAyMDIxLTAxLTIwIOe0hee3mg0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhcy5udW1lcmljKGFzLkRhdGUoIjIwMjEtMDUtMTMiKSksIGNvbD0ncmVkJywgc2l6ZSA9IDEpICsgDQogICMgMjAyMS0wMi0yMyDntIXnt5oNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXMubnVtZXJpYyhhcy5EYXRlKCIyMDIxLTA1LTE3IikpLCBjb2w9J3JlZCcsIHNpemUgPSAxKSArIA0KICAjIGNvb3JkaW5hdGVzDQoNCiAgZ2d0aXRsZSgiRGNhcmQg6IKh56Wo55yL5p2/IOiojuirluaWh+eroOaVuCIpICsgDQogIHhsYWIoIuaXpeacnyIpICsgDQogIHlsYWIoIuaVuOmHjyIpICsgDQogICMgdGhlbWUNCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkgI+WKoOWFpeS4reaWh+Wtl+Wei+ioreWumu+8jOmBv+WFjeS4reaWh+Wtl+mhr+ekuumMr+iqpOOAgg0KDQpwbG90X2RhdGUNCmBgYA0KDQojIOWbm+OAgeaWh+Wtl+mbsg0KYGBge3J9DQpkYXRhIDwtIHJkICU+JSANCiAgZ3JvdXBfYnkod29yZCkgJT4lIA0KICBzdW1tYXJpc2Uoc3VtID0gc3VtKGNvdW50KSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICBhcnJhbmdlKGRlc2Moc3VtKSkNCg0KZGF0YSAlPiUgZmlsdGVyKHN1bSA+IDUwKSAlPiUgd29yZGNsb3VkMigpDQpgYGANCg0KIyDkupTjgIHmg4Xnt5LliIbmnpANCiMjIDEu6LyJ5YWl5oOF57eS5YiG5p6Q5a2X5YW4DQpgYGB7cn0NCiMg5q2j5ZCR5a2X5YW4dHh05qqUDQojIOS7pSzlsIflrZfliIbpmpQNClAgPC0gcmVhZF9maWxlKCJwb3NpdGl2ZS50eHQiKQ0KDQojIOiyoOWQkeWtl+WFuHR4dOaqlA0KTiA8LSByZWFkX2ZpbGUoIm5lZ2F0aXZlLnR4dCIpDQoNCiPlsIflrZfkuLLkvp0s5YiG5YmyDQojc3Ryc3BsaXTlm57lgrNsaXN0ICwg5oiR5YCR5Y+W5Ye6bGlzdOS4reeahOesrOS4gOWAi+WFg+e0oA0KUCA9IHN0cnNwbGl0KFAsICIsIilbWzFdXQ0KTiA9IHN0cnNwbGl0KE4sICIsIilbWzFdXQ0KDQojIOW7uueri2RhdGFmcmFtZSDmnInlhanlgIvmrITkvY13b3JkLHNlbnRpbWVudHPvvIx3b3Jk5qyE5L2N5YWn5a655piv5a2X5YW45ZCR6YePDQpQID0gZGF0YS5mcmFtZSh3b3JkID0gUCwgc2VudGltZW50ID0gInBvc2l0aXZlIikNCk4gPSBkYXRhLmZyYW1lKHdvcmQgPSBOLCBzZW50aW1lbnQgPSAibmVnYXRpdmUiKQ0KTElXQyA9IHJiaW5kKFAsIE4pDQoNCnJkX3Rva2VucyA8LSByZCAlPiUNCiAgc2VsZWN0KC1hcnRUaW1lLCAtYXJ0VXJsKQ0KaGVhZChyZF90b2tlbnMpDQoNCnJkX3Rva2Vuc19ieV9kYXRlIDwtIHJkX3Rva2VucyAlPiUgDQogIGNvdW50KGFydERhdGUsIHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUNCiAgZmlsdGVyKG4gPiA1KQ0KcmRfdG9rZW5zX2J5X2RhdGUNCg0KcmRfdG9rZW5zX2J5X2RhdGUgJT4lDQogIGlubmVyX2pvaW4oTElXQykgJT4lDQogIHNlbGVjdCh3b3JkKSAlPiUNCiAgaW5uZXJfam9pbihMSVdDKSANCg0KDQpzZW50aW1lbnRfY291bnQgPSByZF90b2tlbnNfYnlfZGF0ZSAlPiUNCiAgc2VsZWN0KGFydERhdGUsd29yZCxuKSAlPiUNCiAgaW5uZXJfam9pbihMSVdDKSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUsc2VudGltZW50KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50PXN1bShuKSkNCmBgYA0KDQoNCiMjIDIu5Y+w54Gj5YGc6Zu75LqL5Lu25ZyoUFRU5YWr5Y2m54mINS8xM341LzE45q2j6LKg6Z2i5oOF57eS6IGy6YeP5oqY57ea5ZyWDQpgYGB7cn0NCnNlbnRpbWVudF9jb3VudCAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX2xpbmUoYWVzKHg9YXJ0RGF0ZSx5PWNvdW50LGNvbG91cj1zZW50aW1lbnQpKSArDQogIGxhYnMoeD1OVUxMLHk9IuaVuOmHjyIpDQogDQpgYGANCg0KIyMgMy7lj7DngaPlgZzpm7vkuovku7blnKhQVFTlhavljabniYg1LzEzfjUvOOato+iyoOaDhee3kumVt+aineWclg0KYGBge3J9DQpyZF90b2tlbnNfYWxsICU+JQ0KICBmaWx0ZXIoYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA1LTEzIikgfA0KICAgICAgICAgYXJ0RGF0ZSA9PSBhcy5EYXRlKCIyMDIxLTA1LTE0IikgfCANCiAgICAgICAgIGFydERhdGUgPT0gYXMuRGF0ZSgiMjAyMS0wNS0xNSIpIHwgDQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDUtMTYiKSB8DQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDUtMTciKSB8DQogICAgICAgICBhcnREYXRlID09IGFzLkRhdGUoIjIwMjEtMDUtMTgiKSApICU+JSANCiAgaW5uZXJfam9pbihMSVdDKSAlPiUNCiAgZ3JvdXBfYnkod29yZCxzZW50aW1lbnQpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgY291bnQgPSBuKCkNCiAgKSAlPiUgZGF0YS5mcmFtZSgpICU+JSANCiAgdG9wX24oMzAsd3QgPSBjb3VudCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBjb3VudCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHdvcmQsIGNvdW50LCBmaWxsID0gc2VudGltZW50KSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGxhYnMoeD0gIuaWh+WtlyIsIHk9IuaVuOmHjyIpICsNCiAgZmFjZXRfd3JhcCh+c2VudGltZW50LCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE0KSkrDQogIGNvb3JkX2ZsaXAoKQ0KDQpgYGANCg0KIyDlha3jgIFMREEg5Li76aGM5YiG6aGeDQoNCg0KIyMgMS5MREEg5Li76aGM5YiG5p6QDQpgYGB7cn0NCiMgTERB5YiG5oiQNuWAi+S4u+mhjA0KbWFza19sZGEgPC0gTERBKG1hc2tfZHRtLCBrID0gNiwgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDEyMzQ1KSkNCmBgYA0KDQoNCiMjIDIu5Y+W5Ye65Luj6KGo5a2X6KmeKHRlcm0pDQpgYGB7cn0NCg0KI3JlbW92ZWRfd29yZCA9IGMoIuS4jeaYryIsIuavj+WkqSIsIuWHuuS+hiIsIuimuuW+lyIpIA0KcmVtb3ZlZF93b3JkID0gYygi5LiA5LiLIiwi5LiN5pivIikgDQojIOeci+WQhOe+pOeahOW4uOeUqOipnuW9mQ0KdGlkeShtYXNrX2xkYSwgbWF0cml4ID0gImJldGEiKSAlPiUgIyDlj5blh7p0b3BpYyB0ZXJtIGJldGHlgLwNCiAgZmlsdGVyKCEgdGVybSAlaW4lIHJlbW92ZWRfd29yZCkgJT4lIA0KICBncm91cF9ieSh0b3BpYykgJT4lDQogIHRvcF9uKDEwLCBiZXRhKSAlPiUgIyBiZXRh5YC85YmNMTDnmoTlrZcNCiAgdW5ncm91cCgpICU+JQ0KICBtdXRhdGUodG9waWMgPSBhcy5mYWN0b3IodG9waWMpLA0KICAgICAgICAgdGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgJT4lDQogIGdncGxvdChhZXModGVybSwgYmV0YSwgZmlsbCA9IHRvcGljKSkgKw0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGZhY2V0X3dyYXAofiB0b3BpYywgc2NhbGVzID0gImZyZWUiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHNjYWxlX3hfcmVvcmRlcmVkKCkNCmBgYA0KDQoNCg0KIyMgMy7lj5blh7rku6PooajkuLvpoYwodG9waWMpDQpgYGB7cn0NCiMg5ZyodGlkeSBmdW5jdGlvbuS4reS9v+eUqOWPg+aVuCJnYW1tYSLkvoblj5blvpcgdGhldGHnn6npmaMNCm1hc2tfdG9waWNzIDwtIHRpZHkobWFza19sZGEsIG1hdHJpeD0iZ2FtbWEiKSAlPiUgIyBkb2N1bWVudCB0b3BpYyBnYW1tYQ0KICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZG9jdW1lbnQpICU+JQ0KICAgICAgICAgICAgICAgICAgdG9wX24oMSwgd3Q9Z2FtbWEpDQptYXNrX3RvcGljcw0KYGBgDQoNCiMjIDQu6LOH5paZ5YWn5a655o6i57SiDQpgYGB7cn0NCnBvc3RzX3RvcGljIDwtIG1lcmdlKHggPSBwb3N0cywgeSA9IG1hc2tfdG9waWNzLCBieS54ID0gImFydFVybCIsIGJ5Lnk9ImRvY3VtZW50IikNCg0KIyDnnIvkuIDkuIvlkITkuLvpoYzlnKjoqqrnlJrpurwNCnNldC5zZWVkKDEyMzQ1KQ0KDQpwb3N0c190b3BpYyAlPiUgIyDkuLvpoYzkuIANCiAgZmlsdGVyKHRvcGljPT0xKSAlPiUNCiAgc2VsZWN0KGFydFRpdGxlKSAlPiUNCiAgdW5pcXVlKCkgJT4lDQogIHNhbXBsZV9uKDEwKQ0KDQoNCnBvc3RzX3RvcGljICU+JSAjIOS4u+mhjOS6jA0KICBmaWx0ZXIodG9waWM9PTIpICU+JQ0KICBzZWxlY3QoYXJ0VGl0bGUpICU+JQ0KICB1bmlxdWUoKSAlPiUNCiAgc2FtcGxlX24oMTApDQoNCnBvc3RzX3RvcGljICU+JSAjIOS4u+mhjOS4iQ0KICBmaWx0ZXIodG9waWM9PTMpICU+JQ0KICBzZWxlY3QoYXJ0VGl0bGUpICU+JQ0KICB1bmlxdWUoKSAlPiUNCiAgc2FtcGxlX24oMTApDQoNCnBvc3RzX3RvcGljICU+JSAjIOS4u+mhjOWbmw0KICBmaWx0ZXIodG9waWM9PTQpICU+JQ0KICBzZWxlY3QoYXJ0VGl0bGUpICU+JQ0KICB1bmlxdWUoKSAlPiUNCiAgc2FtcGxlX24oMTApDQoNCg0KcG9zdHNfdG9waWMgJT4lICMg5Li76aGM5LqUDQogIGZpbHRlcih0b3BpYz09NSkgJT4lDQogIHNlbGVjdChhcnRUaXRsZSkgJT4lDQogIHVuaXF1ZSgpICU+JQ0KICBzYW1wbGVfbigxMCkNCg0KcG9zdHNfdG9waWMgJT4lICMg5Li76aGM5YWtDQogIGZpbHRlcih0b3BpYz09NikgJT4lDQogIHNlbGVjdChhcnRUaXRsZSkgJT4lDQogIHVuaXF1ZSgpICU+JQ0KICBzYW1wbGVfbigxMCkNCmBgYA0KDQojIyA1LuaXpeacn+S4u+mhjOWIhuW4gw0KYGBge3J9DQpwb3N0c190b3BpYyAlPiUNCiAgbXV0YXRlKGFydERhdGUgPSBhcy5EYXRlKGFydERhdGUpKSAlPiUgDQogIGdyb3VwX2J5KGFydERhdGUsdG9waWMpICU+JQ0KICBzdW1tYXJpc2Uoc3VtID1zdW0odG9waWMpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PSBhcnREYXRlLHk9c3VtLGZpbGw9YXMuZmFjdG9yKHRvcGljKSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb249ImZpbGwiKSANCg0KDQpwb3N0c190b3BpYyAlPiUNCiAgZ3JvdXBfYnkoYXJ0Q2F0LHRvcGljKSAlPiUNCiAgc3VtbWFyaXNlKHN1bSA9IG4oKSkgICU+JQ0KICBnZ3Bsb3QoYWVzKHg9IGFydENhdCx5PXN1bSxmaWxsPWFzLmZhY3Rvcih0b3BpYykpKSArDQogIGdlb21fY29sKHBvc2l0aW9uPSJkb2RnZSIpIA0KDQpgYGANCg0KIyDkuIPjgIHnpL7nvqTntrLot6/lnJYNCg0KIyMgMS7os4fmlpnlkIjkvbUNCmBgYHtyfQ0KIyDmlofnq6DlkoznlZnoqIANCnJldmlld3MgPC0gcmV2aWV3cyAlPiUNCiAgICAgIHNlbGVjdChhcnRVcmwsIGNtdFBvc3RlciwgY210U3RhdHVzLCBjbXRDb250ZW50KQ0KcG9zdHNfUmV2aWV3cyA8LSBtZXJnZSh4ID0gcG9zdHMsIHkgPSByZXZpZXdzLCBieSA9ICJhcnRVcmwiKQ0KDQojIOaKiuaWh+eroOWSjHRvcGljDQpwb3N0c19SZXZpZXdzIDwtIG1lcmdlKHggPSBwb3N0c19SZXZpZXdzLCB5ID0gbWFza190b3BpY3MsIGJ5LnggPSAiYXJ0VXJsIiwgYnkueT0iZG9jdW1lbnQiKQ0KaGVhZChwb3N0c19SZXZpZXdzLDMpDQpgYGANCg0KYGBge3J9DQpsaW5rIDwtIHBvc3RzX1Jldmlld3MgJT4lIHNlbGVjdChjbXRQb3N0ZXIsIGFydFBvc3RlciwgYXJ0VXJsKQ0KaGVhZChsaW5rLDMpDQpgYGANCg0KIyMgMi7ln7rmnKzntrLot6/lnJYNCmBgYHtyfQ0KcmV2aWV3TmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZD1saW5rLCBkaXJlY3RlZD1UKQ0KcmV2aWV3TmV0d29yaw0KYGBgDQoNCiMjIDMu6LOH5paZ56+p6YG4DQpgYGB7cn0NCiMg55yL5LiA5LiL55WZ6KiA5pW45aSn5qaC6YO95aSa5bCRKOaWueS+v+W+jOmdouevqemBuCkNCnBvc3RzICU+JQ0KIyAgZmlsdGVyKGNvbW1lbnROdW08MTAwKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWNvbW1lbnROdW0pKSArIGdlb21faGlzdG9ncmFtKCkNCmBgYA0KDQojIyA0LuS+neaTmueZvOaWh+aVuOaIluWbnuimhuaVuOevqemBuHBvc3TlkoxyZXZpZXcNCmBgYHtyfQ0KIyAjIOW4s+iZn+eZvOaWh+evh+aVuA0KcG9zdF9jb3VudCA9IHBvc3RzICU+JQ0KICBncm91cF9ieShhcnRQb3N0ZXIpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKSANCnBvc3RfY291bnQNCiMgDQojICMg5biz6Jmf5Zue6KaG57i95pW4DQpyZXZpZXdfY291bnQgPSByZXZpZXdzICU+JQ0KICBncm91cF9ieShjbXRQb3N0ZXIpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKSANCnJldmlld19jb3VudA0KDQojICMg55m85paH6ICFDQpwb3N0ZXJfc2VsZWN0IDwtIHBvc3RfY291bnQgJT4lIGZpbHRlcihjb3VudCA+PSAyKQ0KcG9zdHMgPC0gcG9zdHMgJT4lICBmaWx0ZXIocG9zdHMkYXJ0UG9zdGVyICVpbiUgcG9zdGVyX3NlbGVjdCRhcnRQb3N0ZXIpDQojIA0KIyAjIOWbnuimhuiAhQ0KcmV2aWV3ZXJfc2VsZWN0IDwtIHJldmlld19jb3VudCAlPiUgIGZpbHRlcihjb3VudCA+PSAyMCkNCnJldmlld3MgPC0gcmV2aWV3cyAlPiUgIGZpbHRlcihyZXZpZXdzJGNtdFBvc3RlciAlaW4lIHJldmlld2VyX3NlbGVjdCRjbXRQb3N0ZXIpDQpgYGANCg0KDQpgYGB7cn0NCiMg5qqi6KaW5Y+D6IiH5Lq65pW4DQpsZW5ndGgodW5pcXVlKHBvc3RzX1Jldmlld3MkYXJ0UG9zdGVyKSkgIyDnmbzmlofogIXmlbjph48gOTExDQpsZW5ndGgodW5pcXVlKHBvc3RzX1Jldmlld3MkY210UG9zdGVyKSkgIyDlm57opobogIXmlbjph48gMTUyMjQNCmFsbFBvc3RlciA8LSBjKHBvc3RzX1Jldmlld3MkYXJ0UG9zdGVyLCBwb3N0c19SZXZpZXdzJGNtdFBvc3RlcikgIyDnuL3lj4PoiIfkurrmlbggMTU2NDENCmxlbmd0aCh1bmlxdWUoYWxsUG9zdGVyKSkNCmBgYA0KDQpgYGB7cn0NCnVzZXJMaXN0IDwtIGRhdGEuZnJhbWUodXNlcj11bmlxdWUoYWxsUG9zdGVyKSkgJT4lDQogICAgICAgICAgICAgIG11dGF0ZSh0eXBlPWlmZWxzZSh1c2VyJWluJXBvc3RzJGFydFBvc3RlciwgInBvc3RlciIsICJyZXBseWVyIikpDQpoZWFkKHVzZXJMaXN0LDMpDQpgYGANCg0KIyMgNS7ku6Xml6XmnJ/nr6npgbjnpL7nvqQNCmBgYHtyfQ0KbGluayA8LSBwb3N0c19SZXZpZXdzICU+JQ0KICAgICAgZ3JvdXBfYnkoY210UG9zdGVyLCBhcnRVcmwpICU+JSANCiAgICAgIGZpbHRlcihuKCk+MykgJT4lIA0KICAgICAgZmlsdGVyKGNvbW1lbnROdW0gPiAyMDApICU+JQ0KICAgICAgZmlsdGVyKGFydENhdD09Ikdvc3NpcGluZyIpICU+JSANCiAgICAgIGZpbHRlcihhcnREYXRlID09IGFzLkRhdGUoJzIwMjEtMDUtMTMnKSkgJT4lDQogICAgICBzZWxlY3QoY210UG9zdGVyLCBhcnRQb3N0ZXIsIGFydFVybCkgJT4lIA0KICAgICAgdW5pcXVlKCkNCmxpbmsNCmBgYA0KDQpgYGB7cn0NCmZpbHRlcmVkX3VzZXIgPC0gdXNlckxpc3QgJT4lDQogICAgICAgICAgZmlsdGVyKHVzZXIlaW4lbGluayRjbXRQb3N0ZXIgfCB1c2VyJWluJWxpbmskYXJ0UG9zdGVyKSAlPiUNCiAgICAgICAgICBhcnJhbmdlKGRlc2ModHlwZSkpDQpoZWFkKGZpbHRlcmVkX3VzZXIsMykNCmBgYA0KDQpgYGB7cn0NCnNldC5zZWVkKDQ4NykNCiMgdj1maWx0ZXJlZF91c2VyDQoNCnJldmlld05ldHdvcmsgPSBkZWdyZWUocmV2aWV3TmV0d29yaykgPiAyDQpyZXZpZXdOZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPWxpbmssIHY9ZmlsdGVyZWRfdXNlciwgZGlyZWN0ZWQ9RikNCnBsb3QocmV2aWV3TmV0d29yaywgdmVydGV4LnNpemU9MywgZWRnZS5hcnJvdy5zaXplPTAuMyx2ZXJ0ZXgubGFiZWw9TkEpDQpgYGANCg0KYGBge3J9DQpzZXQuc2VlZCg0ODcpDQpWKHJldmlld05ldHdvcmspJGNvbG9yIDwtIGlmZWxzZShWKHJldmlld05ldHdvcmspJHR5cGU9PSJwb3N0ZXIiLCAiZ29sZCIsICJsaWdodGJsdWUiKQ0KcGxvdChyZXZpZXdOZXR3b3JrLCB2ZXJ0ZXguc2l6ZT0zLCBlZGdlLmFycm93LnNpemU9MC4zLHZlcnRleC5sYWJlbD1OQSkNCmBgYA0KDQpgYGB7cn0NCmZpbHRlcl9kZWdyZWUgPSA0DQpzZXQuc2VlZCgxMjMpDQoNCiMg6Kit5a6aIG5vZGUg55qEIGxhYmVsLyBjb2xvcg0KbGFiZWxzIDwtIGRlZ3JlZShyZXZpZXdOZXR3b3JrKSAjIOeul+WHuuavj+WAi+m7nueahGRlZ3JlZQ0KVihyZXZpZXdOZXR3b3JrKSRsYWJlbCA8LSBuYW1lcyhsYWJlbHMpDQpWKHJldmlld05ldHdvcmspJGNvbG9yIDwtIGlmZWxzZShWKHJldmlld05ldHdvcmspJHR5cGU9PSJwb3N0ZXIiLCAiZ29sZCIsICJsaWdodGJsdWUiKQ0KDQpwbG90KA0KICByZXZpZXdOZXR3b3JrLCANCiAgdmVydGV4LnNpemU9MywgDQogIGVkZ2Uud2lkdGg9MywgDQogIHZlcnRleC5sYWJlbC5kaXN0PTEsDQogIHZlcnRleC5sYWJlbD1pZmVsc2UoZGVncmVlKHJldmlld05ldHdvcmspID4gZmlsdGVyX2RlZ3JlZSwgVihyZXZpZXdOZXR3b3JrKSRsYWJlbCwgTkEpLHZlcnRleC5sYWJlbC5mb250PTIpDQpgYGANCg0KYGBge3J9DQpsaW5rIDwtIHBvc3RzX1Jldmlld3MgJT4lDQogICAgICBncm91cF9ieShjbXRQb3N0ZXIsIGFydFVybCkgJT4lIA0KICAgICAgZmlsdGVyKG4oKT4zKSAlPiUgDQogICAgICBmaWx0ZXIoY29tbWVudE51bSA+IDIwMCkgJT4lDQogICAgICBmaWx0ZXIoYXJ0Q2F0PT0iR29zc2lwaW5nIikgJT4lICNIYXRlUG9saXRpY3MgLyBHb3NzaXBpbmcNCiAgICAgIGZpbHRlcihhcnREYXRlID09IGFzLkRhdGUoJzIwMjEtMDUtMTMnKSkgJT4lDQogICAgICBmaWx0ZXIodG9waWMgPT0gMiB8IHRvcGljID09IDQpICU+JSANCiAgICAgIHNlbGVjdChjbXRQb3N0ZXIsIGFydFBvc3RlciwgYXJ0VXJsLCB0b3BpYykgJT4lIA0KICAgICAgdW5pcXVlKCkNCmxpbmsNCmBgYA0KDQpgYGB7cn0NCmZpbHRlcmVkX3VzZXIgPC0gdXNlckxpc3QgJT4lDQogICAgICAgICAgZmlsdGVyKHVzZXIlaW4lbGluayRjbXRQb3N0ZXIgfCB1c2VyJWluJWxpbmskYXJ0UG9zdGVyKSAlPiUNCiAgICAgICAgICBhcnJhbmdlKGRlc2ModHlwZSkpDQpoZWFkKGZpbHRlcmVkX3VzZXIsMykNCmBgYA0KDQojIyA2LuS9v+eUqOiAhee2k+W4uOWPg+iIh+eahOaWh+eroOeorumhng0KDQpgYGB7cn0NCmZpbHRlcl9kZWdyZWUgPSAxMw0KDQojIOW7uueri+e2sui3r+mXnOS/gg0KcmV2aWV3TmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZD1saW5rLCB2PWZpbHRlcmVkX3VzZXIsIGRpcmVjdGVkPUYpDQoNCiMg5L6d5pOa5L2/55So6ICF6Lqr5Lu95bCN6bue6YCy6KGM5LiK6ImyDQpsYWJlbHMgPC0gZGVncmVlKHJldmlld05ldHdvcmspDQpWKHJldmlld05ldHdvcmspJGxhYmVsIDwtIG5hbWVzKGxhYmVscykNClYocmV2aWV3TmV0d29yaykkY29sb3IgPC0gaWZlbHNlKFYocmV2aWV3TmV0d29yaykkdHlwZT09InBvc3RlciIsICJnb2xkIiwgImxpZ2h0Ymx1ZSIpDQoNCiMg5L6d5pOa5Zue6KaG55m855Sf55qE5paH56ug5omA5bCN5oeJ55qE5Li76aGM77yM5bCN5LuW5YCR55qE6Zec6IGv57ea6YCy6KGM5LiK6ImyDQpFKHJldmlld05ldHdvcmspJGNvbG9yIDwtIGlmZWxzZShFKHJldmlld05ldHdvcmspJHRvcGljID09ICIyIiwgInBhbGV2aW9sZXRyZWQiLCAibGlnaHRncmVlbiIpDQoNCiMg55Wr5Ye656S+576k57ay6Lev5ZyWKGRlZ3JlZT4355qE5omN55Wr5Ye65L6GKQ0Kc2V0LnNlZWQoNTQzMikNCnBsb3QocmV2aWV3TmV0d29yaywgdmVydGV4LnNpemU9MywgZWRnZS53aWR0aD0zLCB2ZXJ0ZXgubGFiZWwuZGlzdD0xLA0KICAgICB2ZXJ0ZXgubGFiZWw9aWZlbHNlKGRlZ3JlZShyZXZpZXdOZXR3b3JrKSA+IGZpbHRlcl9kZWdyZWUsIFYocmV2aWV3TmV0d29yaykkbGFiZWwsIE5BKSx2ZXJ0ZXgubGFiZWwuZm9udD0yKQ0KDQojIOWKoOWFpeaomeekug0KbGVnZW5kKCJib3R0b21yaWdodCIsIGMoIueZvOaWh+iAhSIsIuWbnuaWh+iAhSIpLCBwY2g9MjEsIA0KICBjb2w9IiM3Nzc3NzciLCBwdC5iZz1jKCJnb2xkIiwibGlnaHRibHVlIiksIHB0LmNleD0xLCBjZXg9MSkNCmxlZ2VuZCgidG9wbGVmdCIsIGMoIuaJueipleiqv+S+gyIsIuWgseWwjuebuOmXnCIpLCANCiAgICAgICBjb2w9YygicGFsZXZpb2xldHJlZCIsICJsaWdodGdyZWVuIiksIGx0eT0xLCBjZXg9MSkNCmBgYA0KDQojIyA3LuS9v+eUqOiAheaYr+WQpuWPl+WIsOatoei/jg0KDQpgYGB7cn0NCmZpbHRlcl9kZWdyZWUgPSA3ICMg5L2/55So6ICFZGVncmVlDQoNCiMg6YGO5r++55WZ6KiA6ICF5bCN55m85paH6ICF55qE5o6o5ZmT56iL5bqmDQpsaW5rIDwtIHBvc3RzX1Jldmlld3MgJT4lDQogICAgICBmaWx0ZXIoYXJ0Q2F0PT0iR29zc2lwaW5nIikgJT4lIA0KICAgICAgZmlsdGVyKGNvbW1lbnROdW0gPiAxMDApICU+JQ0KICAgICAgZmlsdGVyKGNtdFN0YXR1cyE9IuKGkiIpICU+JQ0KICAgICAgZ3JvdXBfYnkoY210UG9zdGVyLCBhcnRVcmwpICU+JQ0KICAgICAgZmlsdGVyKCBuKCkgPiAyKSAlPiUNCiAgICAgIHVuZ3JvdXAoKSAlPiUgDQogICAgICBzZWxlY3QoY210UG9zdGVyLCBhcnRQb3N0ZXIsIGFydFVybCwgY210U3RhdHVzKSAlPiUgDQogICAgICB1bmlxdWUoKQ0KDQojIOaOpeS4i+S+huaKiue2sui3r+WclueVq+WHuuS+hu+8jOi3n+WJjemdouWBmueahOS6i+mDveS4gOaoo++8jOWboOatpOS4jeWGjee0sOi/sA0KDQojIOevqemBuGxpbmvkuK3mnInlh7rnj77nmoTkvb/nlKjogIUNCmZpbHRlcmVkX3VzZXIgPC0gdXNlckxpc3QgJT4lDQogICAgICAgICAgZmlsdGVyKHVzZXIlaW4lbGluayRjbXRQb3N0ZXIgfCB1c2VyJWluJWxpbmskYXJ0UG9zdGVyKSAlPiUNCiAgICAgICAgICBhcnJhbmdlKGRlc2ModHlwZSkpDQoNCiMg5bu656uL57ay6Lev6Zec5L+CDQpyZXZpZXdOZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPWxpbmssIHY9ZmlsdGVyZWRfdXNlciwgZGlyZWN0ZWQ9RikNCg0KIyDkvp3mk5rkvb/nlKjogIXouqvku73lsI3pu57pgLLooYzkuIroibINCmxhYmVscyA8LSBkZWdyZWUocmV2aWV3TmV0d29yaykNClYocmV2aWV3TmV0d29yaykkbGFiZWwgPC0gbmFtZXMobGFiZWxzKQ0KVihyZXZpZXdOZXR3b3JrKSRjb2xvciA8LSBpZmVsc2UoVihyZXZpZXdOZXR3b3JrKSR0eXBlPT0icG9zdGVyIiwgImdvbGQiLCAibGlnaHRibHVlIikNCg0KDQojIOS+neaTmuWbnuimhueZvOeUn+eahOaWh+eroOaJgOWwjeaHieeahOS4u+mhjO+8jOWwjeS7luWAkeeahOmXnOiBr+e3mumAsuihjOS4iuiJsg0KRShyZXZpZXdOZXR3b3JrKSRjb2xvciA8LSBpZmVsc2UoRShyZXZpZXdOZXR3b3JrKSRjbXRTdGF0dXMgPT0gIuaOqCIsICJsaWdodGdyZWVuIiwgInBhbGV2aW9sZXRyZWQiKQ0KDQojIOeVq+WHuuekvue+pOe2sui3r+Wclg0Kc2V0LnNlZWQoNTQzMikNCnBsb3QocmV2aWV3TmV0d29yaywgdmVydGV4LnNpemU9MiwgZWRnZS53aWR0aD0zLCB2ZXJ0ZXgubGFiZWwuZGlzdD0xLA0KICAgICB2ZXJ0ZXgubGFiZWw9aWZlbHNlKGRlZ3JlZShyZXZpZXdOZXR3b3JrKSA+IGZpbHRlcl9kZWdyZWUsIFYocmV2aWV3TmV0d29yaykkbGFiZWwsIE5BKSx2ZXJ0ZXgubGFiZWwuZm9udD0yKQ0KDQojIOWKoOWFpeaomeekug0KbGVnZW5kKCJib3R0b21yaWdodCIsIGMoIueZvOaWh+iAhSIsIuWbnuaWh+iAhSIpLCBwY2g9MjEsDQogIGNvbD0iIzc3Nzc3NyIsIHB0LmJnPWMoImdvbGQiLCJsaWdodGJsdWUiKSwgcHQuY2V4PTEsIGNleD0xKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgYygi5o6oIiwi5ZmTIiksIA0KICAgICAgIGNvbD1jKCJsaWdodGdyZWVuIiwicGFsZXZpb2xldHJlZCIpLCBsdHk9MSwgY2V4PTEpDQpgYGANCg0KDQojIOWFq+OAgee4vee1kA0KDQoxLiDlj7DngaPlgZzpm7vkuovku7bnmoToqI7oq5bph43pu57mnInlk6rkups/IOS4u+imgeWIhueCuuWTquW5vueorumiqOWQkT88L2JyPg0K5bCN5pa8MjAyMS0wNS0yMSB+IDIwMjEtMDUtMjPmlLbpm4bnmoTmlofnq6DvvIzlpKfmpoLlj6/ku6XliIbmiJDlmLLoq7fmoKHmraPlm57mrbjjgIHlrqLop4DoqI7oq5bmoKHmraPlm57mrbjpgJnlhannqK7vvIzlhbbku5bpgoTmnInokZfph43oqI7oq5bnorroqLrlgIvmoYjotrPot6HmiJblkoznlqvoi5fnm7jpl5znmoToqI7oq5bnrYnlm5vnqK7jgILoqI7oq5bph43pu57lpJrlnKjmlrzntbHoqIjjgIzmlbjlrZfjgI3jgIHjgIzlhazluIPml6XmnJ/jgI3nrYnmoYjkvovnmoToqIjnrpfmlrnlvI/jgIINCg0KMi4g55uu5YmN6aKo5ZCR5pyA5YGP5ZOq6YKKPzwvYnI+DQrlrqLop4DoqI7oq5boqIjnrpfmlrnlvI/nmoTmlofnq6DkuI3lsJHvvIzkvYblmLLoq7fjgIHlhavljabmgKfos6rnmoTmlofnq6DlsYXlpJrjgIINCg0KMy4g6KiO6KuW5qCh5q2j5Zue5q2455qE56S+576k57ay6Lev5aaC5L2V5YiG5biDPzwvYnI+DQrku6XnpL7nvqTmlofnq6DmlbjkvobnnIvvvIzmibnoqZXlmLLoq7fnmoTntrLlj4vovIPlpJrvvIzkvYblvp7npL7nvqTntrLot6/op4Dlr5/nmbznj77vvIzlhanpgornmoTosrzmlofoqI7oq5bogbLph4/pg73lvojpq5jjgIINCg0KDQo0LiDmoKHmraPlm57mrbjnmoTmhI/opovpoJjoopbmnInoqrA/57ay5Y+L55qE5o6o5ZmT54uA5oWL5aaC5L2VPzwvYnI+DQrlm6Dngrros4fmlpnpgbjlj5bnmoTmmYLplpPovIPnn63vvIzlj6ropoHlub7nr4flm57opobph4/pq5jnmoTosrzmlofvvIzlsLHmnInmqZ/mnIPmiJDngrrnpL7nvqTkuK3lv4PvvIzlnKjlhavljabniYjkuIrvvIzku6XloLHlsI7oqI7oq5bngrrkuLvnmoTmhI/opovpoJjoopbmnIkgW2NlbnRyZTAxMzBdKGh0dHBzOi8vd3d3LnB0dC5jYy9iYnMvR29zc2lwaW5nL00uMTYyMTY3MDc2OC5BLkUxQi5odG1sKe+8jOWbnuimhuaOqOWZk+eahuacie+8jOiqv+S+g+aJueiplemDqOWIhuWJh+aciSBbaHN0Zl0oaHR0cHM6Ly93d3cucHR0LmNjL2Jicy9Hb3NzaXBpbmcvTS4xNjIxNjYzNjUzLkEuOTI1Lmh0bWwp77yM57ay5Y+L5aSn5aSa5q2j6Z2i5o6o5paH44CCDQoNCg0KDQoNCg==