1 Tóm tắt

Khi phân tích hơn 13 nghìn thông tin tuyển dụng trong 8 năm qua tại trang VUFO , chúng tôi thấy một số xu hướng như sau:

  • Trừ Hà Nội và Sài Gòn, 5 tỉnh tuyển dụng nhiều việc nhất là: Thanh Hóa, Điện Biện, Đà Nẵng, Cao Bằng, Yên Bái.
  • Tháng tuyển dụng nhiều nhất là tháng 8; tháng tuyển dụng ít nhất là tháng 1 và tháng 2;
  • Các vị trí được tuyển dụng nhiều nhất là: tư vấn, project officer, trợ lý dự án, quản lý dự án, điều phối viên, đánh giá dự án, đào tạo, tài chính.
  • 5 nhà tuyển dụng lớn nhất là World Vision , SNV , Save the Children , Oxfam và CARE.

2 Giới thiệu

VUFO-NGO Resource Centre là một nguồn thông tin rất quen thuộc đối với các tổ chức và cá nhân làm việc trong lĩnh vực tư vấn cho các dự án phát triển.

Trừ một số tổ chức lớn có cổng đấu thầu riêng như ADB, WB thì hầu hết các nhà tài trợ tại Việt Nam đều đăng tải tuyển dụng trên trang Web này. Công việc đăng tại NGO Center khá đa dạng gồm cả nhân viên dài hạn cho dự án hoặc nhà tài trợ, tư vấn cá nhân và các gói thầu cỡ vừa và nhỏ.

Tại GFD chúng tôi cũng thường xuyên sử dụng trang VUFO-NGO để tìm kiếm các công việc mới. Để có một cái nhìn tốt hơn về số lượng công việc theo nhà tài trợ, theo ngành nghề chúng tôi làm một “nghiên cứu bỏ túi” về chủ đề này. Nghiên cứu này thực hiện bởi bộ phận phân tích dữ liệu của GFD (GFD Analytics Section ). Công cụ sử dụng là phần mềm R, gồm một số bước chính như sau:

  • Sử dụng RCurl phân tích cấu trúc html của VUFO-NGO Resource Centre
  • Lần lượt quét và tải dữ liệu jobs từ 2009-2018
  • Làm sạch và lưu thành các thuộc tính quan trọng (jobs name, donors, date, location)
  • Dữ liệu đã làm sạch có thể tải từ địa chỉ https://github.com/hoangvietanh/NGO_Job_R/blob/master/NGO-Jobs-v4.csv
  • Thực hiện một số tính toán đơn giản như số đếm job theo năm, số job theo nhà tài trợ, đếm từ khóa để thống kê ngành nghề
  • Vẽ đồ thị dùng ggplot2, và một số công cụ xử lý khác trong gói tidyverse,

Một vài con số ban đầu như sau:

  • Công việc sớm nhất mà hệ thống còn lưu lại được đăng tải vào ngày 14/08/2009, do tổ chức VSO tuyển dụng: Administrative and Financial Support Officer .
  • Tổng số công việc là 13,720, trung bình mỗi ngày có 4.4 việc được đăng lên hệ thống.
  • Tổng số tổ chức đã đăng tuyển dụng là 1629. Tuy nhiên có rất nhiều tổ chức chỉ đăng tuyển 1 lần, hoặc tên nhà tuyển dụng là tên dự án, do đó không thống kê được vào một tổ chức cụ thể. Nếu chỉ tính những tổ chức có đăng tuyển dụng 5 lần trở lên thì số lượng chỉ còn 370; đăng trên 10 tuyển dụng là 240 tổ chức; trên 20 tuyển dụng là 100 tổ chức.
rm(list = ls())
library(tidyverse)
library(magrittr)
library(lubridate)
library(stringr)
library(highcharter)
job <- read.csv("D:/GFD_GIT/NGO-Jobs-v4.csv")

thoi_gian <- function(x) {
  x %>% 
    str_sub(start = 6, end = 16) %>% 
    ymd() %>% 
    return()
}


job %<>% mutate(time = thoi_gian(deadline), 
                nam = year(time), 
                org_name = as.character(org_name))

# Có một số tổ chức sử dụng hai tên khác nhau do đó cần rename
# lại tên cho chúng (đoạn codes bổ sung ngày 11 / 03): 

# rename_org <- function(x) {
#   ELSE <- TRUE
#   case_when(x == "GIZ BiO Forestry Project" ~ "GIZ", 
#             str_detect(x, "SNV") ~ "SNV - Netherlands Development Organisation", 
#             ELSE ~ x)
# }
# 
# 
# job %<>% mutate(org_name = rename_org(org_name))
job %<>% filter(nam %in% c(2009:2017))

# Top 30 tổ chức có nhiều việc nhất: 

# top30 <- job %>% 
#   group_by(org_name) %>% 
#   count() %>%
#   ungroup() %>% 
#   arrange(-n) %>% 
#   mutate_if(is.factor, character) %>% 
#   slice(1:30) 


top30 <- job %>%
  group_by(org_name) %>%
  count() %>%
  ungroup() %>%
  arrange(-n) %>%
  mutate_if(is.factor, character) %>%
  slice(1:30)
job %>% 
  group_by(nam) %>% 
  count() %>% 
  ungroup()-> job_by_year


# highchart() %>% 
#   hc_xAxis(categories = job_by_year$nam) %>% 
#   hc_add_series(data = job_by_year$n, 
#                 showInLegend = FALSE, 
#                 type = "column", 
#                 color = "#104E8B") %>% 
#   hc_title(text = "The Number of Jobs from 2009 to 2017") %>% 
#   hc_credits(enabled = TRUE,
#              text = "Data Source: http://www.ngocentre.org.vn",  
#              style = list(fontSize = "12px")) %>% 
#   hc_tooltip(valueDecimals = 0, 
#              pointFormat = "Number: {point.y}") %>% 
#   hc_add_theme(hc_theme_538())

3 Phân bổ việc làm theo nhà tuyển dụng

5 nhà tuyển dụng có số lượng công việc nhiều nhất là: World Vision , SNV , Save the Children , Oxfam và CARE. Tổng số công việc của 5 tổ chức này là 3071 việc chiếm 22% tổng số đăng tuyển.

Đồ thị dưới đây trình bầy số lượng tuyển dụng của 30 NGOs có lượng tuyển dụng lớn. Tổng số công việc của 30 tổ chức này là 5473 - chiếm 40% tất cả các công việc được đăng tải.Đây là một sự tập trung rất lớn so với tổng số hơn 1600 tổ chức có thông báo đăng tuyển việc làm. Tuy nhiên như đã nói ở trên, có rất nhiều công việc được đăng lên dưới tên dự án, đối với những trường hợp này chúng ta sẽ không có thông tin chính xác về nhà tài trợ.

Sau top 5 nhà tuyển dụng thì WWF, ActionAid, UNDP, ENV, PlanInternational cũng là những tổ chức có lượng tuyển dụng lớn. JICA, mặc dù là một nhà tài trợ rất lớn nhưng hầu như không có đăng tuyển ở đây, giống như ADB và WB, JICA có hệ thống tuyển dụng riêng.

# highchart() %>%
#   hc_xAxis(categories = top30$org_name) %>%
#   hc_add_series(data = top30$n,
#                 showInLegend = FALSE,
#                 type = "column",
#                 color = "#104E8B") %>%
#   hc_title(text = "Top 30 NGOs with The largest Number of Jobs from 2009 to 2017") %>%
#   hc_credits(enabled = TRUE,
#              text = "Data Source: http://www.ngocentre.org.vn",
#              style = list(fontSize = "12px")) %>%
#   hc_tooltip(valueDecimals = 0,
#              pointFormat = "Number: {point.y}") %>%
#   hc_add_theme(hc_theme_538())

u <- job %>% 
  group_by(org_name) %>% 
  count() %>%
  ungroup() %>% 
  arrange(-n)


# u$org_name %>% unique() %>% length()
#u$n[1:20] %>% sum() / u$n %>% sum()



highchart() %>%
  hc_xAxis(categories = top30$org_name[1:20]) %>% 
  hc_add_series(name = "Number of Jobs", 
                data = top30$n[1:20], 
                color = "#104E8B", 
                showInLegend = FALSE) %>% 
  hc_chart(type = "bar", options2d = list(enabled = TRUE, beta = 1, alpha = 1)) %>% 
  hc_title(text = "Top 20 NGOs with The largest Number of Jobs from 2009 to 2017") %>% 
  hc_credits(enabled = TRUE,
             text = "Data Source: http://www.ngocentre.org.vn",  
             style = list(fontSize = "12px")) %>% 
  hc_add_theme(hc_theme_538())

4 Phân bổ việc làm theo năm

Ngoại trừ năm 2009 chỉ có số liệu từ tháng 8, từ 2010 số lượng công việc có xu hướng tăng nhẹ cho tới năm 2015, tuy nhiên mức tăng không nhiều. Từ 2015 đến 2017 số lượng công việc có xu hướng giảm nhẹ.

# Top 5 tổ chức có nhiều việc nhất: 
top30$org_name[1:5] -> top5_org

job %<>% mutate(org_name2 = case_when(org_name %in% top5_org ~ org_name, 
                                      !org_name %in% top5_org ~ "Others"))


org_rename <- function(x) {
  case_when(x == top5_org[1] ~ "SNV", 
            x == top5_org[2] ~ "World Vision", 
            x == top5_org[5] ~ "CARE", 
            !x %in% top5_org[c(1, 2, 5)] ~ x)
}



job %>% 
  group_by(org_name2, nam) %>% 
  count() %>% 
  ungroup() -> top_5_cong1

top_5_cong1$org_name2 <- org_rename(top_5_cong1$org_name2)

