Introduction and Context
The Business Problem
Employee turnover (also known as Employee Attrition) is one
of the greatest challenges faced by organisations—and one of the most
financially costly.
Studies indicate that the cost of replacing an employee can range from
50% to 200% of their annual salary, considering
recruitment, training, and productivity loss expenses.
Beyond the financial impact, a high turnover rate affects
team morale, company culture, and project continuity.
Therefore, the ability to predict who is at risk of
leaving and, more importantly, why, represents a
crucial competitive advantage for the Human Resources (HR)
department.
About the Dataset
This project uses the dataset “IBM HR Analytics Employee
Attrition & Performance”, publicly available on
Kaggle.
The dataset was created by IBM data scientists and, although synthetic,
accurately reflects the real challenges of corporate environments.
It contains 1,470 observations (employees) and
35 variables (features).
Variable Dictionary
Our target variable is Attrition, which
indicates whether the employee left (“Yes”) or
remained (“No”) in the company.
The remaining variables can be grouped into three main categories
explored throughout the analysis:
- Demographic:
Age, Gender,
MaritalStatus, DistanceFromHome
- Work-related:
Department,
JobRole, JobLevel, OverTime,
BusinessTravel
- Compensation and Satisfaction:
MonthlyIncome, PercentSalaryHike,
StockOptionLevel, JobSatisfaction,
EnvironmentSatisfaction
For readability, only the most relevant variables are listed
above.
A complete dictionary of all 35 variables and their data types is
presented in the technical data inspection section.
Project Objectives
The core objective of this project is to develop a People
Analytics solution capable of anticipating employee attrition
and providing management with data‑driven retention
strategies.
To achieve that, the analysis follows three vertical pillars:
- Root‑Cause Diagnosis – Quantify the true impact of
risk factors, testing the hypothesis that workload
(
OverTime) and commuting distance
(DistanceFromHome) act as catalysts for
burnout.
- Retention Hierarchy – Determine, using Machine
Learning algorithms, which factors weigh more in the decision to leave:
financial incentives (
MonthlyIncome) or intangible elements
such as job satisfaction.
- Predictive Modeling – Train classification
algorithms (Logistic Regression and Random Forest) to identify at‑risk
employees with high precision, enabling preventive HR action.
Data Import and Initial Inspection
# Data Import
# Read the original file
ibm_hr <- read.csv("data/WA_Fn-UseC_-HR-Employee-Attrition.csv", sep = ";")
library(janitor)
library(dplyr)
# Data Cleaning and Standardization
# Here we create the object 'ibm_clean'
ibm_clean <- ibm_hr %>%
clean_names() %>%
# Remove columns with no variability
select(-any_of(c("employee_count", "over18", "standard_hours", "employee_number")))
# Visualization (kable)
library(kableExtra)
ibm_clean %>%
select(age, attrition, monthly_income, job_role, over_time, total_working_years) %>%
head(10) %>%
kable(caption = "Table 1: Sample of Key Variables for Attrition Analysis") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE,
position = "center"
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50")
Table 1: Sample of Key Variables for Attrition Analysis
|
age
|
attrition
|
monthly_income
|
job_role
|
over_time
|
total_working_years
|
|
41
|
Yes
|
5993
|
Sales Executive
|
Yes
|
8
|
|
49
|
No
|
5130
|
Research Scientist
|
No
|
10
|
|
37
|
Yes
|
2090
|
Laboratory Technician
|
Yes
|
7
|
|
33
|
No
|
2909
|
Research Scientist
|
Yes
|
8
|
|
27
|
No
|
3468
|
Laboratory Technician
|
No
|
6
|
|
32
|
No
|
3068
|
Laboratory Technician
|
No
|
8
|
|
59
|
No
|
2670
|
Laboratory Technician
|
Yes
|
12
|
|
30
|
No
|
2693
|
Laboratory Technician
|
No
|
1
|
|
38
|
No
|
9526
|
Manufacturing Director
|
No
|
10
|
|
36
|
No
|
5237
|
Healthcare Representative
|
No
|
17
|
The dataset consists of 35 variables covering three
main dimensions: demographic characteristics,
financial factors, and performance
indicators.
At this initial stage, the analysis focuses on variables with the
highest explanatory potential for employee attrition,
namely monthly income, total years of
experience in the company, and overtime
work.
Empirical evidence and preliminary analyses suggest a significant
relationship between these factors and the probability of
employee departure, establishing them as fundamental starting
points for deeper analytical exploration.
Exploratory Data Analysis (EDA)
The main goal of this phase is to understand the distribution of the
variables and identify patterns or relationships that may explain the
phenomenon of employee turnover (employee
attrition).
The exploration begins with the target variable,
Attrition, which indicates whether the employee
remained with the company (No) or
chose to leave (Yes).
Analysing this variable provides an initial understanding of the
balance between active employees and those who left the organisation,
helping assess the real magnitude of the attrition phenomenon.
Target Variable Analysis (Attrition)
How many employees actually left the company?
# Create Frequency Table for the Target Variable
tabela_target <- ibm_clean %>%
count(attrition) %>%
mutate(
percentage = (n / sum(n)) * 100,
attrition = ifelse(attrition == "Yes", "Left (Yes)", "Stayed (No)")
)
# Display Table with kableExtra
tabela_target %>%
kable(
caption = "Distribution of the Target Variable (Attrition)",
col.names = c("Status", "Total (n)", "Percentage (%)"),
digits = 1
) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50") %>%
column_spec(3, bold = TRUE, color = ifelse(tabela_target$percentage < 20, "#e74c3c", "#2c3e50"))
Distribution of the Target Variable (Attrition)
|
Status
|
Total (n)
|
Percentage (%)
|
|
Stayed (No)
|
1233
|
83.9
|
|
Left (Yes)
|
237
|
16.1
|
# Visualization
ggplot(ibm_clean, aes(x = attrition, fill = attrition)) +
geom_bar(width = 0.6, alpha = 0.9) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
labs(
title = "Overview of Employee Turnover",
subtitle = "Only 16% of employees left the organisation during the analysed period",
x = "Attrition Decision",
y = "Number of Employees"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
panel.grid.major.x = element_blank()
)
Initial Insight:
The attrition rate is approximately
16%, indicating that the majority of employees (around
84%) remained with the company during the analysed
period.
This shows a clear class imbalance in the target
variable, with a predominance of employees who did not leave the
organisation.
This point is particularly important for the later stages of
predictive modelling, as the class disproportion may
lead the model to overfit the majority class (employees
who stay) and underestimate the minority cases
(employees who leave), which are precisely the most valuable to
understand and predict.
Demographic Analysis: Does Age Matter?
Next, we analyse the distribution of employee ages between those who
left and those who stayed.
A boxplot is used to visualise the median and data dispersion.
# Plot: Age Distribution by Attrition
ggplot(ibm_clean, aes(x = attrition, y = age, fill = attrition)) +
geom_jitter(alpha = 0.2, color = "grey40", width = 0.2) +
geom_boxplot(alpha = 0.8, outlier.colour = "red", width = 0.5) +
# Colors consistent with the rest of the report
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "The Age Factor in Talent Retention",
subtitle = "Employees who leave (Yes) show a visibly lower median age",
x = "Attrition Decision",
y = "Age (Years)"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
panel.grid.major.x = element_blank(),
axis.title = element_text(face = "bold")
)

Insights on Age:
The boxplot analysis reveals a clear pattern in the relationship
between age and employee
attrition:
Youth Factor – There is a tendency for younger
employees to show a higher propensity to leave the
company. The median age of those who leave is visibly lower
than that of those who stay.
Risk Zone – The highest concentration of
departures occurs between 25 and 35 years old, a range
commonly associated with career mobility and the
search for advancement opportunities. This behaviour
may reflect challenges faced by the organisation in retaining
young talent or providing structured development
pathways.
Senior Stability – Employees over 40
years old demonstrate greater stability and a
lower probability of leaving. The few cases in this age
group appear as outliers in the plot, suggesting isolated
departures (e.g., retirement, personal relocation, or internal
restructuring).
Conclusion:
The findings highlight the need for a segmented retention
strategy:
- Junior and mid‑level employees (25–35 years old)
should be targeted with initiatives focused on engagement,
internal mobility, and career‑growth management.
- For senior employees, emphasis should be placed on
recognition, mentorship, and knowledge transfer, reinforcing a sense of
belonging and organisational continuity.
# Bar Chart: Attrition Proportion by Marital Status
ggplot(ibm_clean, aes(x = marital_status, fill = attrition)) +
geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
# Format Y-axis as percentage
scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
labs(
title = "Impact of Marital Status on Retention",
subtitle = "Single employees show a significantly higher attrition rate",
x = "Marital Status",
y = "Proportion of Employees",
fill = "Left?"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
legend.position = "top",
panel.grid.major.x = element_blank(),
axis.text.x = element_text(face = "bold")
)

Insights on Marital Status:
The analysis suggests that marital status is a
significant factor influencing employee attrition:
Higher risk among single employees – Single
employees display an attrition rate above 25%, more
than double that of married or divorced employees (approximately 11%).
This indicates a strong association between marital status and the
probability of leaving the company.
Potential behavioural explanation – This pattern
aligns with empirical evidence in human resources research, which shows
that professionals without dependants or family commitments tend to
exhibit greater job mobility. Their
geographical and financial flexibility facilitates the
pursuit of new opportunities or acceptance of offers in different
locations.
Conclusion:
Talent management strategies may benefit from differentiated
retention approaches across employee groups, for instance,
designing career‑progression initiatives and
engagement programmes to strengthen the commitment of
younger, single employees to the organisation.
Professional Analysis: Workload and Business Travel
Could excessive workload (OverTime) and frequent travel
(BusinessTravel) lead to fatigue and increased
attrition?
# Plot: Overtime Hours (p1)
p1 <- ggplot(ibm_clean, aes(x = over_time, fill = attrition)) +
geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Impact of Overtime Hours",
x = "Works Overtime?",
y = "Proportion"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
panel.grid.major.x = element_blank()
)
# Plot: Business Travel (p2)
p2 <- ggplot(ibm_clean, aes(x = business_travel, fill = attrition)) +
geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Impact of Business Travel",
x = "Travel Frequency",
y = NULL,
fill = "Left?"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
axis.text.x = element_text(angle = 45, hjust = 1),
panel.grid.major.x = element_blank()
)
# Combine both visualizations
library(gridExtra)
grid.arrange(
p1, p2, ncol = 2,
top = grid::textGrob(
"Workload and Mobility Analysis",
gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")
)
)

Insights on Workload and Lifestyle:
The analysis of workload and professional mobility reveals a clear
association between exhaustion and employee
attrition:
Impact of Overtime Hours – The effect of
overtime work is particularly striking. Employees who do
not work overtime show an attrition rate close to
10%, while among those who regularly exceed their
working hours, this rate triples to around 30%.
This result serves as a clear indicator of burnout
risk and suggests that excessive workload may be linked to
dissatisfaction and emotional fatigue.
The Weight of Mobility
(BusinessTravel) – There is a visible upward trend between
travel frequency and attrition
probability:
- Employees who do not travel
(
Non‑Travel) show the lowest attrition rate
(<10%);
- Those who travel frequently
(
Travel_Frequently) face a risk close to
25%, indicating that their work‑life
balance is substantially compromised.
Conclusion:
Both work overload and excessive
mobility emerge as relevant risk factors for talent
retention.
Organisational policies that promote healthy working‑hour
limits, flexibility, and work‑life
balance can significantly mitigate this type of turnover.
Financial Analysis: Does Salary Matter?
The distribution of monthly income (MonthlyIncome) was
analysed to determine whether lower salaries contribute to higher
attrition.
# Density Plot: Monthly Income by Attrition
ggplot(ibm_clean, aes(x = monthly_income, fill = attrition)) +
geom_density(alpha = 0.7, color = "white") +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
# Format X-axis as Currency (USD)
scale_x_continuous(labels = scales::dollar_format(), breaks = seq(0, 20000, 2500)) +
labs(
title = "Salary Distribution and Attrition Risk",
subtitle = "The probability of leaving is drastically higher for salary ranges below $5,000",
x = "Monthly Salary (USD)",
y = "Employee Density",
fill = "Attrition Status"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
legend.position = "top",
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank()
)

Financial Insights:
The analysis of salary distribution reveals that compensation
is a decisive factor in the likelihood of employee attrition,
showing a markedly distinct pattern across income ranges:
The $5,000 Threshold – There is a significant
concentration of departures among employees with monthly salaries below
$5,000. In this range, the density of attrition cases is substantially
higher, suggesting that lower income levels are associated with greater
workforce volatility.
Retention at Higher Salary Levels – As salary
increases (particularly above $10,000), the probability of leaving drops
sharply. Among higher‑earning employees, the density curve associated
with “staying” clearly dominates, indicating greater stability and
professional satisfaction.
Conclusion:
The observed pattern suggests that the company faces greater retention
challenges among operational and junior‑level
employees, where compensation may not fully meet market
expectations.
More competitive pay strategies, complemented by
career‑development and internal advancement plans,
could be decisive in reducing attrition within these salary groups.
Job Function and Satisfaction Analysis
Before proceeding to the numerical correlations, it is important to
analyse two key categorical variables: Job Role
(JobRole) and Job Satisfaction
(JobSatisfaction).
The goal is to determine whether specific job roles exhibit higher
attrition rates.
# Turnover by Job Role
p_role <- ggplot(ibm_clean, aes(y = reorder(job_role, (attrition == "Yes")), fill = attrition)) +
geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
scale_x_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Turnover by Job Role",
subtitle = "Sales, HR, and Laboratory Technicians show higher risk",
y = NULL,
x = "Proportion of Attrition"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
panel.grid.major.y = element_blank(),
axis.text.y = element_text(size = 9, face = "bold")
)
# Impact of Job Satisfaction
p_sat <- ggplot(ibm_clean, aes(x = factor(job_satisfaction), fill = attrition)) +
geom_bar(position = "fill", width = 0.6, alpha = 0.9) +
scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Impact of Job Satisfaction",
subtitle = "Low satisfaction levels (1 and 2) correlate with higher churn",
x = "Satisfaction Level (1: Low → 4: High)",
y = "Proportion",
fill = "Left?"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
legend.position = "right",
panel.grid.major.x = element_blank()
)
library(gridExtra)
grid.arrange(p_role, p_sat, nrow = 2,
top = grid::textGrob("Job Role and Sentiment Analysis",
gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights on Job Role and Satisfaction:
The analysis reveals distinct attrition patterns by job
function, highlighting critical areas within the
organisation:
Sales Roles (Sales Representatives) –
This group shows the highest attrition rate, around
40%, which suggests high commercial pressure,
demanding targets, or unattractive incentive
structures. Given their strategic importance to the company’s
overall performance, this group should be treated as a top
priority for retention initiatives.
Laboratory Technicians and Human Resources –
Both functions show attrition rates around 25%, clearly
above the organisational average.
Leadership Retention – Managerial and executive
roles (Managers and Directors) demonstrate
very high stability, suggesting that turnover is mainly
concentrated at mid‑level and operational
positions.
This pattern emphasises the importance of designing retention
and development strategies specifically targeted at the most vulnerable
roles.
Conclusion:
Attrition appears to be concentrated in entry‑level and
operational support roles, requiring policies oriented toward
improving the organisational climate, reviewing
incentive systems, and expanding career‑growth
opportunities in order to strengthen commitment and retention
within these groups.
Tenure and Commute Time Analysis
Employee tenure (YearsAtCompany) and commuting distance
(DistanceFromHome) were analysed to assess whether the
company loses recently hired talent and whether daily commuting
influences the decision to leave.
# Plot: Tenure (Years at the Company)
p_years <- ggplot(ibm_clean, aes(x = years_at_company, fill = attrition)) +
geom_density(alpha = 0.7, color = "white") +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Life Cycle: Employee Tenure",
subtitle = "Churn risk is critical within the first 2 years (onboarding period)",
x = "Years at Company",
y = "Density"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
panel.grid.minor = element_blank()
)
# Plot: Distance from Home (Boxplot)
p_dist <- ggplot(ibm_clean, aes(x = attrition, y = distance_from_home, fill = attrition)) +
geom_boxplot(alpha = 0.8, width = 0.6, outlier.colour = "#E74C3C") +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Logistics: Home-to-Work Distance",
subtitle = "Employees who leave tend to travel longer distances",
x = "Attrition Decision",
y = "Distance (km/miles)"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
panel.grid.major.x = element_blank()
)
# Arrange both plots
library(gridExtra)
grid.arrange(p_years, p_dist, nrow = 2,
top = grid::textGrob("Retention and Logistics Analysis",
gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights on Tenure and Logistics:
The analysis highlights critical points in the employee life
cycle, with direct implications for organisational retention
and performance:
Onboarding Phase – Early Exit Risk:
The tenure plot shows a sharp peak in attrition within the first two
years of employment, precisely during the integration and adaptation
period.
This result suggests weaknesses in onboarding processes, early
supervision, or alignment of expectations between the employee and the
organisation. Investing in structured onboarding and mentorship
programmes can substantially reduce this type of premature
talent loss.
Commuting Cost – A Logistical Strain
Factor:
The home‑to‑work distance boxplot reveals that employees who leave tend
to commute longer distances, signalling a potential negative impact of
travel time and effort on overall satisfaction.
The wear and tear associated with daily commuting — especially when
combined with heavy workloads — increases the probability of voluntary
turnover. Measures such as hybrid work models,
flexible scheduling, or transport
incentives can help mitigate this effect.
Conclusion:
Effective retention requires a holistic approach that
addresses both the initial employee experience
(onboarding) and the logistical sustainability
of their work routine.
These two dimensions are crucial for consolidating organisational
commitment during the early years of tenure.
Gender and Work-Life Balance Analysis
# Turnover by Gender (p_gen)
p_gen <- ggplot(ibm_clean, aes(x = gender, fill = attrition)) +
geom_bar(position = "fill", width = 0.6, alpha = 0.9) +
scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Turnover by Gender",
subtitle = "Is there a disparity between men and women?",
x = NULL,
y = "Proportion"
) +
theme_minimal() +
theme(
legend.position = "none", # Hide legend here to avoid repetition
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
panel.grid.major.x = element_blank(),
axis.text.x = element_text(face = "bold")
)
# Work-Life Balance Analysis (p_wlb)
p_wlb <- ggplot(ibm_clean, aes(x = factor(work_life_balance), fill = attrition)) +
geom_bar(position = "fill", width = 0.6, alpha = 0.9) +
scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) +
scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
labs(
title = "Work-Life Balance",
subtitle = "The impact of work-life balance on attrition decisions",
x = "Level (1: Poor → 4: Excellent)",
y = NULL,
fill = "Left?"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
legend.position = "right",
panel.grid.major.x = element_blank(),
axis.text.x = element_text(face = "bold")
)
# Arrange both side by side
library(gridExtra)
grid.arrange(p_gen, p_wlb, ncol = 2,
top = grid::textGrob("Well-Being and Diversity",
gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights on Gender and Well-Being:
To conclude the bivariate analysis, two social and
behavioural factors stand out as relevant to employee
attrition:
Gender Neutrality – The attrition rate appears
relatively uniform between men and women, ranging from
15% to 17%. This result suggests the absence of bias or
discriminatory practices associated with gender and indicates
equitable organisational experiences across
groups.
Work-Life Balance – The Work‑Life
Balance variable exhibits a “critical point” at the lowest
satisfaction level. Employees who rate their balance as “Poor” (Level 1)
show an attrition rate near 30%,
double that observed in the other levels.
Improving work‑life balance even marginally — for example, from Level 1
to Level 2 — produces a substantial reduction in turnover rates.
This indicates that targeted and realistic
interventions, such as flexible schedules, hybrid‑work
policies, or enhanced team support, can have immediate positive
effects on retention, without necessarily achieving ideal
satisfaction levels (Level 4).
Conclusion:
The findings indicate a gender‑balanced organisational
culture, yet one that remains vulnerable to well‑being
and work‑life balance factors.
Investment in occupational health,
flexible‑work arrangements, and employee‑care
initiatives will likely yield direct returns in terms of
employee satisfaction and retention.
Multivariate Analysis (Correlations)
At this stage, the relationships between numerical variables were
examined to identify multicollinearity
(redundancy).
A visual correlation matrix was used for this
purpose.
ibm_numeric <- ibm_clean %>% select(where(is.numeric))
cor_matrix <- cor(ibm_numeric, use = "complete.obs")
# Correlation Plot
color_palette <- colorRampPalette(c("#E74C3C", "#FFFFFF", "#2C3E50"))(200)
corrplot(cor_matrix,
method = "color",
type = "upper",
order = "hclust",
tl.col = "black",
tl.cex = 0.7,
col = color_palette,
title = "\n Intervariable Correlation Map",
mar = c(0, 0, 2, 0),
diag = FALSE)

# Correlation Table
cor_table <- as.data.frame(as.table(cor_matrix))
cor_table_refined <- cor_table %>%
filter(Var1 != Var2) %>%
filter(!duplicated(paste0(
pmax(as.character(Var1), as.character(Var2)),
pmin(as.character(Var1), as.character(Var2))
))) %>%
arrange(desc(abs(Freq))) %>%
rename(Variable_1 = Var1, Variable_2 = Var2, Correlation = Freq)
# Improve Table Design
kable(head(cor_table_refined, 10),
caption = "Top 10 Strongest Correlations Identified",
digits = 2,
col.names = c("Variable 1", "Variable 2", "Correlation Strength")) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE,
position = "center",
font_size = 14
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50") %>%
# Highlight in red correlations that may cause multicollinearity (> 0.7)
column_spec(3, bold = TRUE,
color = ifelse(abs(head(cor_table_refined$Correlation, 10)) > 0.7, "#E74C3C", "black"))
Top 10 Strongest Correlations Identified
|
Variable 1
|
Variable 2
|
Correlation Strength
|
|
monthly_income
|
job_level
|
0.95
|
|
total_working_years
|
job_level
|
0.78
|
|
performance_rating
|
percent_salary_hike
|
0.77
|
|
total_working_years
|
monthly_income
|
0.77
|
|
years_with_curr_manager
|
years_at_company
|
0.77
|
|
years_in_current_role
|
years_at_company
|
0.76
|
|
years_with_curr_manager
|
years_in_current_role
|
0.71
|
|
total_working_years
|
age
|
0.68
|
|
years_at_company
|
total_working_years
|
0.63
|
|
years_since_last_promotion
|
years_at_company
|
0.62
|
Insights from the Correlation Analysis:
The correlation matrix and table reveal clear patterns of
multicollinearity, exposing variables that are
strongly redundant and will require specific treatment
during the data preprocessing stage:
Redundancy between salary and job level – The
strongest correlation in the dataset is observed between
MonthlyIncome and JobLevel (r = 0.95).
Interpretation: These variables are, in practice,
statistically overlapping — the job level almost entirely dictates the
salary.
Keeping both in the model may introduce coefficient instability and
distort the predictive importance of features. It is therefore advisable
to retain only one representative variable (e.g.,
JobLevel).
Tenure cluster – A cluster of highly correlated
time‑related variables was identified: YearsAtCompany,
YearsInCurrentRole, and YearsWithCurrManager,
with correlations ranging between 0.71 and 0.77.
Interpretation: Employees with longer tenure tend to
remain in the same role under the same manager. To avoid redundancy, it
is preferable to include only one of these variables (e.g.,
YearsAtCompany) or create an aggregated “career
stagnation” variable to capture this dynamic.
Professional experience and compensation – The
variable TotalWorkingYears shows strong correlations with
both JobLevel (0.78) and MonthlyIncome
(0.77).
Interpretation: The company’s progression and
compensation system appears to be highly aligned with
seniority, valuing primarily accumulated experience.
Performance and rewards – The correlation of
0.77 between PerformanceRating and
PercentSalaryHike confirms that salary increases are
directly linked to annual performance evaluation,
reflecting a typical meritocratic policy.
Conclusion of the Exploratory Data Analysis
(EDA):
The bivariate and correlation analyses indicate that employee
attrition is associated with demographic and job‑related
factors (younger age, operational roles, frequent travel, and
lower salaries).
At the technical level, strong relationships were found among variables
related to hierarchy, tenure, and remuneration, which
will need to be handled in preprocessing.
These findings establish the foundation for the data
preprocessing phase, where excessive correlations will be
addressed and the most relevant variables selected for
predictive modelling.
Data Preprocessing
Feature Selection
# Execute Feature Selection
ibm_prep <- ibm_clean %>%
select(-job_level) %>%
select(-any_of(c("employee_number", "employee_count", "over18", "standard_hours"))) %>%
mutate(attrition = ifelse(attrition == "Yes", 1, 0))
# Create Summary Table
prep_summary <- data.frame(
Step = c("Original Columns", "Columns Removed", "Final Total", "Target (Attrition)"),
Value = c(ncol(ibm_clean),
ncol(ibm_clean) - ncol(ibm_prep),
ncol(ibm_prep),
"Converted to Binary (0/1)")
)
prep_summary %>%
kable(caption = "Summary of Preprocessing and Feature Selection") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50")
Summary of Preprocessing and Feature Selection
|
Step
|
Value
|
|
Original Columns
|
31
|
|
Columns Removed
|
1
|
|
Final Total
|
30
|
|
Target (Attrition)
|
Converted to Binary (0/1)
|
After the exploratory analysis phase, the data were prepared for
predictive modelling.
This stage is essential to ensure that the resulting model is not
influenced by statistical noise or redundant
information, thus guaranteeing both robustness
and interpretability of results.
Key decisions in this phase:
Elimination of redundancy (multicollinearity) –
As identified in the correlation matrix, the variables
monthly_income and job_level showed a strong
correlation of 0.95.
To avoid overfitting and simplify the model, only the
most representative variable was retained, prioritising direct financial
impact.
Conversion of the target variable – The variable
attrition was transformed into a binary format
(0/1), allowing supervised classification algorithms to be
applied and simplifying the evaluation of predictive
performance.
These operations ensure that the final dataset is
statistically balanced, computationally
efficient, and ready for the next stage of
modelling.
Dummy Variable Creation
library(fastDummies)
ibm_final <- dummy_cols(ibm_prep,
remove_first_dummy = TRUE,
remove_selected_columns = TRUE) %>%
clean_names() # Ensures the new column names are standardised
# Create a visual comparison
dim_comparison <- data.frame(
Metric = c("Columns Before Dummies", "Columns After Dummies (Expanded)", "New Variables Created"),
Quantity = c(ncol(ibm_prep), ncol(ibm_final), ncol(ibm_final) - ncol(ibm_prep))
)
# Display impact table
dim_comparison %>%
kable(caption = "Impact of Categorical Variable Transformation (One-Hot Encoding)") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50")
Impact of Categorical Variable Transformation (One-Hot Encoding)
|
Metric
|
Quantity
|
|
Columns Before Dummies
|
30
|
|
Columns After Dummies (Expanded)
|
44
|
|
New Variables Created
|
14
|
# Show examples of new columns
data.frame(New_Columns_Examples = colnames(ibm_final)[(ncol(ibm_prep)+1):(ncol(ibm_prep)+6)]) %>%
kable() %>%
kable_styling(bootstrap_options = "bordered", full_width = FALSE, position = "float_right")
|
New_Columns_Examples
|
|
education_field_other
|
|
education_field_technical_degree
|
|
gender_male
|
|
job_role_human_resources
|
|
job_role_laboratory_technician
|
|
job_role_manager
|
Most Machine Learning algorithms are not able to process
textual variables directly.
To overcome this limitation, the One‑Hot Encoding
technique (also known as the creation of dummy variables) was
applied.
Procedures performed:
Transformation of categorical variables –
Qualitative variables such as BusinessTravel and
Department were converted into multiple binary columns
(0/1), representing the presence or absence of each distinct
category.
Prevention of multicollinearity – To avoid the
so‑called dummy variable trap, the parameter
remove_first_dummy = TRUE was activated, removing one
category from each group.
For example, in a variable with the modalities Male and
Female, only one is retained since the absence of one
automatically implies the presence of the other.
Controlled dataset expansion – After the
process, the total number of variables increased from 30 to 44,
resulting in 14 newly created derived variables.
This expansion allows for a richer representation of qualitative
information without introducing redundancy or
compromising the stability of predictive models.
Data Splitting (Training and Testing)
library(caTools)
library(dplyr)
library(kableExtra)
# Stratified Split
set.seed(123)
split <- sample.split(ibm_final$attrition, SplitRatio = 0.70)
train_data <- subset(ibm_final, split == TRUE)
test_data <- subset(ibm_final, split == FALSE)
# Create Summary Table
split_summary <- data.frame(
Dataset = c("Training (70%)", "Testing (30%)", "Total"),
Observations = c(nrow(train_data), nrow(test_data), nrow(ibm_final)),
Attrition_Rate = c(
paste0(round(mean(train_data$attrition) * 100, 1), "%"),
paste0(round(mean(test_data$attrition) * 100, 1), "%"),
paste0(round(mean(ibm_final$attrition) * 100, 1), "%")
)
)
# Display Table
split_summary %>%
kable(caption = "Data Split: Consistency and Stratification Check") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE,
position = "center"
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50") %>%
column_spec(3, bold = TRUE, color = "#E74C3C")
Data Split: Consistency and Stratification Check
|
Dataset
|
Observations
|
Attrition_Rate
|
|
Training (70%)
|
1029
|
16.1%
|
|
Testing (30%)
|
441
|
16.1%
|
|
Total
|
1470
|
16.1%
|
The dataset was divided using a stratified sampling
approach, ensuring that the proportion of the target variable
(Attrition) was maintained across both subsets —
Training (70%) and Testing (30%).
As shown in the table, the churn rate remains
perfectly consistent at 16.1% in both sets.
This statistical consistency is essential to prevent sampling
distortion, ensuring that the test set functions as a
representative replica of the original dataset.
Consequently, the performance metrics obtained during the validation
phase realistically and reliably reflect the behaviour of the attrition
phenomenon within the organisation, increasing the credibility
and generalisability of the model results.
Class Balancing
library(ROSE)
library(ggplot2)
library(gridExtra)
# Apply ROSE to balance only the TRAINING set
set.seed(123)
train_balanced <- ROSE(attrition ~ ., data = train_data, seed = 123)$data
# Create data for the comparative plot
before <- as.data.frame(table(train_data$attrition))
before$Status <- "1. Before (Unbalanced)"
after <- as.data.frame(table(train_balanced$attrition))
after$Status <- "2. After (Balanced with ROSE)"
comparison <- rbind(before, after)
# Plot
ggplot(comparison, aes(x = Var1, y = Freq, fill = Var1)) +
geom_bar(stat = "identity", width = 0.6, alpha = 0.9) +
facet_wrap(~Status) +
scale_fill_manual(values = c("0" = "#2C3E50", "1" = "#E74C3C")) +
scale_y_continuous(expand = c(0, 0), limits = c(0, max(comparison$Freq) * 1.1)) +
labs(
title = "Data Rebalancing Strategy (ROSE)",
subtitle = "Adjustment of the minority class to optimise model learning",
x = "Attrition Status (0 = No, 1 = Yes)",
y = "Number of Records"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 14, color = "#2c3e50"),
strip.text = element_text(face = "bold", size = 11),
panel.grid.major.x = element_blank()
)

The effectiveness of a predictive model depends heavily on the
quality and statistical balance of the
training data.
As identified earlier, the target variable (Attrition)
shows a marked class imbalance, with only 16.1%
of positive cases (employees who left the company).
In real-world contexts, such asymmetry often leads the model to
favour predicting retention while
underestimating churn cases.
To address this issue, the ROSE algorithm (Random
Over‑Sampling Examples) was applied exclusively to the training
dataset.
This technique generates synthetic observations based on the
distribution of the minority class, preserving the statistical
integrity of the original dataset.
Main advantages of rebalancing:
- Levelled learning – The model becomes exposed to a
balanced distribution (approximately 50/50) between employees who stay
and those who leave, improving its generalisation capability.
- Improved sensitivity (recall) – Increases
the ability of the model to correctly identify departures, allowing
early detection of potential talent losses.
- Preservation of test integrity – The rebalancing
process was applied only to the training data, leaving the test set
unchanged.
Machine Learning
Model 1: Logistic Regression
# Train the Model
logistic_model <- glm(attrition ~ ., data = train_balanced, family = "binomial")
# Make Predictions
predicted_prob <- predict(logistic_model, newdata = test_data, type = "response")
predicted_class <- ifelse(predicted_prob > 0.50, 1, 0)
# Create Confusion Matrix
conf_matrix <- table(Actual = test_data$attrition, Predicted = predicted_class)
df_confusion <- as.data.frame(conf_matrix)
# Confusion Matrix Plot (Heatmap)
library(ggplot2)
ggplot(df_confusion, aes(x = Predicted, y = Actual, fill = Freq)) +
geom_tile(color = "white") +
geom_text(aes(label = Freq), color = "white", size = 8, fontface = "bold") +
scale_fill_gradient(low = "#34495E", high = "#E74C3C") +
labs(
title = "Confusion Matrix: Logistic Regression",
subtitle = "Visualisation of Correct and Incorrect Predictions",
x = "Model Prediction (0 = Stay, 1 = Leave)",
y = "Actual Outcome (0 = Stay, 1 = Leave)"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 16),
axis.title = element_text(face = "bold")
)

