Logistic Regression

Description of data set

Within this study, the participants were aurally presented string combinations at varying audio volumes and were asked to identify the string.

The file module1-auditory_strings.csv contains the following data:

  • stimulus: character string that was aurally presented

  • condition: the volume at which it was presented (1: very quiet to 100: very loud)

  • response_correct: whether the response given by the participant was correct or incorrect

  • response_time: response time in seconds

Tasks

  1. Read the data file module1-auditory_strings.csv into R (assign it to a variable called “dat”).
dat <- read.csv("module1-auditory_strings.csv")
head(dat)
  1. Create three new variables in dat:

    • “volume” that contains the volume from “condition” as a numeric vector (e.g., 63 for the “condition” volume_63; Hint: You can use the function str_split_fixed() from the stringr package)

    • “stimulus_length” that contains the length of the “stimulus” variable (Hint: You can use the function str_length from the stringr package)

    • “response_correct” that contains the value 1 when the response was correct and 0 otherwise

library(stringr)
dat$volume <- str_split_fixed(dat$condition, "_", 2)[, 2]
dat$volume <- as.numeric(dat$volume)

dat$stimulus_length <- str_length(dat$stimulus)

dat$response_correct <- ifelse(dat$response_correct == 'correct', 1, 0)
  1. Estimate a logistic regression model for “response_correct” as target and “volume”, “stimulus_length”, and “response_time” as features. How to interpret the coefficients of this model? In other words, what’s the effect of each feature on the target in standardized units (i.e., odds ratio)?
library(mlr3verse)
tsk = as_task_classif(response_correct ~ volume + stimulus_length + response_time, data = dat, positive = "1")
mdl = lrn("classif.log_reg", predict_type = "prob")
mdl$train(tsk)
summary(mdl$model)

Call:
stats::glm(formula = task$formula(), family = "binomial", data = data, 
    model = FALSE)

Coefficients:
                 Estimate Std. Error z value Pr(>|z|)   
(Intercept)      0.501333   1.414371   0.354  0.72300   
response_time    0.093562   0.464206   0.202  0.84027   
stimulus_length -0.122235   0.064224  -1.903  0.05701 . 
volume          -0.008218   0.003155  -2.605  0.00919 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 693.15  on 499  degrees of freedom
Residual deviance: 682.31  on 496  degrees of freedom
AIC: 690.31

Number of Fisher Scoring iterations: 4
# estimated odds ratios
exp(coefficients(mdl$model))
    (Intercept)   response_time stimulus_length          volume 
      1.6509210       1.0980789       0.8849406       0.9918159 

The exponential coefficients of a logistic model can be interpreted as odds ratios. Accordingly, negative original coefficients (as for volume and stimulus_length) indicate that the chances to observe a 1 for the target decrease in the respective feature (and vice versa for positive coefficients; e.g., response_time). That is, higher volume and stimulus_length decrease, whereas descriptively higher response_time increases the chances for a correct response here. Moreover, the intercept not being significantly different from zero means that there are no differences in odds for correct or incorrect response for all features being zero (although this is not very informative without, for instance, using centered coefficients here).

  1. Using the model from task 3, calculate the predicted probability for a correct response for each observation and save it as “prob_correct_pred” in dat.
pred <- mdl$predict(tsk)

# predicted probability
dat$prob_correct_pred <- pred$prob[,"1"]

# exploratory plotting
ggplot(dat, aes(x = volume, y = prob_correct_pred)) +
  geom_point()

When we plot the predicted probabilities as a function of a feature, we see that the logistic model actually fitted a linear function to the auxiliary target.

  1. Manually calculate the predicted value of “response_correct” using a cutoff value of 0.5 for the probabilities calculated in task 4 and save it as “response_correct_pred” in dat. Is the result equivalent to the default prediction of mlr3’s predict() method?
# predicted response (with cutoff of 0.5) 
dat$response_correct_pred <- ifelse(dat$prob_correct_pred >= 0.5, 1, 0)

# comparison to mlr3's default prediction
sum(dat$response_correct_pred == pred$response) / nrow(dat)
[1] 1

By default, mlr3’s predict() method uses a cutoff of 0.5 to classify observations according to the predicted probabilities of class membership.

  1. Assess the prediction performance of the model by comparing the actual “response_correct” to the predicted “response_correct_pred” from task 5 using a contingency table. What’s the prediction accuracy of the model?