# top_5_cong1 %>% 
#   ggplot(aes(nam, n, fill = org_name2)) + 
#   geom_col(position = "stack")


top_5_cong1 %>% 
  hchart(hcaes(nam, n, group = org_name2), type = "column", showInLegend = TRUE) %>% 
  hc_plotOptions(series = list(stacking = "normal")) %>% 
  hc_add_theme(hc_theme_sandsignika()) %>% 
  hc_yAxis(title = list(text = "")) %>% 
  hc_xAxis(title = list(text = "")) %>% 
  hc_title(text = "The Number of Jobs from 2009 to 2017") %>% 
  hc_credits(enabled = TRUE,
             text = "Data Source: http://www.ngocentre.org.vn",  
             style = list(fontSize = "12px"))

5 Phân bố về việc làm được tuyển dụng theo tháng của các NGOs

Số lượng công việc được tuyển dụng thường sẽ không cao vào tháng 1 và 2 dương lịch. Đây cũng là thời điểm giáp tết Nguyên Đán. Số lượng công việc được tuyển thường đạt đỉnh cao vào tháng 8 sau đó giảm dần cho đến cuối năm và hai tháng của năm mới kế tiếp:

job %<>% mutate(thang = month(time, label = TRUE, abbr = TRUE))

job_thang_nam <- job %>% 
  group_by(nam, thang) %>% 
  count() %>% 
  ungroup() %>% 
  arrange(thang)

# job_thang_nam %>% 
#   ggplot(aes(thang, n)) + 
#   geom_col() + 
#   facet_wrap(~ nam, scales = "free")


# Việc theo thời gian là tháng - năm: 
# highchart() %>% 
#   hc_add_series(name = "Year of 2010", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2010) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2011", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2011) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2012", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2012) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2013", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2013) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2014", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2014) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2015", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2015) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2016", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2016) %>% pull(n)) %>% 
#   hc_add_series(name = "Year of 2017", 
#                 showInLegend = FALSE, 
#                 data = job_thang_nam %>% filter(nam == 2017) %>% pull(n)) %>% 
#   hc_xAxis(categories = job_thang_nam$thang %>% unique()) %>% 
#   hc_add_theme(hc_theme_538()) %>% 
#   hc_yAxis(title = list(text = "Number of Recruited Jobs")) %>% 
#   hc_title(text = "The Number of Jobs from 2010 to 2017 by Month and Year") %>%
#   hc_subtitle(text = "Data Source: http://www.ngocentre.org.vn")
job %>% 
  group_by(thang) %>% 
  count() -> viec_thang


highchart() %>% 
  hc_add_series(data = round(viec_thang %>% pull(n) / 9, 0), showInLegend = FALSE) %>% 
  hc_add_theme(hc_theme_538()) %>% 
  hc_yAxis(title = list(text = " ")) %>% 
  hc_xAxis(categories = viec_thang$thang %>% unique()) %>% 
  hc_title(text = "Average Jobs by Month") %>%
  hc_subtitle(text = "Data Source: http://www.ngocentre.org.vn")
# Danh sách 10 NGOs có nhiều việc nhất: 

top10_ngo <- top30$org_name[1:10]

# job %>% 
#   filter(org_name %in% top10_ngo) %>% 
#   group_by(org_name, thang) %>% 
#   count() %>% 
#   ungroup() %>% 
#   ggplot(aes(thang, n)) + 
#   geom_col() +
#   facet_wrap(~ org_name, scales = "free")

job %>% 
  filter(org_name %in% top10_ngo) %>% 
  group_by(org_name, thang) %>% 
  count() %>% 
  ungroup() -> top10_by_month

ten_top10 <- top10_by_month$org_name %>% unique()


# highchart() %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[1]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[1]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[2]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[2]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[3]) %>% pull(n),
#               showInLegend = FALSE, name = ten_top10[3]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[4]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[4]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[5]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[5]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[6]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[6]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[7]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[7]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[8]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[8]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[9]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[9]) %>%
#   hc_add_series(data = top10_by_month %>% filter(org_name == ten_top10[10]) %>% pull(n),
#                 showInLegend = FALSE, name = ten_top10[10]) %>%
#   hc_xAxis(categories = top10_by_month$thang %>% unique()) %>%
#   hc_yAxis(title = list(text = "Number of Recruited Jobs")) %>%
#   hc_title(text = "The Number of Jobs from 2010 to 2017 by Month for top 10 NGOs") %>%
#   hc_subtitle(text = "Data Source: http://www.ngocentre.org.vn") %>%
#   hc_add_theme(hc_theme_538())
# Đoạn mới về word cloud: 


# library(wordcloud)

rename_job_title <- function(x) {
  x <- str_to_lower(x)
  x %>% 
    str_replace_all("programme", "program") %>% 
    str_replace_all("consultancy|consultants", "consultant") %>% 
    str_replace_all("project|international|national|program", "")
  
}


# set.seed(291989)
# wordcloud(job$job_name %>% rename_job_title(), 
#           max.words = 100, 
#           random.order = FALSE, 
#           rot.per = 0.35, 
#           font = 4,
#           colors = brewer.pal(8, "Dark2"))

6 Nhóm công việc được tuyển dụng phổ biến nhất

Để thống kê nhóm công việc chúng tôi sử dụng công cụ đếm từ của gói TM. Gói này cho phép làm sạch, bỏ bớt các từ nối và hợp nhất các từ có cùng gốc (ví dụ số ít, số nhiều, các thời khác nhau của động từ). Đây chưa hẳn là cách phù hợp nhất để phân loại công việc theo ngành nghề, chúng tôi chỉ đơn giản đưa ra danh sách một số từ khóa được nhắc đến nhiều nhất trong tiêu đề công việc.

Nhóm các công việc liên quan đến tư vấn (Consultant), Quản lí (Manager), Hỗ trợ (Assistant), Officer và phát triển (Development) là nhóm 5 công việc chiếm tỉ trọng lớn nhất (hơn 26%). Bạn có thể click vào Word Cloud ở dưới để xem số lượng từ được thống kê.

library(tm)


Corpus(VectorSource(job$job_name %>% rename_job_title())) %>% 
  tm_map(removeWords, c("for", "and", "the", "vietnam", "conduct")) %>% 
  TermDocumentMatrix() -> dtm


m <- as.matrix(dtm)
v <- sort(rowSums(m), decreasing = TRUE)
d <- data.frame(word = names(v), freq = v)


library(wordcloud2)


# top_job <- d %>% filter(freq >= 50, word != d$word[7])
# top_job$freq[1:5] %>% sum / top_job$freq %>% sum()

top_job <- d %>% filter(word != d$word[7])

set.seed(1)
wordcloud2(top_job, 
           color = "random-light", 
           backgroundColor = "black", 
           size = 0.7)
top_job %>% 
  slice(1:20) %>% 
  mutate(word = str_to_upper(word)) %>% 
  ggplot(aes(reorder(word, freq), freq)) + 
  geom_col() + 
  coord_flip() + 
  geom_text(aes(label = freq), hjust = 1.1, color = "white", size = 3) + 
  theme_minimal() + 
  labs(x = NULL, y = NULL, 
       title = "20 Most Popular Jobs", 
       caption = "Data Source: http://www.ngocentre.org.vn")

# d %>% 
#   slice(1:20) %>% 
#   mutate(word = str_to_upper(word)) %>% 
#   ggplot(aes(reorder(word, freq), freq)) + 
#   geom_col() + 
#   geom_text(aes(label = freq), hjust = 1.1, color = "white", size = 4) + 
#   coord_flip() + 
#   theme_minimal() + 
#   theme(axis.title.x = element_blank(),
#         axis.text.x = element_blank(),
#         axis.ticks.x = element_blank()) + 
#   labs(x = NULL, y = NULL, 
#        title = "The Most Recruited Jobs by NGOs", 
#        caption = "Data Source: http://www.ngocentre.org.vn")

7 Địa điểm của công việc được tuyển dụng

Hà Nội và Thành Phố Hồ Chí Minh chiếm 67.4% tổng số công việc được tuyển dụng của các NGOs với số công việc được tuyển dụng lần lượt là 6123 và 979. Có thể thấy không chỉ có sự mất cân bằng về số lượng công việc được tuyển của hai thành phố lớn này so với phần còn lại và còn có sự bất đối xứng lớn giữa hai địa điểm có nhiều công việc được đăng tuyển nhất khi tỉ lệ chênh lệch là hơn 6 lần. Kết quả này cũng là dễ hiểu vì hầu hết các nhà tài trợ đều có trụ sở ở Hà Nội, sau đó mới đến Sài Gòn. Tuy vậy cũng có thể thấy vẫn có hơn 30% công việc được tuyển dụng cho các vị trí ở tỉnh. Ngoài ra số lượng việc đăng trên trang VUFO cũng không phản ảnh hết số việc được tuyển ở địa phương, thông thường các công việc này sẽ được tuyển dụng trực tiếp tại tỉnh thông qua các kênh tuyển dụng địa phương.

job$loc_name -> location
u <- location %>% 
  str_split(pattern = ",", simplify = TRUE) %>% 
  as.vector()

u[u == "Na"] <- NA


u %>% 
  str_trim() %>% 
  table() %>% 
  as.data.frame() -> u

names(u) <- c("word", "freq")

u %>%  
  arrange(-freq) %>% 
  slice(-1) %>% 
  filter(freq >= 10) -> p

# p$freq[c(1, 2)] %>% sum() / p$freq %>% sum()


# Hầu hết các job đều ở Hà Nội và Sài Gòn: 
# wordcloud2(p, 
#            color = "random-light", 
#            backgroundColor = "black")


