General Example
Let’s consider the following DGP:
\[\begin{align} Y= X + U \ \ \ with \ \ \
U \sim \mathcal{N}(0,0.5) \\
X = \mathbf{1}(V\geq 0) \\
W = \mathbf{1}(Z\geq 0) \\
[V, Z]'\sim \mathcal{N}\left([0~~0]',\left[ \begin{array}
{rrr}
1 & \rho \\
\rho & 1
\end{array}\right]\right)
\end{align}\]
First, consider the case where \(Y\)
and \(W\) are independent (i.e. \(\rho =0\)). This is illustrated by drawing
a large sample from the described DGP with \(\rho = 0\):
if (!require("tidyverse")) install.packages("tidyverse", dependencies = TRUE); library(tidyverse)
if (!require("ggridges")) install.packages("ggridges", dependencies = TRUE); library(ggridges)
if (!require("MASS")) install.packages("MASS", dependencies = TRUE); library(MASS)
set.seed(1234)
n = 1000000
mu = c(0,0)
rho = 0
sigma = matrix(c(1,rho,rho,1), nrow = 2)
draw = mvrnorm(n, mu, sigma)
X = 1*(draw[,1]>0)
W = 1*(draw[,2] > 0)
Y = X + rnorm(n, sd = 0.5)
Let’s plot the distributions of \(Y\) for \(W=0\) and \(W=1\):
tibble(Y,W,X) %>% mutate(W = as.factor(W)) %>%
ggplot(aes(x = Y, y = fct_rev(W), fill = W))+
geom_density_ridges(alpha = 0.6)+
xlab("Y") + ylab("Density")
The distribution of \(Y\) is the
same when conditioning on different values of \(W\). Consequently, \(Y\) and \(W\) are independent. This is a feature of
the (conditional) distribution of \(Y\)
and thus also holds for the (conditional) expected value:
\[ E[Y \mid W=1] = E[Y \mid W=0] = E[Y] =
0.5 \]
mean(Y)
[1] 0.5002274
mean(Y[W==1])
[1] 0.49979
mean(Y[W==0])
[1] 0.5006651
Now, let’s introduce some correlation between the variables \(V\) and \(Z\) by setting \(\rho = 0.6\). This creates dependence
between \(Y\) and \(W\):
set.seed(1234)
n = 1000000
mu = c(0,0)
rho = 0.6
sigma = matrix(c(1,rho,rho,1), nrow = 2)
draw = mvrnorm(n, mu, sigma)
X = 1*(draw[,1]>0)
W = 1*(draw[,2] > 0)
Y = X + rnorm(n, sd = 0.5)
tibble(Y,W,X) %>% mutate(W = as.factor(W)) %>%
ggplot(aes(x = Y, y = fct_rev(W), fill = W))+
geom_density_ridges(alpha = 0.6)+
xlab("Y")
The distributions are not the same anymore, \(Y\) is not independent of \(W\).
It is however, once we condition on \(X\). In the present context, this can be
seen by looking at the distribution of \(Y\) in the 4 different subgroups formed by
the 2 binary variables \(W\) and \(X\).
tibble(Y,W,X) %>% mutate(W = as.factor(W), X = as.factor(X), Subgroup = interaction(W,X)) %>%
ggplot(aes(x = Y, y = fct_rev(Subgroup), fill = Subgroup))+
geom_density_ridges(alpha = 0.6)+
scale_fill_discrete(labels = c("W=0, X=0","W=1, X=0","W=0, X=1","W=1, X=1"))+
xlab("Y") + ylab("Density")
Once we condition on \(X\),
i.e. look at the distribution of \(Y\)
in the 2 subgroups with \(X=0\) and
\(X=1\), the distributions don’t change
when conditioning on different values of \(W\). \(Y\)
and \(W\) are independent conditional
on \(X\): \(Y
\perp\!\!\!\!\perp W \mid X\)
In this case, \(E[Y \mid W=1] \neq E[Y \mid
W=0] \neq E[Y]\):
mean(Y)
[1] 0.4995484
mean(Y[W==1])
[1] 0.7044881
mean(Y[W==0])
[1] 0.2947923
Conditional on X, we can see that: \(E[Y
\mid W= 0, X=x] = E[Y \mid W= 1, X=x] = E[Y \mid X=x]\) for \(x \in \{0,1\}\):
tibble(Y,W,X) %>% group_by(X,W) %>% summarise(mean_Y = mean(Y))
tibble(Y,W,X) %>% group_by(X) %>% summarise(mean_Y = mean(Y))
Example: Potential Outcomes and causal inference
Let’s look at the importance of the above concept in a causal
inference context. \(Y\) denotes the
outcome, \(W\) the treatment and \(X\) some confounding variable. \(Y(1)\) and \(Y(0)\) are the potential outcomes in the
treated and untreated case respectively, so \(Y = W \cdot Y(1) + (1-W) \cdot Y(0)\).
set.seed(1234)
n = 1000000
mu = c(0,0)
rho = 0
sigma = matrix(c(1,rho,rho,1), nrow = 2)
draw = mvrnorm(n, mu, sigma)
X = 1*(draw[,1] > 0)
W = 1*(draw[,2] > 0)
Y0 = X + rnorm(n, sd = 0.5)
Y1 = 0.5 + X + rnorm(n, sd = 0.5)
Y = W*Y1 + (1-W)*Y0
Consider the following DGP:
\(Y(0) = X + U_0\) with \(U_0 \sim \mathcal{N}(0,0.5)\).
\(Y(1) = 0.5 + X + U_1\) with
\(U_1 \sim
\mathcal{N}(0,0.5)\).
and \[\begin{align}
X = \mathbf{1}(V\geq 0) \\
W = \mathbf{1}(Z\geq 0) \\
[V, Z]'\sim \mathcal{N}\left([0~~0]',\left[ \begin{array}
{rrr}
1 & \rho \\
\rho & 1
\end{array}\right]\right)
\end{align}\]
First, consider again the case with \(\rho
= 0\) to illustrate independence in the sense that \(Y(w) \perp\!\!\!\!\perp W\).
To see that this holds in the first example, plot the distributions
of \(Y(1)\) for the treated and the
untreated separately. As we have independence, they should look
identical:
tibble(Y1,Y0,Y,W,X) %>% mutate(W = as.factor(W)) %>%
ggplot(aes(x = Y1, y = fct_rev(W), fill = W))+
geom_density_ridges(alpha = 0.6)+
xlab("Y(1)")+ ylab("Density")
Same for \(Y(0)\):
tibble(Y1,Y0,Y,W,X) %>% mutate(W = as.factor(W)) %>%
ggplot(aes(x = Y0, y = fct_rev(W), fill = W))+
geom_density_ridges(alpha=.6)+
xlab("Y(0)")+ ylab("Density")
These graphs illustrate that the potential outcomes are independent
of the treatment indicator.
The individual treatment effects are given as: \(Y(1) - Y(0) = 0.5 + X + U_1 - X - U_0 = 0.5 + U_1
- U_0\). The ATE is \(E[Y(1)-Y(0)] =
0.5\).
As the potential outcomes are independent of \(W\), we can estimate the ATE using a simple
mean comparison between the treated and the untreated group:
TE_mean_comparison = mean(Y[W==1]) - mean(Y[W==0])
print(TE_mean_comparison)
[1] 0.4984061
As above, let’s introduce some correlation between \(V\) and \(Z\) by setting $= 0.6. Now, \(X\) and \(W\) are not independent:
rho = 0.6
sigma = matrix(c(1,rho,rho,1), nrow = 2)
draw = mvrnorm(n, mu, sigma)
X = 1*(draw[,1] > 0)
W = 1*(draw[,2] > 0)
Y0 = X + rnorm(n, sd = 0.5)
Y1 = 0.5 + X + rnorm(n, sd = 0.5)
Y = W*Y1 + (1-W)*Y0
Intuitively, observations with a high \(X\) (and thus a high \(Y\)) are now more likely to be treated, as
\(V\) and \(Z\), the two variables determining \(X\) and \(W\), are positively correlated. Comparing
means between treated and untreated will give an incorrect, too large,
estimate of the ATE. In a first step, let’s again illustrate the lack of
independence between the potential outcomes and \(W\):
tibble(Y1,Y0,Y,W,X) %>% mutate(W = as.factor(W)) %>%
ggplot(aes(x = Y1, y = fct_rev(W), fill = W))+
geom_density_ridges(alpha=.6)+
xlab("Y(1)")+ylab("Density")
Same for \(Y(0)\):
tibble(Y1,Y0,Y,W,X) %>% mutate(W = as.factor(W)) %>%
ggplot(aes(x = Y0, y = fct_rev(W), fill = W))+
geom_density_ridges(alpha=.6)+
xlab("Y(0)")+ylab("Density")
The potential outcomes are not independent of \(W\). Estimate the ATE by mean
comparison:
TE_mean_comparison = mean(Y[W==1]) - mean(Y[W==0])
print(TE_mean_comparison)
[1] 0.9111342
Let’s condition on \(X\) and see
whether they are independent. For this purpose, look at the
distributions of \(Y(w)\) for the
different subgroups formed by \(W\) and
\(X\):
tibble(Y,Y1,Y0,W,X) %>% mutate(W = as.factor(W), X = as.factor(X), Subgroup = interaction(W,X)) %>%
ggplot(aes(x = Y1, y = fct_rev(Subgroup), fill = Subgroup))+
geom_density_ridges(alpha = 0.6)+
scale_fill_discrete(labels = c("W=0, X=0","W=1, X=0","W=0, X=1","W=1, X=1"))+
xlab("Y(1)")+ylab("Density")
tibble(Y,Y1,Y0,W,X) %>% mutate(W = as.factor(W), X = as.factor(X), Subgroup = interaction(W,X)) %>%
ggplot(aes(x = Y0, y = fct_rev(Subgroup), fill = Subgroup))+
geom_density_ridges(alpha = 0.7)+
scale_fill_discrete(labels = c("W=0, X=0","W=1, X=0","W=0, X=1","W=1, X=1"))+
xlab("Y(0)")+ylab("Density")
When we look at conditional distributions of the potential outcomes,
they are the same for treated and untreated. This shows that conditional
on \(X\), the potential outcomes are
independent of \(W\). What does this
imply for the estimation of the ATE?
We can estimate the ATE by comparing conditional means:
TE_cond_mean_comparison_1 = mean(Y[W==1 & X==1]) - mean(Y[W==0 & X==1])
print(TE_cond_mean_comparison_1)
[1] 0.5019498
TE_cond_mean_comparison_0 = mean(Y[W==1 & X==0]) - mean(Y[W==0 & X==0])
print(TE_cond_mean_comparison_0)
[1] 0.4993736
TE_cond_mean_comparison = mean(X)*TE_cond_mean_comparison_1 + mean(1-X)*TE_cond_mean_comparison_0
print(TE_cond_mean_comparison)
[1] 0.5006614
Alternatively, use a regression model with \(X\) as a control variable:
summary(lm(Y~ W + X))
Call:
lm(formula = Y ~ W + X)
Residuals:
Min 1Q Median 3Q Max
-2.40876 -0.33723 -0.00068 0.33697 2.46799
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001105 0.000778 -1.421 0.155
W 0.500661 0.001097 456.274 <2e-16 ***
X 1.000412 0.001097 911.718 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.5003 on 999997 degrees of freedom
Multiple R-squared: 0.6241, Adjusted R-squared: 0.6241
F-statistic: 8.301e+05 on 2 and 999997 DF, p-value: < 2.2e-16
This recovers the true ATE. Note, that here the true structural model
is actually linear and OLS can be used to recover the true coefficients
on \(X\) and \(W\):
\[ Y = W\cdot (0.5 + X + U_{1}) + (1-W)
\cdot (X + U_{0}) = 0.5W + X +\underbrace{WU_{1} + (1-W)U_{0}}_{=U}
= 0.5W + X + U\]
LS0tDQp0aXRsZTogIihDb25kaXRpb25hbCkgSW5kZXBlbmRlbmNlIg0Kc3VidGl0bGU6ICJTaW11bGF0aW9uIG5vdGVib29rIg0KYXV0aG9yOiAiTWljaGFlbCBLbmF1cyINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVtLyV5JylgIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCi0tLQ0KDQo8YnI+DQoNCg0KR29hbHM6DQoNCi0gSWxsdXN0cmF0ZSAoY29uZGl0aW9uYWwpIGluZGVwZW5kZW5jZSBpbiBnZW5lcmFsIGFuZCBmb3IgY2F1c2FsIGluZmVyZW5jZSB3aXRoIGJpbmFyeSB0cmVhdG1lbnRzIGluIHBhcnRpY3VsYXINCg0KPGJyPg0KDQoqQWNrbm93bGVkZ2VtZW50czogSSB0aGFuayBIZW5yaSBQZmxlaWRlcmVyIGZvciBoaXMgYXNzaXN0YW5jZSBpbiBwcmVwYXJpbmcgdGhpcyBub3RlYm9vay4qDQoNCjxicj4NCg0KIyMgRm9ybWFsIGRlZmluaXRpb24gb2YgKGNvbmRpdGlvbmFsKSBpbmRlcGVuZGVuY2UNCiMjIyBEaXNjcmV0ZSBWYXJpYWJsZXMNCg0KSW5kZXBlbmRlbmNlIG9mIHR3byBkaXNjcmV0ZSB2YXJpYWJsZXMgJFkkIGFuZCAkVyQ6IA0KDQokJCBZIFxwZXJwXCFcIVwhXCFccGVycCBXIFxpZmYgUChZPXksIFc9dykgPSBQKFkgPSB5KSBcY2RvdCBQKFcgPSB3KSQkDQoNClRoaXMgaW1wbGllcyBieSBCYXllcycgbGF3Og0KDQokJCBQKFk9eSBcbWlkIFc9dykgPSAgXGZyYWN7UChZPXksIFc9dyl9e1AoVz13KX0gPSBcZnJhY3tQKFkgPSB5KSBcY2RvdCBQKFcgPSB3KX17UChXPXcpfSA9IFAoWSA9IHkpICQkDQoNCjxicj4NCg0KIyMjIENvbnRpbnVvdXMgVmFyaWFibGVzDQoNCkVxdWl2YWxlbnRseSwgdHdvIGNvbnRpbnVvdXMgdmFyaWFibGVzICRZJCBhbmQgJFckIGJlaW5nIGluZGVwZW5kZW50IG1lYW5zOg0KDQokJCBZIFxwZXJwXCFcIVwhXCFccGVycCBXICBcaWZmIGZfe1ksV30oeSx3KSA9IGZfWSh5KSBcY2RvdCBmX1codykgJCQNCndoZXJlICRmJCBkZW5vdGVzIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb25zLg0KDQo8YnI+DQoNCiMjIyBNaXhlZCBDYXNlDQoNCkluIGFkZGl0aW9uIHRvIHRoZXNlIHR3byBjYXNlcyB0aGVyZSBpcyBhIG1peGVkIGNhc2UuIENvbnNpZGVyIGZvciBleGFtcGxlIGEgY29udGludW91cyAkWSQgYW5kIGEgZGlzY3JldGUgJFckLiBUaGlzIGlzIGEgdmVyeSBjb21tb24gc2V0dXAgaW4gY2F1c2FsIGluZmVyZW5jZS4gV2UgbWF5IHRoaW5rIG9mICRZJCBhcyBhIGNvbnRpbnVvdXMgb3V0Y29tZSBhbmQgJFckIGEgYmluYXJ5IHRyZWF0bWVudCBpbmRpY2F0b3IuIEluIHRoaXMgY2FzZToNCg0KJCQgWSBccGVycFwhXCFcIVwhXHBlcnAgVyAgXGlmZiBmX3tZLFd9KHksdykgPSBmX1koeSkgXGNkb3QgUChXPXcpICQkDQoNClVzaW5nIHRoZSBkZWZpbml0aW9uIG9mIHRoZSBjb25kaXRpb25hbCBkZW5zaXR5IG9yIHByb2JhYmlsaXR5IHJlc3BlY3RpdmVseSwgdGhpcyBpbXBsaWVzOg0KDQokJCBmX3tZIFxtaWQgV30oeSBcbWlkIHcpID0gXGZyYWN7Zl97WSxXfSh5LHcpfXtQKFc9dyl9ID0gXGZyYWN7Zl9ZKHkpIFxjZG90IFAoVz13KX17UChXPXcpfSA9Zl9ZKHkpICAkJA0KYW5kIA0KDQokJCAgUChXID0gdyBcbWlkIFkgPSB5KSA9IFxmcmFje2Zfe1ksV30oeSx3KX17Zl9ZKHkpfSA9IFxmcmFje2ZfWSh5KSBcY2RvdCBQKFc9dyl9e2ZfWSh5KX0gPSBQKFcgPXcpICQkDQoNCjxicj4NCjxicj4NCg0KIyMjIENvbmRpdGlvbmFsIEluZGVwZW5kZW5jZQ0KDQpGb3IgY29tcGFjdG5lc3MsIHdlIGZvY3VzIG9uIHRoZSBtaXhlZCBjYXNlIGhlcmUuIFdlIGhhdmUgdGhyZWUgcmFuZG9tIHZhcmlhYmxlcywgYSBjb250aW51b3VzICRZJCBhbmQgYmluYXJ5ICRYJCBhbmQgJFckLiBXZSBzYXkgdGhhdCAkWSQgYW5kICRXJCBhcmUgaW5kZXBlbmRlbnQgY29uZGl0aW9uYWwgb24gJFgkIGlmZiB0aGUgZm9sbG93aW5nIGhvbGRzOg0KDQokJCBZIFxwZXJwXCFcIVwhXCFccGVycCBXIFxtaWQgWCBcaWZmIGZfe1ksVyBcbWlkIFh9KHksIHcgXG1pZCB4KSA9IGZfe1kgXG1pZCBYfSh5IFxtaWQgeCkgXGNkb3QgUChXID0gdyBcbWlkIFggPSB4KQ0KJCQNCg0KVGhpcyBhbHNvIGltcGxpZXMgZm9yIGFsbCAkdyQgd2l0aCAkUChXID0gdyBcbWlkIFggPSB4KSQgdGhhdA0KDQokJGZfe1lcbWlkIFcsIFh9KHkgXG1pZCB3LHgpID0gXGZyYWN7Zl97WSxXIFxtaWQgWH0oeSx3IFxtaWQgeCl9e1AoVyA9IHcgXG1pZCBYID0geCl9ID0gXGZyYWN7IGZfe1kgXG1pZCBYfSh5IFxtaWQgeCkgXGNkb3QgUChXID0gdyBcbWlkIFggPSB4KX17UChXID0gdyBcbWlkIFggPSB4KX0gPSBmX3tZIFxtaWQgWH0gKHkgXG1pZCB4KSQkDQppLmUuLCB0aGUgY29uZGl0aW9uaW5nIG9uICRXJCBkb2Vzbid0IG1hdHRlciBvbmNlIHdlIGNvbmRpdGlvbiBvbiAkWCQuIEFzIHRoZSAodW5jb25kaXRpb25hbCkgaW5kZXBlbmRlbmNlIGFib3ZlLCB0aGlzIHdvcmtzIHNpbWlsYXJseSBmb3IgdGhlIGNhc2VzIG9mIG9ubHkgY29udGludW91cyBhbmQgb25seSBkaXNjcmV0ZSB2YXJpYWJsZXMgdXNpbmcgb25seSBkZW5zaXRpZXMgb3IgcHJvYmFiaWxpdGllcywgcmVzcGVjdGl2ZWx5Lg0KDQo8YnI+DQoNCiMjIyBDb25kaXRpb25hbCBpbmRlcGVuZGVuY2UgaW1wbGllcyBjb25kaXRpb25hbCAqbWVhbiogaW5kZXBlbmRlbmNlDQoNCkNvbmRpdGlvbmFsIGluZGVwZW5kZW5jZSBvZiAkWSQgYW5kICRXJCBnaXZlbiAkWCQgaW1wbGllcyBtZWFuIGluZGVwZW5kZW5jZSwgbWVhbmluZzogJEVbWSBcbWlkIFgsV10gPSBFW1kgXG1pZCBYXSQ6DQoNCiQkDQpFW1kgXG1pZCBXLFhdID0gXGludF97LVxpbmZ0eX1eeytcaW5mdHl9IHkgXHVuZGVyYnJhY2V7Zl97WSBcbWlkIFcsWH0oeVxtaWQgdyx4KX1fez1mX3tZIFxtaWQgWH0gKHkgXG1pZCB4KSwgXCBjb25kLiBcIGluZGVwLn0gZHkgPSBcaW50X3stXGluZnR5fV57K1xpbmZ0eX0geSBcIFwgZl97WSBcbWlkIFh9ICh5IFxtaWQgeCkgXCBkeSA9IEVbWSBcbWlkIFhdDQokJA0KDQoNCkFsbCBvZiB0aGlzIGlzIGlsbHVzdHJhdGVkIGluIHRoZSBmb2xsb3dpbmcgZXhhbXBsZXMuDQoNCjxicj4NCg0KIyMgR2VuZXJhbCBFeGFtcGxlIA0KDQpMZXQncyBjb25zaWRlciB0aGUgZm9sbG93aW5nIERHUDogDQoNCiQkXGJlZ2lue2FsaWdufSBZPSBYICsgVSBcIFwgXCB3aXRoIFwgXCBcIFUgXHNpbSBcbWF0aGNhbHtOfSgwLDAuNSkgXFwNClggPSBcbWF0aGJmezF9KFZcZ2VxIDApIFxcDQpXID0gXG1hdGhiZnsxfShaXGdlcSAwKSBcXA0KIFtWLCBaXSdcc2ltIFxtYXRoY2Fse059XGxlZnQoWzB+fjBdJyxcbGVmdFsgXGJlZ2lue2FycmF5fQ0Ke3Jycn0NCjEgJiBccmhvICBcXA0KXHJobyAmIDEgDQpcZW5ke2FycmF5fVxyaWdodF1ccmlnaHQpIA0KXGVuZHthbGlnbn0kJA0KDQpGaXJzdCwgY29uc2lkZXIgdGhlIGNhc2Ugd2hlcmUgJFkkIGFuZCAkVyQgYXJlIGluZGVwZW5kZW50IChpLmUuICRccmhvID0wJCkuIFRoaXMgaXMgaWxsdXN0cmF0ZWQgYnkgZHJhd2luZyBhIGxhcmdlIHNhbXBsZSBmcm9tIHRoZSBkZXNjcmliZWQgREdQIHdpdGggJFxyaG8gPSAwJDoNCg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIsIGRlcGVuZGVuY2llcyA9IFRSVUUpOyBsaWJyYXJ5KHRpZHl2ZXJzZSkNCmlmICghcmVxdWlyZSgiZ2dyaWRnZXMiKSkgaW5zdGFsbC5wYWNrYWdlcygiZ2dyaWRnZXMiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKTsgbGlicmFyeShnZ3JpZGdlcykNCmlmICghcmVxdWlyZSgiTUFTUyIpKSBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIiwgZGVwZW5kZW5jaWVzID0gVFJVRSk7IGxpYnJhcnkoTUFTUykNCg0Kc2V0LnNlZWQoMTIzNCkNCm4gPSAxMDAwMDAwDQptdSA9IGMoMCwwKQ0KcmhvID0gMA0Kc2lnbWEgPSBtYXRyaXgoYygxLHJobyxyaG8sMSksIG5yb3cgPSAyKQ0KZHJhdyA9IG12cm5vcm0obiwgbXUsIHNpZ21hKQ0KWCA9IDEqKGRyYXdbLDFdPjApDQpXID0gMSooZHJhd1ssMl0gPiAwKQ0KWSA9IFggKyBybm9ybShuLCBzZCA9IDAuNSkNCmBgYA0KDQpMZXQncyBwbG90IHRoZSBkaXN0cmlidXRpb25zIG9mICRZJCBmb3IgJFc9MCQgYW5kICRXPTEkOg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQ0KdGliYmxlKFksVyxYKSAlPiUgbXV0YXRlKFcgPSBhcy5mYWN0b3IoVykpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gWSwgeSA9IGZjdF9yZXYoVyksIGZpbGwgPSBXKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjYpKw0KICB4bGFiKCJZIikgKyB5bGFiKCJEZW5zaXR5IikNCmBgYA0KDQpUaGUgZGlzdHJpYnV0aW9uIG9mICRZJCBpcyB0aGUgc2FtZSB3aGVuIGNvbmRpdGlvbmluZyBvbiBkaWZmZXJlbnQgdmFsdWVzIG9mICRXJC4gQ29uc2VxdWVudGx5LCAkWSQgYW5kICRXJCBhcmUgaW5kZXBlbmRlbnQuIFRoaXMgaXMgYSBmZWF0dXJlIG9mIHRoZSAoY29uZGl0aW9uYWwpIGRpc3RyaWJ1dGlvbiBvZiAkWSQgYW5kIHRodXMgYWxzbyBob2xkcyBmb3IgdGhlIChjb25kaXRpb25hbCkgZXhwZWN0ZWQgdmFsdWU6DQoNCiQkIEVbWSBcbWlkIFc9MV0gPSBFW1kgXG1pZCBXPTBdID0gRVtZXSA9IDAuNSAkJA0KYGBge3J9DQptZWFuKFkpDQptZWFuKFlbVz09MV0pDQptZWFuKFlbVz09MF0pDQpgYGANCg0KTm93LCBsZXQncyBpbnRyb2R1Y2Ugc29tZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgJFYkIGFuZCAkWiQgYnkgc2V0dGluZyAkXHJobyA9IDAuNiQuIFRoaXMgY3JlYXRlcyBkZXBlbmRlbmNlIGJldHdlZW4gJFkkIGFuZCAkVyQ6DQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpzZXQuc2VlZCgxMjM0KQ0KbiA9IDEwMDAwMDANCm11ID0gYygwLDApDQpyaG8gPSAwLjYNCnNpZ21hID0gbWF0cml4KGMoMSxyaG8scmhvLDEpLCBucm93ID0gMikNCmRyYXcgPSBtdnJub3JtKG4sIG11LCBzaWdtYSkNClggPSAgMSooZHJhd1ssMV0+MCkgDQpXID0gMSooZHJhd1ssMl0gPiAwKQ0KWSA9IFggKyBybm9ybShuLCBzZCA9IDAuNSkNCg0KYGBgDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9DQp0aWJibGUoWSxXLFgpICU+JSBtdXRhdGUoVyA9IGFzLmZhY3RvcihXKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBZLCB5ID0gZmN0X3JldihXKSwgZmlsbCA9IFcpKSsNCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhbHBoYSA9IDAuNikrDQogIHhsYWIoIlkiKQ0KYGBgDQoNClRoZSBkaXN0cmlidXRpb25zIGFyZSBub3QgdGhlIHNhbWUgYW55bW9yZSwgJFkkIGlzIG5vdCBpbmRlcGVuZGVudCBvZiAkVyQuDQoNCkl0IGlzIGhvd2V2ZXIsIG9uY2Ugd2UgY29uZGl0aW9uIG9uICRYJC4gSW4gdGhlIHByZXNlbnQgY29udGV4dCwgdGhpcyBjYW4gYmUgc2VlbiBieSBsb29raW5nIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgJFkkIGluIHRoZSA0IGRpZmZlcmVudCBzdWJncm91cHMgZm9ybWVkIGJ5IHRoZSAyIGJpbmFyeSB2YXJpYWJsZXMgJFckIGFuZCAkWCQuDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9DQp0aWJibGUoWSxXLFgpICU+JSAgbXV0YXRlKFcgPSBhcy5mYWN0b3IoVyksIFggPSBhcy5mYWN0b3IoWCksIFN1Ymdyb3VwID0gaW50ZXJhY3Rpb24oVyxYKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IFksIHkgPSBmY3RfcmV2KFN1Ymdyb3VwKSwgZmlsbCA9IFN1Ymdyb3VwKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjYpKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKGxhYmVscyA9IGMoIlc9MCwgWD0wIiwiVz0xLCBYPTAiLCJXPTAsIFg9MSIsIlc9MSwgWD0xIikpKw0KICB4bGFiKCJZIikgKyB5bGFiKCJEZW5zaXR5IikNCmBgYA0KDQpPbmNlIHdlIGNvbmRpdGlvbiBvbiAkWCQsIGkuZS4gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mICRZJCBpbiB0aGUgMiBzdWJncm91cHMgd2l0aCAkWD0wJCBhbmQgJFg9MSQsIHRoZSBkaXN0cmlidXRpb25zIGRvbid0IGNoYW5nZSB3aGVuIGNvbmRpdGlvbmluZyBvbiBkaWZmZXJlbnQgdmFsdWVzIG9mICRXJC4gJFkkIGFuZCAkVyQgYXJlIGluZGVwZW5kZW50IGNvbmRpdGlvbmFsIG9uICRYJDogJFkgXHBlcnBcIVwhXCFcIVxwZXJwIFcgXG1pZCBYJCANCg0KSW4gdGhpcyBjYXNlLCAkRVtZIFxtaWQgVz0xXSBcbmVxIEVbWSBcbWlkIFc9MF0gXG5lcSBFW1ldJDoNCg0KYGBge3J9DQptZWFuKFkpDQptZWFuKFlbVz09MV0pDQptZWFuKFlbVz09MF0pDQpgYGANCg0KQ29uZGl0aW9uYWwgb24gWCwgd2UgY2FuIHNlZSB0aGF0OiAkRVtZIFxtaWQgVz0gMCwgWD14XSA9IEVbWSBcbWlkIFc9IDEsIFg9eF0gPSBFW1kgXG1pZCBYPXhdJCBmb3IgJHggXGluIFx7MCwxXH0kOg0KDQpgYGB7ciwgd2FybmluZyA9RkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NCnRpYmJsZShZLFcsWCkgJT4lIGdyb3VwX2J5KFgsVykgJT4lIHN1bW1hcmlzZShtZWFuX1kgPSBtZWFuKFkpKQ0KdGliYmxlKFksVyxYKSAlPiUgZ3JvdXBfYnkoWCkgJT4lIHN1bW1hcmlzZShtZWFuX1kgPSBtZWFuKFkpKQ0KYGBgDQoNCjxicj4NCg0KIyMgRXhhbXBsZTogUG90ZW50aWFsIE91dGNvbWVzIGFuZCBjYXVzYWwgaW5mZXJlbmNlDQoNCkxldCdzIGxvb2sgYXQgdGhlIGltcG9ydGFuY2Ugb2YgdGhlIGFib3ZlIGNvbmNlcHQgaW4gYSBjYXVzYWwgaW5mZXJlbmNlIGNvbnRleHQuICRZJCBkZW5vdGVzIHRoZSBvdXRjb21lLCAkVyQgdGhlIHRyZWF0bWVudCBhbmQgJFgkIHNvbWUgY29uZm91bmRpbmcgdmFyaWFibGUuICRZKDEpJCBhbmQgJFkoMCkkIGFyZSB0aGUgcG90ZW50aWFsIG91dGNvbWVzIGluIHRoZSB0cmVhdGVkIGFuZCB1bnRyZWF0ZWQgY2FzZSByZXNwZWN0aXZlbHksIHNvICRZID0gVyBcY2RvdCBZKDEpICsgKDEtVykgXGNkb3QgWSgwKSQuDQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpzZXQuc2VlZCgxMjM0KQ0KbiA9IDEwMDAwMDANCm11ID0gYygwLDApDQpyaG8gPSAwDQpzaWdtYSA9IG1hdHJpeChjKDEscmhvLHJobywxKSwgbnJvdyA9IDIpDQpkcmF3ID0gbXZybm9ybShuLCBtdSwgc2lnbWEpDQpYID0gIDEqKGRyYXdbLDFdID4gMCkNClcgPSAxKihkcmF3WywyXSA+IDApDQpZMCA9IFggKyBybm9ybShuLCBzZCA9IDAuNSkNClkxID0gMC41ICsgWCArIHJub3JtKG4sIHNkID0gMC41KQ0KWSA9IFcqWTEgKyAoMS1XKSpZMA0KYGBgDQoNCg0KQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBER1A6DQoNCi0gJFkoMCkgPSBYICsgVV8wJCB3aXRoICRVXzAgXHNpbSBcbWF0aGNhbHtOfSgwLDAuNSkkLg0KDQotICRZKDEpID0gMC41ICsgWCArIFVfMSQgd2l0aCAkVV8xIFxzaW0gXG1hdGhjYWx7Tn0oMCwwLjUpJC4gDQoNCmFuZA0KJCRcYmVnaW57YWxpZ259DQpYID0gXG1hdGhiZnsxfShWXGdlcSAwKSBcXA0KVyA9IFxtYXRoYmZ7MX0oWlxnZXEgMCkgXFwNCiBbViwgWl0nXHNpbSBcbWF0aGNhbHtOfVxsZWZ0KFswfn4wXScsXGxlZnRbIFxiZWdpbnthcnJheX0NCntycnJ9DQoxICYgXHJobyAgXFwNClxyaG8gJiAxIA0KXGVuZHthcnJheX1ccmlnaHRdXHJpZ2h0KSANClxlbmR7YWxpZ259JCQNCg0KRmlyc3QsIGNvbnNpZGVyIGFnYWluIHRoZSBjYXNlIHdpdGggJFxyaG8gPSAwJCB0byBpbGx1c3RyYXRlIGluZGVwZW5kZW5jZSBpbiB0aGUgc2Vuc2UgdGhhdCAkWSh3KSBccGVycFwhXCFcIVwhXHBlcnAgVyQuDQoNClRvIHNlZSB0aGF0IHRoaXMgaG9sZHMgaW4gdGhlIGZpcnN0IGV4YW1wbGUsIHBsb3QgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgJFkoMSkkIGZvciB0aGUgdHJlYXRlZCBhbmQgdGhlIHVudHJlYXRlZCBzZXBhcmF0ZWx5LiBBcyB3ZSBoYXZlIGluZGVwZW5kZW5jZSwgdGhleSBzaG91bGQgbG9vayBpZGVudGljYWw6DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9DQp0aWJibGUoWTEsWTAsWSxXLFgpICU+JSBtdXRhdGUoVyA9IGFzLmZhY3RvcihXKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBZMSwgeSA9IGZjdF9yZXYoVyksIGZpbGwgPSBXKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjYpKw0KICB4bGFiKCJZKDEpIikrIHlsYWIoIkRlbnNpdHkiKQ0KYGBgDQoNClNhbWUgZm9yICRZKDApJDoNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0NCnRpYmJsZShZMSxZMCxZLFcsWCkgJT4lIG11dGF0ZShXID0gYXMuZmFjdG9yKFcpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFkwLCB5ID0gZmN0X3JldihXKSwgZmlsbCA9IFcpKSsNCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhbHBoYT0uNikrDQogIHhsYWIoIlkoMCkiKSsgeWxhYigiRGVuc2l0eSIpDQpgYGANCg0KVGhlc2UgZ3JhcGhzIGlsbHVzdHJhdGUgdGhhdCB0aGUgcG90ZW50aWFsIG91dGNvbWVzIGFyZSBpbmRlcGVuZGVudCBvZiB0aGUgdHJlYXRtZW50IGluZGljYXRvci4NCg0KVGhlIGluZGl2aWR1YWwgdHJlYXRtZW50IGVmZmVjdHMgYXJlIGdpdmVuIGFzOiAkWSgxKSAtIFkoMCkgPSAwLjUgKyBYICsgVV8xIC0gWCAtIFVfMCA9IDAuNSArIFVfMSAtIFVfMCQuIFRoZSBBVEUgaXMgJEVbWSgxKS1ZKDApXSA9IDAuNSQuDQoNCkFzIHRoZSBwb3RlbnRpYWwgb3V0Y29tZXMgYXJlIGluZGVwZW5kZW50IG9mICRXJCwgd2UgY2FuIGVzdGltYXRlIHRoZSBBVEUgdXNpbmcgYSBzaW1wbGUgbWVhbiBjb21wYXJpc29uIGJldHdlZW4gdGhlIHRyZWF0ZWQgYW5kIHRoZSB1bnRyZWF0ZWQgZ3JvdXA6DQoNCmBgYHtyfQ0KVEVfbWVhbl9jb21wYXJpc29uID0gbWVhbihZW1c9PTFdKSAtIG1lYW4oWVtXPT0wXSkNCnByaW50KFRFX21lYW5fY29tcGFyaXNvbikNCmBgYA0KPGJyPg0KDQpBcyBhYm92ZSwgbGV0J3MgaW50cm9kdWNlIHNvbWUgY29ycmVsYXRpb24gYmV0d2VlbiAkViQgYW5kICRaJCBieSBzZXR0aW5nICRccmhvID0gMC42LiBOb3csICRYJCBhbmQgJFckIGFyZSBub3QgaW5kZXBlbmRlbnQ6DQoNCmBgYHtyLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpyaG8gPSAwLjYNCnNpZ21hID0gbWF0cml4KGMoMSxyaG8scmhvLDEpLCBucm93ID0gMikNCmRyYXcgPSBtdnJub3JtKG4sIG11LCBzaWdtYSkNClggPSAgMSooZHJhd1ssMV0gPiAwKQ0KVyA9IDEqKGRyYXdbLDJdID4gMCkNClkwID0gWCArIHJub3JtKG4sIHNkID0gMC41KQ0KWTEgPSAwLjUgKyBYICsgcm5vcm0obiwgc2QgPSAwLjUpDQpZID0gVypZMSArICgxLVcpKlkwDQpgYGANCg0KSW50dWl0aXZlbHksIG9ic2VydmF0aW9ucyB3aXRoIGEgaGlnaCAkWCQgKGFuZCB0aHVzIGEgaGlnaCAkWSQpIGFyZSBub3cgbW9yZSBsaWtlbHkgdG8gYmUgdHJlYXRlZCwgYXMgJFYkIGFuZCAkWiQsIHRoZSB0d28gdmFyaWFibGVzIGRldGVybWluaW5nICRYJCBhbmQgJFckLCBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkLiBDb21wYXJpbmcgbWVhbnMgYmV0d2VlbiB0cmVhdGVkIGFuZCB1bnRyZWF0ZWQgd2lsbCBnaXZlIGFuIGluY29ycmVjdCwgdG9vIGxhcmdlLCBlc3RpbWF0ZSBvZiB0aGUgQVRFLiBJbiBhIGZpcnN0IHN0ZXAsIGxldCdzIGFnYWluIGlsbHVzdHJhdGUgdGhlIGxhY2sgb2YgaW5kZXBlbmRlbmNlIGJldHdlZW4gdGhlIHBvdGVudGlhbCBvdXRjb21lcyBhbmQgJFckOg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQ0KdGliYmxlKFkxLFkwLFksVyxYKSAlPiUgbXV0YXRlKFcgPSBhcy5mYWN0b3IoVykpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gWTEsIHkgPSBmY3RfcmV2KFcpLCBmaWxsID0gVykpKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFscGhhPS42KSsNCiAgeGxhYigiWSgxKSIpK3lsYWIoIkRlbnNpdHkiKQ0KYGBgDQoNClNhbWUgZm9yICRZKDApJDoNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0NCnRpYmJsZShZMSxZMCxZLFcsWCkgJT4lIG11dGF0ZShXID0gYXMuZmFjdG9yKFcpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFkwLCB5ID0gZmN0X3JldihXKSwgZmlsbCA9IFcpKSsNCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhbHBoYT0uNikrDQogIHhsYWIoIlkoMCkiKSt5bGFiKCJEZW5zaXR5IikNCmBgYA0KDQpUaGUgcG90ZW50aWFsIG91dGNvbWVzIGFyZSBub3QgaW5kZXBlbmRlbnQgb2YgJFckLiBFc3RpbWF0ZSB0aGUgQVRFIGJ5IG1lYW4gY29tcGFyaXNvbjoNCg0KYGBge3J9DQpURV9tZWFuX2NvbXBhcmlzb24gPSBtZWFuKFlbVz09MV0pIC0gbWVhbihZW1c9PTBdKQ0KcHJpbnQoVEVfbWVhbl9jb21wYXJpc29uKQ0KYGBgDQoNCkxldCdzIGNvbmRpdGlvbiBvbiAkWCQgYW5kIHNlZSB3aGV0aGVyIHRoZXkgYXJlIGluZGVwZW5kZW50LiBGb3IgdGhpcyBwdXJwb3NlLCBsb29rIGF0IHRoZSBkaXN0cmlidXRpb25zIG9mICRZKHcpJCBmb3IgdGhlIGRpZmZlcmVudCBzdWJncm91cHMgZm9ybWVkIGJ5ICRXJCBhbmQgJFgkOg0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQ0KdGliYmxlKFksWTEsWTAsVyxYKSAlPiUgIG11dGF0ZShXID0gYXMuZmFjdG9yKFcpLCBYID0gYXMuZmFjdG9yKFgpLCBTdWJncm91cCA9IGludGVyYWN0aW9uKFcsWCkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gWTEsIHkgPSBmY3RfcmV2KFN1Ymdyb3VwKSwgZmlsbCA9IFN1Ymdyb3VwKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAwLjYpKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKGxhYmVscyA9IGMoIlc9MCwgWD0wIiwiVz0xLCBYPTAiLCJXPTAsIFg9MSIsIlc9MSwgWD0xIikpKw0KICB4bGFiKCJZKDEpIikreWxhYigiRGVuc2l0eSIpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0NCnRpYmJsZShZLFkxLFkwLFcsWCkgJT4lICBtdXRhdGUoVyA9IGFzLmZhY3RvcihXKSwgWCA9IGFzLmZhY3RvcihYKSwgU3ViZ3JvdXAgPSBpbnRlcmFjdGlvbihXLFgpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFkwLCB5ID0gZmN0X3JldihTdWJncm91cCksIGZpbGwgPSBTdWJncm91cCkpKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFscGhhID0gMC43KSsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJXPTAsIFg9MCIsIlc9MSwgWD0wIiwiVz0wLCBYPTEiLCJXPTEsIFg9MSIpKSsNCiAgeGxhYigiWSgwKSIpK3lsYWIoIkRlbnNpdHkiKQ0KYGBgDQoNCldoZW4gd2UgbG9vayBhdCBjb25kaXRpb25hbCBkaXN0cmlidXRpb25zIG9mIHRoZSBwb3RlbnRpYWwgb3V0Y29tZXMsIHRoZXkgYXJlIHRoZSBzYW1lIGZvciB0cmVhdGVkIGFuZCB1bnRyZWF0ZWQuIFRoaXMgc2hvd3MgdGhhdCBjb25kaXRpb25hbCBvbiAkWCQsIHRoZSBwb3RlbnRpYWwgb3V0Y29tZXMgYXJlIGluZGVwZW5kZW50IG9mICRXJC4gV2hhdCBkb2VzIHRoaXMgaW1wbHkgZm9yIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSBBVEU/DQoNCldlIGNhbiBlc3RpbWF0ZSB0aGUgQVRFIGJ5IGNvbXBhcmluZyBjb25kaXRpb25hbCBtZWFuczoNCg0KYGBge3J9DQpURV9jb25kX21lYW5fY29tcGFyaXNvbl8xID0gbWVhbihZW1c9PTEgJiBYPT0xXSkgLSBtZWFuKFlbVz09MCAmIFg9PTFdKQ0KcHJpbnQoVEVfY29uZF9tZWFuX2NvbXBhcmlzb25fMSkNCmBgYA0KYGBge3J9DQpURV9jb25kX21lYW5fY29tcGFyaXNvbl8wID0gbWVhbihZW1c9PTEgJiBYPT0wXSkgLSBtZWFuKFlbVz09MCAmIFg9PTBdKQ0KcHJpbnQoVEVfY29uZF9tZWFuX2NvbXBhcmlzb25fMCkNCmBgYA0KYGBge3J9DQpURV9jb25kX21lYW5fY29tcGFyaXNvbiA9IG1lYW4oWCkqVEVfY29uZF9tZWFuX2NvbXBhcmlzb25fMSArIG1lYW4oMS1YKSpURV9jb25kX21lYW5fY29tcGFyaXNvbl8wDQpwcmludChURV9jb25kX21lYW5fY29tcGFyaXNvbikNCmBgYA0KDQpBbHRlcm5hdGl2ZWx5LCB1c2UgYSByZWdyZXNzaW9uIG1vZGVsIHdpdGggJFgkIGFzIGEgY29udHJvbCB2YXJpYWJsZToNCg0KYGBge3J9DQpzdW1tYXJ5KGxtKFl+IFcgKyBYKSkNCmBgYA0KDQpUaGlzIHJlY292ZXJzIHRoZSB0cnVlIEFURS4gTm90ZSwgdGhhdCBoZXJlIHRoZSB0cnVlIHN0cnVjdHVyYWwgbW9kZWwgaXMgYWN0dWFsbHkgbGluZWFyIGFuZCBPTFMgY2FuIGJlIHVzZWQgdG8gcmVjb3ZlciB0aGUgdHJ1ZSBjb2VmZmljaWVudHMgb24gJFgkIGFuZCAkVyQ6DQoNCiQkIFkgPSBXXGNkb3QgKDAuNSArIFggKyBVX3sxfSkgKyAoMS1XKSBcY2RvdCAoWCArIFVfezB9KSA9IDAuNVcgKyBYICtcdW5kZXJicmFjZXtXVV97MX0gKyAoMS1XKVVfezB9fV97PVV9ID0gIDAuNVcgKyBYICsgVSQkDQoNCg==