# contingency table
## mlr3verse:
pred$confusion
        truth
response   1   0
       1 138 111
       0 112 139
## manual:
#cont_table <- with(dat, table(response_correct_pred, response_correct))
#cont_table

# prediction accuracy
## mlr3verse:
mes <- msrs(c("classif.acc"))
pred$score(measures = mes)
classif.acc 
      0.554 
## manual:
#acc <- (cont_table[1,1] + cont_table[2,2]) / sum(cont_table)
#acc

The prediction accuracy is only slightly above chance for our logistic regression model.

  1. Calculate the predicted probability for a correct response for a “stimulus_length” of 3, the mean “volume”, and the first and third quartiles of “response_time”. Do the logistic model’s predictions for “response_correct” differ between the first and third quartiles of “response_time” using a cutoff value of 0.5?
dat_new <- data.frame('volume' = mean(dat$volume)
                      , 'stimulus_length' = 3
                      , 'response_time' = quantile(dat$response_time)[c('25%','75%')]
                      )
pred_new <- mdl$predict_newdata(newdata = dat_new)
#pred_old <- mdl$predict_newdata(newdata = dat)

dat_new$prob_correct_pred <- pred_new$prob[,"1"]
dat_new

As the predicted probability for a correct response is smaller than the cutoff for the first quartile of “response_time”, the model would predict a wrong response, whereas it would predict a correct response for the third quartile. Importantly, however, the differences are not very substantial because the coefficient of “response_time” is not significantly different from zero.

  1. Bonus: Also estimate a linear regression model for the model as specified in task 3, that is, for “response_correct” as target and “volume”, “stimulus_length”, and “response_time” as features.
task_lin = as_task_regr(response_correct ~ volume + stimulus_length + response_time, data = dat)
mdl_lin = lrn("regr.lm")
mdl_lin$train(task_lin)
summary(mdl_lin$model)

Call:
stats::lm(formula = task$formula(), data = task$data())

Residuals:
     Min       1Q   Median       3Q      Max 
-0.65500 -0.48392  0.00504  0.49281  0.65963 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)   
(Intercept)      0.6230940  0.3471279   1.795  0.07326 . 
response_time    0.0230195  0.1139398   0.202  0.83997   
stimulus_length -0.0299921  0.0157301  -1.907  0.05714 . 
volume          -0.0020219  0.0007707  -2.623  0.00898 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4966 on 496 degrees of freedom
Multiple R-squared:  0.02149,   Adjusted R-squared:  0.01558 
F-statistic: 3.632 on 3 and 496 DF,  p-value: 0.01293

Note that that significance of the individual features is comparable to the results of the significance testing in the logistic regression model from task 3.

  1. Bonus: Why is the linear model estimated in task 8 fundamentally wrong? (Hint: Use both models, i.e., linear and logistic regression, to predict the probability for a correct response for the following new data set “dat_new2” with extremely high “stimulus_length”, and compare the results)
dat_new2 <- data.frame('stimulus_length' = 50
                       , 'response_time' = 5*max(dat$response_time)
                       , 'volume' = mean(dat$volume)
                       )
# prediction of linear model for extreme data
mdl_lin$predict_newdata(newdata = dat_new2)$response
[1] -0.5548653
# prediction of logistic model for extreme data
mdl$predict_newdata(newdata = dat_new2)$prob[,"1"]
         1 
0.01334644 

The linear model is conceptually wrong for binary targets because it allows negative probabilities and probabilities above 1, whereas the logistic model is well-defined, which can be seen, for instance, for the predicted probabilities of both models for the new (extreme) data.