# Metrics Table
accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
recall <- conf_matrix[2, 2] / sum(conf_matrix[2, ])
metrics <- data.frame(
Metric = c("Overall Accuracy", "Sensitivity (Recall)"),
Result = c(paste0(round(accuracy * 100, 2), "%"),
paste0(round(recall * 100, 2), "%"))
)
library(kableExtra)
metrics %>%
kable(caption = "Model 1 Performance") %>%
kable_styling(
bootstrap_options = c("striped", "hover"),
full_width = FALSE
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50")
Model 1 Performance
|
Metric
|
Result
|
|
Overall Accuracy
|
72.79%
|
|
Sensitivity (Recall)
|
73.24%
|
Model 1 Performance Analysis (Logistic
Regression):
The first model was trained using the balanced
dataset obtained through the ROSE technique,
achieving an overall accuracy of 72.79%.
Although this metric is satisfactory, accuracy alone is insufficient for
evaluating performance in a talent retention problem,
where the cost of incorrectly predicting an employee’s departure is
particularly high.
The main results obtained on the test set (441
employees) are presented below:
- Detection Capability (Recall): 73.2%
In the test set, there were 71 employees who actually left the
company.
The model correctly identified 52 of these 71 cases, demonstrating a
strong detection capability, as it successfully flagged
approximately three out of four at‑risk
employees.
This represents the model’s main strength — ensuring that most critical
cases are anticipated, allowing HR teams to take preventive
action.
- Cost of False Alarms (Precision: ~34%)
To maximise the detection of departures, the model became more
sensitive, which led to an increase in false
positives.
A total of 153 employees were flagged as potential
departures, but only 52 actually left the
organisation.
Thus, about two thirds of flagged employees remained,
generating a considerable level of false alerts.
While the model is effective at forecasting real departures, it operates
in a “hyper‑vigilant” mode, which can lead to
unnecessary HR interventions and resource strain.
- Confusion Matrix:
- True Negatives (269): Employees who stayed and were
correctly classified.
- False Positives (101): Employees who stayed but
were incorrectly flagged as at risk — potential waste of management
resources.
- False Negatives (19): Employees who left but were
not predicted to do so — unanticipated losses.
- True Positives (52): Employees who left and were
correctly identified — opportunities for proactive retention.
Next Step:
Test a more robust model, such as Random Forest, aiming
to reduce the number of false positives without
compromising the good sensitivity achieved by the logistic regression
model.
Model 2: Random Forest
library(randomForest)
library(caret)
library(ggplot2)
library(dplyr)
library(kableExtra)
# Data Preparation and Training
train_balanced$attrition <- as.factor(train_balanced$attrition)
test_data$attrition <- as.factor(test_data$attrition)
set.seed(123)
rf_model <- randomForest(attrition ~ .,
data = train_balanced,
ntree = 500,
importance = TRUE)
# Predictions and Metrics
rf_predictions <- predict(rf_model, newdata = test_data)
rf_conf_matrix <- confusionMatrix(data = rf_predictions,
reference = test_data$attrition,
positive = "1")
# Variable Importance Plot
imp_df <- as.data.frame(importance(rf_model))
imp_df$Variable <- rownames(imp_df)
ggplot(imp_df %>% arrange(desc(MeanDecreaseAccuracy)) %>% head(15),
aes(x = reorder(Variable, MeanDecreaseAccuracy), y = MeanDecreaseAccuracy)) +
geom_bar(stat = "identity", fill = "#2C3E50", alpha = 0.9, width = 0.7) +
coord_flip() +
labs(
title = "Top 15 Predictors of Employee Attrition",
subtitle = "Factors that most influence the decision to leave",
x = NULL,
y = "Importance (Mean Decrease Accuracy)"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 16),
panel.grid.major.y = element_blank()
)