p %>% 
  slice(-c(1, 2)) %>% 
  slice(1:25) %>% 
  mutate(word = str_to_upper(word) %>% as.factor()) %>% 
  ggplot(aes(reorder(word, freq), freq)) + 
  geom_col() + 
  geom_text(aes(label = freq), hjust = 1.1, color = "white") + 
  coord_flip() + 
  theme_minimal() + 
  labs(x = NULL, y = NULL, 
       title = "Top 25 Locations for NGO Jobs", 
       caption = "Data Source: http://www.ngocentre.org.vn")

# Nếu không tính đến hai thành phố này thì: 
# wordcloud2(p %>% slice(-c(1, 2)), 
#            color = "random-light", 
#            backgroundColor = "black", 
#            size = 0.4)
LS0tDQp0aXRsZTogIlBow6JuIHTDrWNoIHRow7RuZyB0aW4gdHV54buDbiBk4bulbmcgdHLDqm4gdHJhbmcgVlVGTy1OR08iIA0Kc3VidGl0bGU6ICJHRkQgQW5hbHl0aWNzIFNlY3Rpb24iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiZGVmYXVsdCINCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQojIFTDs20gdOG6r3QNCktoaSBwaMOibiB0w61jaCBoxqFuIDEzIG5naMOsbiB0aMO0bmcgdGluIHR1eeG7g24gZOG7pW5nIHRyb25nIDggbsSDbSBxdWEgdOG6oWkgdHJhbmcgVlVGTyAgLCBjaMO6bmcgdMO0aSB0aOG6pXkgbeG7mXQgc+G7kSB4dSBoxrDhu5tuZyBuaMawIHNhdToNCg0KLSBUcuG7qyBIw6AgTuG7mWkgdsOgIFPDoGkgR8OybiwgNSB04buJbmggdHV54buDbiBk4bulbmcgbmhp4buBdSB2aeG7h2MgbmjhuqV0IGzDoDogVGhhbmggSMOzYSwgxJBp4buHbiBCaeG7h24sIMSQw6AgTuG6tW5nLCBDYW8gQuG6sW5nLCBZw6puIELDoWkuDQotIFRow6FuZyB0dXnhu4NuIGThu6VuZyBuaGnhu4F1IG5o4bqldCBsw6AgdGjDoW5nIDg7IHRow6FuZyB0dXnhu4NuIGThu6VuZyDDrXQgbmjhuqV0IGzDoCB0aMOhbmcgMSB2w6AgdGjDoW5nIDI7DQotIEPDoWMgduG7iyB0csOtIMSRxrDhu6NjIHR1eeG7g24gZOG7pW5nIG5oaeG7gXUgbmjhuqV0IGzDoDogdMawIHbhuqVuLCBwcm9qZWN0IG9mZmljZXIsIHRy4bujIGzDvSBk4buxIMOhbiwgcXXhuqNuIGzDvSBk4buxIMOhbiwgxJFp4buBdSBwaOG7kWkgdmnDqm4sIMSRw6FuaCBnacOhIGThu7Egw6FuLCDEkcOgbyB04bqhbywgdMOgaSBjaMOtbmguDQotIDUgbmjDoCB0dXnhu4NuIGThu6VuZyBs4bubbiBuaOG6pXQgbMOgIFdvcmxkIFZpc2lvbiAsIFNOViAsIFNhdmUgdGhlIENoaWxkcmVuICwgT3hmYW0gdsOgIENBUkUuDQoNCg0KIyBHaeG7m2kgdGhp4buHdQ0KDQpbVlVGTy1OR08gUmVzb3VyY2UgQ2VudHJlXSggaHR0cDovL3d3dy5uZ29jZW50cmUub3JnLnZuL2pvYnMpIGzDoCBt4buZdCBuZ3Xhu5NuIHRow7RuZyB0aW4gcuG6pXQgcXVlbiB0aHXhu5ljIMSR4buRaSB24bubaSBjw6FjIHThu5UgY2jhu6ljIHbDoCBjw6EgbmjDom4gbMOgbSB2aeG7h2MgdHJvbmcgbMSpbmggduG7sWMgdMawIHbhuqVuIGNobyBjw6FjIGThu7Egw6FuIHBow6F0IHRyaeG7g24uDQoNCg0KVHLhu6sgbeG7mXQgc+G7kSB04buVIGNo4bupYyBs4bubbiBjw7MgDQpj4buVbmcgxJHhuqV1IHRo4bqndSByacOqbmcgbmjGsCBBREIsIFdCIHRow6wgaOG6p3UgaOG6v3QgY8OhYyBuaMOgIHTDoGkgdHLhu6MgdOG6oWkgVmnhu4d0IE5hbSDEkeG7gXUgxJHEg25nIHThuqNpIHR1eeG7g24gZOG7pW5nIHRyw6puIHRyYW5nIFdlYiBuw6B5LiBDw7RuZyB2aeG7h2MgxJHEg25nIHThuqFpIE5HTyBDZW50ZXIga2jDoSDEkWEgZOG6oW5nDQpn4buTbSBj4bqjIG5ow6JuIHZpw6puIGTDoGkgaOG6oW4gY2hvIGThu7Egw6FuIGhv4bq3YyBuaMOgIHTDoGkgdHLhu6MsIHTGsCB24bqlbiBjw6EgbmjDom4gdsOgIGPDoWMgZ8OzaSB0aOG6p3UgY+G7oSB24burYSB2w6Agbmjhu48uDQoNClThuqFpIFtHRkRdKCBodHRwOi8vZ2ZkLmNvbS52bi9lbi9pbmRleC5odG1sKSBjaMO6bmcgdMO0aSBjxaluZyB0aMaw4budbmcgeHV5w6puIHPhu60gZOG7pW5nIHRyYW5nIFZVRk8tTkdPIMSR4buDIHTDrG0ga2nhur9tIGPDoWMgY8O0bmcgdmnhu4djIG3hu5tpLiDEkOG7gyBjw7MgbeG7mXQgY8OhaSBuaMOsbiB04buRdCBoxqFuIHbhu4Egc+G7kSBsxrDhu6NuZyBjw7RuZyB2aeG7h2MgdGhlbyBuaMOgIHTDoGkgdHLhu6MsIHRoZW8gbmfDoG5oIG5naOG7gSBjaMO6bmcgdMO0aSBsw6BtIG3hu5l0ICJuZ2hpw6puIGPhu6l1IGLhu48gdMO6aSIgduG7gSBjaOG7pyDEkeG7gSBuw6B5LiBOZ2hpw6puIGPhu6l1IG7DoHkgdGjhu7FjIGhp4buHbiBi4bufaSAgYuG7mSBwaOG6rW4gcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgY+G7p2EgR0ZEIChHRkQgQW5hbHl0aWNzIFNlY3Rpb24gKS4gQ8O0bmcgY+G7pSBz4butIGThu6VuZyBsw6AgcGjhuqduIG3hu4FtIFIsIGfhu5NtIG3hu5l0IHPhu5EgYsaw4bubYyBjaMOtbmggbmjGsCBzYXU6DQoNCi0gU+G7rSBk4bulbmcgUkN1cmwgcGjDom4gdMOtY2ggY+G6pXUgdHLDumMgaHRtbCBj4bunYSBWVUZPLU5HTyBSZXNvdXJjZSBDZW50cmUgDQotIEzhuqduIGzGsOG7o3QgcXXDqXQgdsOgIHThuqNpIGThu68gbGnhu4d1IGpvYnMgdOG7qyAyMDA5LTIwMTggDQotIEzDoG0gc+G6oWNoIHbDoCBsxrB1IHRow6BuaCBjw6FjIHRodeG7mWMgdMOtbmggcXVhbiB0cuG7jW5nIChqb2JzIG5hbWUsIGRvbm9ycywgZGF0ZSwgbG9jYXRpb24pDQotIEThu68gbGnhu4d1IMSRw6MgbMOgbSBz4bqhY2ggY8OzIHRo4buDIHThuqNpIHThu6sgxJHhu4thIGNo4buJIGh0dHBzOi8vZ2l0aHViLmNvbS9ob2FuZ3ZpZXRhbmgvTkdPX0pvYl9SL2Jsb2IvbWFzdGVyL05HTy1Kb2JzLXY0LmNzdg0KLSBUaOG7sWMgaGnhu4duIG3hu5l0IHPhu5EgdMOtbmggdG/DoW4gxJHGoW4gZ2nhuqNuIG5oxrAgc+G7kSDEkeG6v20gam9iIHRoZW8gbsSDbSwgc+G7kSBqb2IgdGhlbyBuaMOgIHTDoGkgdHLhu6MsIMSR4bq/bSB04burIGtow7NhIMSR4buDIHRo4buRbmcga8OqIG5nw6BuaCBuZ2jhu4EgDQotIFbhur0gxJHhu5MgdGjhu4sgZMO5bmcgIGdncGxvdDIsIHbDoCBt4buZdCBz4buRIGPDtG5nIGPhu6UgeOG7rSBsw70ga2jDoWMgdHJvbmcgZ8OzaSB0aWR5dmVyc2UsDQoNCk3hu5l0IHbDoGkgY29uIHPhu5EgYmFuIMSR4bqndSBuaMawIHNhdToNCg0KLSBDw7RuZyB2aeG7h2Mgc+G7m20gbmjhuqV0IG3DoCBo4buHIHRo4buRbmcgY8OybiBsxrB1IGzhuqFpIMSRxrDhu6NjIMSRxINuZyB04bqjaSB2w6BvIG5nw6B5IDE0LzA4LzIwMDksIGRvIHThu5UgY2jhu6ljIFZTTyB0dXnhu4NuIGThu6VuZzogQWRtaW5pc3RyYXRpdmUgYW5kIEZpbmFuY2lhbCBTdXBwb3J0IE9mZmljZXIgLiANCi0gVOG7lW5nIHPhu5EgY8O0bmcgdmnhu4djIGzDoCAxMyw3MjAsIHRydW5nIGLDrG5oIG3hu5dpIG5nw6B5IGPDsyA0LjQgdmnhu4djIMSRxrDhu6NjIMSRxINuZyBsw6puIGjhu4cgdGjhu5FuZy4NCi0gVOG7lW5nIHPhu5EgdOG7lSBjaOG7qWMgxJHDoyDEkcSDbmcgdHV54buDbiBk4bulbmcgbMOgIDE2MjkuIFR1eSBuaGnDqm4gY8OzIHLhuqV0IG5oaeG7gXUgdOG7lSBjaOG7qWMgY2jhu4kgxJHEg25nIHR1eeG7g24gMSBs4bqnbiwgaG/hurdjIHTDqm4gbmjDoCB0dXnhu4NuIGThu6VuZyBsw6AgdMOqbiBk4buxIMOhbiwgZG8gxJHDsyBraMO0bmcgdGjhu5FuZyBrw6ogxJHGsOG7o2MgdsOgbyBt4buZdCB04buVIGNo4bupYyBj4bulIHRo4buDLiBO4bq/dSBjaOG7iSB0w61uaCBuaOG7r25nIHThu5UgY2jhu6ljIGPDsyDEkcSDbmcgdHV54buDbiBk4bulbmcgNSBs4bqnbiB0cuG7nyBsw6puIHRow6wgc+G7kSBsxrDhu6NuZyBjaOG7iSBjw7JuIDM3MDsgxJHEg25nIHRyw6puIDEwIHR1eeG7g24gZOG7pW5nIGzDoCAyNDAgdOG7lSBjaOG7qWM7IHRyw6puIDIwIHR1eeG7g24gZOG7pW5nIGzDoCAxMDAgdOG7lSBjaOG7qWMuDQoNCg0KYGBge3J9DQpybShsaXN0ID0gbHMoKSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShoaWdoY2hhcnRlcikNCmpvYiA8LSByZWFkLmNzdigiRDovR0ZEX0dJVC9OR08tSm9icy12NC5jc3YiKQ0KDQp0aG9pX2dpYW4gPC0gZnVuY3Rpb24oeCkgew0KICB4ICU+JSANCiAgICBzdHJfc3ViKHN0YXJ0ID0gNiwgZW5kID0gMTYpICU+JSANCiAgICB5bWQoKSAlPiUgDQogICAgcmV0dXJuKCkNCn0NCg0KDQpqb2IgJTw+JSBtdXRhdGUodGltZSA9IHRob2lfZ2lhbihkZWFkbGluZSksIA0KICAgICAgICAgICAgICAgIG5hbSA9IHllYXIodGltZSksIA0KICAgICAgICAgICAgICAgIG9yZ19uYW1lID0gYXMuY2hhcmFjdGVyKG9yZ19uYW1lKSkNCg0KIyBDw7MgbeG7mXQgc+G7kSB04buVIGNo4bupYyBz4butIGThu6VuZyBoYWkgdMOqbiBraMOhYyBuaGF1IGRvIMSRw7MgY+G6p24gcmVuYW1lDQojIGzhuqFpIHTDqm4gY2hvIGNow7puZyAoxJFv4bqhbiBjb2RlcyBi4buVIHN1bmcgbmfDoHkgMTEgLyAwMyk6IA0KDQojIHJlbmFtZV9vcmcgPC0gZnVuY3Rpb24oeCkgew0KIyAgIEVMU0UgPC0gVFJVRQ0KIyAgIGNhc2Vfd2hlbih4ID09ICJHSVogQmlPIEZvcmVzdHJ5IFByb2plY3QiIH4gIkdJWiIsIA0KIyAgICAgICAgICAgICBzdHJfZGV0ZWN0KHgsICJTTlYiKSB+ICJTTlYgLSBOZXRoZXJsYW5kcyBEZXZlbG9wbWVudCBPcmdhbmlzYXRpb24iLCANCiMgICAgICAgICAgICAgRUxTRSB+IHgpDQojIH0NCiMgDQojIA0KIyBqb2IgJTw+JSBtdXRhdGUob3JnX25hbWUgPSByZW5hbWVfb3JnKG9yZ19uYW1lKSkNCmpvYiAlPD4lIGZpbHRlcihuYW0gJWluJSBjKDIwMDk6MjAxNykpDQoNCiMgVG9wIDMwIHThu5UgY2jhu6ljIGPDsyBuaGnhu4F1IHZp4buHYyBuaOG6pXQ6IA0KDQojIHRvcDMwIDwtIGpvYiAlPiUgDQojICAgZ3JvdXBfYnkob3JnX25hbWUpICU+JSANCiMgICBjb3VudCgpICU+JQ0KIyAgIHVuZ3JvdXAoKSAlPiUgDQojICAgYXJyYW5nZSgtbikgJT4lIA0KIyAgIG11dGF0ZV9pZihpcy5mYWN0b3IsIGNoYXJhY3RlcikgJT4lIA0KIyAgIHNsaWNlKDE6MzApIA0KDQoNCnRvcDMwIDwtIGpvYiAlPiUNCiAgZ3JvdXBfYnkob3JnX25hbWUpICU+JQ0KICBjb3VudCgpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFycmFuZ2UoLW4pICU+JQ0KICBtdXRhdGVfaWYoaXMuZmFjdG9yLCBjaGFyYWN0ZXIpICU+JQ0KICBzbGljZSgxOjMwKQ0KDQoNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCmpvYiAlPiUgDQogIGdyb3VwX2J5KG5hbSkgJT4lIA0KICBjb3VudCgpICU+JSANCiAgdW5ncm91cCgpLT4gam9iX2J5X3llYXINCg0KDQojIGhpZ2hjaGFydCgpICU+JSANCiMgICBoY194QXhpcyhjYXRlZ29yaWVzID0gam9iX2J5X3llYXIkbmFtKSAlPiUgDQojICAgaGNfYWRkX3NlcmllcyhkYXRhID0gam9iX2J5X3llYXIkbiwgDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgDQojICAgICAgICAgICAgICAgICB0eXBlID0gImNvbHVtbiIsIA0KIyAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzEwNEU4QiIpICU+JSANCiMgICBoY190aXRsZSh0ZXh0ID0gIlRoZSBOdW1iZXIgb2YgSm9icyBmcm9tIDIwMDkgdG8gMjAxNyIpICU+JSANCiMgICBoY19jcmVkaXRzKGVuYWJsZWQgPSBUUlVFLA0KIyAgICAgICAgICAgICAgdGV4dCA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy5uZ29jZW50cmUub3JnLnZuIiwgIA0KIyAgICAgICAgICAgICAgc3R5bGUgPSBsaXN0KGZvbnRTaXplID0gIjEycHgiKSkgJT4lIA0KIyAgIGhjX3Rvb2x0aXAodmFsdWVEZWNpbWFscyA9IDAsIA0KIyAgICAgICAgICAgICAgcG9pbnRGb3JtYXQgPSAiTnVtYmVyOiB7cG9pbnQueX0iKSAlPiUgDQojICAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lXzUzOCgpKQ0KYGBgDQoNCiMgUGjDom4gYuG7lSB2aeG7h2MgbMOgbSB0aGVvIG5ow6AgdHV54buDbiBk4bulbmcNCg0KNSBuaMOgIHR1eeG7g24gZOG7pW5nIGPDsyBz4buRIGzGsOG7o25nIGPDtG5nIHZp4buHYyBuaGnhu4F1IG5o4bqldCBsw6A6IFdvcmxkIFZpc2lvbiAsIFNOViAsIFNhdmUgdGhlIENoaWxkcmVuICwgT3hmYW0gdsOgIENBUkUuIFThu5VuZyBz4buRIGPDtG5nIHZp4buHYyBj4bunYSA1IHThu5UgY2jhu6ljIG7DoHkgbMOgIDMwNzEgdmnhu4djIGNoaeG6v20gMjIlIHThu5VuZyBz4buRIMSRxINuZyB0dXnhu4NuLg0KDQoNCsSQ4buTIHRo4buLIGTGsOG7m2kgxJHDonkgdHLDrG5oIGLhuqd5IHPhu5EgbMaw4bujbmcgdHV54buDbiBk4bulbmcgY+G7p2EgMzAgTkdPcyBjw7MgbMaw4bujbmcgdHV54buDbiBk4bulbmcgbOG7m24uIFThu5VuZyBz4buRIGPDtG5nIHZp4buHYyBj4bunYSAzMCB04buVIGNo4bupYyBuw6B5IGzDoCA1NDczIC0gY2hp4bq/bSA0MCUgdOG6pXQgY+G6oyBjw6FjIGPDtG5nIHZp4buHYyDEkcaw4bujYyDEkcSDbmcgdOG6o2kuxJDDonkgbMOgIG3hu5l0IHPhu7EgdOG6rXAgdHJ1bmcgcuG6pXQgbOG7m24gc28gduG7m2kgdOG7lW5nIHPhu5EgaMahbiAxNjAwIHThu5UgY2jhu6ljIGPDsyB0aMO0bmcgYsOhbyDEkcSDbmcgdHV54buDbiB2aeG7h2MgbMOgbS4gVHV5IG5oacOqbiBuaMawIMSRw6MgbsOzaSDhu58gdHLDqm4sIGPDsyBy4bqldCBuaGnhu4F1IGPDtG5nIHZp4buHYyDEkcaw4bujYyDEkcSDbmcgbMOqbiBkxrDhu5tpIHTDqm4gZOG7sSDDoW4sIMSR4buRaSB24bubaSBuaOG7r25nIHRyxrDhu51uZyBo4bujcCBuw6B5IGNow7puZyB0YSBz4bq9IGtow7RuZyBjw7MgdGjDtG5nIHRpbiBjaMOtbmggeMOhYyB24buBIG5ow6AgdMOgaSB0cuG7oy4NCg0KU2F1IHRvcCA1IG5ow6AgdHV54buDbiBk4bulbmcgdGjDrCBXV0YsIEFjdGlvbkFpZCwgVU5EUCwgRU5WLCBQbGFuSW50ZXJuYXRpb25hbCBjxaluZyBsw6Agbmjhu69uZyB04buVIGNo4bupYyBjw7MgbMaw4bujbmcgdHV54buDbiBk4bulbmcgbOG7m24uIEpJQ0EsIG3hurdjIGTDuSBsw6AgbeG7mXQgbmjDoCB0w6BpIHRy4bujIHLhuqV0IGzhu5tuIG5oxrBuZyBo4bqndSBuaMawIGtow7RuZyBjw7MgxJHEg25nIHR1eeG7g24g4bufIMSRw6J5LCBnaeG7kW5nIG5oxrAgQURCIHbDoCBXQiwgSklDQSBjw7MgaOG7hyB0aOG7kW5nIHR1eeG7g24gZOG7pW5nIHJpw6puZy4NCg0KDQoNCmBgYHtyfQ0KIyBoaWdoY2hhcnQoKSAlPiUNCiMgICBoY194QXhpcyhjYXRlZ29yaWVzID0gdG9wMzAkb3JnX25hbWUpICU+JQ0KIyAgIGhjX2FkZF9zZXJpZXMoZGF0YSA9IHRvcDMwJG4sDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwNCiMgICAgICAgICAgICAgICAgIHR5cGUgPSAiY29sdW1uIiwNCiMgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMDRFOEIiKSAlPiUNCiMgICBoY190aXRsZSh0ZXh0ID0gIlRvcCAzMCBOR09zIHdpdGggVGhlIGxhcmdlc3QgTnVtYmVyIG9mIEpvYnMgZnJvbSAyMDA5IHRvIDIwMTciKSAlPiUNCiMgICBoY19jcmVkaXRzKGVuYWJsZWQgPSBUUlVFLA0KIyAgICAgICAgICAgICAgdGV4dCA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy5uZ29jZW50cmUub3JnLnZuIiwNCiMgICAgICAgICAgICAgIHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICIxMnB4IikpICU+JQ0KIyAgIGhjX3Rvb2x0aXAodmFsdWVEZWNpbWFscyA9IDAsDQojICAgICAgICAgICAgICBwb2ludEZvcm1hdCA9ICJOdW1iZXI6IHtwb2ludC55fSIpICU+JQ0KIyAgIGhjX2FkZF90aGVtZShoY190aGVtZV81MzgoKSkNCg0KdSA8LSBqb2IgJT4lIA0KICBncm91cF9ieShvcmdfbmFtZSkgJT4lIA0KICBjb3VudCgpICU+JQ0KICB1bmdyb3VwKCkgJT4lIA0KICBhcnJhbmdlKC1uKQ0KDQoNCiMgdSRvcmdfbmFtZSAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpDQojdSRuWzE6MjBdICU+JSBzdW0oKSAvIHUkbiAlPiUgc3VtKCkNCg0KDQoNCmhpZ2hjaGFydCgpICU+JQ0KICBoY194QXhpcyhjYXRlZ29yaWVzID0gdG9wMzAkb3JnX25hbWVbMToyMF0pICU+JSANCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIk51bWJlciBvZiBKb2JzIiwgDQogICAgICAgICAgICAgICAgZGF0YSA9IHRvcDMwJG5bMToyMF0sIA0KICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMDRFOEIiLCANCiAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSkgJT4lIA0KICBoY19jaGFydCh0eXBlID0gImJhciIsIG9wdGlvbnMyZCA9IGxpc3QoZW5hYmxlZCA9IFRSVUUsIGJldGEgPSAxLCBhbHBoYSA9IDEpKSAlPiUgDQogIGhjX3RpdGxlKHRleHQgPSAiVG9wIDIwIE5HT3Mgd2l0aCBUaGUgbGFyZ2VzdCBOdW1iZXIgb2YgSm9icyBmcm9tIDIwMDkgdG8gMjAxNyIpICU+JSANCiAgaGNfY3JlZGl0cyhlbmFibGVkID0gVFJVRSwNCiAgICAgICAgICAgICB0ZXh0ID0gIkRhdGEgU291cmNlOiBodHRwOi8vd3d3Lm5nb2NlbnRyZS5vcmcudm4iLCAgDQogICAgICAgICAgICAgc3R5bGUgPSBsaXN0KGZvbnRTaXplID0gIjEycHgiKSkgJT4lIA0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfNTM4KCkpDQoNCmBgYA0KDQoNCiMgUGjDom4gYuG7lSB2aeG7h2MgbMOgbSB0aGVvIG7Eg20NCg0KTmdv4bqhaSB0cuG7qyBuxINtIDIwMDkgY2jhu4kgY8OzIHPhu5EgbGnhu4d1IHThu6sgdGjDoW5nIDgsIHThu6sgMjAxMCBz4buRIGzGsOG7o25nIGPDtG5nIHZp4buHYyBjw7MgeHUgaMaw4bubbmcgdMSDbmcgbmjhurkgY2hvIHThu5tpIG7Eg20gMjAxNSwgdHV5IG5oacOqbiBt4bupYyB0xINuZyBraMO0bmcgbmhp4buBdS4gVOG7qyAyMDE1IMSR4bq/biAyMDE3IHPhu5EgbMaw4bujbmcgY8O0bmcgdmnhu4djIGPDsyB4dSBoxrDhu5tuZyBnaeG6o20gbmjhurkuDQoNCg0KDQpgYGB7cn0NCiMgVG9wIDUgdOG7lSBjaOG7qWMgY8OzIG5oaeG7gXUgdmnhu4djIG5o4bqldDogDQp0b3AzMCRvcmdfbmFtZVsxOjVdIC0+IHRvcDVfb3JnDQoNCmpvYiAlPD4lIG11dGF0ZShvcmdfbmFtZTIgPSBjYXNlX3doZW4ob3JnX25hbWUgJWluJSB0b3A1X29yZyB+IG9yZ19uYW1lLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIW9yZ19uYW1lICVpbiUgdG9wNV9vcmcgfiAiT3RoZXJzIikpDQoNCg0Kb3JnX3JlbmFtZSA8LSBmdW5jdGlvbih4KSB7DQogIGNhc2Vfd2hlbih4ID09IHRvcDVfb3JnWzFdIH4gIlNOViIsIA0KICAgICAgICAgICAgeCA9PSB0b3A1X29yZ1syXSB+ICJXb3JsZCBWaXNpb24iLCANCiAgICAgICAgICAgIHggPT0gdG9wNV9vcmdbNV0gfiAiQ0FSRSIsIA0KICAgICAgICAgICAgIXggJWluJSB0b3A1X29yZ1tjKDEsIDIsIDUpXSB+IHgpDQp9DQoNCg0KDQpqb2IgJT4lIA0KICBncm91cF9ieShvcmdfbmFtZTIsIG5hbSkgJT4lIA0KICBjb3VudCgpICU+JSANCiAgdW5ncm91cCgpIC0+IHRvcF81X2NvbmcxDQoNCnRvcF81X2NvbmcxJG9yZ19uYW1lMiA8LSBvcmdfcmVuYW1lKHRvcF81X2NvbmcxJG9yZ19uYW1lMikNCg0KIyB0b3BfNV9jb25nMSAlPiUgDQojICAgZ2dwbG90KGFlcyhuYW0sIG4sIGZpbGwgPSBvcmdfbmFtZTIpKSArIA0KIyAgIGdlb21fY29sKHBvc2l0aW9uID0gInN0YWNrIikNCg0KDQp0b3BfNV9jb25nMSAlPiUgDQogIGhjaGFydChoY2FlcyhuYW0sIG4sIGdyb3VwID0gb3JnX25hbWUyKSwgdHlwZSA9ICJjb2x1bW4iLCBzaG93SW5MZWdlbmQgPSBUUlVFKSAlPiUgDQogIGhjX3Bsb3RPcHRpb25zKHNlcmllcyA9IGxpc3Qoc3RhY2tpbmcgPSAibm9ybWFsIikpICU+JSANCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX3NhbmRzaWduaWthKCkpICU+JSANCiAgaGNfeUF4aXModGl0bGUgPSBsaXN0KHRleHQgPSAiIikpICU+JSANCiAgaGNfeEF4aXModGl0bGUgPSBsaXN0KHRleHQgPSAiIikpICU+JSANCiAgaGNfdGl0bGUodGV4dCA9ICJUaGUgTnVtYmVyIG9mIEpvYnMgZnJvbSAyMDA5IHRvIDIwMTciKSAlPiUgDQogIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsDQogICAgICAgICAgICAgdGV4dCA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy5uZ29jZW50cmUub3JnLnZuIiwgIA0KICAgICAgICAgICAgIHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICIxMnB4IikpDQpgYGANCg0KDQoNCg0KIyBQaMOibiBi4buRIHbhu4Egdmnhu4djIGzDoG0gxJHGsOG7o2MgdHV54buDbiBk4bulbmcgdGhlbyB0aMOhbmcgY+G7p2EgY8OhYyBOR09zDQoNClPhu5EgbMaw4bujbmcgY8O0bmcgdmnhu4djIMSRxrDhu6NjIHR1eeG7g24gZOG7pW5nIHRoxrDhu51uZyBz4bq9IGtow7RuZyBjYW8gdsOgbyB0aMOhbmcgMSB2w6AgMiBkxrDGoW5nIGzhu4tjaC4gxJDDonkgY8WpbmcgbMOgIHRo4budaSDEkWnhu4NtIGdpw6FwIHThur90IE5ndXnDqm4gxJDDoW4uIFPhu5EgbMaw4bujbmcgY8O0bmcgdmnhu4djIMSRxrDhu6NjIHR1eeG7g24gdGjGsOG7nW5nIMSR4bqhdCDEkeG7iW5oIGNhbyB2w6BvIHRow6FuZyA4IHNhdSDEkcOzIGdp4bqjbSBk4bqnbiBjaG8gxJHhur9uIGN14buRaSBuxINtIHbDoCBoYWkgdGjDoW5nIGPhu6dhIG7Eg20gbeG7m2kga+G6vyB0aeG6v3A6IA0KDQpgYGB7cn0NCmpvYiAlPD4lIG11dGF0ZSh0aGFuZyA9IG1vbnRoKHRpbWUsIGxhYmVsID0gVFJVRSwgYWJiciA9IFRSVUUpKQ0KDQpqb2JfdGhhbmdfbmFtIDwtIGpvYiAlPiUgDQogIGdyb3VwX2J5KG5hbSwgdGhhbmcpICU+JSANCiAgY291bnQoKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGFycmFuZ2UodGhhbmcpDQoNCiMgam9iX3RoYW5nX25hbSAlPiUgDQojICAgZ2dwbG90KGFlcyh0aGFuZywgbikpICsgDQojICAgZ2VvbV9jb2woKSArIA0KIyAgIGZhY2V0X3dyYXAofiBuYW0sIHNjYWxlcyA9ICJmcmVlIikNCg0KDQojIFZp4buHYyB0aGVvIHRo4budaSBnaWFuIGzDoCB0aMOhbmcgLSBuxINtOiANCiMgaGlnaGNoYXJ0KCkgJT4lIA0KIyAgIGhjX2FkZF9zZXJpZXMobmFtZSA9ICJZZWFyIG9mIDIwMTAiLCANCiMgICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFLCANCiMgICAgICAgICAgICAgICAgIGRhdGEgPSBqb2JfdGhhbmdfbmFtICU+JSBmaWx0ZXIobmFtID09IDIwMTApICU+JSBwdWxsKG4pKSAlPiUgDQojICAgaGNfYWRkX3NlcmllcyhuYW1lID0gIlllYXIgb2YgMjAxMSIsIA0KIyAgICAgICAgICAgICAgICAgc2hvd0luTGVnZW5kID0gRkFMU0UsIA0KIyAgICAgICAgICAgICAgICAgZGF0YSA9IGpvYl90aGFuZ19uYW0gJT4lIGZpbHRlcihuYW0gPT0gMjAxMSkgJT4lIHB1bGwobikpICU+JSANCiMgICBoY19hZGRfc2VyaWVzKG5hbWUgPSAiWWVhciBvZiAyMDEyIiwgDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgDQojICAgICAgICAgICAgICAgICBkYXRhID0gam9iX3RoYW5nX25hbSAlPiUgZmlsdGVyKG5hbSA9PSAyMDEyKSAlPiUgcHVsbChuKSkgJT4lIA0KIyAgIGhjX2FkZF9zZXJpZXMobmFtZSA9ICJZZWFyIG9mIDIwMTMiLCANCiMgICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFLCANCiMgICAgICAgICAgICAgICAgIGRhdGEgPSBqb2JfdGhhbmdfbmFtICU+JSBmaWx0ZXIobmFtID09IDIwMTMpICU+JSBwdWxsKG4pKSAlPiUgDQojICAgaGNfYWRkX3NlcmllcyhuYW1lID0gIlllYXIgb2YgMjAxNCIsIA0KIyAgICAgICAgICAgICAgICAgc2hvd0luTGVnZW5kID0gRkFMU0UsIA0KIyAgICAgICAgICAgICAgICAgZGF0YSA9IGpvYl90aGFuZ19uYW0gJT4lIGZpbHRlcihuYW0gPT0gMjAxNCkgJT4lIHB1bGwobikpICU+JSANCiMgICBoY19hZGRfc2VyaWVzKG5hbWUgPSAiWWVhciBvZiAyMDE1IiwgDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgDQojICAgICAgICAgICAgICAgICBkYXRhID0gam9iX3RoYW5nX25hbSAlPiUgZmlsdGVyKG5hbSA9PSAyMDE1KSAlPiUgcHVsbChuKSkgJT4lIA0KIyAgIGhjX2FkZF9zZXJpZXMobmFtZSA9ICJZZWFyIG9mIDIwMTYiLCANCiMgICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFLCANCiMgICAgICAgICAgICAgICAgIGRhdGEgPSBqb2JfdGhhbmdfbmFtICU+JSBmaWx0ZXIobmFtID09IDIwMTYpICU+JSBwdWxsKG4pKSAlPiUgDQojICAgaGNfYWRkX3NlcmllcyhuYW1lID0gIlllYXIgb2YgMjAxNyIsIA0KIyAgICAgICAgICAgICAgICAgc2hvd0luTGVnZW5kID0gRkFMU0UsIA0KIyAgICAgICAgICAgICAgICAgZGF0YSA9IGpvYl90aGFuZ19uYW0gJT4lIGZpbHRlcihuYW0gPT0gMjAxNykgJT4lIHB1bGwobikpICU+JSANCiMgICBoY194QXhpcyhjYXRlZ29yaWVzID0gam9iX3RoYW5nX25hbSR0aGFuZyAlPiUgdW5pcXVlKCkpICU+JSANCiMgICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfNTM4KCkpICU+JSANCiMgICBoY195QXhpcyh0aXRsZSA9IGxpc3QodGV4dCA9ICJOdW1iZXIgb2YgUmVjcnVpdGVkIEpvYnMiKSkgJT4lIA0KIyAgIGhjX3RpdGxlKHRleHQgPSAiVGhlIE51bWJlciBvZiBKb2JzIGZyb20gMjAxMCB0byAyMDE3IGJ5IE1vbnRoIGFuZCBZZWFyIikgJT4lDQojICAgaGNfc3VidGl0bGUodGV4dCA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy5uZ29jZW50cmUub3JnLnZuIikNCmBgYA0KDQogDQoNCmBgYHtyfQ0Kam9iICU+JSANCiAgZ3JvdXBfYnkodGhhbmcpICU+JSANCiAgY291bnQoKSAtPiB2aWVjX3RoYW5nDQoNCg0KaGlnaGNoYXJ0KCkgJT4lIA0KICBoY19hZGRfc2VyaWVzKGRhdGEgPSByb3VuZCh2aWVjX3RoYW5nICU+JSBwdWxsKG4pIC8gOSwgMCksIHNob3dJbkxlZ2VuZCA9IEZBTFNFKSAlPiUgDQogIGhjX2FkZF90aGVtZShoY190aGVtZV81MzgoKSkgJT4lIA0KICBoY195QXhpcyh0aXRsZSA9IGxpc3QodGV4dCA9ICIgIikpICU+JSANCiAgaGNfeEF4aXMoY2F0ZWdvcmllcyA9IHZpZWNfdGhhbmckdGhhbmcgJT4lIHVuaXF1ZSgpKSAlPiUgDQogIGhjX3RpdGxlKHRleHQgPSAiQXZlcmFnZSBKb2JzIGJ5IE1vbnRoIikgJT4lDQogIGhjX3N1YnRpdGxlKHRleHQgPSAiRGF0YSBTb3VyY2U6IGh0dHA6Ly93d3cubmdvY2VudHJlLm9yZy52biIpDQpgYGANCg0KDQpgYGB7cn0NCiMgRGFuaCBzw6FjaCAxMCBOR09zIGPDsyBuaGnhu4F1IHZp4buHYyBuaOG6pXQ6IA0KDQp0b3AxMF9uZ28gPC0gdG9wMzAkb3JnX25hbWVbMToxMF0NCg0KIyBqb2IgJT4lIA0KIyAgIGZpbHRlcihvcmdfbmFtZSAlaW4lIHRvcDEwX25nbykgJT4lIA0KIyAgIGdyb3VwX2J5KG9yZ19uYW1lLCB0aGFuZykgJT4lIA0KIyAgIGNvdW50KCkgJT4lIA0KIyAgIHVuZ3JvdXAoKSAlPiUgDQojICAgZ2dwbG90KGFlcyh0aGFuZywgbikpICsgDQojICAgZ2VvbV9jb2woKSArDQojICAgZmFjZXRfd3JhcCh+IG9yZ19uYW1lLCBzY2FsZXMgPSAiZnJlZSIpDQoNCmpvYiAlPiUgDQogIGZpbHRlcihvcmdfbmFtZSAlaW4lIHRvcDEwX25nbykgJT4lIA0KICBncm91cF9ieShvcmdfbmFtZSwgdGhhbmcpICU+JSANCiAgY291bnQoKSAlPiUgDQogIHVuZ3JvdXAoKSAtPiB0b3AxMF9ieV9tb250aA0KDQp0ZW5fdG9wMTAgPC0gdG9wMTBfYnlfbW9udGgkb3JnX25hbWUgJT4lIHVuaXF1ZSgpDQoNCg0KIyBoaWdoY2hhcnQoKSAlPiUNCiMgICBoY19hZGRfc2VyaWVzKGRhdGEgPSB0b3AxMF9ieV9tb250aCAlPiUgZmlsdGVyKG9yZ19uYW1lID09IHRlbl90b3AxMFsxXSkgJT4lIHB1bGwobiksDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgbmFtZSA9IHRlbl90b3AxMFsxXSkgJT4lDQojICAgaGNfYWRkX3NlcmllcyhkYXRhID0gdG9wMTBfYnlfbW9udGggJT4lIGZpbHRlcihvcmdfbmFtZSA9PSB0ZW5fdG9wMTBbMl0pICU+JSBwdWxsKG4pLA0KIyAgICAgICAgICAgICAgICAgc2hvd0luTGVnZW5kID0gRkFMU0UsIG5hbWUgPSB0ZW5fdG9wMTBbMl0pICU+JQ0KIyAgIGhjX2FkZF9zZXJpZXMoZGF0YSA9IHRvcDEwX2J5X21vbnRoICU+JSBmaWx0ZXIob3JnX25hbWUgPT0gdGVuX3RvcDEwWzNdKSAlPiUgcHVsbChuKSwNCiMgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgbmFtZSA9IHRlbl90b3AxMFszXSkgJT4lDQojICAgaGNfYWRkX3NlcmllcyhkYXRhID0gdG9wMTBfYnlfbW9udGggJT4lIGZpbHRlcihvcmdfbmFtZSA9PSB0ZW5fdG9wMTBbNF0pICU+JSBwdWxsKG4pLA0KIyAgICAgICAgICAgICAgICAgc2hvd0luTGVnZW5kID0gRkFMU0UsIG5hbWUgPSB0ZW5fdG9wMTBbNF0pICU+JQ0KIyAgIGhjX2FkZF9zZXJpZXMoZGF0YSA9IHRvcDEwX2J5X21vbnRoICU+JSBmaWx0ZXIob3JnX25hbWUgPT0gdGVuX3RvcDEwWzVdKSAlPiUgcHVsbChuKSwNCiMgICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFLCBuYW1lID0gdGVuX3RvcDEwWzVdKSAlPiUNCiMgICBoY19hZGRfc2VyaWVzKGRhdGEgPSB0b3AxMF9ieV9tb250aCAlPiUgZmlsdGVyKG9yZ19uYW1lID09IHRlbl90b3AxMFs2XSkgJT4lIHB1bGwobiksDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgbmFtZSA9IHRlbl90b3AxMFs2XSkgJT4lDQojICAgaGNfYWRkX3NlcmllcyhkYXRhID0gdG9wMTBfYnlfbW9udGggJT4lIGZpbHRlcihvcmdfbmFtZSA9PSB0ZW5fdG9wMTBbN10pICU+JSBwdWxsKG4pLA0KIyAgICAgICAgICAgICAgICAgc2hvd0luTGVnZW5kID0gRkFMU0UsIG5hbWUgPSB0ZW5fdG9wMTBbN10pICU+JQ0KIyAgIGhjX2FkZF9zZXJpZXMoZGF0YSA9IHRvcDEwX2J5X21vbnRoICU+JSBmaWx0ZXIob3JnX25hbWUgPT0gdGVuX3RvcDEwWzhdKSAlPiUgcHVsbChuKSwNCiMgICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFLCBuYW1lID0gdGVuX3RvcDEwWzhdKSAlPiUNCiMgICBoY19hZGRfc2VyaWVzKGRhdGEgPSB0b3AxMF9ieV9tb250aCAlPiUgZmlsdGVyKG9yZ19uYW1lID09IHRlbl90b3AxMFs5XSkgJT4lIHB1bGwobiksDQojICAgICAgICAgICAgICAgICBzaG93SW5MZWdlbmQgPSBGQUxTRSwgbmFtZSA9IHRlbl90b3AxMFs5XSkgJT4lDQojICAgaGNfYWRkX3NlcmllcyhkYXRhID0gdG9wMTBfYnlfbW9udGggJT4lIGZpbHRlcihvcmdfbmFtZSA9PSB0ZW5fdG9wMTBbMTBdKSAlPiUgcHVsbChuKSwNCiMgICAgICAgICAgICAgICAgIHNob3dJbkxlZ2VuZCA9IEZBTFNFLCBuYW1lID0gdGVuX3RvcDEwWzEwXSkgJT4lDQojICAgaGNfeEF4aXMoY2F0ZWdvcmllcyA9IHRvcDEwX2J5X21vbnRoJHRoYW5nICU+JSB1bmlxdWUoKSkgJT4lDQojICAgaGNfeUF4aXModGl0bGUgPSBsaXN0KHRleHQgPSAiTnVtYmVyIG9mIFJlY3J1aXRlZCBKb2JzIikpICU+JQ0KIyAgIGhjX3RpdGxlKHRleHQgPSAiVGhlIE51bWJlciBvZiBKb2JzIGZyb20gMjAxMCB0byAyMDE3IGJ5IE1vbnRoIGZvciB0b3AgMTAgTkdPcyIpICU+JQ0KIyAgIGhjX3N1YnRpdGxlKHRleHQgPSAiRGF0YSBTb3VyY2U6IGh0dHA6Ly93d3cubmdvY2VudHJlLm9yZy52biIpICU+JQ0KIyAgIGhjX2FkZF90aGVtZShoY190aGVtZV81MzgoKSkNCmBgYA0KDQoNCg0KYGBge3J9DQojIMSQb+G6oW4gbeG7m2kgduG7gSB3b3JkIGNsb3VkOiANCg0KDQojIGxpYnJhcnkod29yZGNsb3VkKQ0KDQpyZW5hbWVfam9iX3RpdGxlIDwtIGZ1bmN0aW9uKHgpIHsNCiAgeCA8LSBzdHJfdG9fbG93ZXIoeCkNCiAgeCAlPiUgDQogICAgc3RyX3JlcGxhY2VfYWxsKCJwcm9ncmFtbWUiLCAicHJvZ3JhbSIpICU+JSANCiAgICBzdHJfcmVwbGFjZV9hbGwoImNvbnN1bHRhbmN5fGNvbnN1bHRhbnRzIiwgImNvbnN1bHRhbnQiKSAlPiUgDQogICAgc3RyX3JlcGxhY2VfYWxsKCJwcm9qZWN0fGludGVybmF0aW9uYWx8bmF0aW9uYWx8cHJvZ3JhbSIsICIiKQ0KICANCn0NCg0KDQojIHNldC5zZWVkKDI5MTk4OSkNCiMgd29yZGNsb3VkKGpvYiRqb2JfbmFtZSAlPiUgcmVuYW1lX2pvYl90aXRsZSgpLCANCiMgICAgICAgICAgIG1heC53b3JkcyA9IDEwMCwgDQojICAgICAgICAgICByYW5kb20ub3JkZXIgPSBGQUxTRSwgDQojICAgICAgICAgICByb3QucGVyID0gMC4zNSwgDQojICAgICAgICAgICBmb250ID0gNCwNCiMgICAgICAgICAgIGNvbG9ycyA9IGJyZXdlci5wYWwoOCwgIkRhcmsyIikpDQpgYGANCg0KDQojIE5ow7NtIGPDtG5nIHZp4buHYyDEkcaw4bujYyB0dXnhu4NuIGThu6VuZyBwaOG7lSBiaeG6v24gbmjhuqV0DQoNCsSQ4buDIHRo4buRbmcga8OqIG5ow7NtIGPDtG5nIHZp4buHYyBjaMO6bmcgdMO0aSBz4butIGThu6VuZyBjw7RuZyBj4bulIMSR4bq/bSB04burIGPhu6dhIGfDs2kgVE0uIEfDs2kgbsOgeSBjaG8gcGjDqXAgbMOgbSBz4bqhY2gsIGLhu48gYuG7m3QgY8OhYyB04burIG7hu5FpIHbDoCBo4bujcCBuaOG6pXQgY8OhYyB04burIGPDsyBjw7luZyBn4buRYyAodsOtIGThu6Ugc+G7kSDDrXQsIHPhu5Egbmhp4buBdSwgY8OhYyB0aOG7nWkga2jDoWMgbmhhdSBj4bunYSDEkeG7mW5nIHThu6spLiDEkMOieSBjaMawYSBo4bqzbiBsw6AgY8OhY2ggcGjDuSBo4bujcCBuaOG6pXQgxJHhu4MgcGjDom4gbG/huqFpIGPDtG5nIHZp4buHYyB0aGVvIG5nw6BuaCBuZ2jhu4EsIGNow7puZyB0w7RpIGNo4buJIMSRxqFuIGdp4bqjbiDEkcawYSByYSBkYW5oIHPDoWNoIG3hu5l0IHPhu5EgdOG7qyBraMOzYSDEkcaw4bujYyBuaOG6r2MgxJHhur9uIG5oaeG7gXUgbmjhuqV0IHRyb25nIHRpw6p1IMSR4buBIGPDtG5nIHZp4buHYy4NCg0KTmjDs20gY8OhYyBjw7RuZyB2aeG7h2MgbGnDqm4gcXVhbiDEkeG6v24gdMawIHbhuqVuIChDb25zdWx0YW50KSwgUXXhuqNuIGzDrSAoTWFuYWdlciksIEjhu5cgdHLhu6MgKEFzc2lzdGFudCksIE9mZmljZXIgdsOgIHBow6F0IHRyaeG7g24gKERldmVsb3BtZW50KSBsw6AgbmjDs20gNSBjw7RuZyB2aeG7h2MgY2hp4bq/bSB04buJIHRy4buNbmcgbOG7m24gbmjhuqV0IChoxqFuIDI2JSkuIELhuqFuIGPDsyB0aOG7gyBjbGljayB2w6BvIFdvcmQgQ2xvdWQg4bufIGTGsOG7m2kgxJHhu4MgeGVtIHPhu5EgbMaw4bujbmcgdOG7qyDEkcaw4bujYyB0aOG7kW5nIGvDqi4NCg0KDQpgYGB7cn0NCmxpYnJhcnkodG0pDQoNCg0KQ29ycHVzKFZlY3RvclNvdXJjZShqb2Ikam9iX25hbWUgJT4lIHJlbmFtZV9qb2JfdGl0bGUoKSkpICU+JSANCiAgdG1fbWFwKHJlbW92ZVdvcmRzLCBjKCJmb3IiLCAiYW5kIiwgInRoZSIsICJ2aWV0bmFtIiwgImNvbmR1Y3QiKSkgJT4lIA0KICBUZXJtRG9jdW1lbnRNYXRyaXgoKSAtPiBkdG0NCg0KDQptIDwtIGFzLm1hdHJpeChkdG0pDQp2IDwtIHNvcnQocm93U3VtcyhtKSwgZGVjcmVhc2luZyA9IFRSVUUpDQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLCBmcmVxID0gdikNCg0KDQpsaWJyYXJ5KHdvcmRjbG91ZDIpDQoNCg0KIyB0b3Bfam9iIDwtIGQgJT4lIGZpbHRlcihmcmVxID49IDUwLCB3b3JkICE9IGQkd29yZFs3XSkNCiMgdG9wX2pvYiRmcmVxWzE6NV0gJT4lIHN1bSAvIHRvcF9qb2IkZnJlcSAlPiUgc3VtKCkNCg0KdG9wX2pvYiA8LSBkICU+JSBmaWx0ZXIod29yZCAhPSBkJHdvcmRbN10pDQoNCnNldC5zZWVkKDEpDQp3b3JkY2xvdWQyKHRvcF9qb2IsIA0KICAgICAgICAgICBjb2xvciA9ICJyYW5kb20tbGlnaHQiLCANCiAgICAgICAgICAgYmFja2dyb3VuZENvbG9yID0gImJsYWNrIiwgDQogICAgICAgICAgIHNpemUgPSAwLjcpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQp0b3Bfam9iICU+JSANCiAgc2xpY2UoMToyMCkgJT4lIA0KICBtdXRhdGUod29yZCA9IHN0cl90b191cHBlcih3b3JkKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIod29yZCwgZnJlcSksIGZyZXEpKSArIA0KICBnZW9tX2NvbCgpICsgDQogIGNvb3JkX2ZsaXAoKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcSksIGhqdXN0ID0gMS4xLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArIA0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIA0KICAgICAgIHRpdGxlID0gIjIwIE1vc3QgUG9wdWxhciBKb2JzIiwgDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy5uZ29jZW50cmUub3JnLnZuIikNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgZCAlPiUgDQojICAgc2xpY2UoMToyMCkgJT4lIA0KIyAgIG11dGF0ZSh3b3JkID0gc3RyX3RvX3VwcGVyKHdvcmQpKSAlPiUgDQojICAgZ2dwbG90KGFlcyhyZW9yZGVyKHdvcmQsIGZyZXEpLCBmcmVxKSkgKyANCiMgICBnZW9tX2NvbCgpICsgDQojICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZyZXEpLCBoanVzdCA9IDEuMSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gNCkgKyANCiMgICBjb29yZF9mbGlwKCkgKyANCiMgICB0aGVtZV9taW5pbWFsKCkgKyANCiMgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQojICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQojICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KIyAgIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCANCiMgICAgICAgIHRpdGxlID0gIlRoZSBNb3N0IFJlY3J1aXRlZCBKb2JzIGJ5IE5HT3MiLCANCiMgICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IGh0dHA6Ly93d3cubmdvY2VudHJlLm9yZy52biIpDQoNCmBgYA0KDQojIMSQ4buLYSDEkWnhu4NtIGPhu6dhIGPDtG5nIHZp4buHYyDEkcaw4bujYyB0dXnhu4NuIGThu6VuZw0KDQpIw6AgTuG7mWkgdsOgIFRow6BuaCBQaOG7kSBI4buTIENow60gTWluaCBjaGnhur9tIDY3LjQlIHThu5VuZyBz4buRIGPDtG5nIHZp4buHYyDEkcaw4bujYyB0dXnhu4NuIGThu6VuZyBj4bunYSBjw6FjIE5HT3MgduG7m2kgc+G7kSBjw7RuZyB2aeG7h2MgxJHGsOG7o2MgdHV54buDbiBk4bulbmcgbOG6p24gbMaw4bujdCBsw6AgNjEyMyB2w6AgOTc5LiBDw7MgdGjhu4MgdGjhuqV5IGtow7RuZyBjaOG7iSBjw7Mgc+G7sSBt4bqldCBjw6JuIGLhurFuZyB24buBIHPhu5EgbMaw4bujbmcgY8O0bmcgdmnhu4djIMSRxrDhu6NjIHR1eeG7g24gY+G7p2EgaGFpIHRow6BuaCBwaOG7kSBs4bubbiBuw6B5IHNvIHbhu5tpIHBo4bqnbiBjw7JuIGzhuqFpIHbDoCBjw7JuIGPDsyBz4buxIGLhuqV0IMSR4buRaSB44bupbmcgbOG7m24gZ2nhu69hIGhhaSDEkeG7i2EgxJFp4buDbSBjw7Mgbmhp4buBdSBjw7RuZyB2aeG7h2MgxJHGsOG7o2MgxJHEg25nIHR1eeG7g24gbmjhuqV0IGtoaSB04buJIGzhu4cgY2jDqm5oIGzhu4djaCBsw6AgaMahbiA2IGzhuqduLiBL4bq/dCBxdeG6oyBuw6B5IGPFqW5nIGzDoCBk4buFIGhp4buDdSB2w6wgaOG6p3UgaOG6v3QgY8OhYyBuaMOgIHTDoGkgdHLhu6MgxJHhu4F1IGPDsyB0cuG7pSBz4bufIOG7nyBIw6AgTuG7mWksIHNhdSDEkcOzIG3hu5tpIMSR4bq/biBTw6BpIEfDsm4uIFR1eSB24bqteSBjxaluZyBjw7MgdGjhu4MgdGjhuqV5IHbhuqtuIGPDsyBoxqFuIDMwJSBjw7RuZyB2aeG7h2MgxJHGsOG7o2MgdHV54buDbiBk4bulbmcgY2hvIGPDoWMgduG7iyB0csOtIOG7nyB04buJbmguIE5nb8OgaSByYSBz4buRIGzGsOG7o25nIHZp4buHYyDEkcSDbmcgdHLDqm4gdHJhbmcgVlVGTyBjxaluZyBraMO0bmcgcGjhuqNuIOG6o25oIGjhur90IHPhu5Egdmnhu4djIMSRxrDhu6NjIHR1eeG7g24g4bufIMSR4buLYSBwaMawxqFuZywgdGjDtG5nIHRoxrDhu51uZyBjw6FjIGPDtG5nIHZp4buHYyBuw6B5IHPhur0gxJHGsOG7o2MgdHV54buDbiBk4bulbmcgdHLhu7FjIHRp4bq/cCB04bqhaSB04buJbmggdGjDtG5nIHF1YSBjw6FjIGvDqm5oIHR1eeG7g24gZOG7pW5nIMSR4buLYSBwaMawxqFuZy4NCg0KYGBge3J9DQpqb2IkbG9jX25hbWUgLT4gbG9jYXRpb24NCnUgPC0gbG9jYXRpb24gJT4lIA0KICBzdHJfc3BsaXQocGF0dGVybiA9ICIsIiwgc2ltcGxpZnkgPSBUUlVFKSAlPiUgDQogIGFzLnZlY3RvcigpDQoNCnVbdSA9PSAiTmEiXSA8LSBOQQ0KDQoNCnUgJT4lIA0KICBzdHJfdHJpbSgpICU+JSANCiAgdGFibGUoKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKSAtPiB1DQoNCm5hbWVzKHUpIDwtIGMoIndvcmQiLCAiZnJlcSIpDQoNCnUgJT4lICANCiAgYXJyYW5nZSgtZnJlcSkgJT4lIA0KICBzbGljZSgtMSkgJT4lIA0KICBmaWx0ZXIoZnJlcSA+PSAxMCkgLT4gcA0KDQojIHAkZnJlcVtjKDEsIDIpXSAlPiUgc3VtKCkgLyBwJGZyZXEgJT4lIHN1bSgpDQoNCg0KIyBI4bqndSBo4bq/dCBjw6FjIGpvYiDEkeG7gXUg4bufIEjDoCBO4buZaSB2w6AgU8OgaSBHw7JuOiANCiMgd29yZGNsb3VkMihwLCANCiMgICAgICAgICAgICBjb2xvciA9ICJyYW5kb20tbGlnaHQiLCANCiMgICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3IgPSAiYmxhY2siKQ0KDQoNCnAgJT4lIA0KICBzbGljZSgtYygxLCAyKSkgJT4lIA0KICBzbGljZSgxOjI1KSAlPiUgDQogIG11dGF0ZSh3b3JkID0gc3RyX3RvX3VwcGVyKHdvcmQpICU+JSBhcy5mYWN0b3IoKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIod29yZCwgZnJlcSksIGZyZXEpKSArIA0KICBnZW9tX2NvbCgpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxKSwgaGp1c3QgPSAxLjEsIGNvbG9yID0gIndoaXRlIikgKyANCiAgY29vcmRfZmxpcCgpICsgDQogIHRoZW1lX21pbmltYWwoKSArIA0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiVG9wIDI1IExvY2F0aW9ucyBmb3IgTkdPIEpvYnMiLCANCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBodHRwOi8vd3d3Lm5nb2NlbnRyZS5vcmcudm4iKQ0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQojIE7hur91IGtow7RuZyB0w61uaCDEkeG6v24gaGFpIHRow6BuaCBwaOG7kSBuw6B5IHRow6w6IA0KIyB3b3JkY2xvdWQyKHAgJT4lIHNsaWNlKC1jKDEsIDIpKSwgDQojICAgICAgICAgICAgY29sb3IgPSAicmFuZG9tLWxpZ2h0IiwgDQojICAgICAgICAgICAgYmFja2dyb3VuZENvbG9yID0gImJsYWNrIiwgDQojICAgICAgICAgICAgc2l6ZSA9IDAuNCkNCmBgYA0KDQo=