LS0tDQp0aXRsZTogIk1vZHVsZSAxOiBUdXRvcmlhbDogUmVncmVzc2lvbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KIyBMb2dpc3RpYyBSZWdyZXNzaW9uDQoNCiMjIERlc2NyaXB0aW9uIG9mIGRhdGEgc2V0DQoNCldpdGhpbiB0aGlzIHN0dWR5LCB0aGUgcGFydGljaXBhbnRzIHdlcmUgYXVyYWxseSBwcmVzZW50ZWQgc3RyaW5nIGNvbWJpbmF0aW9ucyBhdCB2YXJ5aW5nIGF1ZGlvIHZvbHVtZXMgYW5kIHdlcmUgYXNrZWQgdG8gaWRlbnRpZnkgdGhlIHN0cmluZy4NCg0KVGhlIGZpbGUgbW9kdWxlMS1hdWRpdG9yeV9zdHJpbmdzLmNzdiBjb250YWlucyB0aGUgZm9sbG93aW5nIGRhdGE6DQoNCi0gICBzdGltdWx1czogY2hhcmFjdGVyIHN0cmluZyB0aGF0IHdhcyBhdXJhbGx5IHByZXNlbnRlZA0KDQotICAgY29uZGl0aW9uOiB0aGUgdm9sdW1lIGF0IHdoaWNoIGl0IHdhcyBwcmVzZW50ZWQgKDE6IHZlcnkgcXVpZXQgdG8gMTAwOiB2ZXJ5IGxvdWQpDQoNCi0gICByZXNwb25zZV9jb3JyZWN0OiB3aGV0aGVyIHRoZSByZXNwb25zZSBnaXZlbiBieSB0aGUgcGFydGljaXBhbnQgd2FzIGNvcnJlY3Qgb3IgaW5jb3JyZWN0DQoNCi0gICByZXNwb25zZV90aW1lOiByZXNwb25zZSB0aW1lIGluIHNlY29uZHMNCg0KIyMgVGFza3MNCg0KMS4gIFJlYWQgdGhlIGRhdGEgZmlsZSBtb2R1bGUxLWF1ZGl0b3J5X3N0cmluZ3MuY3N2IGludG8gUiAoYXNzaWduIGl0IHRvIGEgdmFyaWFibGUgY2FsbGVkICJkYXQiKS4NCg0KYGBge3J9DQpkYXQgPC0gcmVhZC5jc3YoIm1vZHVsZTEtYXVkaXRvcnlfc3RyaW5ncy5jc3YiKQ0KaGVhZChkYXQpDQpgYGANCg0KMi4gIENyZWF0ZSB0aHJlZSBuZXcgdmFyaWFibGVzIGluIGRhdDoNCg0KICAgIC0gICAidm9sdW1lIiB0aGF0IGNvbnRhaW5zIHRoZSB2b2x1bWUgZnJvbSAiY29uZGl0aW9uIiBhcyBhIG51bWVyaWMgdmVjdG9yIChlLmcuLCA2MyBmb3IgdGhlICJjb25kaXRpb24iIHZvbHVtZV82MzsgSGludDogWW91IGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGBzdHJfc3BsaXRfZml4ZWQoKWAgZnJvbSB0aGUgYHN0cmluZ3JgIHBhY2thZ2UpDQoNCiAgICAtICAgInN0aW11bHVzX2xlbmd0aCIgdGhhdCBjb250YWlucyB0aGUgbGVuZ3RoIG9mIHRoZSAic3RpbXVsdXMiIHZhcmlhYmxlIChIaW50OiBZb3UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gYHN0cl9sZW5ndGhgIGZyb20gdGhlIGBzdHJpbmdyYCBwYWNrYWdlKQ0KDQogICAgLSAgICJyZXNwb25zZV9jb3JyZWN0IiB0aGF0IGNvbnRhaW5zIHRoZSB2YWx1ZSAxIHdoZW4gdGhlIHJlc3BvbnNlIHdhcyBjb3JyZWN0IGFuZCAwIG90aGVyd2lzZQ0KDQpgYGB7cn0NCmxpYnJhcnkoc3RyaW5ncikNCmRhdCR2b2x1bWUgPC0gc3RyX3NwbGl0X2ZpeGVkKGRhdCRjb25kaXRpb24sICJfIiwgMilbLCAyXQ0KZGF0JHZvbHVtZSA8LSBhcy5udW1lcmljKGRhdCR2b2x1bWUpDQoNCmRhdCRzdGltdWx1c19sZW5ndGggPC0gc3RyX2xlbmd0aChkYXQkc3RpbXVsdXMpDQoNCmRhdCRyZXNwb25zZV9jb3JyZWN0IDwtIGlmZWxzZShkYXQkcmVzcG9uc2VfY29ycmVjdCA9PSAnY29ycmVjdCcsIDEsIDApDQpgYGANCg0KMy4gIEVzdGltYXRlIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCBmb3IgInJlc3BvbnNlX2NvcnJlY3QiIGFzIHRhcmdldCBhbmQgInZvbHVtZSIsICJzdGltdWx1c19sZW5ndGgiLCBhbmQgInJlc3BvbnNlX3RpbWUiIGFzIGZlYXR1cmVzLiBIb3cgdG8gaW50ZXJwcmV0IHRoZSBjb2VmZmljaWVudHMgb2YgdGhpcyBtb2RlbD8gSW4gb3RoZXIgd29yZHMsIHdoYXQncyB0aGUgZWZmZWN0IG9mIGVhY2ggZmVhdHVyZSBvbiB0aGUgdGFyZ2V0IGluIHN0YW5kYXJkaXplZCB1bml0cyAoaS5lLiwgb2RkcyByYXRpbyk/DQoNCmBgYHtyfQ0KbGlicmFyeShtbHIzdmVyc2UpDQp0c2sgPSBhc190YXNrX2NsYXNzaWYocmVzcG9uc2VfY29ycmVjdCB+IHZvbHVtZSArIHN0aW11bHVzX2xlbmd0aCArIHJlc3BvbnNlX3RpbWUsIGRhdGEgPSBkYXQsIHBvc2l0aXZlID0gIjEiKQ0KbWRsID0gbHJuKCJjbGFzc2lmLmxvZ19yZWciLCBwcmVkaWN0X3R5cGUgPSAicHJvYiIpDQptZGwkdHJhaW4odHNrKQ0Kc3VtbWFyeShtZGwkbW9kZWwpDQoNCiMgZXN0aW1hdGVkIG9kZHMgcmF0aW9zDQpleHAoY29lZmZpY2llbnRzKG1kbCRtb2RlbCkpDQpgYGANCg0KVGhlIGV4cG9uZW50aWFsIGNvZWZmaWNpZW50cyBvZiBhIGxvZ2lzdGljIG1vZGVsIGNhbiBiZSBpbnRlcnByZXRlZCBhcyBvZGRzIHJhdGlvcy4gQWNjb3JkaW5nbHksIG5lZ2F0aXZlIG9yaWdpbmFsIGNvZWZmaWNpZW50cyAoYXMgZm9yIHZvbHVtZSBhbmQgc3RpbXVsdXNfbGVuZ3RoKSBpbmRpY2F0ZSB0aGF0IHRoZSBjaGFuY2VzIHRvIG9ic2VydmUgYSAxIGZvciB0aGUgdGFyZ2V0IGRlY3JlYXNlIGluIHRoZSByZXNwZWN0aXZlIGZlYXR1cmUgKGFuZCB2aWNlIHZlcnNhIGZvciBwb3NpdGl2ZSBjb2VmZmljaWVudHM7IGUuZy4sIHJlc3BvbnNlX3RpbWUpLiBUaGF0IGlzLCBoaWdoZXIgdm9sdW1lIGFuZCBzdGltdWx1c19sZW5ndGggZGVjcmVhc2UsIHdoZXJlYXMgZGVzY3JpcHRpdmVseSBoaWdoZXIgcmVzcG9uc2VfdGltZSBpbmNyZWFzZXMgdGhlIGNoYW5jZXMgZm9yIGEgY29ycmVjdCByZXNwb25zZSBoZXJlLiBNb3Jlb3ZlciwgdGhlIGludGVyY2VwdCBub3QgYmVpbmcgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB6ZXJvIG1lYW5zIHRoYXQgdGhlcmUgYXJlIG5vIGRpZmZlcmVuY2VzIGluIG9kZHMgZm9yIGNvcnJlY3Qgb3IgaW5jb3JyZWN0IHJlc3BvbnNlIGZvciBhbGwgZmVhdHVyZXMgYmVpbmcgemVybyAoYWx0aG91Z2ggdGhpcyBpcyBub3QgdmVyeSBpbmZvcm1hdGl2ZSB3aXRob3V0LCBmb3IgaW5zdGFuY2UsIHVzaW5nIGNlbnRlcmVkIGNvZWZmaWNpZW50cyBoZXJlKS4NCg0KNC4gIFVzaW5nIHRoZSBtb2RlbCBmcm9tIHRhc2sgMywgY2FsY3VsYXRlIHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgZm9yIGEgY29ycmVjdCByZXNwb25zZSBmb3IgZWFjaCBvYnNlcnZhdGlvbiBhbmQgc2F2ZSBpdCBhcyAicHJvYl9jb3JyZWN0X3ByZWQiIGluIGRhdC4NCg0KYGBge3J9DQpwcmVkIDwtIG1kbCRwcmVkaWN0KHRzaykNCg0KIyBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkNCmRhdCRwcm9iX2NvcnJlY3RfcHJlZCA8LSBwcmVkJHByb2JbLCIxIl0NCg0KIyBleHBsb3JhdG9yeSBwbG90dGluZw0KZ2dwbG90KGRhdCwgYWVzKHggPSB2b2x1bWUsIHkgPSBwcm9iX2NvcnJlY3RfcHJlZCkpICsNCiAgZ2VvbV9wb2ludCgpDQpgYGANCg0KV2hlbiB3ZSBwbG90IHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBhcyBhIGZ1bmN0aW9uIG9mIGEgZmVhdHVyZSwgd2Ugc2VlIHRoYXQgdGhlIGxvZ2lzdGljIG1vZGVsIGFjdHVhbGx5IGZpdHRlZCBhIGxpbmVhciBmdW5jdGlvbiB0byB0aGUgYXV4aWxpYXJ5IHRhcmdldC4NCg0KNS4gIE1hbnVhbGx5IGNhbGN1bGF0ZSB0aGUgcHJlZGljdGVkIHZhbHVlIG9mICJyZXNwb25zZV9jb3JyZWN0IiB1c2luZyBhIGN1dG9mZiB2YWx1ZSBvZiAwLjUgZm9yIHRoZSBwcm9iYWJpbGl0aWVzIGNhbGN1bGF0ZWQgaW4gdGFzayA0IGFuZCBzYXZlIGl0IGFzICJyZXNwb25zZV9jb3JyZWN0X3ByZWQiIGluIGRhdC4gSXMgdGhlIHJlc3VsdCBlcXVpdmFsZW50IHRvIHRoZSBkZWZhdWx0IHByZWRpY3Rpb24gb2YgYG1scjNgJ3MgYHByZWRpY3QoKWAgbWV0aG9kPw0KDQpgYGB7cn0NCiMgcHJlZGljdGVkIHJlc3BvbnNlICh3aXRoIGN1dG9mZiBvZiAwLjUpIA0KZGF0JHJlc3BvbnNlX2NvcnJlY3RfcHJlZCA8LSBpZmVsc2UoZGF0JHByb2JfY29ycmVjdF9wcmVkID49IDAuNSwgMSwgMCkNCg0KIyBjb21wYXJpc29uIHRvIG1scjMncyBkZWZhdWx0IHByZWRpY3Rpb24NCnN1bShkYXQkcmVzcG9uc2VfY29ycmVjdF9wcmVkID09IHByZWQkcmVzcG9uc2UpIC8gbnJvdyhkYXQpDQpgYGANCg0KQnkgZGVmYXVsdCwgYG1scjNgJ3MgYHByZWRpY3QoKWAgbWV0aG9kIHVzZXMgYSBjdXRvZmYgb2YgMC41IHRvIGNsYXNzaWZ5IG9ic2VydmF0aW9ucyBhY2NvcmRpbmcgdG8gdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIG9mIGNsYXNzIG1lbWJlcnNoaXAuDQoNCjYuICBBc3Nlc3MgdGhlIHByZWRpY3Rpb24gcGVyZm9ybWFuY2Ugb2YgdGhlIG1vZGVsIGJ5IGNvbXBhcmluZyB0aGUgYWN0dWFsICJyZXNwb25zZV9jb3JyZWN0IiB0byB0aGUgcHJlZGljdGVkICJyZXNwb25zZV9jb3JyZWN0X3ByZWQiIGZyb20gdGFzayA1IHVzaW5nIGEgY29udGluZ2VuY3kgdGFibGUuIFdoYXQncyB0aGUgcHJlZGljdGlvbiBhY2N1cmFjeSBvZiB0aGUgbW9kZWw/DQoNCmBgYHtyfQ0KIyBjb250aW5nZW5jeSB0YWJsZQ0KIyMgbWxyM3ZlcnNlOg0KcHJlZCRjb25mdXNpb24NCg0KIyMgbWFudWFsOg0KI2NvbnRfdGFibGUgPC0gd2l0aChkYXQsIHRhYmxlKHJlc3BvbnNlX2NvcnJlY3RfcHJlZCwgcmVzcG9uc2VfY29ycmVjdCkpDQojY29udF90YWJsZQ0KDQojIHByZWRpY3Rpb24gYWNjdXJhY3kNCiMjIG1scjN2ZXJzZToNCm1lcyA8LSBtc3JzKGMoImNsYXNzaWYuYWNjIikpDQpwcmVkJHNjb3JlKG1lYXN1cmVzID0gbWVzKQ0KDQojIyBtYW51YWw6DQojYWNjIDwtIChjb250X3RhYmxlWzEsMV0gKyBjb250X3RhYmxlWzIsMl0pIC8gc3VtKGNvbnRfdGFibGUpDQojYWNjDQpgYGANCg0KVGhlIHByZWRpY3Rpb24gYWNjdXJhY3kgaXMgb25seSBzbGlnaHRseSBhYm92ZSBjaGFuY2UgZm9yIG91ciBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLg0KDQo3LiAgQ2FsY3VsYXRlIHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgZm9yIGEgY29ycmVjdCByZXNwb25zZSBmb3IgYSAic3RpbXVsdXNfbGVuZ3RoIiBvZiAzLCB0aGUgbWVhbiAidm9sdW1lIiwgYW5kIHRoZSBmaXJzdCBhbmQgdGhpcmQgcXVhcnRpbGVzIG9mICJyZXNwb25zZV90aW1lIi4gRG8gdGhlIGxvZ2lzdGljIG1vZGVsJ3MgcHJlZGljdGlvbnMgZm9yICJyZXNwb25zZV9jb3JyZWN0IiBkaWZmZXIgYmV0d2VlbiB0aGUgZmlyc3QgYW5kIHRoaXJkIHF1YXJ0aWxlcyBvZiAicmVzcG9uc2VfdGltZSIgdXNpbmcgYSBjdXRvZmYgdmFsdWUgb2YgMC41Pw0KDQpgYGB7cn0NCmRhdF9uZXcgPC0gZGF0YS5mcmFtZSgndm9sdW1lJyA9IG1lYW4oZGF0JHZvbHVtZSkNCiAgICAgICAgICAgICAgICAgICAgICAsICdzdGltdWx1c19sZW5ndGgnID0gMw0KICAgICAgICAgICAgICAgICAgICAgICwgJ3Jlc3BvbnNlX3RpbWUnID0gcXVhbnRpbGUoZGF0JHJlc3BvbnNlX3RpbWUpW2MoJzI1JScsJzc1JScpXQ0KICAgICAgICAgICAgICAgICAgICAgICkNCnByZWRfbmV3IDwtIG1kbCRwcmVkaWN0X25ld2RhdGEobmV3ZGF0YSA9IGRhdF9uZXcpDQojcHJlZF9vbGQgPC0gbWRsJHByZWRpY3RfbmV3ZGF0YShuZXdkYXRhID0gZGF0KQ0KDQpkYXRfbmV3JHByb2JfY29ycmVjdF9wcmVkIDwtIHByZWRfbmV3JHByb2JbLCIxIl0NCmRhdF9uZXcNCmBgYA0KDQpBcyB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXR5IGZvciBhIGNvcnJlY3QgcmVzcG9uc2UgaXMgc21hbGxlciB0aGFuIHRoZSBjdXRvZmYgZm9yIHRoZSBmaXJzdCBxdWFydGlsZSBvZiAicmVzcG9uc2VfdGltZSIsIHRoZSBtb2RlbCB3b3VsZCBwcmVkaWN0IGEgd3JvbmcgcmVzcG9uc2UsIHdoZXJlYXMgaXQgd291bGQgcHJlZGljdCBhIGNvcnJlY3QgcmVzcG9uc2UgZm9yIHRoZSB0aGlyZCBxdWFydGlsZS4gSW1wb3J0YW50bHksIGhvd2V2ZXIsIHRoZSBkaWZmZXJlbmNlcyBhcmUgbm90IHZlcnkgc3Vic3RhbnRpYWwgYmVjYXVzZSB0aGUgY29lZmZpY2llbnQgb2YgInJlc3BvbnNlX3RpbWUiIGlzIG5vdCBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHplcm8uDQoNCjguICBCb251czogQWxzbyBlc3RpbWF0ZSBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGZvciB0aGUgbW9kZWwgYXMgc3BlY2lmaWVkIGluIHRhc2sgMywgdGhhdCBpcywgZm9yICJyZXNwb25zZV9jb3JyZWN0IiBhcyB0YXJnZXQgYW5kICJ2b2x1bWUiLCAic3RpbXVsdXNfbGVuZ3RoIiwgYW5kICJyZXNwb25zZV90aW1lIiBhcyBmZWF0dXJlcy4NCg0KYGBge3J9DQp0YXNrX2xpbiA9IGFzX3Rhc2tfcmVncihyZXNwb25zZV9jb3JyZWN0IH4gdm9sdW1lICsgc3RpbXVsdXNfbGVuZ3RoICsgcmVzcG9uc2VfdGltZSwgZGF0YSA9IGRhdCkNCm1kbF9saW4gPSBscm4oInJlZ3IubG0iKQ0KbWRsX2xpbiR0cmFpbih0YXNrX2xpbikNCnN1bW1hcnkobWRsX2xpbiRtb2RlbCkNCmBgYA0KDQpOb3RlIHRoYXQgdGhhdCBzaWduaWZpY2FuY2Ugb2YgdGhlIGluZGl2aWR1YWwgZmVhdHVyZXMgaXMgY29tcGFyYWJsZSB0byB0aGUgcmVzdWx0cyBvZiB0aGUgc2lnbmlmaWNhbmNlIHRlc3RpbmcgaW4gdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgZnJvbSB0YXNrIDMuDQoNCjkuICBCb251czogV2h5IGlzIHRoZSBsaW5lYXIgbW9kZWwgZXN0aW1hdGVkIGluIHRhc2sgOCBmdW5kYW1lbnRhbGx5IHdyb25nPyAoSGludDogVXNlIGJvdGggbW9kZWxzLCBpLmUuLCBsaW5lYXIgYW5kIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIHRvIHByZWRpY3QgdGhlIHByb2JhYmlsaXR5IGZvciBhIGNvcnJlY3QgcmVzcG9uc2UgZm9yIHRoZSBmb2xsb3dpbmcgbmV3IGRhdGEgc2V0ICJkYXRfbmV3MiIgd2l0aCBleHRyZW1lbHkgaGlnaCAic3RpbXVsdXNfbGVuZ3RoIiwgYW5kIGNvbXBhcmUgdGhlIHJlc3VsdHMpDQoNCmBgYHtyfQ0KZGF0X25ldzIgPC0gZGF0YS5mcmFtZSgnc3RpbXVsdXNfbGVuZ3RoJyA9IDUwDQogICAgICAgICAgICAgICAgICAgICAgICwgJ3Jlc3BvbnNlX3RpbWUnID0gNSptYXgoZGF0JHJlc3BvbnNlX3RpbWUpDQogICAgICAgICAgICAgICAgICAgICAgICwgJ3ZvbHVtZScgPSBtZWFuKGRhdCR2b2x1bWUpDQogICAgICAgICAgICAgICAgICAgICAgICkNCmBgYA0KDQpgYGB7cn0NCiMgcHJlZGljdGlvbiBvZiBsaW5lYXIgbW9kZWwgZm9yIGV4dHJlbWUgZGF0YQ0KbWRsX2xpbiRwcmVkaWN0X25ld2RhdGEobmV3ZGF0YSA9IGRhdF9uZXcyKSRyZXNwb25zZQ0KDQojIHByZWRpY3Rpb24gb2YgbG9naXN0aWMgbW9kZWwgZm9yIGV4dHJlbWUgZGF0YQ0KbWRsJHByZWRpY3RfbmV3ZGF0YShuZXdkYXRhID0gZGF0X25ldzIpJHByb2JbLCIxIl0NCmBgYA0KDQpUaGUgbGluZWFyIG1vZGVsIGlzIGNvbmNlcHR1YWxseSB3cm9uZyBmb3IgYmluYXJ5IHRhcmdldHMgYmVjYXVzZSBpdCBhbGxvd3MgbmVnYXRpdmUgcHJvYmFiaWxpdGllcyBhbmQgcHJvYmFiaWxpdGllcyBhYm92ZSAxLCB3aGVyZWFzIHRoZSBsb2dpc3RpYyBtb2RlbCBpcyB3ZWxsLWRlZmluZWQsIHdoaWNoIGNhbiBiZSBzZWVuLCBmb3IgaW5zdGFuY2UsIGZvciB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMgb2YgYm90aCBtb2RlbHMgZm9yIHRoZSBuZXcgKGV4dHJlbWUpIGRhdGEuDQo=