目標

利用統計數據,分析以下五點:
1. 探討主客場優勢是否存在
2. 最佳進攻者與最佳防守者
3. 兩分球與三分球對勝負的影響
4. 投籃命中率高的條件
5. 個別進攻者與防守者之間的關係

library(plyr)
library(readr)
library(dplyr)
library(jiebaR)
library(tidyr)
library(tidytext)
library(igraph)
library(topicmodels)
library(stringr)
library(ggplot2)
library(jsonlite)
library(plotly)

資料來源:kaggle上的NBA shot logs資料集
https://www.kaggle.com/dansbecker/nba-shot-logs

讀入資料

records = read_csv("shot_logs.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  MATCHUP = col_character(),
  LOCATION = col_character(),
  W = col_character(),
  GAME_CLOCK = col_time(format = ""),
  SHOT_RESULT = col_character(),
  CLOSEST_DEFENDER = col_character(),
  player_name = col_character()
)
See spec(...) for full column specifications.
records

會發現 CLOSEST_DEFENDER 的名字與 player_name 的格式不一樣,因此我們先將格式統一。

# 出手球員的id與name
player_list <- records %>% select(player_name, player_id) %>% unique() %>% rename(name = player_name)

# 統一姓名格式
pro_records <- records %>% 
  separate(CLOSEST_DEFENDER, c("first_name", "last_name"), fill = "right", sep = ", ") %>% 
  unite("defender_name", last_name, first_name, sep =" ") %>%
  left_join(player_list, by = c("CLOSEST_DEFENDER_PLAYER_ID" = "player_id")) %>% 
  mutate(defender_name = ifelse(!is.na(name), name, tolower(defender_name))) %>% 
  select(-name)

shot_Data = pro_records %>%
  na.omit(shot_Data) %>%
  filter(SHOT_CLOCK!=24 & TOUCH_TIME>=0)
shot_Data$PTS_TYPE = as.factor(shot_Data$PTS_TYPE)

是否有主客場優勢

pro_records %>% 
  select(GAME_ID, LOCATION, W) %>%
  filter(LOCATION == "H") %>% 
  unique() %>% 
  arrange(GAME_ID) %>% 
  rename(WIN_OR_LOSE = W) %>% 
  group_by(WIN_OR_LOSE) %>% 
  count() %>% 
  ungroup() %>% 
  mutate(total = sum(n)) %>% 
  mutate(percent = n / total * 100) %>% 
  mutate(lab.ypos = cumsum(percent) - 0.5*percent) %>% 
  mutate(WIN_OR_LOSE = factor(WIN_OR_LOSE, levels=c("W", "L"))) %>% 
  ggplot(aes(x = "", y = percent, fill = WIN_OR_LOSE)) + 
  geom_bar(width = 1, stat = "identity", color = "white") +
  coord_polar("y", start = 0, direction = -1) +
  geom_text(aes(y = lab.ypos, label = round(percent,2)), color = "white") +
  labs(x = "", y ="") +
  theme_minimal() +
  theme(text = element_text(family = "Heiti TC Light"))

有主客場優勢存在
主場勝率55.97%
客場勝率44.03%

上場次數大於100之前10位命中率最高的球員

success_percent_Off <- shot_Data %>%
  group_by(player_name, SHOT_RESULT) %>%
  summarise(count = n()) %>%
  spread(SHOT_RESULT, count) %>% 
  mutate(made = ifelse(is.na(made), 1, made), missed = ifelse(is.na(missed), 1, missed)) %>% 
  mutate(Percent = (made/(made+missed))) %>% 
  arrange(desc(Percent)) %>% 
  rename(name = player_name) %>% 
  mutate(off_or_def = "off")
success_percent_Off

上場次數大於100之前10位成功防守率最高球員

success_percent_Def <- shot_Data %>%
  group_by(defender_name, SHOT_RESULT) %>%
  summarise(count = n()) %>%
  spread(SHOT_RESULT, count) %>% 
  mutate(made = ifelse(is.na(made), 1, made), missed = ifelse(is.na(missed), 1, missed)) %>% 
  mutate(Percent = (missed/(made+missed))) %>% 
  arrange(desc(Percent)) %>% 
  rename(name = defender_name) %>% 
  mutate(off_or_def = "def")
success_percent_Def

進攻球員進球率與防守球員成功防守率之密度曲線圖

success_percent_all <-bind_rows(success_percent_Off,success_percent_Def) %>% 
  mutate(off_or_def = factor(off_or_def, levels=c("off", "def")))
success_percent_all %>% 
  filter(made >= 100 & missed >= 100) %>% 
  ggplot(aes(x = Percent, fill = off_or_def)) + 
  geom_density(alpha = 0.5) +
  geom_vline(xintercept = c(0.5465, 0.45), color = "blue")

球員命中率與防守成功率散佈圖

g <- success_percent_Off %>% 
  left_join(success_percent_Def, by = "name") %>% 
  filter(made.x>100 & made.y>100 & missed.x>100 & missed.y>100) %>% 
  rename(off_Percent = Percent.x, def_Percent = Percent.y) %>% 
  mutate(benefit = def_Percent + off_Percent - 0.9983286) %>% 
  select(name, off_Percent, def_Percent, benefit) %>% 
  na.omit() %>% 
  ggplot(aes(label = name, x = off_Percent, y = def_Percent, color = benefit)) +
  geom_abline(color = "gray40", lty = 2, slope = 0.5457545/0.4525722) +
  geom_vline(xintercept = 0.4525722, color="orange") +
  geom_hline(yintercept = 0.5457545, color="orange") +
  geom_point(alpha = 0.3, size = 1) +
  geom_text(size = 2.5) +
  theme_minimal() +
  theme(legend.position="none") +
  labs(x = "FG%", y = "DEF%")
ggplotly(g, width = 840, height = 600)

垂直線代表出手平均命中率,水平線代表防守平均成功率。

兩分球、三分球投進/未投進數量比

shot_Data %>% 
  group_by(PTS_TYPE, SHOT_RESULT) %>% 
  summarise(total = n()) %>% 
  mutate(SHOT_RESULT = factor(SHOT_RESULT, levels=c("made", "missed"))) %>% 
  group_by(PTS_TYPE) %>% 
  mutate(percent = total/sum(total) * 100) %>% 
  mutate(lab.ypos = cumsum(percent) - 0.5*percent) %>% 
  ungroup() %>% 
  ggplot(aes(x="", y=percent, fill=SHOT_RESULT)) + 
  geom_bar(width = 1, stat = "identity", color = "white") + 
  coord_polar("y", start = 0, direction = -1) +
  geom_text(aes(y = 100-lab.ypos, label = round(percent,2)), color = "white") +
  facet_wrap(~PTS_TYPE, labeller = label_both) +
  labs(x = "", y= "") +
  theme_minimal() +
  theme(text = element_text(family = "Heiti TC Light"))

兩分球與三分球的期望值

shot_Data %>% 
  group_by(PTS_TYPE) %>%
  summarise(PTS_TYPE_EXP = mean(PTS))

三分球進球密度曲線圖

shot_Data %>% 
  filter(PTS_TYPE == "3") %>% 
  group_by(player_name) %>% 
  mutate(count = n()) %>% 
  ungroup() %>% 
  group_by(player_name, count, SHOT_RESULT) %>% 
  summarise(result = n()) %>% 
  mutate(percent = result / count) %>% 
  filter(count >= 10 & SHOT_RESULT == "made") %>% 
  arrange(desc(percent)) %>% 
  ggplot(aes(x = percent)) + 
  geom_density(fill = "blue", color = "blue", alpha = 0.4) +
  geom_vline(xintercept = 0.37)

投三分球的數量多寡對於比賽勝負的影響

two_three_points <- shot_Data %>% 
  group_by(GAME_ID, LOCATION, PTS_TYPE, W) %>%
  summarise(TOTAL_SHOT_NUM = n()) %>%
  ungroup() %>% 
  spread(PTS_TYPE, TOTAL_SHOT_NUM) %>% 
  setNames(c("GAME_ID", "LOCATION", "WIN_OR_LOSE", "PTS_TYPE_2", "PTS_TYPE_3")) %>% 
  mutate(total_shot = PTS_TYPE_2 + PTS_TYPE_3, shot3_prop = PTS_TYPE_3 / total_shot) %>% 
  na.omit()

two_three_points %>% 
  ggplot(aes(x=shot3_prop, fill = WIN_OR_LOSE)) + 
  geom_density(alpha = 0.5) +
  geom_vline(xintercept = 0.2533333, color = "#F8766D", size = 1) +
  geom_vline(xintercept = 0.2711310, color = "#00BFC4", size = 1) +
  labs(x = "三分球佔進攻的比例") +
  theme(text = element_text(family = "Heiti TC Light"))

三分球投得多的勝率高。

投三分球比例前一百的場次

two_three_points %>%
  arrange(desc(shot3_prop)) %>% 
  head(100) %>% 
  group_by(WIN_OR_LOSE) %>% 
  count() %>% 
  ungroup() %>% 
  mutate(lab.ypos = cumsum(n) - 0.5*n) %>% 
  mutate(WIN_OR_LOSE = factor(WIN_OR_LOSE, levels=c("W", "L"))) %>% 
  ggplot(aes(x = "", y = n, fill = WIN_OR_LOSE)) + 
  geom_bar(width = 1, stat = "identity", color = "white") +
  coord_polar("y", start = 0, direction = -1) +
  geom_text(aes(y = lab.ypos, label = n), color = "white") +
  labs(x = "", y ="") +
  theme_minimal() +
  theme(text = element_text(family = "Heiti TC Light"))

查看投三分球比例前一百的場次,勝率確實較高。

防守距離與命中率關係

兩分球在八英尺後,與防守距離有比較大的關係。
三分球則與防守距離有明顯關係,整體命中率還是低於兩分球。

運球次數與命中率率關係

運球次數越多,命中率越低。

投球距離與進球數的趨勢圖

shot_Data %>% 
  ggplot(aes(x=SHOT_DIST, color=SHOT_RESULT, fill=SHOT_RESULT)) + 
  geom_density(alpha = 0.3) +
  xlab("Shot Distance") + 
  ylab("") +
  theme_light()+ 
  geom_vline(xintercept = 22, color="blue") +
  geom_text(aes(x=22, label="3-point line", y=0.08), colour="blue", angle=90, vjust = -1)

