Introduction
Post trước cho thấy Đà Nẵng là tỉnh có thu nhập trung vị hộ gia đình cao nhất nước (450 triệu). Kết quả đó được tính toán dựa vào biến thunhap từ bộ dữ liệu HO3.dta:

Theo dữ liệu ở bảng này thì hộ ở tinh = 96, huyen = 973, xa = 32239 , diaban = 19, hoso = 1 xuất hiện ở 8 dòng và do vậy giả định rằng mỗi một dòng tương ứng với một thành viên của gia đình thì tổng thu nhập của hộ này sẽ là 169250 + 600 + 17435. Tính toán tương tự theo logic này cho các hộ còn lại.
Post này trình bày một cách tính toán khác căn cứ vào biến thubq - tức là thu nhập bình quân đầu người của hộ. Như vậy theo cách tính này thì chúng ta chỉ cần biết số thành viên trong gia đình của hộ, nhân với thubq rồi nhân tiếp với 12 chúng ta sẽ có tổng thu nhập của hộ theo năm.
Thông tin về số thành viên của hộ gia đình có thể khai thác từ bộ dữ liệu HO1.dta. Cách tính này chúng ta có kết quả như Figure 1 ở trên.
Data Pre-processing
Trước hết đọc dữ liệu vào R:
# Clear R environment:
rm(list = ls())
# Load some R packages:
library(dplyr)
library(stringr)
library(stringi)
library(kableExtra) # For presenting table.
library(haven)
# Import HO3.dta:
read_dta("D:/VHLSS2018_Household/HO3.dta") -> ho3
# HO1.dta:
read_dta("D:/VHLSS2018_Household/HO1.dta") -> ho1
Mỗi một hộ gia đình có ID được hình thành từ mã của 5 cột biến: tỉnh, huyện, xã, địa bàn, hộ số (cái này ban đầu em và nhiều người nữa vẫn hiểu là “hồ sơ” vì chữ không dấu, thực ra nó là “hộ số”). Vấn đề đầu tiên là chúng ta cần chuẩn hóa các mã này một cách thống nhất cho những mục đích sử dụng xa hơn sau này. Chẳng hạn, tỉnh có mã là 1 thì cần phải chuẩn hóa về 01 (tương ứng với Hà Nội). Mã tỉnh code chuẩn sử dụng 2 chữ số và do vậy với các tỉnh là số tự nhiên bé hơn 9 thì chúng ta phải thêm 1 số 0 đằng trước. Tương tự là Huyện sử dụng 3 chữ số đễ mã hóa. Do vậy với huyện mà chỉ sử dụng 1 chữ số thì chúng ta chuẩn hóa bằng cách thêm 2 chữ số 0 đằng trước, với huyện có mã là 2 chữ số thì thêm 1 chữ số 0 đằng trước. Cách thức chuẩn hóa này áp dụng tương tự cho các biến còn lại là xã, địa bàn và hộ số.
Chúng ta viết hàm có tên add_zero() để chuẩn hóa mã hành chính:
#========================
# Data Pre-processing
#========================
# Function creates full code by adding zeros:
add_zero <- function(x) {
tibble(x_text = as.character(x)) %>%
mutate(n_digits = str_count(x_text),
n_max = max(n_digits),
delta = n_max - n_digits,
pre = strrep("0", times = delta),
full_code = str_c(pre, x_text)) %>%
pull(full_code) %>%
return()
}
Để thuận lợi cho đối chiếu và tra cứu, viết hàm có tên extract_description() để lấy các mô tả về các biến số:
# Function extracts variable description:
extract_description <- function(df_selected) {
sapply(df_selected, function(x) {attributes(x) %>% .$label}) %>%
data.frame() %>%
mutate(description = stri_trans_general(`.`, "Latin-ASCII")) -> df_des
df_des %>%
mutate(var_name = row.names(df_des)) %>%
select(var_name, description) -> df_des
row.names(df_des) <- NULL
return(df_des)
}
Ý nghĩa của các biến số thuộc HO3.dta được trình bày ở Table 1 dưới đây:
# Use the function:
extract_description(df_selected = ho3) -> des_ho3
des_ho3 %>%
kbl(caption = "Table 1: Variable Description for HO3.dta", escape = TRUE) %>%
kable_classic(full_width = TRUE, html_font = "Cambria")
Table 1: Variable Description for HO3.dta
var_name
|
description
|
tinh
|
Tinh
|
huyen
|
Huyen
|
xa
|
Xa
|
diaban
|
Dia ban
|
hoso
|
Ho so
|
thunhap
|
- Thu nhap
|
thubq
|
- Thu nhap binh quan/nguoi/thang
|
tongthu
|
Tong thu
|
chisxkd
|
Chi phi SXKD
|
chikhac
|
Chi tieu va chi khac
|
Tạo một biến mới có tên h_code là mã của các hộ gia đình và mã này được hình thành từ mã chuẩn hóa của tỉnh, huyện, xã, địa bàn và hồ sơ:
#------------------------
# Create Household ID
#------------------------
# Create h_code column for ho3:
ho3 %>%
mutate(tinh_n = add_zero(tinh),
huyen_n = add_zero(huyen),
xa_n = add_zero(xa),
diaban_n = add_zero(diaban),
hoso_n = add_zero(hoso)) %>%
mutate(h_code = str_c(tinh_n, huyen_n, xa_n, diaban_n, hoso_n)) -> ho3
# For ho1:
ho1 %>%
mutate(tinh_n = add_zero(tinh),
huyen_n = add_zero(huyen),
xa_n = add_zero(xa),
diaban_n = add_zero(diaban),
hoso_n = add_zero(hoso)) %>%
mutate(h_code = str_c(tinh_n, huyen_n, xa_n, diaban_n, hoso_n)) -> ho1
# Remove duplications:
ho1 %>% filter(!duplicated(h_code)) -> ho1
# Join the two data sets:
ho3 %>%
select(h_code, tinh_n, thubq) %>%
filter(!is.na(thubq)) %>%
full_join(ho1 %>% select(h_code, tsnguoi), by = "h_code") -> df_monthly_income
# Calculate yearly-household income:
df_monthly_income %>%
mutate(total_year_income = thubq*tsnguoi*12) -> df_monthly_income
#--------------------------
# Extract province names
#--------------------------
# Extract province info:
ho3$tinh %>%
attributes() %>%
.$labels %>% data.frame() -> df_province
# Rename for DF:
names(df_province) <- "province_code"
# Create some columns and relabel for provinces:
df_province %>%
mutate(province_vie = row.names(df_province)) %>%
mutate(province_eng = stri_trans_general(province_vie, "Latin-ASCII")) %>%
mutate(province_eng = str_replace_all(province_eng, "Tinh |Thanh pho ", "")) %>%
mutate(province_eng = str_replace_all(province_eng, " - ", "-")) %>%
mutate(province_code = add_zero(province_code)) -> df_province
row.names(df_province) <- NULL
# Join province name:
df_monthly_income %>%
full_join(df_province %>% select(province_eng, province_code), by = c("tinh_n" = "province_code")) -> df_household_income
# Calculate some percentiles by household level:
df_household_income %>%
filter(!is.na(province_eng)) %>%
group_by(province_eng) %>%
summarise(th25 = quantile(total_year_income, 0.25),
th50 = quantile(total_year_income, 0.50),
th75 = quantile(total_year_income, 0.75)) %>%
mutate_if(is.numeric, function(x) {round(x / 1000, 1)}) %>%
ungroup() %>%
arrange(th50) %>%
mutate(province_eng = factor(province_eng, province_eng)) -> df_thunhap
Nếu chọn mean để tính toán và so sánh mức độ chênh lệnh về thu nhập của hộ gia đình có một điểm yếu là mean bị ảnh hưởng rất lớn bởi Outliers. Do vậy chọn thu nhập trung vị (Median) để đánh giá và so sánh chúng ta có thể khắc phục nhược điểm này.
R codes for Data Visualization
Sau bước xử lí dữ liệu thô và tính toán các thống kê, dưới đây là R Codes tạo ra Figure 1:
#====================
# Data Visualization
#====================
# Load some R packages for Data Visualization:
library(ggeconodist) # install.packages("ggeconodist", repos = "https://cinc.rud.is")
library(ggplot2)
library(showtext)
# Select Ubuntu Condensed font:
showtext.auto()
font_add_google(name = "Ubuntu Condensed", family = "ubu")
my_font <- "ubu"
df_thunhap %>%
ggplot(aes(x = province_eng)) +
geom_econodist(aes(ymin = th25, median = th50, ymax = th75),
median_col = "firebrick",
stat = "identity",
median_point_size = 1.3,
show.legend = TRUE) +
coord_flip() +
theme_econodist() +
scale_y_continuous(expand = c(0, 0), limits = range(0, 350), breaks = seq(0, 350, 50), position = "right") +
labs(title = "Figure 1: Gaps in Household Income (millions VND) by Province, 2018",
caption = "Data Source: VHLSS 2018, GSO") +
theme(plot.margin = unit(c(0.3, 1, 0.3, 0.5), "cm")) +
theme(axis.title.y = element_blank()) +
theme(axis.text.y = element_text(family = my_font, size = 9)) +
theme(axis.text.x = element_text(family = my_font)) +
theme(plot.caption = element_text(family = my_font, size = 8, face = "italic")) +
theme(plot.title = element_text(family = my_font, size = 15)) -> f1
grid.newpage()
f1 %>%
left_align(c("title", "caption")) %>%
add_econodist_legend(
econodist_legend_grob(
tenth_lab = "25th Percentile",
ninetieth_lab = "75th Percentile",
med_lab = "Median",
med_col = "firebrick",
family = my_font,
label_size = 11,
),
below = "title"
) %>%
grid.draw()
LS0tDQp0aXRsZTogJ0dhcHMgaW4gSG91c2Vob2xkIEluY29tZSBGcm9tIFZITFNTIDIwMTgnDQphdXRob3I6ICdBdXRob3I6IE5ndXllbiBDaGkgRHVuZycNCnN1YnRpdGxlOiAiUiBEYWlseSBHcmFwaCBTZXJpZXMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICAjIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogemVuYnVybg0KICAgICMgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogImZsYXRseSINCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgY2FjaGUgPSBUUlVFKQ0KDQpgYGANCg0KDQohW10oQzovVXNlcnMvQURNSU4vRG9jdW1lbnRzL2hvMzMuanBnKQ0KDQojIEludHJvZHVjdGlvbg0KDQpbUG9zdCB0csaw4bubY10oaHR0cHM6Ly9ycHVicy5jb20vY2hpZHVuZ2t0Lzc4ODEzMSkgY2hvIHRo4bqleSDEkMOgIE7hurVuZyBsw6AgdOG7iW5oIGPDsyB0aHUgbmjhuq1wIHRydW5nIHbhu4sgaOG7mSBnaWEgxJHDrG5oIGNhbyBuaOG6pXQgbsaw4bubYyAoNDUwIHRyaeG7h3UpLiBL4bq/dCBxdeG6oyDEkcOzIMSRxrDhu6NjIHTDrW5oIHRvw6FuIGThu7FhIHbDoG8gYmnhur9uICoqdGh1bmhhcCoqIHThu6sgYuG7mSBk4buvIGxp4buHdSBITzMuZHRhOiANCg0KIVtdKEM6L1VzZXJzL0FETUlOL0RvY3VtZW50cy9obzMuanBnKQ0KDQpUaGVvIGThu68gbGnhu4d1IOG7nyBi4bqjbmcgbsOgeSB0aMOsIGjhu5kg4bufIHRpbmggPSA5NiwgaHV5ZW4gPSA5NzMsIHhhID0gMzIyMzkgLCBkaWFiYW4gPSAxOSwgaG9zbyA9IDEgeHXhuqV0IGhp4buHbiDhu58gOCBkw7JuZyB2w6AgZG8gduG6rXkgZ2nhuqMgxJHhu4tuaCBy4bqxbmcgbeG7l2kgbeG7mXQgZMOybmcgdMawxqFuZyDhu6luZyB24bubaSBt4buZdCB0aMOgbmggdmnDqm4gY+G7p2EgZ2lhIMSRw6xuaCB0aMOsIHThu5VuZyB0aHUgbmjhuq1wIGPhu6dhIGjhu5kgbsOgeSBz4bq9IGzDoCAxNjkyNTAgKyA2MDAgKyAxNzQzNS4gVMOtbmggdG/DoW4gdMawxqFuZyB04buxIHRoZW8gbG9naWMgbsOgeSBjaG8gY8OhYyBo4buZIGPDsm4gbOG6oWkuIA0KDQpQb3N0IG7DoHkgdHLDrG5oIGLDoHkgbeG7mXQgY8OhY2ggdMOtbmggdG/DoW4ga2jDoWMgY8SDbiBj4bupIHbDoG8gYmnhur9uICoqdGh1YnEqKiAtIHThu6ljIGzDoCB0aHUgbmjhuq1wIGLDrG5oIHF1w6JuIMSR4bqndSBuZ8aw4budaSBj4bunYSBo4buZLiBOaMawIHbhuq15IHRoZW8gY8OhY2ggdMOtbmggbsOgeSB0aMOsIGNow7puZyB0YSBjaOG7iSBj4bqnbiBiaeG6v3Qgc+G7kSB0aMOgbmggdmnDqm4gdHJvbmcgZ2lhIMSRw6xuaCBj4bunYSBo4buZLCBuaMOibiB24bubaSB0aHVicSBy4buTaSBuaMOibiB0aeG6v3AgduG7m2kgMTIgY2jDum5nIHRhIHPhur0gY8OzIHThu5VuZyB0aHUgbmjhuq1wIGPhu6dhIGjhu5kgdGhlbyBuxINtLiANCg0KVGjDtG5nIHRpbiB24buBIHPhu5EgdGjDoG5oIHZpw6puIGPhu6dhIGjhu5kgZ2lhIMSRw6xuaCBjw7MgdGjhu4Mga2hhaSB0aMOhYyB04burIGLhu5kgZOG7ryBsaeG7h3UgSE8xLmR0YS4gQ8OhY2ggdMOtbmggbsOgeSBjaMO6bmcgdGEgY8OzIGvhur90IHF14bqjIG5oxrAgRmlndXJlIDEg4bufIHRyw6puLiANCg0KIyBEYXRhIFByZS1wcm9jZXNzaW5nDQoNClRyxrDhu5tjIGjhur90IMSR4buNYyBk4buvIGxp4buHdSB2w6BvIFI6IA0KDQpgYGB7cn0NCiMgQ2xlYXIgUiBlbnZpcm9ubWVudDogDQpybShsaXN0ID0gbHMoKSkNCg0KIyBMb2FkIHNvbWUgUiBwYWNrYWdlczogDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShzdHJpbmdpKQ0KbGlicmFyeShrYWJsZUV4dHJhKSAjIEZvciBwcmVzZW50aW5nIHRhYmxlLiANCmxpYnJhcnkoaGF2ZW4pDQoNCiMgSW1wb3J0IEhPMy5kdGE6IA0KDQpyZWFkX2R0YSgiRDovVkhMU1MyMDE4X0hvdXNlaG9sZC9ITzMuZHRhIikgLT4gaG8zDQoNCiMgSE8xLmR0YTogDQoNCnJlYWRfZHRhKCJEOi9WSExTUzIwMThfSG91c2Vob2xkL0hPMS5kdGEiKSAtPiBobzEgDQpgYGANCg0KDQpN4buXaSBt4buZdCBo4buZIGdpYSDEkcOsbmggY8OzIElEIMSRxrDhu6NjIGjDrG5oIHRow6BuaCB04burIG3DoyBj4bunYSA1IGPhu5l0IGJp4bq/bjogdOG7iW5oLCBodXnhu4duLCB4w6MsIMSR4buLYSBiw6BuLCBo4buZIHPhu5EgKGPDoWkgbsOgeSBiYW4gxJHhuqd1IGVtIHbDoCBuaGnhu4F1IG5nxrDhu51pIG7hu69hIHbhuqtuIGhp4buDdSBsw6AgImjhu5Mgc8ahIiB2w6wgY2jhu68ga2jDtG5nIGThuqV1LCB0aOG7sWMgcmEgbsOzIGzDoCAiaOG7mSBz4buRIikuIFbhuqVuIMSR4buBIMSR4bqndSB0acOqbiBsw6AgY2jDum5nIHRhIGPhuqduIGNodeG6qW4gaMOzYSBjw6FjIG3DoyBuw6B5IG3hu5l0IGPDoWNoIHRo4buRbmcgbmjhuqV0IGNobyBuaOG7r25nIG3hu6VjIMSRw61jaCBz4butIGThu6VuZyB4YSBoxqFuIHNhdSBuw6B5LiBDaOG6s25nIGjhuqFuLCB04buJbmggY8OzIG3DoyBsw6AgMSB0aMOsIGPhuqduIHBo4bqjaSBjaHXhuqluIGjDs2EgduG7gSAwMSAodMawxqFuZyDhu6luZyB24bubaSBIw6AgTuG7mWkpLiBNw6MgdOG7iW5oIGNvZGUgY2h14bqpbiBz4butIGThu6VuZyAyIGNo4buvIHPhu5EgdsOgIGRvIHbhuq15IHbhu5tpIGPDoWMgdOG7iW5oIGzDoCBz4buRIHThu7Egbmhpw6puIGLDqSBoxqFuIDkgdGjDrCBjaMO6bmcgdGEgcGjhuqNpIHRow6ptIDEgc+G7kSAwIMSR4bqxbmcgdHLGsOG7m2MuIFTGsMahbmcgdOG7sSBsw6AgSHV54buHbiBz4butIGThu6VuZyAzIGNo4buvIHPhu5EgxJHhu4UgbcOjIGjDs2EuIERvIHbhuq15IHbhu5tpIGh1eeG7h24gbcOgIGNo4buJIHPhu60gZOG7pW5nIDEgY2jhu68gc+G7kSB0aMOsIGNow7puZyB0YSBjaHXhuqluIGjDs2EgYuG6sW5nIGPDoWNoIHRow6ptIDIgY2jhu68gc+G7kSAwIMSR4bqxbmcgdHLGsOG7m2MsIHbhu5tpIGh1eeG7h24gY8OzIG3DoyBsw6AgMiBjaOG7ryBz4buRIHRow6wgdGjDqm0gMSBjaOG7ryBz4buRIDAgxJHhurFuZyB0csaw4bubYy4gQ8OhY2ggdGjhu6ljIGNodeG6qW4gaMOzYSBuw6B5IMOhcCBk4bulbmcgdMawxqFuZyB04buxIGNobyBjw6FjIGJp4bq/biBjw7JuIGzhuqFpIGzDoCB4w6MsIMSR4buLYSBiw6BuIHbDoCBo4buZIHPhu5EuIA0KDQpDaMO6bmcgdGEgdmnhur90IGjDoG0gY8OzIHTDqm4gKiphZGRfemVybygpKiogxJHhu4MgY2h14bqpbiBow7NhIG3DoyBow6BuaCBjaMOtbmg6IA0KDQpgYGB7cn0NCg0KIz09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAgRGF0YSBQcmUtcHJvY2Vzc2luZyANCiM9PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBGdW5jdGlvbiBjcmVhdGVzIGZ1bGwgY29kZSBieSBhZGRpbmcgemVyb3M6IA0KDQphZGRfemVybyA8LSBmdW5jdGlvbih4KSB7DQogIA0KICB0aWJibGUoeF90ZXh0ID0gYXMuY2hhcmFjdGVyKHgpKSAlPiUgDQogICAgbXV0YXRlKG5fZGlnaXRzID0gc3RyX2NvdW50KHhfdGV4dCksDQogICAgICAgICAgIG5fbWF4ID0gbWF4KG5fZGlnaXRzKSwgDQogICAgICAgICAgIGRlbHRhID0gbl9tYXggLSBuX2RpZ2l0cywgDQogICAgICAgICAgIHByZSA9IHN0cnJlcCgiMCIsIHRpbWVzID0gZGVsdGEpLCANCiAgICAgICAgICAgZnVsbF9jb2RlID0gc3RyX2MocHJlLCB4X3RleHQpKSAlPiUgDQogICAgcHVsbChmdWxsX2NvZGUpICU+JSANCiAgICByZXR1cm4oKQ0KfQ0KYGBgDQoNCsSQ4buDIHRodeG6rW4gbOG7o2kgY2hvIMSR4buRaSBjaGnhur91IHbDoCB0cmEgY+G7qXUsIHZp4bq/dCBow6BtIGPDsyB0w6puICoqZXh0cmFjdF9kZXNjcmlwdGlvbigpKiogxJHhu4MgbOG6pXkgY8OhYyBtw7QgdOG6oyB24buBIGPDoWMgYmnhur9uIHPhu5E6IA0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gZXh0cmFjdHMgdmFyaWFibGUgZGVzY3JpcHRpb246IA0KDQpleHRyYWN0X2Rlc2NyaXB0aW9uIDwtIGZ1bmN0aW9uKGRmX3NlbGVjdGVkKSB7DQogIA0KICBzYXBwbHkoZGZfc2VsZWN0ZWQsIGZ1bmN0aW9uKHgpIHthdHRyaWJ1dGVzKHgpICU+JSAuJGxhYmVsfSkgJT4lIA0KICAgIGRhdGEuZnJhbWUoKSAlPiUgDQogICAgbXV0YXRlKGRlc2NyaXB0aW9uID0gc3RyaV90cmFuc19nZW5lcmFsKGAuYCwgIkxhdGluLUFTQ0lJIikpIC0+IGRmX2Rlcw0KICANCiAgZGZfZGVzICU+JSANCiAgICBtdXRhdGUodmFyX25hbWUgPSByb3cubmFtZXMoZGZfZGVzKSkgJT4lIA0KICAgIHNlbGVjdCh2YXJfbmFtZSwgZGVzY3JpcHRpb24pIC0+IGRmX2Rlcw0KICANCiAgcm93Lm5hbWVzKGRmX2RlcykgPC0gTlVMTA0KICANCiAgcmV0dXJuKGRmX2RlcykNCiAgDQp9DQpgYGANCg0Kw50gbmdoxKlhIGPhu6dhIGPDoWMgYmnhur9uIHPhu5EgdGh14buZYyBITzMuZHRhIMSRxrDhu6NjIHRyw6xuaCBiw6B5IOG7nyBUYWJsZSAxIGTGsOG7m2kgxJHDonk6IA0KDQpgYGB7cn0NCiMgVXNlIHRoZSBmdW5jdGlvbjogDQoNCmV4dHJhY3RfZGVzY3JpcHRpb24oZGZfc2VsZWN0ZWQgPSBobzMpIC0+IGRlc19obzMNCg0KZGVzX2hvMyAlPiUgDQogIGtibChjYXB0aW9uID0gIlRhYmxlIDE6IFZhcmlhYmxlIERlc2NyaXB0aW9uIGZvciBITzMuZHRhIiwgZXNjYXBlID0gVFJVRSkgJT4lDQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IFRSVUUsIGh0bWxfZm9udCA9ICJDYW1icmlhIikNCmBgYA0KDQpU4bqhbyBt4buZdCBiaeG6v24gbeG7m2kgY8OzIHTDqm4gaF9jb2RlIGzDoCBtw6MgY+G7p2EgY8OhYyBo4buZIGdpYSDEkcOsbmggdsOgIG3DoyBuw6B5IMSRxrDhu6NjIGjDrG5oIHRow6BuaCB04burIG3DoyBjaHXhuqluIGjDs2EgY+G7p2EgdOG7iW5oLCBodXnhu4duLCB4w6MsIMSR4buLYSBiw6BuIHbDoCBo4buTIHPGoTogDQoNCmBgYHtyfQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgQ3JlYXRlIEhvdXNlaG9sZCBJRA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIENyZWF0ZSBoX2NvZGUgY29sdW1uIGZvciBobzM6IA0KDQpobzMgJT4lIA0KICBtdXRhdGUodGluaF9uID0gYWRkX3plcm8odGluaCksIA0KICAgICAgICAgaHV5ZW5fbiA9IGFkZF96ZXJvKGh1eWVuKSwgDQogICAgICAgICB4YV9uID0gYWRkX3plcm8oeGEpLCANCiAgICAgICAgIGRpYWJhbl9uID0gYWRkX3plcm8oZGlhYmFuKSwgDQogICAgICAgICBob3NvX24gPSBhZGRfemVybyhob3NvKSkgJT4lIA0KICBtdXRhdGUoaF9jb2RlID0gc3RyX2ModGluaF9uLCBodXllbl9uLCB4YV9uLCBkaWFiYW5fbiwgaG9zb19uKSkgLT4gaG8zDQoNCiMgRm9yIGhvMToNCg0KaG8xICU+JSANCiAgbXV0YXRlKHRpbmhfbiA9IGFkZF96ZXJvKHRpbmgpLCANCiAgICAgICAgIGh1eWVuX24gPSBhZGRfemVybyhodXllbiksIA0KICAgICAgICAgeGFfbiA9IGFkZF96ZXJvKHhhKSwgDQogICAgICAgICBkaWFiYW5fbiA9IGFkZF96ZXJvKGRpYWJhbiksIA0KICAgICAgICAgaG9zb19uID0gYWRkX3plcm8oaG9zbykpICU+JSANCiAgbXV0YXRlKGhfY29kZSA9IHN0cl9jKHRpbmhfbiwgaHV5ZW5fbiwgeGFfbiwgZGlhYmFuX24sIGhvc29fbikpIC0+IGhvMQ0KDQojIFJlbW92ZSBkdXBsaWNhdGlvbnM6IA0KDQpobzEgJT4lIGZpbHRlcighZHVwbGljYXRlZChoX2NvZGUpKSAtPiBobzENCg0KIyBKb2luIHRoZSB0d28gZGF0YSBzZXRzOiANCg0KaG8zICU+JSANCiAgc2VsZWN0KGhfY29kZSwgdGluaF9uLCB0aHVicSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHRodWJxKSkgJT4lIA0KICBmdWxsX2pvaW4oaG8xICU+JSBzZWxlY3QoaF9jb2RlLCB0c25ndW9pKSwgYnkgPSAiaF9jb2RlIikgLT4gZGZfbW9udGhseV9pbmNvbWUNCg0KIyBDYWxjdWxhdGUgeWVhcmx5LWhvdXNlaG9sZCBpbmNvbWU6IA0KDQpkZl9tb250aGx5X2luY29tZSAlPiUgDQogIG11dGF0ZSh0b3RhbF95ZWFyX2luY29tZSA9IHRodWJxKnRzbmd1b2kqMTIpIC0+IGRmX21vbnRobHlfaW5jb21lDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgRXh0cmFjdCBwcm92aW5jZSBuYW1lcw0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgRXh0cmFjdCBwcm92aW5jZSBpbmZvOg0KDQpobzMkdGluaCAlPiUgDQogIGF0dHJpYnV0ZXMoKSAlPiUgDQogIC4kbGFiZWxzICU+JSBkYXRhLmZyYW1lKCkgLT4gZGZfcHJvdmluY2UNCg0KIyBSZW5hbWUgZm9yIERGOiANCm5hbWVzKGRmX3Byb3ZpbmNlKSA8LSAicHJvdmluY2VfY29kZSINCg0KIyBDcmVhdGUgc29tZSBjb2x1bW5zIGFuZCByZWxhYmVsIGZvciBwcm92aW5jZXM6IA0KDQpkZl9wcm92aW5jZSAlPiUgDQogIG11dGF0ZShwcm92aW5jZV92aWUgPSByb3cubmFtZXMoZGZfcHJvdmluY2UpKSAlPiUgDQogIG11dGF0ZShwcm92aW5jZV9lbmcgPSBzdHJpX3RyYW5zX2dlbmVyYWwocHJvdmluY2VfdmllLCAiTGF0aW4tQVNDSUkiKSkgJT4lIA0KICBtdXRhdGUocHJvdmluY2VfZW5nID0gc3RyX3JlcGxhY2VfYWxsKHByb3ZpbmNlX2VuZywgIlRpbmggfFRoYW5oIHBobyAiLCAiIikpICU+JSANCiAgbXV0YXRlKHByb3ZpbmNlX2VuZyA9IHN0cl9yZXBsYWNlX2FsbChwcm92aW5jZV9lbmcsICIgLSAiLCAiLSIpKSAlPiUgDQogIG11dGF0ZShwcm92aW5jZV9jb2RlID0gYWRkX3plcm8ocHJvdmluY2VfY29kZSkpIC0+IGRmX3Byb3ZpbmNlDQoNCnJvdy5uYW1lcyhkZl9wcm92aW5jZSkgPC0gTlVMTA0KDQojIEpvaW4gcHJvdmluY2UgbmFtZTogDQoNCmRmX21vbnRobHlfaW5jb21lICU+JSANCiAgZnVsbF9qb2luKGRmX3Byb3ZpbmNlICU+JSBzZWxlY3QocHJvdmluY2VfZW5nLCBwcm92aW5jZV9jb2RlKSwgYnkgPSBjKCJ0aW5oX24iID0gInByb3ZpbmNlX2NvZGUiKSkgLT4gZGZfaG91c2Vob2xkX2luY29tZQ0KDQojIENhbGN1bGF0ZSBzb21lIHBlcmNlbnRpbGVzIGJ5IGhvdXNlaG9sZCBsZXZlbDogDQoNCmRmX2hvdXNlaG9sZF9pbmNvbWUgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHByb3ZpbmNlX2VuZykpICU+JSANCiAgZ3JvdXBfYnkocHJvdmluY2VfZW5nKSAlPiUgDQogIHN1bW1hcmlzZSh0aDI1ID0gcXVhbnRpbGUodG90YWxfeWVhcl9pbmNvbWUsIDAuMjUpLCANCiAgICAgICAgICAgIHRoNTAgPSBxdWFudGlsZSh0b3RhbF95ZWFyX2luY29tZSwgMC41MCksIA0KICAgICAgICAgICAgdGg3NSA9IHF1YW50aWxlKHRvdGFsX3llYXJfaW5jb21lLCAwLjc1KSkgJT4lIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVuY3Rpb24oeCkge3JvdW5kKHggLyAxMDAwLCAxKX0pICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgYXJyYW5nZSh0aDUwKSAlPiUgDQogIG11dGF0ZShwcm92aW5jZV9lbmcgPSBmYWN0b3IocHJvdmluY2VfZW5nLCBwcm92aW5jZV9lbmcpKSAtPiBkZl90aHVuaGFwDQpgYGANCg0KTuG6v3UgY2jhu41uIG1lYW4gxJHhu4MgdMOtbmggdG/DoW4gdsOgIHNvIHPDoW5oIG3hu6ljIMSR4buZIGNow6puaCBs4buHbmggduG7gSB0aHUgbmjhuq1wIGPhu6dhIGjhu5kgZ2lhIMSRw6xuaCBjw7MgbeG7mXQgxJFp4buDbSB54bq/dSBsw6AgbWVhbiBi4buLIOG6o25oIGjGsOG7n25nIHLhuqV0IGzhu5tuIGLhu59pIE91dGxpZXJzLiBEbyB24bqteSBjaOG7jW4gdGh1IG5o4bqtcCB0cnVuZyB24buLIChNZWRpYW4pIMSR4buDIMSRw6FuaCBnacOhIHbDoCBzbyBzw6FuaCBjaMO6bmcgdGEgY8OzIHRo4buDIGto4bqvYyBwaOG7pWMgbmjGsOG7o2MgxJFp4buDbSBuw6B5LiANCg0KIyBSIGNvZGVzIGZvciBEYXRhIFZpc3VhbGl6YXRpb24NCg0KU2F1IGLGsOG7m2MgeOG7rSBsw60gZOG7ryBsaeG7h3UgdGjDtCB2w6AgdMOtbmggdG/DoW4gY8OhYyB0aOG7kW5nIGvDqiwgZMaw4bubaSDEkcOieSBsw6AgUiBDb2RlcyB04bqhbyByYSBGaWd1cmUgMTogDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIz09PT09PT09PT09PT09PT09PT09DQojIERhdGEgVmlzdWFsaXphdGlvbg0KIz09PT09PT09PT09PT09PT09PT09DQoNCiMgTG9hZCBzb21lIFIgcGFja2FnZXMgZm9yIERhdGEgVmlzdWFsaXphdGlvbjogDQoNCmxpYnJhcnkoZ2dlY29ub2Rpc3QpICMgaW5zdGFsbC5wYWNrYWdlcygiZ2dlY29ub2Rpc3QiLCByZXBvcyA9ICJodHRwczovL2NpbmMucnVkLmlzIikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc2hvd3RleHQpDQoNCiMgU2VsZWN0IFVidW50dSBDb25kZW5zZWQgZm9udDogDQpzaG93dGV4dC5hdXRvKCkNCmZvbnRfYWRkX2dvb2dsZShuYW1lID0gIlVidW50dSBDb25kZW5zZWQiLCBmYW1pbHkgPSAidWJ1IikNCm15X2ZvbnQgPC0gInVidSINCg0KDQpkZl90aHVuaGFwICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcHJvdmluY2VfZW5nKSkgKyANCiAgZ2VvbV9lY29ub2Rpc3QoYWVzKHltaW4gPSB0aDI1LCBtZWRpYW4gPSB0aDUwLCB5bWF4ID0gdGg3NSksIA0KICAgICAgICAgICAgICAgICBtZWRpYW5fY29sID0gImZpcmVicmljayIsIA0KICAgICAgICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IiwgDQogICAgICAgICAgICAgICAgIG1lZGlhbl9wb2ludF9zaXplID0gMS4zLCANCiAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBUUlVFKSArIA0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV9lY29ub2Rpc3QoKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSwgbGltaXRzID0gcmFuZ2UoMCwgMzUwKSwgYnJlYWtzID0gc2VxKDAsIDM1MCwgNTApLCBwb3NpdGlvbiA9ICJyaWdodCIpICsgDQogIGxhYnModGl0bGUgPSAiRmlndXJlIDE6IEdhcHMgaW4gSG91c2Vob2xkIEluY29tZSAobWlsbGlvbnMgVk5EKSBieSBQcm92aW5jZSwgMjAxOCIsIA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IFZITFNTIDIwMTgsIEdTTyIpICsgIA0KICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjMsIDEsIDAuMywgMC41KSwgImNtIikpICsgDQogIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gbXlfZm9udCwgc2l6ZSA9IDkpKSArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBteV9mb250KSkgKyANCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSA4LCBmYWNlID0gIml0YWxpYyIpKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9IG15X2ZvbnQsIHNpemUgPSAxNSkpIC0+IGYxIA0KDQpncmlkLm5ld3BhZ2UoKQ0KDQpmMSAlPiUgDQogIGxlZnRfYWxpZ24oYygidGl0bGUiLCAiY2FwdGlvbiIpKSAlPiUgDQogIGFkZF9lY29ub2Rpc3RfbGVnZW5kKA0KICAgIGVjb25vZGlzdF9sZWdlbmRfZ3JvYigNCiAgICAgIHRlbnRoX2xhYiA9ICIyNXRoIFBlcmNlbnRpbGUiLCANCiAgICAgIG5pbmV0aWV0aF9sYWIgPSAiNzV0aCBQZXJjZW50aWxlIiwgDQogICAgICBtZWRfbGFiID0gIk1lZGlhbiIsIA0KICAgICAgbWVkX2NvbCA9ICJmaXJlYnJpY2siLCANCiAgICAgIGZhbWlseSA9IG15X2ZvbnQsIA0KICAgICAgbGFiZWxfc2l6ZSA9IDExLA0KICAgICksIA0KICAgIGJlbG93ID0gInRpdGxlIg0KICApICU+JSANCiAgZ3JpZC5kcmF3KCkNCmBgYA0KDQo=