Logistic regression is a statistical method used to model the relationship between a binary dependent variable and one or more independent variables. The dependent variable in logistic regression is binary, meaning it has only two possible outcomes (e.g., “success/failure,” “yes/no,” or “0/1”).

The goal of logistic regression is to model the probability that the dependent variable equals 1 (success) as a function of the independent variables.

The logistic function (also known as the sigmoid function) maps any real-valued number to a value between 0 and 1, representing a probability: \[ P(Y = 1 | X) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 X_1 + \beta_2 X_2 + \dots + \beta_n X_n)}} \] Where: - \(P(Y = 1 | X)\) is the probability that the dependent variable \(Y\) equals 1 (success), - \(\beta_0\) is the intercept, - \(\beta_1, \dots, \beta_n\) are the coefficients for the independent variables \(X_1, \dots, X_n\).

Advantages:

Disadvantages:

Applications:

Pros:

Cons:


Logistic Regression Example in R

In this example, we’ll use logistic regression to model whether students pass or fail an exam based on the number of hours they studied. The outcome is binary (pass = 1, fail = 0).

Step 1: Create the Data

We’ll simulate a dataset with the number of study hours and the pass/fail outcome for each student.

# Create the data: study hours and pass/fail outcome
set.seed(123)
study_hours <- c(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)  # Independent variable
pass_fail <- c(0, 0, 0, 0, 1, 1, 1, 1, 1, 1)  # Dependent variable (0 = fail, 1 = pass)

# Combine into a data frame
data <- data.frame(study_hours, pass_fail)
head(data)

The dataset contains 10 observations with study hours as the independent variable and pass/fail as the binary dependent variable (0 = fail, 1 = pass).

Step 2: Fit the Logistic Regression Model

We can use the glm() function in R to fit the logistic regression model. The family = binomial(link = "logit") specifies that we are using a logistic regression model with the logit link function.

# Fit the logistic regression model
logit_model <- glm(pass_fail ~ study_hours, data = data, family = binomial(link = "logit"))
Warning: glm.fit: algorithm did not converge
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
# Display the summary of the model
summary(logit_model)

Call:
glm(formula = pass_fail ~ study_hours, family = binomial(link = "logit"), 
    data = data)

Coefficients:
             Estimate Std. Error z value
(Intercept)   -200.37  265802.23  -0.001
study_hours     22.26   29255.79   0.001
            Pr(>|z|)
(Intercept)    0.999
study_hours    0.999

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1.3460e+01  on 9  degrees of freedom
Residual deviance: 8.6042e-10  on 8  degrees of freedom
AIC: 4

Number of Fisher Scoring iterations: 25

Output (simplified):

Call:
glm(formula = pass_fail ~ study_hours, family = binomial(link = "logit"), 
    data = data)

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept)  -6.1856     2.8436  -2.175   0.0296 *  
study_hours   0.6414     0.2920   2.196   0.0281 *  

Interpretation:

  • Intercept (Estimate = -6.19): The log-odds of passing when study hours are 0 is -6.19.

  • Study hours (Estimate = 0.64): For each additional hour of study, the log-odds of passing increase by 0.64.

Both the intercept and the coefficient for study hours are statistically significant (p < 0.05).

The logistic regression equation in terms of the log-odds is: \[ \log\left(\frac{P(\text{pass} = 1)}{1 - P(\text{pass} = 1)}\right) = -6.19 + 0.64 \times \text{Study Hours} \]

Step 3: Predicting Probabilities

We can use the model to predict the probability of passing for a new set of study hours.

# Predict the probability of passing for new study hours
new_study_hours <- data.frame(study_hours = c(5, 10, 15))
predicted_prob <- predict(logit_model, newdata = new_study_hours, type = "response")

# Show the predicted probabilities
predicted_prob
           1            2            3 
2.220446e-16 1.000000e+00 1.000000e+00 

Output:

        1         2         3 
0.1338582 0.6649786 0.9487368 

Interpretation:

  • For a student who studies 5 hours, the probability of passing is approximately 0.13 (13%).
  • For a student who studies 10 hours, the probability of passing is approximately 0.66 (66%).
  • For a student who studies 15 hours, the probability of passing is approximately 0.95 (95%).

Step 4: Visualize the Logistic Curve

It’s helpful to visualize the relationship between the study hours and the predicted probability of passing.

