Problem 1: Tax Code

Tiền xử lí số liệu (Data Pre-processing) là một khâu mất nhiều thời gian. Post này sử dụng bộ dữ liệu VES - Vietnam Enterprise Survey được cung cấp bởi Dr. Mai Vu. Đọc và xem qua một số thông tin về bộ dữ liệu này:

#===================================================================
#  Data Processing Project with real-world data: VES 2015 data set
#  Data Source: maivp@ftu.edu.vn
#===================================================================

# Clear work space: 
rm(list = ls())

# Import data: 

haven::read_dta("F:\\VES_from_MaiVu_FTU\\Stata_2015\\dn2015.dta") -> dn2015

# Load dplyr gackage: 
library(dplyr)

# Number of columns/rows: 
dim(dn2015)
## [1] 455238    150

Bộ dữ liệu này là lớn với 455238 quan sát và 150 cột biến. Theo quy định của các cơ quan quản lí tại Việt Nam thì:

  1. Mỗi một DN chỉ có một mã số thuế duy nhất và mã số thuế này là độc nhất.
  2. Một mã số thuế hợp lệ dùng 10 chữ số.

Tuy nhiên một số MST (mã số thuế) trong bộ dữ liệu chỉ có 5 chữ số. Mặt khác, một số DN có MST trùng nhau. Chúng ta sẽ loại bỏ các quan sát này ra khỏi bộ dữ liệu ban đầu như sau:

#---------- Remove firms with duplicated tax code ---------------

dn2015 %>% 
  group_by(ma_thue) %>% 
  summarise(tansuat = n()) -> df_tansuat_mathue

df_tansuat_mathue %>% 
  filter(tansuat > 1) %>% 
  pull(ma_thue) -> tax_codes_duplicated

# Remove duplications: 

dn2015 %>% filter(!duplicated(ma_thue)) -> dn2015

#--------- Remove firms with tax code != 10 digits ----------------

library(stringr)

dn2015 %>% filter(str_count(ma_thue) == 10) -> dn2015

Problem 2: VSIC Code 5 Digits

Theo Quyết định số 27/2018/QĐ-TTg thì mã ngành cấp 5 của doanh nghiệp sẽ phải có 5 chữ số. Tuy nhiên một số quan sát thì mã ngành chỉ có 4 chữ số. Ta có thể suy luận rằng nguyên nhân là do một số ngành có mã với số 0 đứng ở vị trí đầu tiên đã bị “biến mất” trong quá trình vào-lưu-gửi dữ liệu:

# Number of digits from nganh_kd: 

dn2015 %>% mutate(vsic_n_digits = str_count(nganh_kd)) -> dn2015

dn2015 %>% 
  group_by(vsic_n_digits) %>% 
  summarise(tansuat = n()) %>% 
  arrange(-tansuat)
## # A tibble: 3 × 2
##   vsic_n_digits tansuat
##           <int>   <int>
## 1             5  440397
## 2             4    9502
## 3            NA       2

Kết quả này chỉ ra có 9502 quan sát mà mã ngành (VSIC Code) có 4 kí tự. Chúng ta có thể khôi phục nguyên trạng VISIC Code như sau:

# Add 0 for 4-digits sector codes: 

dn2015 %>% 
  mutate(nganh_kd = as.character(nganh_kd)) %>% 
  mutate(vsic_adj  = case_when(vsic_n_digits == 4 ~ str_c("0", nganh_kd), TRUE ~ nganh_kd)) -> dn2015

# Remove missing: 

dn2015 %>% filter(!is.na(nganh_kd)) -> dn2015

Chúng ta có thể viết một hàm mà xử lí đồng thời cả hai việc: (1) loại bỏ các observations mà tax code không hợp lệ, và (2) khôi phục - loại bỏ các quan sát mà VSIC codes không hợp lí như sau:

# Function for processing/cleaning data: 

cleaning_data_tax_vsic_code <- function(your_ves_data) {
  
  # your_ves_data <- dn2015
  
  # Convert to text: 
  
  your_ves_data %>% mutate(nganh_kd = as.character(nganh_kd)) -> ves_data 
  
  # Remove missing at nganh_kd: 
  
  ves_data %>% filter(!is.na(nganh_kd)) -> ves_data
  
  # Remove missing at ma_thue: 
  
  ves_data %>% filter(!is.na(ma_thue)) -> ves_data
  
  #---------------
  # VSIC 5 digits
  #---------------
  
  ves_data %>% 
    mutate(nganh_kd = case_when(str_count(nganh_kd) == 4 ~ str_c("0", nganh_kd), TRUE ~ nganh_kd)) %>% 
    filter(str_count(nganh_kd) == 5) -> ves_data
  
  #----------------------
  # Tax code processing
  #----------------------
  
  # Remove missing: 
  
  ves_data %>% filter(!is.na(ma_thue)) -> ves_data
  
  # Remove duplications: 
  
  ves_data %>% filter(!duplicated(ma_thue)) -> ves_data
  
  # Remove cases != 10 digits: 
  
  ves_data %>% filter(str_count(ma_thue) == 10) -> ves_data

  return(ves_data)
  
}

Với hàm đã có ở trên chúng ta có thể sử dụng để thực hiện việc xử lí tax-vsic code cho bất kì bộ dữ liệu nào. Chẳng hạn của năm 2014:

# Load VES data - 2014: 

haven::read_dta("F:\\VES_from_MaiVu_FTU\\Stata_2014\\dn2014.dta") -> dn2014

# Clean data for VES 2014 data: 

dn2014 %>% cleaning_data_tax_vsic_code() -> dn2014_processed

Problem 3: VSIC Code Level 3

Cũng theo quyết định 27/2018/QĐ-TTg thì mã ngành cấp 3 và cấp 4 có sự khác biệt. Do vậy chúng ta cần xử lí (hay đồng nhất) về các mã cấp 3 và cấp 4 này. Trước hết load dữ liệu chuyển đổi VSIC code:

# Load data (download from https://dangkykinhdoanh.gov.vn/vn/Pages/NganhNghe.aspx): 

readxl::read_xls("C://Users//Admin//Documents//Bảng chuyển đổi VSIC 2018 - VSIC 2007.xls") -> vsic_converted

vsic_converted %>% slice(-c(1:4)) -> vsic_converted

names(vsic_converted) <- c("vsic_new_c3", "vsic_new_c4", "sector_name_new", 
                           "vsic_old_c3", "vsic_old_c4", "sector_name_old")

vsic_converted %>% 
  filter(vsic_new_c3 != vsic_old_c3) %>% 
  select(vsic_new_c3, vsic_old_c3, sector_name_new, sector_name_old) -> vsic_diff_c3

# Show: 

vsic_diff_c3 %>% 
  select(vsic_new_c3, vsic_old_c3)
## # A tibble: 3 × 2
##   vsic_new_c3 vsic_old_c3
##   <chr>       <chr>      
## 1 023         022        
## 2 139         132        
## 3 799         792

Điều này có nghĩa là chúng ta cần phải, ví dụ, convert mã ngành (cấp 3) 022 về 023 (tên ngành: Khai thác, thu nhặt lâm sản khác trừ gỗ). Dưới đây là R codes xử lí:

# Extract old VSIC codes: 

dn2014_processed %>% 
  mutate(code_l2 = str_sub(nganh_kd, start = 1, end = 2), 
         code_l3 = str_sub(nganh_kd, start = 1, end = 3), 
         code_l4 = str_sub(nganh_kd, start = 1, end = 4), 
         code_5_end = str_sub(nganh_kd, start = 5, end = 5)) -> dn2014_processed

#-------------------------------------
#      Adjust VSIC code level 3
#-------------------------------------

# Solution 1 (use case_when() funtion): 

vsic_diff_c3$vsic_old_c3 -> vsic_old_c3

vsic_diff_c3$vsic_new_c3 -> vsic_new_c3

dn2014_processed %>% 
  mutate(code_l3_adj = case_when(code_l3 == vsic_old_c3[1] ~ vsic_new_c3[1], 
                                 code_l3 == vsic_old_c3[2] ~ vsic_new_c3[2], 
                                 code_l3 == vsic_old_c3[3] ~ vsic_new_c3[3], 
                                 TRUE ~ code_l3)) -> dn2014_processed_c1

# Check output: 

dn2014_processed_c1 %>% 
  filter(code_l3 %in% vsic_old_c3) %>% 
  select(nganh_kd, contains("code")) %>% 
  sample_n(6)
## # A tibble: 6 × 6
##   nganh_kd code_l2 code_l3 code_l4 code_5_end code_l3_adj
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>      
## 1 13220    13      132     1322    0          139        
## 2 13290    13      132     1329    0          139        
## 3 13220    13      132     1322    0          139        
## 4 13220    13      132     1322    0          139        
## 5 13220    13      132     1322    0          139        
## 6 13220    13      132     1322    0          139
# Solution 2: 

full_join(dn2014_processed, 
          vsic_diff_c3 %>% select(vsic_new_c3, code_l3 = vsic_old_c3),
          by = c("code_l3")) -> dn2014_processed_c2

# Compare: 

dn2014_processed_c2 %>% 
  select(nganh_kd, contains("code"), vsic_new_c3) %>% 
  head()
## # A tibble: 6 × 6
##   nganh_kd code_l2 code_l3 code_l4 code_5_end vsic_new_c3
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>      
## 1 42101    42      421     4210    1          <NA>       
## 2 23941    23      239     2394    1          <NA>       
## 3 41000    41      410     4100    0          <NA>       
## 4 33140    33      331     3314    0          <NA>       
## 5 42200    42      422     4220    0          <NA>       
## 6 21001    21      210     2100    1          <NA>
dn2014_processed_c2 %>% 
  select(nganh_kd, contains("code"), vsic_new_c3) %>% 
  filter(!is.na(vsic_new_c3)) %>% 
  head()
## # A tibble: 6 × 6
##   nganh_kd code_l2 code_l3 code_l4 code_5_end vsic_new_c3
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>      
## 1 13220    13      132     1322    0          139        
## 2 13220    13      132     1322    0          139        
## 3 13220    13      132     1322    0          139        
## 4 13220    13      132     1322    0          139        
## 5 13220    13      132     1322    0          139        
## 6 13220    13      132     1322    0          139
# Process for missing: 

dn2014_processed_c2 %>% 
  mutate(code_l3_adj = case_when(is.na(vsic_new_c3) ~ code_l3, TRUE ~ vsic_new_c3)) -> dn2014_processed_c2

# Final output: 

dn2014_processed_c2 %>% 
  select(nganh_kd, contains("code"), vsic_new_c3) %>% 
  head()
## # A tibble: 6 × 7
##   nganh_kd code_l2 code_l3 code_l4 code_5_end code_l3_adj vsic_new_c3
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>       <chr>      
## 1 42101    42      421     4210    1          421         <NA>       
## 2 23941    23      239     2394    1          239         <NA>       
## 3 41000    41      410     4100    0          410         <NA>       
## 4 33140    33      331     3314    0          331         <NA>       
## 5 42200    42      422     4220    0          422         <NA>       
## 6 21001    21      210     2100    1          210         <NA>
# Check again: 

dn2014_processed_c2 %>% 
  filter(code_l3 %in% vsic_old_c3) %>% 
  select(nganh_kd, contains("code"), vsic_new_c3) %>% 
  head()
## # A tibble: 6 × 7
##   nganh_kd code_l2 code_l3 code_l4 code_5_end code_l3_adj vsic_new_c3
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>       <chr>      
## 1 13220    13      132     1322    0          139         139        
## 2 13220    13      132     1322    0          139         139        
## 3 13220    13      132     1322    0          139         139        
## 4 13220    13      132     1322    0          139         139        
## 5 13220    13      132     1322    0          139         139        
## 6 13220    13      132     1322    0          139         139

Problem 4: VSIC Code Level 4

Hiệu chỉnh VSIC cấp 4 nảy sinh một vấn đề: đó là sự không rõ ràng và tường minh. Một ví dụ là mã ngành cấp 4 (theo hệ thống cũ) 0130 (Nhân và chăm sóc cây giống nông nghiệp) sẽ được convert sang mã 0131 (Nhân và chăm sóc cây giống hàng năm) hoặc 0132 (Nhân và chăm sóc cây giống lâu năm). Tuy nhiên luật chuyển đổi không tuyên bố rõ tình huống nào thì 0130 sẽ chuyển đổi sang mã 0131/0132 như ta có thể thấy:

vsic_converted %>% 
  filter(vsic_new_c4 != vsic_old_c4) -> vsic_diff_c4

library(knitr)

vsic_diff_c4 %>% 
  select(-1, -4) %>% 
  slice(1:2) %>%  
  kable()
vsic_new_c4 sector_name_new vsic_old_c4 sector_name_old
0131 Nhân và chăm sóc cây giống hàng năm 0130 Nhân và chăm sóc cây giống nông nghiệp
0132 Nhân và chăm sóc cây giống lâu năm 0130 Nhân và chăm sóc cây giống nông nghiệp

Trong khi chưa rõ ràng về luật chuyển đổi mã cấp 4 cho những cases trùng nhau này, chúng ta tạm chấp nhận giải pháp sau để hiệu chỉnh mã ngành cấp 4:

#-------------------------------------
#      Adjust VSIC code level 4
#-------------------------------------

vsic_diff_c4 %>% 
  filter(!duplicated(vsic_old_c4)) %>% 
  select(vsic_new_c4, code_l4 = vsic_old_c4) -> convert_table_c4

full_join(dn2014_processed_c2, convert_table_c4, by = "code_l4") -> dn2014_processed_c2

# Our data: 

dn2014_processed_c2 %>% 
  select(nganh_kd, contains("code"), vsic_new_c4) %>% 
  head()
