There are several loan_statutes from which we derive binary column
indicating where given credit was good or bad. Categories
Current, Fully Paid and Charged Off consists
of \(96.8\%\) of all the credits.
Here we create good_bad column. Out data set is imbalanced: there are
\(89\%\) of good credits and \(11\%\) of bad ones.
Split data into training set and test set in proportions 80:20.
Fine classing and coarse classing
Function woe() groups data by a choosen attribute and
calculates Weight of Evidence (and bunch of another proportions and
ratios) and Information Value for that attribute. If
discrete=TRUE data is arranged by WoE (suitable for
quantitative attributes). If discrete=FALSE data is arranged by
the attribute itself in ascending order (suitable for qualitative
attributes). Function plot_by_woe() plots attribute values
againts its WoE. In this function we’ve added additional feature which
is bubble size depending on the n_obs. We use
tidyverse environment extensively to define below
functions.
woe <- function(df, train, column, discrete = TRUE){
if (!('good_bad' %in% colnames(df))) {
stop('Lack of column good_bad in the data frame.')
}
temp <- df[train,] %>%
group_by(across(all_of(column)), good_bad) %>%
summarise(n_obs = n(), .groups = 'keep') %>%
ungroup() %>%
mutate(good_bad = ifelse(good_bad == 0, 'bad', 'good')) %>%
pivot_wider(names_from = good_bad, names_prefix = 'n_', values_from = n_obs, values_fill = 0) %>%
mutate(n_obs = n_bad + n_good) %>%
mutate(prop_n_obs = n_obs / sum(n_obs)
,prop_bad = n_bad / n_obs
,prop_good = n_good / n_obs
,prop_n_bad = n_bad / sum(n_bad)
,prop_n_good = n_good / sum(n_good)) %>%
mutate(WoE = log(prop_n_good / prop_n_bad)) %>%
arrange(ifelse(discrete, WoE, eval(column))) %>%
mutate(diff_prop_good = c(NaN, prop_good %>% diff() %>% abs())
,diff_WoE = c(NaN, WoE %>% diff() %>% abs())
,IV = (prop_n_good - prop_n_bad) * WoE) %>%
mutate(IV = sum(IV))
return(temp)
}
plot_by_woe <- function(df_woe, discrete = TRUE, rotation = 0){
col_name <- colnames(df_woe)[1]
if (discrete) sort_col = 'WoE' else sort_col = colnames(df_woe)[1]
ggplot(df_woe, aes(reorder(.data[[col_name]], .data[[sort_col]]), WoE)) +
geom_point(aes(size = n_obs)) +
theme_bw() +
theme(axis.text.x = element_text(angle = rotation, vjust = 1, hjust = 1)) +
labs(x = '', y = '', title =paste0('Weight of evidence of the attribute ', col_name), size = 'Size')
}
Preprocessing attribute grade was explained in chapter 29 of
the Udemy course. This attribute has medium Information Value
(0.29).
woe_grade <- woe(data, train_index, 'grade')
woe_grade %>% select(grade, n_obs, WoE, IV)
plot_by_woe(woe_grade)

list_of_dummy_variables <- c(
'grade_A', 'grade_B', 'grade_C', 'grade_D', 'grade_E', 'grade_F', 'grade_G'
)
list_of_reference_categories <- c('grade_G')
Preprocessing attribute home_ownership was explained in
chapter 29 of the Udemy course. This attribute has weak Information
Value (0.02).
woe_home_ownership <- woe(data, train_index, 'home_ownership')
woe_home_ownership %>% select(home_ownership, n_obs, WoE, IV)
plot_by_woe(woe_home_ownership)

data <- data %>%
mutate(home_ownership_RENT_OTHER_NONE_ANY = home_ownership_RENT + home_ownership_OTHER + home_ownership_NONE + home_ownership_ANY)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'home_ownership_RENT_OTHER_NONE_ANY', 'home_ownership_OWN', 'home_ownership_MORTGAGE'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'home_ownership_RENT_OTHER_NONE_ANY'
)
Preprocessing attribute addr_state was explained in chapter
30 of the Udemy course.
woe_addr_state <- woe(data, train_index, 'addr_state')
woe_addr_state %>% select(addr_state, n_obs, WoE, IV)
plot_by_woe(woe_addr_state, rotation = 90)

data <- data %>%
mutate(addr_state_NE_IA_NV_FL_HI_AL = addr_state_NE + addr_state_IA + addr_state_NV + addr_state_FL + addr_state_HI + addr_state_AL
,addr_state_NM_VA = addr_state_NM + addr_state_VA
,addr_state_OK_TN_MO_LA_MD_NC = addr_state_OK + addr_state_TN + addr_state_MO + addr_state_LA + addr_state_MD + addr_state_NC
,addr_state_UT_KY_AZ_NJ = addr_state_UT + addr_state_KY + addr_state_AZ + addr_state_NJ
,addr_state_AR_MI_PA_OH_MN = addr_state_AR + addr_state_MI + addr_state_PA + addr_state_OH + addr_state_MN
,addr_state_RI_MA_DE_SD_IN = addr_state_RI + addr_state_MA + addr_state_DE + addr_state_SD + addr_state_IN
,addr_state_GA_WA_OR = addr_state_GA + addr_state_WA + addr_state_OR
,addr_state_WI_MT = addr_state_WI + addr_state_MT
,addr_state_IL_CT = addr_state_IL + addr_state_CT
,addr_state_KS_SC_CO_VT_AK_MS = addr_state_KS + addr_state_SC + addr_state_CO + addr_state_VT + addr_state_AK + addr_state_MS
,addr_state_WV_NH_WY_DC_ME_ID = addr_state_WV + addr_state_NH + addr_state_WY + addr_state_DC + addr_state_ME + addr_state_ID
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'addr_state_NE_IA_NV_FL_HI_AL', 'addr_state_NM_VA', 'addr_state_NY'
,'addr_state_OK_TN_MO_LA_MD_NC', 'addr_state_CA', 'addr_state_UT_KY_AZ_NJ'
,'addr_state_AR_MI_PA_OH_MN', 'addr_state_RI_MA_DE_SD_IN', 'addr_state_GA_WA_OR'
,'addr_state_WI_MT', 'addr_state_IL_CT', 'addr_state_KS_SC_CO_VT_AK_MS'
,'addr_state_TX', 'addr_state_WV_NH_WY_DC_ME_ID'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'addr_state_NE_IA_NV_FL_HI_AL'
)
Preprocessing attribute verification_status left as homework
of the Udemy course. This attribute has weak Information Value
(0.02).
woe_verification_status <- woe(data, train_index, 'verification_status')
woe_verification_status %>% select(verification_status, n_obs, WoE, IV)
plot_by_woe(woe_verification_status)

list_of_dummy_variables <- c(
list_of_dummy_variables
,'verification_status_Verified'
,'verification_status_Source.Verified'
,'verification_status_Not.Verified'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'verification_status_Verified'
)
Preprocessing attribute purpose left as homework of the
Udemy course. This attribute has weak Information Value (0.04).
woe_purpose <- woe(data, train_index, 'purpose')
woe_purpose %>% select(purpose, n_obs, WoE, IV)
plot_by_woe(woe_purpose, rotation = 45)

data <- data %>%
mutate(purpose_small_business_educational = purpose_small_business + purpose_educational
,purpose_renewable_energy_moving_other_house_medical = purpose_renewable_energy + purpose_moving + purpose_other + purpose_house + purpose_medical
,purpose_wedding_vacation_debt_consolidation = purpose_wedding + purpose_vacation + purpose_debt_consolidation
,purpose_major_purchase_home_improvement = purpose_major_purchase + purpose_home_improvement
,purpose_car_credit_card = purpose_car + purpose_credit_card
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'purpose_small_business_educational'
,'purpose_renewable_energy_moving_other_house_medical'
,'purpose_wedding_vacation_debt_consolidation'
,'purpose_major_purchase_home_improvement'
,'purpose_car_credit_card'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'purpose_small_business_educational'
)
Preprocessing attribute initial_list_status left as homework
of the Udemy course. This attribute has weak Information Value
(0.03).
woe_initial_list_status <- woe(data, train_index, 'initial_list_status')
woe_initial_list_status %>% select(initial_list_status, n_obs, WoE, IV)
plot_by_woe(woe_initial_list_status)

list_of_dummy_variables <- c(
list_of_dummy_variables
,'initial_list_status_f', 'initial_list_status_w'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'initial_list_status_f'
)
Preprocessing attribute term was explained in chapter 33 of
the Udemy course. This attribute has weak Information Value (0.04).
woe_term <- woe(data, train_index, 'term', discrete = FALSE)
woe_term %>% select(term, n_obs, WoE, IV)
plot_by_woe(woe_term)

data <- data %>%
mutate(term_36 = if_else(term == 36, 1, 0)
,term_60 = if_else(term == 60, 1, 0))
list_of_dummy_variables <- c(
list_of_dummy_variables
,'term_36', 'term_60'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'term_60'
)
Preprocessing attribute emp_length was explained in chapter
33 of the Udemy course. This attribute has no predictive power according
to the Information Value (<0.02).
woe_emp_length <- woe(data, train_index, 'emp_length', discrete = FALSE)
woe_emp_length %>% select(emp_length, n_obs, WoE, IV)
plot_by_woe(woe_emp_length, discrete = FALSE)

