Introduction
This data set was obtained from kaggle.com. The data set contains
information on several thousand employees from an unnamed company. Since
no details are given about the company, it cannot be said how exactly
the data was collected. The response variable we are trying to predict
is whether or no an employee stays at or leaves the company. The
explanatory variables relate to each subjects work life. The response
variable is whether or not an employee stays at or leaves the company.
For my simple logistic regression analysis, the variable that I am going
to use is “satisfaction_level”. This is the employees self reported
satisfaction level.
Variable
Description
- satisfaction_level (x1) - the employees self reported satisfaction
level. (Numeric from 0-1)
- last_evaluation (x2) - the employees last performance review.
(Numeric from 0-1)
- number_project (x3) - the number of projects an employee has done
for the company. (Numeric)
- average_monthly_hours (x4) - the average number of hours an employee
works per month. (Numeric)
- time_spend_company (x5) - how long the employee has worked at the
company in years. (Numeric)
- Work_accident (x6) - number of work related accidents the employee
has had. (Numeric)
- promotion_last_5years (x7) - Has the employee had a promotion in the
last 5 years? (Binary 1=yes, 0=n0)
- Department (x8) - the department the employee is in.
(categorical)
- Salary (x9) - salary level. (categorical)
- left (y) - whether the employee stays at or leaves the company
(0=stay, 1=leave)
Practical
Question
For this study, we want to identify which factors about an employee’s
work life indicate they will leave the company.
Data Download
hr_data <- read.csv("https://raw.githubusercontent.com/AvaDeSt/STA-321/refs/heads/main/HR_comma_sep.csv", header = TRUE)
pred_vars <- select(hr_data, - "left")
data(hr_data)
## Warning in data(hr_data): data set 'hr_data' not found
hr.0 = hr_data
hr_d = na.omit(hr.0)
duplicates <- duplicated(hr_d)
hr <- unique(hr_d)
The are no missing values in the data set. But there are 3008
duplicate values so I took those out of the data set.
Exploratory
Analysis
data.num <- select(hr_data, "satisfaction_level", "last_evaluation", "number_project", "average_montly_hours", "time_spend_company") #data set of only the numeric variables
pairs.panels(data.num[,-9],
method = "pearson",
hist.col = "#00AFBB",
density = TRUE,
ellipses = TRUE
)
We can see from the graphs that the variable for the number of years
spent at the company is skewed. Here is a closer look:
par(mfrow=c(1,2))
hist(hr$time_spend_company, xlab="Years at the company", main = "")
To fix this, I am going to discretize “time_spend_company” based on the
histogram.
time = hr$time_spend_company
grp.time = time
grp.time[time %in% c(2:4)] = "2-4"
grp.time[time %in% c(5:7)] = "5-7"
grp.time[time %in% c(8:10)] = "8-10"
hr$grp.time = grp.time
There is a moderate correlation between the number of projects and
the average monthly hours an employee has worked. But since they are not
too similar, they will both be kept for the time being. There is no need
to transform any of the variables since we are only doing association
analysis.
Model Building
full.model = glm(left ~ satisfaction_level + last_evaluation + number_project + average_montly_hours + Work_accident + promotion_last_5years + Department + salary + grp.time,
family = binomial(link = "logit"), # logit(p) = log(p/(1-p))!
data = hr)
kable(summary(full.model)$coef,
caption="Summary of inferential statistics of the full model")
Summary of inferential statistics of the full model
(Intercept) |
-0.9867879 |
0.2450354 |
-4.0271237 |
0.0000565 |
satisfaction_level |
-4.2525608 |
0.1242625 |
-34.2224070 |
0.0000000 |
last_evaluation |
0.5919079 |
0.1826236 |
3.2411352 |
0.0011905 |
number_project |
-0.3052465 |
0.0263733 |
-11.5740741 |
0.0000000 |
average_montly_hours |
0.0043584 |
0.0006329 |
6.8864733 |
0.0000000 |
Work_accident |
-1.4801817 |
0.1136691 |
-13.0218516 |
0.0000000 |
promotion_last_5years |
-1.2925052 |
0.3859450 |
-3.3489364 |
0.0008112 |
Departmenthr |
0.0657740 |
0.1691216 |
0.3889154 |
0.6973387 |
DepartmentIT |
-0.0451906 |
0.1555504 |
-0.2905204 |
0.7714181 |
Departmentmanagement |
-0.0866355 |
0.2069245 |
-0.4186819 |
0.6754487 |
Departmentmarketing |
0.0722944 |
0.1692217 |
0.4272169 |
0.6692214 |
Departmentproduct_mng |
-0.0514320 |
0.1672970 |
-0.3074294 |
0.7585166 |
DepartmentRandD |
-0.4590236 |
0.1779200 |
-2.5799431 |
0.0098817 |
Departmentsales |
0.0447254 |
0.1318253 |
0.3392778 |
0.7344004 |
Departmentsupport |
0.0902813 |
0.1396548 |
0.6464604 |
0.5179812 |
Departmenttechnical |
0.0614581 |
0.1361925 |
0.4512593 |
0.6518027 |
salarylow |
1.7717805 |
0.1653125 |
10.7177616 |
0.0000000 |
salarymedium |
1.3334114 |
0.1665768 |
8.0047854 |
0.0000000 |
grp.time5-7 |
1.3512536 |
0.0701784 |
19.2545459 |
0.0000000 |
grp.time8-10 |
-14.2440493 |
155.6796437 |
-0.0914959 |
0.9270986 |
Reduced Model
reduced.model = glm(left ~ satisfaction_level + last_evaluation + number_project + promotion_last_5years + average_montly_hours + Work_accident,
family = binomial(link = "logit"), # logit(p) = log(p/(1-p))!
data = hr)
kable(summary(reduced.model)$coef,
caption="Summary of inferential statistics of the reduced model")
Summary of inferential statistics of the reduced
model
(Intercept) |
0.3371415 |
0.1487394 |
2.266659 |
0.0234110 |
satisfaction_level |
-4.1861392 |
0.1201123 |
-34.851889 |
0.0000000 |
last_evaluation |
0.7862953 |
0.1752611 |
4.486422 |
0.0000072 |
number_project |
-0.2339762 |
0.0250456 |
-9.342022 |
0.0000000 |
promotion_last_5years |
-1.4115858 |
0.3708276 |
-3.806582 |
0.0001409 |
average_montly_hours |
0.0042296 |
0.0006067 |
6.970990 |
0.0000000 |
Work_accident |
-1.3338246 |
0.1078854 |
-12.363349 |
0.0000000 |
Final Model
final.model.forward = stepAIC(reduced.model,
scope = list(lower=formula(reduced.model),upper=formula(full.model)),
direction = "forward",
trace = 0
)
kable(summary(final.model.forward)$coef,
caption="Summary of inferential statistics of the final model")
Summary of inferential statistics of the final model
(Intercept) |
-0.9779961 |
0.2147754 |
-4.553576 |
0.0000053 |
satisfaction_level |
-4.2413818 |
0.1239701 |
-34.212943 |
0.0000000 |
last_evaluation |
0.5927693 |
0.1823071 |
3.251488 |
0.0011480 |
number_project |
-0.3046392 |
0.0263297 |
-11.570158 |
0.0000000 |
promotion_last_5years |
-1.3257470 |
0.3845411 |
-3.447608 |
0.0005656 |
average_montly_hours |
0.0043328 |
0.0006318 |
6.857459 |
0.0000000 |
Work_accident |
-1.4841619 |
0.1136100 |
-13.063650 |
0.0000000 |
grp.time5-7 |
1.3416190 |
0.0700726 |
19.146130 |
0.0000000 |
grp.time8-10 |
-14.2350334 |
156.2040875 |
-0.091131 |
0.9273885 |
salarylow |
1.7761701 |
0.1647064 |
10.783859 |
0.0000000 |
salarymedium |
1.3355641 |
0.1660276 |
8.044227 |
0.0000000 |
Even though we discovered that the number of projects an employee has
and the average number of hours worked have a moderate correlation, the
final model still includes both variables. We can see that the final
mode only takes out the variable “Department”. The model stills keeps
the variables for the number of years spent at the company “grp.time”,
even though when time time spent at the company ranges from 8-10 years,
the p-value is no longer significant.
global.measure=function(s.logit){
dev.resid = s.logit$deviance
dev.0.resid = s.logit$null.deviance
aic = s.logit$aic
goodness = cbind(Deviance.residual =dev.resid, Null.Deviance.Residual = dev.0.resid,
AIC = aic)
goodness
}
goodness=rbind(full.model = global.measure(full.model),
reduced.model=global.measure(reduced.model),
final.model=global.measure(final.model.forward))
row.names(goodness) = c("full.model", "reduced.model", "final.model")
kable(goodness, caption ="Comparison of global goodness-of-fit statistics")
Comparison of global goodness-of-fit statistics
full.model |
8395.920 |
10781.18 |
8435.920 |
reduced.model |
9005.841 |
10781.18 |
9019.841 |
final.model |
8413.683 |
10781.18 |
8435.683 |
We can see that the final model has the lowest AIC, indicating it is
the best one to use.
Odds Ratio
model.coef.stats = summary(final.model.forward)$coef
odds.ratio = exp(coef(final.model.forward))
out.stats = cbind(model.coef.stats, odds.ratio = odds.ratio)
kable(out.stats,caption = "Summary Stats with Odds Ratios")
Summary Stats with Odds Ratios
(Intercept) |
-0.9779961 |
0.2147754 |
-4.553576 |
0.0000053 |
0.3760639 |
satisfaction_level |
-4.2413818 |
0.1239701 |
-34.212943 |
0.0000000 |
0.0143877 |
last_evaluation |
0.5927693 |
0.1823071 |
3.251488 |
0.0011480 |
1.8089912 |
number_project |
-0.3046392 |
0.0263297 |
-11.570158 |
0.0000000 |
0.7373894 |
promotion_last_5years |
-1.3257470 |
0.3845411 |
-3.447608 |
0.0005656 |
0.2656045 |
average_montly_hours |
0.0043328 |
0.0006318 |
6.857459 |
0.0000000 |
1.0043422 |
Work_accident |
-1.4841619 |
0.1136100 |
-13.063650 |
0.0000000 |
0.2266923 |
grp.time5-7 |
1.3416190 |
0.0700726 |
19.146130 |
0.0000000 |
3.8252314 |
grp.time8-10 |
-14.2350334 |
156.2040875 |
-0.091131 |
0.9273885 |
0.0000007 |
salarylow |
1.7761701 |
0.1647064 |
10.783859 |
0.0000000 |
5.9071891 |
salarymedium |
1.3355641 |
0.1660276 |
8.044227 |
0.0000000 |
3.8021401 |
The highest odds ratio belongs to the salarylow variable at 5.907.
This means that when an employee has a low salary, their odds of leaving
the company increase by about 5.907. (Although this does not instantly
mean that having a low salary is the best indicator of if an employee
leaves the company). The variable for time has three different
categories with 2-4 as the base year. As the number of years spent at
the company increases, the odds of leaving the company decreases.
Summary and
Conclusion
To summarize, the data set we did an association analysis on looks at
several factors affecting why an employee would leave a company. The
data has nine explanatory variables. After discretising the variable
“time_spend_company” into three dummy variables, there are eleven
explanatory variables. We then built a full model, a reduced model, and
a final model. Due to their high significance, all of the explanatory
variables except for “Department” were kept in the final model. After
calculating the odds ratios for each explanatory variable in the final
model, we discovered that in regards to the time spent working at the
company, as the number of years spent at the company increases, the odds
of leaving the company decreases. To conclude, most of the variables in
the data set could strongly indicate whether or not an employee would
leave this certain company. This might suggest that other companies
should look at things such as their employee satisfaction rate, and
employee evaluation scores to predict if employees will stay with them
or leave.
LS0tDQp0aXRsZTogIk11bHRpcGxlIExvZ2lzdGljIFJlZ3Jlc3Npb24iDQphdXRob3I6ICdBdmEgRGVTdGVmYW5vJw0KZGF0ZTogIjEwLzIwLzI0Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgZmlnX3dpZHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgdGhlbWU6IGx1bWVuDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8NCiAgZm9udC1zaXplOiAyMHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBkYXRlICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBEZXRlY3QsIGluc3RhbGwgYW5kIGxvYWQgcGFja2FnZXMgaWYgbmVlZGVkLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJNQVNTIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIk1BU1MiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KaWYgKCFyZXF1aXJlKCJubGVxc2x2IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIm5sZXFzbHYiKQ0KICAgbGlicmFyeShubGVxc2x2KQ0KfQ0KIw0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBzeWNoIikpIHsgICANCiAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICAgbGlicmFyeShwc3ljaCkNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoIk1BU1MiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KDQojIHNwZWNpZmljYXRpb25zIG9mIG91dHB1dHMgb2YgY29kZSBpbiBjb2RlIGNodW5rcw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmdzID0gRkFMU0UsICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlcyA9IEZBTFNFLCAgIw0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFICAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuDQogICAgICAgICAgICAgICAgICAgICAgKSAgIA0KYGBgDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBkYXRhIHNldCB3YXMgb2J0YWluZWQgZnJvbSBrYWdnbGUuY29tLiBUaGUgZGF0YSBzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gb24gc2V2ZXJhbCB0aG91c2FuZCBlbXBsb3llZXMgZnJvbSBhbiB1bm5hbWVkIGNvbXBhbnkuIFNpbmNlIG5vIGRldGFpbHMgYXJlIGdpdmVuIGFib3V0IHRoZSBjb21wYW55LCBpdCBjYW5ub3QgYmUgc2FpZCBob3cgZXhhY3RseSB0aGUgZGF0YSB3YXMgY29sbGVjdGVkLiBUaGUgcmVzcG9uc2UgdmFyaWFibGUgd2UgYXJlIHRyeWluZyB0byBwcmVkaWN0IGlzIHdoZXRoZXIgb3Igbm8gYW4gZW1wbG95ZWUgc3RheXMgYXQgb3IgbGVhdmVzIHRoZSBjb21wYW55LiBUaGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIHJlbGF0ZSB0byBlYWNoIHN1YmplY3RzIHdvcmsgbGlmZS4gVGhlIHJlc3BvbnNlIHZhcmlhYmxlIGlzIHdoZXRoZXIgb3Igbm90IGFuIGVtcGxveWVlIHN0YXlzIGF0IG9yIGxlYXZlcyB0aGUgY29tcGFueS4gRm9yIG15IHNpbXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIGFuYWx5c2lzLCB0aGUgdmFyaWFibGUgdGhhdCBJIGFtIGdvaW5nIHRvIHVzZSBpcyAic2F0aXNmYWN0aW9uX2xldmVsIi4gVGhpcyBpcyB0aGUgZW1wbG95ZWVzIHNlbGYgcmVwb3J0ZWQgc2F0aXNmYWN0aW9uIGxldmVsLg0KDQojIyBWYXJpYWJsZSBEZXNjcmlwdGlvbiANCg0KKiBzYXRpc2ZhY3Rpb25fbGV2ZWwgKHgxKSAtIHRoZSBlbXBsb3llZXMgc2VsZiByZXBvcnRlZCBzYXRpc2ZhY3Rpb24gbGV2ZWwuIChOdW1lcmljIGZyb20gMC0xKQ0KKiBsYXN0X2V2YWx1YXRpb24gKHgyKSAtIHRoZSBlbXBsb3llZXMgbGFzdCBwZXJmb3JtYW5jZSByZXZpZXcuIChOdW1lcmljIGZyb20gMC0xKQ0KKiBudW1iZXJfcHJvamVjdCAoeDMpIC0gdGhlIG51bWJlciBvZiBwcm9qZWN0cyBhbiBlbXBsb3llZSBoYXMgZG9uZSBmb3IgdGhlIGNvbXBhbnkuIChOdW1lcmljKQ0KKiBhdmVyYWdlX21vbnRobHlfaG91cnMgKHg0KSAtIHRoZSBhdmVyYWdlIG51bWJlciBvZiBob3VycyBhbiBlbXBsb3llZSB3b3JrcyBwZXIgbW9udGguIChOdW1lcmljKQ0KKiB0aW1lX3NwZW5kX2NvbXBhbnkgKHg1KSAtIGhvdyBsb25nIHRoZSBlbXBsb3llZSBoYXMgd29ya2VkIGF0IHRoZSBjb21wYW55IGluIHllYXJzLiAoTnVtZXJpYykNCiogV29ya19hY2NpZGVudCAoeDYpIC0gbnVtYmVyIG9mIHdvcmsgcmVsYXRlZCBhY2NpZGVudHMgdGhlIGVtcGxveWVlIGhhcyBoYWQuIChOdW1lcmljKQ0KKiBwcm9tb3Rpb25fbGFzdF81eWVhcnMgKHg3KSAtIEhhcyB0aGUgZW1wbG95ZWUgaGFkIGEgcHJvbW90aW9uIGluIHRoZSBsYXN0IDUgeWVhcnM/IChCaW5hcnkgMT15ZXMsIDA9bjApDQoqIERlcGFydG1lbnQgKHg4KSAtIHRoZSBkZXBhcnRtZW50IHRoZSBlbXBsb3llZSBpcyBpbi4gKGNhdGVnb3JpY2FsKQ0KKiBTYWxhcnkgKHg5KSAtIHNhbGFyeSBsZXZlbC4gKGNhdGVnb3JpY2FsKQ0KKiBsZWZ0ICh5KSAtIHdoZXRoZXIgdGhlIGVtcGxveWVlIHN0YXlzIGF0IG9yIGxlYXZlcyB0aGUgY29tcGFueSAoMD1zdGF5LCAxPWxlYXZlKQ0KDQojIyBQcmFjdGljYWwgUXVlc3Rpb24gDQoNCkZvciB0aGlzIHN0dWR5LCB3ZSB3YW50IHRvIGlkZW50aWZ5IHdoaWNoIGZhY3RvcnMgYWJvdXQgYW4gZW1wbG95ZWUncyB3b3JrIGxpZmUgaW5kaWNhdGUgdGhleSB3aWxsIGxlYXZlIHRoZSBjb21wYW55Lg0KDQoNCiMjIERhdGEgRG93bmxvYWQgDQpgYGB7cn0NCmhyX2RhdGEgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9BdmFEZVN0L1NUQS0zMjEvcmVmcy9oZWFkcy9tYWluL0hSX2NvbW1hX3NlcC5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KDQoNCnByZWRfdmFycyA8LSBzZWxlY3QoaHJfZGF0YSwgLSAibGVmdCIpDQoNCg0KZGF0YShocl9kYXRhKSAgICAgICAgICAgDQpoci4wID0gaHJfZGF0YSAgICANCmhyX2QgPSBuYS5vbWl0KGhyLjApDQoNCmR1cGxpY2F0ZXMgPC0gZHVwbGljYXRlZChocl9kKQ0KDQpociA8LSB1bmlxdWUoaHJfZCkNCg0KYGBgDQoNClRoZSBhcmUgbm8gbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0LiBCdXQgdGhlcmUgYXJlIDMwMDggZHVwbGljYXRlIHZhbHVlcyBzbyBJIHRvb2sgdGhvc2Ugb3V0IG9mIHRoZSBkYXRhIHNldC4gDQoNCiMgRXhwbG9yYXRvcnkgQW5hbHlzaXMNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD03fQ0KZGF0YS5udW0gPC0gc2VsZWN0KGhyX2RhdGEsICJzYXRpc2ZhY3Rpb25fbGV2ZWwiLCAibGFzdF9ldmFsdWF0aW9uIiwgIm51bWJlcl9wcm9qZWN0IiwgImF2ZXJhZ2VfbW9udGx5X2hvdXJzIiwgInRpbWVfc3BlbmRfY29tcGFueSIpICNkYXRhIHNldCBvZiBvbmx5IHRoZSBudW1lcmljIHZhcmlhYmxlcw0KDQpwYWlycy5wYW5lbHMoZGF0YS5udW1bLC05XSwgDQogICAgICAgICAgICAgbWV0aG9kID0gInBlYXJzb24iLCANCiAgICAgICAgICAgICBoaXN0LmNvbCA9ICIjMDBBRkJCIiwNCiAgICAgICAgICAgICBkZW5zaXR5ID0gVFJVRSwgDQogICAgICAgICAgICAgZWxsaXBzZXMgPSBUUlVFIA0KICAgICAgICAgICAgICkNCmBgYA0KV2UgY2FuIHNlZSBmcm9tIHRoZSBncmFwaHMgdGhhdCB0aGUgdmFyaWFibGUgZm9yIHRoZSBudW1iZXIgb2YgeWVhcnMgc3BlbnQgYXQgdGhlIGNvbXBhbnkgaXMgc2tld2VkLiBIZXJlIGlzIGEgY2xvc2VyIGxvb2s6DQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9N30NCnBhcihtZnJvdz1jKDEsMikpDQpoaXN0KGhyJHRpbWVfc3BlbmRfY29tcGFueSwgeGxhYj0iWWVhcnMgYXQgdGhlIGNvbXBhbnkiLCBtYWluID0gIiIpDQpgYGANClRvIGZpeCB0aGlzLCBJIGFtIGdvaW5nIHRvIGRpc2NyZXRpemUgInRpbWVfc3BlbmRfY29tcGFueSIgYmFzZWQgb24gdGhlIGhpc3RvZ3JhbS4NCg0KYGBge3J9DQp0aW1lID0gaHIkdGltZV9zcGVuZF9jb21wYW55DQpncnAudGltZSA9IHRpbWUNCmdycC50aW1lW3RpbWUgJWluJSBjKDI6NCldID0gIjItNCINCmdycC50aW1lW3RpbWUgJWluJSBjKDU6NyldID0gIjUtNyINCmdycC50aW1lW3RpbWUgJWluJSBjKDg6MTApXSA9ICI4LTEwIg0KDQpociRncnAudGltZSA9IGdycC50aW1lDQoNCmBgYA0KDQpUaGVyZSBpcyBhIG1vZGVyYXRlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIG51bWJlciBvZiBwcm9qZWN0cyBhbmQgdGhlIGF2ZXJhZ2UgbW9udGhseSBob3VycyBhbiBlbXBsb3llZSBoYXMgd29ya2VkLiBCdXQgc2luY2UgdGhleSBhcmUgbm90IHRvbyBzaW1pbGFyLCB0aGV5IHdpbGwgYm90aCBiZSBrZXB0IGZvciB0aGUgdGltZSBiZWluZy4gVGhlcmUgaXMgbm8gbmVlZCB0byB0cmFuc2Zvcm0gYW55IG9mIHRoZSB2YXJpYWJsZXMgc2luY2Ugd2UgYXJlIG9ubHkgZG9pbmcgYXNzb2NpYXRpb24gYW5hbHlzaXMuIA0KDQojIE1vZGVsIEJ1aWxkaW5nIA0KDQpgYGB7cn0NCmZ1bGwubW9kZWwgPSBnbG0obGVmdCB+IHNhdGlzZmFjdGlvbl9sZXZlbCArIGxhc3RfZXZhbHVhdGlvbiArIG51bWJlcl9wcm9qZWN0ICsgYXZlcmFnZV9tb250bHlfaG91cnMgKyBXb3JrX2FjY2lkZW50ICsgcHJvbW90aW9uX2xhc3RfNXllYXJzICsgRGVwYXJ0bWVudCArIHNhbGFyeSArIGdycC50aW1lLCANCiAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksICAjICBsb2dpdChwKSA9IGxvZyhwLygxLXApKSENCiAgICAgICAgICBkYXRhID0gaHIpICANCmthYmxlKHN1bW1hcnkoZnVsbC5tb2RlbCkkY29lZiwgDQogICAgICBjYXB0aW9uPSJTdW1tYXJ5IG9mIGluZmVyZW50aWFsIHN0YXRpc3RpY3Mgb2YgdGhlIGZ1bGwgbW9kZWwiKQ0KYGBgDQoNCiMjIFJlZHVjZWQgTW9kZWwgDQoNCmBgYHtyfQ0KcmVkdWNlZC5tb2RlbCA9IGdsbShsZWZ0IH4gc2F0aXNmYWN0aW9uX2xldmVsICsgbGFzdF9ldmFsdWF0aW9uICsgbnVtYmVyX3Byb2plY3QgKyBwcm9tb3Rpb25fbGFzdF81eWVhcnMgKyBhdmVyYWdlX21vbnRseV9ob3VycyArIFdvcmtfYWNjaWRlbnQsIA0KICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgICMgbG9naXQocCkgPSBsb2cocC8oMS1wKSkhDQogICAgICAgICAgZGF0YSA9IGhyKSANCmthYmxlKHN1bW1hcnkocmVkdWNlZC5tb2RlbCkkY29lZiwgDQogICAgICBjYXB0aW9uPSJTdW1tYXJ5IG9mIGluZmVyZW50aWFsIHN0YXRpc3RpY3Mgb2YgdGhlIHJlZHVjZWQgbW9kZWwiKQ0KYGBgDQoNCiMjIEZpbmFsIE1vZGVsDQoNCmBgYHtyfQ0KZmluYWwubW9kZWwuZm9yd2FyZCA9IHN0ZXBBSUMocmVkdWNlZC5tb2RlbCwgDQogICAgICAgICAgICAgICAgICAgICAgc2NvcGUgPSBsaXN0KGxvd2VyPWZvcm11bGEocmVkdWNlZC5tb2RlbCksdXBwZXI9Zm9ybXVsYShmdWxsLm1vZGVsKSksDQogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gMCAgIA0KICAgICAgICAgICAgICAgICAgICAgICkNCmthYmxlKHN1bW1hcnkoZmluYWwubW9kZWwuZm9yd2FyZCkkY29lZiwgDQogICAgICBjYXB0aW9uPSJTdW1tYXJ5IG9mIGluZmVyZW50aWFsIHN0YXRpc3RpY3Mgb2YgdGhlIGZpbmFsIG1vZGVsIikNCmBgYA0KDQoNCkV2ZW4gdGhvdWdoIHdlIGRpc2NvdmVyZWQgdGhhdCB0aGUgbnVtYmVyIG9mIHByb2plY3RzIGFuIGVtcGxveWVlIGhhcyBhbmQgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGhvdXJzIHdvcmtlZCBoYXZlIGEgbW9kZXJhdGUgY29ycmVsYXRpb24sIHRoZSBmaW5hbCBtb2RlbCBzdGlsbCBpbmNsdWRlcyBib3RoIHZhcmlhYmxlcy4gV2UgY2FuIHNlZSB0aGF0IHRoZSBmaW5hbCBtb2RlIG9ubHkgdGFrZXMgb3V0IHRoZSB2YXJpYWJsZSAiRGVwYXJ0bWVudCIuIFRoZSBtb2RlbCBzdGlsbHMga2VlcHMgdGhlIHZhcmlhYmxlcyBmb3IgdGhlIG51bWJlciBvZiB5ZWFycyBzcGVudCBhdCB0aGUgY29tcGFueSAiZ3JwLnRpbWUiLCBldmVuIHRob3VnaCB3aGVuIHRpbWUgdGltZSBzcGVudCBhdCB0aGUgY29tcGFueSByYW5nZXMgZnJvbSA4LTEwIHllYXJzLCB0aGUgcC12YWx1ZSBpcyBubyBsb25nZXIgc2lnbmlmaWNhbnQuDQoNCmBgYHtyfQ0KZ2xvYmFsLm1lYXN1cmU9ZnVuY3Rpb24ocy5sb2dpdCl7DQpkZXYucmVzaWQgPSBzLmxvZ2l0JGRldmlhbmNlDQpkZXYuMC5yZXNpZCA9IHMubG9naXQkbnVsbC5kZXZpYW5jZQ0KYWljID0gcy5sb2dpdCRhaWMNCmdvb2RuZXNzID0gY2JpbmQoRGV2aWFuY2UucmVzaWR1YWwgPWRldi5yZXNpZCwgTnVsbC5EZXZpYW5jZS5SZXNpZHVhbCA9IGRldi4wLnJlc2lkLA0KICAgICAgQUlDID0gYWljKQ0KZ29vZG5lc3MNCn0NCmdvb2RuZXNzPXJiaW5kKGZ1bGwubW9kZWwgPSBnbG9iYWwubWVhc3VyZShmdWxsLm1vZGVsKSwNCiAgICAgIHJlZHVjZWQubW9kZWw9Z2xvYmFsLm1lYXN1cmUocmVkdWNlZC5tb2RlbCksDQogICAgICBmaW5hbC5tb2RlbD1nbG9iYWwubWVhc3VyZShmaW5hbC5tb2RlbC5mb3J3YXJkKSkNCnJvdy5uYW1lcyhnb29kbmVzcykgPSBjKCJmdWxsLm1vZGVsIiwgInJlZHVjZWQubW9kZWwiLCAiZmluYWwubW9kZWwiKQ0Ka2FibGUoZ29vZG5lc3MsIGNhcHRpb24gPSJDb21wYXJpc29uIG9mIGdsb2JhbCBnb29kbmVzcy1vZi1maXQgc3RhdGlzdGljcyIpDQpgYGANCldlIGNhbiBzZWUgdGhhdCB0aGUgZmluYWwgbW9kZWwgaGFzIHRoZSBsb3dlc3QgQUlDLCBpbmRpY2F0aW5nIGl0IGlzIHRoZSBiZXN0IG9uZSB0byB1c2UuIA0KDQojIyBPZGRzIFJhdGlvDQoNCmBgYHtyfQ0KbW9kZWwuY29lZi5zdGF0cyA9IHN1bW1hcnkoZmluYWwubW9kZWwuZm9yd2FyZCkkY29lZg0Kb2Rkcy5yYXRpbyA9IGV4cChjb2VmKGZpbmFsLm1vZGVsLmZvcndhcmQpKQ0Kb3V0LnN0YXRzID0gY2JpbmQobW9kZWwuY29lZi5zdGF0cywgb2Rkcy5yYXRpbyA9IG9kZHMucmF0aW8pICAgICAgICAgICAgICAgICANCmthYmxlKG91dC5zdGF0cyxjYXB0aW9uID0gIlN1bW1hcnkgU3RhdHMgd2l0aCBPZGRzIFJhdGlvcyIpDQpgYGANCg0KVGhlIGhpZ2hlc3Qgb2RkcyByYXRpbyBiZWxvbmdzIHRvIHRoZSBzYWxhcnlsb3cgdmFyaWFibGUgYXQgNS45MDcuIFRoaXMgbWVhbnMgdGhhdCB3aGVuIGFuIGVtcGxveWVlIGhhcyBhIGxvdyBzYWxhcnksIHRoZWlyIG9kZHMgb2YgbGVhdmluZyB0aGUgY29tcGFueSBpbmNyZWFzZSBieSBhYm91dCA1LjkwNy4gKEFsdGhvdWdoIHRoaXMgZG9lcyBub3QgaW5zdGFudGx5IG1lYW4gdGhhdCBoYXZpbmcgYSBsb3cgc2FsYXJ5IGlzIHRoZSBiZXN0IGluZGljYXRvciBvZiBpZiBhbiBlbXBsb3llZSBsZWF2ZXMgdGhlIGNvbXBhbnkpLiBUaGUgdmFyaWFibGUgZm9yIHRpbWUgaGFzIHRocmVlIGRpZmZlcmVudCBjYXRlZ29yaWVzIHdpdGggMi00IGFzIHRoZSBiYXNlIHllYXIuIEFzIHRoZSBudW1iZXIgb2YgeWVhcnMgc3BlbnQgYXQgdGhlIGNvbXBhbnkgaW5jcmVhc2VzLCB0aGUgb2RkcyBvZiBsZWF2aW5nIHRoZSBjb21wYW55IGRlY3JlYXNlcy4gDQoNCiMgU3VtbWFyeSBhbmQgQ29uY2x1c2lvbg0KDQpUbyBzdW1tYXJpemUsIHRoZSBkYXRhIHNldCB3ZSBkaWQgYW4gYXNzb2NpYXRpb24gYW5hbHlzaXMgb24gbG9va3MgYXQgc2V2ZXJhbCBmYWN0b3JzIGFmZmVjdGluZyB3aHkgYW4gZW1wbG95ZWUgd291bGQgbGVhdmUgYSBjb21wYW55LiBUaGUgZGF0YSBoYXMgbmluZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMuIEFmdGVyIGRpc2NyZXRpc2luZw0KdGhlIHZhcmlhYmxlICJ0aW1lX3NwZW5kX2NvbXBhbnkiIGludG8gdGhyZWUgZHVtbXkgdmFyaWFibGVzLCB0aGVyZSBhcmUgZWxldmVuIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4gV2UgdGhlbiBidWlsdCBhIGZ1bGwgbW9kZWwsIGEgcmVkdWNlZCBtb2RlbCwgYW5kIGEgZmluYWwgbW9kZWwuIER1ZSB0byB0aGVpciBoaWdoIHNpZ25pZmljYW5jZSwgYWxsIG9mIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgZXhjZXB0IGZvciAiRGVwYXJ0bWVudCIgd2VyZSBrZXB0IGluIHRoZSBmaW5hbCBtb2RlbC4gQWZ0ZXIgY2FsY3VsYXRpbmcgdGhlIG9kZHMgcmF0aW9zIGZvciBlYWNoIGV4cGxhbmF0b3J5IHZhcmlhYmxlIGluIHRoZSBmaW5hbCBtb2RlbCwgd2UgZGlzY292ZXJlZCB0aGF0IGluIHJlZ2FyZHMgdG8gdGhlIHRpbWUgc3BlbnQgd29ya2luZyBhdCB0aGUgY29tcGFueSwgYXMgdGhlIG51bWJlciBvZiB5ZWFycyBzcGVudCBhdCB0aGUgY29tcGFueSBpbmNyZWFzZXMsIHRoZSBvZGRzIG9mIGxlYXZpbmcgdGhlIGNvbXBhbnkgZGVjcmVhc2VzLiBUbyBjb25jbHVkZSwgbW9zdCBvZiB0aGUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldCBjb3VsZCBzdHJvbmdseSBpbmRpY2F0ZSB3aGV0aGVyIG9yIG5vdCBhbiBlbXBsb3llZSB3b3VsZCBsZWF2ZSB0aGlzIGNlcnRhaW4gY29tcGFueS4gVGhpcyBtaWdodCBzdWdnZXN0IHRoYXQgb3RoZXIgY29tcGFuaWVzIHNob3VsZCBsb29rIGF0IHRoaW5ncyBzdWNoIGFzIHRoZWlyIGVtcGxveWVlIHNhdGlzZmFjdGlvbiByYXRlLCBhbmQgZW1wbG95ZWUgZXZhbHVhdGlvbiBzY29yZXMgdG8gcHJlZGljdCBpZiBlbXBsb3llZXMgd2lsbCBzdGF5IHdpdGggdGhlbSBvciBsZWF2ZS4g