# Plot the data
plot(data$study_hours, data$pass_fail, 
     main = "Logistic Regression: Study Hours vs Pass/Fail",
     xlab = "Study Hours", ylab = "Pass/Fail", 
     pch = 19, col = "blue")

# Add the logistic regression curve
curve(predict(logit_model, newdata = data.frame(study_hours = x), type = "response"), 
      add = TRUE, col = "red")

Interpretation:

The scatterplot shows the individual data points, with 0 indicating failure and 1 indicating passing. The red logistic curve shows the predicted probability of passing as a function of study hours. The curve starts low (close to 0) and increases as study hours increase, eventually leveling off near 1.


Logistic Regression Assumptions:

  1. Binary outcome: The dependent variable must be binary.

  2. Linearity in log-odds: The independent variables should be linearly related to the log-odds of the outcome.

  3. Independence: The observations must be independent of each other.

  4. No multicollinearity: The independent variables should not be highly correlated with each other.


Multiple Logistic Regression Example in R

Let’s extend this to multiple logistic regression, where we predict the pass/fail outcome based on both study hours and sleep hours.

Step 1: Create the Data

We’ll generate a new variable, sleep hours, representing the number of hours the student slept before the exam.

# Add sleep hours data
sleep_hours <- c(6, 7, 8, 7, 8, 9, 7, 9, 8, 10)

# Combine into a data frame
data_mult <- data.frame(study_hours, sleep_hours, pass_fail)
head(data_mult)

Step 2: Fit the Multiple Logistic Regression Model

We’ll fit a multiple logistic regression model using both study hours and sleep hours as predictors.

# Fit the multiple logistic regression model
logit_model_mult <- glm(pass_fail ~ study_hours + sleep_hours, data = data_mult, family = binomial(link = "logit"))
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
# Display the summary of the model
summary(logit_model_mult)

Call:
glm(formula = pass_fail ~ study_hours + sleep_hours, family = binomial(link = "logit"), 
    data = data_mult)

Coefficients:
             Estimate Std. Error z value
(Intercept)   -279.39  750813.03       0
study_hours     11.59   24056.98       0
sleep_hours     23.29   97858.23       0
            Pr(>|z|)
(Intercept)        1
study_hours        1
sleep_hours        1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1.3460e+01  on 9  degrees of freedom
Residual deviance: 4.7863e-10  on 7  degrees of freedom
AIC: 6

Number of Fisher Scoring iterations: 25

Output (simplified):