距離籃框越近,命中率越高,另外也可看出,球員出手的兩個高點,分別為禁區與三分線外一步。

挑出有該年度冠軍金州勇士的球員出手紀錄

該年度總冠軍隊伍為金州勇士,我們將其球員的出手紀錄與對到的防守球員挑出來做分析。

warriors <- pro_records %>% 
  filter(str_detect(MATCHUP, "GSW ")) %>% 
  add_count(defender_name, player_name, name = "d_FG") %>% 
  group_by(defender_name, player_name, d_FG) %>% 
  summarise(d_FGM = sum(FGM)) %>% 
  filter(d_FG >= 10) %>% 
  ungroup() %>% 
  mutate(d_FGP = d_FGM/d_FG)
warriors
# 建立網路關係
was_Network <- graph_from_data_frame(d=warriors, directed=T)
# 畫出網路圖
# 線的粗細代表防守到的次數多寡
# 綠線表示防守效益優於平均
# 紅線表示防守效益差於平均
set.seed(231)
E(was_Network)$color <- ifelse(E(was_Network)$d_FGP < mean(E(was_Network)$d_FGP) , "lightgreen", "palevioletred")
E(was_Network)$width <- (E(was_Network)$d_FG/10)^1.5
plot(was_Network, vertex.size=2, edge.arrow.size=0.1, vertex.label.cex=0.7)

勇士教練Kerr在設計戰術時,球員可以多挑防守效益不佳的球員做單打,若對上防守效益好的球員則可透過傳導化解。

篩選出總出手次數大於一定次數的紀錄

選出所有球員中總出手次數大於940的球員,相對其他球員可表示他們在場上時間更多,為隊上的主力輸出。

# 篩選出總出手次數大於940的紀錄
# 挑出相遇次數大於 15 次的紀錄
count_records <- pro_records %>% 
  add_count(player_name, name = "p_count") %>% 
  filter(p_count >= 940) %>% 
  add_count(defender_name, player_name, name = "d_FG") %>% 
  group_by(defender_name, player_name, d_FG) %>% 
  summarise(d_FGM = sum(FGM)) %>% 
  filter(d_FG >= 15) %>% 
  ungroup() %>% 
  mutate(d_FGP = d_FGM/d_FG)
count_records
# 建立網路關係
count_Network <- graph_from_data_frame(d=count_records, directed=T)
# 畫出網路圖
# 線的粗細代表防守到的次數多寡
# 綠線表示防守效益優於平均
# 紅線表示防守效益差於平均
set.seed(1213)
E(count_Network)$color <- ifelse(E(count_Network)$d_FGP < mean(E(count_Network)$d_FGP) , "lightgreen", "palevioletred")
E(count_Network)$width <- E(count_Network)$d_FG/10
plot(count_Network, vertex.size=2, edge.arrow.size=0.2, vertex.label.cex=0.7)

從圖中可以看出,Westbrook在進攻時,較容易被防守者影響而投不進。
Curry 與 Harden 的表現明顯較圖中的其他人好。
但有可能因為進攻者本身命中率的高低,而使得其他球員的防守差距不明顯,所以…

防守效益比較

透過先計算出一名出手球員的總命中率,與個別球員防守時的命中率差值,
來單獨看每位防守球員在對上哪位出手球員時,有較大的防守效益。

# 出手球員總命中率
field_goal_per <- pro_records %>% 
  group_by(player_name) %>% 
  mutate(total_FGM = sum(FGM), total_FG = n()) %>% 
  mutate(total_FGP = total_FGM/total_FG) %>% 
  ungroup()
field_goal_per %>% select(defender_name, player_name, FGM, total_FGM, total_FG, total_FGP)
# 出手球員與個別防守球員相對時之命中率
pair_def_records <- field_goal_per %>% 
  select(defender_name, player_name, FGM, total_FGP) %>% 
  group_by(defender_name, player_name, total_FGP) %>% 
  summarise(def_FGM = sum(FGM), def_FG = n()) %>% 
  mutate(def_FGP = def_FGM/def_FG) %>% 
  ungroup()
pair_def_records
# 個別組合間的防守效益差距
# 挑出相遇次數大於 8 次的紀錄
# 挑出差異大於 30% 的組合
s_pair_def_records <- pair_def_records %>% 
  filter(def_FG >= 8) %>% 
  mutate(dif_FGP = def_FGP - total_FGP) %>% 
  filter(abs(dif_FGP) >= 0.3) %>% 
  select(defender_name, player_name, dif_FGP)
s_pair_def_records
# 建立網路關係
s_pair_def_Network <- graph_from_data_frame(d=s_pair_def_records, directed=T)
# 畫出網路圖
# 防守影響較大的關係:綠色
# 防守影響較小的關係:紅色
set.seed(1234)
E(s_pair_def_Network)$color <- ifelse(E(s_pair_def_Network)$dif_FGP < 0 , "lightgreen", "palevioletred")
plot(s_pair_def_Network, vertex.size=2, edge.arrow.size=0.3, vertex.label.cex=0.7)

年度最佳防守陣容

NBA每年都會由各隊總教練選出防守第一隊與第二隊,從球場上的各個位置選最適合的人選。
這裡我們找出2014-15賽季,防守第一隊與第二隊的名單,
透過在名單上各球員的防守下,出手球員命中率的差別來驗證這份名單。

年度最佳防守陣容第一隊

# 個別組合間的防守效益差距
# 挑出相遇次數的大於 3 次的紀錄
# 挑出差異大於 30% 的組合
first_team_records <- pair_def_records %>% 
  filter(defender_name == "kawhi leonard" | 
         defender_name == "draymond green" |
         defender_name == "deandre jordan" |
         defender_name == "tony allen" |
         defender_name == "chris paul") %>% 
  filter(def_FG >= 3) %>% 
  mutate(dif_FGP = def_FGP - total_FGP) %>% 
  filter(abs(dif_FGP) >= 0.3) %>% 
  select(defender_name, player_name, dif_FGP)
first_team_records
# 建立網路關係
first_team_Network <- graph_from_data_frame(d=first_team_records, directed=T)
# 畫出網路圖
# 防守影響較大的關係:綠色
# 防守影響較小的關係:紅色
set.seed(2019)
E(first_team_Network)$color <- ifelse(E(first_team_Network)$dif_FGP < 0 , "lightgreen", "palevioletred")
plot(first_team_Network, vertex.size=2, edge.arrow.size=0.3, vertex.label.cex=0.7)

由圖中可以看出,Tony Allen的防守效益特別優異,其他四位也大多是防守成功率高的。

年度最佳防守陣容第二隊

# 個別組合間的防守效益差距
# 挑出相遇次數的大於 3 次的紀錄
# 挑出差異大於 30% 的組合
second_team_records <- pair_def_records %>% 
  filter(defender_name == "anthony davis" | 
         defender_name == "tim duncan" |
         defender_name == "andrew bogut" |
         defender_name == "jimmy butler" |
         defender_name == "john wall") %>% 
  filter(def_FG >= 3) %>% 
  mutate(dif_FGP = def_FGP - total_FGP) %>% 
  filter(abs(dif_FGP) >= 0.3) %>% 
  select(defender_name, player_name, dif_FGP)
second_team_records
# 建立網路關係
second_team_Network <- graph_from_data_frame(d=second_team_records, directed=T)
# 畫出網路圖
# 防守影響較大的關係:綠色
# 防守影響較小的關係:紅色
set.seed(222)
E(second_team_Network)$color <- ifelse(E(second_team_Network)$dif_FGP < 0 , "lightgreen", "palevioletred")
plot(second_team_Network, vertex.size=2, edge.arrow.size=0.3, vertex.label.cex=0.7)

由圖中可以看出,多數球員的防守效益都很不錯,其中比較特別的是 Tim Duncan,綠線與紅線都很多,可見其防守表現起伏較大。

去除Wide Open狀態下的資料

來源資料中是每一筆的出手紀錄,故其中的防守球員只是距離出手球員最近的球員,
但球場上可能透過卡位、空切、傳球等手段來跑出空檔,此時出手球員會與防守球員拉開一段距離,
此時防守球員是誰的意義便不會那麼大,因此我們透過數據中的最近防守球員距離為依據,
將距離超過 4.92feet(=1.5公尺) 的紀錄去除,再看剛剛的年度最佳防守陣容第一隊和第二隊的紀錄。

# 挑出與防守者距離小於 4.92feet 的紀錄
no_wide_records <- pro_records %>% 
  filter(CLOSE_DEF_DIST <= 4.92)
no_wide_records
# 出手球員總命中率
n_field_goal_per <- no_wide_records %>% 
  group_by(player_name) %>% 
  mutate(total_FGM = sum(FGM), total_FG = n()) %>% 
  mutate(total_FGP = total_FGM/total_FG) %>% 
  ungroup()

# 出手球員與個別防守球員相對時之命中率
n_pair_def_records <- n_field_goal_per %>% 
  select(defender_name, player_name, FGM, total_FGP) %>% 
  group_by(defender_name, player_name, total_FGP) %>% 
  summarise(def_FGM = sum(FGM), def_FG = n()) %>% 
  mutate(def_FGP = def_FGM/def_FG) %>% 
  ungroup()
n_pair_def_records

年度最佳防守陣容第一隊(剔除wide open)

# 個別組合間的防守效益差距
# 挑出相遇次數的大於 3 次的紀錄
# 挑出差異大於 25% 的組合
n_first_team_records <- n_pair_def_records %>% 
  filter(defender_name == "kawhi leonard" | 
         defender_name == "draymond green" |
         defender_name == "deandre jordan" |
         defender_name == "tony allen" |
         defender_name == "chris paul") %>% 
  filter(def_FG >= 3) %>% 
  mutate(dif_FGP = def_FGP - total_FGP) %>% 
  filter(abs(dif_FGP) >= 0.3) %>% 
  select(defender_name, player_name, dif_FGP)
n_first_team_records
# 建立網路關係
n_first_team_Network <- graph_from_data_frame(d=n_first_team_records, directed=T)
# 畫出網路圖
# 防守影響較大的關係:綠色
# 防守影響較小的關係:紅色
set.seed(31)
E(n_first_team_Network)$color <- ifelse(E(n_first_team_Network)$dif_FGP < 0 , "lightgreen", "palevioletred")
plot(n_first_team_Network, vertex.size=2, edge.arrow.size=0.3, vertex.label.cex=0.7)

