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:

  1. Demographic: Age, Gender, MaritalStatus, DistanceFromHome
  2. Work-related: Department, JobRole, JobLevel, OverTime, BusinessTravel
  3. 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.

Data Preparation

Data Cleaning

The initial descriptive analysis revealed two key aspects regarding the quality and structure of the dataset:

  1. Data Quality – No missing values were identified across any variable, which greatly simplifies the preprocessing stage.

  2. Redundant and Non‑Informative Variables – Three variables were found to have constant values across all observations (standard deviation = 0), and one variable served exclusively as a unique identifier. As these show no variability or predictive contribution, they were removed from the dataset.

The removed variables were:

  • EmployeeCount: Constant value equal to “1”;
  • Over18: All employees recorded as adults (“Y”);
  • StandardHours: Fixed value “80” for all records;
  • EmployeeNumber: Unique identifier for each employee, with no predictive relevance.

The exclusion of these variables reduces data dimensionality without losing meaningful information, contributing to a more efficient and interpretable analytical model.

# Standardization of Column Names
ibm_clean <- ibm_hr %>% 
  clean_names()

# Remove Invariant Variables
columns_to_remove <- c("employee_count", "over18", "standard_hours", "employee_number")

ibm_clean <- ibm_clean %>% 
  select(-any_of(columns_to_remove))

# Cleaning Summary
cat("Dataset cleaned successfully.\n",
    "Total Original Columns: ", ncol(ibm_hr), "\n",
    "Total Columns After Cleaning: ", ncol(ibm_clean))
Dataset cleaned successfully.
 Total Original Columns:  35 
 Total Columns After Cleaning:  31

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:

  1. 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.

  2. 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.

  3. 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:

  1. 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.

  2. 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:

  1. 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.

  2. 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:

  1. 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.

  2. 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:

  1. 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.

  2. Laboratory Technicians and Human Resources – Both functions show attrition rates around 25%, clearly above the organisational average.

  3. 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:

  1. 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.

  2. 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:

  1. 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.

  2. 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:

  1. 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).

  2. 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.

  3. 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.

  4. 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:

  1. 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.

  2. 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:

  1. 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.

  2. 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.

  3. 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:

  1. 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.

  1. 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.

  1. 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.

  1. 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.


  1. 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.


  1. 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.

  1. 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.

  1. 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.

  2. 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.

  1. 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:

  1. Reassess conditions and incentives for Sales teams, where turnover is highest;
  2. Monitor and regulate overtime, encouraging initiatives that promote work‑life balance and overall well‑being;
  3. 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:

  1. 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.

  2. 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.

  3. 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.


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=