## # A tibble: 6 × 7
##   nganh_kd code_l2 code_l3 code_l4 code_5_end code_l3_adj vsic_new_c4
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>       <chr>      
## 1 42101    42      421     4210    1          421         4211       
## 2 23941    23      239     2394    1          239         <NA>       
## 3 41000    41      410     4100    0          410         4101       
## 4 33140    33      331     3314    0          331         <NA>       
## 5 42200    42      422     4220    0          422         4221       
## 6 21001    21      210     2100    1          210         <NA>
# Adjust missing: 

dn2014_processed_c2 %>% 
  mutate(code_l4_adj = case_when(is.na(vsic_new_c4) ~ code_l4, TRUE ~ vsic_new_c4)) -> dn2014_processed_c2

# Compare: 

dn2014_processed_c2 %>% 
  select(nganh_kd, contains("code"), vsic_new_c4) %>% 
  head()
## # A tibble: 6 × 8
##   nganh_kd code_l2 code_l3 code_l4 code_5_end code_l3_adj code_l4_adj vsic_new…¹
##   <chr>    <chr>   <chr>   <chr>   <chr>      <chr>       <chr>       <chr>     
## 1 42101    42      421     4210    1          421         4211        4211      
## 2 23941    23      239     2394    1          239         2394        <NA>      
## 3 41000    41      410     4100    0          410         4101        4101      
## 4 33140    33      331     3314    0          331         3314        <NA>      
## 5 42200    42      422     4220    0          422         4221        4221      
## 6 21001    21      210     2100    1          210         2100        <NA>      
## # … with abbreviated variable name ¹​vsic_new_c4

Đến đây chúng ta đã hiệu chỉnh xong mã ngành cấp 4. Chúng ta có thể khôi phục lại mã ngành đầy đủ theo quyết định 27/2018/QĐ-TTg cho dữ liệu của năm 2014 rồi lưu lại để sử dụng hoặc gửi cho đồng nghiệp như sau:

# Create new VSIC code: 

dn2014_processed_c2 %>% 
  mutate(vsic_code = str_c(code_l4_adj, code_5_end)) -> dn2014_processed_c2

# Check again: 

dn2014_processed_c2 %>% 
  select(nganh_kd, contains("code"), contains("vsic")) %>% 
  head() %>% 
  kable()
nganh_kd code_l2 code_l3 code_l4 code_5_end code_l3_adj code_l4_adj vsic_code vsic_new_c3 vsic_new_c4
42101 42 421 4210 1 421 4211 42111 NA 4211
41000 41 410 4100 0 410 4101 41010 NA 4101
42200 42 422 4220 0 422 4221 42210 NA 4221
41000 41 410 4100 0 410 4101 41010 NA 4101
42102 42 421 4210 2 421 4211 42112 NA 4211
41000 41 410 4100 0 410 4101 41010 NA 4101
# Save data: 

haven::write_dta(dn2014_processed_c2, "dn2014_cleaned.dta")

Problem 5: VSIC Code Level 1

Các paper thường chỉ sử dụng đến mã ngành cấp 1 hoặc cấp 2. Trước hết lấy dữ liệu về mã ngành cấp 1 (và cả cấp 2) như sau:

# --------------------------------------------------------------------------------
# Extract sector code from https://dangkykinhdoanh.gov.vn/vn/Pages/NganhNghe.aspx
#---------------------------------------------------------------------------------

library(rvest)

link <- "https://dangkykinhdoanh.gov.vn/vn/Pages/NganhNghe.aspx"

link %>% 
  read_html() %>% 
  html_nodes(xpath = '//*[@id="ctl00_SPWebPartManager1_g_15a30b99_50d8_49e5_8f11_de265cb949e8"]/div/div[2]/table') %>% 
  html_table() %>% 
  .[[1]] -> df_sector_code

# Rename for columns: 

names(df_sector_code) <- c(str_c("code_level", 1:5), "sector_name")

# Remove/ filter data: 

df_sector_code %>% 
  slice(-1) %>% 
  filter(code_level1 != "21") %>% 
  mutate(sector_name_latin = stringi::stri_trans_general(sector_name, "Latin-ASCII")) -> df_sector_code

# Save for using laler: 

writexl::write_xlsx(df_sector_code, "df_sector_code.xlsx")

Có 21 ngành lớn (Cấp 1) theo quy định của chính phủ như ta thấy (chỉ hiển thị 6 ngành cấp 1):

df_sector_code %>% 
  filter(str_count(code_level1) != 0) %>% 
  select(code_level1, sector_name_latin) %>% 
  head() %>% 
  kable(caption = "Some Level-1 Sectors")
Some Level-1 Sectors
code_level1 sector_name_latin
A NONG NGHIEP, LAM NGHIEP VA THUY SAN
B KHAI KHOANG
C CONG NGHIEP CHE BIEN, CHE TAO
D SAN XUAT VA PHAN PHOI DIEN, KHI DOT, NUOC NONG, HOI NUOC VA DIEU HOA KHONG KHI
E CUNG CAP NUOC; HOAT DONG QUAN LY VA XU LY RAC THAI, NUOC THAI
F XAY DUNG

Để lấp đầy dữ liệu trống cho cột 1 chúng ta có thể sử dụng tidyr::fill() như sau:

df_sector_code %>% 
  mutate(code_level1 = case_when(str_count(code_level1) == 0 ~ NA_character_, TRUE ~ code_level1)) %>% 
  tidyr::fill(code_level1, .direction = "down") %>% 
  filter(str_detect(sector_name_latin, "[a-z]")) -> df_sector_code_filled

Tương tự:

df_sector_code_filled %>% 
  mutate(code_level2 = case_when(str_count(code_level2) == 0 ~ NA_character_, TRUE ~ code_level2)) %>% 
  tidyr::fill(code_level2, .direction = "down") -> df_sector_code_filled

Với data đã xử lí chúng ta có thể, ví dụ, báo cáo một số thống kê cho 21 ngành cấp 1:

df_sector_code %>% 
  select(code_level1, sector_name_latin) %>% 
  filter(str_count(code_level1) != 0) -> df_sector_l1

Rồi join các data sets:

full_join(df_sector_l1, 
          df_sector_code_filled %>% select(code_level1, code_level2)) -> df_sector_l1

df_sector_l1 %>% 
  rename(code_l2 = code_level2) %>% 
  filter(!duplicated(code_l2)) -> df_sector_l1


inner_join(dn2014_processed_c2, 
           df_sector_l1, 
           by = c("code_l2")) -> dn2014_processed_c2_updated 

Với data cuối cùng này chúng ta có thể, ví dụ, tạo ra báo cáo như sau:

dn2014_processed_c2_updated %>% 
  filter(!is.na(kqkd1)) %>% 
  group_by(sector_name_latin) %>% 
  summarise(Min = min(kqkd1), 
            Max = max(kqkd1), 
            SD = sd(kqkd1), 
            Median = median(kqkd1), 
            N_obs = n()) %>% 
  arrange(-N_obs) -> df_report

df_report %>% 
  mutate(sector_name_short = str_sub(sector_name_latin, 1, 20)) %>% 
  select(-sector_name_latin) %>% 
  select(sector_name_short, everything()) %>% 
  kable()
sector_name_short Min Max SD Median N_obs
XAY DUNG -514 7085110.0 104805.13 1692.0 41516
CONG NGHIEP CHE BIEN 0 6930426.0 257591.51 2517.0 3008
GIAO DUC VA DAO TAO 0 1647168.0 67346.63 364.0 1379
VAN TAI KHO BAI -220 3179655.0 131597.57 1209.5 1008
SAN XUAT VA PHAN PHO 0 52630921.0 2991102.80 3159.0 691
HOAT DONG HANH CHINH 0 435217.0 23495.42 348.5 584
HOAT DONG CHUYEN MON 0 179989.0 14849.89 210.0 247
BAN BUON VA BAN LE; 0 245064.8 30109.35 1433.5 80
HOAT DONG TAI CHINH, 0 6587334.0 1239477.31 23633.0 52

Task for You

Bằng các bước xử lí như trên chúng ta có thể hiệu chỉnh mã ngành cấp 3, cấp 4 và tạo ra mã ngành VSIC mới cho bất kì bộ dữ liệu nào. Tuy nhiên sẽ thuận lợi hơn khi viết thành hàm để còn tái sử dụng nhằm đảm bảo nguyên lí DRY. Hãy viết hai hàm lần lượt có tên là process_vsic3()process_vsic4() để hiệu chỉnh mã cấp 3 và cấp 4 nếu input của hàm là một data frame.

Dưới đây là phương án đề xuất để viết hai hàm có mô tả ở trên:

# Function corrects VSIC Level 3: 

process_vsic3 <- function(your_df) {
  
  your_df %>% 
    mutate(code_l2 = str_sub(nganh_kd, start = 1, end = 2), 
           code_l3 = str_sub(nganh_kd, start = 1, end = 3), 
           code_l4 = str_sub(nganh_kd, start = 1, end = 4), 
           code_5_end = str_sub(nganh_kd, start = 5, end = 5)) -> your_df
  
  full_join(your_df, 
            vsic_diff_c3 %>% select(vsic_new_c3, code_l3 = vsic_old_c3),
            by = c("code_l3")) -> your_df
  
  your_df %>% 
    mutate(code_l3_adj = case_when(is.na(vsic_new_c3) ~ code_l3, TRUE ~ vsic_new_c3)) -> final_df
  
  return(final_df)
}

# Function corrects VSIC Level 4:


process_vsic4 <- function(your_df) {
  
  your_df %>% 
    mutate(code_l2 = str_sub(nganh_kd, start = 1, end = 2), 
           code_l3 = str_sub(nganh_kd, start = 1, end = 3), 
           code_l4 = str_sub(nganh_kd, start = 1, end = 4), 
           code_5_end = str_sub(nganh_kd, start = 5, end = 5)) -> your_df
  
  full_join(your_df, convert_table_c4, by = "code_l4") -> your_df
  
  your_df %>% 
    mutate(code_l4_adj = case_when(is.na(vsic_new_c4) ~ code_l4, TRUE ~ vsic_new_c4)) -> final_df
  
  your_df %>% 
    mutate(code_l4_adj = case_when(is.na(vsic_new_c4) ~ code_l4, TRUE ~ vsic_new_c4)) %>% 
    mutate(nganh_kd_adj = str_c(code_l4_adj, code_5_end)) %>% 
    mutate(code_l2_adj = str_sub(nganh_kd_adj, start = 1, end = 2)) -> final_df
  
  return(final_df)
  
}

Với hai hàm này chúng ta có thể xử lí dữ liệu VES cho bất cứ năm nào. Ví dụ:

# Load VES 2015: 

haven::read_dta("F:\\VES_from_MaiVu_FTU\\Stata_2015\\dn2015.dta") -> dn2015

# Process VES 2015 data: 

dn2015 %>% 
  cleaning_data_tax_vsic_code() %>% 
  process_vsic3() %>% 
  process_vsic4() -> dn2015_after_processing

Tương tự chúng ta viết hàm join tên ngành cấp 1:

# Funtions join sector name: 

add_sector_name_at_level_1 <- function(your_df) {
  
  inner_join(your_df, 
             df_sector_l1, 
             by = c("code_l2_adj" = "code_l2")) -> final_df
  
  return(final_df)
  
}

Rồi sử dụng hàm này:

dn2015_after_processing %>% add_sector_name_at_level_1() -> dn2015_after_processing

Tính toán một số thống kê cho kqkd1 theo ngành cấp 1 cho năm 2015:

dn2015_after_processing %>% 
  filter(!is.na(kqkd1)) %>% 
  group_by(sector_name_latin) %>% 
  summarise(Min = min(kqkd1), 
            Max = max(kqkd1), 
            SD = sd(kqkd1), 
            Median = median(kqkd1), 
            N_obs = n()) %>% 
  arrange(-N_obs) %>% 
  mutate(sector_name_short = str_sub(sector_name_latin, 1, 20)) %>% 
  select(-sector_name_latin) %>% 
  select(sector_name_short, everything()) %>% 
  kable()
sector_name_short Min Max SD Median N_obs
BAN BUON VA BAN LE; 0 105559749 395966.60 2102.00 169612
CONG NGHIEP CHE BIEN 0 375812792 2153560.26 2816.00 66510
XAY DUNG -26 11966123 133276.12 1717.00 58651
HOAT DONG CHUYEN MON -95 3404914 39534.42 435.00 36787
VAN TAI KHO BAI 0 10965323 130059.25 2175.00 26425
DICH VU LUU TRU VA A 0 4694252 62100.38 586.00 16056
HOAT DONG HANH CHINH 0 4815353 68874.28 545.00 15457
THONG TIN VA TRUYEN 0 10098702 145922.91 231.15 9448
HOAT DONG KINH DOANH 0 7292986 169680.21 290.50 8624
NONG NGHIEP, LAM NGH 0 13207539 190797.08 944.00 6300
GIAO DUC VA DAO TAO 0 1136408 35180.19 106.00 5283
HOAT DONG TAI CHINH, -292 22942233 785044.73 1699.00 3175
HOAT DONG DICH VU KH 0 366965 13330.10 165.00 3155
KHAI KHOANG 0 57474075 1808576.59 3378.50 2396
NGHE THUAT, VUI CHOI 0 5615034 275200.03 153.00 2374
CUNG CAP NUOC; HOAT 0 2826496 118502.49 1002.00 1702
SAN XUAT VA PHAN PHO 0 77951360 3103259.73 2445.00 1495
Y TE VA HOAT DONG TR 0 969653 59694.20 753.90 1420

Prepare Panel Data

Giả sử chúng ta áp dụng Panel Data cho các năm 2014, 2015, 2016 để ước lượng mô hình sau:

\[\begin{equation} Y_{it}=\beta_{1}+\beta_{2}X_{it}+e_{it} \label{eq:panelgeneq15} \end{equation}\]

Trong đó Y là kqkd1 và X là ts11. Trước hết xử lí dữ liệu theo chuỗi như chúng ta đã biết cho năm 2014 và 2016:

# For 2014: 