DeAndre Jordan很明顯地變差,我們研究看看他的防守紀錄。

DeAndre Jordan v.s. Tony Alllen

可以看出 DeAndre Jordan 在 4.92feet 以內的防守成功率,明顯比大於 4.92feet 的成功率低了很多。
另外將數據與 Tony Allen 比較,可以發現在 4.92feet 以內的防守成功率明顯優於 DeAndre Jordan。

年度最佳防守陣容第二隊(剔除wide open)

# 個別組合間的防守效益差距
# 挑出相遇次數的大於 3 次的紀錄
# 挑出差異大於 30% 的組合
n_second_team_records <- n_pair_def_records %>% 
  filter(defender_name == "anthony davis" |
         defender_name == "tim duncan" |
         defender_name == "andrew bogut" |
         defender_name == "jimmy butler" |
         defender_name == "john wall") %>% 
  filter(def_FG >= 3) %>% 
  mutate(dif_FGP = def_FGP - total_FGP) %>% 
  filter(abs(dif_FGP) >= 0.3) %>% 
  select(defender_name, player_name, dif_FGP)
n_second_team_records
# 建立網路關係
n_second_team_Network <- graph_from_data_frame(d=n_second_team_records, directed=T)
# 畫出網路圖
# 防守影響較大的關係:綠色
# 防守影響較小的關係:紅色
set.seed(2019)
E(n_second_team_Network)$color <- ifelse(E(n_second_team_Network)$dif_FGP < 0 , "lightgreen", "palevioletred")
plot(n_second_team_Network, vertex.size=2, edge.arrow.size=0.3, vertex.label.cex=0.7)

與沒有去除 wide open 的資料差距不大。

結論

  1. 主客場優勢確實存在。
  2. 三分球投得越多,勝率越高。
  3. 進攻者離籃框越近,命中率越高。
  4. 運球次數越少,命中率越高。
  5. 可透過網路圖看出特定防守組合之間的防守效益。
  6. 年度最佳防守陣容中,可看出部分球員實際防守影響很顯著,但也有些沒有很突出的表現。

分析這個現象產生的原因,我們認為是因為在籃球的「防守」中,並不單單只是要防守進攻者出手,還有進攻籃板、防守籃板、抄截、防守意識等等,所以若單就出手數據評斷可能不夠完整,所以我們不能以此就否定這份名單的純度,但可以懷疑一些在防守進攻者出手上效益不好的球員。