# Comparative Performance Table
rf_metrics <- data.frame(
Metric = c("Accuracy", "Sensitivity (Recall)", "Specificity"),
Result = c(
paste0(round(rf_conf_matrix$overall['Accuracy'] * 100, 2), "%"),
paste0(round(rf_conf_matrix$byClass['Sensitivity'] * 100, 2), "%"),
paste0(round(rf_conf_matrix$byClass['Specificity'] * 100, 2), "%")
)
)
rf_metrics %>%
kable(caption = "Performance of the Random Forest Model") %>%
kable_styling(
bootstrap_options = c("striped", "hover"),
full_width = FALSE
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2c3e50")
Performance of the Random Forest Model
|
Metric
|
Result
|
|
Accuracy
|
74.15%
|
|
Sensitivity (Recall)
|
70.42%
|
|
Specificity
|
74.86%
|
The Random Forest model delivered superior
and more balanced performance compared with Logistic
Regression.
With an overall accuracy of 74.15%, this algorithm
proved to be a robust and reliable tool to support strategic
talent retention decisions.
- Balance between detection and precision
Unlike the previous model, Random Forest was more
precise in distinguishing between risk and stability
profiles.
Sensitivity (Recall) of 70.4% – It
correctly identified 50 of the 71 employees who
actually left the company.
Reduction of false positives – Although some
false alerts remain, the model was more selective in
identifying risk, reducing operational noise for HR teams.
This balance results in a more “surgical” tool,
capable of achieving a high detection capability without significantly
sacrificing predictive precision.
- Main predictors of attrition
The variable importance analysis highlights the factors most strongly
influencing the decision to leave, providing highly valuable management
insights:
OverTime (Overtime Work): Emerges as
the most powerful predictor, indicating that employees exposed to long
working hours are significantly more likely to leave.
MonthlyIncome (Salary): Confirms that
lower salary ranges represent the most vulnerable zone in terms of
attrition risk.
StockOptionLevel: The absence of
long‑term incentives (e.g., stock plans) is linked to weaker
organisational commitment.
Age and
TotalWorkingYears: Younger employees and those
with fewer years of experience show greater external mobility.
These findings align with HR research, emphasising the combined
influence of financial factors, workload, and professional
experience as key determinants of employee attrition.
- Technical and interpretative conclusion
The Random Forest model was able to capture non‑linear
interactions and complex patterns that linear models could not
represent.
For instance, the algorithm identified that an average salary
may be acceptable in isolation, but becomes a risk
factor when combined with excessive overtime or low satisfaction with
management.
In short, this model not only enhances predictive performance but
also provides actionable insights for targeted
retention policies and proactive talent management
strategies.
Attrition Drivers Analysis (Feature Importance)
# Extract variable importance from the Random Forest model
importance_df <- as.data.frame(importance(rf_model))
importance_df$Variable <- rownames(importance_df)
# Create the plot
library(ggplot2)
library(dplyr)
ggplot(importance_df %>% arrange(desc(MeanDecreaseAccuracy)) %>% head(15),
aes(x = reorder(Variable, MeanDecreaseAccuracy), y = MeanDecreaseAccuracy)) +
geom_bar(stat = "identity", fill = "#2C3E50", alpha = 0.9, width = 0.7) +
geom_text(aes(label = round(MeanDecreaseAccuracy, 1)),
hjust = -0.2, size = 3, fontface = "bold", color = "#2C3E50") +
coord_flip() +
scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
labs(
title = "Critical Attrition Drivers",
subtitle = "Variables that most impact the accuracy of the Random Forest model",
x = NULL,
y = "Importance (Mean Decrease Accuracy)"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
plot.subtitle = element_text(size = 11, color = "grey40"),
panel.grid.major.y = element_blank(),
axis.text.y = element_text(face = "bold", size = 10)
)

The chart above presents the most influential variables identified by
the Random Forest model, ranked according to the “Mean Decrease
Accuracy” metric.
In practical terms, the higher the importance of this metric, the
greater the variable’s contribution to the model’s overall predictive
capability—its removal would result in a significant drop in
accuracy.
- Job Role as the main determinant
(
JobRole)
Four of the top five most relevant variables relate to specific
functions within the organisation.
Two extremes stand out: Research Director (a highly stable
position) and Sales Representative (a considerably more
volatile one).
This difference confirms the conclusions drawn from the exploratory
stage: hierarchical level and job type
are key factors driving attrition behaviour across the company.
Implication: Generic people‑management policies
(“one‑size‑fits‑all”) are ineffective.
Retention strategies must be function‑specific,
acknowledging that sales and research/leadership teams require distinct
approaches to motivation and recognition.
The weight of overtime
(OverTime)
The variable over_time_yes ranks as the third most
critical predictor across the dataset.
This supports prior evidence showing that work overload
and poor work‑life balance are direct triggers of
attrition.
This is less a question of compensation and more one of
organisational well‑being and burnout
prevention.
Stagnation and long‑term incentives
- Stagnation: The variable
years_in_current_role (years in current position) ranks
sixth in importance. Prolonged permanence in the same role without
visible career progression markedly increases voluntary attrition
risk.
- Incentives:
stock_option_level follows
closely, highlighting that long‑term incentives have a
stronger retention effect than monthly income
(monthly_income), which only appears in fifteenth
position.
These findings suggest that career progression and
symbolic capital appreciation (e.g., ownership
incentives, recognition, visibility) are more effective retention
mechanisms than salary increases alone.
- Demographic risk profile
The presence of the variables marital_status_single and
age within the top 15 reaffirms the previously observed
pattern: younger and single employees are more mobile
and more prone to job changes, particularly when development
opportunities are limited.
To mitigate attrition risks, the company should
prioritise three strategic action areas:
- Reassess conditions and incentives for Sales teams,
where turnover is highest;
- Monitor and regulate overtime, encouraging
initiatives that promote work‑life balance and overall well‑being;
- Implement career‑rotation and development
programmes, particularly for employees who have remained in the
same position for several years.
These strategic actions align directly with the model results and can
substantially reduce unwanted turnover, thereby
strengthening the retention of critical talent.
Conclusion and Business Recommendations
The purpose of this project was to identify the key drivers
of employee attrition and to build a predictive model
to mitigate turnover risk.
Model Comparison
Two modelling approaches were evaluated: Logistic
Regression and Random Forest.
The Random Forest algorithm demonstrated
superior and more stable performance, achieving an
overall accuracy of 74.15%.
The model correctly identified 70.4% of employees who actually
left (sensitivity) while maintaining a controlled
false‑positive rate (specificity of 74.9%).
These metrics reveal an appropriate balance between detection
and precision, making the algorithm a reliable and practical
tool for HR decision‑making contexts.
Key Attrition Drivers (Model Insights)
The feature‑importance analysis revealed three core pillars
for action:
Risk Associated with Sales Roles
The Sales Representative role emerged as the
strongest predictor of departure. Turnover in this
function is substantially higher than in stable roles such as
Research Director or Manager.
Likely diagnosis: commission scheme imbalances,
excessive target pressure, or limited advancement
opportunities.
Overtime Culture and Occupational Fatigue
The OverTime variable remains among the top three
most critical factors, demonstrating that work
overload is a direct attrition trigger.
Employees who work overtime show markedly higher turnover likelihood,
regardless of salary level.
Interpretation: This pattern indicates possible signs
of burnout and work‑life imbalance,
areas that require continuous HR monitoring.
Retention Through Long‑Term Incentives
StockOptionLevel proves to be a key driver of
talent retention.
Employees with stock participation or long‑term incentives tend to stay
longer, driven by a stronger sense of ownership and organisational
commitment.
Conversely, the absence of these mechanisms correlates with a higher
turnover propensity.
Recommended Action Plan (Next Steps)
Based on the analytical findings, the following measures are
recommended:
Targeted Intervention in Sales Teams:
Conduct exit interviews focusing specifically on Sales
Representatives to reassess commission structures, target systems, and
career development opportunities.
Working‑Hours and Well‑Being Audit:
Implement mechanisms to monitor and compensate overtime
work (through time‑off or benefits).
In parallel, develop burnout prevention and work‑life balance
initiatives.
Continuous Attrition Prediction Tool:
Deploy the Random Forest model as a monthly
predictive‑monitoring system — a dynamic “risk list”
highlighting employees with a probability of departure above
50%.
HR teams should use this information proactively,
engaging with at‑risk employees before the decision to leave
occurs.
LS0tCnRpdGxlOiAiRW1wbG95ZWUgQXR0cml0aW9uIEFuYWx5c2lzIChIUiBBbmFseXRpY3MpIgpzdWJ0aXRsZTogIklkZW50aWZpY2F0aW9uIG9mIENyaXRpY2FsIEZhY3RvcnMgZm9yIFRhbGVudCBSZXRlbnRpb24iCmF1dGhvcjogIkpvYW5hIEluw6FjaW8gfCBEYXRhIEFuYWx5c3QiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVkLSVtLSVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IGNvc21vICAgICAgICAgICAKICAgIGhpZ2hsaWdodDogcHlnbWVudHMgICAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQotLS0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgRGF0YSBtYW5pcHVsYXRpb24gYW5kIGNsZWFuaW5nCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShmYXN0RHVtbWllcykKbGlicmFyeShza2ltcikKCiMgVmlzdWFsaXphdGlvbgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoY29ycnBsb3QpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIE1vZGVsaW5nIGFuZCBldmFsdWF0aW9uCmxpYnJhcnkoY2FUb29scykKbGlicmFyeShST1NFKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShjYXJldCkKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICAgIyBTaG93IFIgY29kZSBpbiB0aGUgcmVwb3J0IChUUlVFKSBvciBoaWRlIGl0IChGQUxTRSkKICB3YXJuaW5nID0gRkFMU0UsICAgICAgIyBIaWRlIHdhcm5pbmcgbWVzc2FnZXMgCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAgICMgSGlkZSBub3JtYWwgbWVzc2FnZXMKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgIyBDZW50ZXIgYWxsIGdyYXBoaWNzCiAgZmlnLndpZHRoID0gMTAsICAgICAgICMgRGVmYXVsdCBmaWd1cmUgd2lkdGgKICBmaWcuaGVpZ2h0ID0gNiwgICAgICAgIyBEZWZhdWx0IGZpZ3VyZSBoZWlnaHQKICBjb21tZW50ID0gTkEsICAgICAgICAgIyBSZW1vdmUgJyMjJyBmcm9tIGNvZGUgb3V0cHV0IGxpbmVzCiAgb3V0LndpZHRoID0gIjgwJSIgICAgICMgRmlndXJlcyBvY2N1cHkgODAlIG9mIHBhZ2Ugd2lkdGgKKQpgYGAKCiMgSW50cm9kdWN0aW9uIGFuZCBDb250ZXh0CiMjIFRoZSBCdXNpbmVzcyBQcm9ibGVtCkVtcGxveWVlIHR1cm5vdmVyIChhbHNvIGtub3duIGFzIF9FbXBsb3llZSBBdHRyaXRpb25fKSBpcyBvbmUgb2YgdGhlIGdyZWF0ZXN0IGNoYWxsZW5nZXMgZmFjZWQgYnkgb3JnYW5pc2F0aW9uc+KAlGFuZCBvbmUgb2YgdGhlIG1vc3QgZmluYW5jaWFsbHkgY29zdGx5LiAgClN0dWRpZXMgaW5kaWNhdGUgdGhhdCB0aGUgY29zdCBvZiByZXBsYWNpbmcgYW4gZW1wbG95ZWUgY2FuIHJhbmdlIGZyb20gKio1MCUgdG8gMjAwJSBvZiB0aGVpciBhbm51YWwgc2FsYXJ5KiosIGNvbnNpZGVyaW5nIHJlY3J1aXRtZW50LCB0cmFpbmluZywgYW5kIHByb2R1Y3Rpdml0eSBsb3NzIGV4cGVuc2VzLgoKQmV5b25kIHRoZSBmaW5hbmNpYWwgaW1wYWN0LCBhIGhpZ2ggX3R1cm5vdmVyXyByYXRlIGFmZmVjdHMgdGVhbSBtb3JhbGUsIGNvbXBhbnkgY3VsdHVyZSwgYW5kIHByb2plY3QgY29udGludWl0eS4gIApUaGVyZWZvcmUsIHRoZSBhYmlsaXR5IHRvIHByZWRpY3QgKip3aG8qKiBpcyBhdCByaXNrIG9mIGxlYXZpbmcgYW5kLCBtb3JlIGltcG9ydGFudGx5LCAqKndoeSoqLCByZXByZXNlbnRzIGEgY3J1Y2lhbCBjb21wZXRpdGl2ZSBhZHZhbnRhZ2UgZm9yIHRoZSBIdW1hbiBSZXNvdXJjZXMgKEhSKSBkZXBhcnRtZW50LgoKIyMgQWJvdXQgdGhlIERhdGFzZXQKVGhpcyBwcm9qZWN0IHVzZXMgdGhlIGRhdGFzZXQgKirigJxJQk0gSFIgQW5hbHl0aWNzIEVtcGxveWVlIEF0dHJpdGlvbiAmIFBlcmZvcm1hbmNl4oCdKiosIHB1YmxpY2x5IGF2YWlsYWJsZSBvbiBLYWdnbGUuICAKVGhlIGRhdGFzZXQgd2FzIGNyZWF0ZWQgYnkgSUJNIGRhdGEgc2NpZW50aXN0cyBhbmQsIGFsdGhvdWdoIHN5bnRoZXRpYywgYWNjdXJhdGVseSByZWZsZWN0cyB0aGUgcmVhbCBjaGFsbGVuZ2VzIG9mIGNvcnBvcmF0ZSBlbnZpcm9ubWVudHMuCgpJdCBjb250YWlucyAqKjEsNDcwIG9ic2VydmF0aW9ucyoqIChlbXBsb3llZXMpIGFuZCAqKjM1IHZhcmlhYmxlcyoqIChmZWF0dXJlcykuCgojIyBWYXJpYWJsZSBEaWN0aW9uYXJ5Ck91ciB0YXJnZXQgdmFyaWFibGUgaXMgKipfQXR0cml0aW9uXyoqLCB3aGljaCBpbmRpY2F0ZXMgd2hldGhlciB0aGUgZW1wbG95ZWUgKipsZWZ0KiogKCJZZXMiKSBvciAqKnJlbWFpbmVkKiogKCJObyIpIGluIHRoZSBjb21wYW55LgoKVGhlIHJlbWFpbmluZyB2YXJpYWJsZXMgY2FuIGJlIGdyb3VwZWQgaW50byB0aHJlZSBtYWluIGNhdGVnb3JpZXMgZXhwbG9yZWQgdGhyb3VnaG91dCB0aGUgYW5hbHlzaXM6CgoxLiAqKkRlbW9ncmFwaGljKio6IGBBZ2VgLCBgR2VuZGVyYCwgYE1hcml0YWxTdGF0dXNgLCBgRGlzdGFuY2VGcm9tSG9tZWAKMi4gKipXb3JrLXJlbGF0ZWQqKjogYERlcGFydG1lbnRgLCBgSm9iUm9sZWAsIGBKb2JMZXZlbGAsIGBPdmVyVGltZWAsIGBCdXNpbmVzc1RyYXZlbGAKMy4gKipDb21wZW5zYXRpb24gYW5kIFNhdGlzZmFjdGlvbioqOiBgTW9udGhseUluY29tZWAsIGBQZXJjZW50U2FsYXJ5SGlrZWAsIGBTdG9ja09wdGlvbkxldmVsYCwgYEpvYlNhdGlzZmFjdGlvbmAsIGBFbnZpcm9ubWVudFNhdGlzZmFjdGlvbmAKCkZvciByZWFkYWJpbGl0eSwgb25seSB0aGUgbW9zdCByZWxldmFudCB2YXJpYWJsZXMgYXJlIGxpc3RlZCBhYm92ZS4gIApBIGNvbXBsZXRlIGRpY3Rpb25hcnkgb2YgYWxsIDM1IHZhcmlhYmxlcyBhbmQgdGhlaXIgZGF0YSB0eXBlcyBpcyBwcmVzZW50ZWQgaW4gdGhlIHRlY2huaWNhbCBkYXRhIGluc3BlY3Rpb24gc2VjdGlvbi4KCiMjIFByb2plY3QgT2JqZWN0aXZlcwpUaGUgY29yZSBvYmplY3RpdmUgb2YgdGhpcyBwcm9qZWN0IGlzIHRvIGRldmVsb3AgYSAqKlBlb3BsZSBBbmFseXRpY3MqKiBzb2x1dGlvbiBjYXBhYmxlIG9mIGFudGljaXBhdGluZyBlbXBsb3llZSBhdHRyaXRpb24gYW5kIHByb3ZpZGluZyBtYW5hZ2VtZW50IHdpdGggKipkYXRh4oCRZHJpdmVuIHJldGVudGlvbiBzdHJhdGVnaWVzKiouICAKVG8gYWNoaWV2ZSB0aGF0LCB0aGUgYW5hbHlzaXMgZm9sbG93cyB0aHJlZSB2ZXJ0aWNhbCBwaWxsYXJzOgoKKiAqKlJvb3TigJFDYXVzZSBEaWFnbm9zaXMqKiDigJMgUXVhbnRpZnkgdGhlIHRydWUgaW1wYWN0IG9mIHJpc2sgZmFjdG9ycywgdGVzdGluZyB0aGUgaHlwb3RoZXNpcyB0aGF0IHdvcmtsb2FkIChgT3ZlclRpbWVgKSBhbmQgY29tbXV0aW5nIGRpc3RhbmNlIChgRGlzdGFuY2VGcm9tSG9tZWApIGFjdCBhcyBjYXRhbHlzdHMgZm9yIF9idXJub3V0Xy4KKiAqKlJldGVudGlvbiBIaWVyYXJjaHkqKiDigJMgRGV0ZXJtaW5lLCB1c2luZyBNYWNoaW5lIExlYXJuaW5nIGFsZ29yaXRobXMsIHdoaWNoIGZhY3RvcnMgd2VpZ2ggbW9yZSBpbiB0aGUgZGVjaXNpb24gdG8gbGVhdmU6IGZpbmFuY2lhbCBpbmNlbnRpdmVzIChgTW9udGhseUluY29tZWApIG9yIGludGFuZ2libGUgZWxlbWVudHMgc3VjaCBhcyBqb2Igc2F0aXNmYWN0aW9uLgoqICoqUHJlZGljdGl2ZSBNb2RlbGluZyoqIOKAkyBUcmFpbiBjbGFzc2lmaWNhdGlvbiBhbGdvcml0aG1zIChMb2dpc3RpYyBSZWdyZXNzaW9uIGFuZCBSYW5kb20gRm9yZXN0KSB0byBpZGVudGlmeSBhdOKAkXJpc2sgZW1wbG95ZWVzIHdpdGggaGlnaCBwcmVjaXNpb24sIGVuYWJsaW5nIHByZXZlbnRpdmUgSFIgYWN0aW9uLgoKIyBEYXRhIEltcG9ydCBhbmQgSW5pdGlhbCBJbnNwZWN0aW9uCmBgYHtyIGltcG9ydGFjYW8sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGF0YSBJbXBvcnQKIyBSZWFkIHRoZSBvcmlnaW5hbCBmaWxlCmlibV9ociA8LSByZWFkLmNzdigiZGF0YS9XQV9Gbi1Vc2VDXy1IUi1FbXBsb3llZS1BdHRyaXRpb24uY3N2Iiwgc2VwID0gIjsiKQoKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGRwbHlyKQoKIyBEYXRhIENsZWFuaW5nIGFuZCBTdGFuZGFyZGl6YXRpb24KIyBIZXJlIHdlIGNyZWF0ZSB0aGUgb2JqZWN0ICdpYm1fY2xlYW4nCgppYm1fY2xlYW4gPC0gaWJtX2hyICU+JSAKICBjbGVhbl9uYW1lcygpICU+JSAKICAjIFJlbW92ZSBjb2x1bW5zIHdpdGggbm8gdmFyaWFiaWxpdHkKICBzZWxlY3QoLWFueV9vZihjKCJlbXBsb3llZV9jb3VudCIsICJvdmVyMTgiLCAic3RhbmRhcmRfaG91cnMiLCAiZW1wbG95ZWVfbnVtYmVyIikpKQoKIyBWaXN1YWxpemF0aW9uIChrYWJsZSkKbGlicmFyeShrYWJsZUV4dHJhKQppYm1fY2xlYW4gJT4lIAogIHNlbGVjdChhZ2UsIGF0dHJpdGlvbiwgbW9udGhseV9pbmNvbWUsIGpvYl9yb2xlLCBvdmVyX3RpbWUsIHRvdGFsX3dvcmtpbmdfeWVhcnMpICU+JSAKICBoZWFkKDEwKSAlPiUgCiAga2FibGUoY2FwdGlvbiA9ICJUYWJsZSAxOiBTYW1wbGUgb2YgS2V5IFZhcmlhYmxlcyBmb3IgQXR0cml0aW9uIEFuYWx5c2lzIikgJT4lIAogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksIAogICAgZnVsbF93aWR0aCA9IFRSVUUsIAogICAgcG9zaXRpb24gPSAiY2VudGVyIgogICkgJT4lIAogIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzJjM2U1MCIpCmBgYAoKVGhlIGRhdGFzZXQgY29uc2lzdHMgb2YgKiozNSB2YXJpYWJsZXMqKiBjb3ZlcmluZyB0aHJlZSBtYWluIGRpbWVuc2lvbnM6ICoqZGVtb2dyYXBoaWMgY2hhcmFjdGVyaXN0aWNzKiosICoqZmluYW5jaWFsIGZhY3RvcnMqKiwgYW5kICoqcGVyZm9ybWFuY2UgaW5kaWNhdG9ycyoqLgoKQXQgdGhpcyBpbml0aWFsIHN0YWdlLCB0aGUgYW5hbHlzaXMgZm9jdXNlcyBvbiB2YXJpYWJsZXMgd2l0aCB0aGUgKipoaWdoZXN0IGV4cGxhbmF0b3J5IHBvdGVudGlhbCBmb3IgZW1wbG95ZWUgYXR0cml0aW9uKiosIG5hbWVseSAqKm1vbnRobHkgaW5jb21lKiosICoqdG90YWwgeWVhcnMgb2YgZXhwZXJpZW5jZSBpbiB0aGUgY29tcGFueSoqLCBhbmQgKipvdmVydGltZSB3b3JrKiouCgpFbXBpcmljYWwgZXZpZGVuY2UgYW5kIHByZWxpbWluYXJ5IGFuYWx5c2VzIHN1Z2dlc3QgYSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGVzZSBmYWN0b3JzIGFuZCB0aGUgKipwcm9iYWJpbGl0eSBvZiBlbXBsb3llZSBkZXBhcnR1cmUqKiwgZXN0YWJsaXNoaW5nIHRoZW0gYXMgZnVuZGFtZW50YWwgc3RhcnRpbmcgcG9pbnRzIGZvciBkZWVwZXIgYW5hbHl0aWNhbCBleHBsb3JhdGlvbi4KCiMgRGF0YSBQcmVwYXJhdGlvbgojIyBEYXRhIENsZWFuaW5nClRoZSBpbml0aWFsIGRlc2NyaXB0aXZlIGFuYWx5c2lzIHJldmVhbGVkIHR3byBrZXkgYXNwZWN0cyByZWdhcmRpbmcgdGhlIHF1YWxpdHkgYW5kIHN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldDoKCjEuICoqRGF0YSBRdWFsaXR5Kiog4oCTIE5vIG1pc3NpbmcgdmFsdWVzIHdlcmUgaWRlbnRpZmllZCBhY3Jvc3MgYW55IHZhcmlhYmxlLCB3aGljaCBncmVhdGx5IHNpbXBsaWZpZXMgdGhlIHByZXByb2Nlc3Npbmcgc3RhZ2UuCgoyLiAqKlJlZHVuZGFudCBhbmQgTm9u4oCRSW5mb3JtYXRpdmUgVmFyaWFibGVzKiog4oCTIFRocmVlIHZhcmlhYmxlcyB3ZXJlIGZvdW5kIHRvIGhhdmUgY29uc3RhbnQgdmFsdWVzIGFjcm9zcyBhbGwgb2JzZXJ2YXRpb25zIChzdGFuZGFyZCBkZXZpYXRpb24gPSAwKSwgYW5kIG9uZSB2YXJpYWJsZSBzZXJ2ZWQgZXhjbHVzaXZlbHkgYXMgYSB1bmlxdWUgaWRlbnRpZmllci4gQXMgdGhlc2Ugc2hvdyBubyB2YXJpYWJpbGl0eSBvciBwcmVkaWN0aXZlIGNvbnRyaWJ1dGlvbiwgdGhleSB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgZGF0YXNldC4KClRoZSAqKnJlbW92ZWQgdmFyaWFibGVzKiogd2VyZToKCiogYEVtcGxveWVlQ291bnRgOiBDb25zdGFudCB2YWx1ZSBlcXVhbCB0byDigJwx4oCdOwoqIGBPdmVyMThgOiBBbGwgZW1wbG95ZWVzIHJlY29yZGVkIGFzIGFkdWx0cyAo4oCcWeKAnSk7CiogYFN0YW5kYXJkSG91cnNgOiBGaXhlZCB2YWx1ZSDigJw4MOKAnSBmb3IgYWxsIHJlY29yZHM7CiogYEVtcGxveWVlTnVtYmVyYDogVW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggZW1wbG95ZWUsIHdpdGggbm8gcHJlZGljdGl2ZSByZWxldmFuY2UuCgpUaGUgZXhjbHVzaW9uIG9mIHRoZXNlIHZhcmlhYmxlcyByZWR1Y2VzIGRhdGEgZGltZW5zaW9uYWxpdHkgKip3aXRob3V0IGxvc2luZyBtZWFuaW5nZnVsIGluZm9ybWF0aW9uKiosIGNvbnRyaWJ1dGluZyB0byBhIG1vcmUgZWZmaWNpZW50IGFuZCBpbnRlcnByZXRhYmxlIGFuYWx5dGljYWwgbW9kZWwuCgpgYGB7ciBsaW1wZXphX2VzcGVjaWZpY2EsIG1lc3NhZ2U9RkFMU0V9CiMgU3RhbmRhcmRpemF0aW9uIG9mIENvbHVtbiBOYW1lcwppYm1fY2xlYW4gPC0gaWJtX2hyICU+JSAKICBjbGVhbl9uYW1lcygpCgojIFJlbW92ZSBJbnZhcmlhbnQgVmFyaWFibGVzCmNvbHVtbnNfdG9fcmVtb3ZlIDwtIGMoImVtcGxveWVlX2NvdW50IiwgIm92ZXIxOCIsICJzdGFuZGFyZF9ob3VycyIsICJlbXBsb3llZV9udW1iZXIiKQoKaWJtX2NsZWFuIDwtIGlibV9jbGVhbiAlPiUgCiAgc2VsZWN0KC1hbnlfb2YoY29sdW1uc190b19yZW1vdmUpKQoKIyBDbGVhbmluZyBTdW1tYXJ5CmNhdCgiRGF0YXNldCBjbGVhbmVkIHN1Y2Nlc3NmdWxseS5cbiIsCiAgICAiVG90YWwgT3JpZ2luYWwgQ29sdW1uczogIiwgbmNvbChpYm1faHIpLCAiXG4iLAogICAgIlRvdGFsIENvbHVtbnMgQWZ0ZXIgQ2xlYW5pbmc6ICIsIG5jb2woaWJtX2NsZWFuKSkKYGBgCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkKVGhlIG1haW4gZ29hbCBvZiB0aGlzIHBoYXNlIGlzIHRvIHVuZGVyc3RhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdmFyaWFibGVzIGFuZCBpZGVudGlmeSBwYXR0ZXJucyBvciByZWxhdGlvbnNoaXBzIHRoYXQgbWF5IGV4cGxhaW4gdGhlIHBoZW5vbWVub24gb2YgKiplbXBsb3llZSB0dXJub3ZlcioqIChfZW1wbG95ZWUgYXR0cml0aW9uXykuCgpUaGUgZXhwbG9yYXRpb24gYmVnaW5zIHdpdGggdGhlIHRhcmdldCB2YXJpYWJsZSwgYEF0dHJpdGlvbmAsIHdoaWNoIGluZGljYXRlcyB3aGV0aGVyIHRoZSBlbXBsb3llZSAqKnJlbWFpbmVkIHdpdGggdGhlIGNvbXBhbnkqKiAoYE5vYCkgb3IgKipjaG9zZSB0byBsZWF2ZSoqIChgWWVzYCkuCgpBbmFseXNpbmcgdGhpcyB2YXJpYWJsZSBwcm92aWRlcyBhbiBpbml0aWFsIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGJhbGFuY2UgYmV0d2VlbiBhY3RpdmUgZW1wbG95ZWVzIGFuZCB0aG9zZSB3aG8gbGVmdCB0aGUgb3JnYW5pc2F0aW9uLCBoZWxwaW5nIGFzc2VzcyB0aGUgcmVhbCBtYWduaXR1ZGUgb2YgdGhlIGF0dHJpdGlvbiBwaGVub21lbm9uLgoKIyMgVGFyZ2V0IFZhcmlhYmxlIEFuYWx5c2lzIChfQXR0cml0aW9uXykKSG93IG1hbnkgZW1wbG95ZWVzIGFjdHVhbGx5IGxlZnQgdGhlIGNvbXBhbnk/CgpgYGB7ciBhbmFsaXNlX3RhcmdlfQojIENyZWF0ZSBGcmVxdWVuY3kgVGFibGUgZm9yIHRoZSBUYXJnZXQgVmFyaWFibGUKdGFiZWxhX3RhcmdldCA8LSBpYm1fY2xlYW4gJT4lCiAgY291bnQoYXR0cml0aW9uKSAlPiUKICBtdXRhdGUoCiAgICBwZXJjZW50YWdlID0gKG4gLyBzdW0obikpICogMTAwLAogICAgYXR0cml0aW9uID0gaWZlbHNlKGF0dHJpdGlvbiA9PSAiWWVzIiwgIkxlZnQgKFllcykiLCAiU3RheWVkIChObykiKQogICkKCiMgRGlzcGxheSBUYWJsZSB3aXRoIGthYmxlRXh0cmEKdGFiZWxhX3RhcmdldCAlPiUKICBrYWJsZSgKICAgIGNhcHRpb24gPSAiRGlzdHJpYnV0aW9uIG9mIHRoZSBUYXJnZXQgVmFyaWFibGUgKEF0dHJpdGlvbikiLAogICAgY29sLm5hbWVzID0gYygiU3RhdHVzIiwgIlRvdGFsIChuKSIsICJQZXJjZW50YWdlICglKSIpLAogICAgZGlnaXRzID0gMQogICkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSwgZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKSAlPiUKICBjb2x1bW5fc3BlYygzLCBib2xkID0gVFJVRSwgY29sb3IgPSBpZmVsc2UodGFiZWxhX3RhcmdldCRwZXJjZW50YWdlIDwgMjAsICIjZTc0YzNjIiwgIiMyYzNlNTAiKSkKCiMgVmlzdWFsaXphdGlvbgpnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IGF0dHJpdGlvbiwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcih3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xKSkpICsKICBsYWJzKAogICAgdGl0bGUgPSAiT3ZlcnZpZXcgb2YgRW1wbG95ZWUgVHVybm92ZXIiLAogICAgc3VidGl0bGUgPSAiT25seSAxNiUgb2YgZW1wbG95ZWVzIGxlZnQgdGhlIG9yZ2FuaXNhdGlvbiBkdXJpbmcgdGhlIGFuYWx5c2VkIHBlcmlvZCIsCiAgICB4ID0gIkF0dHJpdGlvbiBEZWNpc2lvbiIsCiAgICB5ID0gIk51bWJlciBvZiBFbXBsb3llZXMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2LCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYAoqKl9Jbml0aWFsIEluc2lnaHRfKio6ICAKVGhlICoqYXR0cml0aW9uIHJhdGUqKiBpcyBhcHByb3hpbWF0ZWx5ICoqMTYlKiosIGluZGljYXRpbmcgdGhhdCB0aGUgbWFqb3JpdHkgb2YgZW1wbG95ZWVzIChhcm91bmQgKio4NCUqKikgcmVtYWluZWQgd2l0aCB0aGUgY29tcGFueSBkdXJpbmcgdGhlIGFuYWx5c2VkIHBlcmlvZC4KClRoaXMgc2hvd3MgYSBjbGVhciAqKmNsYXNzIGltYmFsYW5jZSoqIGluIHRoZSB0YXJnZXQgdmFyaWFibGUsIHdpdGggYSBwcmVkb21pbmFuY2Ugb2YgZW1wbG95ZWVzIHdobyBkaWQgbm90IGxlYXZlIHRoZSBvcmdhbmlzYXRpb24uCgpUaGlzIHBvaW50IGlzIHBhcnRpY3VsYXJseSBpbXBvcnRhbnQgZm9yIHRoZSBsYXRlciBzdGFnZXMgb2YgKipwcmVkaWN0aXZlIG1vZGVsbGluZyoqLCBhcyB0aGUgY2xhc3MgZGlzcHJvcG9ydGlvbiBtYXkgbGVhZCB0aGUgbW9kZWwgdG8gKipvdmVyZml0IHRoZSBtYWpvcml0eSBjbGFzcyoqIChlbXBsb3llZXMgd2hvIHN0YXkpIGFuZCAqKnVuZGVyZXN0aW1hdGUqKiB0aGUgbWlub3JpdHkgY2FzZXMgKGVtcGxveWVlcyB3aG8gbGVhdmUpLCB3aGljaCBhcmUgcHJlY2lzZWx5IHRoZSBtb3N0IHZhbHVhYmxlIHRvIHVuZGVyc3RhbmQgYW5kIHByZWRpY3QuCgojIyBEZW1vZ3JhcGhpYyBBbmFseXNpczogRG9lcyBBZ2UgTWF0dGVyPwpOZXh0LCB3ZSBhbmFseXNlIHRoZSBkaXN0cmlidXRpb24gb2YgZW1wbG95ZWUgYWdlcyBiZXR3ZWVuIHRob3NlIHdobyBsZWZ0IGFuZCB0aG9zZSB3aG8gc3RheWVkLiAgCkEgYm94cGxvdCBpcyB1c2VkIHRvIHZpc3VhbGlzZSB0aGUgbWVkaWFuIGFuZCBkYXRhIGRpc3BlcnNpb24uCgpgYGB7ciBhbmFsaXNlX2lkYWRlfQojIFBsb3Q6IEFnZSBEaXN0cmlidXRpb24gYnkgQXR0cml0aW9uCmdncGxvdChpYm1fY2xlYW4sIGFlcyh4ID0gYXR0cml0aW9uLCB5ID0gYWdlLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21faml0dGVyKGFscGhhID0gMC4yLCBjb2xvciA9ICJncmV5NDAiLCB3aWR0aCA9IDAuMikgKwogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuOCwgb3V0bGllci5jb2xvdXIgPSAicmVkIiwgd2lkdGggPSAwLjUpICsKICAKICAjIENvbG9ycyBjb25zaXN0ZW50IHdpdGggdGhlIHJlc3Qgb2YgdGhlIHJlcG9ydAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgCiAgbGFicygKICAgIHRpdGxlID0gIlRoZSBBZ2UgRmFjdG9yIGluIFRhbGVudCBSZXRlbnRpb24iLAogICAgc3VidGl0bGUgPSAiRW1wbG95ZWVzIHdobyBsZWF2ZSAoWWVzKSBzaG93IGEgdmlzaWJseSBsb3dlciBtZWRpYW4gYWdlIiwKICAgIHggPSAiQXR0cml0aW9uIERlY2lzaW9uIiwKICAgIHkgPSAiQWdlIChZZWFycykiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2LCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpCiAgKQpgYGAKCioqX0luc2lnaHRzIG9uIEFnZTpfKioKClRoZSBib3hwbG90IGFuYWx5c2lzIHJldmVhbHMgYSBjbGVhciBwYXR0ZXJuIGluIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiAqKmFnZSoqIGFuZCAqKmVtcGxveWVlIGF0dHJpdGlvbioqOgoKMS4gKipZb3V0aCBGYWN0b3IqKiDigJMgVGhlcmUgaXMgYSB0ZW5kZW5jeSBmb3IgeW91bmdlciBlbXBsb3llZXMgdG8gc2hvdyBhICoqaGlnaGVyIHByb3BlbnNpdHkgdG8gbGVhdmUgdGhlIGNvbXBhbnkqKi4gVGhlIG1lZGlhbiBhZ2Ugb2YgdGhvc2Ugd2hvIGxlYXZlIGlzIHZpc2libHkgbG93ZXIgdGhhbiB0aGF0IG9mIHRob3NlIHdobyBzdGF5LiAgCgoyLiAqKlJpc2sgWm9uZSoqIOKAkyBUaGUgaGlnaGVzdCBjb25jZW50cmF0aW9uIG9mIGRlcGFydHVyZXMgb2NjdXJzIGJldHdlZW4gKioyNSBhbmQgMzUgeWVhcnMgb2xkKiosIGEgcmFuZ2UgY29tbW9ubHkgYXNzb2NpYXRlZCB3aXRoICoqY2FyZWVyIG1vYmlsaXR5KiogYW5kIHRoZSAqKnNlYXJjaCBmb3IgYWR2YW5jZW1lbnQgb3Bwb3J0dW5pdGllcyoqLiBUaGlzIGJlaGF2aW91ciBtYXkgcmVmbGVjdCBjaGFsbGVuZ2VzIGZhY2VkIGJ5IHRoZSBvcmdhbmlzYXRpb24gaW4gKipyZXRhaW5pbmcgeW91bmcgdGFsZW50Kiogb3IgcHJvdmlkaW5nICoqc3RydWN0dXJlZCBkZXZlbG9wbWVudCBwYXRod2F5cyoqLiAgCgozLiAqKlNlbmlvciBTdGFiaWxpdHkqKiDigJMgRW1wbG95ZWVzICoqb3ZlciA0MCB5ZWFycyBvbGQqKiBkZW1vbnN0cmF0ZSAqKmdyZWF0ZXIgc3RhYmlsaXR5KiogYW5kIGEgKipsb3dlciBwcm9iYWJpbGl0eSBvZiBsZWF2aW5nKiouIFRoZSBmZXcgY2FzZXMgaW4gdGhpcyBhZ2UgZ3JvdXAgYXBwZWFyIGFzIF9vdXRsaWVyc18gaW4gdGhlIHBsb3QsIHN1Z2dlc3RpbmcgaXNvbGF0ZWQgZGVwYXJ0dXJlcyAoZS5nLiwgcmV0aXJlbWVudCwgcGVyc29uYWwgcmVsb2NhdGlvbiwgb3IgaW50ZXJuYWwgcmVzdHJ1Y3R1cmluZykuICAKCioqQ29uY2x1c2lvbjoqKiAgClRoZSBmaW5kaW5ncyBoaWdobGlnaHQgdGhlIG5lZWQgZm9yIGEgKipzZWdtZW50ZWQgcmV0ZW50aW9uIHN0cmF0ZWd5Kio6CgoqICoqSnVuaW9yIGFuZCBtaWTigJFsZXZlbCBlbXBsb3llZXMqKiAoMjXigJMzNSB5ZWFycyBvbGQpIHNob3VsZCBiZSB0YXJnZXRlZCB3aXRoIGluaXRpYXRpdmVzIGZvY3VzZWQgb24gX2VuZ2FnZW1lbnRfLCBpbnRlcm5hbCBtb2JpbGl0eSwgYW5kIGNhcmVlcuKAkWdyb3d0aCBtYW5hZ2VtZW50LiAgCiogRm9yICoqc2VuaW9yIGVtcGxveWVlcyoqLCBlbXBoYXNpcyBzaG91bGQgYmUgcGxhY2VkIG9uIHJlY29nbml0aW9uLCBtZW50b3JzaGlwLCBhbmQga25vd2xlZGdlIHRyYW5zZmVyLCByZWluZm9yY2luZyBhIHNlbnNlIG9mIGJlbG9uZ2luZyBhbmQgb3JnYW5pc2F0aW9uYWwgY29udGludWl0eS4KCmBgYHtyIGFuYWxpc2VfZXN0YWRvX2NpdmlsfQojIEJhciBDaGFydDogQXR0cml0aW9uIFByb3BvcnRpb24gYnkgTWFyaXRhbCBTdGF0dXMKZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSBtYXJpdGFsX3N0YXR1cywgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAwLjcsIGFscGhhID0gMC45KSArCiAgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICAKICAjIEZvcm1hdCBZLWF4aXMgYXMgcGVyY2VudGFnZQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICAKICBsYWJzKAogICAgdGl0bGUgPSAiSW1wYWN0IG9mIE1hcml0YWwgU3RhdHVzIG9uIFJldGVudGlvbiIsCiAgICBzdWJ0aXRsZSA9ICJTaW5nbGUgZW1wbG95ZWVzIHNob3cgYSBzaWduaWZpY2FudGx5IGhpZ2hlciBhdHRyaXRpb24gcmF0ZSIsCiAgICB4ID0gIk1hcml0YWwgU3RhdHVzIiwKICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBFbXBsb3llZXMiLAogICAgZmlsbCA9ICJMZWZ0PyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYsIGNvbG9yID0gIiMyYzNlNTAiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICApCmBgYAoKKipfSW5zaWdodHMgb24gTWFyaXRhbCBTdGF0dXM6XyoqCgpUaGUgYW5hbHlzaXMgc3VnZ2VzdHMgdGhhdCAqKm1hcml0YWwgc3RhdHVzKiogaXMgYSAqKnNpZ25pZmljYW50IGZhY3RvciBpbmZsdWVuY2luZyBlbXBsb3llZSBhdHRyaXRpb24qKjoKCjEuICoqSGlnaGVyIHJpc2sgYW1vbmcgc2luZ2xlIGVtcGxveWVlcyoqIOKAkyBTaW5nbGUgZW1wbG95ZWVzIGRpc3BsYXkgYW4gKiphdHRyaXRpb24gcmF0ZSBhYm92ZSAyNSUqKiwgbW9yZSB0aGFuIGRvdWJsZSB0aGF0IG9mIG1hcnJpZWQgb3IgZGl2b3JjZWQgZW1wbG95ZWVzIChhcHByb3hpbWF0ZWx5IDExJSkuIFRoaXMgaW5kaWNhdGVzIGEgc3Ryb25nIGFzc29jaWF0aW9uIGJldHdlZW4gbWFyaXRhbCBzdGF0dXMgYW5kIHRoZSBwcm9iYWJpbGl0eSBvZiBsZWF2aW5nIHRoZSBjb21wYW55LiAgCgoyLiAqKlBvdGVudGlhbCBiZWhhdmlvdXJhbCBleHBsYW5hdGlvbioqIOKAkyBUaGlzIHBhdHRlcm4gYWxpZ25zIHdpdGggZW1waXJpY2FsIGV2aWRlbmNlIGluIGh1bWFuIHJlc291cmNlcyByZXNlYXJjaCwgd2hpY2ggc2hvd3MgdGhhdCBwcm9mZXNzaW9uYWxzIHdpdGhvdXQgZGVwZW5kYW50cyBvciBmYW1pbHkgY29tbWl0bWVudHMgdGVuZCB0byBleGhpYml0ICoqZ3JlYXRlciBqb2IgbW9iaWxpdHkqKi4gVGhlaXIgKipnZW9ncmFwaGljYWwgYW5kIGZpbmFuY2lhbCBmbGV4aWJpbGl0eSoqIGZhY2lsaXRhdGVzIHRoZSBwdXJzdWl0IG9mIG5ldyBvcHBvcnR1bml0aWVzIG9yIGFjY2VwdGFuY2Ugb2Ygb2ZmZXJzIGluIGRpZmZlcmVudCBsb2NhdGlvbnMuICAKCioqQ29uY2x1c2lvbjoqKiAgClRhbGVudCBtYW5hZ2VtZW50IHN0cmF0ZWdpZXMgbWF5IGJlbmVmaXQgZnJvbSAqKmRpZmZlcmVudGlhdGVkIHJldGVudGlvbiBhcHByb2FjaGVzKiogYWNyb3NzIGVtcGxveWVlIGdyb3VwcywgZm9yIGluc3RhbmNlLCBkZXNpZ25pbmcgKipjYXJlZXLigJFwcm9ncmVzc2lvbiBpbml0aWF0aXZlcyoqIGFuZCAqKmVuZ2FnZW1lbnQgcHJvZ3JhbW1lcyoqIHRvIHN0cmVuZ3RoZW4gdGhlIGNvbW1pdG1lbnQgb2YgeW91bmdlciwgc2luZ2xlIGVtcGxveWVlcyB0byB0aGUgb3JnYW5pc2F0aW9uLgoKIyMgUHJvZmVzc2lvbmFsIEFuYWx5c2lzOiBXb3JrbG9hZCBhbmQgQnVzaW5lc3MgVHJhdmVsCgpDb3VsZCBleGNlc3NpdmUgd29ya2xvYWQgKGBPdmVyVGltZWApIGFuZCBmcmVxdWVudCB0cmF2ZWwgKGBCdXNpbmVzc1RyYXZlbGApIGxlYWQgdG8gZmF0aWd1ZSBhbmQgaW5jcmVhc2VkIGF0dHJpdGlvbj8KCmBgYHtyIGFuYWxpc2VfY2FyZ2FfdHJhYmFsaG99CiMgUGxvdDogT3ZlcnRpbWUgSG91cnMgKHAxKQpwMSA8LSBnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IG92ZXJfdGltZSwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAwLjcsIGFscGhhID0gMC45KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwgZXhwYW5kID0gYygwLCAwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgbGFicygKICAgIHRpdGxlID0gIkltcGFjdCBvZiBPdmVydGltZSBIb3VycyIsIAogICAgeCA9ICJXb3JrcyBPdmVydGltZT8iLCAKICAgIHkgPSAiUHJvcG9ydGlvbiIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCgojIFBsb3Q6IEJ1c2luZXNzIFRyYXZlbCAocDIpCnAyIDwtIGdncGxvdChpYm1fY2xlYW4sIGFlcyh4ID0gYnVzaW5lc3NfdHJhdmVsLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCB3aWR0aCA9IDAuNywgYWxwaGEgPSAwLjkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLCBleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSW1wYWN0IG9mIEJ1c2luZXNzIFRyYXZlbCIsIAogICAgeCA9ICJUcmF2ZWwgRnJlcXVlbmN5IiwgCiAgICB5ID0gTlVMTCwKICAgIGZpbGwgPSAiTGVmdD8iCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBDb21iaW5lIGJvdGggdmlzdWFsaXphdGlvbnMKbGlicmFyeShncmlkRXh0cmEpCmdyaWQuYXJyYW5nZSgKICBwMSwgcDIsIG5jb2wgPSAyLAogIHRvcCA9IGdyaWQ6OnRleHRHcm9iKAogICAgIldvcmtsb2FkIGFuZCBNb2JpbGl0eSBBbmFseXNpcyIsCiAgICBncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxNiwgZm9udCA9IDIsIGNvbCA9ICIjMmMzZTUwIikKICApCikKYGBgCgoqKl9JbnNpZ2h0cyBvbiBXb3JrbG9hZCBhbmQgTGlmZXN0eWxlOl8qKgoKVGhlIGFuYWx5c2lzIG9mIHdvcmtsb2FkIGFuZCBwcm9mZXNzaW9uYWwgbW9iaWxpdHkgcmV2ZWFscyBhIGNsZWFyIGFzc29jaWF0aW9uIGJldHdlZW4gKipleGhhdXN0aW9uKiogYW5kICoqZW1wbG95ZWUgYXR0cml0aW9uKio6CgoxLiAqKkltcGFjdCBvZiBPdmVydGltZSBIb3VycyoqIOKAkyBUaGUgZWZmZWN0IG9mIG92ZXJ0aW1lIHdvcmsgaXMgcGFydGljdWxhcmx5IHN0cmlraW5nLiBFbXBsb3llZXMgd2hvIGRvICoqbm90Kiogd29yayBvdmVydGltZSBzaG93IGFuIGF0dHJpdGlvbiByYXRlIGNsb3NlIHRvICoqMTAlKiosIHdoaWxlIGFtb25nIHRob3NlIHdobyByZWd1bGFybHkgZXhjZWVkIHRoZWlyIHdvcmtpbmcgaG91cnMsIHRoaXMgcmF0ZSAqKnRyaXBsZXMgdG8gYXJvdW5kIDMwJSoqLiAgClRoaXMgcmVzdWx0IHNlcnZlcyBhcyBhIGNsZWFyIGluZGljYXRvciBvZiAqKl9idXJub3V0XyByaXNrKiogYW5kIHN1Z2dlc3RzIHRoYXQgZXhjZXNzaXZlIHdvcmtsb2FkIG1heSBiZSBsaW5rZWQgdG8gZGlzc2F0aXNmYWN0aW9uIGFuZCBlbW90aW9uYWwgZmF0aWd1ZS4KCjIuICoqVGhlIFdlaWdodCBvZiBNb2JpbGl0eSoqIChgQnVzaW5lc3NUcmF2ZWxgKSDigJMgVGhlcmUgaXMgYSB2aXNpYmxlIHVwd2FyZCB0cmVuZCBiZXR3ZWVuICoqdHJhdmVsIGZyZXF1ZW5jeSoqIGFuZCAqKmF0dHJpdGlvbiBwcm9iYWJpbGl0eSoqOgoKICAgKiBFbXBsb3llZXMgd2hvICoqZG8gbm90IHRyYXZlbCoqIChgTm9u4oCRVHJhdmVsYCkgc2hvdyB0aGUgbG93ZXN0IGF0dHJpdGlvbiByYXRlICg8MTAlKTsgIAogICAqIFRob3NlIHdobyAqKnRyYXZlbCBmcmVxdWVudGx5KiogKGBUcmF2ZWxfRnJlcXVlbnRseWApIGZhY2UgYSByaXNrIGNsb3NlIHRvICoqMjUlKiosIGluZGljYXRpbmcgdGhhdCB0aGVpciAqKndvcmvigJFsaWZlIGJhbGFuY2UqKiBpcyBzdWJzdGFudGlhbGx5IGNvbXByb21pc2VkLgoKKipDb25jbHVzaW9uOioqICAKQm90aCAqKndvcmsgb3ZlcmxvYWQqKiBhbmQgKipleGNlc3NpdmUgbW9iaWxpdHkqKiBlbWVyZ2UgYXMgcmVsZXZhbnQgcmlzayBmYWN0b3JzIGZvciB0YWxlbnQgcmV0ZW50aW9uLiAgCk9yZ2FuaXNhdGlvbmFsIHBvbGljaWVzIHRoYXQgcHJvbW90ZSAqKmhlYWx0aHkgd29ya2luZ+KAkWhvdXIgbGltaXRzKiosICoqZmxleGliaWxpdHkqKiwgYW5kICoqd29ya+KAkWxpZmUgYmFsYW5jZSoqIGNhbiBzaWduaWZpY2FudGx5IG1pdGlnYXRlIHRoaXMgdHlwZSBvZiB0dXJub3Zlci4KCiMjIEZpbmFuY2lhbCBBbmFseXNpczogRG9lcyBTYWxhcnkgTWF0dGVyPwpUaGUgZGlzdHJpYnV0aW9uIG9mIG1vbnRobHkgaW5jb21lIChgTW9udGhseUluY29tZWApIHdhcyBhbmFseXNlZCB0byBkZXRlcm1pbmUgd2hldGhlciBsb3dlciBzYWxhcmllcyBjb250cmlidXRlIHRvIGhpZ2hlciBhdHRyaXRpb24uCgpgYGB7ciBhbmFsaXNlX3NhbGFyaW99CiMgRGVuc2l0eSBQbG90OiBNb250aGx5IEluY29tZSBieSBBdHRyaXRpb24KZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSBtb250aGx5X2luY29tZSwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjcsIGNvbG9yID0gIndoaXRlIikgKwogIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgCiAgIyBGb3JtYXQgWC1heGlzIGFzIEN1cnJlbmN5IChVU0QpCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdCgpLCBicmVha3MgPSBzZXEoMCwgMjAwMDAsIDI1MDApKSArCiAgCiAgbGFicygKICAgIHRpdGxlID0gIlNhbGFyeSBEaXN0cmlidXRpb24gYW5kIEF0dHJpdGlvbiBSaXNrIiwKICAgIHN1YnRpdGxlID0gIlRoZSBwcm9iYWJpbGl0eSBvZiBsZWF2aW5nIGlzIGRyYXN0aWNhbGx5IGhpZ2hlciBmb3Igc2FsYXJ5IHJhbmdlcyBiZWxvdyAkNSwwMDAiLAogICAgeCA9ICJNb250aGx5IFNhbGFyeSAoVVNEKSIsCiAgICB5ID0gIkVtcGxveWVlIERlbnNpdHkiLAogICAgZmlsbCA9ICJBdHRyaXRpb24gU3RhdHVzIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiwgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpCiAgKQpgYGAKCioqX0ZpbmFuY2lhbCBJbnNpZ2h0czpfKioKClRoZSBhbmFseXNpcyBvZiBzYWxhcnkgZGlzdHJpYnV0aW9uIHJldmVhbHMgdGhhdCAqKmNvbXBlbnNhdGlvbiBpcyBhIGRlY2lzaXZlIGZhY3RvcioqIGluIHRoZSBsaWtlbGlob29kIG9mIGVtcGxveWVlIGF0dHJpdGlvbiwgc2hvd2luZyBhIG1hcmtlZGx5IGRpc3RpbmN0IHBhdHRlcm4gYWNyb3NzIGluY29tZSByYW5nZXM6CgoxLiAqKlRoZSAkNSwwMDAgVGhyZXNob2xkKiog4oCTIFRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgY29uY2VudHJhdGlvbiBvZiBkZXBhcnR1cmVzIGFtb25nIGVtcGxveWVlcyB3aXRoIG1vbnRobHkgc2FsYXJpZXMgYmVsb3cgJDUsMDAwLiBJbiB0aGlzIHJhbmdlLCB0aGUgZGVuc2l0eSBvZiBhdHRyaXRpb24gY2FzZXMgaXMgc3Vic3RhbnRpYWxseSBoaWdoZXIsIHN1Z2dlc3RpbmcgdGhhdCBsb3dlciBpbmNvbWUgbGV2ZWxzIGFyZSBhc3NvY2lhdGVkIHdpdGggZ3JlYXRlciB3b3JrZm9yY2Ugdm9sYXRpbGl0eS4gIAoKMi4gKipSZXRlbnRpb24gYXQgSGlnaGVyIFNhbGFyeSBMZXZlbHMqKiDigJMgQXMgc2FsYXJ5IGluY3JlYXNlcyAocGFydGljdWxhcmx5IGFib3ZlICQxMCwwMDApLCB0aGUgcHJvYmFiaWxpdHkgb2YgbGVhdmluZyBkcm9wcyBzaGFycGx5LiBBbW9uZyBoaWdoZXLigJFlYXJuaW5nIGVtcGxveWVlcywgdGhlIGRlbnNpdHkgY3VydmUgYXNzb2NpYXRlZCB3aXRoIOKAnHN0YXlpbmfigJ0gY2xlYXJseSBkb21pbmF0ZXMsIGluZGljYXRpbmcgZ3JlYXRlciBzdGFiaWxpdHkgYW5kIHByb2Zlc3Npb25hbCBzYXRpc2ZhY3Rpb24uICAKCioqQ29uY2x1c2lvbjoqKiAgClRoZSBvYnNlcnZlZCBwYXR0ZXJuIHN1Z2dlc3RzIHRoYXQgdGhlIGNvbXBhbnkgZmFjZXMgZ3JlYXRlciByZXRlbnRpb24gY2hhbGxlbmdlcyBhbW9uZyAqKm9wZXJhdGlvbmFsIGFuZCBqdW5pb3LigJFsZXZlbCBlbXBsb3llZXMqKiwgd2hlcmUgY29tcGVuc2F0aW9uIG1heSBub3QgZnVsbHkgbWVldCBtYXJrZXQgZXhwZWN0YXRpb25zLiAgCk1vcmUgKipjb21wZXRpdGl2ZSBwYXkgc3RyYXRlZ2llcyoqLCBjb21wbGVtZW50ZWQgYnkgKipjYXJlZXLigJFkZXZlbG9wbWVudCBhbmQgaW50ZXJuYWwgYWR2YW5jZW1lbnQgcGxhbnMqKiwgY291bGQgYmUgZGVjaXNpdmUgaW4gcmVkdWNpbmcgYXR0cml0aW9uIHdpdGhpbiB0aGVzZSBzYWxhcnkgZ3JvdXBzLgoKIyMgSm9iIEZ1bmN0aW9uIGFuZCBTYXRpc2ZhY3Rpb24gQW5hbHlzaXMKQmVmb3JlIHByb2NlZWRpbmcgdG8gdGhlIG51bWVyaWNhbCBjb3JyZWxhdGlvbnMsIGl0IGlzIGltcG9ydGFudCB0byBhbmFseXNlIHR3byBrZXkgY2F0ZWdvcmljYWwgdmFyaWFibGVzOiAqKkpvYiBSb2xlIChgSm9iUm9sZWApKiogYW5kICoqSm9iIFNhdGlzZmFjdGlvbiAoYEpvYlNhdGlzZmFjdGlvbmApKiouICAKClRoZSBnb2FsIGlzIHRvIGRldGVybWluZSB3aGV0aGVyIHNwZWNpZmljIGpvYiByb2xlcyBleGhpYml0IGhpZ2hlciBhdHRyaXRpb24gcmF0ZXMuCgpgYGB7ciBhbmFsaXNlX2NhcmdvX3NhdGlzZmFjYW99CiMgVHVybm92ZXIgYnkgSm9iIFJvbGUKcF9yb2xlIDwtIGdncGxvdChpYm1fY2xlYW4sIGFlcyh5ID0gcmVvcmRlcihqb2Jfcm9sZSwgKGF0dHJpdGlvbiA9PSAiWWVzIikpLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCB3aWR0aCA9IDAuNywgYWxwaGEgPSAwLjkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLCBleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiVHVybm92ZXIgYnkgSm9iIFJvbGUiLAogICAgc3VidGl0bGUgPSAiU2FsZXMsIEhSLCBhbmQgTGFib3JhdG9yeSBUZWNobmljaWFucyBzaG93IGhpZ2hlciByaXNrIiwKICAgIHkgPSBOVUxMLAogICAgeCA9ICJQcm9wb3J0aW9uIG9mIEF0dHJpdGlvbiIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTMsIGNvbG9yID0gIiMyYzNlNTAiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiKQogICkKCiMgSW1wYWN0IG9mIEpvYiBTYXRpc2ZhY3Rpb24KcF9zYXQgPC0gZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSBmYWN0b3Ioam9iX3NhdGlzZmFjdGlvbiksIGZpbGwgPSBhdHRyaXRpb24pKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMC42LCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJJbXBhY3Qgb2YgSm9iIFNhdGlzZmFjdGlvbiIsCiAgICBzdWJ0aXRsZSA9ICJMb3cgc2F0aXNmYWN0aW9uIGxldmVscyAoMSBhbmQgMikgY29ycmVsYXRlIHdpdGggaGlnaGVyIGNodXJuIiwKICAgIHggPSAiU2F0aXNmYWN0aW9uIExldmVsICgxOiBMb3cg4oaSIDQ6IEhpZ2gpIiwKICAgIHkgPSAiUHJvcG9ydGlvbiIsCiAgICBmaWxsID0gIkxlZnQ/IgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMywgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKCmxpYnJhcnkoZ3JpZEV4dHJhKQpncmlkLmFycmFuZ2UocF9yb2xlLCBwX3NhdCwgbnJvdyA9IDIsIAogICAgICAgICAgICAgdG9wID0gZ3JpZDo6dGV4dEdyb2IoIkpvYiBSb2xlIGFuZCBTZW50aW1lbnQgQW5hbHlzaXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE2LCBmb250ID0gMiwgY29sID0gIiMyYzNlNTAiKSkpCmBgYAoKKipfSW5zaWdodHMgb24gSm9iIFJvbGUgYW5kIFNhdGlzZmFjdGlvbjpfKioKClRoZSBhbmFseXNpcyByZXZlYWxzICoqZGlzdGluY3QgYXR0cml0aW9uIHBhdHRlcm5zIGJ5IGpvYiBmdW5jdGlvbioqLCBoaWdobGlnaHRpbmcgY3JpdGljYWwgYXJlYXMgd2l0aGluIHRoZSBvcmdhbmlzYXRpb246CgoxLiAqKlNhbGVzIFJvbGVzIChfU2FsZXMgUmVwcmVzZW50YXRpdmVzXykqKiDigJMgVGhpcyBncm91cCBzaG93cyB0aGUgKipoaWdoZXN0IGF0dHJpdGlvbiByYXRlLCBhcm91bmQgNDAlKiosIHdoaWNoIHN1Z2dlc3RzICoqaGlnaCBjb21tZXJjaWFsIHByZXNzdXJlKiosIGRlbWFuZGluZyB0YXJnZXRzLCBvciAqKnVuYXR0cmFjdGl2ZSBpbmNlbnRpdmUgc3RydWN0dXJlcyoqLiBHaXZlbiB0aGVpciBzdHJhdGVnaWMgaW1wb3J0YW5jZSB0byB0aGUgY29tcGFueeKAmXMgb3ZlcmFsbCBwZXJmb3JtYW5jZSwgdGhpcyBncm91cCBzaG91bGQgYmUgdHJlYXRlZCBhcyBhICoqdG9wIHByaW9yaXR5IGZvciByZXRlbnRpb24gaW5pdGlhdGl2ZXMqKi4gIAoKMi4gKipMYWJvcmF0b3J5IFRlY2huaWNpYW5zIGFuZCBIdW1hbiBSZXNvdXJjZXMqKiDigJMgQm90aCBmdW5jdGlvbnMgc2hvdyAqKmF0dHJpdGlvbiByYXRlcyBhcm91bmQgMjUlKiosIGNsZWFybHkgYWJvdmUgdGhlIG9yZ2FuaXNhdGlvbmFsIGF2ZXJhZ2UuICAKCjMuICoqTGVhZGVyc2hpcCBSZXRlbnRpb24qKiDigJMgTWFuYWdlcmlhbCBhbmQgZXhlY3V0aXZlIHJvbGVzIChfTWFuYWdlcnNfIGFuZCBfRGlyZWN0b3JzXykgZGVtb25zdHJhdGUgKip2ZXJ5IGhpZ2ggc3RhYmlsaXR5KiosIHN1Z2dlc3RpbmcgdGhhdCB0dXJub3ZlciBpcyBtYWlubHkgY29uY2VudHJhdGVkIGF0ICoqbWlk4oCRbGV2ZWwgYW5kIG9wZXJhdGlvbmFsIHBvc2l0aW9ucyoqLiAgClRoaXMgcGF0dGVybiBlbXBoYXNpc2VzIHRoZSBpbXBvcnRhbmNlIG9mIGRlc2lnbmluZyAqKnJldGVudGlvbiBhbmQgZGV2ZWxvcG1lbnQgc3RyYXRlZ2llcyBzcGVjaWZpY2FsbHkgdGFyZ2V0ZWQgYXQgdGhlIG1vc3QgdnVsbmVyYWJsZSByb2xlcyoqLgoKKipDb25jbHVzaW9uOioqICAKQXR0cml0aW9uIGFwcGVhcnMgdG8gYmUgY29uY2VudHJhdGVkIGluICoqZW50cnnigJFsZXZlbCBhbmQgb3BlcmF0aW9uYWwgc3VwcG9ydCByb2xlcyoqLCByZXF1aXJpbmcgcG9saWNpZXMgb3JpZW50ZWQgdG93YXJkIGltcHJvdmluZyB0aGUgKipvcmdhbmlzYXRpb25hbCBjbGltYXRlKiosICoqcmV2aWV3aW5nIGluY2VudGl2ZSBzeXN0ZW1zKiosIGFuZCAqKmV4cGFuZGluZyBjYXJlZXLigJFncm93dGggb3Bwb3J0dW5pdGllcyoqIGluIG9yZGVyIHRvIHN0cmVuZ3RoZW4gY29tbWl0bWVudCBhbmQgcmV0ZW50aW9uIHdpdGhpbiB0aGVzZSBncm91cHMuCgojIyBUZW51cmUgYW5kIENvbW11dGUgVGltZSBBbmFseXNpcyAgCkVtcGxveWVlIHRlbnVyZSAoYFllYXJzQXRDb21wYW55YCkgYW5kIGNvbW11dGluZyBkaXN0YW5jZSAoYERpc3RhbmNlRnJvbUhvbWVgKSB3ZXJlIGFuYWx5c2VkIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBjb21wYW55IGxvc2VzIHJlY2VudGx5IGhpcmVkIHRhbGVudCBhbmQgd2hldGhlciBkYWlseSBjb21tdXRpbmcgaW5mbHVlbmNlcyB0aGUgZGVjaXNpb24gdG8gbGVhdmUuCgpgYGB7ciBhbmFsaXNlX2FudGlndWlkYWRlX2Rpc3RhbmNpYX0KIyBQbG90OiBUZW51cmUgKFllYXJzIGF0IHRoZSBDb21wYW55KQpwX3llYXJzIDwtIGdncGxvdChpYm1fY2xlYW4sIGFlcyh4ID0geWVhcnNfYXRfY29tcGFueSwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjcsIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgbGFicygKICAgIHRpdGxlID0gIkxpZmUgQ3ljbGU6IEVtcGxveWVlIFRlbnVyZSIsCiAgICBzdWJ0aXRsZSA9ICJDaHVybiByaXNrIGlzIGNyaXRpY2FsIHdpdGhpbiB0aGUgZmlyc3QgMiB5ZWFycyAob25ib2FyZGluZyBwZXJpb2QpIiwKICAgIHggPSAiWWVhcnMgYXQgQ29tcGFueSIsCiAgICB5ID0gIkRlbnNpdHkiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBQbG90OiBEaXN0YW5jZSBmcm9tIEhvbWUgKEJveHBsb3QpCnBfZGlzdCA8LSBnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IGF0dHJpdGlvbiwgeSA9IGRpc3RhbmNlX2Zyb21faG9tZSwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjgsIHdpZHRoID0gMC42LCBvdXRsaWVyLmNvbG91ciA9ICIjRTc0QzNDIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgbGFicygKICAgIHRpdGxlID0gIkxvZ2lzdGljczogSG9tZS10by1Xb3JrIERpc3RhbmNlIiwKICAgIHN1YnRpdGxlID0gIkVtcGxveWVlcyB3aG8gbGVhdmUgdGVuZCB0byB0cmF2ZWwgbG9uZ2VyIGRpc3RhbmNlcyIsCiAgICB4ID0gIkF0dHJpdGlvbiBEZWNpc2lvbiIsCiAgICB5ID0gIkRpc3RhbmNlIChrbS9taWxlcykiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCgojIEFycmFuZ2UgYm90aCBwbG90cwpsaWJyYXJ5KGdyaWRFeHRyYSkKZ3JpZC5hcnJhbmdlKHBfeWVhcnMsIHBfZGlzdCwgbnJvdyA9IDIsIAogICAgICAgICAgICAgdG9wID0gZ3JpZDo6dGV4dEdyb2IoIlJldGVudGlvbiBhbmQgTG9naXN0aWNzIEFuYWx5c2lzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxNiwgZm9udCA9IDIsIGNvbCA9ICIjMmMzZTUwIikpKQpgYGAKCioqX0luc2lnaHRzIG9uIFRlbnVyZSBhbmQgTG9naXN0aWNzOl8qKgoKVGhlIGFuYWx5c2lzIGhpZ2hsaWdodHMgKipjcml0aWNhbCBwb2ludHMgaW4gdGhlIGVtcGxveWVlIGxpZmUgY3ljbGUqKiwgd2l0aCBkaXJlY3QgaW1wbGljYXRpb25zIGZvciBvcmdhbmlzYXRpb25hbCByZXRlbnRpb24gYW5kIHBlcmZvcm1hbmNlOgoKMS4gKipPbmJvYXJkaW5nIFBoYXNlIOKAkyBFYXJseSBFeGl0IFJpc2sqKjogIApUaGUgdGVudXJlIHBsb3Qgc2hvd3MgYSBzaGFycCBwZWFrIGluIGF0dHJpdGlvbiB3aXRoaW4gdGhlIGZpcnN0IHR3byB5ZWFycyBvZiBlbXBsb3ltZW50LCBwcmVjaXNlbHkgZHVyaW5nIHRoZSBpbnRlZ3JhdGlvbiBhbmQgYWRhcHRhdGlvbiBwZXJpb2QuICAKVGhpcyByZXN1bHQgc3VnZ2VzdHMgd2Vha25lc3NlcyBpbiBvbmJvYXJkaW5nIHByb2Nlc3NlcywgZWFybHkgc3VwZXJ2aXNpb24sIG9yIGFsaWdubWVudCBvZiBleHBlY3RhdGlvbnMgYmV0d2VlbiB0aGUgZW1wbG95ZWUgYW5kIHRoZSBvcmdhbmlzYXRpb24uIEludmVzdGluZyBpbiAqKnN0cnVjdHVyZWQgb25ib2FyZGluZyBhbmQgbWVudG9yc2hpcCBwcm9ncmFtbWVzKiogY2FuIHN1YnN0YW50aWFsbHkgcmVkdWNlIHRoaXMgdHlwZSBvZiBwcmVtYXR1cmUgdGFsZW50IGxvc3MuICAKCjIuICoqQ29tbXV0aW5nIENvc3Qg4oCTIEEgTG9naXN0aWNhbCBTdHJhaW4gRmFjdG9yKio6ICAKVGhlIGhvbWXigJF0b+KAkXdvcmsgZGlzdGFuY2UgYm94cGxvdCByZXZlYWxzIHRoYXQgZW1wbG95ZWVzIHdobyBsZWF2ZSB0ZW5kIHRvIGNvbW11dGUgbG9uZ2VyIGRpc3RhbmNlcywgc2lnbmFsbGluZyBhIHBvdGVudGlhbCBuZWdhdGl2ZSBpbXBhY3Qgb2YgdHJhdmVsIHRpbWUgYW5kIGVmZm9ydCBvbiBvdmVyYWxsIHNhdGlzZmFjdGlvbi4gIApUaGUgd2VhciBhbmQgdGVhciBhc3NvY2lhdGVkIHdpdGggZGFpbHkgY29tbXV0aW5nIOKAlCBlc3BlY2lhbGx5IHdoZW4gY29tYmluZWQgd2l0aCBoZWF2eSB3b3JrbG9hZHMg4oCUIGluY3JlYXNlcyB0aGUgcHJvYmFiaWxpdHkgb2Ygdm9sdW50YXJ5IHR1cm5vdmVyLgpNZWFzdXJlcyBzdWNoIGFzICoqaHlicmlkIHdvcmsgbW9kZWxzKiosICoqZmxleGlibGUgc2NoZWR1bGluZyoqLCBvciAqKnRyYW5zcG9ydCBpbmNlbnRpdmVzKiogY2FuIGhlbHAgbWl0aWdhdGUgdGhpcyBlZmZlY3QuICAKCioqQ29uY2x1c2lvbjoqKiAgCkVmZmVjdGl2ZSByZXRlbnRpb24gcmVxdWlyZXMgYSAqKmhvbGlzdGljIGFwcHJvYWNoKiogdGhhdCBhZGRyZXNzZXMgYm90aCB0aGUgKippbml0aWFsIGVtcGxveWVlIGV4cGVyaWVuY2UgKG9uYm9hcmRpbmcpKiogYW5kIHRoZSAqKmxvZ2lzdGljYWwgc3VzdGFpbmFiaWxpdHkqKiBvZiB0aGVpciB3b3JrIHJvdXRpbmUuICAKVGhlc2UgdHdvIGRpbWVuc2lvbnMgYXJlIGNydWNpYWwgZm9yIGNvbnNvbGlkYXRpbmcgb3JnYW5pc2F0aW9uYWwgY29tbWl0bWVudCBkdXJpbmcgdGhlIGVhcmx5IHllYXJzIG9mIHRlbnVyZS4KCiMjIEdlbmRlciBhbmQgV29yay1MaWZlIEJhbGFuY2UgQW5hbHlzaXMKCmBgYHtyIGFuYWxpc2VfZ2VuZXJvX3d9CiMgVHVybm92ZXIgYnkgR2VuZGVyIChwX2dlbikKcF9nZW4gPC0gZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSBnZW5kZXIsIGZpbGwgPSBhdHRyaXRpb24pKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMC42LCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUdXJub3ZlciBieSBHZW5kZXIiLCAKICAgIHN1YnRpdGxlID0gIklzIHRoZXJlIGEgZGlzcGFyaXR5IGJldHdlZW4gbWVuIGFuZCB3b21lbj8iLAogICAgeCA9IE5VTEwsIAogICAgeSA9ICJQcm9wb3J0aW9uIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsICMgSGlkZSBsZWdlbmQgaGVyZSB0byBhdm9pZCByZXBldGl0aW9uCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMywgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICApCgojIFdvcmstTGlmZSBCYWxhbmNlIEFuYWx5c2lzIChwX3dsYikKcF93bGIgPC0gZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSBmYWN0b3Iod29ya19saWZlX2JhbGFuY2UpLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCB3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLCBleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiV29yay1MaWZlIEJhbGFuY2UiLCAKICAgIHN1YnRpdGxlID0gIlRoZSBpbXBhY3Qgb2Ygd29yay1saWZlIGJhbGFuY2Ugb24gYXR0cml0aW9uIGRlY2lzaW9ucyIsCiAgICB4ID0gIkxldmVsICgxOiBQb29yIOKGkiA0OiBFeGNlbGxlbnQpIiwgCiAgICB5ID0gTlVMTCwKICAgIGZpbGwgPSAiTGVmdD8iCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICApCgojIEFycmFuZ2UgYm90aCBzaWRlIGJ5IHNpZGUKbGlicmFyeShncmlkRXh0cmEpCmdyaWQuYXJyYW5nZShwX2dlbiwgcF93bGIsIG5jb2wgPSAyLCAKICAgICAgICAgICAgIHRvcCA9IGdyaWQ6OnRleHRHcm9iKCJXZWxsLUJlaW5nIGFuZCBEaXZlcnNpdHkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE2LCBmb250ID0gMiwgY29sID0gIiMyYzNlNTAiKSkpCmBgYAoKKipfSW5zaWdodHMgb24gR2VuZGVyIGFuZCBXZWxsLUJlaW5nOl8qKgoKVG8gY29uY2x1ZGUgdGhlIGJpdmFyaWF0ZSBhbmFseXNpcywgdHdvICoqc29jaWFsIGFuZCBiZWhhdmlvdXJhbCBmYWN0b3JzKiogc3RhbmQgb3V0IGFzIHJlbGV2YW50IHRvIGVtcGxveWVlIGF0dHJpdGlvbjoKCjEuICoqR2VuZGVyIE5ldXRyYWxpdHkqKiDigJMgVGhlIGF0dHJpdGlvbiByYXRlIGFwcGVhcnMgKipyZWxhdGl2ZWx5IHVuaWZvcm0gYmV0d2VlbiBtZW4gYW5kIHdvbWVuKiosIHJhbmdpbmcgZnJvbSAxNSUgdG8gMTclLiBUaGlzIHJlc3VsdCBzdWdnZXN0cyB0aGUgKiphYnNlbmNlIG9mIGJpYXMgb3IgZGlzY3JpbWluYXRvcnkgcHJhY3RpY2VzKiogYXNzb2NpYXRlZCB3aXRoIGdlbmRlciBhbmQgaW5kaWNhdGVzICoqZXF1aXRhYmxlIG9yZ2FuaXNhdGlvbmFsIGV4cGVyaWVuY2VzKiogYWNyb3NzIGdyb3Vwcy4gIAoKMi4gKipXb3JrLUxpZmUgQmFsYW5jZSoqIOKAkyBUaGUgX1dvcmvigJFMaWZlIEJhbGFuY2VfIHZhcmlhYmxlIGV4aGliaXRzIGEg4oCcY3JpdGljYWwgcG9pbnTigJ0gYXQgdGhlIGxvd2VzdCBzYXRpc2ZhY3Rpb24gbGV2ZWwuIEVtcGxveWVlcyB3aG8gcmF0ZSB0aGVpciBiYWxhbmNlIGFzIOKAnFBvb3LigJ0gKExldmVsIDEpIHNob3cgYW4gYXR0cml0aW9uIHJhdGUgbmVhciAqKjMwJSoqLCAqKmRvdWJsZSoqIHRoYXQgb2JzZXJ2ZWQgaW4gdGhlIG90aGVyIGxldmVscy4gIApJbXByb3Zpbmcgd29ya+KAkWxpZmUgYmFsYW5jZSBldmVuIG1hcmdpbmFsbHkg4oCUIGZvciBleGFtcGxlLCBmcm9tIExldmVsIDEgdG8gTGV2ZWwgMiDigJQgcHJvZHVjZXMgYSBzdWJzdGFudGlhbCByZWR1Y3Rpb24gaW4gdHVybm92ZXIgcmF0ZXMuICAKVGhpcyBpbmRpY2F0ZXMgdGhhdCAqKnRhcmdldGVkIGFuZCByZWFsaXN0aWMgaW50ZXJ2ZW50aW9ucyoqLCBzdWNoIGFzIGZsZXhpYmxlIHNjaGVkdWxlcywgaHlicmlk4oCRd29yayBwb2xpY2llcywgb3IgZW5oYW5jZWQgdGVhbSBzdXBwb3J0LCBjYW4gaGF2ZSAqKmltbWVkaWF0ZSBwb3NpdGl2ZSBlZmZlY3RzKiogb24gcmV0ZW50aW9uLCB3aXRob3V0IG5lY2Vzc2FyaWx5IGFjaGlldmluZyBpZGVhbCBzYXRpc2ZhY3Rpb24gbGV2ZWxzIChMZXZlbCA0KS4gIAoKKipDb25jbHVzaW9uOioqICAKVGhlIGZpbmRpbmdzIGluZGljYXRlIGEgKipnZW5kZXLigJFiYWxhbmNlZCBvcmdhbmlzYXRpb25hbCBjdWx0dXJlKiosIHlldCBvbmUgdGhhdCByZW1haW5zICoqdnVsbmVyYWJsZSB0byB3ZWxs4oCRYmVpbmcgYW5kIHdvcmvigJFsaWZlIGJhbGFuY2UgZmFjdG9ycyoqLiAgCkludmVzdG1lbnQgaW4gKipvY2N1cGF0aW9uYWwgaGVhbHRoKiosICoqZmxleGlibGXigJF3b3JrIGFycmFuZ2VtZW50cyoqLCBhbmQgKiplbXBsb3llZeKAkWNhcmUgaW5pdGlhdGl2ZXMqKiB3aWxsIGxpa2VseSB5aWVsZCBkaXJlY3QgcmV0dXJucyBpbiB0ZXJtcyBvZiBlbXBsb3llZSBzYXRpc2ZhY3Rpb24gYW5kIHJldGVudGlvbi4gIAoKIyBNdWx0aXZhcmlhdGUgQW5hbHlzaXMgKENvcnJlbGF0aW9ucykKQXQgdGhpcyBzdGFnZSwgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBudW1lcmljYWwgdmFyaWFibGVzIHdlcmUgZXhhbWluZWQgdG8gaWRlbnRpZnkgKiptdWx0aWNvbGxpbmVhcml0eSoqIChyZWR1bmRhbmN5KS4gIApBIHZpc3VhbCAqKmNvcnJlbGF0aW9uIG1hdHJpeCoqIHdhcyB1c2VkIGZvciB0aGlzIHB1cnBvc2UuCgpgYGB7cn0KaWJtX251bWVyaWMgPC0gaWJtX2NsZWFuICU+JSBzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpCmNvcl9tYXRyaXggIDwtIGNvcihpYm1fbnVtZXJpYywgdXNlID0gImNvbXBsZXRlLm9icyIpCgojIENvcnJlbGF0aW9uIFBsb3QKY29sb3JfcGFsZXR0ZSA8LSBjb2xvclJhbXBQYWxldHRlKGMoIiNFNzRDM0MiLCAiI0ZGRkZGRiIsICIjMkMzRTUwIikpKDIwMCkKCmNvcnJwbG90KGNvcl9tYXRyaXgsIAogICAgICAgICBtZXRob2QgPSAiY29sb3IiLCAKICAgICAgICAgdHlwZSA9ICJ1cHBlciIsIAogICAgICAgICBvcmRlciA9ICJoY2x1c3QiLCAgICAgICAgIAogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCAKICAgICAgICAgdGwuY2V4ID0gMC43LCAKICAgICAgICAgY29sID0gY29sb3JfcGFsZXR0ZSwgICAgICAgICAKICAgICAgICAgdGl0bGUgPSAiXG4gSW50ZXJ2YXJpYWJsZSBDb3JyZWxhdGlvbiBNYXAiLCAKICAgICAgICAgbWFyID0gYygwLCAwLCAyLCAwKSwKICAgICAgICAgZGlhZyA9IEZBTFNFKQoKIyBDb3JyZWxhdGlvbiBUYWJsZQpjb3JfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShhcy50YWJsZShjb3JfbWF0cml4KSkKCmNvcl90YWJsZV9yZWZpbmVkIDwtIGNvcl90YWJsZSAlPiUKICBmaWx0ZXIoVmFyMSAhPSBWYXIyKSAlPiUKICBmaWx0ZXIoIWR1cGxpY2F0ZWQocGFzdGUwKAogICAgcG1heChhcy5jaGFyYWN0ZXIoVmFyMSksIGFzLmNoYXJhY3RlcihWYXIyKSksIAogICAgcG1pbihhcy5jaGFyYWN0ZXIoVmFyMSksIGFzLmNoYXJhY3RlcihWYXIyKSkKICApKSkgJT4lCiAgYXJyYW5nZShkZXNjKGFicyhGcmVxKSkpICU+JQogIHJlbmFtZShWYXJpYWJsZV8xID0gVmFyMSwgVmFyaWFibGVfMiA9IFZhcjIsIENvcnJlbGF0aW9uID0gRnJlcSkKCiMgSW1wcm92ZSBUYWJsZSBEZXNpZ24Ka2FibGUoaGVhZChjb3JfdGFibGVfcmVmaW5lZCwgMTApLCAKICAgICAgY2FwdGlvbiA9ICJUb3AgMTAgU3Ryb25nZXN0IENvcnJlbGF0aW9ucyBJZGVudGlmaWVkIiwgCiAgICAgIGRpZ2l0cyA9IDIsCiAgICAgIGNvbC5uYW1lcyA9IGMoIlZhcmlhYmxlIDEiLCAiVmFyaWFibGUgMiIsICJDb3JyZWxhdGlvbiBTdHJlbmd0aCIpKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLCAKICAgIGZ1bGxfd2lkdGggPSBUUlVFLCAgICAgICAgICAgCiAgICBwb3NpdGlvbiA9ICJjZW50ZXIiLCAgICAgIAogICAgZm9udF9zaXplID0gMTQgICAgICAgICAgICAKICApICU+JQogIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzJjM2U1MCIpICU+JQogICMgSGlnaGxpZ2h0IGluIHJlZCBjb3JyZWxhdGlvbnMgdGhhdCBtYXkgY2F1c2UgbXVsdGljb2xsaW5lYXJpdHkgKD4gMC43KQogIGNvbHVtbl9zcGVjKDMsIGJvbGQgPSBUUlVFLCAKICAgICAgICAgICAgICBjb2xvciA9IGlmZWxzZShhYnMoaGVhZChjb3JfdGFibGVfcmVmaW5lZCRDb3JyZWxhdGlvbiwgMTApKSA+IDAuNywgIiNFNzRDM0MiLCAiYmxhY2siKSkKYGBgCgoqKl9JbnNpZ2h0cyBmcm9tIHRoZSBDb3JyZWxhdGlvbiBBbmFseXNpczpfKioKClRoZSBjb3JyZWxhdGlvbiBtYXRyaXggYW5kIHRhYmxlIHJldmVhbCBjbGVhciBwYXR0ZXJucyBvZiAqKm11bHRpY29sbGluZWFyaXR5KiosIGV4cG9zaW5nIHZhcmlhYmxlcyB0aGF0IGFyZSAqKnN0cm9uZ2x5IHJlZHVuZGFudCoqIGFuZCB3aWxsIHJlcXVpcmUgc3BlY2lmaWMgdHJlYXRtZW50IGR1cmluZyB0aGUgKipkYXRhIHByZXByb2Nlc3NpbmcqKiBzdGFnZToKCjEuICoqUmVkdW5kYW5jeSBiZXR3ZWVuIHNhbGFyeSBhbmQgam9iIGxldmVsKiog4oCTIFRoZSBzdHJvbmdlc3QgY29ycmVsYXRpb24gaW4gdGhlIGRhdGFzZXQgaXMgb2JzZXJ2ZWQgYmV0d2VlbiBgTW9udGhseUluY29tZWAgYW5kIGBKb2JMZXZlbGAgKHIgPSAwLjk1KS4gIAogICAqKkludGVycHJldGF0aW9uOioqIFRoZXNlIHZhcmlhYmxlcyBhcmUsIGluIHByYWN0aWNlLCBzdGF0aXN0aWNhbGx5IG92ZXJsYXBwaW5nIOKAlCB0aGUgam9iIGxldmVsIGFsbW9zdCBlbnRpcmVseSBkaWN0YXRlcyB0aGUgc2FsYXJ5LiAgCiAgIEtlZXBpbmcgYm90aCBpbiB0aGUgbW9kZWwgbWF5IGludHJvZHVjZSBjb2VmZmljaWVudCBpbnN0YWJpbGl0eSBhbmQgZGlzdG9ydCB0aGUgcHJlZGljdGl2ZSBpbXBvcnRhbmNlIG9mIGZlYXR1cmVzLiBJdCBpcyB0aGVyZWZvcmUgYWR2aXNhYmxlIHRvIHJldGFpbiBvbmx5IG9uZSByZXByZXNlbnRhdGl2ZSB2YXJpYWJsZSAoZS5nLiwgYEpvYkxldmVsYCkuICAKCjIuICoqVGVudXJlIGNsdXN0ZXIqKiDigJMgQSBjbHVzdGVyIG9mIGhpZ2hseSBjb3JyZWxhdGVkIHRpbWXigJFyZWxhdGVkIHZhcmlhYmxlcyB3YXMgaWRlbnRpZmllZDogYFllYXJzQXRDb21wYW55YCwgYFllYXJzSW5DdXJyZW50Um9sZWAsIGFuZCBgWWVhcnNXaXRoQ3Vyck1hbmFnZXJgLCB3aXRoIGNvcnJlbGF0aW9ucyByYW5naW5nIGJldHdlZW4gMC43MSBhbmQgMC43Ny4gIAogICAqKkludGVycHJldGF0aW9uOioqIEVtcGxveWVlcyB3aXRoIGxvbmdlciB0ZW51cmUgdGVuZCB0byByZW1haW4gaW4gdGhlIHNhbWUgcm9sZSB1bmRlciB0aGUgc2FtZSBtYW5hZ2VyLiBUbyBhdm9pZCByZWR1bmRhbmN5LCBpdCBpcyBwcmVmZXJhYmxlIHRvIGluY2x1ZGUgb25seSBvbmUgb2YgdGhlc2UgdmFyaWFibGVzIChlLmcuLCBgWWVhcnNBdENvbXBhbnlgKSBvciBjcmVhdGUgYW4gKiphZ2dyZWdhdGVkIOKAnGNhcmVlciBzdGFnbmF0aW9u4oCdIHZhcmlhYmxlKiogdG8gY2FwdHVyZSB0aGlzIGR5bmFtaWMuICAKCjMuICoqUHJvZmVzc2lvbmFsIGV4cGVyaWVuY2UgYW5kIGNvbXBlbnNhdGlvbioqIOKAkyBUaGUgdmFyaWFibGUgYFRvdGFsV29ya2luZ1llYXJzYCBzaG93cyBzdHJvbmcgY29ycmVsYXRpb25zIHdpdGggYm90aCBgSm9iTGV2ZWxgICgwLjc4KSBhbmQgYE1vbnRobHlJbmNvbWVgICgwLjc3KS4gIAogICAqKkludGVycHJldGF0aW9uOioqIFRoZSBjb21wYW554oCZcyBwcm9ncmVzc2lvbiBhbmQgY29tcGVuc2F0aW9uIHN5c3RlbSBhcHBlYXJzIHRvIGJlICoqaGlnaGx5IGFsaWduZWQgd2l0aCBzZW5pb3JpdHkqKiwgdmFsdWluZyBwcmltYXJpbHkgYWNjdW11bGF0ZWQgZXhwZXJpZW5jZS4gIAoKNC4gKipQZXJmb3JtYW5jZSBhbmQgcmV3YXJkcyoqIOKAkyBUaGUgY29ycmVsYXRpb24gb2YgMC43NyBiZXR3ZWVuIGBQZXJmb3JtYW5jZVJhdGluZ2AgYW5kIGBQZXJjZW50U2FsYXJ5SGlrZWAgY29uZmlybXMgdGhhdCBzYWxhcnkgaW5jcmVhc2VzIGFyZSAqKmRpcmVjdGx5IGxpbmtlZCB0byBhbm51YWwgcGVyZm9ybWFuY2UgZXZhbHVhdGlvbioqLCByZWZsZWN0aW5nIGEgdHlwaWNhbCBtZXJpdG9jcmF0aWMgcG9saWN5LiAgCgoqKkNvbmNsdXNpb24gb2YgdGhlIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSk6KiogIApUaGUgYml2YXJpYXRlIGFuZCBjb3JyZWxhdGlvbiBhbmFseXNlcyBpbmRpY2F0ZSB0aGF0ICoqZW1wbG95ZWUgYXR0cml0aW9uIGlzIGFzc29jaWF0ZWQgd2l0aCBkZW1vZ3JhcGhpYyBhbmQgam9i4oCRcmVsYXRlZCBmYWN0b3JzKiogKHlvdW5nZXIgYWdlLCBvcGVyYXRpb25hbCByb2xlcywgZnJlcXVlbnQgdHJhdmVsLCBhbmQgbG93ZXIgc2FsYXJpZXMpLiAgCkF0IHRoZSB0ZWNobmljYWwgbGV2ZWwsIHN0cm9uZyByZWxhdGlvbnNoaXBzIHdlcmUgZm91bmQgYW1vbmcgdmFyaWFibGVzIHJlbGF0ZWQgdG8gKipoaWVyYXJjaHksIHRlbnVyZSwgYW5kIHJlbXVuZXJhdGlvbioqLCB3aGljaCB3aWxsIG5lZWQgdG8gYmUgaGFuZGxlZCBpbiBwcmVwcm9jZXNzaW5nLgoKVGhlc2UgZmluZGluZ3MgZXN0YWJsaXNoIHRoZSBmb3VuZGF0aW9uIGZvciB0aGUgKipkYXRhIHByZXByb2Nlc3NpbmcgcGhhc2UqKiwgd2hlcmUgZXhjZXNzaXZlIGNvcnJlbGF0aW9ucyB3aWxsIGJlIGFkZHJlc3NlZCBhbmQgdGhlICoqbW9zdCByZWxldmFudCB2YXJpYWJsZXMqKiBzZWxlY3RlZCBmb3IgcHJlZGljdGl2ZSBtb2RlbGxpbmcuCgojIERhdGEgUHJlcHJvY2Vzc2luZwojIyBGZWF0dXJlIFNlbGVjdGlvbgoKYGBge3J9CiMgRXhlY3V0ZSBGZWF0dXJlIFNlbGVjdGlvbgppYm1fcHJlcCA8LSBpYm1fY2xlYW4gJT4lCiAgc2VsZWN0KC1qb2JfbGV2ZWwpICU+JSAgCiAgc2VsZWN0KC1hbnlfb2YoYygiZW1wbG95ZWVfbnVtYmVyIiwgImVtcGxveWVlX2NvdW50IiwgIm92ZXIxOCIsICJzdGFuZGFyZF9ob3VycyIpKSkgJT4lCiAgbXV0YXRlKGF0dHJpdGlvbiA9IGlmZWxzZShhdHRyaXRpb24gPT0gIlllcyIsIDEsIDApKQoKIyBDcmVhdGUgU3VtbWFyeSBUYWJsZQpwcmVwX3N1bW1hcnkgPC0gZGF0YS5mcmFtZSgKICBTdGVwID0gYygiT3JpZ2luYWwgQ29sdW1ucyIsICJDb2x1bW5zIFJlbW92ZWQiLCAiRmluYWwgVG90YWwiLCAiVGFyZ2V0IChBdHRyaXRpb24pIiksCiAgVmFsdWUgPSBjKG5jb2woaWJtX2NsZWFuKSwgCiAgICAgICAgICAgIG5jb2woaWJtX2NsZWFuKSAtIG5jb2woaWJtX3ByZXApLCAKICAgICAgICAgICAgbmNvbChpYm1fcHJlcCksIAogICAgICAgICAgICAiQ29udmVydGVkIHRvIEJpbmFyeSAoMC8xKSIpCikKCnByZXBfc3VtbWFyeSAlPiUKICBrYWJsZShjYXB0aW9uID0gIlN1bW1hcnkgb2YgUHJlcHJvY2Vzc2luZyBhbmQgRmVhdHVyZSBTZWxlY3Rpb24iKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFCiAgKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKQpgYGAKCkFmdGVyIHRoZSBleHBsb3JhdG9yeSBhbmFseXNpcyBwaGFzZSwgdGhlIGRhdGEgd2VyZSBwcmVwYXJlZCBmb3IgKipwcmVkaWN0aXZlIG1vZGVsbGluZyoqLgoKVGhpcyBzdGFnZSBpcyBlc3NlbnRpYWwgdG8gZW5zdXJlIHRoYXQgdGhlIHJlc3VsdGluZyBtb2RlbCBpcyBub3QgaW5mbHVlbmNlZCBieSAqKnN0YXRpc3RpY2FsIG5vaXNlKiogb3IgKipyZWR1bmRhbnQgaW5mb3JtYXRpb24qKiwgdGh1cyBndWFyYW50ZWVpbmcgYm90aCAqKnJvYnVzdG5lc3MqKiBhbmQgKippbnRlcnByZXRhYmlsaXR5Kiogb2YgcmVzdWx0cy4KCktleSBkZWNpc2lvbnMgaW4gdGhpcyBwaGFzZToKCjEuICoqRWxpbWluYXRpb24gb2YgcmVkdW5kYW5jeSAobXVsdGljb2xsaW5lYXJpdHkpKiog4oCTIEFzIGlkZW50aWZpZWQgaW4gdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCwgdGhlIHZhcmlhYmxlcyBgbW9udGhseV9pbmNvbWVgIGFuZCBgam9iX2xldmVsYCBzaG93ZWQgYSBzdHJvbmcgY29ycmVsYXRpb24gb2YgMC45NS4gIAogICBUbyBhdm9pZCAqKm92ZXJmaXR0aW5nKiogYW5kIHNpbXBsaWZ5IHRoZSBtb2RlbCwgb25seSB0aGUgbW9zdCByZXByZXNlbnRhdGl2ZSB2YXJpYWJsZSB3YXMgcmV0YWluZWQsIHByaW9yaXRpc2luZyBkaXJlY3QgZmluYW5jaWFsIGltcGFjdC4KCjIuICoqQ29udmVyc2lvbiBvZiB0aGUgdGFyZ2V0IHZhcmlhYmxlKiog4oCTIFRoZSB2YXJpYWJsZSBgYXR0cml0aW9uYCB3YXMgdHJhbnNmb3JtZWQgaW50byBhICoqYmluYXJ5IGZvcm1hdCAoMC8xKSoqLCBhbGxvd2luZyBzdXBlcnZpc2VkIGNsYXNzaWZpY2F0aW9uIGFsZ29yaXRobXMgdG8gYmUgYXBwbGllZCBhbmQgc2ltcGxpZnlpbmcgdGhlIGV2YWx1YXRpb24gb2YgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZS4KClRoZXNlIG9wZXJhdGlvbnMgZW5zdXJlIHRoYXQgdGhlIGZpbmFsIGRhdGFzZXQgaXMgKipzdGF0aXN0aWNhbGx5IGJhbGFuY2VkKiosICoqY29tcHV0YXRpb25hbGx5IGVmZmljaWVudCoqLCBhbmQgKipyZWFkeSBmb3IgdGhlIG5leHQgc3RhZ2Ugb2YgbW9kZWxsaW5nKiouCgojIyBEdW1teSBWYXJpYWJsZSBDcmVhdGlvbgpgYGB7cn0KbGlicmFyeShmYXN0RHVtbWllcykKCmlibV9maW5hbCA8LSBkdW1teV9jb2xzKGlibV9wcmVwLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX2ZpcnN0X2R1bW15ID0gVFJVRSwgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX3NlbGVjdGVkX2NvbHVtbnMgPSBUUlVFKSAlPiUKICAgICAgICAgICAgIGNsZWFuX25hbWVzKCkgIyBFbnN1cmVzIHRoZSBuZXcgY29sdW1uIG5hbWVzIGFyZSBzdGFuZGFyZGlzZWQKCiMgQ3JlYXRlIGEgdmlzdWFsIGNvbXBhcmlzb24KZGltX2NvbXBhcmlzb24gPC0gZGF0YS5mcmFtZSgKICBNZXRyaWMgPSBjKCJDb2x1bW5zIEJlZm9yZSBEdW1taWVzIiwgIkNvbHVtbnMgQWZ0ZXIgRHVtbWllcyAoRXhwYW5kZWQpIiwgIk5ldyBWYXJpYWJsZXMgQ3JlYXRlZCIpLAogIFF1YW50aXR5ID0gYyhuY29sKGlibV9wcmVwKSwgbmNvbChpYm1fZmluYWwpLCBuY29sKGlibV9maW5hbCkgLSBuY29sKGlibV9wcmVwKSkKKQoKIyBEaXNwbGF5IGltcGFjdCB0YWJsZQpkaW1fY29tcGFyaXNvbiAlPiUKICBrYWJsZShjYXB0aW9uID0gIkltcGFjdCBvZiBDYXRlZ29yaWNhbCBWYXJpYWJsZSBUcmFuc2Zvcm1hdGlvbiAoT25lLUhvdCBFbmNvZGluZykiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKQoKIyBTaG93IGV4YW1wbGVzIG9mIG5ldyBjb2x1bW5zCmRhdGEuZnJhbWUoTmV3X0NvbHVtbnNfRXhhbXBsZXMgPSBjb2xuYW1lcyhpYm1fZmluYWwpWyhuY29sKGlibV9wcmVwKSsxKToobmNvbChpYm1fcHJlcCkrNildKSAlPiUKICBrYWJsZSgpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAiYm9yZGVyZWQiLCBmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImZsb2F0X3JpZ2h0IikKYGBgCgpNb3N0IE1hY2hpbmUgTGVhcm5pbmcgYWxnb3JpdGhtcyBhcmUgKipub3QgYWJsZSB0byBwcm9jZXNzIHRleHR1YWwgdmFyaWFibGVzIGRpcmVjdGx5KiouCgpUbyBvdmVyY29tZSB0aGlzIGxpbWl0YXRpb24sIHRoZSAqKk9uZeKAkUhvdCBFbmNvZGluZyoqIHRlY2huaXF1ZSAoYWxzbyBrbm93biBhcyB0aGUgY3JlYXRpb24gb2YgKmR1bW15IHZhcmlhYmxlcyopIHdhcyBhcHBsaWVkLgoKUHJvY2VkdXJlcyBwZXJmb3JtZWQ6CgoxLiAqKlRyYW5zZm9ybWF0aW9uIG9mIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyoqIOKAkyBRdWFsaXRhdGl2ZSB2YXJpYWJsZXMgc3VjaCBhcyBgQnVzaW5lc3NUcmF2ZWxgIGFuZCBgRGVwYXJ0bWVudGAgd2VyZSBjb252ZXJ0ZWQgaW50byBtdWx0aXBsZSBiaW5hcnkgY29sdW1ucyAoMC8xKSwgcmVwcmVzZW50aW5nIHRoZSBwcmVzZW5jZSBvciBhYnNlbmNlIG9mIGVhY2ggZGlzdGluY3QgY2F0ZWdvcnkuCgoyLiAqKlByZXZlbnRpb24gb2YgbXVsdGljb2xsaW5lYXJpdHkqKiDigJMgVG8gYXZvaWQgdGhlIHNv4oCRY2FsbGVkIF9kdW1teSB2YXJpYWJsZSB0cmFwXywgdGhlIHBhcmFtZXRlciBgcmVtb3ZlX2ZpcnN0X2R1bW15ID0gVFJVRWAgd2FzIGFjdGl2YXRlZCwgcmVtb3Zpbmcgb25lIGNhdGVnb3J5IGZyb20gZWFjaCBncm91cC4gIAogICBGb3IgZXhhbXBsZSwgaW4gYSB2YXJpYWJsZSB3aXRoIHRoZSBtb2RhbGl0aWVzICpNYWxlKiBhbmQgKkZlbWFsZSosIG9ubHkgb25lIGlzIHJldGFpbmVkIHNpbmNlIHRoZSBhYnNlbmNlIG9mIG9uZSBhdXRvbWF0aWNhbGx5IGltcGxpZXMgdGhlIHByZXNlbmNlIG9mIHRoZSBvdGhlci4KCjMuICoqQ29udHJvbGxlZCBkYXRhc2V0IGV4cGFuc2lvbioqIOKAkyBBZnRlciB0aGUgcHJvY2VzcywgdGhlIHRvdGFsIG51bWJlciBvZiB2YXJpYWJsZXMgaW5jcmVhc2VkIGZyb20gMzAgdG8gNDQsIHJlc3VsdGluZyBpbiAxNCBuZXdseSBjcmVhdGVkIGRlcml2ZWQgdmFyaWFibGVzLgoKVGhpcyBleHBhbnNpb24gYWxsb3dzIGZvciBhIHJpY2hlciByZXByZXNlbnRhdGlvbiBvZiBxdWFsaXRhdGl2ZSBpbmZvcm1hdGlvbiAqKndpdGhvdXQgaW50cm9kdWNpbmcgcmVkdW5kYW5jeSoqIG9yIGNvbXByb21pc2luZyB0aGUgKipzdGFiaWxpdHkgb2YgcHJlZGljdGl2ZSBtb2RlbHMqKi4KCiMjIERhdGEgU3BsaXR0aW5nIChUcmFpbmluZyBhbmQgVGVzdGluZykKCmBgYHtyIGRhdGFfc3BsaXQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoY2FUb29scykKbGlicmFyeShkcGx5cikKbGlicmFyeShrYWJsZUV4dHJhKQoKIyBTdHJhdGlmaWVkIFNwbGl0CnNldC5zZWVkKDEyMykKc3BsaXQgPC0gc2FtcGxlLnNwbGl0KGlibV9maW5hbCRhdHRyaXRpb24sIFNwbGl0UmF0aW8gPSAwLjcwKQoKdHJhaW5fZGF0YSA8LSBzdWJzZXQoaWJtX2ZpbmFsLCBzcGxpdCA9PSBUUlVFKQp0ZXN0X2RhdGEgIDwtIHN1YnNldChpYm1fZmluYWwsIHNwbGl0ID09IEZBTFNFKQoKIyBDcmVhdGUgU3VtbWFyeSBUYWJsZQpzcGxpdF9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoCiAgRGF0YXNldCA9IGMoIlRyYWluaW5nICg3MCUpIiwgIlRlc3RpbmcgKDMwJSkiLCAiVG90YWwiKSwKICBPYnNlcnZhdGlvbnMgPSBjKG5yb3codHJhaW5fZGF0YSksIG5yb3codGVzdF9kYXRhKSwgbnJvdyhpYm1fZmluYWwpKSwKICBBdHRyaXRpb25fUmF0ZSA9IGMoCiAgICBwYXN0ZTAocm91bmQobWVhbih0cmFpbl9kYXRhJGF0dHJpdGlvbikgKiAxMDAsIDEpLCAiJSIpLAogICAgcGFzdGUwKHJvdW5kKG1lYW4odGVzdF9kYXRhJGF0dHJpdGlvbikgKiAxMDAsIDEpLCAiJSIpLAogICAgcGFzdGUwKHJvdW5kKG1lYW4oaWJtX2ZpbmFsJGF0dHJpdGlvbikgKiAxMDAsIDEpLCAiJSIpCiAgKQopCgojIERpc3BsYXkgVGFibGUKc3BsaXRfc3VtbWFyeSAlPiUKICBrYWJsZShjYXB0aW9uID0gIkRhdGEgU3BsaXQ6IENvbnNpc3RlbmN5IGFuZCBTdHJhdGlmaWNhdGlvbiBDaGVjayIpICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksIAogICAgZnVsbF93aWR0aCA9IEZBTFNFLCAKICAgIHBvc2l0aW9uID0gImNlbnRlciIKICApICU+JQogIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzJjM2U1MCIpICU+JQogIGNvbHVtbl9zcGVjKDMsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICIjRTc0QzNDIikKYGBgCgpUaGUgZGF0YXNldCB3YXMgZGl2aWRlZCB1c2luZyBhICoqc3RyYXRpZmllZCBzYW1wbGluZyBhcHByb2FjaCoqLCBlbnN1cmluZyB0aGF0IHRoZSBwcm9wb3J0aW9uIG9mIHRoZSB0YXJnZXQgdmFyaWFibGUgKGBBdHRyaXRpb25gKSB3YXMgbWFpbnRhaW5lZCBhY3Jvc3MgYm90aCBzdWJzZXRzIOKAlCAqKlRyYWluaW5nICg3MCUpKiogYW5kICoqVGVzdGluZyAoMzAlKSoqLgoKQXMgc2hvd24gaW4gdGhlIHRhYmxlLCB0aGUgKipjaHVybiByYXRlKiogcmVtYWlucyBwZXJmZWN0bHkgY29uc2lzdGVudCBhdCAqKjE2LjElKiogaW4gYm90aCBzZXRzLiAgClRoaXMgc3RhdGlzdGljYWwgY29uc2lzdGVuY3kgaXMgZXNzZW50aWFsIHRvIHByZXZlbnQgc2FtcGxpbmcgZGlzdG9ydGlvbiwgZW5zdXJpbmcgdGhhdCB0aGUgdGVzdCBzZXQgZnVuY3Rpb25zIGFzIGEgKipyZXByZXNlbnRhdGl2ZSByZXBsaWNhIG9mIHRoZSBvcmlnaW5hbCBkYXRhc2V0KiouCgpDb25zZXF1ZW50bHksIHRoZSBwZXJmb3JtYW5jZSBtZXRyaWNzIG9idGFpbmVkIGR1cmluZyB0aGUgdmFsaWRhdGlvbiBwaGFzZSByZWFsaXN0aWNhbGx5IGFuZCByZWxpYWJseSByZWZsZWN0IHRoZSBiZWhhdmlvdXIgb2YgdGhlIGF0dHJpdGlvbiBwaGVub21lbm9uIHdpdGhpbiB0aGUgb3JnYW5pc2F0aW9uLCBpbmNyZWFzaW5nIHRoZSAqKmNyZWRpYmlsaXR5IGFuZCBnZW5lcmFsaXNhYmlsaXR5Kiogb2YgdGhlIG1vZGVsIHJlc3VsdHMuCgojIyBDbGFzcyBCYWxhbmNpbmcKCmBgYHtyfQpsaWJyYXJ5KFJPU0UpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCgojIEFwcGx5IFJPU0UgdG8gYmFsYW5jZSBvbmx5IHRoZSBUUkFJTklORyBzZXQKc2V0LnNlZWQoMTIzKQp0cmFpbl9iYWxhbmNlZCA8LSBST1NFKGF0dHJpdGlvbiB+IC4sIGRhdGEgPSB0cmFpbl9kYXRhLCBzZWVkID0gMTIzKSRkYXRhCgojIENyZWF0ZSBkYXRhIGZvciB0aGUgY29tcGFyYXRpdmUgcGxvdApiZWZvcmUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZSh0cmFpbl9kYXRhJGF0dHJpdGlvbikpCmJlZm9yZSRTdGF0dXMgPC0gIjEuIEJlZm9yZSAoVW5iYWxhbmNlZCkiCgphZnRlciA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHRyYWluX2JhbGFuY2VkJGF0dHJpdGlvbikpCmFmdGVyJFN0YXR1cyA8LSAiMi4gQWZ0ZXIgKEJhbGFuY2VkIHdpdGggUk9TRSkiCgpjb21wYXJpc29uIDwtIHJiaW5kKGJlZm9yZSwgYWZ0ZXIpCgojIFBsb3QKZ2dwbG90KGNvbXBhcmlzb24sIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEsIGZpbGwgPSBWYXIxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjkpICsKICBmYWNldF93cmFwKH5TdGF0dXMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICIjMkMzRTUwIiwgIjEiID0gIiNFNzRDM0MiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIG1heChjb21wYXJpc29uJEZyZXEpICogMS4xKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEYXRhIFJlYmFsYW5jaW5nIFN0cmF0ZWd5IChST1NFKSIsCiAgICBzdWJ0aXRsZSA9ICJBZGp1c3RtZW50IG9mIHRoZSBtaW5vcml0eSBjbGFzcyB0byBvcHRpbWlzZSBtb2RlbCBsZWFybmluZyIsCiAgICB4ID0gIkF0dHJpdGlvbiBTdGF0dXMgKDAgPSBObywgMSA9IFllcykiLAogICAgeSA9ICJOdW1iZXIgb2YgUmVjb3JkcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQsIGNvbG9yID0gIiMyYzNlNTAiKSwKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDExKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKYGBgCgpUaGUgZWZmZWN0aXZlbmVzcyBvZiBhIHByZWRpY3RpdmUgbW9kZWwgZGVwZW5kcyBoZWF2aWx5IG9uIHRoZSAqKnF1YWxpdHkqKiBhbmQgKipzdGF0aXN0aWNhbCBiYWxhbmNlKiogb2YgdGhlIHRyYWluaW5nIGRhdGEuICAKCkFzIGlkZW50aWZpZWQgZWFybGllciwgdGhlIHRhcmdldCB2YXJpYWJsZSAoYEF0dHJpdGlvbmApIHNob3dzIGEgKiptYXJrZWQgY2xhc3MgaW1iYWxhbmNlKiosIHdpdGggb25seSAqKjE2LjElIG9mIHBvc2l0aXZlIGNhc2VzKiogKGVtcGxveWVlcyB3aG8gbGVmdCB0aGUgY29tcGFueSkuICAKSW4gcmVhbC13b3JsZCBjb250ZXh0cywgc3VjaCBhc3ltbWV0cnkgb2Z0ZW4gbGVhZHMgdGhlIG1vZGVsIHRvICoqZmF2b3VyIHByZWRpY3RpbmcgcmV0ZW50aW9uKiogd2hpbGUgKip1bmRlcmVzdGltYXRpbmcgY2h1cm4gY2FzZXMqKi4KClRvIGFkZHJlc3MgdGhpcyBpc3N1ZSwgdGhlICoqUk9TRSBhbGdvcml0aG0qKiAoUmFuZG9tIE92ZXLigJFTYW1wbGluZyBFeGFtcGxlcykgd2FzIGFwcGxpZWQgZXhjbHVzaXZlbHkgdG8gdGhlICoqdHJhaW5pbmcgZGF0YXNldCoqLiAgClRoaXMgdGVjaG5pcXVlIGdlbmVyYXRlcyAqKnN5bnRoZXRpYyBvYnNlcnZhdGlvbnMgYmFzZWQgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWlub3JpdHkgY2xhc3MqKiwgcHJlc2VydmluZyB0aGUgc3RhdGlzdGljYWwgaW50ZWdyaXR5IG9mIHRoZSBvcmlnaW5hbCBkYXRhc2V0LgoKKipNYWluIGFkdmFudGFnZXMgb2YgcmViYWxhbmNpbmc6KioKCiogKipMZXZlbGxlZCBsZWFybmluZyoqIOKAkyBUaGUgbW9kZWwgYmVjb21lcyBleHBvc2VkIHRvIGEgYmFsYW5jZWQgZGlzdHJpYnV0aW9uIChhcHByb3hpbWF0ZWx5IDUwLzUwKSBiZXR3ZWVuIGVtcGxveWVlcyB3aG8gc3RheSBhbmQgdGhvc2Ugd2hvIGxlYXZlLCBpbXByb3ZpbmcgaXRzIGdlbmVyYWxpc2F0aW9uIGNhcGFiaWxpdHkuICAKKiAqKkltcHJvdmVkIHNlbnNpdGl2aXR5IChfcmVjYWxsXykqKiDigJMgSW5jcmVhc2VzIHRoZSBhYmlsaXR5IG9mIHRoZSBtb2RlbCB0byBjb3JyZWN0bHkgaWRlbnRpZnkgZGVwYXJ0dXJlcywgYWxsb3dpbmcgKiplYXJseSBkZXRlY3Rpb24gb2YgcG90ZW50aWFsIHRhbGVudCBsb3NzZXMqKi4gIAoqICoqUHJlc2VydmF0aW9uIG9mIHRlc3QgaW50ZWdyaXR5Kiog4oCTIFRoZSByZWJhbGFuY2luZyBwcm9jZXNzIHdhcyBhcHBsaWVkIG9ubHkgdG8gdGhlIHRyYWluaW5nIGRhdGEsIGxlYXZpbmcgdGhlIHRlc3Qgc2V0IHVuY2hhbmdlZC4gIAoKIyBNYWNoaW5lIExlYXJuaW5nCiMjIE1vZGVsIDE6IExvZ2lzdGljIFJlZ3Jlc3Npb24KCmBgYHtyfQojIFRyYWluIHRoZSBNb2RlbApsb2dpc3RpY19tb2RlbCA8LSBnbG0oYXR0cml0aW9uIH4gLiwgZGF0YSA9IHRyYWluX2JhbGFuY2VkLCBmYW1pbHkgPSAiYmlub21pYWwiKQoKIyBNYWtlIFByZWRpY3Rpb25zCnByZWRpY3RlZF9wcm9iIDwtIHByZWRpY3QobG9naXN0aWNfbW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEsIHR5cGUgPSAicmVzcG9uc2UiKQpwcmVkaWN0ZWRfY2xhc3MgPC0gaWZlbHNlKHByZWRpY3RlZF9wcm9iID4gMC41MCwgMSwgMCkKCiMgQ3JlYXRlIENvbmZ1c2lvbiBNYXRyaXgKY29uZl9tYXRyaXggPC0gdGFibGUoQWN0dWFsID0gdGVzdF9kYXRhJGF0dHJpdGlvbiwgUHJlZGljdGVkID0gcHJlZGljdGVkX2NsYXNzKQpkZl9jb25mdXNpb24gPC0gYXMuZGF0YS5mcmFtZShjb25mX21hdHJpeCkKCiMgQ29uZnVzaW9uIE1hdHJpeCBQbG90IChIZWF0bWFwKQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkZl9jb25mdXNpb24sIGFlcyh4ID0gUHJlZGljdGVkLCB5ID0gQWN0dWFsLCBmaWxsID0gRnJlcSkpICsKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA4LCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIiMzNDQ5NUUiLCBoaWdoID0gIiNFNzRDM0MiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkNvbmZ1c2lvbiBNYXRyaXg6IExvZ2lzdGljIFJlZ3Jlc3Npb24iLAogICAgc3VidGl0bGUgPSAiVmlzdWFsaXNhdGlvbiBvZiBDb3JyZWN0IGFuZCBJbmNvcnJlY3QgUHJlZGljdGlvbnMiLAogICAgeCA9ICJNb2RlbCBQcmVkaWN0aW9uICgwID0gU3RheSwgMSA9IExlYXZlKSIsCiAgICB5ID0gIkFjdHVhbCBPdXRjb21lICgwID0gU3RheSwgMSA9IExlYXZlKSIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKQogICkKCiMgTWV0cmljcyBUYWJsZQphY2N1cmFjeSA8LSBzdW0oZGlhZyhjb25mX21hdHJpeCkpIC8gc3VtKGNvbmZfbWF0cml4KQpyZWNhbGwgPC0gY29uZl9tYXRyaXhbMiwgMl0gLyBzdW0oY29uZl9tYXRyaXhbMiwgXSkKCm1ldHJpY3MgPC0gZGF0YS5mcmFtZSgKICBNZXRyaWMgPSBjKCJPdmVyYWxsIEFjY3VyYWN5IiwgIlNlbnNpdGl2aXR5IChSZWNhbGwpIiksCiAgUmVzdWx0ID0gYyhwYXN0ZTAocm91bmQoYWNjdXJhY3kgKiAxMDAsIDIpLCAiJSIpLAogICAgICAgICAgICAgIHBhc3RlMChyb3VuZChyZWNhbGwgKiAxMDAsIDIpLCAiJSIpKQopCgpsaWJyYXJ5KGthYmxlRXh0cmEpCm1ldHJpY3MgJT4lCiAga2FibGUoY2FwdGlvbiA9ICJNb2RlbCAxIFBlcmZvcm1hbmNlIikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFCiAgKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKQpgYGAKCioqTW9kZWwgMSBQZXJmb3JtYW5jZSBBbmFseXNpcyAoTG9naXN0aWMgUmVncmVzc2lvbik6KioKClRoZSBmaXJzdCBtb2RlbCB3YXMgdHJhaW5lZCB1c2luZyB0aGUgKipiYWxhbmNlZCBkYXRhc2V0Kiogb2J0YWluZWQgdGhyb3VnaCB0aGUgKipST1NFIHRlY2huaXF1ZSoqLCBhY2hpZXZpbmcgYW4gKipvdmVyYWxsIGFjY3VyYWN5IG9mIDcyLjc5JSoqLiAgCkFsdGhvdWdoIHRoaXMgbWV0cmljIGlzIHNhdGlzZmFjdG9yeSwgYWNjdXJhY3kgYWxvbmUgaXMgaW5zdWZmaWNpZW50IGZvciBldmFsdWF0aW5nIHBlcmZvcm1hbmNlIGluIGEgKip0YWxlbnQgcmV0ZW50aW9uIHByb2JsZW0qKiwgd2hlcmUgdGhlIGNvc3Qgb2YgaW5jb3JyZWN0bHkgcHJlZGljdGluZyBhbiBlbXBsb3llZeKAmXMgZGVwYXJ0dXJlIGlzIHBhcnRpY3VsYXJseSBoaWdoLgoKVGhlIG1haW4gcmVzdWx0cyBvYnRhaW5lZCBvbiB0aGUgKip0ZXN0IHNldCAoNDQxIGVtcGxveWVlcykqKiBhcmUgcHJlc2VudGVkIGJlbG93OgoKMS4gKipEZXRlY3Rpb24gQ2FwYWJpbGl0eSAoUmVjYWxsKTogNzMuMiUqKgoKSW4gdGhlIHRlc3Qgc2V0LCB0aGVyZSB3ZXJlIDcxIGVtcGxveWVlcyB3aG8gYWN0dWFsbHkgbGVmdCB0aGUgY29tcGFueS4gIApUaGUgbW9kZWwgY29ycmVjdGx5IGlkZW50aWZpZWQgNTIgb2YgdGhlc2UgNzEgY2FzZXMsIGRlbW9uc3RyYXRpbmcgYSAqKnN0cm9uZyBkZXRlY3Rpb24gY2FwYWJpbGl0eSoqLCBhcyBpdCBzdWNjZXNzZnVsbHkgZmxhZ2dlZCBhcHByb3hpbWF0ZWx5ICoqdGhyZWUgb3V0IG9mIGZvdXIgYXTigJFyaXNrIGVtcGxveWVlcyoqLiAgClRoaXMgcmVwcmVzZW50cyB0aGUgbW9kZWzigJlzIG1haW4gc3RyZW5ndGgg4oCUIGVuc3VyaW5nIHRoYXQgbW9zdCBjcml0aWNhbCBjYXNlcyBhcmUgYW50aWNpcGF0ZWQsIGFsbG93aW5nIEhSIHRlYW1zIHRvIHRha2UgKipwcmV2ZW50aXZlIGFjdGlvbioqLgoKMi4gKipDb3N0IG9mIEZhbHNlIEFsYXJtcyAoUHJlY2lzaW9uOiB+MzQlKSoqCgpUbyBtYXhpbWlzZSB0aGUgZGV0ZWN0aW9uIG9mIGRlcGFydHVyZXMsIHRoZSBtb2RlbCBiZWNhbWUgbW9yZSBzZW5zaXRpdmUsIHdoaWNoIGxlZCB0byBhbiAqKmluY3JlYXNlIGluIGZhbHNlIHBvc2l0aXZlcyoqLiAgCkEgdG90YWwgb2YgKioxNTMgZW1wbG95ZWVzKiogd2VyZSBmbGFnZ2VkIGFzIHBvdGVudGlhbCBkZXBhcnR1cmVzLCBidXQgb25seSAqKjUyIGFjdHVhbGx5IGxlZnQqKiB0aGUgb3JnYW5pc2F0aW9uLiAgClRodXMsIGFib3V0ICoqdHdvIHRoaXJkcyBvZiBmbGFnZ2VkIGVtcGxveWVlcyoqIHJlbWFpbmVkLCBnZW5lcmF0aW5nIGEgY29uc2lkZXJhYmxlIGxldmVsIG9mIGZhbHNlIGFsZXJ0cy4gIApXaGlsZSB0aGUgbW9kZWwgaXMgZWZmZWN0aXZlIGF0IGZvcmVjYXN0aW5nIHJlYWwgZGVwYXJ0dXJlcywgaXQgb3BlcmF0ZXMgaW4gYSAqKuKAnGh5cGVy4oCRdmlnaWxhbnTigJ0gbW9kZSoqLCB3aGljaCBjYW4gbGVhZCB0byAqKnVubmVjZXNzYXJ5IEhSIGludGVydmVudGlvbnMqKiBhbmQgcmVzb3VyY2Ugc3RyYWluLgoKMy4gKipDb25mdXNpb24gTWF0cml4OioqCgoqICoqVHJ1ZSBOZWdhdGl2ZXMgKDI2OSk6KiogRW1wbG95ZWVzIHdobyBzdGF5ZWQgYW5kIHdlcmUgY29ycmVjdGx5IGNsYXNzaWZpZWQuICAKKiAqKkZhbHNlIFBvc2l0aXZlcyAoMTAxKToqKiBFbXBsb3llZXMgd2hvIHN0YXllZCBidXQgd2VyZSBpbmNvcnJlY3RseSBmbGFnZ2VkIGFzIGF0IHJpc2sg4oCUIHBvdGVudGlhbCB3YXN0ZSBvZiBtYW5hZ2VtZW50IHJlc291cmNlcy4gIAoqICoqRmFsc2UgTmVnYXRpdmVzICgxOSk6KiogRW1wbG95ZWVzIHdobyBsZWZ0IGJ1dCB3ZXJlIG5vdCBwcmVkaWN0ZWQgdG8gZG8gc28g4oCUIHVuYW50aWNpcGF0ZWQgbG9zc2VzLiAgCiogKipUcnVlIFBvc2l0aXZlcyAoNTIpOioqIEVtcGxveWVlcyB3aG8gbGVmdCBhbmQgd2VyZSBjb3JyZWN0bHkgaWRlbnRpZmllZCDigJQgb3Bwb3J0dW5pdGllcyBmb3IgcHJvYWN0aXZlIHJldGVudGlvbi4KCioqTmV4dCBTdGVwOioqICAKVGVzdCBhIG1vcmUgcm9idXN0IG1vZGVsLCBzdWNoIGFzICoqUmFuZG9tIEZvcmVzdCoqLCBhaW1pbmcgdG8gKipyZWR1Y2UgdGhlIG51bWJlciBvZiBmYWxzZSBwb3NpdGl2ZXMqKiB3aXRob3V0IGNvbXByb21pc2luZyB0aGUgZ29vZCBzZW5zaXRpdml0eSBhY2hpZXZlZCBieSB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4KCiMjIE1vZGVsIDI6IFJhbmRvbSBGb3Jlc3QKCmBgYHtyfQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShjYXJldCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIERhdGEgUHJlcGFyYXRpb24gYW5kIFRyYWluaW5nCnRyYWluX2JhbGFuY2VkJGF0dHJpdGlvbiA8LSBhcy5mYWN0b3IodHJhaW5fYmFsYW5jZWQkYXR0cml0aW9uKQp0ZXN0X2RhdGEkYXR0cml0aW9uIDwtIGFzLmZhY3Rvcih0ZXN0X2RhdGEkYXR0cml0aW9uKQoKc2V0LnNlZWQoMTIzKQpyZl9tb2RlbCA8LSByYW5kb21Gb3Jlc3QoYXR0cml0aW9uIH4gLiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fYmFsYW5jZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgbnRyZWUgPSA1MDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgaW1wb3J0YW5jZSA9IFRSVUUpCgojIFByZWRpY3Rpb25zIGFuZCBNZXRyaWNzCnJmX3ByZWRpY3Rpb25zIDwtIHByZWRpY3QocmZfbW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEpCnJmX2NvbmZfbWF0cml4IDwtIGNvbmZ1c2lvbk1hdHJpeChkYXRhID0gcmZfcHJlZGljdGlvbnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmZXJlbmNlID0gdGVzdF9kYXRhJGF0dHJpdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGl2ZSA9ICIxIikKCiMgVmFyaWFibGUgSW1wb3J0YW5jZSBQbG90CmltcF9kZiA8LSBhcy5kYXRhLmZyYW1lKGltcG9ydGFuY2UocmZfbW9kZWwpKQppbXBfZGYkVmFyaWFibGUgPC0gcm93bmFtZXMoaW1wX2RmKQoKZ2dwbG90KGltcF9kZiAlPiUgYXJyYW5nZShkZXNjKE1lYW5EZWNyZWFzZUFjY3VyYWN5KSkgJT4lIGhlYWQoMTUpLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihWYXJpYWJsZSwgTWVhbkRlY3JlYXNlQWNjdXJhY3kpLCB5ID0gTWVhbkRlY3JlYXNlQWNjdXJhY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzJDM0U1MCIsIGFscGhhID0gMC45LCB3aWR0aCA9IDAuNykgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHRpdGxlID0gIlRvcCAxNSBQcmVkaWN0b3JzIG9mIEVtcGxveWVlIEF0dHJpdGlvbiIsCiAgICBzdWJ0aXRsZSA9ICJGYWN0b3JzIHRoYXQgbW9zdCBpbmZsdWVuY2UgdGhlIGRlY2lzaW9uIHRvIGxlYXZlIiwKICAgIHggPSBOVUxMLAogICAgeSA9ICJJbXBvcnRhbmNlIChNZWFuIERlY3JlYXNlIEFjY3VyYWN5KSIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBDb21wYXJhdGl2ZSBQZXJmb3JtYW5jZSBUYWJsZQpyZl9tZXRyaWNzIDwtIGRhdGEuZnJhbWUoCiAgTWV0cmljID0gYygiQWNjdXJhY3kiLCAiU2Vuc2l0aXZpdHkgKFJlY2FsbCkiLCAiU3BlY2lmaWNpdHkiKSwKICBSZXN1bHQgPSBjKAogICAgcGFzdGUwKHJvdW5kKHJmX2NvbmZfbWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10gKiAxMDAsIDIpLCAiJSIpLAogICAgcGFzdGUwKHJvdW5kKHJmX2NvbmZfbWF0cml4JGJ5Q2xhc3NbJ1NlbnNpdGl2aXR5J10gKiAxMDAsIDIpLCAiJSIpLAogICAgcGFzdGUwKHJvdW5kKHJmX2NvbmZfbWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10gKiAxMDAsIDIpLCAiJSIpCiAgKQopCgpyZl9tZXRyaWNzICU+JQogIGthYmxlKGNhcHRpb24gPSAiUGVyZm9ybWFuY2Ugb2YgdGhlIFJhbmRvbSBGb3Jlc3QgTW9kZWwiKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiksCiAgICBmdWxsX3dpZHRoID0gRkFMU0UKICApICU+JQogIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzJjM2U1MCIpCmBgYAoKVGhlICoqUmFuZG9tIEZvcmVzdCoqIG1vZGVsIGRlbGl2ZXJlZCAqKnN1cGVyaW9yIGFuZCBtb3JlIGJhbGFuY2VkIHBlcmZvcm1hbmNlKiogY29tcGFyZWQgd2l0aCBMb2dpc3RpYyBSZWdyZXNzaW9uLiAgCldpdGggYW4gKipvdmVyYWxsIGFjY3VyYWN5IG9mIDc0LjE1JSoqLCB0aGlzIGFsZ29yaXRobSBwcm92ZWQgdG8gYmUgYSByb2J1c3QgYW5kIHJlbGlhYmxlIHRvb2wgdG8gc3VwcG9ydCAqKnN0cmF0ZWdpYyB0YWxlbnQgcmV0ZW50aW9uIGRlY2lzaW9ucyoqLgoKMS4gKipCYWxhbmNlIGJldHdlZW4gZGV0ZWN0aW9uIGFuZCBwcmVjaXNpb24qKiAgClVubGlrZSB0aGUgcHJldmlvdXMgbW9kZWwsIFJhbmRvbSBGb3Jlc3Qgd2FzICoqbW9yZSBwcmVjaXNlKiogaW4gZGlzdGluZ3Vpc2hpbmcgYmV0d2VlbiByaXNrIGFuZCBzdGFiaWxpdHkgcHJvZmlsZXMuCgoqICoqU2Vuc2l0aXZpdHkgKF9SZWNhbGxfKSBvZiA3MC40JSoqIOKAkyBJdCBjb3JyZWN0bHkgaWRlbnRpZmllZCAqKjUwIG9mIHRoZSA3MSBlbXBsb3llZXMqKiB3aG8gYWN0dWFsbHkgbGVmdCB0aGUgY29tcGFueS4gIAoKKiAqKlJlZHVjdGlvbiBvZiBmYWxzZSBwb3NpdGl2ZXMqKiDigJMgQWx0aG91Z2ggc29tZSBmYWxzZSBhbGVydHMgcmVtYWluLCB0aGUgbW9kZWwgd2FzICoqbW9yZSBzZWxlY3RpdmUqKiBpbiBpZGVudGlmeWluZyByaXNrLCByZWR1Y2luZyBvcGVyYXRpb25hbCBub2lzZSBmb3IgSFIgdGVhbXMuICAKClRoaXMgYmFsYW5jZSByZXN1bHRzIGluIGEgbW9yZSAqKuKAnHN1cmdpY2Fs4oCdIHRvb2wqKiwgY2FwYWJsZSBvZiBhY2hpZXZpbmcgYSBoaWdoIGRldGVjdGlvbiBjYXBhYmlsaXR5IHdpdGhvdXQgc2lnbmlmaWNhbnRseSBzYWNyaWZpY2luZyBwcmVkaWN0aXZlIHByZWNpc2lvbi4KCi0tLQoKMi4gKipNYWluIHByZWRpY3RvcnMgb2YgYXR0cml0aW9uKiogIApUaGUgdmFyaWFibGUgaW1wb3J0YW5jZSBhbmFseXNpcyBoaWdobGlnaHRzIHRoZSBmYWN0b3JzIG1vc3Qgc3Ryb25nbHkgaW5mbHVlbmNpbmcgdGhlIGRlY2lzaW9uIHRvIGxlYXZlLCBwcm92aWRpbmcgaGlnaGx5IHZhbHVhYmxlIG1hbmFnZW1lbnQgaW5zaWdodHM6CgoqICoqYE92ZXJUaW1lYCAoT3ZlcnRpbWUgV29yayk6KiogRW1lcmdlcyBhcyB0aGUgbW9zdCBwb3dlcmZ1bCBwcmVkaWN0b3IsIGluZGljYXRpbmcgdGhhdCBlbXBsb3llZXMgZXhwb3NlZCB0byBsb25nIHdvcmtpbmcgaG91cnMgYXJlIHNpZ25pZmljYW50bHkgbW9yZSBsaWtlbHkgdG8gbGVhdmUuICAKKiAqKmBNb250aGx5SW5jb21lYCAoU2FsYXJ5KToqKiBDb25maXJtcyB0aGF0IGxvd2VyIHNhbGFyeSByYW5nZXMgcmVwcmVzZW50IHRoZSBtb3N0IHZ1bG5lcmFibGUgem9uZSBpbiB0ZXJtcyBvZiBhdHRyaXRpb24gcmlzay4gIAoqICoqYFN0b2NrT3B0aW9uTGV2ZWxgOioqIFRoZSBhYnNlbmNlIG9mIGxvbmfigJF0ZXJtIGluY2VudGl2ZXMgKGUuZy4sIHN0b2NrIHBsYW5zKSBpcyBsaW5rZWQgdG8gd2Vha2VyIG9yZ2FuaXNhdGlvbmFsIGNvbW1pdG1lbnQuICAKKiAqKmBBZ2VgIGFuZCBgVG90YWxXb3JraW5nWWVhcnNgOioqIFlvdW5nZXIgZW1wbG95ZWVzIGFuZCB0aG9zZSB3aXRoIGZld2VyIHllYXJzIG9mIGV4cGVyaWVuY2Ugc2hvdyBncmVhdGVyIGV4dGVybmFsIG1vYmlsaXR5LiAgCgpUaGVzZSBmaW5kaW5ncyBhbGlnbiB3aXRoIEhSIHJlc2VhcmNoLCBlbXBoYXNpc2luZyB0aGUgY29tYmluZWQgaW5mbHVlbmNlIG9mICoqZmluYW5jaWFsIGZhY3RvcnMsIHdvcmtsb2FkLCBhbmQgcHJvZmVzc2lvbmFsIGV4cGVyaWVuY2UqKiBhcyBrZXkgZGV0ZXJtaW5hbnRzIG9mIGVtcGxveWVlIGF0dHJpdGlvbi4KCi0tLQoKMy4gKipUZWNobmljYWwgYW5kIGludGVycHJldGF0aXZlIGNvbmNsdXNpb24qKiAgClRoZSBSYW5kb20gRm9yZXN0IG1vZGVsIHdhcyBhYmxlIHRvICoqY2FwdHVyZSBub27igJFsaW5lYXIgaW50ZXJhY3Rpb25zIGFuZCBjb21wbGV4IHBhdHRlcm5zKiogdGhhdCBsaW5lYXIgbW9kZWxzIGNvdWxkIG5vdCByZXByZXNlbnQuICAKRm9yIGluc3RhbmNlLCB0aGUgYWxnb3JpdGhtIGlkZW50aWZpZWQgdGhhdCBhbiAqKmF2ZXJhZ2Ugc2FsYXJ5IG1heSBiZSBhY2NlcHRhYmxlIGluIGlzb2xhdGlvbioqLCBidXQgYmVjb21lcyBhICoqcmlzayBmYWN0b3Igd2hlbiBjb21iaW5lZCB3aXRoIGV4Y2Vzc2l2ZSBvdmVydGltZSBvciBsb3cgc2F0aXNmYWN0aW9uIHdpdGggbWFuYWdlbWVudCoqLiAgCgpJbiBzaG9ydCwgdGhpcyBtb2RlbCBub3Qgb25seSBlbmhhbmNlcyBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlIGJ1dCBhbHNvIHByb3ZpZGVzICoqYWN0aW9uYWJsZSBpbnNpZ2h0cyoqIGZvciAqKnRhcmdldGVkIHJldGVudGlvbiBwb2xpY2llcyoqIGFuZCAqKnByb2FjdGl2ZSB0YWxlbnQgbWFuYWdlbWVudCBzdHJhdGVnaWVzKiouCgojIyBBdHRyaXRpb24gRHJpdmVycyBBbmFseXNpcyAoRmVhdHVyZSBJbXBvcnRhbmNlKQoKYGBge3J9CiMgRXh0cmFjdCB2YXJpYWJsZSBpbXBvcnRhbmNlIGZyb20gdGhlIFJhbmRvbSBGb3Jlc3QgbW9kZWwKaW1wb3J0YW5jZV9kZiA8LSBhcy5kYXRhLmZyYW1lKGltcG9ydGFuY2UocmZfbW9kZWwpKQppbXBvcnRhbmNlX2RmJFZhcmlhYmxlIDwtIHJvd25hbWVzKGltcG9ydGFuY2VfZGYpCgojIENyZWF0ZSB0aGUgcGxvdApsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCgpnZ3Bsb3QoaW1wb3J0YW5jZV9kZiAlPiUgYXJyYW5nZShkZXNjKE1lYW5EZWNyZWFzZUFjY3VyYWN5KSkgJT4lIGhlYWQoMTUpLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihWYXJpYWJsZSwgTWVhbkRlY3JlYXNlQWNjdXJhY3kpLCB5ID0gTWVhbkRlY3JlYXNlQWNjdXJhY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzJDM0U1MCIsIGFscGhhID0gMC45LCB3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChNZWFuRGVjcmVhc2VBY2N1cmFjeSwgMSkpLCAKICAgICAgICAgICAgaGp1c3QgPSAtMC4yLCBzaXplID0gMywgZm9udGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIiMyQzNFNTAiKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMSkpKSArCiAgbGFicygKICAgIHRpdGxlID0gIkNyaXRpY2FsIEF0dHJpdGlvbiBEcml2ZXJzIiwKICAgIHN1YnRpdGxlID0gIlZhcmlhYmxlcyB0aGF0IG1vc3QgaW1wYWN0IHRoZSBhY2N1cmFjeSBvZiB0aGUgUmFuZG9tIEZvcmVzdCBtb2RlbCIsCiAgICB4ID0gTlVMTCwKICAgIHkgPSAiSW1wb3J0YW5jZSAoTWVhbiBEZWNyZWFzZSBBY2N1cmFjeSkiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2LCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSwgY29sb3IgPSAiZ3JleTQwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTApCiAgKQpgYGAKClRoZSBjaGFydCBhYm92ZSBwcmVzZW50cyB0aGUgbW9zdCBpbmZsdWVudGlhbCB2YXJpYWJsZXMgaWRlbnRpZmllZCBieSB0aGUgUmFuZG9tIEZvcmVzdCBtb2RlbCwgcmFua2VkIGFjY29yZGluZyB0byB0aGUgKirigJxNZWFuIERlY3JlYXNlIEFjY3VyYWN54oCdKiogbWV0cmljLiAgCkluIHByYWN0aWNhbCB0ZXJtcywgdGhlIGhpZ2hlciB0aGUgaW1wb3J0YW5jZSBvZiB0aGlzIG1ldHJpYywgdGhlIGdyZWF0ZXIgdGhlIHZhcmlhYmxl4oCZcyBjb250cmlidXRpb24gdG8gdGhlIG1vZGVs4oCZcyBvdmVyYWxsIHByZWRpY3RpdmUgY2FwYWJpbGl0eeKAlGl0cyByZW1vdmFsIHdvdWxkIHJlc3VsdCBpbiBhIHNpZ25pZmljYW50IGRyb3AgaW4gYWNjdXJhY3kuCgoxLiAqKkpvYiBSb2xlIGFzIHRoZSBtYWluIGRldGVybWluYW50IChgSm9iUm9sZWApKiogIApGb3VyIG9mIHRoZSB0b3AgZml2ZSBtb3N0IHJlbGV2YW50IHZhcmlhYmxlcyByZWxhdGUgdG8gc3BlY2lmaWMgZnVuY3Rpb25zIHdpdGhpbiB0aGUgb3JnYW5pc2F0aW9uLiAgClR3byBleHRyZW1lcyBzdGFuZCBvdXQ6IGBSZXNlYXJjaCBEaXJlY3RvcmAgKGEgaGlnaGx5IHN0YWJsZSBwb3NpdGlvbikgYW5kIGBTYWxlcyBSZXByZXNlbnRhdGl2ZWAgKGEgY29uc2lkZXJhYmx5IG1vcmUgdm9sYXRpbGUgb25lKS4gIAoKVGhpcyBkaWZmZXJlbmNlIGNvbmZpcm1zIHRoZSBjb25jbHVzaW9ucyBkcmF3biBmcm9tIHRoZSBleHBsb3JhdG9yeSBzdGFnZTogKipoaWVyYXJjaGljYWwgbGV2ZWwqKiBhbmQgKipqb2IgdHlwZSoqIGFyZSBrZXkgZmFjdG9ycyBkcml2aW5nIGF0dHJpdGlvbiBiZWhhdmlvdXIgYWNyb3NzIHRoZSBjb21wYW55LiAgCgoqKkltcGxpY2F0aW9uOioqIEdlbmVyaWMgcGVvcGxl4oCRbWFuYWdlbWVudCBwb2xpY2llcyAo4oCcb25l4oCRc2l6ZeKAkWZpdHPigJFhbGzigJ0pIGFyZSBpbmVmZmVjdGl2ZS4gIApSZXRlbnRpb24gc3RyYXRlZ2llcyBtdXN0IGJlICoqZnVuY3Rpb27igJFzcGVjaWZpYyoqLCBhY2tub3dsZWRnaW5nIHRoYXQgc2FsZXMgYW5kIHJlc2VhcmNoL2xlYWRlcnNoaXAgdGVhbXMgcmVxdWlyZSBkaXN0aW5jdCBhcHByb2FjaGVzIHRvIG1vdGl2YXRpb24gYW5kIHJlY29nbml0aW9uLgoKMi4gKipUaGUgd2VpZ2h0IG9mIG92ZXJ0aW1lIChgT3ZlclRpbWVgKSoqICAKVGhlIHZhcmlhYmxlIGBvdmVyX3RpbWVfeWVzYCByYW5rcyBhcyB0aGUgKip0aGlyZCBtb3N0IGNyaXRpY2FsIHByZWRpY3RvcioqIGFjcm9zcyB0aGUgZGF0YXNldC4gIApUaGlzIHN1cHBvcnRzIHByaW9yIGV2aWRlbmNlIHNob3dpbmcgdGhhdCAqKndvcmsgb3ZlcmxvYWQqKiBhbmQgKipwb29yIHdvcmvigJFsaWZlIGJhbGFuY2UqKiBhcmUgZGlyZWN0IHRyaWdnZXJzIG9mIGF0dHJpdGlvbi4gIApUaGlzIGlzIGxlc3MgYSBxdWVzdGlvbiBvZiBjb21wZW5zYXRpb24gYW5kIG1vcmUgb25lIG9mICoqb3JnYW5pc2F0aW9uYWwgd2VsbOKAkWJlaW5nIGFuZCBidXJub3V0IHByZXZlbnRpb24qKi4KCjMuICoqU3RhZ25hdGlvbiBhbmQgbG9uZ+KAkXRlcm0gaW5jZW50aXZlcyoqICAKCiogKipTdGFnbmF0aW9uOioqIFRoZSB2YXJpYWJsZSBgeWVhcnNfaW5fY3VycmVudF9yb2xlYCAoeWVhcnMgaW4gY3VycmVudCBwb3NpdGlvbikgcmFua3Mgc2l4dGggaW4gaW1wb3J0YW5jZS4gUHJvbG9uZ2VkIHBlcm1hbmVuY2UgaW4gdGhlIHNhbWUgcm9sZSB3aXRob3V0IHZpc2libGUgY2FyZWVyIHByb2dyZXNzaW9uIG1hcmtlZGx5IGluY3JlYXNlcyB2b2x1bnRhcnkgYXR0cml0aW9uIHJpc2suICAKKiAqKkluY2VudGl2ZXM6KiogYHN0b2NrX29wdGlvbl9sZXZlbGAgZm9sbG93cyBjbG9zZWx5LCBoaWdobGlnaHRpbmcgdGhhdCAqKmxvbmfigJF0ZXJtIGluY2VudGl2ZXMqKiBoYXZlIGEgc3Ryb25nZXIgcmV0ZW50aW9uIGVmZmVjdCB0aGFuIG1vbnRobHkgaW5jb21lIChgbW9udGhseV9pbmNvbWVgKSwgd2hpY2ggb25seSBhcHBlYXJzIGluIGZpZnRlZW50aCBwb3NpdGlvbi4gIAoKVGhlc2UgZmluZGluZ3Mgc3VnZ2VzdCB0aGF0ICoqY2FyZWVyIHByb2dyZXNzaW9uKiogYW5kICoqc3ltYm9saWMgY2FwaXRhbCBhcHByZWNpYXRpb24qKiAoZS5nLiwgb3duZXJzaGlwIGluY2VudGl2ZXMsIHJlY29nbml0aW9uLCB2aXNpYmlsaXR5KSBhcmUgbW9yZSBlZmZlY3RpdmUgcmV0ZW50aW9uIG1lY2hhbmlzbXMgdGhhbiBzYWxhcnkgaW5jcmVhc2VzIGFsb25lLgoKNC4gKipEZW1vZ3JhcGhpYyByaXNrIHByb2ZpbGUqKiAgClRoZSBwcmVzZW5jZSBvZiB0aGUgdmFyaWFibGVzIGBtYXJpdGFsX3N0YXR1c19zaW5nbGVgIGFuZCBgYWdlYCB3aXRoaW4gdGhlIHRvcCAxNSByZWFmZmlybXMgdGhlIHByZXZpb3VzbHkgb2JzZXJ2ZWQgcGF0dGVybjogKip5b3VuZ2VyIGFuZCBzaW5nbGUgZW1wbG95ZWVzKiogYXJlIG1vcmUgbW9iaWxlIGFuZCBtb3JlIHByb25lIHRvIGpvYiBjaGFuZ2VzLCBwYXJ0aWN1bGFybHkgd2hlbiBkZXZlbG9wbWVudCBvcHBvcnR1bml0aWVzIGFyZSBsaW1pdGVkLgoKVG8gbWl0aWdhdGUgKiphdHRyaXRpb24gcmlza3MqKiwgdGhlIGNvbXBhbnkgc2hvdWxkIHByaW9yaXRpc2UgdGhyZWUgc3RyYXRlZ2ljIGFjdGlvbiBhcmVhczoKCjEuICoqUmVhc3Nlc3MgY29uZGl0aW9ucyBhbmQgaW5jZW50aXZlcyBmb3IgU2FsZXMgdGVhbXMqKiwgd2hlcmUgdHVybm92ZXIgaXMgaGlnaGVzdDsgIAoyLiAqKk1vbml0b3IgYW5kIHJlZ3VsYXRlIG92ZXJ0aW1lKiosIGVuY291cmFnaW5nIGluaXRpYXRpdmVzIHRoYXQgcHJvbW90ZSB3b3Jr4oCRbGlmZSBiYWxhbmNlIGFuZCBvdmVyYWxsIHdlbGzigJFiZWluZzsgIAozLiAqKkltcGxlbWVudCBjYXJlZXLigJFyb3RhdGlvbiBhbmQgZGV2ZWxvcG1lbnQgcHJvZ3JhbW1lcyoqLCBwYXJ0aWN1bGFybHkgZm9yIGVtcGxveWVlcyB3aG8gaGF2ZSByZW1haW5lZCBpbiB0aGUgc2FtZSBwb3NpdGlvbiBmb3Igc2V2ZXJhbCB5ZWFycy4KClRoZXNlIHN0cmF0ZWdpYyBhY3Rpb25zIGFsaWduIGRpcmVjdGx5IHdpdGggdGhlIG1vZGVsIHJlc3VsdHMgYW5kIGNhbiAqKnN1YnN0YW50aWFsbHkgcmVkdWNlIHVud2FudGVkIHR1cm5vdmVyKiosIHRoZXJlYnkgc3RyZW5ndGhlbmluZyB0aGUgcmV0ZW50aW9uIG9mIGNyaXRpY2FsIHRhbGVudC4KCi0tLQoKIyBDb25jbHVzaW9uIGFuZCBCdXNpbmVzcyBSZWNvbW1lbmRhdGlvbnMKClRoZSBwdXJwb3NlIG9mIHRoaXMgcHJvamVjdCB3YXMgdG8gKippZGVudGlmeSB0aGUga2V5IGRyaXZlcnMgb2YgZW1wbG95ZWUgYXR0cml0aW9uKiogYW5kIHRvICoqYnVpbGQgYSBwcmVkaWN0aXZlIG1vZGVsIHRvIG1pdGlnYXRlIHR1cm5vdmVyIHJpc2sqKi4KCiMjIE1vZGVsIENvbXBhcmlzb24KVHdvIG1vZGVsbGluZyBhcHByb2FjaGVzIHdlcmUgZXZhbHVhdGVkOiAqKkxvZ2lzdGljIFJlZ3Jlc3Npb24qKiBhbmQgKipSYW5kb20gRm9yZXN0KiouCgpUaGUgKipSYW5kb20gRm9yZXN0KiogYWxnb3JpdGhtIGRlbW9uc3RyYXRlZCAqKnN1cGVyaW9yIGFuZCBtb3JlIHN0YWJsZSBwZXJmb3JtYW5jZSoqLCBhY2hpZXZpbmcgYW4gKipvdmVyYWxsIGFjY3VyYWN5IG9mIDc0LjE1JSoqLiAgClRoZSBtb2RlbCBjb3JyZWN0bHkgaWRlbnRpZmllZCAqKjcwLjQlIG9mIGVtcGxveWVlcyB3aG8gYWN0dWFsbHkgbGVmdCoqIChzZW5zaXRpdml0eSkgd2hpbGUgbWFpbnRhaW5pbmcgYSAqKmNvbnRyb2xsZWQgZmFsc2XigJFwb3NpdGl2ZSByYXRlKiogKHNwZWNpZmljaXR5IG9mIDc0LjklKS4KClRoZXNlIG1ldHJpY3MgcmV2ZWFsIGFuICoqYXBwcm9wcmlhdGUgYmFsYW5jZSBiZXR3ZWVuIGRldGVjdGlvbiBhbmQgcHJlY2lzaW9uKiosIG1ha2luZyB0aGUgYWxnb3JpdGhtIGEgcmVsaWFibGUgYW5kIHByYWN0aWNhbCB0b29sIGZvciBIUiBkZWNpc2lvbuKAkW1ha2luZyBjb250ZXh0cy4KCi0tLQoKIyMgS2V5IEF0dHJpdGlvbiBEcml2ZXJzIChfTW9kZWwgSW5zaWdodHNfKQpUaGUgZmVhdHVyZeKAkWltcG9ydGFuY2UgYW5hbHlzaXMgcmV2ZWFsZWQgdGhyZWUgKipjb3JlIHBpbGxhcnMgZm9yIGFjdGlvbioqOgoKMS4gKipSaXNrIEFzc29jaWF0ZWQgd2l0aCBTYWxlcyBSb2xlcyoqICAKVGhlIGBTYWxlcyBSZXByZXNlbnRhdGl2ZWAgcm9sZSBlbWVyZ2VkIGFzIHRoZSAqKnN0cm9uZ2VzdCBwcmVkaWN0b3Igb2YgZGVwYXJ0dXJlKiouIFR1cm5vdmVyIGluIHRoaXMgZnVuY3Rpb24gaXMgc3Vic3RhbnRpYWxseSBoaWdoZXIgdGhhbiBpbiBzdGFibGUgcm9sZXMgc3VjaCBhcyBgUmVzZWFyY2ggRGlyZWN0b3JgIG9yIGBNYW5hZ2VyYC4gIAoqKkxpa2VseSBkaWFnbm9zaXM6KiogY29tbWlzc2lvbiBzY2hlbWUgaW1iYWxhbmNlcywgZXhjZXNzaXZlIHRhcmdldCBwcmVzc3VyZSwgb3IgbGltaXRlZCBhZHZhbmNlbWVudCBvcHBvcnR1bml0aWVzLgoKMi4gKipPdmVydGltZSBDdWx0dXJlIGFuZCBPY2N1cGF0aW9uYWwgRmF0aWd1ZSoqICAKVGhlIGBPdmVyVGltZWAgdmFyaWFibGUgcmVtYWlucyBhbW9uZyB0aGUgKip0b3AgdGhyZWUgbW9zdCBjcml0aWNhbCBmYWN0b3JzKiosIGRlbW9uc3RyYXRpbmcgdGhhdCAqKndvcmsgb3ZlcmxvYWQqKiBpcyBhIGRpcmVjdCAqKmF0dHJpdGlvbiB0cmlnZ2VyKiouICAKRW1wbG95ZWVzIHdobyB3b3JrIG92ZXJ0aW1lIHNob3cgbWFya2VkbHkgaGlnaGVyIHR1cm5vdmVyIGxpa2VsaWhvb2QsIHJlZ2FyZGxlc3Mgb2Ygc2FsYXJ5IGxldmVsLiAgCioqSW50ZXJwcmV0YXRpb246KiogVGhpcyBwYXR0ZXJuIGluZGljYXRlcyBwb3NzaWJsZSBzaWducyBvZiAqKmJ1cm5vdXQqKiBhbmQgKip3b3Jr4oCRbGlmZSBpbWJhbGFuY2UqKiwgYXJlYXMgdGhhdCByZXF1aXJlIGNvbnRpbnVvdXMgSFIgbW9uaXRvcmluZy4KCjMuICoqUmV0ZW50aW9uIFRocm91Z2ggTG9uZ+KAkVRlcm0gSW5jZW50aXZlcyoqICAKYFN0b2NrT3B0aW9uTGV2ZWxgIHByb3ZlcyB0byBiZSAqKmEga2V5IGRyaXZlciBvZiB0YWxlbnQgcmV0ZW50aW9uKiouICAKRW1wbG95ZWVzIHdpdGggc3RvY2sgcGFydGljaXBhdGlvbiBvciBsb25n4oCRdGVybSBpbmNlbnRpdmVzIHRlbmQgdG8gc3RheSBsb25nZXIsIGRyaXZlbiBieSBhIHN0cm9uZ2VyIHNlbnNlIG9mIG93bmVyc2hpcCBhbmQgb3JnYW5pc2F0aW9uYWwgY29tbWl0bWVudC4gIApDb252ZXJzZWx5LCB0aGUgYWJzZW5jZSBvZiB0aGVzZSBtZWNoYW5pc21zIGNvcnJlbGF0ZXMgd2l0aCBhIGhpZ2hlciB0dXJub3ZlciBwcm9wZW5zaXR5LgoKLS0tCgojIyBSZWNvbW1lbmRlZCBBY3Rpb24gUGxhbiAoTmV4dCBTdGVwcykKCkJhc2VkIG9uIHRoZSBhbmFseXRpY2FsIGZpbmRpbmdzLCB0aGUgZm9sbG93aW5nIG1lYXN1cmVzIGFyZSByZWNvbW1lbmRlZDoKCjEuICoqVGFyZ2V0ZWQgSW50ZXJ2ZW50aW9uIGluIFNhbGVzIFRlYW1zOioqICAKICAgQ29uZHVjdCAqKmV4aXQgaW50ZXJ2aWV3cyoqIGZvY3VzaW5nIHNwZWNpZmljYWxseSBvbiBTYWxlcyBSZXByZXNlbnRhdGl2ZXMgdG8gcmVhc3Nlc3MgY29tbWlzc2lvbiBzdHJ1Y3R1cmVzLCB0YXJnZXQgc3lzdGVtcywgYW5kIGNhcmVlciBkZXZlbG9wbWVudCBvcHBvcnR1bml0aWVzLiAgCgoyLiAqKldvcmtpbmfigJFIb3VycyBhbmQgV2VsbOKAkUJlaW5nIEF1ZGl0OioqICAKICAgSW1wbGVtZW50ICoqbWVjaGFuaXNtcyB0byBtb25pdG9yIGFuZCBjb21wZW5zYXRlIG92ZXJ0aW1lIHdvcmsqKiAodGhyb3VnaCB0aW1l4oCRb2ZmIG9yIGJlbmVmaXRzKS4gIAogICBJbiBwYXJhbGxlbCwgZGV2ZWxvcCAqKmJ1cm5vdXQgcHJldmVudGlvbiBhbmQgd29ya+KAkWxpZmUgYmFsYW5jZSBpbml0aWF0aXZlcyoqLiAgCgozLiAqKkNvbnRpbnVvdXMgQXR0cml0aW9uIFByZWRpY3Rpb24gVG9vbDoqKiAgCiAgIERlcGxveSB0aGUgUmFuZG9tIEZvcmVzdCBtb2RlbCBhcyBhICoqbW9udGhseSBwcmVkaWN0aXZl4oCRbW9uaXRvcmluZyBzeXN0ZW0qKiDigJQgYSBkeW5hbWljICrigJxyaXNrIGxpc3TigJ0qIGhpZ2hsaWdodGluZyBlbXBsb3llZXMgd2l0aCBhICoqcHJvYmFiaWxpdHkgb2YgZGVwYXJ0dXJlIGFib3ZlIDUwJSoqLiAgCiAgIEhSIHRlYW1zIHNob3VsZCB1c2UgdGhpcyBpbmZvcm1hdGlvbiAqKnByb2FjdGl2ZWx5KiosIGVuZ2FnaW5nIHdpdGggYXTigJFyaXNrIGVtcGxveWVlcyBiZWZvcmUgdGhlIGRlY2lzaW9uIHRvIGxlYXZlIG9jY3Vycy4=