data <- data %>%
mutate(emp_length_0 = if_else(emp_length == 0, 1, 0)
,emp_length_1_4 = if_else(emp_length >= 1 & emp_length <= 4, 1, 0)
,emp_length_5_6 = if_else(emp_length >= 5 & emp_length <= 6, 1, 0)
,emp_length_7_9 = if_else(emp_length >= 7 & emp_length <= 9, 1, 0)
,emp_length_10 = if_else(emp_length == 10, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'emp_length_0', 'emp_length_1_4', 'emp_length_5_6', 'emp_length_7_9', 'emp_length_10'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'emp_length_0'
)
Preprocessing attribute months_since_issue_d was explained
in chapter 34 of the Udemy course. This attribute has medium Information
Value (0.11).
data <- data %>%
mutate(months_since_issue_d_cut = cut(months_since_issue_d, 50))
woe_months_since_issue_d_cut <- woe(data, train_index, 'months_since_issue_d_cut', discrete = FALSE)
woe_months_since_issue_d_cut %>% select(months_since_issue_d_cut, n_obs, WoE, IV)
plot_by_woe(woe_months_since_issue_d_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(months_since_issue_d_less_38 = if_else(months_since_issue_d < 38, 1, 0)
,months_since_issue_d_38_39 = if_else(months_since_issue_d >= 38 & months_since_issue_d <= 39, 1, 0)
,months_since_issue_d_40_41 = if_else(months_since_issue_d >= 40 & months_since_issue_d <= 41, 1, 0)
,months_since_issue_d_42_48 = if_else(months_since_issue_d >= 42 & months_since_issue_d <= 48, 1, 0)
,months_since_issue_d_49_52 = if_else(months_since_issue_d >= 49 & months_since_issue_d <= 52, 1, 0)
,months_since_issue_d_53_64 = if_else(months_since_issue_d >= 53 & months_since_issue_d <= 64, 1, 0)
,months_since_issue_d_65_84 = if_else(months_since_issue_d >= 65 & months_since_issue_d <= 84, 1, 0)
,months_since_issue_d_84_more = if_else(months_since_issue_d > 84, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'months_since_issue_d_less_38'
,'months_since_issue_d_38_39'
,'months_since_issue_d_40_41'
,'months_since_issue_d_42_48'
,'months_since_issue_d_49_52'
,'months_since_issue_d_53_64'
,'months_since_issue_d_65_84'
,'months_since_issue_d_84_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'months_since_issue_d_less_38'
)
Preprocessing attribute int_rate was explained in chapter 34
of the Udemy course. This attribute has strong Information Value
(0.35).
data <- data %>%
mutate(int_rate_cut = cut(int_rate, 50))
woe_int_rate_cut <- woe(data, train_index, 'int_rate_cut', discrete = FALSE)
woe_int_rate_cut %>% select(int_rate_cut, n_obs, WoE, IV)
plot_by_woe(woe_int_rate_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(int_rate_less_9.548 = if_else(int_rate < 9.548, 1, 0)
,int_rate_9.548_12.025 = if_else(int_rate >= 9.548 & int_rate <= 12.025, 1, 0)
,int_rate_12.025_15.74 = if_else(int_rate >= 12.025 & int_rate <= 15.74, 1, 0)
,int_rate_15.74_20.281 = if_else(int_rate >= 15.74 & int_rate <= 20.281, 1, 0)
,int_rate_20.281_more = if_else(int_rate > 20.281, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'int_rate_less_9.548'
,'int_rate_9.548_12.025'
,'int_rate_12.025_15.74'
,'int_rate_15.74_20.281'
,'int_rate_20.281_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'int_rate_less_9.548'
)
Preprocessing attribute months_since_earliest_cr_line left
as homework of the Udemy course. This attribute has has no predictive
power according to the Information Value (<0.02).
data <- data %>%
mutate(months_since_earliest_cr_line_cut = cut(months_since_earliest_cr_line, 50))
woe_months_since_earliest_cr_line_cut <- woe(data, train_index, 'months_since_earliest_cr_line_cut', discrete = FALSE)
woe_months_since_earliest_cr_line_cut %>% select(months_since_earliest_cr_line_cut, n_obs, WoE, IV)
plot_by_woe(woe_months_since_earliest_cr_line_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(months_since_earliest_cr_line_less_140 = if_else(months_since_earliest_cr_line < 140, 1, 0)
,months_since_earliest_cr_line_141_164 = if_else(months_since_earliest_cr_line >= 141
& months_since_earliest_cr_line <= 164, 1, 0)
,months_since_earliest_cr_line_165_247 = if_else(months_since_earliest_cr_line >= 165
& months_since_earliest_cr_line <= 247, 1, 0)
,months_since_earliest_cr_line_248_270 = if_else(months_since_earliest_cr_line >= 248
& months_since_earliest_cr_line <= 270, 1, 0)
,months_since_earliest_cr_line_271_352 = if_else(months_since_earliest_cr_line >= 271
& months_since_earliest_cr_line <= 352, 1, 0)
,months_since_earliest_cr_line_352_more = if_else(months_since_earliest_cr_line > 352, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'months_since_earliest_cr_line_less_140'
,'months_since_earliest_cr_line_141_164'
,'months_since_earliest_cr_line_165_247'
,'months_since_earliest_cr_line_248_270'
,'months_since_earliest_cr_line_271_352'
,'months_since_earliest_cr_line_352_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'months_since_earliest_cr_line_less_140'
)
Preprocessing attribute installment left as homework of the
Udemy course. This attribute has has no predictive power according to
the Information Value (<0.02).
data <- data %>%
mutate(installment_cut = cut(installment, 50))
woe_installment_cut <- woe(data, train_index, 'installment_cut', discrete = FALSE)
woe_installment_cut %>% select(installment_cut, n_obs, WoE, IV)
plot_by_woe(woe_installment_cut, discrete = FALSE, rotation = 90)

Preprocessing attribute delinq_2yrs left as homework of the
Udemy course.
woe_delinq_2yrs <- woe(data, train_index, 'delinq_2yrs', discrete = FALSE)
woe_delinq_2yrs %>% select(delinq_2yrs, n_obs, WoE, IV)
plot_by_woe(woe_delinq_2yrs, discrete = FALSE)

data <- data %>%
mutate(delinq_2yrs_0 = if_else(delinq_2yrs == 0, 1, 0)
,delinq_2yrs_1_3 = if_else(delinq_2yrs >= 1 & delinq_2yrs <= 3, 1, 0)
,delinq_2yrs_3_more = if_else(delinq_2yrs > 3, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'delinq_2yrs_0 '
,'delinq_2yrs_1_3'
,'delinq_2yrs_3_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'delinq_2yrs_0 '
)
Preprocessing attribute inq_last_6mths left as homework of
the Udemy course.
woe_inq_last_6mths <- woe(data, train_index, 'inq_last_6mths', discrete = FALSE)
woe_inq_last_6mths %>% select(inq_last_6mths, n_obs, WoE, IV)
plot_by_woe(woe_inq_last_6mths, discrete = FALSE)

data <- data %>%
mutate(inq_last_6mths_0 = if_else(inq_last_6mths == 0, 1, 0)
,inq_last_6mths_1_2 = if_else(inq_last_6mths >= 1 & inq_last_6mths <= 2, 1, 0)
,inq_last_6mths_3_6 = if_else(inq_last_6mths >= 3 & inq_last_6mths <= 6, 1, 0)
,inq_last_6mths_6_more = if_else(inq_last_6mths > 6, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'inq_last_6mths_0'
,'inq_last_6mths_1_2'
,'inq_last_6mths_3_6'
,'inq_last_6mths_6_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'inq_last_6mths_0'
)
Preprocessing attribute open_acc left as homework of the
Udemy course.
woe_open_acc <- woe(data, train_index, 'open_acc', discrete = FALSE)
woe_open_acc %>% select(open_acc, n_obs, WoE, IV)
plot_by_woe(woe_open_acc, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(open_acc_0 = if_else(open_acc == 0, 1, 0)
,open_acc_1_3 = if_else(open_acc >= 1 & open_acc <= 3, 1, 0)
,open_acc_4_12 = if_else(open_acc >= 4 & open_acc <= 12, 1, 0)
,open_acc_13_17 = if_else(open_acc >= 13 & open_acc <= 17, 1, 0)
,open_acc_18_22 = if_else(open_acc >= 18 & open_acc <= 22, 1, 0)
,open_acc_23_25 = if_else(open_acc >= 23 & open_acc <= 25, 1, 0)
,open_acc_26_30 = if_else(open_acc >= 26 & open_acc <= 30, 1, 0)
,open_acc_30_more = if_else(open_acc > 30, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'open_acc_0'
,'open_acc_1_3'
,'open_acc_4_12'
,'open_acc_13_17'
,'open_acc_18_22'
,'open_acc_23_25'
,'open_acc_26_30'
,'open_acc_30_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'open_acc_0'
)
Preprocessing attribute pub_rec left as homework of the
Udemy course.
woe_pub_rec <- woe(data, train_index, 'pub_rec', discrete = FALSE)
woe_pub_rec %>% select(pub_rec, n_obs, WoE, IV)
plot_by_woe(woe_pub_rec, discrete = FALSE)

data <- data %>%
mutate(pub_rec_0_2 = if_else(pub_rec >= 0 & pub_rec <= 2, 1, 0)
,pub_rec_3_4 = if_else(pub_rec >= 3 & pub_rec <= 4, 1, 0)
,pub_rec_4_more = if_else(pub_rec > 4, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'pub_rec_0_2'
,'pub_rec_3_4'
,'pub_rec_4_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'pub_rec_0_2'
)
Preprocessing attribute total_acc left as homework of the
Udemy course.
data <- data %>%
mutate(total_acc_cut = cut(total_acc, 50))
woe_total_acc_cut <- woe(data, train_index, 'total_acc_cut', discrete = FALSE)
woe_total_acc_cut %>% select(total_acc_cut, n_obs, WoE, IV)
plot_by_woe(woe_total_acc_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(total_acc_less_28 = if_else(total_acc < 28, 1, 0)
,total_acc_28_51 = if_else(total_acc >= 28 & total_acc <= 51, 1, 0)
,total_acc_51_more = if_else(total_acc > 51, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'total_acc_less_28'
,'total_acc_28_51'
,'total_acc_51_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'total_acc_less_28'
)
Preprocessing attribute acc_now_delinq left as homework of
the Udemy course.
woe_acc_now_delinq <- woe(data, train_index, 'acc_now_delinq', discrete = FALSE)
woe_acc_now_delinq %>% select(acc_now_delinq, n_obs, WoE, IV)
plot_by_woe(woe_acc_now_delinq, discrete = FALSE)

data <- data %>%
mutate(acc_now_delinq_0 = if_else(acc_now_delinq == 0, 1, 0)
,acc_now_delinq_0_more = if_else(acc_now_delinq > 0, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'acc_now_delinq_0'
,'acc_now_delinq_0_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'acc_now_delinq_0'
)
Preprocessing attribute total_rev_hi_lim left as homework of
the Udemy course.
data <- data %>%
mutate(total_rev_hi_lim_cut = cut(total_rev_hi_lim, 50))
woe_total_rev_hi_lim_cut <- woe(data, train_index, 'total_rev_hi_lim_cut', discrete = FALSE)
woe_total_rev_hi_lim_cut %>% select(total_rev_hi_lim_cut, n_obs, WoE, IV)
plot_by_woe(woe_total_rev_hi_lim_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(total_rev_hi_lim_Missing = if_else(is.na(total_rev_hi_lim), 1, 0)
,total_rev_hi_lim_less_5 = if_else(total_rev_hi_lim < 5000, 1, 0, missing = 0)
,total_rev_hi_lim_5_10 = if_else(total_rev_hi_lim >= 5000 & total_rev_hi_lim <= 10000, 1, 0, missing = 0)
,total_rev_hi_lim_10_20 = if_else(total_rev_hi_lim >= 10000 & total_rev_hi_lim <= 20000, 1, 0, missing = 0)
,total_rev_hi_lim_20_30 = if_else(total_rev_hi_lim >= 20000 & total_rev_hi_lim <= 30000, 1, 0, missing = 0)
,total_rev_hi_lim_30_40 = if_else(total_rev_hi_lim >= 30000 & total_rev_hi_lim <= 40000, 1, 0, missing = 0)
,total_rev_hi_lim_40_55 = if_else(total_rev_hi_lim >= 40000 & total_rev_hi_lim <= 55000, 1, 0, missing = 0)
,total_rev_hi_lim_55_95 = if_else(total_rev_hi_lim >= 55000 & total_rev_hi_lim <= 95000, 1, 0, missing = 0)
,total_rev_hi_lim_95_more = if_else(total_rev_hi_lim > 95000, 1, 0, missing = 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'total_rev_hi_lim_Missing'
,'total_rev_hi_lim_less_5'
,'total_rev_hi_lim_5_10'
,'total_rev_hi_lim_10_20'
,'total_rev_hi_lim_20_30'
,'total_rev_hi_lim_30_40'
,'total_rev_hi_lim_40_55'
,'total_rev_hi_lim_55_95'
,'total_rev_hi_lim_95_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'total_rev_hi_lim_Missing'
)
Preprocessing attribute annual_inc was explained in chapter
36 of the Udemy course.
data <- data %>%
mutate(annual_inc_cut = cut(annual_inc, 50))
woe_annual_inc_cut <- woe(data, train_index, 'annual_inc_cut', discrete = FALSE)
woe_annual_inc_cut %>% select(annual_inc_cut, n_obs, WoE, IV)
plot_by_woe(woe_annual_inc_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(annual_inc_less_20 = if_else(annual_inc < 20000, 1, 0)
,annual_inc_20_30 = if_else(annual_inc >= 20000 & annual_inc <= 30000, 1, 0)
,annual_inc_30_40 = if_else(annual_inc >= 30000 & annual_inc <= 40000, 1, 0)
,annual_inc_40_50 = if_else(annual_inc >= 40000 & annual_inc <= 50000, 1, 0)
,annual_inc_50_60 = if_else(annual_inc >= 50000 & annual_inc <= 60000, 1, 0)
,annual_inc_60_70 = if_else(annual_inc >= 60000 & annual_inc <= 70000, 1, 0)
,annual_inc_70_80 = if_else(annual_inc >= 70000 & annual_inc <= 80000, 1, 0)
,annual_inc_80_90 = if_else(annual_inc >= 80000 & annual_inc <= 90000, 1, 0)
,annual_inc_90_100 = if_else(annual_inc >= 90000 & annual_inc <= 100000, 1, 0)
,annual_inc_100_120 = if_else(annual_inc >= 100000 & annual_inc <= 120000, 1, 0)
,annual_inc_120_140 = if_else(annual_inc >= 120000 & annual_inc <= 140000, 1, 0)
,annual_inc_140_more = if_else(annual_inc > 140000, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'annual_inc_less_20'
,'annual_inc_20_30'
,'annual_inc_30_40'
,'annual_inc_40_50'
,'annual_inc_50_60'
,'annual_inc_60_70'
,'annual_inc_70_80'
,'annual_inc_80_90'
,'annual_inc_90_100'
,'annual_inc_100_120'
,'annual_inc_120_140'
,'annual_inc_140_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'annual_inc_less_20'
)
Preprocessing attribute mths_since_last_delinq was explained
in chapter 36 of the Udemy course.
data <- data %>%
mutate(mths_since_last_delinq_cut = cut(mths_since_last_delinq, 50))
woe_mths_since_last_delinq_cut <- woe(data, train_index, 'mths_since_last_delinq_cut', discrete = FALSE)
woe_mths_since_last_delinq_cut %>% select(mths_since_last_delinq_cut, n_obs, WoE, IV)
plot_by_woe(woe_mths_since_last_delinq_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(mths_since_last_delinq_Missing = if_else(is.na(mths_since_last_delinq), 1, 0)
,mths_since_last_delinq_0_3 = if_else(mths_since_last_delinq >= 0 & mths_since_last_delinq <= 3, 1, 0, missing = 0)
,mths_since_last_delinq_4_30 = if_else(mths_since_last_delinq >= 4 & mths_since_last_delinq <= 30, 1, 0, missing = 0)
,mths_since_last_delinq_31_56 = if_else(mths_since_last_delinq >= 31 & mths_since_last_delinq <= 56, 1, 0, missing = 0)
,mths_since_last_delinq_56_more = if_else(mths_since_last_delinq > 56, 1, 0, missing = 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'mths_since_last_delinq_Missing'
,'mths_since_last_delinq_0_3'
,'mths_since_last_delinq_4_30'
,'mths_since_last_delinq_31_56'
,'mths_since_last_delinq_56_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'mths_since_last_delinq_Missing'
)
Preprocessing attribute dti left as homework of the Udemy
course.
data <- data %>%
mutate(dti_cut = cut(dti, 50))
woe_dti_cut <- woe(data, train_index, 'dti_cut', discrete = FALSE)
woe_dti_cut %>% select(dti_cut, n_obs, WoE, IV)
plot_by_woe(woe_dti_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(dti_less_1.4 = if_else(dti < 1.4, 1, 0)
,dti_1.4_3.5 = if_else(dti >= 1.4 & dti <= 3.5, 1, 0)
,dti_3.5_7.7 = if_else(dti >= 3.5 & dti <= 7.7, 1, 0)
,dti_7.7_10.5 = if_else(dti >= 7.7 & dti <= 10.5, 1, 0)
,dti_10.5_16.1 = if_else(dti >= 10.5 & dti <= 16.1, 1, 0)
,dti_16.1_20.3 = if_else(dti >= 16.1 & dti <= 20.3, 1, 0)
,dti_20.3_21.7 = if_else(dti >= 20.3 & dti <= 21.7, 1, 0)
,dti_21.7_22.4 = if_else(dti >= 21.7 & dti <= 22.4, 1, 0)
,dti_22.4_35 = if_else(dti >= 22.4 & dti <= 35, 1, 0)
,dti_35_more = if_else(dti > 35, 1, 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'dti_less_1.4'
,'dti_1.4_3.5'
,'dti_3.5_7.7'
,'dti_7.7_10.5'
,'dti_10.5_16.1'
,'dti_16.1_20.3'
,'dti_20.3_21.7'
,'dti_21.7_22.4'
,'dti_22.4_35'
,'dti_35_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'dti_less_1.4'
)
Preprocessing attribute mths_since_last_record was left as
homework of the Udemy course.
data <- data %>%
mutate(mths_since_last_record_cut = cut(mths_since_last_record, 50))
woe_mths_since_last_record_cut <- woe(data, train_index, 'mths_since_last_record_cut', discrete = FALSE)
woe_mths_since_last_record_cut %>% select(mths_since_last_record_cut, n_obs, WoE, IV)
plot_by_woe(woe_mths_since_last_record_cut, discrete = FALSE, rotation = 90)

data <- data %>%
mutate(mths_since_last_record_Missing = if_else(is.na(mths_since_last_record), 1, 0)
,mths_since_last_record_0_2 = if_else(mths_since_last_record >= 0 & mths_since_last_record <= 2, 1, 0, missing = 0)
,mths_since_last_record_3_20 = if_else(mths_since_last_record >= 3 & mths_since_last_record <= 20, 1, 0, missing = 0)
,mths_since_last_record_21_31 = if_else(mths_since_last_record >= 21 & mths_since_last_record <= 31, 1, 0, missing = 0)
,mths_since_last_record_32_80 = if_else(mths_since_last_record >= 32 & mths_since_last_record <= 80, 1, 0, missing = 0)
,mths_since_last_record_81_86 = if_else(mths_since_last_record >= 81 & mths_since_last_record <= 86, 1, 0, missing = 0)
,mths_since_last_record_86_more = if_else(mths_since_last_record > 86, 1, 0, missing = 0)
)
list_of_dummy_variables <- c(
list_of_dummy_variables
,'mths_since_last_record_Missing'
,'mths_since_last_record_0_2'
,'mths_since_last_record_3_20'
,'mths_since_last_record_21_31'
,'mths_since_last_record_32_80'
,'mths_since_last_record_81_86'
,'mths_since_last_record_86_more'
)
list_of_reference_categories <- c(
list_of_reference_categories
,'mths_since_last_record_Missing'
)
write.csv(list_of_dummy_variables, 'pd_dummies.csv', row.names = FALSE)
write.csv(list_of_reference_categories, 'pd_dummies_reference.csv', row.names = FALSE)
write.csv(data, 'pd_preprocessed_loan_data_2007_2014.csv', row.names = FALSE)
LS0tDQp0aXRsZTogIkNyZWRpdCBSaXNrIE1vZGVsaW5nIC0gUEQgTW9kZWwgRGF0YSBQcmVwYXJhdGlvbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCklmIGFueSBpc3N1ZXMsIHF1ZXN0aW9ucyBvciBzdWdnZXN0aW9ucyBmZWVsIGZyZWUgdG8gcmVhY2ggbWUgb3V0IHZpYSBlLW1haWwgPHdpZWN6eW5za2lwYXdlbEBnbWFpbC5jb20+IG9yIFtMaW5rZWRpbl0oaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL3Bhd2VsLXdpZWN6eW5za2kvKS4gWW91IGNhbiBhbHNvIHZpc2l0IG15IFtHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9wYXdlbC13aWVjenluc2tpKS4NCg0KVGhpcyBpcyBSIHJlcGxpY2F0aW9uIG9mIHRoZSBjb2RlIGFuZCBleGVyY2lzZXMgZnJvbSB0aGUgVWRlbXkgY291cnNlIFsiQ3JlZGl0IFJpc2sgTW9kZWxpbmcgaW4gUHl0aG9uIDIwMjIiXShodHRwczovL3d3dy51ZGVteS5jb20vY291cnNlL2NyZWRpdC1yaXNrLW1vZGVsaW5nLWluLXB5dGhvbi8pLg0KDQpgYGB7ciBsb2FkX2xpYnJhcmllc30NCmlmKCFyZXF1aXJlKCdwYWNtYW4nKSkgaW5zdGFsbC5wYWNrYWdlcygncGFjbWFuJykNCnBhY21hbjo6cF9sb2FkKGRwbHlyLCB0aWR5ciwgZ2dwbG90MikNCm9wdGlvbnMoc2NpcGVuID0gMjApDQpgYGANCg0KV2UgbG9hZCBkYXRhIHdoaWNoIHdhcyBwcmVwcm9jZXNzZWQgaW4gdGhlIHByZXZpb3VzIHNjcmlwdCB3aGljaCB5b3UgY2FuIGZvdW5kIFtoZXJlXShodHRwczovL3JwdWJzLmNvbS9wYXdlbC13aWVjenluc2tpLzg5MTgxNSkuDQpgYGB7ciBsb2FkX2RhdGF9DQpkYXRhIDwtIHJlYWQuY3N2KCdwcmVwcm9jZXNzZWRfbG9hbl9kYXRhXzIwMDdfMjAxNC5jc3YnKQ0KYGBgDQoNClRoZXJlIGFyZSBzZXZlcmFsIGxvYW5fc3RhdHV0ZXMgZnJvbSB3aGljaCB3ZSBkZXJpdmUgYmluYXJ5IGNvbHVtbiBpbmRpY2F0aW5nIHdoZXJlIGdpdmVuIGNyZWRpdCB3YXMgZ29vZCBvciBiYWQuIENhdGVnb3JpZXMgKkN1cnJlbnQqLCAqRnVsbHkgUGFpZCogYW5kICpDaGFyZ2VkIE9mZiogY29uc2lzdHMgb2YgJDk2LjhcJSQgb2YgYWxsIHRoZSBjcmVkaXRzLg0KYGBge3IgbG9hbl9zdGF0dXN9DQpsb2FuX3N0YXR1c19zdW1tYXJ5IDwtIGRhdGEgJT4lDQogIGdyb3VwX2J5KGxvYW5fc3RhdHVzKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSBjb3VudCAvIHN1bShjb3VudCkpICU+JQ0KICBhcnJhbmdlKC1jb3VudCkNCg0KbG9hbl9zdGF0dXNfc3VtbWFyeQ0KDQpsb2FuX3N0YXR1c19zdW1tYXJ5ICU+JQ0KICB0b3Bfbig1LCBjb3VudCkgJT4lDQogIGdncGxvdChhZXMocmVvcmRlcihsb2FuX3N0YXR1cywgLWNvdW50KSwgY291bnQpKSArDQogIGdlb21fY29sKGFlcyhmaWxsID0gbG9hbl9zdGF0dXMpKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpICsNCiAgbGFicyh4ID0gJycsIHkgPSAnJykNCmBgYA0KDQpIZXJlIHdlIGNyZWF0ZSBnb29kX2JhZCBjb2x1bW4uIE91dCBkYXRhIHNldCBpcyBpbWJhbGFuY2VkOiB0aGVyZSBhcmUgJDg5XCUkIG9mIGdvb2QgY3JlZGl0cyBhbmQgJDExXCUkIG9mIGJhZCBvbmVzLg0KYGBge3IgZ29vZF9iYWR9DQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShnb29kX2JhZCA9IGlmX2Vsc2UoDQogICAgbG9hbl9zdGF0dXMgJWluJSBjKCdGdWxseSBQYWlkJywgJ0N1cnJlbnQnLCAnSW4gR3JhY2UgUGVyaW9kJywgJ0xhdGUgKDE2LTMwIGRheXMpJw0KICAgICAgICAgICAgICAgICAgICAgICAsJ0RvZXMgbm90IG1lZXQgdGhlIGNyZWRpdCBwb2xpY3kuIFN0YXR1czpGdWxseSBQYWlkJykNCiAgICAsMSwgMA0KICApKQ0KDQpkYXRhICU+JQ0KICBncm91cF9ieShnb29kX2JhZCkgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gY291bnQgLyBzdW0oY291bnQpKSAlPiUNCiAgYXJyYW5nZSgtY291bnQpDQpgYGANCg0KU3BsaXQgZGF0YSBpbnRvIHRyYWluaW5nIHNldCBhbmQgdGVzdCBzZXQgaW4gcHJvcG9ydGlvbnMgODA6MjAuDQpgYGB7ciBkYXRhX3NwbGl0fQ0Kc2V0LnNlZWQoMjEzNykNCm5fb2JzIDwtIG5yb3coZGF0YSkNCnRyYWluX2luZGV4IDwtIHNhbXBsZSgxOm5fb2JzLCAwLjggKiBuX29icykNCmBgYA0KDQojIyMgRmluZSBjbGFzc2luZyBhbmQgY29hcnNlIGNsYXNzaW5nDQoNCkZ1bmN0aW9uICp3b2UoKSogZ3JvdXBzIGRhdGEgYnkgYSBjaG9vc2VuIGF0dHJpYnV0ZSBhbmQgY2FsY3VsYXRlcyBXZWlnaHQgb2YgRXZpZGVuY2UgKGFuZCBidW5jaCBvZiBhbm90aGVyIHByb3BvcnRpb25zIGFuZCByYXRpb3MpIGFuZCBJbmZvcm1hdGlvbiBWYWx1ZSBmb3IgdGhhdCBhdHRyaWJ1dGUuIElmICpkaXNjcmV0ZT1UUlVFKiBkYXRhIGlzIGFycmFuZ2VkIGJ5IFdvRSAoc3VpdGFibGUgZm9yIHF1YW50aXRhdGl2ZSBhdHRyaWJ1dGVzKS4gSWYgKmRpc2NyZXRlPUZBTFNFKiBkYXRhIGlzIGFycmFuZ2VkIGJ5IHRoZSBhdHRyaWJ1dGUgaXRzZWxmIGluIGFzY2VuZGluZyBvcmRlciAoc3VpdGFibGUgZm9yIHF1YWxpdGF0aXZlIGF0dHJpYnV0ZXMpLiBGdW5jdGlvbiAqcGxvdF9ieV93b2UoKSogcGxvdHMgYXR0cmlidXRlIHZhbHVlcyBhZ2FpbnRzIGl0cyBXb0UuIEluIHRoaXMgZnVuY3Rpb24gd2UndmUgYWRkZWQgYWRkaXRpb25hbCBmZWF0dXJlIHdoaWNoIGlzIGJ1YmJsZSBzaXplIGRlcGVuZGluZyBvbiB0aGUgKm5fb2JzKi4gV2UgdXNlICp0aWR5dmVyc2UqIGVudmlyb25tZW50IGV4dGVuc2l2ZWx5IHRvIGRlZmluZSBiZWxvdyBmdW5jdGlvbnMuIA0KYGBge3Igd29lfQ0Kd29lIDwtIGZ1bmN0aW9uKGRmLCB0cmFpbiwgY29sdW1uLCBkaXNjcmV0ZSA9IFRSVUUpew0KICANCiAgaWYgKCEoJ2dvb2RfYmFkJyAlaW4lIGNvbG5hbWVzKGRmKSkpIHsNCiAgICBzdG9wKCdMYWNrIG9mIGNvbHVtbiBnb29kX2JhZCBpbiB0aGUgZGF0YSBmcmFtZS4nKQ0KICB9DQogIA0KICB0ZW1wIDwtIGRmW3RyYWluLF0gJT4lDQogICAgZ3JvdXBfYnkoYWNyb3NzKGFsbF9vZihjb2x1bW4pKSwgZ29vZF9iYWQpICU+JQ0KICAgIHN1bW1hcmlzZShuX29icyA9IG4oKSwgLmdyb3VwcyA9ICdrZWVwJykgJT4lDQogICAgdW5ncm91cCgpICU+JQ0KICAgIG11dGF0ZShnb29kX2JhZCA9IGlmZWxzZShnb29kX2JhZCA9PSAwLCAnYmFkJywgJ2dvb2QnKSkgJT4lDQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdvb2RfYmFkLCBuYW1lc19wcmVmaXggPSAnbl8nLCB2YWx1ZXNfZnJvbSA9IG5fb2JzLCB2YWx1ZXNfZmlsbCA9IDApICU+JQ0KICAgIG11dGF0ZShuX29icyA9IG5fYmFkICsgbl9nb29kKSAlPiUNCiAgICBtdXRhdGUocHJvcF9uX29icyA9IG5fb2JzIC8gc3VtKG5fb2JzKQ0KICAgICAgICAgICAscHJvcF9iYWQgPSBuX2JhZCAvIG5fb2JzDQogICAgICAgICAgICxwcm9wX2dvb2QgPSBuX2dvb2QgLyBuX29icw0KICAgICAgICAgICAscHJvcF9uX2JhZCA9IG5fYmFkIC8gc3VtKG5fYmFkKQ0KICAgICAgICAgICAscHJvcF9uX2dvb2QgPSBuX2dvb2QgLyBzdW0obl9nb29kKSkgJT4lDQogICAgbXV0YXRlKFdvRSA9IGxvZyhwcm9wX25fZ29vZCAvIHByb3Bfbl9iYWQpKSAlPiUNCiAgICBhcnJhbmdlKGlmZWxzZShkaXNjcmV0ZSwgV29FLCBldmFsKGNvbHVtbikpKSAlPiUNCiAgICBtdXRhdGUoZGlmZl9wcm9wX2dvb2QgPSBjKE5hTiwgcHJvcF9nb29kICU+JSBkaWZmKCkgJT4lIGFicygpKQ0KICAgICAgICAgICAsZGlmZl9Xb0UgPSBjKE5hTiwgV29FICU+JSBkaWZmKCkgJT4lIGFicygpKQ0KICAgICAgICAgICAsSVYgPSAocHJvcF9uX2dvb2QgLSBwcm9wX25fYmFkKSAqIFdvRSkgJT4lDQogICAgbXV0YXRlKElWID0gc3VtKElWKSkNCiAgDQogIHJldHVybih0ZW1wKQ0KICANCn0NCg0KcGxvdF9ieV93b2UgPC0gZnVuY3Rpb24oZGZfd29lLCBkaXNjcmV0ZSA9IFRSVUUsIHJvdGF0aW9uID0gMCl7DQogIA0KICBjb2xfbmFtZSA8LSBjb2xuYW1lcyhkZl93b2UpWzFdDQogIA0KICBpZiAoZGlzY3JldGUpIHNvcnRfY29sID0gJ1dvRScgZWxzZSBzb3J0X2NvbCA9IGNvbG5hbWVzKGRmX3dvZSlbMV0NCiAgDQogIGdncGxvdChkZl93b2UsIGFlcyhyZW9yZGVyKC5kYXRhW1tjb2xfbmFtZV1dLCAuZGF0YVtbc29ydF9jb2xdXSksIFdvRSkpICsNCiAgICBnZW9tX3BvaW50KGFlcyhzaXplID0gbl9vYnMpKSArIA0KICAgIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gcm90YXRpb24sIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSkgKw0KICAgIGxhYnMoeCA9ICcnLCB5ID0gJycsIHRpdGxlID1wYXN0ZTAoJ1dlaWdodCBvZiBldmlkZW5jZSBvZiB0aGUgYXR0cmlidXRlICcsIGNvbF9uYW1lKSwgc2l6ZSA9ICdTaXplJykNCiAgDQp9DQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmdyYWRlKiB3YXMgZXhwbGFpbmVkIGluIGNoYXB0ZXIgMjkgb2YgdGhlIFVkZW15IGNvdXJzZS4gVGhpcyBhdHRyaWJ1dGUgaGFzIG1lZGl1bSBJbmZvcm1hdGlvbiBWYWx1ZSAoMC4yOSkuDQpgYGB7ciB3b2VfZ3JhZGV9DQp3b2VfZ3JhZGUgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnZ3JhZGUnKQ0Kd29lX2dyYWRlICU+JSBzZWxlY3QoZ3JhZGUsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2dyYWRlKQ0KDQpsaXN0X29mX2R1bW15X3ZhcmlhYmxlcyA8LSBjKA0KICAnZ3JhZGVfQScsICdncmFkZV9CJywgJ2dyYWRlX0MnLCAnZ3JhZGVfRCcsICdncmFkZV9FJywgJ2dyYWRlX0YnLCAnZ3JhZGVfRycNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKCdncmFkZV9HJykNCmBgYA0KDQpQcmVwcm9jZXNzaW5nIGF0dHJpYnV0ZSAqaG9tZV9vd25lcnNoaXAqIHdhcyBleHBsYWluZWQgaW4gY2hhcHRlciAyOSBvZiB0aGUgVWRlbXkgY291cnNlLiBUaGlzIGF0dHJpYnV0ZSBoYXMgd2VhayBJbmZvcm1hdGlvbiBWYWx1ZSAoMC4wMikuDQpgYGB7ciBob21lX293bmVyc2hpcH0NCndvZV9ob21lX293bmVyc2hpcCA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICdob21lX293bmVyc2hpcCcpDQp3b2VfaG9tZV9vd25lcnNoaXAgJT4lIHNlbGVjdChob21lX293bmVyc2hpcCwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfaG9tZV9vd25lcnNoaXApDQoNCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShob21lX293bmVyc2hpcF9SRU5UX09USEVSX05PTkVfQU5ZID0gaG9tZV9vd25lcnNoaXBfUkVOVCArIGhvbWVfb3duZXJzaGlwX09USEVSICsgaG9tZV9vd25lcnNoaXBfTk9ORSArIGhvbWVfb3duZXJzaGlwX0FOWSkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCdob21lX293bmVyc2hpcF9SRU5UX09USEVSX05PTkVfQU5ZJywgJ2hvbWVfb3duZXJzaGlwX09XTicsICdob21lX293bmVyc2hpcF9NT1JUR0FHRScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwnaG9tZV9vd25lcnNoaXBfUkVOVF9PVEhFUl9OT05FX0FOWScNCikNCmBgYA0KDQpQcmVwcm9jZXNzaW5nIGF0dHJpYnV0ZSAqYWRkcl9zdGF0ZSogd2FzIGV4cGxhaW5lZCBpbiBjaGFwdGVyIDMwIG9mIHRoZSBVZGVteSBjb3Vyc2UuDQpgYGB7ciBhZGRyX3N0YXRlfQ0Kd29lX2FkZHJfc3RhdGUgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnYWRkcl9zdGF0ZScpDQp3b2VfYWRkcl9zdGF0ZSAlPiUgc2VsZWN0KGFkZHJfc3RhdGUsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2FkZHJfc3RhdGUsIHJvdGF0aW9uID0gOTApDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKGFkZHJfc3RhdGVfTkVfSUFfTlZfRkxfSElfQUwgPSBhZGRyX3N0YXRlX05FICsgYWRkcl9zdGF0ZV9JQSArIGFkZHJfc3RhdGVfTlYgKyBhZGRyX3N0YXRlX0ZMICsgYWRkcl9zdGF0ZV9ISSArIGFkZHJfc3RhdGVfQUwNCiAgICAgICAgICAsYWRkcl9zdGF0ZV9OTV9WQSA9IGFkZHJfc3RhdGVfTk0gKyBhZGRyX3N0YXRlX1ZBDQogICAgICAgICAgLGFkZHJfc3RhdGVfT0tfVE5fTU9fTEFfTURfTkMgPSBhZGRyX3N0YXRlX09LICsgYWRkcl9zdGF0ZV9UTiArIGFkZHJfc3RhdGVfTU8gKyBhZGRyX3N0YXRlX0xBICsgYWRkcl9zdGF0ZV9NRCArIGFkZHJfc3RhdGVfTkMNCiAgICAgICAgICAsYWRkcl9zdGF0ZV9VVF9LWV9BWl9OSiA9IGFkZHJfc3RhdGVfVVQgKyBhZGRyX3N0YXRlX0tZICsgYWRkcl9zdGF0ZV9BWiArIGFkZHJfc3RhdGVfTkoNCiAgICAgICAgICAsYWRkcl9zdGF0ZV9BUl9NSV9QQV9PSF9NTiA9IGFkZHJfc3RhdGVfQVIgKyBhZGRyX3N0YXRlX01JICsgYWRkcl9zdGF0ZV9QQSArIGFkZHJfc3RhdGVfT0ggKyBhZGRyX3N0YXRlX01ODQogICAgICAgICAgLGFkZHJfc3RhdGVfUklfTUFfREVfU0RfSU4gPSBhZGRyX3N0YXRlX1JJICsgYWRkcl9zdGF0ZV9NQSArIGFkZHJfc3RhdGVfREUgKyBhZGRyX3N0YXRlX1NEICsgYWRkcl9zdGF0ZV9JTg0KICAgICAgICAgICxhZGRyX3N0YXRlX0dBX1dBX09SID0gYWRkcl9zdGF0ZV9HQSArIGFkZHJfc3RhdGVfV0EgKyBhZGRyX3N0YXRlX09SDQogICAgICAgICAgLGFkZHJfc3RhdGVfV0lfTVQgPSBhZGRyX3N0YXRlX1dJICsgYWRkcl9zdGF0ZV9NVA0KICAgICAgICAgICxhZGRyX3N0YXRlX0lMX0NUID0gYWRkcl9zdGF0ZV9JTCArIGFkZHJfc3RhdGVfQ1QNCiAgICAgICAgICAsYWRkcl9zdGF0ZV9LU19TQ19DT19WVF9BS19NUyA9IGFkZHJfc3RhdGVfS1MgKyBhZGRyX3N0YXRlX1NDICsgYWRkcl9zdGF0ZV9DTyArIGFkZHJfc3RhdGVfVlQgKyBhZGRyX3N0YXRlX0FLICsgYWRkcl9zdGF0ZV9NUw0KICAgICAgICAgICxhZGRyX3N0YXRlX1dWX05IX1dZX0RDX01FX0lEID0gYWRkcl9zdGF0ZV9XViArIGFkZHJfc3RhdGVfTkggKyBhZGRyX3N0YXRlX1dZICsgYWRkcl9zdGF0ZV9EQyArIGFkZHJfc3RhdGVfTUUgKyBhZGRyX3N0YXRlX0lEDQogICkNCiAgICANCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnYWRkcl9zdGF0ZV9ORV9JQV9OVl9GTF9ISV9BTCcsICdhZGRyX3N0YXRlX05NX1ZBJywgJ2FkZHJfc3RhdGVfTlknDQogICwnYWRkcl9zdGF0ZV9PS19UTl9NT19MQV9NRF9OQycsICdhZGRyX3N0YXRlX0NBJywgJ2FkZHJfc3RhdGVfVVRfS1lfQVpfTkonDQogICwnYWRkcl9zdGF0ZV9BUl9NSV9QQV9PSF9NTicsICdhZGRyX3N0YXRlX1JJX01BX0RFX1NEX0lOJywgJ2FkZHJfc3RhdGVfR0FfV0FfT1InDQogICwnYWRkcl9zdGF0ZV9XSV9NVCcsICdhZGRyX3N0YXRlX0lMX0NUJywgJ2FkZHJfc3RhdGVfS1NfU0NfQ09fVlRfQUtfTVMnDQogICwnYWRkcl9zdGF0ZV9UWCcsICdhZGRyX3N0YXRlX1dWX05IX1dZX0RDX01FX0lEJw0KKQ0KDQpsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzIDwtIGMoDQogIGxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMNCiAgLCdhZGRyX3N0YXRlX05FX0lBX05WX0ZMX0hJX0FMJw0KKQ0KDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKnZlcmlmaWNhdGlvbl9zdGF0dXMqIGxlZnQgYXMgaG9tZXdvcmsgb2YgdGhlIFVkZW15IGNvdXJzZS4gVGhpcyBhdHRyaWJ1dGUgaGFzIHdlYWsgSW5mb3JtYXRpb24gVmFsdWUgKDAuMDIpLg0KYGBge3IgdmVyaWZpY2F0aW9uX3N0YXR1c30NCndvZV92ZXJpZmljYXRpb25fc3RhdHVzIDwtIHdvZShkYXRhLCB0cmFpbl9pbmRleCwgJ3ZlcmlmaWNhdGlvbl9zdGF0dXMnKQ0Kd29lX3ZlcmlmaWNhdGlvbl9zdGF0dXMgJT4lIHNlbGVjdCh2ZXJpZmljYXRpb25fc3RhdHVzLCBuX29icywgV29FLCBJVikNCnBsb3RfYnlfd29lKHdvZV92ZXJpZmljYXRpb25fc3RhdHVzKQ0KDQpsaXN0X29mX2R1bW15X3ZhcmlhYmxlcyA8LSBjKA0KICBsaXN0X29mX2R1bW15X3ZhcmlhYmxlcw0KICAsJ3ZlcmlmaWNhdGlvbl9zdGF0dXNfVmVyaWZpZWQnDQogICwndmVyaWZpY2F0aW9uX3N0YXR1c19Tb3VyY2UuVmVyaWZpZWQnDQogICwndmVyaWZpY2F0aW9uX3N0YXR1c19Ob3QuVmVyaWZpZWQnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ3ZlcmlmaWNhdGlvbl9zdGF0dXNfVmVyaWZpZWQnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKnB1cnBvc2UqIGxlZnQgYXMgaG9tZXdvcmsgb2YgdGhlIFVkZW15IGNvdXJzZS4gVGhpcyBhdHRyaWJ1dGUgaGFzIHdlYWsgSW5mb3JtYXRpb24gVmFsdWUgKDAuMDQpLg0KYGBge3IgcHVycG9zZX0NCndvZV9wdXJwb3NlIDwtIHdvZShkYXRhLCB0cmFpbl9pbmRleCwgJ3B1cnBvc2UnKQ0Kd29lX3B1cnBvc2UgJT4lIHNlbGVjdChwdXJwb3NlLCBuX29icywgV29FLCBJVikNCnBsb3RfYnlfd29lKHdvZV9wdXJwb3NlLCByb3RhdGlvbiA9IDQ1KQ0KICAgICAgICAgICANCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKHB1cnBvc2Vfc21hbGxfYnVzaW5lc3NfZWR1Y2F0aW9uYWwgPSBwdXJwb3NlX3NtYWxsX2J1c2luZXNzICsgcHVycG9zZV9lZHVjYXRpb25hbA0KICAgICAgICAgLHB1cnBvc2VfcmVuZXdhYmxlX2VuZXJneV9tb3Zpbmdfb3RoZXJfaG91c2VfbWVkaWNhbCA9IHB1cnBvc2VfcmVuZXdhYmxlX2VuZXJneSArIHB1cnBvc2VfbW92aW5nICsgcHVycG9zZV9vdGhlciArIHB1cnBvc2VfaG91c2UgKyAgcHVycG9zZV9tZWRpY2FsDQogICAgICAgICAscHVycG9zZV93ZWRkaW5nX3ZhY2F0aW9uX2RlYnRfY29uc29saWRhdGlvbiA9IHB1cnBvc2Vfd2VkZGluZyArIHB1cnBvc2VfdmFjYXRpb24gKyBwdXJwb3NlX2RlYnRfY29uc29saWRhdGlvbg0KICAgICAgICAgLHB1cnBvc2VfbWFqb3JfcHVyY2hhc2VfaG9tZV9pbXByb3ZlbWVudCA9IHB1cnBvc2VfbWFqb3JfcHVyY2hhc2UgICsgcHVycG9zZV9ob21lX2ltcHJvdmVtZW50DQogICAgICAgICAscHVycG9zZV9jYXJfY3JlZGl0X2NhcmQgPSBwdXJwb3NlX2NhciArIHB1cnBvc2VfY3JlZGl0X2NhcmQNCiAgKQ0KDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwncHVycG9zZV9zbWFsbF9idXNpbmVzc19lZHVjYXRpb25hbCcNCiAgLCdwdXJwb3NlX3JlbmV3YWJsZV9lbmVyZ3lfbW92aW5nX290aGVyX2hvdXNlX21lZGljYWwnDQogICwncHVycG9zZV93ZWRkaW5nX3ZhY2F0aW9uX2RlYnRfY29uc29saWRhdGlvbicNCiAgLCdwdXJwb3NlX21ham9yX3B1cmNoYXNlX2hvbWVfaW1wcm92ZW1lbnQnDQogICwncHVycG9zZV9jYXJfY3JlZGl0X2NhcmQnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ3B1cnBvc2Vfc21hbGxfYnVzaW5lc3NfZWR1Y2F0aW9uYWwnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmluaXRpYWxfbGlzdF9zdGF0dXMqIGxlZnQgYXMgaG9tZXdvcmsgb2YgdGhlIFVkZW15IGNvdXJzZS4gVGhpcyBhdHRyaWJ1dGUgaGFzIHdlYWsgSW5mb3JtYXRpb24gVmFsdWUgKDAuMDMpLg0KYGBge3IgaW5pdGlhbF9saXN0X3N0YXR1c30NCndvZV9pbml0aWFsX2xpc3Rfc3RhdHVzIDwtIHdvZShkYXRhLCB0cmFpbl9pbmRleCwgJ2luaXRpYWxfbGlzdF9zdGF0dXMnKQ0Kd29lX2luaXRpYWxfbGlzdF9zdGF0dXMgJT4lIHNlbGVjdChpbml0aWFsX2xpc3Rfc3RhdHVzLCBuX29icywgV29FLCBJVikNCnBsb3RfYnlfd29lKHdvZV9pbml0aWFsX2xpc3Rfc3RhdHVzKQ0KDQpsaXN0X29mX2R1bW15X3ZhcmlhYmxlcyA8LSBjKA0KICBsaXN0X29mX2R1bW15X3ZhcmlhYmxlcw0KICAsJ2luaXRpYWxfbGlzdF9zdGF0dXNfZicsICdpbml0aWFsX2xpc3Rfc3RhdHVzX3cnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ2luaXRpYWxfbGlzdF9zdGF0dXNfZicNCikNCmBgYA0KDQpQcmVwcm9jZXNzaW5nIGF0dHJpYnV0ZSAqdGVybSogd2FzIGV4cGxhaW5lZCBpbiBjaGFwdGVyIDMzIG9mIHRoZSBVZGVteSBjb3Vyc2UuIFRoaXMgYXR0cmlidXRlIGhhcyB3ZWFrIEluZm9ybWF0aW9uIFZhbHVlICgwLjA0KS4NCmBgYHtyIHRlcm19DQp3b2VfdGVybSA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICd0ZXJtJywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV90ZXJtICU+JSBzZWxlY3QodGVybSwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfdGVybSkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUodGVybV8zNiA9IGlmX2Vsc2UodGVybSA9PSAzNiwgMSwgMCkNCiAgICAgICAgICx0ZXJtXzYwID0gaWZfZWxzZSh0ZXJtID09IDYwLCAxLCAwKSkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCd0ZXJtXzM2JywgJ3Rlcm1fNjAnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ3Rlcm1fNjAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmVtcF9sZW5ndGgqIHdhcyBleHBsYWluZWQgaW4gY2hhcHRlciAzMyBvZiB0aGUgVWRlbXkgY291cnNlLiBUaGlzIGF0dHJpYnV0ZSBoYXMgbm8gcHJlZGljdGl2ZSBwb3dlciBhY2NvcmRpbmcgdG8gdGhlIEluZm9ybWF0aW9uIFZhbHVlICg8MC4wMikuDQpgYGB7ciBlbXBfbGVuZ3RofQ0Kd29lX2VtcF9sZW5ndGggPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnZW1wX2xlbmd0aCcsIGRpc2NyZXRlID0gRkFMU0UpDQp3b2VfZW1wX2xlbmd0aCAlPiUgc2VsZWN0KGVtcF9sZW5ndGgsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2VtcF9sZW5ndGgsIGRpc2NyZXRlID0gRkFMU0UpDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKGVtcF9sZW5ndGhfMCA9IGlmX2Vsc2UoZW1wX2xlbmd0aCA9PSAwLCAxLCAwKQ0KICAgICAgICAgLGVtcF9sZW5ndGhfMV80ID0gaWZfZWxzZShlbXBfbGVuZ3RoID49IDEgJiBlbXBfbGVuZ3RoIDw9IDQsIDEsIDApDQogICAgICAgICAsZW1wX2xlbmd0aF81XzYgPSBpZl9lbHNlKGVtcF9sZW5ndGggPj0gNSAmIGVtcF9sZW5ndGggPD0gNiwgMSwgMCkNCiAgICAgICAgICxlbXBfbGVuZ3RoXzdfOSA9IGlmX2Vsc2UoZW1wX2xlbmd0aCA+PSA3ICYgZW1wX2xlbmd0aCA8PSA5LCAxLCAwKQ0KICAgICAgICAgLGVtcF9sZW5ndGhfMTAgPSBpZl9lbHNlKGVtcF9sZW5ndGggPT0gMTAsIDEsIDApDQogICkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCdlbXBfbGVuZ3RoXzAnLCAnZW1wX2xlbmd0aF8xXzQnLCAnZW1wX2xlbmd0aF81XzYnLCAnZW1wX2xlbmd0aF83XzknLCAnZW1wX2xlbmd0aF8xMCcNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwnZW1wX2xlbmd0aF8wJw0KKQ0KYGBgDQoNClByZXByb2Nlc3NpbmcgYXR0cmlidXRlICptb250aHNfc2luY2VfaXNzdWVfZCogd2FzIGV4cGxhaW5lZCBpbiBjaGFwdGVyIDM0IG9mIHRoZSBVZGVteSBjb3Vyc2UuIFRoaXMgYXR0cmlidXRlIGhhcyBtZWRpdW0gSW5mb3JtYXRpb24gVmFsdWUgKDAuMTEpLg0KYGBge3IgbW9udGhzX3NpbmNlX2lzc3VlX2QsIHdhcm5pbmc9RkFMU0V9DQpkYXRhIDwtIGRhdGEgJT4lIA0KICBtdXRhdGUobW9udGhzX3NpbmNlX2lzc3VlX2RfY3V0ID0gY3V0KG1vbnRoc19zaW5jZV9pc3N1ZV9kLCA1MCkpDQoNCndvZV9tb250aHNfc2luY2VfaXNzdWVfZF9jdXQgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnbW9udGhzX3NpbmNlX2lzc3VlX2RfY3V0JywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV9tb250aHNfc2luY2VfaXNzdWVfZF9jdXQgJT4lIHNlbGVjdChtb250aHNfc2luY2VfaXNzdWVfZF9jdXQsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX21vbnRoc19zaW5jZV9pc3N1ZV9kX2N1dCwgZGlzY3JldGUgPSBGQUxTRSwgcm90YXRpb24gPSA5MCkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUobW9udGhzX3NpbmNlX2lzc3VlX2RfbGVzc18zOCA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPCAzOCwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF8zOF8zOSA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPj0gMzggJiBtb250aHNfc2luY2VfaXNzdWVfZCA8PSAzOSwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF80MF80MSA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPj0gNDAgJiBtb250aHNfc2luY2VfaXNzdWVfZCA8PSA0MSwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF80Ml80OCA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPj0gNDIgJiBtb250aHNfc2luY2VfaXNzdWVfZCA8PSA0OCwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF80OV81MiA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPj0gNDkgJiBtb250aHNfc2luY2VfaXNzdWVfZCA8PSA1MiwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF81M182NCA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPj0gNTMgJiBtb250aHNfc2luY2VfaXNzdWVfZCA8PSA2NCwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF82NV84NCA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2lzc3VlX2QgPj0gNjUgJiBtb250aHNfc2luY2VfaXNzdWVfZCA8PSA4NCwgMSwgMCkNCiAgICAgICAgICxtb250aHNfc2luY2VfaXNzdWVfZF84NF9tb3JlID0gaWZfZWxzZShtb250aHNfc2luY2VfaXNzdWVfZCA+IDg0LCAxLCAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnbW9udGhzX3NpbmNlX2lzc3VlX2RfbGVzc18zOCcNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF8zOF8zOScNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF80MF80MScNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF80Ml80OCcNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF80OV81MicNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF81M182NCcNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF82NV84NCcNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF84NF9tb3JlJw0KKQ0KDQpsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzIDwtIGMoDQogIGxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMNCiAgLCdtb250aHNfc2luY2VfaXNzdWVfZF9sZXNzXzM4Jw0KKQ0KYGBgDQoNClByZXByb2Nlc3NpbmcgYXR0cmlidXRlICppbnRfcmF0ZSogd2FzIGV4cGxhaW5lZCBpbiBjaGFwdGVyIDM0IG9mIHRoZSBVZGVteSBjb3Vyc2UuIFRoaXMgYXR0cmlidXRlIGhhcyBzdHJvbmcgSW5mb3JtYXRpb24gVmFsdWUgKDAuMzUpLg0KYGBge3IgaW50X3JhdGUsIHdhcm5pbmc9RkFMU0V9DQpkYXRhIDwtIGRhdGEgJT4lIA0KICBtdXRhdGUoaW50X3JhdGVfY3V0ID0gY3V0KGludF9yYXRlLCA1MCkpDQoNCndvZV9pbnRfcmF0ZV9jdXQgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnaW50X3JhdGVfY3V0JywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV9pbnRfcmF0ZV9jdXQgJT4lIHNlbGVjdChpbnRfcmF0ZV9jdXQsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2ludF9yYXRlX2N1dCwgZGlzY3JldGUgPSBGQUxTRSwgcm90YXRpb24gPSA5MCkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUoaW50X3JhdGVfbGVzc185LjU0OCA9IGlmX2Vsc2UoaW50X3JhdGUgPCA5LjU0OCwgMSwgMCkNCiAgICAgICAgICxpbnRfcmF0ZV85LjU0OF8xMi4wMjUgPSBpZl9lbHNlKGludF9yYXRlID49IDkuNTQ4ICYgaW50X3JhdGUgPD0gMTIuMDI1LCAxLCAwKQ0KICAgICAgICAgLGludF9yYXRlXzEyLjAyNV8xNS43NCA9IGlmX2Vsc2UoaW50X3JhdGUgPj0gMTIuMDI1ICYgaW50X3JhdGUgPD0gMTUuNzQsIDEsIDApDQogICAgICAgICAsaW50X3JhdGVfMTUuNzRfMjAuMjgxID0gaWZfZWxzZShpbnRfcmF0ZSA+PSAxNS43NCAmIGludF9yYXRlIDw9IDIwLjI4MSwgMSwgMCkNCiAgICAgICAgICxpbnRfcmF0ZV8yMC4yODFfbW9yZSA9IGlmX2Vsc2UoaW50X3JhdGUgPiAyMC4yODEsIDEsIDApDQogICkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCdpbnRfcmF0ZV9sZXNzXzkuNTQ4Jw0KICAsJ2ludF9yYXRlXzkuNTQ4XzEyLjAyNScNCiAgLCdpbnRfcmF0ZV8xMi4wMjVfMTUuNzQnDQogICwnaW50X3JhdGVfMTUuNzRfMjAuMjgxJw0KICAsJ2ludF9yYXRlXzIwLjI4MV9tb3JlJw0KKQ0KDQpsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzIDwtIGMoDQogIGxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMNCiAgLCdpbnRfcmF0ZV9sZXNzXzkuNTQ4Jw0KKQ0KYGBgDQoNClByZXByb2Nlc3NpbmcgYXR0cmlidXRlICptb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZSogbGVmdCBhcyBob21ld29yayBvZiB0aGUgVWRlbXkgY291cnNlLiBUaGlzIGF0dHJpYnV0ZSBoYXMgaGFzIG5vIHByZWRpY3RpdmUgcG93ZXIgYWNjb3JkaW5nIHRvIHRoZSBJbmZvcm1hdGlvbiBWYWx1ZSAoPDAuMDIpLg0KYGBge3IgbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmUsIHdhcm5pbmc9RkFMU0V9DQpkYXRhIDwtIGRhdGEgJT4lIA0KICBtdXRhdGUobW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfY3V0ID0gY3V0KG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lLCA1MCkpDQoNCndvZV9tb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZV9jdXQgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfY3V0JywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV9tb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZV9jdXQgJT4lIHNlbGVjdChtb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZV9jdXQsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX21vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lX2N1dCwgZGlzY3JldGUgPSBGQUxTRSwgcm90YXRpb24gPSA5MCkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUobW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfbGVzc18xNDAgPSBpZl9lbHNlKG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lIDwgMTQwLCAxLCAwKQ0KICAgICAgICAgLG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lXzE0MV8xNjQgPSBpZl9lbHNlKG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lID49IDE0MSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYgbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmUgPD0gMTY0LCAxLCAwKQ0KICAgICAgICAgLG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lXzE2NV8yNDcgPSBpZl9lbHNlKG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lID49IDE2NQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBtb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZSA8PSAyNDcsIDEsIDApDQogICAgICAgICAsbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfMjQ4XzI3MCA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmUgPj0gMjQ4IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBtb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZSA8PSAyNzAsIDEsIDApDQogICAgICAgICAsbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfMjcxXzM1MiA9IGlmX2Vsc2UobW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmUgPj0gMjcxIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBtb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZSA8PSAzNTIsIDEsIDApDQogICAgICAgICAsbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfMzUyX21vcmUgPSBpZl9lbHNlKG1vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lID4gMzUyLCAxLCAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfbGVzc18xNDAnDQogICwnbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfMTQxXzE2NCcNCiAgLCdtb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZV8xNjVfMjQ3Jw0KICAsJ21vbnRoc19zaW5jZV9lYXJsaWVzdF9jcl9saW5lXzI0OF8yNzAnDQogICwnbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfMjcxXzM1MicNCiAgLCdtb250aHNfc2luY2VfZWFybGllc3RfY3JfbGluZV8zNTJfbW9yZScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwnbW9udGhzX3NpbmNlX2VhcmxpZXN0X2NyX2xpbmVfbGVzc18xNDAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmluc3RhbGxtZW50KiBsZWZ0IGFzIGhvbWV3b3JrIG9mIHRoZSBVZGVteSBjb3Vyc2UuIFRoaXMgYXR0cmlidXRlIGhhcyBoYXMgbm8gcHJlZGljdGl2ZSBwb3dlciBhY2NvcmRpbmcgdG8gdGhlIEluZm9ybWF0aW9uIFZhbHVlICg8MC4wMikuDQpgYGB7ciBpbnN0YWxsbWVudCwgd2FybmluZz1GQUxTRX0NCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShpbnN0YWxsbWVudF9jdXQgPSBjdXQoaW5zdGFsbG1lbnQsIDUwKSkNCg0Kd29lX2luc3RhbGxtZW50X2N1dCA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICdpbnN0YWxsbWVudF9jdXQnLCBkaXNjcmV0ZSA9IEZBTFNFKQ0Kd29lX2luc3RhbGxtZW50X2N1dCAlPiUgc2VsZWN0KGluc3RhbGxtZW50X2N1dCwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfaW5zdGFsbG1lbnRfY3V0LCBkaXNjcmV0ZSA9IEZBTFNFLCByb3RhdGlvbiA9IDkwKQ0KYGBgDQoNClByZXByb2Nlc3NpbmcgYXR0cmlidXRlICpkZWxpbnFfMnlycyogbGVmdCBhcyBob21ld29yayBvZiB0aGUgVWRlbXkgY291cnNlLiANCmBgYHtyIGRlbGlucV8yeXJzfQ0Kd29lX2RlbGlucV8yeXJzIDwtIHdvZShkYXRhLCB0cmFpbl9pbmRleCwgJ2RlbGlucV8yeXJzJywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV9kZWxpbnFfMnlycyAlPiUgc2VsZWN0KGRlbGlucV8yeXJzLCBuX29icywgV29FLCBJVikNCnBsb3RfYnlfd29lKHdvZV9kZWxpbnFfMnlycywgZGlzY3JldGUgPSBGQUxTRSkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUoZGVsaW5xXzJ5cnNfMCA9IGlmX2Vsc2UoZGVsaW5xXzJ5cnMgPT0gMCwgMSwgMCkNCiAgICAgICAgICxkZWxpbnFfMnlyc18xXzMgPSBpZl9lbHNlKGRlbGlucV8yeXJzID49IDEgJiBkZWxpbnFfMnlycyA8PSAzLCAxLCAwKQ0KICAgICAgICAgLGRlbGlucV8yeXJzXzNfbW9yZSA9IGlmX2Vsc2UoZGVsaW5xXzJ5cnMgPiAzLCAxLCAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnZGVsaW5xXzJ5cnNfMCAnDQogICwnZGVsaW5xXzJ5cnNfMV8zJw0KICAsJ2RlbGlucV8yeXJzXzNfbW9yZScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwnZGVsaW5xXzJ5cnNfMCAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmlucV9sYXN0XzZtdGhzKiBsZWZ0IGFzIGhvbWV3b3JrIG9mIHRoZSBVZGVteSBjb3Vyc2UuIA0KYGBge3IgaW5xX2xhc3RfNm10aHN9DQp3b2VfaW5xX2xhc3RfNm10aHMgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnaW5xX2xhc3RfNm10aHMnLCBkaXNjcmV0ZSA9IEZBTFNFKQ0Kd29lX2lucV9sYXN0XzZtdGhzICU+JSBzZWxlY3QoaW5xX2xhc3RfNm10aHMsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2lucV9sYXN0XzZtdGhzLCBkaXNjcmV0ZSA9IEZBTFNFKQ0KDQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShpbnFfbGFzdF82bXRoc18wID0gaWZfZWxzZShpbnFfbGFzdF82bXRocyA9PSAwLCAxLCAwKQ0KICAgICAgICAgLGlucV9sYXN0XzZtdGhzXzFfMiA9IGlmX2Vsc2UoaW5xX2xhc3RfNm10aHMgPj0gMSAmIGlucV9sYXN0XzZtdGhzIDw9IDIsIDEsIDApDQogICAgICAgICAsaW5xX2xhc3RfNm10aHNfM182ID0gaWZfZWxzZShpbnFfbGFzdF82bXRocyA+PSAzICYgaW5xX2xhc3RfNm10aHMgPD0gNiwgMSwgMCkNCiAgICAgICAgICxpbnFfbGFzdF82bXRoc182X21vcmUgPSBpZl9lbHNlKGlucV9sYXN0XzZtdGhzID4gNiwgMSwgMCkNCiAgKQ0KDQpsaXN0X29mX2R1bW15X3ZhcmlhYmxlcyA8LSBjKA0KICBsaXN0X29mX2R1bW15X3ZhcmlhYmxlcw0KICAsJ2lucV9sYXN0XzZtdGhzXzAnDQogICwnaW5xX2xhc3RfNm10aHNfMV8yJw0KICAsJ2lucV9sYXN0XzZtdGhzXzNfNicNCiAgLCdpbnFfbGFzdF82bXRoc182X21vcmUnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ2lucV9sYXN0XzZtdGhzXzAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKm9wZW5fYWNjKiBsZWZ0IGFzIGhvbWV3b3JrIG9mIHRoZSBVZGVteSBjb3Vyc2UuIA0KYGBge3Igb3Blbl9hY2N9DQp3b2Vfb3Blbl9hY2MgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnb3Blbl9hY2MnLCBkaXNjcmV0ZSA9IEZBTFNFKQ0Kd29lX29wZW5fYWNjICU+JSBzZWxlY3Qob3Blbl9hY2MsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX29wZW5fYWNjLCBkaXNjcmV0ZSA9IEZBTFNFLCByb3RhdGlvbiA9IDkwKQ0KDQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShvcGVuX2FjY18wID0gaWZfZWxzZShvcGVuX2FjYyA9PSAwLCAxLCAwKQ0KICAgICAgICAgLG9wZW5fYWNjXzFfMyA9IGlmX2Vsc2Uob3Blbl9hY2MgPj0gMSAmIG9wZW5fYWNjIDw9IDMsIDEsIDApDQogICAgICAgICAsb3Blbl9hY2NfNF8xMiA9IGlmX2Vsc2Uob3Blbl9hY2MgPj0gNCAmIG9wZW5fYWNjIDw9IDEyLCAxLCAwKQ0KICAgICAgICAgLG9wZW5fYWNjXzEzXzE3ID0gaWZfZWxzZShvcGVuX2FjYyA+PSAxMyAmIG9wZW5fYWNjIDw9IDE3LCAxLCAwKQ0KICAgICAgICAgLG9wZW5fYWNjXzE4XzIyID0gaWZfZWxzZShvcGVuX2FjYyA+PSAxOCAmIG9wZW5fYWNjIDw9IDIyLCAxLCAwKQ0KICAgICAgICAgLG9wZW5fYWNjXzIzXzI1ID0gaWZfZWxzZShvcGVuX2FjYyA+PSAyMyAmIG9wZW5fYWNjIDw9IDI1LCAxLCAwKQ0KICAgICAgICAgLG9wZW5fYWNjXzI2XzMwID0gaWZfZWxzZShvcGVuX2FjYyA+PSAyNiAmIG9wZW5fYWNjIDw9IDMwLCAxLCAwKQ0KICAgICAgICAgLG9wZW5fYWNjXzMwX21vcmUgPSBpZl9lbHNlKG9wZW5fYWNjID4gMzAsIDEsIDApDQogICkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCdvcGVuX2FjY18wJw0KICAsJ29wZW5fYWNjXzFfMycNCiAgLCdvcGVuX2FjY180XzEyJw0KICAsJ29wZW5fYWNjXzEzXzE3Jw0KICAsJ29wZW5fYWNjXzE4XzIyJw0KICAsJ29wZW5fYWNjXzIzXzI1Jw0KICAsJ29wZW5fYWNjXzI2XzMwJw0KICAsJ29wZW5fYWNjXzMwX21vcmUnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ29wZW5fYWNjXzAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKnB1Yl9yZWMqIGxlZnQgYXMgaG9tZXdvcmsgb2YgdGhlIFVkZW15IGNvdXJzZS4gDQpgYGB7ciBwdWJfcmVjfQ0Kd29lX3B1Yl9yZWMgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAncHViX3JlYycsIGRpc2NyZXRlID0gRkFMU0UpDQp3b2VfcHViX3JlYyAlPiUgc2VsZWN0KHB1Yl9yZWMsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX3B1Yl9yZWMsIGRpc2NyZXRlID0gRkFMU0UpDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKHB1Yl9yZWNfMF8yID0gaWZfZWxzZShwdWJfcmVjID49IDAgJiBwdWJfcmVjIDw9IDIsIDEsIDApDQogICAgICAgICAscHViX3JlY18zXzQgPSBpZl9lbHNlKHB1Yl9yZWMgPj0gMyAmIHB1Yl9yZWMgPD0gNCwgMSwgMCkNCiAgICAgICAgICxwdWJfcmVjXzRfbW9yZSA9IGlmX2Vsc2UocHViX3JlYyA+IDQsIDEsIDApDQogICkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCdwdWJfcmVjXzBfMicNCiAgLCdwdWJfcmVjXzNfNCcNCiAgLCdwdWJfcmVjXzRfbW9yZScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwncHViX3JlY18wXzInDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKnRvdGFsX2FjYyogbGVmdCBhcyBob21ld29yayBvZiB0aGUgVWRlbXkgY291cnNlLiANCmBgYHtyIHRvdGFsX2FjYywgd2FybmluZz1GQUxTRX0NCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZSh0b3RhbF9hY2NfY3V0ID0gY3V0KHRvdGFsX2FjYywgNTApKQ0KDQp3b2VfdG90YWxfYWNjX2N1dCA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICd0b3RhbF9hY2NfY3V0JywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV90b3RhbF9hY2NfY3V0ICU+JSBzZWxlY3QodG90YWxfYWNjX2N1dCwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfdG90YWxfYWNjX2N1dCwgZGlzY3JldGUgPSBGQUxTRSwgcm90YXRpb24gPSA5MCkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUodG90YWxfYWNjX2xlc3NfMjggPSBpZl9lbHNlKHRvdGFsX2FjYyA8IDI4LCAxLCAwKQ0KICAgICAgICAgLHRvdGFsX2FjY18yOF81MSA9IGlmX2Vsc2UodG90YWxfYWNjID49IDI4ICYgdG90YWxfYWNjIDw9IDUxLCAxLCAwKQ0KICAgICAgICAgLHRvdGFsX2FjY181MV9tb3JlID0gaWZfZWxzZSh0b3RhbF9hY2MgPiA1MSwgMSwgMCkNCiAgKQ0KDQpsaXN0X29mX2R1bW15X3ZhcmlhYmxlcyA8LSBjKA0KICBsaXN0X29mX2R1bW15X3ZhcmlhYmxlcw0KICAsJ3RvdGFsX2FjY19sZXNzXzI4Jw0KICAsJ3RvdGFsX2FjY18yOF81MScNCiAgLCd0b3RhbF9hY2NfNTFfbW9yZScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwndG90YWxfYWNjX2xlc3NfMjgnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmFjY19ub3dfZGVsaW5xKiBsZWZ0IGFzIGhvbWV3b3JrIG9mIHRoZSBVZGVteSBjb3Vyc2UuIA0KYGBge3IgYWNjX25vd19kZWxpbnF9DQp3b2VfYWNjX25vd19kZWxpbnEgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnYWNjX25vd19kZWxpbnEnLCBkaXNjcmV0ZSA9IEZBTFNFKQ0Kd29lX2FjY19ub3dfZGVsaW5xICU+JSBzZWxlY3QoYWNjX25vd19kZWxpbnEsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2FjY19ub3dfZGVsaW5xLCBkaXNjcmV0ZSA9IEZBTFNFKQ0KDQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShhY2Nfbm93X2RlbGlucV8wID0gaWZfZWxzZShhY2Nfbm93X2RlbGlucSA9PSAwLCAxLCAwKQ0KICAgICAgICAgLGFjY19ub3dfZGVsaW5xXzBfbW9yZSA9IGlmX2Vsc2UoYWNjX25vd19kZWxpbnEgPiAwLCAxLCAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnYWNjX25vd19kZWxpbnFfMCcNCiAgLCdhY2Nfbm93X2RlbGlucV8wX21vcmUnDQopDQoNCmxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMgPC0gYygNCiAgbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcw0KICAsJ2FjY19ub3dfZGVsaW5xXzAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKnRvdGFsX3Jldl9oaV9saW0qIGxlZnQgYXMgaG9tZXdvcmsgb2YgdGhlIFVkZW15IGNvdXJzZS4gDQpgYGB7ciB0b3RhbF9yZXZfaGlfbGltLCB3YXJuaW5nPUZBTFNFfQ0KZGF0YSA8LSBkYXRhICU+JSANCiAgbXV0YXRlKHRvdGFsX3Jldl9oaV9saW1fY3V0ID0gY3V0KHRvdGFsX3Jldl9oaV9saW0sIDUwKSkNCg0Kd29lX3RvdGFsX3Jldl9oaV9saW1fY3V0IDwtIHdvZShkYXRhLCB0cmFpbl9pbmRleCwgJ3RvdGFsX3Jldl9oaV9saW1fY3V0JywgZGlzY3JldGUgPSBGQUxTRSkNCndvZV90b3RhbF9yZXZfaGlfbGltX2N1dCAlPiUgc2VsZWN0KHRvdGFsX3Jldl9oaV9saW1fY3V0LCBuX29icywgV29FLCBJVikNCnBsb3RfYnlfd29lKHdvZV90b3RhbF9yZXZfaGlfbGltX2N1dCwgZGlzY3JldGUgPSBGQUxTRSwgcm90YXRpb24gPSA5MCkNCg0KZGF0YSA8LSBkYXRhICU+JQ0KICBtdXRhdGUodG90YWxfcmV2X2hpX2xpbV9NaXNzaW5nID0gaWZfZWxzZShpcy5uYSh0b3RhbF9yZXZfaGlfbGltKSwgMSwgMCkNCiAgICAgICAgICx0b3RhbF9yZXZfaGlfbGltX2xlc3NfNSA9IGlmX2Vsc2UodG90YWxfcmV2X2hpX2xpbSA8IDUwMDAsIDEsIDAsIG1pc3NpbmcgPSAwKQ0KICAgICAgICAgLHRvdGFsX3Jldl9oaV9saW1fNV8xMCA9IGlmX2Vsc2UodG90YWxfcmV2X2hpX2xpbSA+PSA1MDAwICYgdG90YWxfcmV2X2hpX2xpbSA8PSAxMDAwMCwgMSwgMCwgbWlzc2luZyA9IDApDQogICAgICAgICAsdG90YWxfcmV2X2hpX2xpbV8xMF8yMCA9IGlmX2Vsc2UodG90YWxfcmV2X2hpX2xpbSA+PSAxMDAwMCAmIHRvdGFsX3Jldl9oaV9saW0gPD0gMjAwMDAsIDEsIDAsIG1pc3NpbmcgPSAwKQ0KICAgICAgICAgLHRvdGFsX3Jldl9oaV9saW1fMjBfMzAgPSBpZl9lbHNlKHRvdGFsX3Jldl9oaV9saW0gPj0gMjAwMDAgJiB0b3RhbF9yZXZfaGlfbGltIDw9IDMwMDAwLCAxLCAwLCBtaXNzaW5nID0gMCkNCiAgICAgICAgICx0b3RhbF9yZXZfaGlfbGltXzMwXzQwID0gaWZfZWxzZSh0b3RhbF9yZXZfaGlfbGltID49IDMwMDAwICYgdG90YWxfcmV2X2hpX2xpbSA8PSA0MDAwMCwgMSwgMCwgbWlzc2luZyA9IDApDQogICAgICAgICAsdG90YWxfcmV2X2hpX2xpbV80MF81NSA9IGlmX2Vsc2UodG90YWxfcmV2X2hpX2xpbSA+PSA0MDAwMCAmIHRvdGFsX3Jldl9oaV9saW0gPD0gNTUwMDAsIDEsIDAsIG1pc3NpbmcgPSAwKQ0KICAgICAgICAgLHRvdGFsX3Jldl9oaV9saW1fNTVfOTUgPSBpZl9lbHNlKHRvdGFsX3Jldl9oaV9saW0gPj0gNTUwMDAgJiB0b3RhbF9yZXZfaGlfbGltIDw9IDk1MDAwLCAxLCAwLCBtaXNzaW5nID0gMCkNCiAgICAgICAgICx0b3RhbF9yZXZfaGlfbGltXzk1X21vcmUgPSBpZl9lbHNlKHRvdGFsX3Jldl9oaV9saW0gPiA5NTAwMCwgMSwgMCwgbWlzc2luZyA9IDApDQogICkNCg0KDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwndG90YWxfcmV2X2hpX2xpbV9NaXNzaW5nJw0KICAsJ3RvdGFsX3Jldl9oaV9saW1fbGVzc181Jw0KICAsJ3RvdGFsX3Jldl9oaV9saW1fNV8xMCcNCiAgLCd0b3RhbF9yZXZfaGlfbGltXzEwXzIwJw0KICAsJ3RvdGFsX3Jldl9oaV9saW1fMjBfMzAnDQogICwndG90YWxfcmV2X2hpX2xpbV8zMF80MCcNCiAgLCd0b3RhbF9yZXZfaGlfbGltXzQwXzU1Jw0KICAsJ3RvdGFsX3Jldl9oaV9saW1fNTVfOTUnDQogICwndG90YWxfcmV2X2hpX2xpbV85NV9tb3JlJw0KKQ0KDQpsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzIDwtIGMoDQogIGxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMNCiAgLCd0b3RhbF9yZXZfaGlfbGltX01pc3NpbmcnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKmFubnVhbF9pbmMqIHdhcyBleHBsYWluZWQgaW4gY2hhcHRlciAzNiBvZiB0aGUgVWRlbXkgY291cnNlLg0KYGBge3IgYW5udWFsX2luYywgd2FybmluZz1GQUxTRX0NCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShhbm51YWxfaW5jX2N1dCA9IGN1dChhbm51YWxfaW5jLCA1MCkpDQoNCndvZV9hbm51YWxfaW5jX2N1dCA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICdhbm51YWxfaW5jX2N1dCcsIGRpc2NyZXRlID0gRkFMU0UpDQp3b2VfYW5udWFsX2luY19jdXQgJT4lIHNlbGVjdChhbm51YWxfaW5jX2N1dCwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfYW5udWFsX2luY19jdXQsIGRpc2NyZXRlID0gRkFMU0UsIHJvdGF0aW9uID0gOTApDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKGFubnVhbF9pbmNfbGVzc18yMCA9IGlmX2Vsc2UoYW5udWFsX2luYyA8IDIwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfMjBfMzAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gMjAwMDAgJiBhbm51YWxfaW5jIDw9IDMwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfMzBfNDAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gMzAwMDAgJiBhbm51YWxfaW5jIDw9IDQwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfNDBfNTAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gNDAwMDAgJiBhbm51YWxfaW5jIDw9IDUwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfNTBfNjAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gNTAwMDAgJiBhbm51YWxfaW5jIDw9IDYwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfNjBfNzAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gNjAwMDAgJiBhbm51YWxfaW5jIDw9IDcwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfNzBfODAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gNzAwMDAgJiBhbm51YWxfaW5jIDw9IDgwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfODBfOTAgPSBpZl9lbHNlKGFubnVhbF9pbmMgPj0gODAwMDAgJiBhbm51YWxfaW5jIDw9IDkwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfOTBfMTAwID0gaWZfZWxzZShhbm51YWxfaW5jID49IDkwMDAwICYgYW5udWFsX2luYyA8PSAxMDAwMDAsIDEsIDApDQogICAgICAgICAsYW5udWFsX2luY18xMDBfMTIwID0gaWZfZWxzZShhbm51YWxfaW5jID49IDEwMDAwMCAmIGFubnVhbF9pbmMgPD0gMTIwMDAwLCAxLCAwKQ0KICAgICAgICAgLGFubnVhbF9pbmNfMTIwXzE0MCA9IGlmX2Vsc2UoYW5udWFsX2luYyA+PSAxMjAwMDAgJiBhbm51YWxfaW5jIDw9IDE0MDAwMCwgMSwgMCkNCiAgICAgICAgICxhbm51YWxfaW5jXzE0MF9tb3JlID0gaWZfZWxzZShhbm51YWxfaW5jID4gMTQwMDAwLCAxLCAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnYW5udWFsX2luY19sZXNzXzIwJw0KICAsJ2FubnVhbF9pbmNfMjBfMzAnDQogICwnYW5udWFsX2luY18zMF80MCcNCiAgLCdhbm51YWxfaW5jXzQwXzUwJw0KICAsJ2FubnVhbF9pbmNfNTBfNjAnDQogICwnYW5udWFsX2luY182MF83MCcNCiAgLCdhbm51YWxfaW5jXzcwXzgwJw0KICAsJ2FubnVhbF9pbmNfODBfOTAnDQogICwnYW5udWFsX2luY185MF8xMDAnDQogICwnYW5udWFsX2luY18xMDBfMTIwJw0KICAsJ2FubnVhbF9pbmNfMTIwXzE0MCcNCiAgLCdhbm51YWxfaW5jXzE0MF9tb3JlJw0KKQ0KDQpsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzIDwtIGMoDQogIGxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMNCiAgLCdhbm51YWxfaW5jX2xlc3NfMjAnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKm10aHNfc2luY2VfbGFzdF9kZWxpbnEqIHdhcyBleHBsYWluZWQgaW4gY2hhcHRlciAzNiBvZiB0aGUgVWRlbXkgY291cnNlLg0KYGBge3IgbXRoc19zaW5jZV9sYXN0X2RlbGlucSwgd2FybmluZz1GQUxTRX0NCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShtdGhzX3NpbmNlX2xhc3RfZGVsaW5xX2N1dCA9IGN1dChtdGhzX3NpbmNlX2xhc3RfZGVsaW5xLCA1MCkpDQoNCndvZV9tdGhzX3NpbmNlX2xhc3RfZGVsaW5xX2N1dCA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICdtdGhzX3NpbmNlX2xhc3RfZGVsaW5xX2N1dCcsIGRpc2NyZXRlID0gRkFMU0UpDQp3b2VfbXRoc19zaW5jZV9sYXN0X2RlbGlucV9jdXQgJT4lIHNlbGVjdChtdGhzX3NpbmNlX2xhc3RfZGVsaW5xX2N1dCwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfbXRoc19zaW5jZV9sYXN0X2RlbGlucV9jdXQsIGRpc2NyZXRlID0gRkFMU0UsIHJvdGF0aW9uID0gOTApDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKG10aHNfc2luY2VfbGFzdF9kZWxpbnFfTWlzc2luZyA9IGlmX2Vsc2UoaXMubmEobXRoc19zaW5jZV9sYXN0X2RlbGlucSksIDEsIDApDQogICAgICAgICAsbXRoc19zaW5jZV9sYXN0X2RlbGlucV8wXzMgPSBpZl9lbHNlKG10aHNfc2luY2VfbGFzdF9kZWxpbnEgPj0gMCAmIG10aHNfc2luY2VfbGFzdF9kZWxpbnEgPD0gMywgMSwgMCwgbWlzc2luZyA9IDApDQogICAgICAgICAsbXRoc19zaW5jZV9sYXN0X2RlbGlucV80XzMwID0gaWZfZWxzZShtdGhzX3NpbmNlX2xhc3RfZGVsaW5xID49IDQgJiBtdGhzX3NpbmNlX2xhc3RfZGVsaW5xIDw9IDMwLCAxLCAwLCBtaXNzaW5nID0gMCkNCiAgICAgICAgICxtdGhzX3NpbmNlX2xhc3RfZGVsaW5xXzMxXzU2ID0gaWZfZWxzZShtdGhzX3NpbmNlX2xhc3RfZGVsaW5xID49IDMxICYgbXRoc19zaW5jZV9sYXN0X2RlbGlucSA8PSA1NiwgMSwgMCwgbWlzc2luZyA9IDApDQogICAgICAgICAsbXRoc19zaW5jZV9sYXN0X2RlbGlucV81Nl9tb3JlID0gaWZfZWxzZShtdGhzX3NpbmNlX2xhc3RfZGVsaW5xID4gNTYsIDEsIDAsIG1pc3NpbmcgPSAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnbXRoc19zaW5jZV9sYXN0X2RlbGlucV9NaXNzaW5nJw0KICAsJ210aHNfc2luY2VfbGFzdF9kZWxpbnFfMF8zJw0KICAsJ210aHNfc2luY2VfbGFzdF9kZWxpbnFfNF8zMCcNCiAgLCdtdGhzX3NpbmNlX2xhc3RfZGVsaW5xXzMxXzU2Jw0KICAsJ210aHNfc2luY2VfbGFzdF9kZWxpbnFfNTZfbW9yZScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwnbXRoc19zaW5jZV9sYXN0X2RlbGlucV9NaXNzaW5nJw0KKQ0KYGBgDQoNClByZXByb2Nlc3NpbmcgYXR0cmlidXRlICpkdGkqIGxlZnQgYXMgaG9tZXdvcmsgb2YgdGhlIFVkZW15IGNvdXJzZS4gDQpgYGB7ciBkdGksIHdhcm5pbmc9RkFMU0V9DQpkYXRhIDwtIGRhdGEgJT4lIA0KICBtdXRhdGUoZHRpX2N1dCA9IGN1dChkdGksIDUwKSkNCg0Kd29lX2R0aV9jdXQgPC0gd29lKGRhdGEsIHRyYWluX2luZGV4LCAnZHRpX2N1dCcsIGRpc2NyZXRlID0gRkFMU0UpDQp3b2VfZHRpX2N1dCAlPiUgc2VsZWN0KGR0aV9jdXQsIG5fb2JzLCBXb0UsIElWKQ0KcGxvdF9ieV93b2Uod29lX2R0aV9jdXQsIGRpc2NyZXRlID0gRkFMU0UsIHJvdGF0aW9uID0gOTApDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKGR0aV9sZXNzXzEuNCA9IGlmX2Vsc2UoZHRpIDwgMS40LCAxLCAwKQ0KICAgICAgICAgLGR0aV8xLjRfMy41ID0gaWZfZWxzZShkdGkgPj0gMS40ICYgZHRpIDw9IDMuNSwgMSwgMCkNCiAgICAgICAgICxkdGlfMy41XzcuNyA9IGlmX2Vsc2UoZHRpID49IDMuNSAmIGR0aSA8PSA3LjcsIDEsIDApDQogICAgICAgICAsZHRpXzcuN18xMC41ID0gaWZfZWxzZShkdGkgPj0gNy43ICYgZHRpIDw9IDEwLjUsIDEsIDApDQogICAgICAgICAsZHRpXzEwLjVfMTYuMSA9IGlmX2Vsc2UoZHRpID49IDEwLjUgJiBkdGkgPD0gMTYuMSwgMSwgMCkNCiAgICAgICAgICxkdGlfMTYuMV8yMC4zID0gaWZfZWxzZShkdGkgPj0gMTYuMSAmIGR0aSA8PSAyMC4zLCAxLCAwKQ0KICAgICAgICAgLGR0aV8yMC4zXzIxLjcgPSBpZl9lbHNlKGR0aSA+PSAyMC4zICYgZHRpIDw9IDIxLjcsIDEsIDApDQogICAgICAgICAsZHRpXzIxLjdfMjIuNCA9IGlmX2Vsc2UoZHRpID49IDIxLjcgJiBkdGkgPD0gMjIuNCwgMSwgMCkNCiAgICAgICAgICxkdGlfMjIuNF8zNSA9IGlmX2Vsc2UoZHRpID49IDIyLjQgJiBkdGkgPD0gMzUsIDEsIDApDQogICAgICAgICAsZHRpXzM1X21vcmUgPSBpZl9lbHNlKGR0aSA+IDM1LCAxLCAwKQ0KICApDQoNCmxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzIDwtIGMoDQogIGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzDQogICwnZHRpX2xlc3NfMS40Jw0KICAsJ2R0aV8xLjRfMy41Jw0KICAsJ2R0aV8zLjVfNy43Jw0KICAsJ2R0aV83LjdfMTAuNScNCiAgLCdkdGlfMTAuNV8xNi4xJw0KICAsJ2R0aV8xNi4xXzIwLjMnDQogICwnZHRpXzIwLjNfMjEuNycNCiAgLCdkdGlfMjEuN18yMi40Jw0KICAsJ2R0aV8yMi40XzM1Jw0KICAsJ2R0aV8zNV9tb3JlJw0KKQ0KDQpsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzIDwtIGMoDQogIGxpc3Rfb2ZfcmVmZXJlbmNlX2NhdGVnb3JpZXMNCiAgLCdkdGlfbGVzc18xLjQnDQopDQpgYGANCg0KUHJlcHJvY2Vzc2luZyBhdHRyaWJ1dGUgKm10aHNfc2luY2VfbGFzdF9yZWNvcmQqIHdhcyBsZWZ0IGFzIGhvbWV3b3JrIG9mIHRoZSBVZGVteSBjb3Vyc2UuIA0KYGBge3IgbXRoc19zaW5jZV9sYXN0X3JlY29yZCwgd2FybmluZz1GQUxTRX0NCmRhdGEgPC0gZGF0YSAlPiUgDQogIG11dGF0ZShtdGhzX3NpbmNlX2xhc3RfcmVjb3JkX2N1dCA9IGN1dChtdGhzX3NpbmNlX2xhc3RfcmVjb3JkLCA1MCkpDQoNCndvZV9tdGhzX3NpbmNlX2xhc3RfcmVjb3JkX2N1dCA8LSB3b2UoZGF0YSwgdHJhaW5faW5kZXgsICdtdGhzX3NpbmNlX2xhc3RfcmVjb3JkX2N1dCcsIGRpc2NyZXRlID0gRkFMU0UpDQp3b2VfbXRoc19zaW5jZV9sYXN0X3JlY29yZF9jdXQgJT4lIHNlbGVjdChtdGhzX3NpbmNlX2xhc3RfcmVjb3JkX2N1dCwgbl9vYnMsIFdvRSwgSVYpDQpwbG90X2J5X3dvZSh3b2VfbXRoc19zaW5jZV9sYXN0X3JlY29yZF9jdXQsIGRpc2NyZXRlID0gRkFMU0UsIHJvdGF0aW9uID0gOTApDQoNCmRhdGEgPC0gZGF0YSAlPiUNCiAgbXV0YXRlKG10aHNfc2luY2VfbGFzdF9yZWNvcmRfTWlzc2luZyA9IGlmX2Vsc2UoaXMubmEobXRoc19zaW5jZV9sYXN0X3JlY29yZCksIDEsIDApDQogICAgICAgICAsbXRoc19zaW5jZV9sYXN0X3JlY29yZF8wXzIgPSBpZl9lbHNlKG10aHNfc2luY2VfbGFzdF9yZWNvcmQgPj0gMCAmIG10aHNfc2luY2VfbGFzdF9yZWNvcmQgPD0gMiwgMSwgMCwgbWlzc2luZyA9IDApDQogICAgICAgICAsbXRoc19zaW5jZV9sYXN0X3JlY29yZF8zXzIwID0gaWZfZWxzZShtdGhzX3NpbmNlX2xhc3RfcmVjb3JkID49IDMgJiBtdGhzX3NpbmNlX2xhc3RfcmVjb3JkIDw9IDIwLCAxLCAwLCBtaXNzaW5nID0gMCkNCiAgICAgICAgICxtdGhzX3NpbmNlX2xhc3RfcmVjb3JkXzIxXzMxID0gaWZfZWxzZShtdGhzX3NpbmNlX2xhc3RfcmVjb3JkID49IDIxICYgbXRoc19zaW5jZV9sYXN0X3JlY29yZCA8PSAzMSwgMSwgMCwgbWlzc2luZyA9IDApDQogICAgICAgICAsbXRoc19zaW5jZV9sYXN0X3JlY29yZF8zMl84MCA9IGlmX2Vsc2UobXRoc19zaW5jZV9sYXN0X3JlY29yZCA+PSAzMiAmIG10aHNfc2luY2VfbGFzdF9yZWNvcmQgPD0gODAsIDEsIDAsIG1pc3NpbmcgPSAwKQ0KICAgICAgICAgLG10aHNfc2luY2VfbGFzdF9yZWNvcmRfODFfODYgPSBpZl9lbHNlKG10aHNfc2luY2VfbGFzdF9yZWNvcmQgPj0gODEgJiBtdGhzX3NpbmNlX2xhc3RfcmVjb3JkIDw9IDg2LCAxLCAwLCBtaXNzaW5nID0gMCkNCiAgICAgICAgICxtdGhzX3NpbmNlX2xhc3RfcmVjb3JkXzg2X21vcmUgPSBpZl9lbHNlKG10aHNfc2luY2VfbGFzdF9yZWNvcmQgPiA4NiwgMSwgMCwgbWlzc2luZyA9IDApDQogICkNCg0KbGlzdF9vZl9kdW1teV92YXJpYWJsZXMgPC0gYygNCiAgbGlzdF9vZl9kdW1teV92YXJpYWJsZXMNCiAgLCdtdGhzX3NpbmNlX2xhc3RfcmVjb3JkX01pc3NpbmcnDQogICwnbXRoc19zaW5jZV9sYXN0X3JlY29yZF8wXzInDQogICwnbXRoc19zaW5jZV9sYXN0X3JlY29yZF8zXzIwJw0KICAsJ210aHNfc2luY2VfbGFzdF9yZWNvcmRfMjFfMzEnDQogICwnbXRoc19zaW5jZV9sYXN0X3JlY29yZF8zMl84MCcNCiAgLCdtdGhzX3NpbmNlX2xhc3RfcmVjb3JkXzgxXzg2Jw0KICAsJ210aHNfc2luY2VfbGFzdF9yZWNvcmRfODZfbW9yZScNCikNCg0KbGlzdF9vZl9yZWZlcmVuY2VfY2F0ZWdvcmllcyA8LSBjKA0KICBsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzDQogICwnbXRoc19zaW5jZV9sYXN0X3JlY29yZF9NaXNzaW5nJw0KKQ0KYGBgDQoNCmBgYHtyIHdyaXRlfQ0Kd3JpdGUuY3N2KGxpc3Rfb2ZfZHVtbXlfdmFyaWFibGVzLCAncGRfZHVtbWllcy5jc3YnLCByb3cubmFtZXMgPSBGQUxTRSkNCndyaXRlLmNzdihsaXN0X29mX3JlZmVyZW5jZV9jYXRlZ29yaWVzLCAncGRfZHVtbWllc19yZWZlcmVuY2UuY3N2Jywgcm93Lm5hbWVzID0gRkFMU0UpDQoNCndyaXRlLmNzdihkYXRhLCAncGRfcHJlcHJvY2Vzc2VkX2xvYW5fZGF0YV8yMDA3XzIwMTQuY3N2Jywgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0K