For weeks, we’ve built analytical capacity using two core models:
Linear Regression (Normal Distribution) and
Logistic Regression (Binomial Distribution). Today, we
look under the hood of the glm() function in R
to see how these models are just two members of a much larger,
incredibly flexible family: Generalized Linear Models
(GLMs).
Your knowledge of Linear and Logistic Regression is the foundation.
If you can identify the type of data you have, you can select the
correct GLM family, and the rest of the process (fitting, interpreting,
diagnosing) follows familiar rules.
The GLM Framework: The Three Pillars
Every GLM is defined by three fundamental components. In
glm(), you only need to specify the Random
Component (via family).
| 1. Random |
The probability distribution of the response variable (\(Y\)). |
Normal (family = gaussian) |
Binomial (family = binomial) |
Poisson, Gamma, etc. |
| 2. Systematic |
The linear predictor: \(X\beta\)
(the familiar part). |
\(\beta_0 + \beta_1 X_1 +
\dots\) |
\(\beta_0 + \beta_1 X_1 +
\dots\) |
Same! |
| 3. Link |
The function that links the mean of \(Y\) to the linear predictor. |
Identity (\(\mu =
\eta\)) |
Logit (\(\log(\frac{\mu}{1-\mu})
= \eta\)) |
Log, Inverse, etc. |
For any new GLM, we only need to learn:
- Which
family to use (based on the data type).
- What the
link function does to the mean \(\mu\).
Modeling Counts with Poisson Regression
Call Center Incident Reports: A company wants to
model the number of customer support incidents reported per week for
different product lines. Since the response variable is a count (0, 1,
2, 3, …), the Normal (Gaussian) distribution is inappropriate, and the
Binomial (Logistic) distribution is for proportions. Count data is
exactly applicable to the Poisson GLM Family.
The Poisson Link Function
The Poisson distribution requires the mean (\(\mu\)) to be positive. The standard link
function is the Log Link:
\[\log(\mu) = \beta_0 + \beta_1 X_1 +
\dots\]
This is identical to the Logit link in Logistic Regression! This
means the coefficients will be interpreted similarly:
multiplicatively.
R Code & Interpretation
We’ll simulate some data for demonstration.
library(tidyverse)
# 1. Simulate data (Incident Reports)
set.seed(42)
data_poisson <- tibble(
Product_Age_Years = runif(100, 1, 10),
Support_Level = factor(sample(c("Basic", "Premium"), 100, replace = TRUE, prob = c(0.7, 0.3))),
# Generate counts (rate depends on age and support)
lambda = exp(1.5 - 0.2 * Product_Age_Years + 0.5 * (Support_Level == "Premium")),
Incidents_Weekly = rpois(100, lambda)
)
# 2. Fit the Poisson GLM
poisson_model <- glm(
Incidents_Weekly ~ Product_Age_Years + Support_Level,
family = poisson(link = "log"), # The only change from lm() or glm(..., family=binomial)
data = data_poisson
)
summary(poisson_model)
Call:
glm(formula = Incidents_Weekly ~ Product_Age_Years + Support_Level,
family = poisson(link = "log"), data = data_poisson)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.38469 0.16897 8.195 2.51e-16 ***
Product_Age_Years -0.19174 0.02863 -6.698 2.11e-11 ***
Support_LevelPremium 0.38595 0.15029 2.568 0.0102 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for poisson family taken to be 1)
Null deviance: 183.54 on 99 degrees of freedom
Residual deviance: 124.62 on 97 degrees of freedom
AIC: 326.7
Number of Fisher Scoring iterations: 5
Interpretation of Coefficients:
Just like in Logistic Regression, we must exponentiate the
coefficients to return them to the original scale of the response
variable (counts). Exponentiated coefficients are interpreted as Rate
Ratios.
# Exponentiate the coefficients
exp(coef(poisson_model))
(Intercept) Product_Age_Years Support_LevelPremium
3.993592 0.825518 1.471006
Product_Age_Years |
-0.19 |
0.82 |
A 1-year increase in product age is associated with an 18%
decrease (\(\approx 1 -
0.82\)) in the expected weekly incident rate. |
Support_LevelPremium |
0.39 |
1.47 |
Premium support products have a 47% higher expected
weekly incident rate compared to Basic support products, holding age
constant. |
Assumption Check: Overdispersion
The core assumption of Poisson is that the mean equals the variance
(\(\text{Var}(Y) = \mu\)). If the
variance is much larger than the mean, we have overdispersion, which
leads to deflated standard errors (and inflated significance).
- Diagnostic: Check the Residual Deviance against the
Degrees of Freedom (DoF) from the
summary().
# Check for Overdispersion: Ratio of Residual Deviance / Residual DoF
deviance_ratio <- summary(poisson_model)$deviance / summary(poisson_model)$df.residual
print(paste("Deviance Ratio:", round(deviance_ratio, 2)))
[1] "Deviance Ratio: 1.28"
# Rule of Thumb: If ratio > 1.5, consider switching to a Quasi-Poisson or Negative Binomial model.
Graphical Summary
A key visualization is comparing the predicted rates to the observed
counts.
# Add predictions (expected counts) back to the data
data_poisson <- data_poisson %>%
mutate(Expected_Incidents = predict(poisson_model, type = "response"))
# Plot Expected vs. Observed Counts
ggplot(data_poisson, aes(x = Expected_Incidents, y = Incidents_Weekly, color = Support_Level)) +
geom_point(alpha = 0.6) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "grey") +
labs(
title = "Poisson Model Fit: Expected vs. Observed Incident Counts",
x = "Expected Weekly Incidents (Model Prediction)",
y = "Observed Weekly Incidents",
color = "Support Level"
) +
theme_minimal()