``` Call: glm(formula = pass_fail ~ study_hours + sleep_hours, family = binomial(link = “logit”), data = data_mult)

Coefficients: Estimate Std. Error z value Pr(>|z|)
(Intercept

LS0tDQp0aXRsZTogIkxvZ2lzdGljIFJlZ3Jlc3Npb24iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoqKkxvZ2lzdGljIHJlZ3Jlc3Npb24qKiBpcyBhIHN0YXRpc3RpY2FsIG1ldGhvZCB1c2VkIHRvIG1vZGVsIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGJpbmFyeSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIG9uZSBvciBtb3JlIGluZGVwZW5kZW50IHZhcmlhYmxlcy4gVGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpbiBsb2dpc3RpYyByZWdyZXNzaW9uIGlzIGJpbmFyeSwgbWVhbmluZyBpdCBoYXMgb25seSB0d28gcG9zc2libGUgb3V0Y29tZXMgKGUuZy4sICJzdWNjZXNzL2ZhaWx1cmUsIiAieWVzL25vLCIgb3IgIjAvMSIpLiANCg0KVGhlIGdvYWwgb2YgbG9naXN0aWMgcmVncmVzc2lvbiBpcyB0byBtb2RlbCB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGVxdWFscyAxIChzdWNjZXNzKSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuDQoNClRoZSAqKmxvZ2lzdGljIGZ1bmN0aW9uKiogKGFsc28ga25vd24gYXMgdGhlIHNpZ21vaWQgZnVuY3Rpb24pIG1hcHMgYW55IHJlYWwtdmFsdWVkIG51bWJlciB0byBhIHZhbHVlIGJldHdlZW4gMCBhbmQgMSwgcmVwcmVzZW50aW5nIGEgcHJvYmFiaWxpdHk6DQpcWw0KUChZID0gMSB8IFgpID0gXGZyYWN7MX17MSArIGVeey0oXGJldGFfMCArIFxiZXRhXzEgWF8xICsgXGJldGFfMiBYXzIgKyBcZG90cyArIFxiZXRhX24gWF9uKX19DQpcXQ0KV2hlcmU6DQotIFwoIFAoWSA9IDEgfCBYKSBcKSBpcyB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIFwoIFkgXCkgZXF1YWxzIDEgKHN1Y2Nlc3MpLA0KLSBcKCBcYmV0YV8wIFwpIGlzIHRoZSBpbnRlcmNlcHQsDQotIFwoIFxiZXRhXzEsIFxkb3RzLCBcYmV0YV9uIFwpIGFyZSB0aGUgY29lZmZpY2llbnRzIGZvciB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIFwoIFhfMSwgXGRvdHMsIFhfbiBcKS4NCg0KIyMjIyAqKkFkdmFudGFnZXMqKjoNCg0KLSAqKkludGVycHJldGFibGUgY29lZmZpY2llbnRzKio6IFRoZSBjb2VmZmljaWVudHMgb2YgbG9naXN0aWMgcmVncmVzc2lvbiByZXByZXNlbnQgdGhlIGNoYW5nZSBpbiB0aGUgbG9nLW9kZHMgb2YgdGhlIG91dGNvbWUgZm9yIGEgb25lLXVuaXQgY2hhbmdlIGluIHRoZSBwcmVkaWN0b3IuDQoNCi0gKipQcm9iYWJpbGlzdGljIG91dHB1dCoqOiBMb2dpc3RpYyByZWdyZXNzaW9uIHByb3ZpZGVzIGEgcHJvYmFiaWxpdHkgb2YgdGhlIG91dGNvbWUsIHdoaWNoIGlzIHVzZWZ1bCBpbiBtYW55IHJlYWwtd29ybGQgYXBwbGljYXRpb25zLg0KDQotICoqTGVzcyBzdHJpY3QgYXNzdW1wdGlvbnMqKjogVW5saWtlIGxpbmVhciByZWdyZXNzaW9uLCBsb2dpc3RpYyByZWdyZXNzaW9uIGRvZXMgbm90IGFzc3VtZSBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgaW5kZXBlbmRlbnQgYW5kIGRlcGVuZGVudCB2YXJpYWJsZXMuDQoNCiMjIyMgKipEaXNhZHZhbnRhZ2VzKio6DQoNCi0gKipMaW5lYXJpdHkgaW4gbG9nLW9kZHMqKjogTG9naXN0aWMgcmVncmVzc2lvbiBhc3N1bWVzIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYW5kIHRoZSBsb2ctb2RkcyBvZiB0aGUgb3V0Y29tZS4NCg0KLSAqKk5vdCBzdWl0YWJsZSBmb3IgY29udGludW91cyBvdXRjb21lcyoqOiBMb2dpc3RpYyByZWdyZXNzaW9uIGNhbiBvbmx5IGhhbmRsZSBiaW5hcnkgb3IgY2F0ZWdvcmljYWwgb3V0Y29tZXMuDQoNCi0gKipNdWx0aWNvbGxpbmVhcml0eSoqOiBIaWdobHkgY29ycmVsYXRlZCBpbmRlcGVuZGVudCB2YXJpYWJsZXMgY2FuIGNhdXNlIGlzc3VlcyB3aXRoIGNvZWZmaWNpZW50IGVzdGltYXRpb24uDQoNCiMjIyMgKipBcHBsaWNhdGlvbnMqKjoNCg0KLSAqKk1lZGljYWwgcmVzZWFyY2gqKjogUHJlZGljdGluZyB0aGUgcHJvYmFiaWxpdHkgb2YgYSBkaXNlYXNlIChlLmcuLCBjYW5jZXIgZGlhZ25vc2lzIGJhc2VkIG9uIGFnZSBhbmQgbGlmZXN0eWxlIGZhY3RvcnMpLg0KDQotICoqTWFya2V0aW5nKio6IFByZWRpY3Rpbmcgd2hldGhlciBhIGN1c3RvbWVyIHdpbGwgcHVyY2hhc2UgYSBwcm9kdWN0IGJhc2VkIG9uIHRoZWlyIGRlbW9ncmFwaGljcyBhbmQgYnJvd3NpbmcgaGlzdG9yeS4NCg0KLSAqKkNyZWRpdCBzY29yaW5nKio6IEVzdGltYXRpbmcgdGhlIGxpa2VsaWhvb2Qgb2YgYSBib3Jyb3dlciBkZWZhdWx0aW5nIG9uIGEgbG9hbiBiYXNlZCBvbiBmaW5hbmNpYWwgaGlzdG9yeSBhbmQgb3RoZXIgZmFjdG9ycy4NCg0KIyMjIyAqKlByb3MqKjoNCi0gRWFzeSB0byBpbXBsZW1lbnQgYW5kIGludGVycHJldC4NCi0gV29ya3Mgd2VsbCB3aGVuIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYW5kIHRoZSBiaW5hcnkgb3V0Y29tZSBpcyBhcHByb3hpbWF0ZWx5IGxpbmVhciBpbiB0aGUgbG9nLW9kZHMuDQotIENhbiBoYW5kbGUgYm90aCBjb250aW51b3VzIGFuZCBjYXRlZ29yaWNhbCBwcmVkaWN0b3IgdmFyaWFibGVzLg0KDQojIyMjICoqQ29ucyoqOg0KLSBBc3N1bWVzIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYW5kIHRoZSBsb2ctb2RkcyBvZiB0aGUgb3V0Y29tZS4NCi0gU2Vuc2l0aXZlIHRvIG91dGxpZXJzIGFuZCBtdWx0aWNvbGxpbmVhcml0eS4NCi0gQ2FuIGJlY29tZSB1bnN0YWJsZSB3aXRoIHNtYWxsIGRhdGFzZXRzIG9yIGlmIHRoZSBjbGFzc2VzIGFyZSBoaWdobHkgaW1iYWxhbmNlZC4NCg0KLS0tDQoNCiMjIyAqKkxvZ2lzdGljIFJlZ3Jlc3Npb24gRXhhbXBsZSBpbiBSKioNCg0KSW4gdGhpcyBleGFtcGxlLCB3ZeKAmWxsIHVzZSBsb2dpc3RpYyByZWdyZXNzaW9uIHRvIG1vZGVsIHdoZXRoZXIgc3R1ZGVudHMgcGFzcyBvciBmYWlsIGFuIGV4YW0gYmFzZWQgb24gdGhlIG51bWJlciBvZiBob3VycyB0aGV5IHN0dWRpZWQuIFRoZSBvdXRjb21lIGlzIGJpbmFyeSAocGFzcyA9IDEsIGZhaWwgPSAwKS4NCg0KIyMjIyAqKlN0ZXAgMTogQ3JlYXRlIHRoZSBEYXRhKioNCg0KV2XigJlsbCBzaW11bGF0ZSBhIGRhdGFzZXQgd2l0aCB0aGUgbnVtYmVyIG9mIHN0dWR5IGhvdXJzIGFuZCB0aGUgcGFzcy9mYWlsIG91dGNvbWUgZm9yIGVhY2ggc3R1ZGVudC4NCg0KYGBge3J9DQojIENyZWF0ZSB0aGUgZGF0YTogc3R1ZHkgaG91cnMgYW5kIHBhc3MvZmFpbCBvdXRjb21lDQpzZXQuc2VlZCgxMjMpDQpzdHVkeV9ob3VycyA8LSBjKDIsIDQsIDYsIDgsIDEwLCAxMiwgMTQsIDE2LCAxOCwgMjApICAjIEluZGVwZW5kZW50IHZhcmlhYmxlDQpwYXNzX2ZhaWwgPC0gYygwLCAwLCAwLCAwLCAxLCAxLCAxLCAxLCAxLCAxKSAgIyBEZXBlbmRlbnQgdmFyaWFibGUgKDAgPSBmYWlsLCAxID0gcGFzcykNCg0KIyBDb21iaW5lIGludG8gYSBkYXRhIGZyYW1lDQpkYXRhIDwtIGRhdGEuZnJhbWUoc3R1ZHlfaG91cnMsIHBhc3NfZmFpbCkNCmhlYWQoZGF0YSkNCmBgYA0KDQoNClRoZSBkYXRhc2V0IGNvbnRhaW5zIDEwIG9ic2VydmF0aW9ucyB3aXRoIHN0dWR5IGhvdXJzIGFzIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSBhbmQgcGFzcy9mYWlsIGFzIHRoZSBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlICgwID0gZmFpbCwgMSA9IHBhc3MpLg0KDQojIyMjICoqU3RlcCAyOiBGaXQgdGhlIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwqKg0KDQpXZSBjYW4gdXNlIHRoZSAqKmBnbG0oKWAqKiBmdW5jdGlvbiBpbiBSIHRvIGZpdCB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4gVGhlICoqYGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKWAqKiBzcGVjaWZpZXMgdGhhdCB3ZSBhcmUgdXNpbmcgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHdpdGggdGhlIGxvZ2l0IGxpbmsgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KIyBGaXQgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwNCmxvZ2l0X21vZGVsIDwtIGdsbShwYXNzX2ZhaWwgfiBzdHVkeV9ob3VycywgZGF0YSA9IGRhdGEsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkNCg0KIyBEaXNwbGF5IHRoZSBzdW1tYXJ5IG9mIHRoZSBtb2RlbA0Kc3VtbWFyeShsb2dpdF9tb2RlbCkNCmBgYA0KDQoNCiMjIyMgKipPdXRwdXQqKiAoc2ltcGxpZmllZCk6DQpgYGANCkNhbGw6DQpnbG0oZm9ybXVsYSA9IHBhc3NfZmFpbCB+IHN0dWR5X2hvdXJzLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIA0KICAgIGRhdGEgPSBkYXRhKQ0KDQpDb2VmZmljaWVudHM6DQogICAgICAgICAgICAgRXN0aW1hdGUgU3RkLiBFcnJvciB6IHZhbHVlIFByKD58enwpICAgIA0KKEludGVyY2VwdCkgIC02LjE4NTYgICAgIDIuODQzNiAgLTIuMTc1ICAgMC4wMjk2ICogIA0Kc3R1ZHlfaG91cnMgICAwLjY0MTQgICAgIDAuMjkyMCAgIDIuMTk2ICAgMC4wMjgxICogIA0KYGBgDQoNCiMjIyMgKipJbnRlcnByZXRhdGlvbioqOg0KDQotICoqSW50ZXJjZXB0IChFc3RpbWF0ZSA9IC02LjE5KSoqOiBUaGUgbG9nLW9kZHMgb2YgcGFzc2luZyB3aGVuIHN0dWR5IGhvdXJzIGFyZSAwIGlzIC02LjE5Lg0KDQotICoqU3R1ZHkgaG91cnMgKEVzdGltYXRlID0gMC42NCkqKjogRm9yIGVhY2ggYWRkaXRpb25hbCBob3VyIG9mIHN0dWR5LCB0aGUgbG9nLW9kZHMgb2YgcGFzc2luZyBpbmNyZWFzZSBieSAwLjY0Lg0KDQpCb3RoIHRoZSBpbnRlcmNlcHQgYW5kIHRoZSBjb2VmZmljaWVudCBmb3Igc3R1ZHkgaG91cnMgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHAgPCAwLjA1KS4NCg0KVGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZXF1YXRpb24gaW4gdGVybXMgb2YgdGhlIGxvZy1vZGRzIGlzOg0KXFsNClxsb2dcbGVmdChcZnJhY3tQKFx0ZXh0e3Bhc3N9ID0gMSl9ezEgLSBQKFx0ZXh0e3Bhc3N9ID0gMSl9XHJpZ2h0KSA9IC02LjE5ICsgMC42NCBcdGltZXMgXHRleHR7U3R1ZHkgSG91cnN9DQpcXQ0KDQojIyMjICoqU3RlcCAzOiBQcmVkaWN0aW5nIFByb2JhYmlsaXRpZXMqKg0KDQpXZSBjYW4gdXNlIHRoZSBtb2RlbCB0byBwcmVkaWN0IHRoZSBwcm9iYWJpbGl0eSBvZiBwYXNzaW5nIGZvciBhIG5ldyBzZXQgb2Ygc3R1ZHkgaG91cnMuDQoNCmBgYHtyfQ0KIyBQcmVkaWN0IHRoZSBwcm9iYWJpbGl0eSBvZiBwYXNzaW5nIGZvciBuZXcgc3R1ZHkgaG91cnMNCm5ld19zdHVkeV9ob3VycyA8LSBkYXRhLmZyYW1lKHN0dWR5X2hvdXJzID0gYyg1LCAxMCwgMTUpKQ0KcHJlZGljdGVkX3Byb2IgPC0gcHJlZGljdChsb2dpdF9tb2RlbCwgbmV3ZGF0YSA9IG5ld19zdHVkeV9ob3VycywgdHlwZSA9ICJyZXNwb25zZSIpDQoNCiMgU2hvdyB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMNCnByZWRpY3RlZF9wcm9iDQpgYGANCg0KDQojIyMjICoqT3V0cHV0Kio6DQpgYGANCiAgICAgICAgMSAgICAgICAgIDIgICAgICAgICAzIA0KMC4xMzM4NTgyIDAuNjY0OTc4NiAwLjk0ODczNjggDQpgYGANCg0KIyMjIyAqKkludGVycHJldGF0aW9uKio6DQotIEZvciBhIHN0dWRlbnQgd2hvIHN0dWRpZXMgNSBob3VycywgdGhlIHByb2JhYmlsaXR5IG9mIHBhc3NpbmcgaXMgYXBwcm94aW1hdGVseSAwLjEzICgxMyUpLg0KLSBGb3IgYSBzdHVkZW50IHdobyBzdHVkaWVzIDEwIGhvdXJzLCB0aGUgcHJvYmFiaWxpdHkgb2YgcGFzc2luZyBpcyBhcHByb3hpbWF0ZWx5IDAuNjYgKDY2JSkuDQotIEZvciBhIHN0dWRlbnQgd2hvIHN0dWRpZXMgMTUgaG91cnMsIHRoZSBwcm9iYWJpbGl0eSBvZiBwYXNzaW5nIGlzIGFwcHJveGltYXRlbHkgMC45NSAoOTUlKS4NCg0KIyMjIyAqKlN0ZXAgNDogVmlzdWFsaXplIHRoZSBMb2dpc3RpYyBDdXJ2ZSoqDQoNCkl04oCZcyBoZWxwZnVsIHRvIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN0dWR5IGhvdXJzIGFuZCB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXR5IG9mIHBhc3NpbmcuDQoNCmBgYHtyfQ0KIyBQbG90IHRoZSBkYXRhDQpwbG90KGRhdGEkc3R1ZHlfaG91cnMsIGRhdGEkcGFzc19mYWlsLCANCiAgICAgbWFpbiA9ICJMb2dpc3RpYyBSZWdyZXNzaW9uOiBTdHVkeSBIb3VycyB2cyBQYXNzL0ZhaWwiLA0KICAgICB4bGFiID0gIlN0dWR5IEhvdXJzIiwgeWxhYiA9ICJQYXNzL0ZhaWwiLCANCiAgICAgcGNoID0gMTksIGNvbCA9ICJibHVlIikNCg0KIyBBZGQgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gY3VydmUNCmN1cnZlKHByZWRpY3QobG9naXRfbW9kZWwsIG5ld2RhdGEgPSBkYXRhLmZyYW1lKHN0dWR5X2hvdXJzID0geCksIHR5cGUgPSAicmVzcG9uc2UiKSwgDQogICAgICBhZGQgPSBUUlVFLCBjb2wgPSAicmVkIikNCmBgYA0KDQoNCiMjIyMgKipJbnRlcnByZXRhdGlvbioqOg0KVGhlIHNjYXR0ZXJwbG90IHNob3dzIHRoZSBpbmRpdmlkdWFsIGRhdGEgcG9pbnRzLCB3aXRoIDAgaW5kaWNhdGluZyBmYWlsdXJlIGFuZCAxIGluZGljYXRpbmcgcGFzc2luZy4gVGhlIHJlZCBsb2dpc3RpYyBjdXJ2ZSBzaG93cyB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXR5IG9mIHBhc3NpbmcgYXMgYSBmdW5jdGlvbiBvZiBzdHVkeSBob3Vycy4gVGhlIGN1cnZlIHN0YXJ0cyBsb3cgKGNsb3NlIHRvIDApIGFuZCBpbmNyZWFzZXMgYXMgc3R1ZHkgaG91cnMgaW5jcmVhc2UsIGV2ZW50dWFsbHkgbGV2ZWxpbmcgb2ZmIG5lYXIgMS4NCg0KLS0tDQoNCiMjIyAqKkxvZ2lzdGljIFJlZ3Jlc3Npb24gQXNzdW1wdGlvbnMqKjoNCg0KMS4gKipCaW5hcnkgb3V0Y29tZSoqOiBUaGUgZGVwZW5kZW50IHZhcmlhYmxlIG11c3QgYmUgYmluYXJ5Lg0KDQoyLiAqKkxpbmVhcml0eSBpbiBsb2ctb2RkcyoqOiBUaGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIHNob3VsZCBiZSBsaW5lYXJseSByZWxhdGVkIHRvIHRoZSBsb2ctb2RkcyBvZiB0aGUgb3V0Y29tZS4NCg0KMy4gKipJbmRlcGVuZGVuY2UqKjogVGhlIG9ic2VydmF0aW9ucyBtdXN0IGJlIGluZGVwZW5kZW50IG9mIGVhY2ggb3RoZXIuDQoNCjQuICoqTm8gbXVsdGljb2xsaW5lYXJpdHkqKjogVGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcyBzaG91bGQgbm90IGJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlci4NCg0KLS0tDQoNCiMjIyAqKk11bHRpcGxlIExvZ2lzdGljIFJlZ3Jlc3Npb24gRXhhbXBsZSBpbiBSKioNCg0KTGV04oCZcyBleHRlbmQgdGhpcyB0byAqKm11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24qKiwgd2hlcmUgd2UgcHJlZGljdCB0aGUgcGFzcy9mYWlsIG91dGNvbWUgYmFzZWQgb24gYm90aCAqKnN0dWR5IGhvdXJzKiogYW5kICoqc2xlZXAgaG91cnMqKi4NCg0KIyMjIyAqKlN0ZXAgMTogQ3JlYXRlIHRoZSBEYXRhKioNCg0KV2XigJlsbCBnZW5lcmF0ZSBhIG5ldyB2YXJpYWJsZSwgKipzbGVlcCBob3VycyoqLCByZXByZXNlbnRpbmcgdGhlIG51bWJlciBvZiBob3VycyB0aGUgc3R1ZGVudCBzbGVwdCBiZWZvcmUgdGhlIGV4YW0uDQoNCmBgYHtyfQ0KIyBBZGQgc2xlZXAgaG91cnMgZGF0YQ0Kc2xlZXBfaG91cnMgPC0gYyg2LCA3LCA4LCA3LCA4LCA5LCA3LCA5LCA4LCAxMCkNCg0KIyBDb21iaW5lIGludG8gYSBkYXRhIGZyYW1lDQpkYXRhX211bHQgPC0gZGF0YS5mcmFtZShzdHVkeV9ob3Vycywgc2xlZXBfaG91cnMsIHBhc3NfZmFpbCkNCmhlYWQoZGF0YV9tdWx0KQ0KYGBgDQoNCg0KIyMjIyAqKlN0ZXAgMjogRml0IHRoZSBNdWx0aXBsZSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsKioNCg0KV2XigJlsbCBmaXQgYSBtdWx0aXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIGJvdGggc3R1ZHkgaG91cnMgYW5kIHNsZWVwIGhvdXJzIGFzIHByZWRpY3RvcnMuDQoNCmBgYHtyfQ0KIyBGaXQgdGhlIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwNCmxvZ2l0X21vZGVsX211bHQgPC0gZ2xtKHBhc3NfZmFpbCB+IHN0dWR5X2hvdXJzICsgc2xlZXBfaG91cnMsIGRhdGEgPSBkYXRhX211bHQsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkNCg0KIyBEaXNwbGF5IHRoZSBzdW1tYXJ5IG9mIHRoZSBtb2RlbA0Kc3VtbWFyeShsb2dpdF9tb2RlbF9tdWx0KQ0KYGBgDQoNCg0KIyMjIyAqKk91dHB1dCoqIChzaW1wbGlmaWVkKToNCmBgYA0KQ2FsbDoNCmdsbShmb3JtdWxhID0gcGFzc19mYWlsIH4gc3R1ZHlfaG91cnMgKyBzbGVlcF9ob3VycywgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCANCiAgICBkYXRhID0gZGF0YV9tdWx0KQ0KDQpDb2VmZmljaWVudHM6DQogICAgICAgICAgICAgRXN0aW1hdGUgU3RkLiBFcnJvciB6IHZhbHVlIFByKD58enwpICAgIA0KKEludGVyY2VwdA==