haven::read_dta("F:\\VES_from_MaiVu_FTU\\Stata_2014\\dn2014.dta") %>% 
  cleaning_data_tax_vsic_code() %>% 
  process_vsic3() %>% 
  process_vsic4() %>% 
  add_sector_name_at_level_1() -> dn2014_after_processing

# For 2016: 

haven::read_dta("F:\\VES_from_MaiVu_FTU\\New data (2016-2020)\\Stata_2016\\dn2016.dta") %>% 
  cleaning_data_tax_vsic_code() %>% 
  process_vsic3() %>% 
  process_vsic4() %>% 
  add_sector_name_at_level_1() -> dn2016_after_processing

Tạo Panel Data:

dn2014_after_processing %>% 
  select(nganh_kd, ma_thue, sector_name_latin, kqkd1, ts11) %>% 
  mutate(year = 2014) %>% 
  na.omit() -> df2014

dn2015_after_processing %>% 
  select(nganh_kd, ma_thue, sector_name_latin, kqkd1, ts11) %>% 
  mutate(year = 2015) %>% 
  na.omit() -> df2015

dn2016_after_processing %>% 
  select(nganh_kd, ma_thue, sector_name_latin, kqkd1, ts11) %>% 
  mutate(year = 2016) %>% 
  na.omit() -> df2016

df2014 %>% 
  bind_rows(df2015) %>% 
  bind_rows(df2016) -> my_panel

# Prepare panel data: 

library(plm)

pdata.frame(my_panel, 
            index = c("ma_thue","year"), 
            row.names = FALSE, 
            drop.index = FALSE) -> panel_data_unbalanced

Tính toán một số thống kê thường được trình bày trong các paper:

library(tidyr)

my_panel %>% 
  select(kqkd1, ts11, year) %>% 
  pivot_longer(cols = c("kqkd1", "ts11"), names_to = "variable", values_to = "value") %>% 
  group_by(variable) %>% 
  summarise(Mean = mean(value), 
            Median = median(value), 
            SD = sd(value), 
            Min = min(value), 
            Max = max(value), 
            N_obs = n()) %>% 
  kable()
variable Mean Median SD Min Max N_obs
kqkd1 33309.63 1540 934370.5 -575.0 457221004 1281370
ts11 38280.46 4058 974257.8 -48923.9 350857811 1281370

Với dữ liệu đã có, chúng ta có thể chạy các mô hình phân tích cho Panel Data. Chẳng hạn ba cách tiếp cận được chọn là Pooled, Fixed Effects và Random Effects sử dụng ước lượng Amemiya:

#========================
# Some Panel Data Models
#========================

# Pooled Model: 
panel_pooled <- plm(kqkd1 ~ ts11, 
                    data = panel_data_unbalanced, 
                    model = "pooling") 

# Fixed Effects Model: 
panel_fe <- plm(kqkd1 ~ ts11, 
                data = panel_data_unbalanced, 
                model = "within")  

# Random Effects Models using Amemiya estimators (1971): 
panel_re <- plm(kqkd1 ~ ts11, 
                data = panel_data_unbalanced, 
                model = "random", 
                random.method = "amemiya")

Rồi so sánh các ước lượng từ ba mô hình này:

# Compare results: 

library(stargazer)

stargazer(panel_pooled, 
          panel_fe, 
          panel_re, 
          title = "Compare Panel Data Regression Results - Unbalanced",
          column.labels = c("Pooled","Fixed Effects", "Random Effects"), 
          type = "text", 
          align = TRUE)
## 
## Compare Panel Data Regression Results - Unbalanced
## ===========================================================================================
##                                           Dependent variable:                              
##              ------------------------------------------------------------------------------
##                                                  kqkd1                                     
##                           Pooled                      Fixed Effects          Random Effects
##                            (1)                             (2)                    (3)      
## -------------------------------------------------------------------------------------------
## ts11                     0.391***                        0.208***               0.240***   
##                          (0.001)                         (0.001)                (0.001)    
##                                                                                            
## Constant              18,342.110***                                          20,272.890*** 
##                         (754.302)                                             (1,086.506)  
##                                                                                            
## -------------------------------------------------------------------------------------------
## Observations            1,281,370                       1,281,370              1,281,370   
## R2                        0.166                           0.109                  0.120     
## Adjusted R2               0.166                           -0.568                 0.120     
## F Statistic  255,430.000*** (df = 1; 1281368) 89,487.630*** (df = 1; 727852) 174,088.900***
## ===========================================================================================
## Note:                                                           *p<0.1; **p<0.05; ***p<0.01

Balanced Panel Data

Để chuẩn bị Balanced Panel Data chúng ta làm như sau:

my_panel %>% 
  group_by(ma_thue) %>% 
  summarise(tansuat = n()) %>% 
  filter(tansuat == 3) %>% 
  pull(ma_thue) -> firms_3_times

pdata.frame(my_panel %>% filter(ma_thue %in% firms_3_times), 
            index = c("ma_thue","year"), 
            row.names = FALSE, 
            drop.index = FALSE) -> panel_data_balanced

Rồi thực hiện lại các bước phân tích như trên:

# Pooled Model: 
panel_pooled_b <- plm(kqkd1 ~ ts11, 
                      data = panel_data_balanced, 
                      model = "pooling") 

# Fixed Effects Model: 
panel_fe_b <- plm(kqkd1 ~ ts11, 
                  data = panel_data_balanced, 
                  model = "within")  

# Random Effects Models using Amemiya estimators (1971): 
panel_re_b <- plm(kqkd1 ~ ts11, 
                  data = panel_data_balanced, 
                  model = "random", 
                  random.method = "amemiya")

stargazer(panel_pooled_b, 
          panel_fe_b, 
          panel_re_b, 
          title = "Compare Panel Data Regression Results - Balanced",
          column.labels = c("Pooled","Fixed Effects", "Random Effects"), 
          type = "text", 
          align = TRUE)
## 
## Compare Panel Data Regression Results - Balanced
## ==========================================================================================
##                                           Dependent variable:                             
##              -----------------------------------------------------------------------------
##                                                  kqkd1                                    
##                          Pooled                      Fixed Effects          Random Effects
##                            (1)                            (2)                    (3)      
## ------------------------------------------------------------------------------------------
## ts11                    0.549***                        0.253***               0.308***   
##                          (0.001)                        (0.001)                (0.001)    
##                                                                                           
## Constant              17,471.040***                                         28,241.140*** 
##                        (1,009.208)                                           (1,747.594)  
##                                                                                           
## ------------------------------------------------------------------------------------------
## Observations             917,379                        917,379                917,379    
## R2                        0.213                          0.114                  0.132     
## Adjusted R2               0.213                          -0.329                 0.132     
## F Statistic  248,668.000*** (df = 1; 917377) 78,610.910*** (df = 1; 611585) 139,304.500***
## ==========================================================================================
## Note:                                                          *p<0.1; **p<0.05; ***p<0.01

Final Notes

Sử dụng VES (cùng với VHLSS) cho research paper là một công việc rất thách thức, đặt biệt là xử lí đồng thời nhiều bộ dữ liệu cùng lúc trong một khoảng thời gian dài. Về chỉ riêng điểm này thôi thì R tốt hơn Stata nhiều.

Appendix

#======================================
#      R codes for explanation
#======================================

# Clear R environment: 

rm(list = ls())

# Create fake data sets: 

ves_data <- data.frame(ma_thue = c("564", "213", "981", "", "213", "83", "745"), 
                       nganh_kd = c("64910", "13251", "2145", "17941", "13251", "27513", "1494")) # VES data


vsic_update <- data.frame(vsic3_new = c("139", "017"), 
                          vsic3_old = c("132", "014")) # Data for correcting. 

# Show our data: 

ves_data

vsic_update

#-------------------------
#  Duplicated Tax Code
#-------------------------

library(dplyr)

ves_data %>% 
  group_by(ma_thue) %>% 
  summarise(tansuat = n()) 

ves_data %>% 
  filter(!duplicated(ma_thue)) -> ves_not_dup

ves_not_dup

#----------------------
#  Taxt Code 3-digits
#----------------------

library(stringr)

ves_not_dup %>% 
  mutate(slkt_tax = str_count(ma_thue)) %>% 
  filter(slkt_tax == 3) # Solution 1. 

ves_not_dup %>% 
  filter(str_count(ma_thue) == 3) # Solution 2. 

#----------------------------
#  Add zero for sector code
#----------------------------

ves_not_dup %>% 
  filter(str_count(ma_thue) == 3) %>% 
  mutate(slkt_code = str_count(nganh_kd)) %>% 
  mutate(nganh_kd_adj = case_when(slkt_code == 4 ~ str_c("0", nganh_kd), 
                                  TRUE ~ nganh_kd))

ves_not_dup %>% 
  filter(str_count(ma_thue) == 3) %>% 
  mutate(slkt_code = str_count(nganh_kd)) %>% 
  mutate(nganh_kd = case_when(slkt_code == 4 ~ str_c("0", nganh_kd), 
                              TRUE ~ nganh_kd)) -> ves_cleaned

#-----------------------
#  Adjust sector code
#-----------------------

# About str_sub() function: 

ves_cleaned %>% pull(nganh_kd) -> nganh_vec

str_sub(nganh_vec, start = 1, end = 3)

str_sub(nganh_vec, start = 5, end = 5)

ves_cleaned %>% 
  mutate(code_l3 = str_sub(nganh_kd, start = 1, end = 3), 
         code_5th = str_sub(nganh_kd, start = 5, end = 5))

ves_cleaned %>% 
  mutate(code_l3 = str_sub(nganh_kd, start = 1, end = 3), 
         code_5th = str_sub(nganh_kd, start = 5, end = 5)) -> ves_cleaned

# Compare: 

vsic_update

vsic_update %>% pull(vsic3_old) -> old_code3

vsic_update$vsic3_new -> new_code3

# ----- Soluion 1 for correcting sector code -----

ves_cleaned %>% 
  mutate(code_l3_adj = case_when(code_l3 == old_code3[1] ~ new_code3[1], 
                                 code_l3 == old_code3[2] ~ new_code3[2], 
                                 TRUE ~ code_l3))

# ----  Soluion 2 for correcting sector code -----

full_join(ves_cleaned, vsic_update, by = c("code_l3" = "vsic3_old"))

inner_join(ves_cleaned, vsic_update, by = c("code_l3" = "vsic3_old"))

full_join(ves_cleaned, vsic_update, by = c("code_l3" = "vsic3_old")) -> ves_cleaned_new

ves_cleaned_new %>% 
  mutate(code_l3_adj = case_when(is.na(vsic3_new) ~ code_l3, 
                                 TRUE ~ vsic3_new))