Points on the graph above the line indicate where our model
underestimates the count, points below the line indicate where our model
overestimates the count, and points exactly on the line are perfect
predictions.
Modeling Skewed Continuous Data with Gamma Regression
Insurance Claim Amounts: An insurance company wants
to model the size of financial claims paid out to customers. Claim
amounts are continuous and positive (cannot be
negative). They are highly right-skewed (most claims are small,
but a few are very large). Positive, continuous, skewed data types can
be modeled with the Gamma GLM Family.
The Gamma Link Function
The Gamma distribution commonly uses the Log Link
(or sometimes the Inverse link). We’ll stick with Log
as it allows for the multiplicative interpretation we just learned.
\[\log(\mu) = \beta_0 + \beta_1 X_1 +
\dots\]
R Code & Interpretation
# 3. Simulate Gamma data (Claim Amounts)
set.seed(101)
data_gamma <- tibble(
Customer_Score = runif(100, 500, 800), # e.g., credit/risk score
Claim_Type = factor(sample(c("Minor", "Major"), 100, replace = TRUE, prob = c(0.7, 0.3))),
# Generate claim amounts (mean depends on score and claim type)
mu = exp(7 - 0.005 * Customer_Score + 0.5 * (Claim_Type == "Major")),
Claim_Amount = rgamma(100, shape = 2, rate = 2/mu) # Gamma parameterization
)
# 4. Fit the Gamma GLM
gamma_model <- glm(
Claim_Amount ~ Customer_Score + Claim_Type,
family = Gamma(link = "log"), # Family changes, link stays 'log'
data = data_gamma
)
summary(gamma_model)
Call:
glm(formula = Claim_Amount ~ Customer_Score + Claim_Type, family = Gamma(link = "log"),
data = data_gamma)
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 7.3717659 0.6912186 10.665 < 2e-16 ***
Customer_Score -0.0048348 0.0009964 -4.852 4.66e-06 ***
Claim_TypeMinor -0.5678030 0.1919092 -2.959 0.00388 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for Gamma family taken to be 0.7735794)
Null deviance: 84.850 on 99 degrees of freedom
Residual deviance: 63.418 on 97 degrees of freedom
AIC: 953.49
Number of Fisher Scoring iterations: 5
Interpretation of Coefficients (Rate Ratios Again!):
Since we used the Log Link again, the interpretation template is the
same as Poisson and Logistic Regression—exponentiate the coefficient for
a multiplicative effect.
# Exponentiate the coefficients
exp(coef(gamma_model))
(Intercept) Customer_Score Claim_TypeMinor
1590.4398662 0.9951769 0.5667693
Since the Gamma model used the Log Link
(family = Gamma(link = "log")), we interpret the
exponentiated coefficients (\(\exp(\beta)\)) as a multiplicative
ratio relative to the expected mean (claim amount).
(Intercept) |
7.3717659 |
1590.44 |
This is the expected claim amount (in currency units, e.g., dollars)
when all predictors are zero (i.e., Customer Score = 0 and Claim Type =
Major). This value is usually theoretical since a score of
0 is unrealistic. |
Customer_Score |
-0.0048348 |
0.9951769 |
For every one-unit increase in the Customer Score,
the expected claim amount is multiplied by 0.995, or decreases by
approximately 0.48% (\(1 -
0.9951769 = 0.00482\)). This suggests higher customer scores are
associated with slightly lower claim amounts. |
Claim_TypeMinor |
-0.5678030 |
0.5667693 |
The baseline (omitted) category is Claim_TypeMajor.
Therefore, the expected claim amount for a Minor claim is
0.567 times the expected claim amount for a
Major claim, holding Customer Score constant. In other
words, Minor claims are expected to be about 43.3%
lower (\(1 - 0.5667693\)) than
Major claims. |
Assumption Check: Homoscedasticity vs. Variance Function
Unlike Linear Regression where variance is constant
(homoscedasticity), GLMs allow variance to be a function of the mean
(\(\text{Var}(Y) = V(\mu)\)).
- For Normal, \(V(\mu) = \sigma^2\)
(Constant variance).
- For Poisson, \(V(\mu) = \mu\)
(Variance increases with the mean).
- For Gamma, \(V(\mu) = \phi \mu^2\)
(Variance increases with the square of the mean).
Diagnostic: Plotting the standardized residuals
against the fitted values (mean).
plot(
fitted(gamma_model),
resid(gamma_model, type = "deviance"),
xlab = "Fitted Values (Expected Claim Amount)",
ylab = "Deviance Residuals",
main = "Gamma Model Residuals vs. Fitted Values"
)
abline(h = 0, col = "grey", lty = 2)
We look for random scatter around zero. We are not looking for
constant variance (as in Linear Regression), but rather ensuring there
is no obvious pattern (like a cone shape, which would indicate a poor
fit for the chosen variance function, \(V(\mu)
= \phi \mu^2\)).
Conclusion
The Transferable Analytical Capacity
You now know three different GLMs, and yet, the core skills you use
are identical:
| Model Specification |
Y ~ X1 + X2 (The systematic component is the same) |
| P-Value Interpretation |
A high Wald \(\chi^2\) statistic
(t-statistic for Linear) results in a low p-value, indicating the
predictor is relevant to the link function of the mean. |
| Coefficient Interpretation |
Identity Link (Linear): Additive effect. \(\beta_1\) is the change in \(Y\) per unit \(X_1\). |
|
Log Link (Logistic, Poisson, Gamma): Multiplicative effect. \(\exp(\beta_1)\) is the ratio of
means/rates/odds per unit \(X_1\). |
Whether you are dealing with Log Odds (Logistic), Log Rates
(Poisson), or Log Means (Gamma), the process of exponentiating the
coefficient to get a multiplicative ratio is the same. You just need to
adjust your language (odds, rate, or mean) to match the data type!
LS0tDQp0aXRsZTogIkdlbmVyYWxpemVkIExpbmVhciBNb2RlbHMgKEdMTXMpIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogY2VydWxlYW4NCi0tLQ0KDQpGb3Igd2Vla3MsIHdl4oCZdmUgYnVpbHQgYW5hbHl0aWNhbCBjYXBhY2l0eSB1c2luZyB0d28gY29yZSBtb2RlbHM6ICoqTGluZWFyIFJlZ3Jlc3Npb24gKE5vcm1hbCBEaXN0cmlidXRpb24pKiogYW5kICoqTG9naXN0aWMgUmVncmVzc2lvbiAoQmlub21pYWwgRGlzdHJpYnV0aW9uKSoqLiBUb2RheSwgd2UgbG9vayB1bmRlciB0aGUgaG9vZCBvZiB0aGUgYGdsbSgpYCBmdW5jdGlvbiBpbiBgUmAgdG8gc2VlIGhvdyB0aGVzZSBtb2RlbHMgYXJlIGp1c3QgdHdvIG1lbWJlcnMgb2YgYSBtdWNoIGxhcmdlciwgaW5jcmVkaWJseSBmbGV4aWJsZSBmYW1pbHk6ICoqR2VuZXJhbGl6ZWQgTGluZWFyIE1vZGVscyAoR0xNcykqKi4NCg0KWW91ciBrbm93bGVkZ2Ugb2YgTGluZWFyIGFuZCBMb2dpc3RpYyBSZWdyZXNzaW9uIGlzIHRoZSBmb3VuZGF0aW9uLiBJZiB5b3UgY2FuIGlkZW50aWZ5IHRoZSB0eXBlIG9mIGRhdGEgeW91IGhhdmUsIHlvdSBjYW4gc2VsZWN0IHRoZSBjb3JyZWN0IEdMTSBmYW1pbHksIGFuZCB0aGUgcmVzdCBvZiB0aGUgcHJvY2VzcyAoZml0dGluZywgaW50ZXJwcmV0aW5nLCBkaWFnbm9zaW5nKSBmb2xsb3dzIGZhbWlsaWFyIHJ1bGVzLg0KDQoNCiMjIFRoZSBHTE0gRnJhbWV3b3JrOiBUaGUgVGhyZWUgUGlsbGFycyANCg0KRXZlcnkgR0xNIGlzIGRlZmluZWQgYnkgdGhyZWUgZnVuZGFtZW50YWwgY29tcG9uZW50cy4gSW4gYGdsbSgpYCwgeW91IG9ubHkgbmVlZCB0byBzcGVjaWZ5IHRoZSAqKlJhbmRvbSBDb21wb25lbnQqKiAodmlhIGBmYW1pbHlgKS4NCg0KfCBDb21wb25lbnQgICAgIHwgRGVzY3JpcHRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IExpbmVhciBSZWdyZXNzaW9uIChOb3JtYWwpICAgICAgfCBMb2dpc3RpYyBSZWdyZXNzaW9uIChCaW5vbWlhbCkgICAgICAgICAgIHwgTmV3IEdMTXMgICAgICAgICAgICAgfA0KfC0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCAxLiAqKlJhbmRvbSoqICAgICB8IFRoZSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gb2YgdGhlIHJlc3BvbnNlIHZhcmlhYmxlICgkWSQpLiAgICAgfCAqTm9ybWFsKiAoYGZhbWlseSA9IGdhdXNzaWFuYCkgICAgICB8ICpCaW5vbWlhbCogKGBmYW1pbHkgPSBiaW5vbWlhbGApICAgICAgICAgICAgIHwgKlBvaXNzb24qLCAqR2FtbWEqLCBldGMuIHwNCnwgMi4gKipTeXN0ZW1hdGljKiogfCBUaGUgbGluZWFyIHByZWRpY3RvcjogJFhcYmV0YSQgKHRoZSBmYW1pbGlhciBwYXJ0KS4gICAgICAgICAgICAgIHwgJFxiZXRhXzAgKyBcYmV0YV8xIFhfMSArIFxkb3RzJCB8ICRcYmV0YV8wICsgXGJldGFfMSBYXzEgKyBcZG90cyQgICAgICAgICAgfCAqKlNhbWUhKiogICAgICAgICAgICAgICAgfA0KfCAzLiAqKkxpbmsqKiAgICAgICB8IFRoZSBmdW5jdGlvbiB0aGF0IGxpbmtzIHRoZSBtZWFuIG9mICRZJCB0byB0aGUgbGluZWFyIHByZWRpY3Rvci4gfCAqSWRlbnRpdHkqICgkXG11ID0gXGV0YSQpICAgICAgICAgfCAqTG9naXQqICgkXGxvZyhcZnJhY3tcbXV9ezEtXG11fSkgPSBcZXRhJCkgfCAqTG9nKiwgKkludmVyc2UqLCBldGMuICAgfA0KDQoNCkZvciBhbnkgbmV3IEdMTSwgd2Ugb25seSBuZWVkIHRvIGxlYXJuOg0KDQogLSBXaGljaCBgZmFtaWx5YCB0byB1c2UgKGJhc2VkIG9uIHRoZSBkYXRhIHR5cGUpLiAgDQogLSBXaGF0IHRoZSBgbGlua2AgZnVuY3Rpb24gZG9lcyB0byB0aGUgbWVhbiAkXG11JC4NCiANCiMjIE1vZGVsaW5nIENvdW50cyB3aXRoIFBvaXNzb24gUmVncmVzc2lvbiANCg0KKipDYWxsIENlbnRlciBJbmNpZGVudCBSZXBvcnRzOioqIEEgY29tcGFueSB3YW50cyB0byBtb2RlbCB0aGUgbnVtYmVyIG9mIGN1c3RvbWVyIHN1cHBvcnQgaW5jaWRlbnRzIHJlcG9ydGVkIHBlciB3ZWVrIGZvciBkaWZmZXJlbnQgcHJvZHVjdCBsaW5lcy4gU2luY2UgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGlzIGEgY291bnQgKDAsIDEsIDIsIDMsIC4uLiksIHRoZSBOb3JtYWwgKEdhdXNzaWFuKSBkaXN0cmlidXRpb24gaXMgaW5hcHByb3ByaWF0ZSwgYW5kIHRoZSBCaW5vbWlhbCAoTG9naXN0aWMpIGRpc3RyaWJ1dGlvbiBpcyBmb3IgcHJvcG9ydGlvbnMuIENvdW50IGRhdGEgaXMgZXhhY3RseSBhcHBsaWNhYmxlIHRvIHRoZSBQb2lzc29uIEdMTSBGYW1pbHkuDQoNCiMjIyBUaGUgUG9pc3NvbiBMaW5rIEZ1bmN0aW9uDQoNClRoZSBQb2lzc29uIGRpc3RyaWJ1dGlvbiByZXF1aXJlcyB0aGUgbWVhbiAoJFxtdSQpIHRvIGJlIHBvc2l0aXZlLiBUaGUgc3RhbmRhcmQgbGluayBmdW5jdGlvbiBpcyB0aGUgTG9nIExpbms6DQoNCiQkXGxvZyhcbXUpID0gXGJldGFfMCArIFxiZXRhXzEgWF8xICsgXGRvdHMkJA0KDQpUaGlzIGlzIGlkZW50aWNhbCB0byB0aGUgTG9naXQgbGluayBpbiBMb2dpc3RpYyBSZWdyZXNzaW9uISBUaGlzIG1lYW5zIHRoZSBjb2VmZmljaWVudHMgd2lsbCBiZSBpbnRlcnByZXRlZCBzaW1pbGFybHk6IG11bHRpcGxpY2F0aXZlbHkuDQoNCiMjIyBSIENvZGUgJiBJbnRlcnByZXRhdGlvbg0KDQpXZSdsbCBzaW11bGF0ZSBzb21lIGRhdGEgZm9yIGRlbW9uc3RyYXRpb24uDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgMS4gU2ltdWxhdGUgZGF0YSAoSW5jaWRlbnQgUmVwb3J0cykNCnNldC5zZWVkKDQyKQ0KZGF0YV9wb2lzc29uIDwtIHRpYmJsZSgNCiAgUHJvZHVjdF9BZ2VfWWVhcnMgPSBydW5pZigxMDAsIDEsIDEwKSwNCiAgU3VwcG9ydF9MZXZlbCA9IGZhY3RvcihzYW1wbGUoYygiQmFzaWMiLCAiUHJlbWl1bSIpLCAxMDAsIHJlcGxhY2UgPSBUUlVFLCBwcm9iID0gYygwLjcsIDAuMykpKSwNCiAgIyBHZW5lcmF0ZSBjb3VudHMgKHJhdGUgZGVwZW5kcyBvbiBhZ2UgYW5kIHN1cHBvcnQpDQogIGxhbWJkYSA9IGV4cCgxLjUgLSAwLjIgKiBQcm9kdWN0X0FnZV9ZZWFycyArIDAuNSAqIChTdXBwb3J0X0xldmVsID09ICJQcmVtaXVtIikpLA0KICBJbmNpZGVudHNfV2Vla2x5ID0gcnBvaXMoMTAwLCBsYW1iZGEpDQopDQoNCiMgMi4gRml0IHRoZSBQb2lzc29uIEdMTQ0KcG9pc3Nvbl9tb2RlbCA8LSBnbG0oDQogIEluY2lkZW50c19XZWVrbHkgfiBQcm9kdWN0X0FnZV9ZZWFycyArIFN1cHBvcnRfTGV2ZWwsDQogIGZhbWlseSA9IHBvaXNzb24obGluayA9ICJsb2ciKSwgIyBUaGUgb25seSBjaGFuZ2UgZnJvbSBsbSgpIG9yIGdsbSguLi4sIGZhbWlseT1iaW5vbWlhbCkNCiAgZGF0YSA9IGRhdGFfcG9pc3Nvbg0KKQ0KDQpzdW1tYXJ5KHBvaXNzb25fbW9kZWwpDQpgYGANCg0KIyMjIEludGVycHJldGF0aW9uIG9mIENvZWZmaWNpZW50czoNCg0KSnVzdCBsaWtlIGluIExvZ2lzdGljIFJlZ3Jlc3Npb24sIHdlIG11c3QgZXhwb25lbnRpYXRlIHRoZSBjb2VmZmljaWVudHMgdG8gcmV0dXJuIHRoZW0gdG8gdGhlIG9yaWdpbmFsIHNjYWxlIG9mIHRoZSByZXNwb25zZSB2YXJpYWJsZSAoY291bnRzKS4gRXhwb25lbnRpYXRlZCBjb2VmZmljaWVudHMgYXJlIGludGVycHJldGVkIGFzIFJhdGUgUmF0aW9zLg0KDQpgYGB7cn0NCiMgRXhwb25lbnRpYXRlIHRoZSBjb2VmZmljaWVudHMNCmV4cChjb2VmKHBvaXNzb25fbW9kZWwpKQ0KYGBgDQoNCnwgQ29lZmZpY2llbnQgICAgICAgICAgfCBFc3RpbWF0ZSB8IEV4cChFc3RpbWF0ZSkgfCBJbnRlcnByZXRhdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgYFByb2R1Y3RfQWdlX1llYXJzYCAgICB8IC0wLjE5ICAgIHwgX18wLjgyX18gICAgICAgICAgfCBBIDEteWVhciBpbmNyZWFzZSBpbiBwcm9kdWN0IGFnZSBpcyBhc3NvY2lhdGVkIHdpdGggYW4gX18xOCUgZGVjcmVhc2VfXyAoJFxhcHByb3ggMSAtIDAuODIkKSBpbiB0aGUgZXhwZWN0ZWQgd2Vla2x5IGluY2lkZW50IHJhdGUuICAgICB8DQp8IGBTdXBwb3J0X0xldmVsUHJlbWl1bWAgfCAwLjM5ICAgICB8IF9fMS40N19fICAgICAgICAgIHwgUHJlbWl1bSBzdXBwb3J0IHByb2R1Y3RzIGhhdmUgYSBfXzQ3JSBoaWdoZXJfXyBleHBlY3RlZCB3ZWVrbHkgaW5jaWRlbnQgcmF0ZSBjb21wYXJlZCB0byBCYXNpYyBzdXBwb3J0IHByb2R1Y3RzLCBob2xkaW5nIGFnZSBjb25zdGFudC4gfA0KDQoNCiMjIyBBc3N1bXB0aW9uIENoZWNrOiBPdmVyZGlzcGVyc2lvbg0KDQpUaGUgY29yZSBhc3N1bXB0aW9uIG9mIFBvaXNzb24gaXMgdGhhdCB0aGUgbWVhbiBlcXVhbHMgdGhlIHZhcmlhbmNlICgkXHRleHR7VmFyfShZKSA9IFxtdSQpLiBJZiB0aGUgdmFyaWFuY2UgaXMgbXVjaCBsYXJnZXIgdGhhbiB0aGUgbWVhbiwgd2UgaGF2ZSBvdmVyZGlzcGVyc2lvbiwgd2hpY2ggbGVhZHMgdG8gZGVmbGF0ZWQgc3RhbmRhcmQgZXJyb3JzIChhbmQgaW5mbGF0ZWQgc2lnbmlmaWNhbmNlKS4gDQoNCiAtIF9fRGlhZ25vc3RpYzpfXyBDaGVjayB0aGUgUmVzaWR1YWwgRGV2aWFuY2UgYWdhaW5zdCB0aGUgRGVncmVlcyBvZiBGcmVlZG9tIChEb0YpIGZyb20gdGhlIGBzdW1tYXJ5KClgLg0KIA0KYGBge3J9DQojIENoZWNrIGZvciBPdmVyZGlzcGVyc2lvbjogUmF0aW8gb2YgUmVzaWR1YWwgRGV2aWFuY2UgLyBSZXNpZHVhbCBEb0YNCmRldmlhbmNlX3JhdGlvIDwtIHN1bW1hcnkocG9pc3Nvbl9tb2RlbCkkZGV2aWFuY2UgLyBzdW1tYXJ5KHBvaXNzb25fbW9kZWwpJGRmLnJlc2lkdWFsDQpwcmludChwYXN0ZSgiRGV2aWFuY2UgUmF0aW86Iiwgcm91bmQoZGV2aWFuY2VfcmF0aW8sIDIpKSkNCg0KIyBSdWxlIG9mIFRodW1iOiBJZiByYXRpbyA+IDEuNSwgY29uc2lkZXIgc3dpdGNoaW5nIHRvIGEgUXVhc2ktUG9pc3NvbiBvciBOZWdhdGl2ZSBCaW5vbWlhbCBtb2RlbC4NCmBgYA0KDQojIyMgR3JhcGhpY2FsIFN1bW1hcnkNCg0KQSBrZXkgdmlzdWFsaXphdGlvbiBpcyBjb21wYXJpbmcgdGhlIHByZWRpY3RlZCByYXRlcyB0byB0aGUgb2JzZXJ2ZWQgY291bnRzLg0KDQpgYGB7cn0NCiMgQWRkIHByZWRpY3Rpb25zIChleHBlY3RlZCBjb3VudHMpIGJhY2sgdG8gdGhlIGRhdGENCmRhdGFfcG9pc3NvbiA8LSBkYXRhX3BvaXNzb24gJT4lDQogIG11dGF0ZShFeHBlY3RlZF9JbmNpZGVudHMgPSBwcmVkaWN0KHBvaXNzb25fbW9kZWwsIHR5cGUgPSAicmVzcG9uc2UiKSkNCg0KIyBQbG90IEV4cGVjdGVkIHZzLiBPYnNlcnZlZCBDb3VudHMNCmdncGxvdChkYXRhX3BvaXNzb24sIGFlcyh4ID0gRXhwZWN0ZWRfSW5jaWRlbnRzLCB5ID0gSW5jaWRlbnRzX1dlZWtseSwgY29sb3IgPSBTdXBwb3J0X0xldmVsKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC42KSArDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJQb2lzc29uIE1vZGVsIEZpdDogRXhwZWN0ZWQgdnMuIE9ic2VydmVkIEluY2lkZW50IENvdW50cyIsDQogICAgeCA9ICJFeHBlY3RlZCBXZWVrbHkgSW5jaWRlbnRzIChNb2RlbCBQcmVkaWN0aW9uKSIsDQogICAgeSA9ICJPYnNlcnZlZCBXZWVrbHkgSW5jaWRlbnRzIiwNCiAgICBjb2xvciA9ICJTdXBwb3J0IExldmVsIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANClBvaW50cyBvbiB0aGUgZ3JhcGggYWJvdmUgdGhlIGxpbmUgaW5kaWNhdGUgd2hlcmUgb3VyIG1vZGVsIHVuZGVyZXN0aW1hdGVzIHRoZSBjb3VudCwgcG9pbnRzIGJlbG93IHRoZSBsaW5lIGluZGljYXRlIHdoZXJlIG91ciBtb2RlbCBvdmVyZXN0aW1hdGVzIHRoZSBjb3VudCwgYW5kIHBvaW50cyBleGFjdGx5IG9uIHRoZSBsaW5lIGFyZSBwZXJmZWN0IHByZWRpY3Rpb25zLiANCg0KIyMgTW9kZWxpbmcgU2tld2VkIENvbnRpbnVvdXMgRGF0YSB3aXRoIEdhbW1hIFJlZ3Jlc3Npb24gDQoNCl9fSW5zdXJhbmNlIENsYWltIEFtb3VudHNfXzogQW4gaW5zdXJhbmNlIGNvbXBhbnkgd2FudHMgdG8gbW9kZWwgdGhlIHNpemUgb2YgZmluYW5jaWFsIGNsYWltcyBwYWlkIG91dCB0byBjdXN0b21lcnMuIENsYWltIGFtb3VudHMgYXJlICpjb250aW51b3VzKiBhbmQgKnBvc2l0aXZlKiAoY2Fubm90IGJlIG5lZ2F0aXZlKS4gVGhleSBhcmUgKmhpZ2hseSByaWdodC1za2V3ZWQqIChtb3N0IGNsYWltcyBhcmUgc21hbGwsIGJ1dCBhIGZldyBhcmUgdmVyeSBsYXJnZSkuIFBvc2l0aXZlLCBjb250aW51b3VzLCBza2V3ZWQgZGF0YSB0eXBlcyBjYW4gYmUgbW9kZWxlZCB3aXRoIHRoZSBfX0dhbW1hX18gR0xNIEZhbWlseS4NCg0KIyMjIFRoZSBHYW1tYSBMaW5rIEZ1bmN0aW9uDQoNClRoZSBHYW1tYSBkaXN0cmlidXRpb24gY29tbW9ubHkgdXNlcyB0aGUgKipMb2cgTGluayoqIChvciBzb21ldGltZXMgdGhlICoqSW52ZXJzZSBsaW5rKiopLiBXZSdsbCBzdGljayB3aXRoIExvZyBhcyBpdCBhbGxvd3MgZm9yIHRoZSBtdWx0aXBsaWNhdGl2ZSBpbnRlcnByZXRhdGlvbiB3ZSBqdXN0IGxlYXJuZWQuDQoNCiQkXGxvZyhcbXUpID0gXGJldGFfMCArIFxiZXRhXzEgWF8xICsgXGRvdHMkJA0KDQojIyMgUiBDb2RlICYgSW50ZXJwcmV0YXRpb24NCmBgYHtyfQ0KIyAzLiBTaW11bGF0ZSBHYW1tYSBkYXRhIChDbGFpbSBBbW91bnRzKQ0Kc2V0LnNlZWQoMTAxKQ0KZGF0YV9nYW1tYSA8LSB0aWJibGUoDQogIEN1c3RvbWVyX1Njb3JlID0gcnVuaWYoMTAwLCA1MDAsIDgwMCksICMgZS5nLiwgY3JlZGl0L3Jpc2sgc2NvcmUNCiAgQ2xhaW1fVHlwZSA9IGZhY3RvcihzYW1wbGUoYygiTWlub3IiLCAiTWFqb3IiKSwgMTAwLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKSksDQogICMgR2VuZXJhdGUgY2xhaW0gYW1vdW50cyAobWVhbiBkZXBlbmRzIG9uIHNjb3JlIGFuZCBjbGFpbSB0eXBlKQ0KICBtdSA9IGV4cCg3IC0gMC4wMDUgKiBDdXN0b21lcl9TY29yZSArIDAuNSAqIChDbGFpbV9UeXBlID09ICJNYWpvciIpKSwNCiAgQ2xhaW1fQW1vdW50ID0gcmdhbW1hKDEwMCwgc2hhcGUgPSAyLCByYXRlID0gMi9tdSkgIyBHYW1tYSBwYXJhbWV0ZXJpemF0aW9uDQopDQoNCiMgNC4gRml0IHRoZSBHYW1tYSBHTE0NCmdhbW1hX21vZGVsIDwtIGdsbSgNCiAgQ2xhaW1fQW1vdW50IH4gQ3VzdG9tZXJfU2NvcmUgKyBDbGFpbV9UeXBlLA0KICBmYW1pbHkgPSBHYW1tYShsaW5rID0gImxvZyIpLCAjIEZhbWlseSBjaGFuZ2VzLCBsaW5rIHN0YXlzICdsb2cnDQogIGRhdGEgPSBkYXRhX2dhbW1hDQopDQoNCnN1bW1hcnkoZ2FtbWFfbW9kZWwpDQpgYGANCg0KIyMjIEludGVycHJldGF0aW9uIG9mIENvZWZmaWNpZW50cyAoUmF0ZSBSYXRpb3MgQWdhaW4hKToNCg0KU2luY2Ugd2UgdXNlZCB0aGUgTG9nIExpbmsgYWdhaW4sIHRoZSBpbnRlcnByZXRhdGlvbiB0ZW1wbGF0ZSBpcyB0aGUgc2FtZSBhcyBQb2lzc29uIGFuZCBMb2dpc3RpYyBSZWdyZXNzaW9u4oCUZXhwb25lbnRpYXRlIHRoZSBjb2VmZmljaWVudCBmb3IgYSBtdWx0aXBsaWNhdGl2ZSBlZmZlY3QuDQoNCmBgYHtyfQ0KIyBFeHBvbmVudGlhdGUgdGhlIGNvZWZmaWNpZW50cw0KZXhwKGNvZWYoZ2FtbWFfbW9kZWwpKQ0KYGBgDQoNClNpbmNlIHRoZSBHYW1tYSBtb2RlbCB1c2VkIHRoZSBMb2cgTGluayAoYGZhbWlseSA9IEdhbW1hKGxpbmsgPSAibG9nIilgKSwgd2UgaW50ZXJwcmV0IHRoZSBleHBvbmVudGlhdGVkIGNvZWZmaWNpZW50cyAoJFxleHAoXGJldGEpJCkgYXMgYSAqbXVsdGlwbGljYXRpdmUgcmF0aW8qIHJlbGF0aXZlIHRvIHRoZSBleHBlY3RlZCBtZWFuIChjbGFpbSBhbW91bnQpLg0KDQp8IENvZWZmaWNpZW50ICAgICB8IEVzdGltYXRlICQoXGJldGEpJCB8ICRcZXhwKFxiZXRhKSQgICAgfCBJbnRlcnByZXRhdGlvbiAoTXVsdGlwbGljYXRpdmUpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgYChJbnRlcmNlcHQpYCAgICAgfCA3LjM3MTc2NTkgICAgfCAxNTkwLjQ0ICAgfCBUaGlzIGlzIHRoZSBleHBlY3RlZCBjbGFpbSBhbW91bnQgKGluIGN1cnJlbmN5IHVuaXRzLCBlLmcuLCBkb2xsYXJzKSB3aGVuIGFsbCBwcmVkaWN0b3JzIGFyZSB6ZXJvIChpLmUuLCBDdXN0b21lciBTY29yZSA9IDAgYW5kIENsYWltIFR5cGUgPSBgTWFqb3JgKS4gVGhpcyB2YWx1ZSBpcyB1c3VhbGx5IHRoZW9yZXRpY2FsIHNpbmNlIGEgc2NvcmUgb2YgMCBpcyB1bnJlYWxpc3RpYy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgYEN1c3RvbWVyX1Njb3JlYCAgfCAtMC4wMDQ4MzQ4ICAgfCAqKjAuOTk1MTc2OSoqIHwgRm9yIGV2ZXJ5ICoqb25lLXVuaXQgaW5jcmVhc2UqKiBpbiB0aGUgQ3VzdG9tZXIgU2NvcmUsIHRoZSBleHBlY3RlZCBjbGFpbSBhbW91bnQgaXMgbXVsdGlwbGllZCBieSAwLjk5NSwgb3IgZGVjcmVhc2VzIGJ5IGFwcHJveGltYXRlbHkgKiowLjQ4JSoqICgkMSAtIDAuOTk1MTc2OSA9IDAuMDA0ODIkKS4gVGhpcyBzdWdnZXN0cyBoaWdoZXIgY3VzdG9tZXIgc2NvcmVzIGFyZSBhc3NvY2lhdGVkIHdpdGggc2xpZ2h0bHkgbG93ZXIgY2xhaW0gYW1vdW50cy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IGBDbGFpbV9UeXBlTWlub3JgIHwgLTAuNTY3ODAzMCAgIHwgKiowLjU2Njc2OTMqKiB8IFRoZSBiYXNlbGluZSAob21pdHRlZCkgY2F0ZWdvcnkgaXMgYENsYWltX1R5cGVNYWpvcmAuIFRoZXJlZm9yZSwgdGhlIGV4cGVjdGVkIGNsYWltIGFtb3VudCBmb3IgYSBgTWlub3JgIGNsYWltIGlzICoqMC41NjcgdGltZXMqKiB0aGUgZXhwZWN0ZWQgY2xhaW0gYW1vdW50IGZvciBhIGBNYWpvcmAgY2xhaW0sIGhvbGRpbmcgQ3VzdG9tZXIgU2NvcmUgY29uc3RhbnQuIEluIG90aGVyIHdvcmRzLCBNaW5vciBjbGFpbXMgYXJlIGV4cGVjdGVkIHRvIGJlIGFib3V0ICoqNDMuMyUgbG93ZXIqKiAoJDEgLSAwLjU2Njc2OTMkKSB0aGFuIE1ham9yIGNsYWltcy4gfA0KDQoNCg0KIyMjIEFzc3VtcHRpb24gQ2hlY2s6IEhvbW9zY2VkYXN0aWNpdHkgdnMuIFZhcmlhbmNlIEZ1bmN0aW9uDQoNClVubGlrZSBMaW5lYXIgUmVncmVzc2lvbiB3aGVyZSB2YXJpYW5jZSBpcyBjb25zdGFudCAoaG9tb3NjZWRhc3RpY2l0eSksIEdMTXMgYWxsb3cgdmFyaWFuY2UgdG8gYmUgYSBmdW5jdGlvbiBvZiB0aGUgbWVhbiAoJFx0ZXh0e1Zhcn0oWSkgPSBWKFxtdSkkKS4gDQoNCiAtIEZvciBOb3JtYWwsICRWKFxtdSkgPSBcc2lnbWFeMiQgKENvbnN0YW50IHZhcmlhbmNlKS4gDQogLSBGb3IgUG9pc3NvbiwgJFYoXG11KSA9IFxtdSQgKFZhcmlhbmNlIGluY3JlYXNlcyB3aXRoIHRoZSBtZWFuKS4gIA0KIC0gRm9yIEdhbW1hLCAkVihcbXUpID0gXHBoaSBcbXVeMiQgKFZhcmlhbmNlIGluY3JlYXNlcyB3aXRoIHRoZSBzcXVhcmUgb2YgdGhlIG1lYW4pLg0KIA0KX19EaWFnbm9zdGljOl9fIFBsb3R0aW5nIHRoZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIGFnYWluc3QgdGhlIGZpdHRlZCB2YWx1ZXMgKG1lYW4pLg0KDQpgYGB7cn0NCnBsb3QoDQogIGZpdHRlZChnYW1tYV9tb2RlbCksDQogIHJlc2lkKGdhbW1hX21vZGVsLCB0eXBlID0gImRldmlhbmNlIiksDQogIHhsYWIgPSAiRml0dGVkIFZhbHVlcyAoRXhwZWN0ZWQgQ2xhaW0gQW1vdW50KSIsDQogIHlsYWIgPSAiRGV2aWFuY2UgUmVzaWR1YWxzIiwNCiAgbWFpbiA9ICJHYW1tYSBNb2RlbCBSZXNpZHVhbHMgdnMuIEZpdHRlZCBWYWx1ZXMiDQopDQphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmV5IiwgbHR5ID0gMikNCmBgYA0KDQpXZSBsb29rIGZvciByYW5kb20gc2NhdHRlciBhcm91bmQgemVyby4gV2UgYXJlIG5vdCBsb29raW5nIGZvciBjb25zdGFudCB2YXJpYW5jZSAoYXMgaW4gTGluZWFyIFJlZ3Jlc3Npb24pLCBidXQgcmF0aGVyIGVuc3VyaW5nIHRoZXJlIGlzIG5vIG9idmlvdXMgcGF0dGVybiAobGlrZSBhIGNvbmUgc2hhcGUsIHdoaWNoIHdvdWxkIGluZGljYXRlIGEgcG9vciBmaXQgZm9yIHRoZSBjaG9zZW4gdmFyaWFuY2UgZnVuY3Rpb24sICRWKFxtdSkgPSBccGhpIFxtdV4yJCkuDQoNCiMjIENvbmNsdXNpb24NCg0KVGhlIFRyYW5zZmVyYWJsZSBBbmFseXRpY2FsIENhcGFjaXR5DQoNCllvdSBub3cga25vdyB0aHJlZSBkaWZmZXJlbnQgR0xNcywgYW5kIHlldCwgdGhlIGNvcmUgc2tpbGxzIHlvdSB1c2UgYXJlIGlkZW50aWNhbDoNCg0KfCBUYXNrICAgICAgICAgICAgICAgICAgICAgICB8IExpbmVhci9Mb2dpc3RpYy9Qb2lzc29uL0dhbW1hICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IE1vZGVsIFNwZWNpZmljYXRpb24gICAgICAgIHwgYFkgfiBYMSArIFgyYCAoVGhlIHN5c3RlbWF0aWMgY29tcG9uZW50IGlzIHRoZSBzYW1lKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICpQKi1WYWx1ZSBJbnRlcnByZXRhdGlvbiAgICAgfCBBIGhpZ2ggV2FsZCAkXGNoaV4yJCBzdGF0aXN0aWMgKHQtc3RhdGlzdGljIGZvciBMaW5lYXIpIHJlc3VsdHMgaW4gYSBsb3cgcC12YWx1ZSwgaW5kaWNhdGluZyB0aGUgcHJlZGljdG9yIGlzIHJlbGV2YW50IHRvIHRoZSBsaW5rIGZ1bmN0aW9uIG9mIHRoZSBtZWFuLiB8DQp8IENvZWZmaWNpZW50IEludGVycHJldGF0aW9uIHwgSWRlbnRpdHkgTGluayAoTGluZWFyKTogQWRkaXRpdmUgZWZmZWN0LiAkXGJldGFfMSQgaXMgdGhlIGNoYW5nZSBpbiAkWSQgcGVyIHVuaXQgJFhfMSQuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IExvZyBMaW5rIChMb2dpc3RpYywgUG9pc3NvbiwgR2FtbWEpOiBNdWx0aXBsaWNhdGl2ZSBlZmZlY3QuICRcZXhwKFxiZXRhXzEpJCBpcyB0aGUgcmF0aW8gb2YgbWVhbnMvcmF0ZXMvb2RkcyBwZXIgdW5pdCAkWF8xJC4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCg0KV2hldGhlciB5b3UgYXJlIGRlYWxpbmcgd2l0aCBMb2cgT2RkcyAoTG9naXN0aWMpLCBMb2cgUmF0ZXMgKFBvaXNzb24pLCBvciBMb2cgTWVhbnMgKEdhbW1hKSwgdGhlIHByb2Nlc3Mgb2YgZXhwb25lbnRpYXRpbmcgdGhlIGNvZWZmaWNpZW50IHRvIGdldCBhIG11bHRpcGxpY2F0aXZlIHJhdGlvIGlzIHRoZSBzYW1lLiBZb3UganVzdCBuZWVkIHRvIGFkanVzdCB5b3VyIGxhbmd1YWdlIChvZGRzLCByYXRlLCBvciBtZWFuKSB0byBtYXRjaCB0aGUgZGF0YSB0eXBlIQ0KDQo=