LS0tCnRpdGxlOiAiTkJB5Ye65omL5pW45pOa5YiG5p6Q6YCy5pS7LemYsuWuiOeQg+WToeS5i+mXnOS/giIKYXV0aG9yOiAi6Zmz55Co57+UIOael+aEj+WplSDnjovmvqTmgakg6JSh5a6X6Ku6IgpkYXRlOiAiMjAxOS84LzkiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMg55uu5qiZCj4g5Yip55So57Wx6KiI5pW45pOa77yM5YiG5p6Q5Lul5LiL5LqU6bue77yaPGJyPgo+IDEuIOaOouiojuS4u+WuouWgtOWEquWLouaYr+WQpuWtmOWcqDxicj4KPiAyLiDmnIDkvbPpgLLmlLvogIXoiIfmnIDkvbPpmLLlrojogIU8YnI+Cj4gMy4g5YWp5YiG55CD6IiH5LiJ5YiG55CD5bCN5Yud6LKg55qE5b2x6Z+/PGJyPgo+IDQuIOaKleexg+WRveS4reeOh+mrmOeahOaineS7tjxicj4KPiA1LiDlgIvliKXpgLLmlLvogIXoiIfpmLLlrojogIXkuYvplpPnmoTpl5zkv4I8YnI+CgpgYGB7cn0KbGlicmFyeShwbHlyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGppZWJhUikKbGlicmFyeSh0aWR5cikKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkodG9waWNtb2RlbHMpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgo+IOizh+aWmeS+hua6kO+8mmthZ2dsZeS4iueahE5CQSBzaG90IGxvZ3Pos4fmlpnpm4Y8YnI+Cj4gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYW5zYmVja2VyL25iYS1zaG90LWxvZ3MKCiMg6K6A5YWl6LOH5paZCmBgYHtyfQpyZWNvcmRzID0gcmVhZF9jc3YoInNob3RfbG9ncy5jc3YiKQpyZWNvcmRzCmBgYAo+IOacg+eZvOePviBDTE9TRVNUX0RFRkVOREVSIOeahOWQjeWtl+iIhyBwbGF5ZXJfbmFtZSDnmoTmoLzlvI/kuI3kuIDmqKPvvIzlm6DmraTmiJHlgJHlhYjlsIfmoLzlvI/ntbHkuIDjgIIKCmBgYHtyfQojIOWHuuaJi+eQg+WToeeahGlk6IiHbmFtZQpwbGF5ZXJfbGlzdCA8LSByZWNvcmRzICU+JSBzZWxlY3QocGxheWVyX25hbWUsIHBsYXllcl9pZCkgJT4lIHVuaXF1ZSgpICU+JSByZW5hbWUobmFtZSA9IHBsYXllcl9uYW1lKQoKIyDntbHkuIDlp5PlkI3moLzlvI8KcHJvX3JlY29yZHMgPC0gcmVjb3JkcyAlPiUgCiAgc2VwYXJhdGUoQ0xPU0VTVF9ERUZFTkRFUiwgYygiZmlyc3RfbmFtZSIsICJsYXN0X25hbWUiKSwgZmlsbCA9ICJyaWdodCIsIHNlcCA9ICIsICIpICU+JSAKICB1bml0ZSgiZGVmZW5kZXJfbmFtZSIsIGxhc3RfbmFtZSwgZmlyc3RfbmFtZSwgc2VwID0iICIpICU+JQogIGxlZnRfam9pbihwbGF5ZXJfbGlzdCwgYnkgPSBjKCJDTE9TRVNUX0RFRkVOREVSX1BMQVlFUl9JRCIgPSAicGxheWVyX2lkIikpICU+JSAKICBtdXRhdGUoZGVmZW5kZXJfbmFtZSA9IGlmZWxzZSghaXMubmEobmFtZSksIG5hbWUsIHRvbG93ZXIoZGVmZW5kZXJfbmFtZSkpKSAlPiUgCiAgc2VsZWN0KC1uYW1lKQoKc2hvdF9EYXRhID0gcHJvX3JlY29yZHMgJT4lCiAgbmEub21pdChzaG90X0RhdGEpICU+JQogIGZpbHRlcihTSE9UX0NMT0NLIT0yNCAmIFRPVUNIX1RJTUU+PTApCnNob3RfRGF0YSRQVFNfVFlQRSA9IGFzLmZhY3RvcihzaG90X0RhdGEkUFRTX1RZUEUpCmBgYAoKCiMg5piv5ZCm5pyJ5Li75a6i5aC05YSq5YuiCmBgYHtyfQpwcm9fcmVjb3JkcyAlPiUgCiAgc2VsZWN0KEdBTUVfSUQsIExPQ0FUSU9OLCBXKSAlPiUKICBmaWx0ZXIoTE9DQVRJT04gPT0gIkgiKSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIGFycmFuZ2UoR0FNRV9JRCkgJT4lIAogIHJlbmFtZShXSU5fT1JfTE9TRSA9IFcpICU+JSAKICBncm91cF9ieShXSU5fT1JfTE9TRSkgJT4lIAogIGNvdW50KCkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHRvdGFsID0gc3VtKG4pKSAlPiUgCiAgbXV0YXRlKHBlcmNlbnQgPSBuIC8gdG90YWwgKiAxMDApICU+JSAKICBtdXRhdGUobGFiLnlwb3MgPSBjdW1zdW0ocGVyY2VudCkgLSAwLjUqcGVyY2VudCkgJT4lIAogIG11dGF0ZShXSU5fT1JfTE9TRSA9IGZhY3RvcihXSU5fT1JfTE9TRSwgbGV2ZWxzPWMoIlciLCAiTCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gcGVyY2VudCwgZmlsbCA9IFdJTl9PUl9MT1NFKSkgKyAKICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCwgZGlyZWN0aW9uID0gLTEpICsKICBnZW9tX3RleHQoYWVzKHkgPSBsYWIueXBvcywgbGFiZWwgPSByb3VuZChwZXJjZW50LDIpKSwgY29sb3IgPSAid2hpdGUiKSArCiAgbGFicyh4ID0gIiIsIHkgPSIiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKQpgYGAKPiDmnInkuLvlrqLloLTlhKrli6LlrZjlnKg8YnI+Cj4g5Li75aC05Yud546HNTUuOTclPGJyPgo+IOWuouWgtOWLneeOhzQ0LjAzJQoKIyDkuIrloLTmrKHmlbjlpKfmlrwxMDDkuYvliY0xMOS9jeWRveS4reeOh+acgOmrmOeahOeQg+WToQpgYGB7cn0Kc3VjY2Vzc19wZXJjZW50X09mZiA8LSBzaG90X0RhdGEgJT4lCiAgZ3JvdXBfYnkocGxheWVyX25hbWUsIFNIT1RfUkVTVUxUKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQogIHNwcmVhZChTSE9UX1JFU1VMVCwgY291bnQpICU+JSAKICBtdXRhdGUobWFkZSA9IGlmZWxzZShpcy5uYShtYWRlKSwgMSwgbWFkZSksIG1pc3NlZCA9IGlmZWxzZShpcy5uYShtaXNzZWQpLCAxLCBtaXNzZWQpKSAlPiUgCiAgbXV0YXRlKFBlcmNlbnQgPSAobWFkZS8obWFkZSttaXNzZWQpKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhQZXJjZW50KSkgJT4lIAogIHJlbmFtZShuYW1lID0gcGxheWVyX25hbWUpICU+JSAKICBtdXRhdGUob2ZmX29yX2RlZiA9ICJvZmYiKQpzdWNjZXNzX3BlcmNlbnRfT2ZmCmBgYAoKIyDkuIrloLTmrKHmlbjlpKfmlrwxMDDkuYvliY0xMOS9jeaIkOWKn+mYsuWuiOeOh+acgOmrmOeQg+WToQpgYGB7cn0Kc3VjY2Vzc19wZXJjZW50X0RlZiA8LSBzaG90X0RhdGEgJT4lCiAgZ3JvdXBfYnkoZGVmZW5kZXJfbmFtZSwgU0hPVF9SRVNVTFQpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lCiAgc3ByZWFkKFNIT1RfUkVTVUxULCBjb3VudCkgJT4lIAogIG11dGF0ZShtYWRlID0gaWZlbHNlKGlzLm5hKG1hZGUpLCAxLCBtYWRlKSwgbWlzc2VkID0gaWZlbHNlKGlzLm5hKG1pc3NlZCksIDEsIG1pc3NlZCkpICU+JSAKICBtdXRhdGUoUGVyY2VudCA9IChtaXNzZWQvKG1hZGUrbWlzc2VkKSkpICU+JSAKICBhcnJhbmdlKGRlc2MoUGVyY2VudCkpICU+JSAKICByZW5hbWUobmFtZSA9IGRlZmVuZGVyX25hbWUpICU+JSAKICBtdXRhdGUob2ZmX29yX2RlZiA9ICJkZWYiKQpzdWNjZXNzX3BlcmNlbnRfRGVmCmBgYAoKIyDpgLLmlLvnkIPlk6HpgLLnkIPnjofoiIfpmLLlrojnkIPlk6HmiJDlip/pmLLlrojnjofkuYvlr4bluqbmm7Lnt5rlnJYKYGBge3J9CnN1Y2Nlc3NfcGVyY2VudF9hbGwgPC1iaW5kX3Jvd3Moc3VjY2Vzc19wZXJjZW50X09mZixzdWNjZXNzX3BlcmNlbnRfRGVmKSAlPiUgCiAgbXV0YXRlKG9mZl9vcl9kZWYgPSBmYWN0b3Iob2ZmX29yX2RlZiwgbGV2ZWxzPWMoIm9mZiIsICJkZWYiKSkpCnN1Y2Nlc3NfcGVyY2VudF9hbGwgJT4lIAogIGZpbHRlcihtYWRlID49IDEwMCAmIG1pc3NlZCA+PSAxMDApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBQZXJjZW50LCBmaWxsID0gb2ZmX29yX2RlZikpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygwLjU0NjUsIDAuNDUpLCBjb2xvciA9ICJibHVlIikKYGBgCgojIOeQg+WToeWRveS4reeOh+iIh+mYsuWuiOaIkOWKn+eOh+aVo+S9iOWclgpgYGB7cn0KZyA8LSBzdWNjZXNzX3BlcmNlbnRfT2ZmICU+JSAKICBsZWZ0X2pvaW4oc3VjY2Vzc19wZXJjZW50X0RlZiwgYnkgPSAibmFtZSIpICU+JSAKICBmaWx0ZXIobWFkZS54PjEwMCAmIG1hZGUueT4xMDAgJiBtaXNzZWQueD4xMDAgJiBtaXNzZWQueT4xMDApICU+JSAKICByZW5hbWUob2ZmX1BlcmNlbnQgPSBQZXJjZW50LngsIGRlZl9QZXJjZW50ID0gUGVyY2VudC55KSAlPiUgCiAgbXV0YXRlKGJlbmVmaXQgPSBkZWZfUGVyY2VudCArIG9mZl9QZXJjZW50IC0gMC45OTgzMjg2KSAlPiUgCiAgc2VsZWN0KG5hbWUsIG9mZl9QZXJjZW50LCBkZWZfUGVyY2VudCwgYmVuZWZpdCkgJT4lIAogIG5hLm9taXQoKSAlPiUgCiAgZ2dwbG90KGFlcyhsYWJlbCA9IG5hbWUsIHggPSBvZmZfUGVyY2VudCwgeSA9IGRlZl9QZXJjZW50LCBjb2xvciA9IGJlbmVmaXQpKSArCiAgZ2VvbV9hYmxpbmUoY29sb3IgPSAiZ3JheTQwIiwgbHR5ID0gMiwgc2xvcGUgPSAwLjU0NTc1NDUvMC40NTI1NzIyKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC40NTI1NzIyLCBjb2xvcj0ib3JhbmdlIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNTQ1NzU0NSwgY29sb3I9Im9yYW5nZSIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC4zLCBzaXplID0gMSkgKwogIGdlb21fdGV4dChzaXplID0gMi41KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgbGFicyh4ID0gIkZHJSIsIHkgPSAiREVGJSIpCmdncGxvdGx5KGcsIHdpZHRoID0gODQwLCBoZWlnaHQgPSA2MDApCmBgYAo+IOWeguebtOe3muS7o+ihqOWHuuaJi+W5s+Wdh+WRveS4reeOh++8jOawtOW5s+e3muS7o+ihqOmYsuWuiOW5s+Wdh+aIkOWKn+eOh+OAggoKIyDlhanliIbnkIPjgIHkuInliIbnkIPmipXpgLIv5pyq5oqV6YCy5pW46YeP5q+UCmBgYHtyfQpzaG90X0RhdGEgJT4lIAogIGdyb3VwX2J5KFBUU19UWVBFLCBTSE9UX1JFU1VMVCkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSkgJT4lIAogIG11dGF0ZShTSE9UX1JFU1VMVCA9IGZhY3RvcihTSE9UX1JFU1VMVCwgbGV2ZWxzPWMoIm1hZGUiLCAibWlzc2VkIikpKSAlPiUgCiAgZ3JvdXBfYnkoUFRTX1RZUEUpICU+JSAKICBtdXRhdGUocGVyY2VudCA9IHRvdGFsL3N1bSh0b3RhbCkgKiAxMDApICU+JSAKICBtdXRhdGUobGFiLnlwb3MgPSBjdW1zdW0ocGVyY2VudCkgLSAwLjUqcGVyY2VudCkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ2dwbG90KGFlcyh4PSIiLCB5PXBlcmNlbnQsIGZpbGw9U0hPVF9SRVNVTFQpKSArIAogIGdlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gIndoaXRlIikgKyAKICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCwgZGlyZWN0aW9uID0gLTEpICsKICBnZW9tX3RleHQoYWVzKHkgPSAxMDAtbGFiLnlwb3MsIGxhYmVsID0gcm91bmQocGVyY2VudCwyKSksIGNvbG9yID0gIndoaXRlIikgKwogIGZhY2V0X3dyYXAoflBUU19UWVBFLCBsYWJlbGxlciA9IGxhYmVsX2JvdGgpICsKICBsYWJzKHggPSAiIiwgeT0gIiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlaXRpIFRDIExpZ2h0IikpCmBgYAoKIyDlhanliIbnkIPoiIfkuInliIbnkIPnmoTmnJ/mnJvlgLwKYGBge3J9CnNob3RfRGF0YSAlPiUgCiAgZ3JvdXBfYnkoUFRTX1RZUEUpICU+JQogIHN1bW1hcmlzZShQVFNfVFlQRV9FWFAgPSBtZWFuKFBUUykpCmBgYAoKIyDkuInliIbnkIPpgLLnkIPlr4bluqbmm7Lnt5rlnJYKYGBge3J9CnNob3RfRGF0YSAlPiUgCiAgZmlsdGVyKFBUU19UWVBFID09ICIzIikgJT4lIAogIGdyb3VwX2J5KHBsYXllcl9uYW1lKSAlPiUgCiAgbXV0YXRlKGNvdW50ID0gbigpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShwbGF5ZXJfbmFtZSwgY291bnQsIFNIT1RfUkVTVUxUKSAlPiUgCiAgc3VtbWFyaXNlKHJlc3VsdCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjZW50ID0gcmVzdWx0IC8gY291bnQpICU+JSAKICBmaWx0ZXIoY291bnQgPj0gMTAgJiBTSE9UX1JFU1VMVCA9PSAibWFkZSIpICU+JSAKICBhcnJhbmdlKGRlc2MocGVyY2VudCkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBwZXJjZW50KSkgKyAKICBnZW9tX2RlbnNpdHkoZmlsbCA9ICJibHVlIiwgY29sb3IgPSAiYmx1ZSIsIGFscGhhID0gMC40KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4zNykKYGBgCgoKIyDmipXkuInliIbnkIPnmoTmlbjph4/lpJrlr6HlsI3mlrzmr5Tos73li53osqDnmoTlvbHpn78KYGBge3J9CnR3b190aHJlZV9wb2ludHMgPC0gc2hvdF9EYXRhICU+JSAKICBncm91cF9ieShHQU1FX0lELCBMT0NBVElPTiwgUFRTX1RZUEUsIFcpICU+JQogIHN1bW1hcmlzZShUT1RBTF9TSE9UX05VTSA9IG4oKSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBzcHJlYWQoUFRTX1RZUEUsIFRPVEFMX1NIT1RfTlVNKSAlPiUgCiAgc2V0TmFtZXMoYygiR0FNRV9JRCIsICJMT0NBVElPTiIsICJXSU5fT1JfTE9TRSIsICJQVFNfVFlQRV8yIiwgIlBUU19UWVBFXzMiKSkgJT4lIAogIG11dGF0ZSh0b3RhbF9zaG90ID0gUFRTX1RZUEVfMiArIFBUU19UWVBFXzMsIHNob3QzX3Byb3AgPSBQVFNfVFlQRV8zIC8gdG90YWxfc2hvdCkgJT4lIAogIG5hLm9taXQoKQoKdHdvX3RocmVlX3BvaW50cyAlPiUgCiAgZ2dwbG90KGFlcyh4PXNob3QzX3Byb3AsIGZpbGwgPSBXSU5fT1JfTE9TRSkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4yNTMzMzMzLCBjb2xvciA9ICIjRjg3NjZEIiwgc2l6ZSA9IDEpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjI3MTEzMTAsIGNvbG9yID0gIiMwMEJGQzQiLCBzaXplID0gMSkgKwogIGxhYnMoeCA9ICLkuInliIbnkIPkvZTpgLLmlLvnmoTmr5TkvosiKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVpdGkgVEMgTGlnaHQiKSkKYGBgCj4g5LiJ5YiG55CD5oqV5b6X5aSa55qE5Yud546H6auY44CCCgojIOaKleS4ieWIhueQg+avlOS+i+WJjeS4gOeZvueahOWgtOasoQpgYGB7cn0KdHdvX3RocmVlX3BvaW50cyAlPiUKICBhcnJhbmdlKGRlc2Moc2hvdDNfcHJvcCkpICU+JSAKICBoZWFkKDEwMCkgJT4lIAogIGdyb3VwX2J5KFdJTl9PUl9MT1NFKSAlPiUgCiAgY291bnQoKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUobGFiLnlwb3MgPSBjdW1zdW0obikgLSAwLjUqbikgJT4lIAogIG11dGF0ZShXSU5fT1JfTE9TRSA9IGZhY3RvcihXSU5fT1JfTE9TRSwgbGV2ZWxzPWMoIlciLCAiTCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gbiwgZmlsbCA9IFdJTl9PUl9MT1NFKSkgKyAKICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCwgZGlyZWN0aW9uID0gLTEpICsKICBnZW9tX3RleHQoYWVzKHkgPSBsYWIueXBvcywgbGFiZWwgPSBuKSwgY29sb3IgPSAid2hpdGUiKSArCiAgbGFicyh4ID0gIiIsIHkgPSIiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKQpgYGAKPiDmn6XnnIvmipXkuInliIbnkIPmr5TkvovliY3kuIDnmb7nmoTloLTmrKHvvIzli53njofnorrlr6bovIPpq5jjgIIKCiMg6Ziy5a6I6Led6Zui6IiH5ZG95Lit546H6Zec5L+CCmBgYHtyfQpzaG90X0RhdGEgJT4lCiAgbXV0YXRlKGRlZl9kaXN0YW5jZSA9IENMT1NFX0RFRl9ESVNUICsgMSkgJT4lICMgCiAgZ3JvdXBfYnkoZGVmX2Rpc3RhbmNlLCBQVFNfVFlQRSkgJT4lCiAgc3VtbWFyaXNlKFBlcmNlbnQgPSBtZWFuKEZHTSkpICU+JQogIGdncGxvdChhZXMoeCA9IGxvZyhkZWZfZGlzdGFuY2UsIGJhc2UgPSAyKSwgeSA9IFBlcmNlbnQpKSArIAogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIG1ldGhvZCA9ICJsb2VzcyIsIGZvcm11bGEgPSAneSB+IHgnKSArIAogIGZhY2V0X2dyaWQoLiB+IFBUU19UWVBFLCBsYWJlbGxlciA9IGxhYmVsX2JvdGgpICsgCiAgdGhlbWVfbGluZWRyYXcoKQpgYGAKPiDlhanliIbnkIPlnKjlhavoi7HlsLrlvozvvIzoiIfpmLLlrojot53pm6LmnInmr5TovIPlpKfnmoTpl5zkv4LjgII8YnI+Cj4g5LiJ5YiG55CD5YmH6IiH6Ziy5a6I6Led6Zui5pyJ5piO6aGv6Zec5L+C77yM5pW06auU5ZG95Lit546H6YKE5piv5L2O5pa85YWp5YiG55CD44CCCgojIOmBi+eQg+asoeaVuOiIh+WRveS4reeOh+eOh+mXnOS/ggpgYGB7cn0Kc2hvdF9EYXRhICU+JQogIGdyb3VwX2J5KERSSUJCTEVTKSAlPiUKICBzdW1tYXJpc2UoUGVyY2VudCA9IG1lYW4oRkdNKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRFJJQkJMRVMsIHkgPSBQZXJjZW50KSkgKyAKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBtZXRob2QgPSAibG9lc3MiLCBmb3JtdWxhID0gJ3kgfiB4JykgKyAKICB0aGVtZV9saW5lZHJhdygpCmBgYAo+IOmBi+eQg+asoeaVuOi2iuWkmu+8jOWRveS4reeOh+i2iuS9juOAggoKIyDmipXnkIPot53pm6LoiIfpgLLnkIPmlbjnmoTotqjli6LlnJYKYGBge3J9CnNob3RfRGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4PVNIT1RfRElTVCwgY29sb3I9U0hPVF9SRVNVTFQsIGZpbGw9U0hPVF9SRVNVTFQpKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMykgKwogIHhsYWIoIlNob3QgRGlzdGFuY2UiKSArIAogIHlsYWIoIiIpICsKICB0aGVtZV9saWdodCgpKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMiwgY29sb3I9ImJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyh4PTIyLCBsYWJlbD0iMy1wb2ludCBsaW5lIiwgeT0wLjA4KSwgY29sb3VyPSJibHVlIiwgYW5nbGU9OTAsIHZqdXN0ID0gLTEpCmBgYAo+IOi3nembouexg+ahhui2iui/ke+8jOWRveS4reeOh+i2iumrmO+8jOWPpuWkluS5n+WPr+eci+WHuu+8jOeQg+WToeWHuuaJi+eahOWFqeWAi+mrmOm7nu+8jOWIhuWIpeeCuuemgeWNgOiIh+S4ieWIhue3muWkluS4gOatpeOAggoKIyDmjJHlh7rmnInoqbLlubTluqblhqDou43ph5Hlt57li4flo6vnmoTnkIPlk6Hlh7rmiYvntIDpjIQKPiDoqbLlubTluqbnuL3lhqDou43pmorkvI3ngrrph5Hlt57li4flo6vvvIzmiJHlgJHlsIflhbbnkIPlk6HnmoTlh7rmiYvntIDpjIToiIflsI3liLDnmoTpmLLlrojnkIPlk6HmjJHlh7rkvoblgZrliIbmnpDjgIIKCmBgYHtyfQp3YXJyaW9ycyA8LSBwcm9fcmVjb3JkcyAlPiUgCiAgZmlsdGVyKHN0cl9kZXRlY3QoTUFUQ0hVUCwgIkdTVyAiKSkgJT4lIAogIGFkZF9jb3VudChkZWZlbmRlcl9uYW1lLCBwbGF5ZXJfbmFtZSwgbmFtZSA9ICJkX0ZHIikgJT4lIAogIGdyb3VwX2J5KGRlZmVuZGVyX25hbWUsIHBsYXllcl9uYW1lLCBkX0ZHKSAlPiUgCiAgc3VtbWFyaXNlKGRfRkdNID0gc3VtKEZHTSkpICU+JSAKICBmaWx0ZXIoZF9GRyA+PSAxMCkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKGRfRkdQID0gZF9GR00vZF9GRykKd2FycmlvcnMKYGBgCgpgYGB7cn0KIyDlu7rnq4vntrLot6/pl5zkv4IKd2FzX05ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGQ9d2FycmlvcnMsIGRpcmVjdGVkPVQpCiMg55Wr5Ye657ay6Lev5ZyWCiMg57ea55qE57KX57Sw5Luj6KGo6Ziy5a6I5Yiw55qE5qyh5pW45aSa5a+hCiMg57ag57ea6KGo56S66Ziy5a6I5pWI55uK5YSq5pa85bmz5Z2HCiMg57SF57ea6KGo56S66Ziy5a6I5pWI55uK5beu5pa85bmz5Z2HCnNldC5zZWVkKDIzMSkKRSh3YXNfTmV0d29yaykkY29sb3IgPC0gaWZlbHNlKEUod2FzX05ldHdvcmspJGRfRkdQIDwgbWVhbihFKHdhc19OZXR3b3JrKSRkX0ZHUCkgLCAibGlnaHRncmVlbiIsICJwYWxldmlvbGV0cmVkIikKRSh3YXNfTmV0d29yaykkd2lkdGggPC0gKEUod2FzX05ldHdvcmspJGRfRkcvMTApXjEuNQpwbG90KHdhc19OZXR3b3JrLCB2ZXJ0ZXguc2l6ZT0yLCBlZGdlLmFycm93LnNpemU9MC4xLCB2ZXJ0ZXgubGFiZWwuY2V4PTAuNykKYGBgCj4g5YuH5aOr5pWZ57e0S2VycuWcqOioreioiOaIsOihk+aZgu+8jOeQg+WToeWPr+S7peWkmuaMkemYsuWuiOaViOebiuS4jeS9s+eahOeQg+WToeWBmuWWruaJk++8jOiLpeWwjeS4iumYsuWuiOaViOebiuWlveeahOeQg+WToeWJh+WPr+mAj+mBjuWCs+WwjuWMluino+OAggoKIyMg56+p6YG45Ye657i95Ye65omL5qyh5pW45aSn5pa85LiA5a6a5qyh5pW455qE57SA6YyECj4g6YG45Ye65omA5pyJ55CD5ZOh5Lit57i95Ye65omL5qyh5pW45aSn5pa8OTQw55qE55CD5ZOh77yM55u45bCN5YW25LuW55CD5ZOh5Y+v6KGo56S65LuW5YCR5Zyo5aC05LiK5pmC6ZaT5pu05aSa77yM54K66ZqK5LiK55qE5Li75Yqb6Ly45Ye644CCCgpgYGB7cn0KIyDnr6npgbjlh7rnuL3lh7rmiYvmrKHmlbjlpKfmlrw5NDDnmoTntIDpjIQKIyDmjJHlh7rnm7jpgYfmrKHmlbjlpKfmlrwgMTUg5qyh55qE57SA6YyECmNvdW50X3JlY29yZHMgPC0gcHJvX3JlY29yZHMgJT4lIAogIGFkZF9jb3VudChwbGF5ZXJfbmFtZSwgbmFtZSA9ICJwX2NvdW50IikgJT4lIAogIGZpbHRlcihwX2NvdW50ID49IDk0MCkgJT4lIAogIGFkZF9jb3VudChkZWZlbmRlcl9uYW1lLCBwbGF5ZXJfbmFtZSwgbmFtZSA9ICJkX0ZHIikgJT4lIAogIGdyb3VwX2J5KGRlZmVuZGVyX25hbWUsIHBsYXllcl9uYW1lLCBkX0ZHKSAlPiUgCiAgc3VtbWFyaXNlKGRfRkdNID0gc3VtKEZHTSkpICU+JSAKICBmaWx0ZXIoZF9GRyA+PSAxNSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKGRfRkdQID0gZF9GR00vZF9GRykKY291bnRfcmVjb3JkcwpgYGAKCmBgYHtyfQojIOW7uueri+e2sui3r+mXnOS/ggpjb3VudF9OZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPWNvdW50X3JlY29yZHMsIGRpcmVjdGVkPVQpCiMg55Wr5Ye657ay6Lev5ZyWCiMg57ea55qE57KX57Sw5Luj6KGo6Ziy5a6I5Yiw55qE5qyh5pW45aSa5a+hCiMg57ag57ea6KGo56S66Ziy5a6I5pWI55uK5YSq5pa85bmz5Z2HCiMg57SF57ea6KGo56S66Ziy5a6I5pWI55uK5beu5pa85bmz5Z2HCnNldC5zZWVkKDEyMTMpCkUoY291bnRfTmV0d29yaykkY29sb3IgPC0gaWZlbHNlKEUoY291bnRfTmV0d29yaykkZF9GR1AgPCBtZWFuKEUoY291bnRfTmV0d29yaykkZF9GR1ApICwgImxpZ2h0Z3JlZW4iLCAicGFsZXZpb2xldHJlZCIpCkUoY291bnRfTmV0d29yaykkd2lkdGggPC0gRShjb3VudF9OZXR3b3JrKSRkX0ZHLzEwCnBsb3QoY291bnRfTmV0d29yaywgdmVydGV4LnNpemU9MiwgZWRnZS5hcnJvdy5zaXplPTAuMiwgdmVydGV4LmxhYmVsLmNleD0wLjcpCmBgYAohW10oY291bnRfcmVzdWx0LnBuZykKCj4g5b6e5ZyW5Lit5Y+v5Lul55yL5Ye677yMV2VzdGJyb29r5Zyo6YCy5pS75pmC77yM6LyD5a655piT6KKr6Ziy5a6I6ICF5b2x6Z+/6ICM5oqV5LiN6YCy44CCPGJyPgo+IEN1cnJ5IOiIhyBIYXJkZW4g55qE6KGo54++5piO6aGv6LyD5ZyW5Lit55qE5YW25LuW5Lq65aW944CCPGJyPgo+IOS9huacieWPr+iDveWboOeCuumAsuaUu+iAheacrOi6q+WRveS4reeOh+eahOmrmOS9ju+8jOiAjOS9v+W+l+WFtuS7lueQg+WToeeahOmYsuWuiOW3rui3neS4jeaYjumhr++8jOaJgOS7pS4uLgoKIyDpmLLlrojmlYjnm4rmr5TovIMKPiDpgI/pgY7lhYjoqIjnrpflh7rkuIDlkI3lh7rmiYvnkIPlk6HnmoTnuL3lkb3kuK3njofvvIzoiIflgIvliKXnkIPlk6HpmLLlrojmmYLnmoTlkb3kuK3njoflt67lgLzvvIw8YnI+Cj4g5L6G5Zau542o55yL5q+P5L2N6Ziy5a6I55CD5ZOh5Zyo5bCN5LiK5ZOq5L2N5Ye65omL55CD5ZOh5pmC77yM5pyJ6LyD5aSn55qE6Ziy5a6I5pWI55uK44CCCgpgYGB7cn0KIyDlh7rmiYvnkIPlk6HnuL3lkb3kuK3njocKZmllbGRfZ29hbF9wZXIgPC0gcHJvX3JlY29yZHMgJT4lIAogIGdyb3VwX2J5KHBsYXllcl9uYW1lKSAlPiUgCiAgbXV0YXRlKHRvdGFsX0ZHTSA9IHN1bShGR00pLCB0b3RhbF9GRyA9IG4oKSkgJT4lIAogIG11dGF0ZSh0b3RhbF9GR1AgPSB0b3RhbF9GR00vdG90YWxfRkcpICU+JSAKICB1bmdyb3VwKCkKZmllbGRfZ29hbF9wZXIgJT4lIHNlbGVjdChkZWZlbmRlcl9uYW1lLCBwbGF5ZXJfbmFtZSwgRkdNLCB0b3RhbF9GR00sIHRvdGFsX0ZHLCB0b3RhbF9GR1ApCmBgYAoKYGBge3J9CiMg5Ye65omL55CD5ZOh6IiH5YCL5Yil6Ziy5a6I55CD5ZOh55u45bCN5pmC5LmL5ZG95Lit546HCnBhaXJfZGVmX3JlY29yZHMgPC0gZmllbGRfZ29hbF9wZXIgJT4lIAogIHNlbGVjdChkZWZlbmRlcl9uYW1lLCBwbGF5ZXJfbmFtZSwgRkdNLCB0b3RhbF9GR1ApICU+JSAKICBncm91cF9ieShkZWZlbmRlcl9uYW1lLCBwbGF5ZXJfbmFtZSwgdG90YWxfRkdQKSAlPiUgCiAgc3VtbWFyaXNlKGRlZl9GR00gPSBzdW0oRkdNKSwgZGVmX0ZHID0gbigpKSAlPiUgCiAgbXV0YXRlKGRlZl9GR1AgPSBkZWZfRkdNL2RlZl9GRykgJT4lIAogIHVuZ3JvdXAoKQpwYWlyX2RlZl9yZWNvcmRzCmBgYAoKYGBge3J9CiMg5YCL5Yil57WE5ZCI6ZaT55qE6Ziy5a6I5pWI55uK5beu6LedCiMg5oyR5Ye655u46YGH5qyh5pW45aSn5pa8IDgg5qyh55qE57SA6YyECiMg5oyR5Ye65beu55Ww5aSn5pa8IDMwJSDnmoTntYTlkIgKc19wYWlyX2RlZl9yZWNvcmRzIDwtIHBhaXJfZGVmX3JlY29yZHMgJT4lIAogIGZpbHRlcihkZWZfRkcgPj0gOCkgJT4lIAogIG11dGF0ZShkaWZfRkdQID0gZGVmX0ZHUCAtIHRvdGFsX0ZHUCkgJT4lIAogIGZpbHRlcihhYnMoZGlmX0ZHUCkgPj0gMC4zKSAlPiUgCiAgc2VsZWN0KGRlZmVuZGVyX25hbWUsIHBsYXllcl9uYW1lLCBkaWZfRkdQKQpzX3BhaXJfZGVmX3JlY29yZHMKYGBgCgpgYGB7cn0KIyDlu7rnq4vntrLot6/pl5zkv4IKc19wYWlyX2RlZl9OZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPXNfcGFpcl9kZWZfcmVjb3JkcywgZGlyZWN0ZWQ9VCkKIyDnlavlh7rntrLot6/lnJYKIyDpmLLlrojlvbHpn7/ovIPlpKfnmoTpl5zkv4LvvJrntqDoibIKIyDpmLLlrojlvbHpn7/ovIPlsI/nmoTpl5zkv4LvvJrntIXoibIKc2V0LnNlZWQoMTIzNCkKRShzX3BhaXJfZGVmX05ldHdvcmspJGNvbG9yIDwtIGlmZWxzZShFKHNfcGFpcl9kZWZfTmV0d29yaykkZGlmX0ZHUCA8IDAgLCAibGlnaHRncmVlbiIsICJwYWxldmlvbGV0cmVkIikKcGxvdChzX3BhaXJfZGVmX05ldHdvcmssIHZlcnRleC5zaXplPTIsIGVkZ2UuYXJyb3cuc2l6ZT0wLjMsIHZlcnRleC5sYWJlbC5jZXg9MC43KQpgYGAKIVtdKHJlc3VsdDEucG5nKQoKIyDlubTluqbmnIDkvbPpmLLlrojpmaPlrrkKPiBOQkHmr4/lubTpg73mnIPnlLHlkITpmornuL3mlZnnt7Tpgbjlh7rpmLLlrojnrKzkuIDpmoroiIfnrKzkuozpmorvvIzlvp7nkIPloLTkuIrnmoTlkITlgIvkvY3nva7pgbjmnIDpganlkIjnmoTkurrpgbjjgII8YnI+Cj4g6YCZ6KOh5oiR5YCR5om+5Ye6MjAxNC0xNeizveWto++8jOmYsuWuiOesrOS4gOmaiuiIh+esrOS6jOmaiueahOWQjeWWru+8jDxicj4KPiDpgI/pgY7lnKjlkI3llq7kuIrlkITnkIPlk6HnmoTpmLLlrojkuIvvvIzlh7rmiYvnkIPlk6Hlkb3kuK3njofnmoTlt67liKXkvobpqZforYnpgJnku73lkI3llq7jgIIKCiMjIOW5tOW6puacgOS9s+mYsuWuiOmZo+WuueesrOS4gOmaigo8aW1nIHNyYz0iLi9maXJzdF90ZWFtLnBuZyIgd2lkdGg9IjQwJSIgLz4KCmBgYHtyfQojIOWAi+WIpee1hOWQiOmWk+eahOmYsuWuiOaViOebiuW3rui3nQojIOaMkeWHuuebuOmBh+asoeaVuOeahOWkp+aWvCAzIOasoeeahOe0gOmMhAojIOaMkeWHuuW3rueVsOWkp+aWvCAzMCUg55qE57WE5ZCICmZpcnN0X3RlYW1fcmVjb3JkcyA8LSBwYWlyX2RlZl9yZWNvcmRzICU+JSAKICBmaWx0ZXIoZGVmZW5kZXJfbmFtZSA9PSAia2F3aGkgbGVvbmFyZCIgfCAKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAiZHJheW1vbmQgZ3JlZW4iIHwKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAiZGVhbmRyZSBqb3JkYW4iIHwKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAidG9ueSBhbGxlbiIgfAogICAgICAgICBkZWZlbmRlcl9uYW1lID09ICJjaHJpcyBwYXVsIikgJT4lIAogIGZpbHRlcihkZWZfRkcgPj0gMykgJT4lIAogIG11dGF0ZShkaWZfRkdQID0gZGVmX0ZHUCAtIHRvdGFsX0ZHUCkgJT4lIAogIGZpbHRlcihhYnMoZGlmX0ZHUCkgPj0gMC4zKSAlPiUgCiAgc2VsZWN0KGRlZmVuZGVyX25hbWUsIHBsYXllcl9uYW1lLCBkaWZfRkdQKQpmaXJzdF90ZWFtX3JlY29yZHMKYGBgCgpgYGB7cn0KIyDlu7rnq4vntrLot6/pl5zkv4IKZmlyc3RfdGVhbV9OZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkPWZpcnN0X3RlYW1fcmVjb3JkcywgZGlyZWN0ZWQ9VCkKIyDnlavlh7rntrLot6/lnJYKIyDpmLLlrojlvbHpn7/ovIPlpKfnmoTpl5zkv4LvvJrntqDoibIKIyDpmLLlrojlvbHpn7/ovIPlsI/nmoTpl5zkv4LvvJrntIXoibIKc2V0LnNlZWQoMjAxOSkKRShmaXJzdF90ZWFtX05ldHdvcmspJGNvbG9yIDwtIGlmZWxzZShFKGZpcnN0X3RlYW1fTmV0d29yaykkZGlmX0ZHUCA8IDAgLCAibGlnaHRncmVlbiIsICJwYWxldmlvbGV0cmVkIikKcGxvdChmaXJzdF90ZWFtX05ldHdvcmssIHZlcnRleC5zaXplPTIsIGVkZ2UuYXJyb3cuc2l6ZT0wLjMsIHZlcnRleC5sYWJlbC5jZXg9MC43KQpgYGAKIVtdKGZpcnN0X3RlYW1fcmVzdWx0LnBuZykKCj4g55Sx5ZyW5Lit5Y+v5Lul55yL5Ye677yMVG9ueSBBbGxlbueahOmYsuWuiOaViOebiueJueWIpeWEqueVsO+8jOWFtuS7luWbm+S9jeS5n+Wkp+WkmuaYr+mYsuWuiOaIkOWKn+eOh+mrmOeahOOAggoKIyMg5bm05bqm5pyA5L2z6Ziy5a6I6Zmj5a6556ys5LqM6ZqKCjxpbWcgc3JjPSIuL3NlY29uZF90ZWFtLnBuZyIgd2lkdGg9IjQwJSIgLz4KCmBgYHtyfQojIOWAi+WIpee1hOWQiOmWk+eahOmYsuWuiOaViOebiuW3rui3nQojIOaMkeWHuuebuOmBh+asoeaVuOeahOWkp+aWvCAzIOasoeeahOe0gOmMhAojIOaMkeWHuuW3rueVsOWkp+aWvCAzMCUg55qE57WE5ZCICnNlY29uZF90ZWFtX3JlY29yZHMgPC0gcGFpcl9kZWZfcmVjb3JkcyAlPiUgCiAgZmlsdGVyKGRlZmVuZGVyX25hbWUgPT0gImFudGhvbnkgZGF2aXMiIHwgCiAgICAgICAgIGRlZmVuZGVyX25hbWUgPT0gInRpbSBkdW5jYW4iIHwKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAiYW5kcmV3IGJvZ3V0IiB8CiAgICAgICAgIGRlZmVuZGVyX25hbWUgPT0gImppbW15IGJ1dGxlciIgfAogICAgICAgICBkZWZlbmRlcl9uYW1lID09ICJqb2huIHdhbGwiKSAlPiUgCiAgZmlsdGVyKGRlZl9GRyA+PSAzKSAlPiUgCiAgbXV0YXRlKGRpZl9GR1AgPSBkZWZfRkdQIC0gdG90YWxfRkdQKSAlPiUgCiAgZmlsdGVyKGFicyhkaWZfRkdQKSA+PSAwLjMpICU+JSAKICBzZWxlY3QoZGVmZW5kZXJfbmFtZSwgcGxheWVyX25hbWUsIGRpZl9GR1ApCnNlY29uZF90ZWFtX3JlY29yZHMKYGBgCgpgYGB7cn0KIyDlu7rnq4vntrLot6/pl5zkv4IKc2Vjb25kX3RlYW1fTmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZD1zZWNvbmRfdGVhbV9yZWNvcmRzLCBkaXJlY3RlZD1UKQojIOeVq+WHuue2sui3r+WclgojIOmYsuWuiOW9semfv+i8g+Wkp+eahOmXnOS/gu+8mue2oOiJsgojIOmYsuWuiOW9semfv+i8g+Wwj+eahOmXnOS/gu+8mue0heiJsgpzZXQuc2VlZCgyMjIpCkUoc2Vjb25kX3RlYW1fTmV0d29yaykkY29sb3IgPC0gaWZlbHNlKEUoc2Vjb25kX3RlYW1fTmV0d29yaykkZGlmX0ZHUCA8IDAgLCAibGlnaHRncmVlbiIsICJwYWxldmlvbGV0cmVkIikKcGxvdChzZWNvbmRfdGVhbV9OZXR3b3JrLCB2ZXJ0ZXguc2l6ZT0yLCBlZGdlLmFycm93LnNpemU9MC4zLCB2ZXJ0ZXgubGFiZWwuY2V4PTAuNykKYGBgCiFbXShzZWNvbmRfdGVhbV9yZXN1bHQucG5nKQoKPiDnlLHlnJbkuK3lj6/ku6XnnIvlh7rvvIzlpJrmlbjnkIPlk6HnmoTpmLLlrojmlYjnm4rpg73lvojkuI3pjK/vvIzlhbbkuK3mr5TovIPnibnliKXnmoTmmK8gVGltIER1bmNhbu+8jOe2oOe3muiIh+e0hee3mumDveW+iOWkmu+8jOWPr+imi+WFtumYsuWuiOihqOePvui1t+S8j+i8g+Wkp+OAggoKIyMg5Y676ZmkV2lkZSBPcGVu54uA5oWL5LiL55qE6LOH5paZCj4g5L6G5rqQ6LOH5paZ5Lit5piv5q+P5LiA562G55qE5Ye65omL57SA6YyE77yM5pWF5YW25Lit55qE6Ziy5a6I55CD5ZOh5Y+q5piv6Led6Zui5Ye65omL55CD5ZOh5pyA6L+R55qE55CD5ZOh77yMPGJyPgo+IOS9hueQg+WgtOS4iuWPr+iDvemAj+mBjuWNoeS9jeOAgeepuuWIh+OAgeWCs+eQg+etieaJi+auteS+hui3keWHuuepuuaqlO+8jOatpOaZguWHuuaJi+eQg+WToeacg+iIh+mYsuWuiOeQg+WToeaLiemWi+S4gOautei3nembou+8jDxicj4KPiDmraTmmYLpmLLlrojnkIPlk6HmmK/oqrDnmoTmhI/nvqnkvr/kuI3mnIPpgqPpurzlpKfvvIzlm6DmraTmiJHlgJHpgI/pgY7mlbjmk5rkuK3nmoTmnIDov5HpmLLlrojnkIPlk6Hot53pm6Lngrrkvp3mk5rvvIw8YnI+Cj4g5bCH6Led6Zui6LaF6YGOIDQuOTJmZWV0KD0xLjXlhazlsLopIOeahOe0gOmMhOWOu+mZpO+8jOWGjeeci+WJm+WJm+eahOW5tOW6puacgOS9s+mYsuWuiOmZo+WuueesrOS4gOmaiuWSjOesrOS6jOmaiueahOe0gOmMhOOAggoKYGBge3J9CiMg5oyR5Ye66IiH6Ziy5a6I6ICF6Led6Zui5bCP5pa8IDQuOTJmZWV0IOeahOe0gOmMhApub193aWRlX3JlY29yZHMgPC0gcHJvX3JlY29yZHMgJT4lIAogIGZpbHRlcihDTE9TRV9ERUZfRElTVCA8PSA0LjkyKQpub193aWRlX3JlY29yZHMKYGBgCgpgYGB7cn0KIyDlh7rmiYvnkIPlk6HnuL3lkb3kuK3njocKbl9maWVsZF9nb2FsX3BlciA8LSBub193aWRlX3JlY29yZHMgJT4lIAogIGdyb3VwX2J5KHBsYXllcl9uYW1lKSAlPiUgCiAgbXV0YXRlKHRvdGFsX0ZHTSA9IHN1bShGR00pLCB0b3RhbF9GRyA9IG4oKSkgJT4lIAogIG11dGF0ZSh0b3RhbF9GR1AgPSB0b3RhbF9GR00vdG90YWxfRkcpICU+JSAKICB1bmdyb3VwKCkKCiMg5Ye65omL55CD5ZOh6IiH5YCL5Yil6Ziy5a6I55CD5ZOh55u45bCN5pmC5LmL5ZG95Lit546HCm5fcGFpcl9kZWZfcmVjb3JkcyA8LSBuX2ZpZWxkX2dvYWxfcGVyICU+JSAKICBzZWxlY3QoZGVmZW5kZXJfbmFtZSwgcGxheWVyX25hbWUsIEZHTSwgdG90YWxfRkdQKSAlPiUgCiAgZ3JvdXBfYnkoZGVmZW5kZXJfbmFtZSwgcGxheWVyX25hbWUsIHRvdGFsX0ZHUCkgJT4lIAogIHN1bW1hcmlzZShkZWZfRkdNID0gc3VtKEZHTSksIGRlZl9GRyA9IG4oKSkgJT4lIAogIG11dGF0ZShkZWZfRkdQID0gZGVmX0ZHTS9kZWZfRkcpICU+JSAKICB1bmdyb3VwKCkKbl9wYWlyX2RlZl9yZWNvcmRzCmBgYAoKIyMg5bm05bqm5pyA5L2z6Ziy5a6I6Zmj5a6556ys5LiA6ZqKKOWJlOmZpHdpZGUgb3BlbikKYGBge3J9CiMg5YCL5Yil57WE5ZCI6ZaT55qE6Ziy5a6I5pWI55uK5beu6LedCiMg5oyR5Ye655u46YGH5qyh5pW455qE5aSn5pa8IDMg5qyh55qE57SA6YyECiMg5oyR5Ye65beu55Ww5aSn5pa8IDI1JSDnmoTntYTlkIgKbl9maXJzdF90ZWFtX3JlY29yZHMgPC0gbl9wYWlyX2RlZl9yZWNvcmRzICU+JSAKICBmaWx0ZXIoZGVmZW5kZXJfbmFtZSA9PSAia2F3aGkgbGVvbmFyZCIgfCAKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAiZHJheW1vbmQgZ3JlZW4iIHwKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAiZGVhbmRyZSBqb3JkYW4iIHwKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAidG9ueSBhbGxlbiIgfAogICAgICAgICBkZWZlbmRlcl9uYW1lID09ICJjaHJpcyBwYXVsIikgJT4lIAogIGZpbHRlcihkZWZfRkcgPj0gMykgJT4lIAogIG11dGF0ZShkaWZfRkdQID0gZGVmX0ZHUCAtIHRvdGFsX0ZHUCkgJT4lIAogIGZpbHRlcihhYnMoZGlmX0ZHUCkgPj0gMC4zKSAlPiUgCiAgc2VsZWN0KGRlZmVuZGVyX25hbWUsIHBsYXllcl9uYW1lLCBkaWZfRkdQKQpuX2ZpcnN0X3RlYW1fcmVjb3JkcwpgYGAKCmBgYHtyfQojIOW7uueri+e2sui3r+mXnOS/ggpuX2ZpcnN0X3RlYW1fTmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZD1uX2ZpcnN0X3RlYW1fcmVjb3JkcywgZGlyZWN0ZWQ9VCkKIyDnlavlh7rntrLot6/lnJYKIyDpmLLlrojlvbHpn7/ovIPlpKfnmoTpl5zkv4LvvJrntqDoibIKIyDpmLLlrojlvbHpn7/ovIPlsI/nmoTpl5zkv4LvvJrntIXoibIKc2V0LnNlZWQoMzEpCkUobl9maXJzdF90ZWFtX05ldHdvcmspJGNvbG9yIDwtIGlmZWxzZShFKG5fZmlyc3RfdGVhbV9OZXR3b3JrKSRkaWZfRkdQIDwgMCAsICJsaWdodGdyZWVuIiwgInBhbGV2aW9sZXRyZWQiKQpwbG90KG5fZmlyc3RfdGVhbV9OZXR3b3JrLCB2ZXJ0ZXguc2l6ZT0yLCBlZGdlLmFycm93LnNpemU9MC4zLCB2ZXJ0ZXgubGFiZWwuY2V4PTAuNykKYGBgCiFbXShmaXJzdF90ZWFtX3Jlc3VsdDIucG5nKQoKPiBEZUFuZHJlIEpvcmRhbuW+iOaYjumhr+WcsOiuiuW3ru+8jOaIkeWAkeeglOeptueci+eci+S7lueahOmYsuWuiOe0gOmMhOOAggoKIyMgRGVBbmRyZSBKb3JkYW4gdi5zLiBUb255IEFsbGxlbgpgYGB7cn0KcHJvX3JlY29yZHMgJT4lIAogIGZpbHRlcihkZWZlbmRlcl9uYW1lICVpbiUgYygiZGVhbmRyZSBqb3JkYW4iLCAidG9ueSBhbGxlbiIpKSAlPiUKICBmaWx0ZXIoQ0xPU0VfREVGX0RJU1QgPD0gMjUpICU+JSAKICBncm91cF9ieShkZWZlbmRlcl9uYW1lLCBDTE9TRV9ERUZfRElTVCwgU0hPVF9SRVNVTFQpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdyb3VwX2J5KGRlZmVuZGVyX25hbWUsIENMT1NFX0RFRl9ESVNUKSAlPiUgCiAgbXV0YXRlKHRvdGFsID0gc3VtKGNvdW50KSkgJT4lIAogIGZpbHRlcihTSE9UX1JFU1VMVCA9PSAibWlzc2VkIikgJT4lIAogIG11dGF0ZShwZXIgPSBjb3VudC90b3RhbCkgJT4lIAogIGdncGxvdChhZXMoeCA9IENMT1NFX0RFRl9ESVNULCB5ID0gcGVyLCBncm91cCA9IGRlZmVuZGVyX25hbWUpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGZvcm11bGEgPSAieSB+IHgiLCBzZSA9IEZBTFNFKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNC45MiwgY29sb3IgPSAiYmx1ZSIpICsgCiAgZmFjZXRfZ3JpZCh+ZGVmZW5kZXJfbmFtZSkgKwogIGxhYnMoeCA9ICLoiIfmlLvmk4rogIXnmoTot53pm6IiLCB5ID0gIumYsuWuiOaIkOWKn+eOhyIpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWl0aSBUQyBMaWdodCIpKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDE1KSkKYGBgCj4g5Y+v5Lul55yL5Ye6IERlQW5kcmUgSm9yZGFuIOWcqCA0LjkyZmVldCDku6XlhafnmoTpmLLlrojmiJDlip/njofvvIzmmI7poa/mr5TlpKfmlrwgNC45MmZlZXQg55qE5oiQ5Yqf546H5L2O5LqG5b6I5aSa44CCPGJyPgo+IOWPpuWkluWwh+aVuOaTmuiIhyBUb255IEFsbGVuIOavlOi8g++8jOWPr+S7peeZvOePvuWcqCA0LjkyZmVldCDku6XlhafnmoTpmLLlrojmiJDlip/njofmmI7poa/lhKrmlrwgRGVBbmRyZSBKb3JkYW7jgIIKCiMjIOW5tOW6puacgOS9s+mYsuWuiOmZo+WuueesrOS6jOmaiijliZTpmaR3aWRlIG9wZW4pCmBgYHtyfQojIOWAi+WIpee1hOWQiOmWk+eahOmYsuWuiOaViOebiuW3rui3nQojIOaMkeWHuuebuOmBh+asoeaVuOeahOWkp+aWvCAzIOasoeeahOe0gOmMhAojIOaMkeWHuuW3rueVsOWkp+aWvCAzMCUg55qE57WE5ZCICm5fc2Vjb25kX3RlYW1fcmVjb3JkcyA8LSBuX3BhaXJfZGVmX3JlY29yZHMgJT4lIAogIGZpbHRlcihkZWZlbmRlcl9uYW1lID09ICJhbnRob255IGRhdmlzIiB8CiAgICAgICAgIGRlZmVuZGVyX25hbWUgPT0gInRpbSBkdW5jYW4iIHwKICAgICAgICAgZGVmZW5kZXJfbmFtZSA9PSAiYW5kcmV3IGJvZ3V0IiB8CiAgICAgICAgIGRlZmVuZGVyX25hbWUgPT0gImppbW15IGJ1dGxlciIgfAogICAgICAgICBkZWZlbmRlcl9uYW1lID09ICJqb2huIHdhbGwiKSAlPiUgCiAgZmlsdGVyKGRlZl9GRyA+PSAzKSAlPiUgCiAgbXV0YXRlKGRpZl9GR1AgPSBkZWZfRkdQIC0gdG90YWxfRkdQKSAlPiUgCiAgZmlsdGVyKGFicyhkaWZfRkdQKSA+PSAwLjMpICU+JSAKICBzZWxlY3QoZGVmZW5kZXJfbmFtZSwgcGxheWVyX25hbWUsIGRpZl9GR1ApCm5fc2Vjb25kX3RlYW1fcmVjb3JkcwpgYGAKCmBgYHtyfQojIOW7uueri+e2sui3r+mXnOS/ggpuX3NlY29uZF90ZWFtX05ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGQ9bl9zZWNvbmRfdGVhbV9yZWNvcmRzLCBkaXJlY3RlZD1UKQojIOeVq+WHuue2sui3r+WclgojIOmYsuWuiOW9semfv+i8g+Wkp+eahOmXnOS/gu+8mue2oOiJsgojIOmYsuWuiOW9semfv+i8g+Wwj+eahOmXnOS/gu+8mue0heiJsgpzZXQuc2VlZCgyMDE5KQpFKG5fc2Vjb25kX3RlYW1fTmV0d29yaykkY29sb3IgPC0gaWZlbHNlKEUobl9zZWNvbmRfdGVhbV9OZXR3b3JrKSRkaWZfRkdQIDwgMCAsICJsaWdodGdyZWVuIiwgInBhbGV2aW9sZXRyZWQiKQpwbG90KG5fc2Vjb25kX3RlYW1fTmV0d29yaywgdmVydGV4LnNpemU9MiwgZWRnZS5hcnJvdy5zaXplPTAuMywgdmVydGV4LmxhYmVsLmNleD0wLjcpCmBgYAohW10oc2Vjb25kX3RlYW1fcmVzdWx0Mi5wbmcpCgo+IOiIh+aykuacieWOu+mZpCB3aWRlIG9wZW4g55qE6LOH5paZ5beu6Led5LiN5aSn44CCIAoKIyDntZDoq5YKPiAxLiDkuLvlrqLloLTlhKrli6Lnorrlr6blrZjlnKjjgII8YnI+Cj4gMi4g5LiJ5YiG55CD5oqV5b6X6LaK5aSa77yM5Yud546H6LaK6auY44CCPGJyPgo+IDMuIOmAsuaUu+iAhembouexg+ahhui2iui/ke+8jOWRveS4reeOh+i2iumrmOOAgjxicj4KPiA0LiDpgYvnkIPmrKHmlbjotorlsJHvvIzlkb3kuK3njofotorpq5jjgII8YnI+Cj4gNS4g5Y+v6YCP6YGO57ay6Lev5ZyW55yL5Ye654m55a6a6Ziy5a6I57WE5ZCI5LmL6ZaT55qE6Ziy5a6I5pWI55uK44CCPGJyPgo+IDYuIOW5tOW6puacgOS9s+mYsuWuiOmZo+WuueS4re+8jOWPr+eci+WHuumDqOWIhueQg+WToeWvpumam+mYsuWuiOW9semfv+W+iOmhr+iRl++8jOS9huS5n+acieS6m+aykuacieW+iOeqgeWHuueahOihqOePvuOAgjxicj4KCj4g5YiG5p6Q6YCZ5YCL54++6LGh55Si55Sf55qE5Y6f5Zug77yM5oiR5YCR6KqN54K65piv5Zug54K65Zyo57GD55CD55qE44CM6Ziy5a6I44CN5Lit77yM5Lim5LiN5Zau5Zau5Y+q5piv6KaB6Ziy5a6I6YCy5pS76ICF5Ye65omL77yM6YKE5pyJ6YCy5pS757GD5p2/44CB6Ziy5a6I57GD5p2/44CB5oqE5oiq44CB6Ziy5a6I5oSP6K2Y562J562J77yM5omA5Lul6Iul5Zau5bCx5Ye65omL5pW45pOa6KmV5pa35Y+v6IO95LiN5aSg5a6M5pW077yM5omA5Lul5oiR5YCR5LiN6IO95Lul5q2k5bCx5ZCm5a6a6YCZ5Lu95ZCN5Zau55qE57SU5bqm77yM5L2G5Y+v5Lul5oe355aR5LiA5Lqb5Zyo6Ziy5a6I6YCy5pS76ICF5Ye65omL5LiK5pWI55uK5LiN5aW955qE55CD5ZOh44CCCgoKCgoKCg==