LS0tDQp0aXRsZTogIkRhdGEgUHJlLXByb2Nlc3Npbmc6IENhc2Ugb2YgVmlldG5hbSBFbnRlcnByaXNlIFN1cnZleSAoVkVTKSINCmF1dGhvcjogJ0F1dGhvcjogTmd1eWVuIENoaSBEdW5nJw0Kc3VidGl0bGU6IERhdGEgUHJlLXByb2Nlc3NpbmcgU2VyaWVzLCBGVFUgU2hvcnQgQ291cnNlDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgY2FjaGUgPSBUUlVFKQ0KDQpgYGANCg0KDQoNCiFbXShDOlxcVXNlcnNcXEFkbWluXFxEb2N1bWVudHNcXHZlcy5wbmcpDQoNCg0KIyBQcm9ibGVtIDE6IFRheCBDb2RlDQoNClRp4buBbiB44butIGzDrSBz4buRIGxp4buHdSAoRGF0YSBQcmUtcHJvY2Vzc2luZykgbMOgIG3hu5l0IGtow6J1IG3huqV0IG5oaeG7gXUgdGjhu51pIGdpYW4uIFBvc3QgbsOgeSBz4butIGThu6VuZyBi4buZIGThu68gbGnhu4d1IFZFUyAtIFZpZXRuYW0gRW50ZXJwcmlzZSBTdXJ2ZXkgxJHGsOG7o2MgY3VuZyBj4bqlcCBi4bufaSBbRHIuIE1haSBWdV0oaHR0cHM6Ly9rdHF0LmZ0dS5lZHUudm4vdGhvbmctdGluLWRhby10YW8vaG8tc28tZ2lhbmctdmllbi90cy12dS10aGktcGh1b25nLW1haS8pLiDEkOG7jWMgdsOgIHhlbSBxdWEgbeG7mXQgc+G7kSB0aMO0bmcgdGluIHbhu4EgYuG7mSBk4buvIGxp4buHdSBuw6B5OiAgDQoNCg0KYGBge3J9DQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAgRGF0YSBQcm9jZXNzaW5nIFByb2plY3Qgd2l0aCByZWFsLXdvcmxkIGRhdGE6IFZFUyAyMDE1IGRhdGEgc2V0DQojICBEYXRhIFNvdXJjZTogbWFpdnBAZnR1LmVkdS52bg0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBDbGVhciB3b3JrIHNwYWNlOiANCnJtKGxpc3QgPSBscygpKQ0KDQojIEltcG9ydCBkYXRhOiANCg0KaGF2ZW46OnJlYWRfZHRhKCJGOlxcVkVTX2Zyb21fTWFpVnVfRlRVXFxTdGF0YV8yMDE1XFxkbjIwMTUuZHRhIikgLT4gZG4yMDE1DQoNCiMgTG9hZCBkcGx5ciBnYWNrYWdlOiANCmxpYnJhcnkoZHBseXIpDQoNCiMgTnVtYmVyIG9mIGNvbHVtbnMvcm93czogDQpkaW0oZG4yMDE1KQ0KYGBgDQoNCg0KQuG7mSBk4buvIGxp4buHdSBuw6B5IGzDoCBs4bubbiB24bubaSA0NTUyMzggcXVhbiBzw6F0IHbDoCAxNTAgY+G7mXQgYmnhur9uLiBUaGVvIHF1eSDEkeG7i25oIGPhu6dhIGPDoWMgY8ahIHF1YW4gcXXhuqNuIGzDrSB04bqhaSBWaeG7h3QgTmFtIHRow6w6IA0KDQoxLiBN4buXaSBt4buZdCBETiBjaOG7iSBjw7MgbeG7mXQgbcOjIHPhu5EgdGh14bq/IGR1eSBuaOG6pXQgdsOgIG3DoyBz4buRIHRodeG6vyBuw6B5IGzDoCDEkeG7mWMgbmjhuqV0LiANCjIuIE3hu5l0IG3DoyBz4buRIHRodeG6vyBo4bujcCBs4buHIGTDuW5nIDEwIGNo4buvIHPhu5EuIA0KDQpUdXkgbmhpw6puIG3hu5l0IHPhu5EgTVNUIChtw6Mgc+G7kSB0aHXhur8pIHRyb25nIGLhu5kgZOG7ryBsaeG7h3UgY2jhu4kgY8OzIDUgY2jhu68gc+G7kS4gTeG6t3Qga2jDoWMsIG3hu5l0IHPhu5EgRE4gY8OzIE1TVCB0csO5bmcgbmhhdS4gQ2jDum5nIHRhIHPhur0gbG/huqFpIGLhu48gY8OhYyBxdWFuIHPDoXQgbsOgeSByYSBraOG7j2kgYuG7mSBk4buvIGxp4buHdSBiYW4gxJHhuqd1IG5oxrAgc2F1OiANCg0KDQpgYGB7cn0NCiMtLS0tLS0tLS0tIFJlbW92ZSBmaXJtcyB3aXRoIGR1cGxpY2F0ZWQgdGF4IGNvZGUgLS0tLS0tLS0tLS0tLS0tDQoNCmRuMjAxNSAlPiUgDQogIGdyb3VwX2J5KG1hX3RodWUpICU+JSANCiAgc3VtbWFyaXNlKHRhbnN1YXQgPSBuKCkpIC0+IGRmX3RhbnN1YXRfbWF0aHVlDQoNCmRmX3RhbnN1YXRfbWF0aHVlICU+JSANCiAgZmlsdGVyKHRhbnN1YXQgPiAxKSAlPiUgDQogIHB1bGwobWFfdGh1ZSkgLT4gdGF4X2NvZGVzX2R1cGxpY2F0ZWQNCg0KIyBSZW1vdmUgZHVwbGljYXRpb25zOiANCg0KZG4yMDE1ICU+JSBmaWx0ZXIoIWR1cGxpY2F0ZWQobWFfdGh1ZSkpIC0+IGRuMjAxNQ0KDQojLS0tLS0tLS0tIFJlbW92ZSBmaXJtcyB3aXRoIHRheCBjb2RlICE9IDEwIGRpZ2l0cyAtLS0tLS0tLS0tLS0tLS0tDQoNCmxpYnJhcnkoc3RyaW5ncikNCg0KZG4yMDE1ICU+JSBmaWx0ZXIoc3RyX2NvdW50KG1hX3RodWUpID09IDEwKSAtPiBkbjIwMTUNCmBgYA0KDQojIFByb2JsZW0gMjogVlNJQyBDb2RlIDUgRGlnaXRzDQoNCg0KVGhlbyBRdXnhur90IMSR4buLbmggc+G7kSBbMjcvMjAxOC9RxJAtVFRnXShodHRwczovL2RhbmdreWtpbmhkb2FuaC5nb3Yudm4vdm4vUGFnZXMvTmdhbmhOZ2hlLmFzcHgpIHRow6wgbcOjIG5nw6BuaCBj4bqlcCA1IGPhu6dhIGRvYW5oIG5naGnhu4dwIHPhur0gcGjhuqNpIGPDsyA1IGNo4buvIHPhu5EuIFR1eSBuaGnDqm4gbeG7mXQgc+G7kSBxdWFuIHPDoXQgdGjDrCBtw6MgbmfDoG5oIGNo4buJIGPDsyA0IGNo4buvIHPhu5EuIFRhIGPDsyB0aOG7gyBzdXkgbHXhuq1uIHLhurFuZyBuZ3V5w6puIG5ow6JuIGzDoCBkbyBt4buZdCBz4buRIG5nw6BuaCBjw7MgbcOjIHbhu5tpIHPhu5EgMCDEkeG7qW5nIOG7nyB24buLIHRyw60gxJHhuqd1IHRpw6puIMSRw6MgYuG7iyAiYmnhur9uIG3huqV0IiB0cm9uZyBxdcOhIHRyw6xuaCB2w6BvLWzGsHUtZ+G7rWkgZOG7ryBsaeG7h3U6IA0KDQoNCmBgYHtyfQ0KIyBOdW1iZXIgb2YgZGlnaXRzIGZyb20gbmdhbmhfa2Q6IA0KDQpkbjIwMTUgJT4lIG11dGF0ZSh2c2ljX25fZGlnaXRzID0gc3RyX2NvdW50KG5nYW5oX2tkKSkgLT4gZG4yMDE1DQoNCmRuMjAxNSAlPiUgDQogIGdyb3VwX2J5KHZzaWNfbl9kaWdpdHMpICU+JSANCiAgc3VtbWFyaXNlKHRhbnN1YXQgPSBuKCkpICU+JSANCiAgYXJyYW5nZSgtdGFuc3VhdCkNCg0KYGBgDQoNCkvhur90IHF14bqjIG7DoHkgY2jhu4kgcmEgY8OzIDk1MDIgcXVhbiBzw6F0IG3DoCBtw6MgbmfDoG5oIChWU0lDIENvZGUpIGPDsyA0IGvDrSB04buxLiBDaMO6bmcgdGEgY8OzIHRo4buDIGtow7RpIHBo4bulYyBuZ3V5w6puIHRy4bqhbmcgVklTSUMgQ29kZSBuaMawIHNhdTogDQoNCg0KYGBge3J9DQoNCiMgQWRkIDAgZm9yIDQtZGlnaXRzIHNlY3RvciBjb2RlczogDQoNCmRuMjAxNSAlPiUgDQogIG11dGF0ZShuZ2FuaF9rZCA9IGFzLmNoYXJhY3RlcihuZ2FuaF9rZCkpICU+JSANCiAgbXV0YXRlKHZzaWNfYWRqICA9IGNhc2Vfd2hlbih2c2ljX25fZGlnaXRzID09IDQgfiBzdHJfYygiMCIsIG5nYW5oX2tkKSwgVFJVRSB+IG5nYW5oX2tkKSkgLT4gZG4yMDE1DQoNCiMgUmVtb3ZlIG1pc3Npbmc6IA0KDQpkbjIwMTUgJT4lIGZpbHRlcighaXMubmEobmdhbmhfa2QpKSAtPiBkbjIwMTUNCg0KYGBgDQoNCkNow7puZyB0YSBjw7MgdGjhu4Mgdmnhur90IG3hu5l0IGjDoG0gbcOgIHjhu60gbMOtIMSR4buTbmcgdGjhu51pIGPhuqMgaGFpIHZp4buHYzogKDEpIGxv4bqhaSBi4buPIGPDoWMgb2JzZXJ2YXRpb25zIG3DoCB0YXggY29kZSBraMO0bmcgaOG7o3AgbOG7hywgdsOgICgyKSBraMO0aSBwaOG7pWMgLSBsb+G6oWkgYuG7jyBjw6FjIHF1YW4gc8OhdCBtw6AgVlNJQyBjb2RlcyBraMO0bmcgaOG7o3AgbMOtIG5oxrAgc2F1OiANCg0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gZm9yIHByb2Nlc3NpbmcvY2xlYW5pbmcgZGF0YTogDQoNCmNsZWFuaW5nX2RhdGFfdGF4X3ZzaWNfY29kZSA8LSBmdW5jdGlvbih5b3VyX3Zlc19kYXRhKSB7DQogIA0KICAjIHlvdXJfdmVzX2RhdGEgPC0gZG4yMDE1DQogIA0KICAjIENvbnZlcnQgdG8gdGV4dDogDQogIA0KICB5b3VyX3Zlc19kYXRhICU+JSBtdXRhdGUobmdhbmhfa2QgPSBhcy5jaGFyYWN0ZXIobmdhbmhfa2QpKSAtPiB2ZXNfZGF0YSANCiAgDQogICMgUmVtb3ZlIG1pc3NpbmcgYXQgbmdhbmhfa2Q6IA0KICANCiAgdmVzX2RhdGEgJT4lIGZpbHRlcighaXMubmEobmdhbmhfa2QpKSAtPiB2ZXNfZGF0YQ0KICANCiAgIyBSZW1vdmUgbWlzc2luZyBhdCBtYV90aHVlOiANCiAgDQogIHZlc19kYXRhICU+JSBmaWx0ZXIoIWlzLm5hKG1hX3RodWUpKSAtPiB2ZXNfZGF0YQ0KICANCiAgIy0tLS0tLS0tLS0tLS0tLQ0KICAjIFZTSUMgNSBkaWdpdHMNCiAgIy0tLS0tLS0tLS0tLS0tLQ0KICANCiAgdmVzX2RhdGEgJT4lIA0KICAgIG11dGF0ZShuZ2FuaF9rZCA9IGNhc2Vfd2hlbihzdHJfY291bnQobmdhbmhfa2QpID09IDQgfiBzdHJfYygiMCIsIG5nYW5oX2tkKSwgVFJVRSB+IG5nYW5oX2tkKSkgJT4lIA0KICAgIGZpbHRlcihzdHJfY291bnQobmdhbmhfa2QpID09IDUpIC0+IHZlc19kYXRhDQogIA0KICAjLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KICAjIFRheCBjb2RlIHByb2Nlc3NpbmcNCiAgIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiAgDQogICMgUmVtb3ZlIG1pc3Npbmc6IA0KICANCiAgdmVzX2RhdGEgJT4lIGZpbHRlcighaXMubmEobWFfdGh1ZSkpIC0+IHZlc19kYXRhDQogIA0KICAjIFJlbW92ZSBkdXBsaWNhdGlvbnM6IA0KICANCiAgdmVzX2RhdGEgJT4lIGZpbHRlcighZHVwbGljYXRlZChtYV90aHVlKSkgLT4gdmVzX2RhdGENCiAgDQogICMgUmVtb3ZlIGNhc2VzICE9IDEwIGRpZ2l0czogDQogIA0KICB2ZXNfZGF0YSAlPiUgZmlsdGVyKHN0cl9jb3VudChtYV90aHVlKSA9PSAxMCkgLT4gdmVzX2RhdGENCg0KICByZXR1cm4odmVzX2RhdGEpDQogIA0KfQ0KDQpgYGANCg0KVuG7m2kgaMOgbSDEkcOjIGPDsyDhu58gdHLDqm4gY2jDum5nIHRhIGPDsyB0aOG7gyBz4butIGThu6VuZyDEkeG7gyB0aOG7sWMgaGnhu4duIHZp4buHYyB44butIGzDrSB0YXgtdnNpYyBjb2RlIGNobyBi4bqldCBrw6wgYuG7mSBk4buvIGxp4buHdSBuw6BvLiBDaOG6s25nIGjhuqFuIGPhu6dhIG7Eg20gMjAxNDogDQoNCg0KYGBge3J9DQojIExvYWQgVkVTIGRhdGEgLSAyMDE0OiANCg0KaGF2ZW46OnJlYWRfZHRhKCJGOlxcVkVTX2Zyb21fTWFpVnVfRlRVXFxTdGF0YV8yMDE0XFxkbjIwMTQuZHRhIikgLT4gZG4yMDE0DQoNCiMgQ2xlYW4gZGF0YSBmb3IgVkVTIDIwMTQgZGF0YTogDQoNCmRuMjAxNCAlPiUgY2xlYW5pbmdfZGF0YV90YXhfdnNpY19jb2RlKCkgLT4gZG4yMDE0X3Byb2Nlc3NlZA0KDQpgYGANCg0KIyBQcm9ibGVtIDM6IFZTSUMgQ29kZSBMZXZlbCAzIA0KDQpDxaluZyB0aGVvIHF1eeG6v3QgxJHhu4tuaCAyNy8yMDE4L1HEkC1UVGcgdGjDrCBtw6MgbmfDoG5oIGPhuqVwIDMgdsOgIGPhuqVwIDQgY8OzIHPhu7Ega2jDoWMgYmnhu4d0LiBEbyB24bqteSBjaMO6bmcgdGEgY+G6p24geOG7rSBsw60gKGhheSDEkeG7k25nIG5o4bqldCkgduG7gSBjw6FjIG3DoyBj4bqlcCAzIHbDoCBj4bqlcCA0IG7DoHkuIFRyxrDhu5tjIGjhur90IGxvYWQgZOG7ryBsaeG7h3UgY2h1eeG7g24gxJHhu5VpIFZTSUMgY29kZTogDQoNCg0KYGBge3J9DQojIExvYWQgZGF0YSAoZG93bmxvYWQgZnJvbSBodHRwczovL2RhbmdreWtpbmhkb2FuaC5nb3Yudm4vdm4vUGFnZXMvTmdhbmhOZ2hlLmFzcHgpOiANCg0KcmVhZHhsOjpyZWFkX3hscygiQzovL1VzZXJzLy9BZG1pbi8vRG9jdW1lbnRzLy9C4bqjbmcgY2h1eeG7g24gxJHhu5VpIFZTSUMgMjAxOCAtIFZTSUMgMjAwNy54bHMiKSAtPiB2c2ljX2NvbnZlcnRlZA0KDQp2c2ljX2NvbnZlcnRlZCAlPiUgc2xpY2UoLWMoMTo0KSkgLT4gdnNpY19jb252ZXJ0ZWQNCg0KbmFtZXModnNpY19jb252ZXJ0ZWQpIDwtIGMoInZzaWNfbmV3X2MzIiwgInZzaWNfbmV3X2M0IiwgInNlY3Rvcl9uYW1lX25ldyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgInZzaWNfb2xkX2MzIiwgInZzaWNfb2xkX2M0IiwgInNlY3Rvcl9uYW1lX29sZCIpDQoNCnZzaWNfY29udmVydGVkICU+JSANCiAgZmlsdGVyKHZzaWNfbmV3X2MzICE9IHZzaWNfb2xkX2MzKSAlPiUgDQogIHNlbGVjdCh2c2ljX25ld19jMywgdnNpY19vbGRfYzMsIHNlY3Rvcl9uYW1lX25ldywgc2VjdG9yX25hbWVfb2xkKSAtPiB2c2ljX2RpZmZfYzMNCg0KIyBTaG93OiANCg0KdnNpY19kaWZmX2MzICU+JSANCiAgc2VsZWN0KHZzaWNfbmV3X2MzLCB2c2ljX29sZF9jMykNCmBgYA0KDQrEkGnhu4F1IG7DoHkgY8OzIG5naMSpYSBsw6AgY2jDum5nIHRhIGPhuqduIHBo4bqjaSwgdsOtIGThu6UsIGNvbnZlcnQgbcOjIG5nw6BuaCAoY+G6pXAgMykgMDIyIHbhu4EgMDIzICh0w6puIG5nw6BuaDogS2hhaSB0aMOhYywgdGh1IG5o4bq3dCBsw6JtIHPhuqNuIGtow6FjIHRy4burIGfhu5cpLiBExrDhu5tpIMSRw6J5IGzDoCBSIGNvZGVzIHjhu60gbMOtOiANCg0KYGBge3J9DQojIEV4dHJhY3Qgb2xkIFZTSUMgY29kZXM6IA0KDQpkbjIwMTRfcHJvY2Vzc2VkICU+JSANCiAgbXV0YXRlKGNvZGVfbDIgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDEsIGVuZCA9IDIpLCANCiAgICAgICAgIGNvZGVfbDMgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDEsIGVuZCA9IDMpLCANCiAgICAgICAgIGNvZGVfbDQgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDEsIGVuZCA9IDQpLCANCiAgICAgICAgIGNvZGVfNV9lbmQgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDUsIGVuZCA9IDUpKSAtPiBkbjIwMTRfcHJvY2Vzc2VkDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICAgICAgQWRqdXN0IFZTSUMgY29kZSBsZXZlbCAzDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFNvbHV0aW9uIDEgKHVzZSBjYXNlX3doZW4oKSBmdW50aW9uKTogDQoNCnZzaWNfZGlmZl9jMyR2c2ljX29sZF9jMyAtPiB2c2ljX29sZF9jMw0KDQp2c2ljX2RpZmZfYzMkdnNpY19uZXdfYzMgLT4gdnNpY19uZXdfYzMNCg0KZG4yMDE0X3Byb2Nlc3NlZCAlPiUgDQogIG11dGF0ZShjb2RlX2wzX2FkaiA9IGNhc2Vfd2hlbihjb2RlX2wzID09IHZzaWNfb2xkX2MzWzFdIH4gdnNpY19uZXdfYzNbMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kZV9sMyA9PSB2c2ljX29sZF9jM1syXSB+IHZzaWNfbmV3X2MzWzJdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZGVfbDMgPT0gdnNpY19vbGRfYzNbM10gfiB2c2ljX25ld19jM1szXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gY29kZV9sMykpIC0+IGRuMjAxNF9wcm9jZXNzZWRfYzENCg0KIyBDaGVjayBvdXRwdXQ6IA0KDQpkbjIwMTRfcHJvY2Vzc2VkX2MxICU+JSANCiAgZmlsdGVyKGNvZGVfbDMgJWluJSB2c2ljX29sZF9jMykgJT4lIA0KICBzZWxlY3Qobmdhbmhfa2QsIGNvbnRhaW5zKCJjb2RlIikpICU+JSANCiAgc2FtcGxlX24oNikNCg0KIyBTb2x1dGlvbiAyOiANCg0KZnVsbF9qb2luKGRuMjAxNF9wcm9jZXNzZWQsIA0KICAgICAgICAgIHZzaWNfZGlmZl9jMyAlPiUgc2VsZWN0KHZzaWNfbmV3X2MzLCBjb2RlX2wzID0gdnNpY19vbGRfYzMpLA0KICAgICAgICAgIGJ5ID0gYygiY29kZV9sMyIpKSAtPiBkbjIwMTRfcHJvY2Vzc2VkX2MyDQoNCiMgQ29tcGFyZTogDQoNCmRuMjAxNF9wcm9jZXNzZWRfYzIgJT4lIA0KICBzZWxlY3Qobmdhbmhfa2QsIGNvbnRhaW5zKCJjb2RlIiksIHZzaWNfbmV3X2MzKSAlPiUgDQogIGhlYWQoKQ0KDQpkbjIwMTRfcHJvY2Vzc2VkX2MyICU+JSANCiAgc2VsZWN0KG5nYW5oX2tkLCBjb250YWlucygiY29kZSIpLCB2c2ljX25ld19jMykgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHZzaWNfbmV3X2MzKSkgJT4lIA0KICBoZWFkKCkNCg0KIyBQcm9jZXNzIGZvciBtaXNzaW5nOiANCg0KZG4yMDE0X3Byb2Nlc3NlZF9jMiAlPiUgDQogIG11dGF0ZShjb2RlX2wzX2FkaiA9IGNhc2Vfd2hlbihpcy5uYSh2c2ljX25ld19jMykgfiBjb2RlX2wzLCBUUlVFIH4gdnNpY19uZXdfYzMpKSAtPiBkbjIwMTRfcHJvY2Vzc2VkX2MyDQoNCiMgRmluYWwgb3V0cHV0OiANCg0KZG4yMDE0X3Byb2Nlc3NlZF9jMiAlPiUgDQogIHNlbGVjdChuZ2FuaF9rZCwgY29udGFpbnMoImNvZGUiKSwgdnNpY19uZXdfYzMpICU+JSANCiAgaGVhZCgpDQoNCiMgQ2hlY2sgYWdhaW46IA0KDQpkbjIwMTRfcHJvY2Vzc2VkX2MyICU+JSANCiAgZmlsdGVyKGNvZGVfbDMgJWluJSB2c2ljX29sZF9jMykgJT4lIA0KICBzZWxlY3Qobmdhbmhfa2QsIGNvbnRhaW5zKCJjb2RlIiksIHZzaWNfbmV3X2MzKSAlPiUgDQogIGhlYWQoKQ0KDQoNCmBgYA0KDQojIFByb2JsZW0gNDogVlNJQyBDb2RlIExldmVsIDQNCg0KSGnhu4d1IGNo4buJbmggVlNJQyBj4bqlcCA0IG7huqN5IHNpbmggbeG7mXQgduG6pW4gxJHhu4E6IMSRw7MgbMOgIHPhu7Ega2jDtG5nIHLDtSByw6BuZyB2w6AgdMaw4budbmcgbWluaC4gTeG7mXQgdsOtIGThu6UgbMOgIG3DoyBuZ8OgbmggY+G6pXAgNCAodGhlbyBo4buHIHRo4buRbmcgY8WpKSAwMTMwIChOaMOibiB2w6AgY2jEg20gc8OzYyBjw6J5IGdp4buRbmcgbsO0bmcgbmdoaeG7h3ApIHPhur0gxJHGsOG7o2MgY29udmVydCBzYW5nIG3DoyAwMTMxIChOaMOibiB2w6AgY2jEg20gc8OzYyBjw6J5IGdp4buRbmcgaMOgbmcgbsSDbSkgaG/hurdjIDAxMzIgKE5ow6JuIHbDoCBjaMSDbSBzw7NjIGPDonkgZ2nhu5FuZyBsw6J1IG7Eg20pLiBUdXkgbmhpw6puIGx14bqtdCBjaHV54buDbiDEkeG7lWkga2jDtG5nIHR1ecOqbiBi4buRIHLDtSB0w6xuaCBodeG7kW5nIG7DoG8gdGjDrCAwMTMwIHPhur0gY2h1eeG7g24gxJHhu5VpIHNhbmcgbcOjIDAxMzEvMDEzMiBuaMawIHRhIGPDsyB0aOG7gyB0aOG6pXk6IA0KDQpgYGB7cn0NCg0KdnNpY19jb252ZXJ0ZWQgJT4lIA0KICBmaWx0ZXIodnNpY19uZXdfYzQgIT0gdnNpY19vbGRfYzQpIC0+IHZzaWNfZGlmZl9jNA0KDQpsaWJyYXJ5KGtuaXRyKQ0KDQp2c2ljX2RpZmZfYzQgJT4lIA0KICBzZWxlY3QoLTEsIC00KSAlPiUgDQogIHNsaWNlKDE6MikgJT4lICANCiAga2FibGUoKQ0KDQpgYGANCg0KVHJvbmcga2hpIGNoxrBhIHLDtSByw6BuZyB24buBIGx14bqtdCBjaHV54buDbiDEkeG7lWkgbcOjIGPhuqVwIDQgY2hvIG5o4buvbmcgY2FzZXMgdHLDuW5nIG5oYXUgbsOgeSwgY2jDum5nIHRhIHThuqFtIGNo4bqlcCBuaOG6rW4gZ2nhuqNpIHBow6FwIHNhdSDEkeG7gyBoaeG7h3UgY2jhu4luaCBtw6MgbmfDoG5oIGPhuqVwIDQ6IA0KDQoNCmBgYHtyfQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgICAgICBBZGp1c3QgVlNJQyBjb2RlIGxldmVsIDQNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCnZzaWNfZGlmZl9jNCAlPiUgDQogIGZpbHRlcighZHVwbGljYXRlZCh2c2ljX29sZF9jNCkpICU+JSANCiAgc2VsZWN0KHZzaWNfbmV3X2M0LCBjb2RlX2w0ID0gdnNpY19vbGRfYzQpIC0+IGNvbnZlcnRfdGFibGVfYzQNCg0KZnVsbF9qb2luKGRuMjAxNF9wcm9jZXNzZWRfYzIsIGNvbnZlcnRfdGFibGVfYzQsIGJ5ID0gImNvZGVfbDQiKSAtPiBkbjIwMTRfcHJvY2Vzc2VkX2MyDQoNCiMgT3VyIGRhdGE6IA0KDQpkbjIwMTRfcHJvY2Vzc2VkX2MyICU+JSANCiAgc2VsZWN0KG5nYW5oX2tkLCBjb250YWlucygiY29kZSIpLCB2c2ljX25ld19jNCkgJT4lIA0KICBoZWFkKCkNCg0KIyBBZGp1c3QgbWlzc2luZzogDQoNCmRuMjAxNF9wcm9jZXNzZWRfYzIgJT4lIA0KICBtdXRhdGUoY29kZV9sNF9hZGogPSBjYXNlX3doZW4oaXMubmEodnNpY19uZXdfYzQpIH4gY29kZV9sNCwgVFJVRSB+IHZzaWNfbmV3X2M0KSkgLT4gZG4yMDE0X3Byb2Nlc3NlZF9jMg0KDQojIENvbXBhcmU6IA0KDQpkbjIwMTRfcHJvY2Vzc2VkX2MyICU+JSANCiAgc2VsZWN0KG5nYW5oX2tkLCBjb250YWlucygiY29kZSIpLCB2c2ljX25ld19jNCkgJT4lIA0KICBoZWFkKCkNCg0KYGBgDQoNCsSQ4bq/biDEkcOieSBjaMO6bmcgdGEgxJHDoyBoaeG7h3UgY2jhu4luaCB4b25nIG3DoyBuZ8OgbmggY+G6pXAgNC4gQ2jDum5nIHRhIGPDsyB0aOG7gyBraMO0aSBwaOG7pWMgbOG6oWkgbcOjIG5nw6BuaCDEkeG6p3kgxJHhu6cgdGhlbyBxdXnhur90IMSR4buLbmggMjcvMjAxOC9RxJAtVFRnIGNobyBk4buvIGxp4buHdSBj4bunYSBuxINtIDIwMTQgcuG7k2kgbMawdSBs4bqhaSDEkeG7gyBz4butIGThu6VuZyBob+G6t2MgZ+G7rWkgY2hvIMSR4buTbmcgbmdoaeG7h3AgbmjGsCBzYXU6IA0KDQoNCmBgYHtyfQ0KIyBDcmVhdGUgbmV3IFZTSUMgY29kZTogDQoNCmRuMjAxNF9wcm9jZXNzZWRfYzIgJT4lIA0KICBtdXRhdGUodnNpY19jb2RlID0gc3RyX2MoY29kZV9sNF9hZGosIGNvZGVfNV9lbmQpKSAtPiBkbjIwMTRfcHJvY2Vzc2VkX2MyDQoNCiMgQ2hlY2sgYWdhaW46IA0KDQpkbjIwMTRfcHJvY2Vzc2VkX2MyICU+JSANCiAgc2VsZWN0KG5nYW5oX2tkLCBjb250YWlucygiY29kZSIpLCBjb250YWlucygidnNpYyIpKSAlPiUgDQogIGhlYWQoKSAlPiUgDQogIGthYmxlKCkNCg0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIFNhdmUgZGF0YTogDQoNCmhhdmVuOjp3cml0ZV9kdGEoZG4yMDE0X3Byb2Nlc3NlZF9jMiwgImRuMjAxNF9jbGVhbmVkLmR0YSIpDQoNCmBgYA0KDQojIFByb2JsZW0gNTogVlNJQyBDb2RlIExldmVsIDENCg0KQ8OhYyBwYXBlciB0aMaw4budbmcgY2jhu4kgc+G7rSBk4bulbmcgxJHhur9uIG3DoyBuZ8OgbmggY+G6pXAgMSBob+G6t2MgY+G6pXAgMi4gVHLGsOG7m2MgaOG6v3QgbOG6pXkgZOG7ryBsaeG7h3UgduG7gSBtw6MgbmfDoG5oIGPhuqVwIDEgKHbDoCBj4bqjIGPhuqVwIDIpIG5oxrAgc2F1OiANCg0KYGBge3J9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEV4dHJhY3Qgc2VjdG9yIGNvZGUgZnJvbSBodHRwczovL2RhbmdreWtpbmhkb2FuaC5nb3Yudm4vdm4vUGFnZXMvTmdhbmhOZ2hlLmFzcHgNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KbGlicmFyeShydmVzdCkNCg0KbGluayA8LSAiaHR0cHM6Ly9kYW5na3lraW5oZG9hbmguZ292LnZuL3ZuL1BhZ2VzL05nYW5oTmdoZS5hc3B4Ig0KDQpsaW5rICU+JSANCiAgcmVhZF9odG1sKCkgJT4lIA0KICBodG1sX25vZGVzKHhwYXRoID0gJy8vKltAaWQ9ImN0bDAwX1NQV2ViUGFydE1hbmFnZXIxX2dfMTVhMzBiOTlfNTBkOF80OWU1XzhmMTFfZGUyNjVjYjk0OWU4Il0vZGl2L2RpdlsyXS90YWJsZScpICU+JSANCiAgaHRtbF90YWJsZSgpICU+JSANCiAgLltbMV1dIC0+IGRmX3NlY3Rvcl9jb2RlDQoNCiMgUmVuYW1lIGZvciBjb2x1bW5zOiANCg0KbmFtZXMoZGZfc2VjdG9yX2NvZGUpIDwtIGMoc3RyX2MoImNvZGVfbGV2ZWwiLCAxOjUpLCAic2VjdG9yX25hbWUiKQ0KDQojIFJlbW92ZS8gZmlsdGVyIGRhdGE6IA0KDQpkZl9zZWN0b3JfY29kZSAlPiUgDQogIHNsaWNlKC0xKSAlPiUgDQogIGZpbHRlcihjb2RlX2xldmVsMSAhPSAiMjEiKSAlPiUgDQogIG11dGF0ZShzZWN0b3JfbmFtZV9sYXRpbiA9IHN0cmluZ2k6OnN0cmlfdHJhbnNfZ2VuZXJhbChzZWN0b3JfbmFtZSwgIkxhdGluLUFTQ0lJIikpIC0+IGRmX3NlY3Rvcl9jb2RlDQoNCiMgU2F2ZSBmb3IgdXNpbmcgbGFsZXI6IA0KDQp3cml0ZXhsOjp3cml0ZV94bHN4KGRmX3NlY3Rvcl9jb2RlLCAiZGZfc2VjdG9yX2NvZGUueGxzeCIpDQoNCmBgYA0KDQpDw7MgMjEgbmfDoG5oIGzhu5tuIChD4bqlcCAxKSB0aGVvIHF1eSDEkeG7i25oIGPhu6dhIGNow61uaCBwaOG7pyBuaMawIHRhIHRo4bqleSAoY2jhu4kgaGnhu4NuIHRo4buLIDYgbmfDoG5oIGPhuqVwIDEpOg0KDQpgYGB7cn0NCmRmX3NlY3Rvcl9jb2RlICU+JSANCiAgZmlsdGVyKHN0cl9jb3VudChjb2RlX2xldmVsMSkgIT0gMCkgJT4lIA0KICBzZWxlY3QoY29kZV9sZXZlbDEsIHNlY3Rvcl9uYW1lX2xhdGluKSAlPiUgDQogIGhlYWQoKSAlPiUgDQogIGthYmxlKGNhcHRpb24gPSAiU29tZSBMZXZlbC0xIFNlY3RvcnMiKQ0KYGBgDQoNCsSQ4buDIGzhuqVwIMSR4bqneSBk4buvIGxp4buHdSB0cuG7kW5nIGNobyBj4buZdCAxIGNow7puZyB0YSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgdGlkeXI6OmZpbGwoKSBuaMawIHNhdToNCg0KYGBge3J9DQpkZl9zZWN0b3JfY29kZSAlPiUgDQogIG11dGF0ZShjb2RlX2xldmVsMSA9IGNhc2Vfd2hlbihzdHJfY291bnQoY29kZV9sZXZlbDEpID09IDAgfiBOQV9jaGFyYWN0ZXJfLCBUUlVFIH4gY29kZV9sZXZlbDEpKSAlPiUgDQogIHRpZHlyOjpmaWxsKGNvZGVfbGV2ZWwxLCAuZGlyZWN0aW9uID0gImRvd24iKSAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHNlY3Rvcl9uYW1lX2xhdGluLCAiW2Etel0iKSkgLT4gZGZfc2VjdG9yX2NvZGVfZmlsbGVkDQpgYGANCg0KVMawxqFuZyB04buxOiANCg0KYGBge3J9DQpkZl9zZWN0b3JfY29kZV9maWxsZWQgJT4lIA0KICBtdXRhdGUoY29kZV9sZXZlbDIgPSBjYXNlX3doZW4oc3RyX2NvdW50KGNvZGVfbGV2ZWwyKSA9PSAwIH4gTkFfY2hhcmFjdGVyXywgVFJVRSB+IGNvZGVfbGV2ZWwyKSkgJT4lIA0KICB0aWR5cjo6ZmlsbChjb2RlX2xldmVsMiwgLmRpcmVjdGlvbiA9ICJkb3duIikgLT4gZGZfc2VjdG9yX2NvZGVfZmlsbGVkDQpgYGANCg0KVuG7m2kgZGF0YSDEkcOjIHjhu60gbMOtIGNow7puZyB0YSBjw7MgdGjhu4MsIHbDrSBk4bulLCBiw6FvIGPDoW8gbeG7mXQgc+G7kSB0aOG7kW5nIGvDqiBjaG8gMjEgbmfDoG5oIGPhuqVwIDE6IA0KDQpgYGB7cn0NCmRmX3NlY3Rvcl9jb2RlICU+JSANCiAgc2VsZWN0KGNvZGVfbGV2ZWwxLCBzZWN0b3JfbmFtZV9sYXRpbikgJT4lIA0KICBmaWx0ZXIoc3RyX2NvdW50KGNvZGVfbGV2ZWwxKSAhPSAwKSAtPiBkZl9zZWN0b3JfbDENCg0KYGBgDQoNClLhu5NpIGpvaW4gY8OhYyBkYXRhIHNldHM6IA0KDQpgYGB7cn0NCg0KZnVsbF9qb2luKGRmX3NlY3Rvcl9sMSwgDQogICAgICAgICAgZGZfc2VjdG9yX2NvZGVfZmlsbGVkICU+JSBzZWxlY3QoY29kZV9sZXZlbDEsIGNvZGVfbGV2ZWwyKSkgLT4gZGZfc2VjdG9yX2wxDQoNCmRmX3NlY3Rvcl9sMSAlPiUgDQogIHJlbmFtZShjb2RlX2wyID0gY29kZV9sZXZlbDIpICU+JSANCiAgZmlsdGVyKCFkdXBsaWNhdGVkKGNvZGVfbDIpKSAtPiBkZl9zZWN0b3JfbDENCg0KDQppbm5lcl9qb2luKGRuMjAxNF9wcm9jZXNzZWRfYzIsIA0KICAgICAgICAgICBkZl9zZWN0b3JfbDEsIA0KICAgICAgICAgICBieSA9IGMoImNvZGVfbDIiKSkgLT4gZG4yMDE0X3Byb2Nlc3NlZF9jMl91cGRhdGVkIA0KDQoNCg0KDQoNCmBgYA0KDQpW4bubaSBkYXRhIGN14buRaSBjw7luZyBuw6B5IGNow7puZyB0YSBjw7MgdGjhu4MsIHbDrSBk4bulLCB04bqhbyByYSBiw6FvIGPDoW8gbmjGsCBzYXU6IA0KDQpgYGB7cn0NCmRuMjAxNF9wcm9jZXNzZWRfYzJfdXBkYXRlZCAlPiUgDQogIGZpbHRlcighaXMubmEoa3FrZDEpKSAlPiUgDQogIGdyb3VwX2J5KHNlY3Rvcl9uYW1lX2xhdGluKSAlPiUgDQogIHN1bW1hcmlzZShNaW4gPSBtaW4oa3FrZDEpLCANCiAgICAgICAgICAgIE1heCA9IG1heChrcWtkMSksIA0KICAgICAgICAgICAgU0QgPSBzZChrcWtkMSksIA0KICAgICAgICAgICAgTWVkaWFuID0gbWVkaWFuKGtxa2QxKSwgDQogICAgICAgICAgICBOX29icyA9IG4oKSkgJT4lIA0KICBhcnJhbmdlKC1OX29icykgLT4gZGZfcmVwb3J0DQoNCmRmX3JlcG9ydCAlPiUgDQogIG11dGF0ZShzZWN0b3JfbmFtZV9zaG9ydCA9IHN0cl9zdWIoc2VjdG9yX25hbWVfbGF0aW4sIDEsIDIwKSkgJT4lIA0KICBzZWxlY3QoLXNlY3Rvcl9uYW1lX2xhdGluKSAlPiUgDQogIHNlbGVjdChzZWN0b3JfbmFtZV9zaG9ydCwgZXZlcnl0aGluZygpKSAlPiUgDQogIGthYmxlKCkNCmBgYA0KDQoNCiMgVGFzayBmb3IgWW91DQoNCkLhurFuZyBjw6FjIGLGsOG7m2MgeOG7rSBsw60gbmjGsCB0csOqbiBjaMO6bmcgdGEgY8OzIHRo4buDIGhp4buHdSBjaOG7iW5oIG3DoyBuZ8OgbmggY+G6pXAgMywgY+G6pXAgNCB2w6AgdOG6oW8gcmEgbcOjIG5nw6BuaCBWU0lDIG3hu5tpIGNobyBi4bqldCBrw6wgYuG7mSBk4buvIGxp4buHdSBuw6BvLiBUdXkgbmhpw6puIHPhur0gdGh14bqtbiBs4bujaSBoxqFuIGtoaSB2aeG6v3QgdGjDoG5oIGjDoG0gxJHhu4MgY8OybiB0w6FpIHPhu60gZOG7pW5nIG5o4bqxbSDEkeG6o20gYuG6o28gbmd1ecOqbiBsw60gRFJZLiBIw6N5IHZp4bq/dCBoYWkgaMOgbSBs4bqnbiBsxrDhu6N0IGPDsyB0w6puIGzDoCBgcHJvY2Vzc192c2ljMygpYCB2w6AgYHByb2Nlc3NfdnNpYzQoKWAgxJHhu4MgaGnhu4d1IGNo4buJbmggbcOjIGPhuqVwIDMgdsOgIGPhuqVwIDQgbuG6v3UgaW5wdXQgY+G7p2EgaMOgbSBsw6AgbeG7mXQgZGF0YSBmcmFtZS4gDQoNCkTGsOG7m2kgxJHDonkgbMOgIHBoxrDGoW5nIMOhbiDEkeG7gSB4deG6pXQgxJHhu4Mgdmnhur90IGhhaSBow6BtIGPDsyBtw7QgdOG6oyDhu58gdHLDqm46IA0KDQoNCmBgYHtyfQ0KDQojIEZ1bmN0aW9uIGNvcnJlY3RzIFZTSUMgTGV2ZWwgMzogDQoNCnByb2Nlc3NfdnNpYzMgPC0gZnVuY3Rpb24oeW91cl9kZikgew0KICANCiAgeW91cl9kZiAlPiUgDQogICAgbXV0YXRlKGNvZGVfbDIgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDEsIGVuZCA9IDIpLCANCiAgICAgICAgICAgY29kZV9sMyA9IHN0cl9zdWIobmdhbmhfa2QsIHN0YXJ0ID0gMSwgZW5kID0gMyksIA0KICAgICAgICAgICBjb2RlX2w0ID0gc3RyX3N1YihuZ2FuaF9rZCwgc3RhcnQgPSAxLCBlbmQgPSA0KSwgDQogICAgICAgICAgIGNvZGVfNV9lbmQgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDUsIGVuZCA9IDUpKSAtPiB5b3VyX2RmDQogIA0KICBmdWxsX2pvaW4oeW91cl9kZiwgDQogICAgICAgICAgICB2c2ljX2RpZmZfYzMgJT4lIHNlbGVjdCh2c2ljX25ld19jMywgY29kZV9sMyA9IHZzaWNfb2xkX2MzKSwNCiAgICAgICAgICAgIGJ5ID0gYygiY29kZV9sMyIpKSAtPiB5b3VyX2RmDQogIA0KICB5b3VyX2RmICU+JSANCiAgICBtdXRhdGUoY29kZV9sM19hZGogPSBjYXNlX3doZW4oaXMubmEodnNpY19uZXdfYzMpIH4gY29kZV9sMywgVFJVRSB+IHZzaWNfbmV3X2MzKSkgLT4gZmluYWxfZGYNCiAgDQogIHJldHVybihmaW5hbF9kZikNCn0NCg0KIyBGdW5jdGlvbiBjb3JyZWN0cyBWU0lDIExldmVsIDQ6DQoNCg0KcHJvY2Vzc192c2ljNCA8LSBmdW5jdGlvbih5b3VyX2RmKSB7DQogIA0KICB5b3VyX2RmICU+JSANCiAgICBtdXRhdGUoY29kZV9sMiA9IHN0cl9zdWIobmdhbmhfa2QsIHN0YXJ0ID0gMSwgZW5kID0gMiksIA0KICAgICAgICAgICBjb2RlX2wzID0gc3RyX3N1YihuZ2FuaF9rZCwgc3RhcnQgPSAxLCBlbmQgPSAzKSwgDQogICAgICAgICAgIGNvZGVfbDQgPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDEsIGVuZCA9IDQpLCANCiAgICAgICAgICAgY29kZV81X2VuZCA9IHN0cl9zdWIobmdhbmhfa2QsIHN0YXJ0ID0gNSwgZW5kID0gNSkpIC0+IHlvdXJfZGYNCiAgDQogIGZ1bGxfam9pbih5b3VyX2RmLCBjb252ZXJ0X3RhYmxlX2M0LCBieSA9ICJjb2RlX2w0IikgLT4geW91cl9kZg0KICANCiAgeW91cl9kZiAlPiUgDQogICAgbXV0YXRlKGNvZGVfbDRfYWRqID0gY2FzZV93aGVuKGlzLm5hKHZzaWNfbmV3X2M0KSB+IGNvZGVfbDQsIFRSVUUgfiB2c2ljX25ld19jNCkpIC0+IGZpbmFsX2RmDQogIA0KICB5b3VyX2RmICU+JSANCiAgICBtdXRhdGUoY29kZV9sNF9hZGogPSBjYXNlX3doZW4oaXMubmEodnNpY19uZXdfYzQpIH4gY29kZV9sNCwgVFJVRSB+IHZzaWNfbmV3X2M0KSkgJT4lIA0KICAgIG11dGF0ZShuZ2FuaF9rZF9hZGogPSBzdHJfYyhjb2RlX2w0X2FkaiwgY29kZV81X2VuZCkpICU+JSANCiAgICBtdXRhdGUoY29kZV9sMl9hZGogPSBzdHJfc3ViKG5nYW5oX2tkX2Fkaiwgc3RhcnQgPSAxLCBlbmQgPSAyKSkgLT4gZmluYWxfZGYNCiAgDQogIHJldHVybihmaW5hbF9kZikNCiAgDQp9DQoNCmBgYA0KDQpW4bubaSBoYWkgaMOgbSBuw6B5IGNow7puZyB0YSBjw7MgdGjhu4MgeOG7rSBsw60gZOG7ryBsaeG7h3UgVkVTIGNobyBi4bqldCBj4bupIG7Eg20gbsOgby4gVsOtIGThu6U6IA0KDQpgYGB7cn0NCiMgTG9hZCBWRVMgMjAxNTogDQoNCmhhdmVuOjpyZWFkX2R0YSgiRjpcXFZFU19mcm9tX01haVZ1X0ZUVVxcU3RhdGFfMjAxNVxcZG4yMDE1LmR0YSIpIC0+IGRuMjAxNQ0KDQojIFByb2Nlc3MgVkVTIDIwMTUgZGF0YTogDQoNCmRuMjAxNSAlPiUgDQogIGNsZWFuaW5nX2RhdGFfdGF4X3ZzaWNfY29kZSgpICU+JSANCiAgcHJvY2Vzc192c2ljMygpICU+JSANCiAgcHJvY2Vzc192c2ljNCgpIC0+IGRuMjAxNV9hZnRlcl9wcm9jZXNzaW5nDQoNCmBgYA0KDQpUxrDGoW5nIHThu7EgY2jDum5nIHRhIHZp4bq/dCBow6BtIGpvaW4gdMOqbiBuZ8OgbmggY+G6pXAgMTogDQoNCmBgYHtyfQ0KIyBGdW50aW9ucyBqb2luIHNlY3RvciBuYW1lOiANCg0KYWRkX3NlY3Rvcl9uYW1lX2F0X2xldmVsXzEgPC0gZnVuY3Rpb24oeW91cl9kZikgew0KICANCiAgaW5uZXJfam9pbih5b3VyX2RmLCANCiAgICAgICAgICAgICBkZl9zZWN0b3JfbDEsIA0KICAgICAgICAgICAgIGJ5ID0gYygiY29kZV9sMl9hZGoiID0gImNvZGVfbDIiKSkgLT4gZmluYWxfZGYNCiAgDQogIHJldHVybihmaW5hbF9kZikNCiAgDQp9DQpgYGANCg0KUuG7k2kgc+G7rSBk4bulbmcgaMOgbSBuw6B5OiANCg0KYGBge3J9DQpkbjIwMTVfYWZ0ZXJfcHJvY2Vzc2luZyAlPiUgYWRkX3NlY3Rvcl9uYW1lX2F0X2xldmVsXzEoKSAtPiBkbjIwMTVfYWZ0ZXJfcHJvY2Vzc2luZw0KYGBgDQoNClTDrW5oIHRvw6FuIG3hu5l0IHPhu5EgdGjhu5FuZyBrw6ogY2hvIGtxa2QxIHRoZW8gbmfDoG5oIGPhuqVwIDEgY2hvIG7Eg20gMjAxNTogDQoNCmBgYHtyfQ0KZG4yMDE1X2FmdGVyX3Byb2Nlc3NpbmcgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGtxa2QxKSkgJT4lIA0KICBncm91cF9ieShzZWN0b3JfbmFtZV9sYXRpbikgJT4lIA0KICBzdW1tYXJpc2UoTWluID0gbWluKGtxa2QxKSwgDQogICAgICAgICAgICBNYXggPSBtYXgoa3FrZDEpLCANCiAgICAgICAgICAgIFNEID0gc2Qoa3FrZDEpLCANCiAgICAgICAgICAgIE1lZGlhbiA9IG1lZGlhbihrcWtkMSksIA0KICAgICAgICAgICAgTl9vYnMgPSBuKCkpICU+JSANCiAgYXJyYW5nZSgtTl9vYnMpICU+JSANCiAgbXV0YXRlKHNlY3Rvcl9uYW1lX3Nob3J0ID0gc3RyX3N1YihzZWN0b3JfbmFtZV9sYXRpbiwgMSwgMjApKSAlPiUgDQogIHNlbGVjdCgtc2VjdG9yX25hbWVfbGF0aW4pICU+JSANCiAgc2VsZWN0KHNlY3Rvcl9uYW1lX3Nob3J0LCBldmVyeXRoaW5nKCkpICU+JSANCiAga2FibGUoKQ0KYGBgDQoNCiMgUHJlcGFyZSBQYW5lbCBEYXRhIA0KDQpHaeG6oyBz4butIGNow7puZyB0YSDDoXAgZOG7pW5nIFBhbmVsIERhdGEgY2hvIGPDoWMgbsSDbSAyMDE0LCAyMDE1LCAyMDE2IMSR4buDIMaw4bubYyBsxrDhu6NuZyBtw7QgaMOsbmggc2F1OiANCg0KDQokJFxiZWdpbntlcXVhdGlvbn0gWV97aXR9PVxiZXRhX3sxfStcYmV0YV97Mn1YX3tpdH0rZV97aXR9IFxsYWJlbHtlcTpwYW5lbGdlbmVxMTV9IFxlbmR7ZXF1YXRpb259JCQNCg0KVHJvbmcgxJHDsyBZIGzDoCBrcWtkMSB2w6AgWCBsw6AgdHMxMS4gVHLGsOG7m2MgaOG6v3QgeOG7rSBsw60gZOG7ryBsaeG7h3UgdGhlbyBjaHXhu5dpIG5oxrAgY2jDum5nIHRhIMSRw6MgYmnhur90IGNobyBuxINtIDIwMTQgdsOgIDIwMTY6IA0KDQoNCmBgYHtyfQ0KIyBGb3IgMjAxNDogDQoNCmhhdmVuOjpyZWFkX2R0YSgiRjpcXFZFU19mcm9tX01haVZ1X0ZUVVxcU3RhdGFfMjAxNFxcZG4yMDE0LmR0YSIpICU+JSANCiAgY2xlYW5pbmdfZGF0YV90YXhfdnNpY19jb2RlKCkgJT4lIA0KICBwcm9jZXNzX3ZzaWMzKCkgJT4lIA0KICBwcm9jZXNzX3ZzaWM0KCkgJT4lIA0KICBhZGRfc2VjdG9yX25hbWVfYXRfbGV2ZWxfMSgpIC0+IGRuMjAxNF9hZnRlcl9wcm9jZXNzaW5nDQoNCiMgRm9yIDIwMTY6IA0KDQpoYXZlbjo6cmVhZF9kdGEoIkY6XFxWRVNfZnJvbV9NYWlWdV9GVFVcXE5ldyBkYXRhICgyMDE2LTIwMjApXFxTdGF0YV8yMDE2XFxkbjIwMTYuZHRhIikgJT4lIA0KICBjbGVhbmluZ19kYXRhX3RheF92c2ljX2NvZGUoKSAlPiUgDQogIHByb2Nlc3NfdnNpYzMoKSAlPiUgDQogIHByb2Nlc3NfdnNpYzQoKSAlPiUgDQogIGFkZF9zZWN0b3JfbmFtZV9hdF9sZXZlbF8xKCkgLT4gZG4yMDE2X2FmdGVyX3Byb2Nlc3NpbmcNCiAgDQpgYGANCg0KVOG6oW8gUGFuZWwgRGF0YTogDQoNCmBgYHtyfQ0KDQpkbjIwMTRfYWZ0ZXJfcHJvY2Vzc2luZyAlPiUgDQogIHNlbGVjdChuZ2FuaF9rZCwgbWFfdGh1ZSwgc2VjdG9yX25hbWVfbGF0aW4sIGtxa2QxLCB0czExKSAlPiUgDQogIG11dGF0ZSh5ZWFyID0gMjAxNCkgJT4lIA0KICBuYS5vbWl0KCkgLT4gZGYyMDE0DQoNCmRuMjAxNV9hZnRlcl9wcm9jZXNzaW5nICU+JSANCiAgc2VsZWN0KG5nYW5oX2tkLCBtYV90aHVlLCBzZWN0b3JfbmFtZV9sYXRpbiwga3FrZDEsIHRzMTEpICU+JSANCiAgbXV0YXRlKHllYXIgPSAyMDE1KSAlPiUgDQogIG5hLm9taXQoKSAtPiBkZjIwMTUNCg0KZG4yMDE2X2FmdGVyX3Byb2Nlc3NpbmcgJT4lIA0KICBzZWxlY3Qobmdhbmhfa2QsIG1hX3RodWUsIHNlY3Rvcl9uYW1lX2xhdGluLCBrcWtkMSwgdHMxMSkgJT4lIA0KICBtdXRhdGUoeWVhciA9IDIwMTYpICU+JSANCiAgbmEub21pdCgpIC0+IGRmMjAxNg0KDQpkZjIwMTQgJT4lIA0KICBiaW5kX3Jvd3MoZGYyMDE1KSAlPiUgDQogIGJpbmRfcm93cyhkZjIwMTYpIC0+IG15X3BhbmVsDQoNCiMgUHJlcGFyZSBwYW5lbCBkYXRhOiANCg0KbGlicmFyeShwbG0pDQoNCnBkYXRhLmZyYW1lKG15X3BhbmVsLCANCiAgICAgICAgICAgIGluZGV4ID0gYygibWFfdGh1ZSIsInllYXIiKSwgDQogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwgDQogICAgICAgICAgICBkcm9wLmluZGV4ID0gRkFMU0UpIC0+IHBhbmVsX2RhdGFfdW5iYWxhbmNlZA0KDQpgYGANCg0KVMOtbmggdG/DoW4gbeG7mXQgc+G7kSB0aOG7kW5nIGvDqiB0aMaw4budbmcgxJHGsOG7o2MgdHLDrG5oIGLDoHkgdHJvbmcgY8OhYyBwYXBlcjogDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5cikNCg0KbXlfcGFuZWwgJT4lIA0KICBzZWxlY3Qoa3FrZDEsIHRzMTEsIHllYXIpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJrcWtkMSIsICJ0czExIiksIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBncm91cF9ieSh2YXJpYWJsZSkgJT4lIA0KICBzdW1tYXJpc2UoTWVhbiA9IG1lYW4odmFsdWUpLCANCiAgICAgICAgICAgIE1lZGlhbiA9IG1lZGlhbih2YWx1ZSksIA0KICAgICAgICAgICAgU0QgPSBzZCh2YWx1ZSksIA0KICAgICAgICAgICAgTWluID0gbWluKHZhbHVlKSwgDQogICAgICAgICAgICBNYXggPSBtYXgodmFsdWUpLCANCiAgICAgICAgICAgIE5fb2JzID0gbigpKSAlPiUgDQogIGthYmxlKCkNCg0KDQpgYGANCg0KDQpW4bubaSBk4buvIGxp4buHdSDEkcOjIGPDsywgY2jDum5nIHRhIGPDsyB0aOG7gyBjaOG6oXkgY8OhYyBtw7QgaMOsbmggcGjDom4gdMOtY2ggY2hvIFBhbmVsIERhdGEuIENo4bqzbmcgaOG6oW4gYmEgY8OhY2ggdGnhur9wIGPhuq1uIMSRxrDhu6NjIGNo4buNbiBsw6AgUG9vbGVkLCBGaXhlZCBFZmZlY3RzIHbDoCBSYW5kb20gRWZmZWN0cyBz4butIGThu6VuZyDGsOG7m2MgbMaw4bujbmcgQW1lbWl5YToNCg0KYGBge3J9DQojPT09PT09PT09PT09PT09PT09PT09PT09DQojIFNvbWUgUGFuZWwgRGF0YSBNb2RlbHMNCiM9PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBQb29sZWQgTW9kZWw6IA0KcGFuZWxfcG9vbGVkIDwtIHBsbShrcWtkMSB+IHRzMTEsIA0KICAgICAgICAgICAgICAgICAgICBkYXRhID0gcGFuZWxfZGF0YV91bmJhbGFuY2VkLCANCiAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSAicG9vbGluZyIpIA0KDQojIEZpeGVkIEVmZmVjdHMgTW9kZWw6IA0KcGFuZWxfZmUgPC0gcGxtKGtxa2QxIH4gdHMxMSwgDQogICAgICAgICAgICAgICAgZGF0YSA9IHBhbmVsX2RhdGFfdW5iYWxhbmNlZCwgDQogICAgICAgICAgICAgICAgbW9kZWwgPSAid2l0aGluIikgIA0KDQojIFJhbmRvbSBFZmZlY3RzIE1vZGVscyB1c2luZyBBbWVtaXlhIGVzdGltYXRvcnMgKDE5NzEpOiANCnBhbmVsX3JlIDwtIHBsbShrcWtkMSB+IHRzMTEsIA0KICAgICAgICAgICAgICAgIGRhdGEgPSBwYW5lbF9kYXRhX3VuYmFsYW5jZWQsIA0KICAgICAgICAgICAgICAgIG1vZGVsID0gInJhbmRvbSIsIA0KICAgICAgICAgICAgICAgIHJhbmRvbS5tZXRob2QgPSAiYW1lbWl5YSIpDQpgYGANCg0KUuG7k2kgc28gc8OhbmggY8OhYyDGsOG7m2MgbMaw4bujbmcgdOG7qyBiYSBtw7QgaMOsbmggbsOgeTogDQoNCmBgYHtyfQ0KIyBDb21wYXJlIHJlc3VsdHM6IA0KDQpsaWJyYXJ5KHN0YXJnYXplcikNCg0Kc3RhcmdhemVyKHBhbmVsX3Bvb2xlZCwgDQogICAgICAgICAgcGFuZWxfZmUsIA0KICAgICAgICAgIHBhbmVsX3JlLCANCiAgICAgICAgICB0aXRsZSA9ICJDb21wYXJlIFBhbmVsIERhdGEgUmVncmVzc2lvbiBSZXN1bHRzIC0gVW5iYWxhbmNlZCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIlBvb2xlZCIsIkZpeGVkIEVmZmVjdHMiLCAiUmFuZG9tIEVmZmVjdHMiKSwgDQogICAgICAgICAgdHlwZSA9ICJ0ZXh0IiwgDQogICAgICAgICAgYWxpZ24gPSBUUlVFKQ0KYGBgDQoNCiMgQmFsYW5jZWQgUGFuZWwgRGF0YQ0KDQrEkOG7gyBjaHXhuqluIGLhu4sgQmFsYW5jZWQgUGFuZWwgRGF0YSBjaMO6bmcgdGEgbMOgbSBuaMawIHNhdTogDQoNCmBgYHtyfQ0KbXlfcGFuZWwgJT4lIA0KICBncm91cF9ieShtYV90aHVlKSAlPiUgDQogIHN1bW1hcmlzZSh0YW5zdWF0ID0gbigpKSAlPiUgDQogIGZpbHRlcih0YW5zdWF0ID09IDMpICU+JSANCiAgcHVsbChtYV90aHVlKSAtPiBmaXJtc18zX3RpbWVzDQoNCnBkYXRhLmZyYW1lKG15X3BhbmVsICU+JSBmaWx0ZXIobWFfdGh1ZSAlaW4lIGZpcm1zXzNfdGltZXMpLCANCiAgICAgICAgICAgIGluZGV4ID0gYygibWFfdGh1ZSIsInllYXIiKSwgDQogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSwgDQogICAgICAgICAgICBkcm9wLmluZGV4ID0gRkFMU0UpIC0+IHBhbmVsX2RhdGFfYmFsYW5jZWQNCg0KYGBgDQoNClLhu5NpIHRo4buxYyBoaeG7h24gbOG6oWkgY8OhYyBixrDhu5tjIHBow6JuIHTDrWNoIG5oxrAgdHLDqm46IA0KDQpgYGB7cn0NCiMgUG9vbGVkIE1vZGVsOiANCnBhbmVsX3Bvb2xlZF9iIDwtIHBsbShrcWtkMSB+IHRzMTEsIA0KICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBwYW5lbF9kYXRhX2JhbGFuY2VkLCANCiAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJwb29saW5nIikgDQoNCiMgRml4ZWQgRWZmZWN0cyBNb2RlbDogDQpwYW5lbF9mZV9iIDwtIHBsbShrcWtkMSB+IHRzMTEsIA0KICAgICAgICAgICAgICAgICAgZGF0YSA9IHBhbmVsX2RhdGFfYmFsYW5jZWQsIA0KICAgICAgICAgICAgICAgICAgbW9kZWwgPSAid2l0aGluIikgIA0KDQojIFJhbmRvbSBFZmZlY3RzIE1vZGVscyB1c2luZyBBbWVtaXlhIGVzdGltYXRvcnMgKDE5NzEpOiANCnBhbmVsX3JlX2IgPC0gcGxtKGtxa2QxIH4gdHMxMSwgDQogICAgICAgICAgICAgICAgICBkYXRhID0gcGFuZWxfZGF0YV9iYWxhbmNlZCwgDQogICAgICAgICAgICAgICAgICBtb2RlbCA9ICJyYW5kb20iLCANCiAgICAgICAgICAgICAgICAgIHJhbmRvbS5tZXRob2QgPSAiYW1lbWl5YSIpDQoNCnN0YXJnYXplcihwYW5lbF9wb29sZWRfYiwgDQogICAgICAgICAgcGFuZWxfZmVfYiwgDQogICAgICAgICAgcGFuZWxfcmVfYiwgDQogICAgICAgICAgdGl0bGUgPSAiQ29tcGFyZSBQYW5lbCBEYXRhIFJlZ3Jlc3Npb24gUmVzdWx0cyAtIEJhbGFuY2VkIiwNCiAgICAgICAgICBjb2x1bW4ubGFiZWxzID0gYygiUG9vbGVkIiwiRml4ZWQgRWZmZWN0cyIsICJSYW5kb20gRWZmZWN0cyIpLCANCiAgICAgICAgICB0eXBlID0gInRleHQiLCANCiAgICAgICAgICBhbGlnbiA9IFRSVUUpDQpgYGANCg0KIyBGaW5hbCBOb3Rlcw0KDQpT4butIGThu6VuZyBWRVMgKGPDuW5nIHbhu5tpIFZITFNTKSBjaG8gcmVzZWFyY2ggcGFwZXIgbMOgIG3hu5l0IGPDtG5nIHZp4buHYyBy4bqldCB0aMOhY2ggdGjhu6ljLCDEkeG6t3QgYmnhu4d0IGzDoCB44butIGzDrSDEkeG7k25nIHRo4budaSBuaGnhu4F1IGLhu5kgZOG7ryBsaeG7h3UgY8O5bmcgbMO6YyB0cm9uZyBt4buZdCBraG/huqNuZyB0aOG7nWkgZ2lhbiBkw6BpLiBW4buBIGNo4buJIHJpw6puZyDEkWnhu4NtIG7DoHkgdGjDtGkgdGjDrCBSIHThu5F0IGjGoW4gU3RhdGEgbmhp4buBdS4gDQoNCiMgQXBwZW5kaXgNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCg0KDQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgICAgICBSIGNvZGVzIGZvciBleHBsYW5hdGlvbg0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgQ2xlYXIgUiBlbnZpcm9ubWVudDogDQoNCnJtKGxpc3QgPSBscygpKQ0KDQojIENyZWF0ZSBmYWtlIGRhdGEgc2V0czogDQoNCnZlc19kYXRhIDwtIGRhdGEuZnJhbWUobWFfdGh1ZSA9IGMoIjU2NCIsICIyMTMiLCAiOTgxIiwgIiIsICIyMTMiLCAiODMiLCAiNzQ1IiksIA0KICAgICAgICAgICAgICAgICAgICAgICBuZ2FuaF9rZCA9IGMoIjY0OTEwIiwgIjEzMjUxIiwgIjIxNDUiLCAiMTc5NDEiLCAiMTMyNTEiLCAiMjc1MTMiLCAiMTQ5NCIpKSAjIFZFUyBkYXRhDQoNCg0KdnNpY191cGRhdGUgPC0gZGF0YS5mcmFtZSh2c2ljM19uZXcgPSBjKCIxMzkiLCAiMDE3IiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB2c2ljM19vbGQgPSBjKCIxMzIiLCAiMDE0IikpICMgRGF0YSBmb3IgY29ycmVjdGluZy4gDQoNCiMgU2hvdyBvdXIgZGF0YTogDQoNCnZlc19kYXRhDQoNCnZzaWNfdXBkYXRlDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICBEdXBsaWNhdGVkIFRheCBDb2RlDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KDQp2ZXNfZGF0YSAlPiUgDQogIGdyb3VwX2J5KG1hX3RodWUpICU+JSANCiAgc3VtbWFyaXNlKHRhbnN1YXQgPSBuKCkpIA0KDQp2ZXNfZGF0YSAlPiUgDQogIGZpbHRlcighZHVwbGljYXRlZChtYV90aHVlKSkgLT4gdmVzX25vdF9kdXANCg0KdmVzX25vdF9kdXANCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgIFRheHQgQ29kZSAzLWRpZ2l0cw0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KbGlicmFyeShzdHJpbmdyKQ0KDQp2ZXNfbm90X2R1cCAlPiUgDQogIG11dGF0ZShzbGt0X3RheCA9IHN0cl9jb3VudChtYV90aHVlKSkgJT4lIA0KICBmaWx0ZXIoc2xrdF90YXggPT0gMykgIyBTb2x1dGlvbiAxLiANCg0KdmVzX25vdF9kdXAgJT4lIA0KICBmaWx0ZXIoc3RyX2NvdW50KG1hX3RodWUpID09IDMpICMgU29sdXRpb24gMi4gDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICBBZGQgemVybyBmb3Igc2VjdG9yIGNvZGUNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCnZlc19ub3RfZHVwICU+JSANCiAgZmlsdGVyKHN0cl9jb3VudChtYV90aHVlKSA9PSAzKSAlPiUgDQogIG11dGF0ZShzbGt0X2NvZGUgPSBzdHJfY291bnQobmdhbmhfa2QpKSAlPiUgDQogIG11dGF0ZShuZ2FuaF9rZF9hZGogPSBjYXNlX3doZW4oc2xrdF9jb2RlID09IDQgfiBzdHJfYygiMCIsIG5nYW5oX2tkKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IG5nYW5oX2tkKSkNCg0KdmVzX25vdF9kdXAgJT4lIA0KICBmaWx0ZXIoc3RyX2NvdW50KG1hX3RodWUpID09IDMpICU+JSANCiAgbXV0YXRlKHNsa3RfY29kZSA9IHN0cl9jb3VudChuZ2FuaF9rZCkpICU+JSANCiAgbXV0YXRlKG5nYW5oX2tkID0gY2FzZV93aGVuKHNsa3RfY29kZSA9PSA0IH4gc3RyX2MoIjAiLCBuZ2FuaF9rZCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IG5nYW5oX2tkKSkgLT4gdmVzX2NsZWFuZWQNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICBBZGp1c3Qgc2VjdG9yIGNvZGUNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIEFib3V0IHN0cl9zdWIoKSBmdW5jdGlvbjogDQoNCnZlc19jbGVhbmVkICU+JSBwdWxsKG5nYW5oX2tkKSAtPiBuZ2FuaF92ZWMNCg0Kc3RyX3N1YihuZ2FuaF92ZWMsIHN0YXJ0ID0gMSwgZW5kID0gMykNCg0Kc3RyX3N1YihuZ2FuaF92ZWMsIHN0YXJ0ID0gNSwgZW5kID0gNSkNCg0KdmVzX2NsZWFuZWQgJT4lIA0KICBtdXRhdGUoY29kZV9sMyA9IHN0cl9zdWIobmdhbmhfa2QsIHN0YXJ0ID0gMSwgZW5kID0gMyksIA0KICAgICAgICAgY29kZV81dGggPSBzdHJfc3ViKG5nYW5oX2tkLCBzdGFydCA9IDUsIGVuZCA9IDUpKQ0KDQp2ZXNfY2xlYW5lZCAlPiUgDQogIG11dGF0ZShjb2RlX2wzID0gc3RyX3N1YihuZ2FuaF9rZCwgc3RhcnQgPSAxLCBlbmQgPSAzKSwgDQogICAgICAgICBjb2RlXzV0aCA9IHN0cl9zdWIobmdhbmhfa2QsIHN0YXJ0ID0gNSwgZW5kID0gNSkpIC0+IHZlc19jbGVhbmVkDQoNCiMgQ29tcGFyZTogDQoNCnZzaWNfdXBkYXRlDQoNCnZzaWNfdXBkYXRlICU+JSBwdWxsKHZzaWMzX29sZCkgLT4gb2xkX2NvZGUzDQoNCnZzaWNfdXBkYXRlJHZzaWMzX25ldyAtPiBuZXdfY29kZTMNCg0KIyAtLS0tLSBTb2x1aW9uIDEgZm9yIGNvcnJlY3Rpbmcgc2VjdG9yIGNvZGUgLS0tLS0NCg0KdmVzX2NsZWFuZWQgJT4lIA0KICBtdXRhdGUoY29kZV9sM19hZGogPSBjYXNlX3doZW4oY29kZV9sMyA9PSBvbGRfY29kZTNbMV0gfiBuZXdfY29kZTNbMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kZV9sMyA9PSBvbGRfY29kZTNbMl0gfiBuZXdfY29kZTNbMl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGNvZGVfbDMpKQ0KDQojIC0tLS0gIFNvbHVpb24gMiBmb3IgY29ycmVjdGluZyBzZWN0b3IgY29kZSAtLS0tLQ0KDQpmdWxsX2pvaW4odmVzX2NsZWFuZWQsIHZzaWNfdXBkYXRlLCBieSA9IGMoImNvZGVfbDMiID0gInZzaWMzX29sZCIpKQ0KDQppbm5lcl9qb2luKHZlc19jbGVhbmVkLCB2c2ljX3VwZGF0ZSwgYnkgPSBjKCJjb2RlX2wzIiA9ICJ2c2ljM19vbGQiKSkNCg0KZnVsbF9qb2luKHZlc19jbGVhbmVkLCB2c2ljX3VwZGF0ZSwgYnkgPSBjKCJjb2RlX2wzIiA9ICJ2c2ljM19vbGQiKSkgLT4gdmVzX2NsZWFuZWRfbmV3DQoNCnZlc19jbGVhbmVkX25ldyAlPiUgDQogIG11dGF0ZShjb2RlX2wzX2FkaiA9IGNhc2Vfd2hlbihpcy5uYSh2c2ljM19uZXcpIH4gY29kZV9sMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gdnNpYzNfbmV3KSkNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg==