Creative Commons License

1 Background

Histologic grade in breast cancer (BC) provides clinically important prognostic information. Researchers examined whether histologic grade was associated with gene expression profiles of breast cancers and whether such profiles could be used to improve histologic grading. In this tutorial we will assess the association between histologic grade and the expression of the KPNA2 gene that is known to be associated with poor BC prognosis. The patients, however, do not only differ in the histologic grade, but also on their lymph node status.

The lymph nodes were not affected (0) or surgically removed (1).

library(car)
library(multcomp)

library(tidyverse)

## Set default theme for ggplot2
theme_set(theme_bw(base_size = 14))

2 Data analysis

2.1 Import KPNA2 data in R

kpna2 <- read_table("https://raw.githubusercontent.com/statOmics/SGA21/master/data/kpna2.txt")
kpna2

2.2 Transform the variable grade and node to a factor

kpna2 <- kpna2 %>%
  mutate(
    grade = as.factor(grade),
    node = as.factor(node),
    node = fct_recode(node, Unaffected = "0", Removed = "1")
  )
kpna2

2.3 Data exploration

Histologic grade and lymph node status can be associated with the kpna2 gene expression. Moreover, it is also possible that the differential expression associated with histological grade is different in patients that have unaffected lymph nodes and patients for which the lymph nodes had to be removed.

ggplot(kpna2, aes(x = grade, y = gene, fill = node)) +
  geom_boxplot(outlier.shape = NA) +
  geom_point(position = position_jitterdodge(), shape = 21, size = 2) +
  labs(
    x = "Histologic grade", y = "KPNA2 expression",
    fill = "Lymph node status"
  ) +
  ggtitle("KPNA2 gene expression in breast cancer patients")

The plot suggests

  • An effect of the histological grade
  • An effect of node status
  • The differential expression associated to grade seems to differ according to the lymph node status (interaction)
  • Mean variance relation?

2.4 Model

Histologic grade and lymph node status can be associated with the kpna2 gene expression. Moreover, it is also possible that the differential expression associated with histological grade is different in patients that have unaffected lymph nodes and patients for which the lymph nodes had to be removed. Hence, we will have to model the gene expression by using main effects for grade, node and a grade x node interaction.

# Model with main effects for histological grade and node and grade x node interaction
fit <- lm(gene ~ grade * node, data = kpna2)

par(mfrow = c(2, 2))
plot(fit)

The variance seems to increase with the mean, i.e. the residuals do not seem to be homoscedastic. The QQ-plot of the residuals shows deviations from normality or some outliers.

We will first log2 transform the data.

fit <- lm(log2(gene) ~ grade * node, data = kpna2)

par(mfrow = c(2, 2))
plot(fit)

  • The variance is now more or less equal for every treatment x node combination.
  • The QQ-plot of the residuals shows no deviations from normality.

2.5 Inference

We perform a type III ANOVA to test the interaction effect. Note that we use the Anova() function (with capital A) from the car package here. This function allows to test type-II and type-III tests. The default anova() from base R only performs type-I tests.

## Anova from car package, make sure it's loaded with `library(car)`
anova_res <- Anova(fit, type = "III")
anova_res

The output shows that there is a very significant interaction (\(p=\) 0.0071). Hence, the association of the histological grade on the gene expression differs according to the lymph node status and vice versa.

The researchers are therefore interested in studying and reporting on the following hypotheses:

  • Is the KPNA2 expression on average different between grade 3 and grade 1 tumors from patients with unaffected lymph nodes (by testing \(H_0: \log_2{FC}_{g3n0-g1n0}=0\text{ vs }H1: \log_2{FC}_{g3n0-g1n0}\neq 0\))

  • Is the KPNA2 expression on average different between grade 3 and grade 1 tumors from patients with affected lymph nodes (by testing \(H_0: \log_2{FC}_{g3n1-g1n1}=0\text{ vs }H1: \log_2{FC}_{g3n1-g1n1}\neq 0\))

  • Is the KPNA2 expression on average different in grade 1 tumors of patients with affected and patients with unaffected lymph nodes (by testing \(H_0: \log_2{FC}_{g1n1-g1n0}=0\text{ vs }H1: \log_2{FC}_{g1n1-g1n0}\neq 0\))

  • Is the KPNA2 expression on average different in grade 3 tumors of patients with affected and patients with unaffected lymph nodes (by testing \(H_0: \log_2{FC}_{g3n1-g3n0}=0\text{ vs }H1: \log_2{FC}_{g3n1-g3n0}\neq 0\))

  • Is the fold change of the KPNA2 gene between grade 3 and grade 1 different according to the lymph node status and vice versa (tested already by assessing the interaction: \(H_0: \log_2{FC}_{g3n0-g1n0}=\log_2{FC}_{g3n1-g1n1} \text{ vs }H1:\log_2{FC}_{g3n0-g1n0}\neq\log_2{FC}_{g3n1-g1n1}\)).

3 Interpretation of model parameters and statistical tests

ExploreModelMatrix::VisualizeDesign(kpna2, ~ grade * node)$plotlist[[1]]

summary(fit)

Call:
lm(formula = log2(gene) ~ grade * node, data = kpna2)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.57694 -0.19857 -0.04079  0.20807  0.64557 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)          7.4796     0.1292  57.893  < 2e-16 ***
grade3               1.6675     0.1827   9.127 1.44e-08 ***
nodeRemoved          0.6577     0.1827   3.600  0.00179 ** 
grade3:nodeRemoved  -0.7748     0.2584  -2.998  0.00710 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3165 on 20 degrees of freedom
Multiple R-squared:  0.848, Adjusted R-squared:  0.8252 
F-statistic: 37.18 on 3 and 20 DF,  p-value: 2.266e-08
# Calculate confidence intervals for parameters of model
CIfit <- confint(fit)

# log_2 FC between g3n0-g1n0, g1n1-g1n0
# and log_2 difference in FC g3n1-g1n1 and FC g3n0-g1n0
CIfit
                        2.5 %     97.5 %
(Intercept)         7.2101125  7.7491128
grade3              1.2864076  2.0486691
nodeRemoved         0.2766005  1.0388620
grade3:nodeRemoved -1.3137511 -0.2357505
# Transform parameters and the CI back to the original scale
2^coef(fit)
       (Intercept)             grade3        nodeRemoved 
       178.4792627          3.1767209          1.5775997 
grade3:nodeRemoved 
         0.5844896 
2^CIfit
                         2.5 %      97.5 %
(Intercept)        148.0676336 215.1371400
grade3               2.4391992   4.1372414
nodeRemoved          1.2113372   2.0546063
grade3:nodeRemoved   0.4022736   0.8492431

We model the log\(_2\)-transformed intensities with the following model: \[ y=\beta_0+\beta_{g3}x_{g3}+\beta_{n1}x_{n1}+\beta_{g3n1}x_{g3}x_{n1}, \]

with \(\beta_0\) the intercept, \(\beta_{g3}\) the main effect for grade, \(x_{g3}\) a dummy variable for grade which is 0 for the control treatment in the absence of grade and 1 for the treatment with grade, \(\beta_{n1}\) the main effect for node, \(x_{n1}\) a dummy variable that is 0 for the measurements of patients with unaffected lymph nodes and 1 for patients for which the lymph nodes were removed and \(\beta_{g3n1}\) the interaction effect between grade and node. To ease the interpretation of the parameters, \(\log_2\) transformed geometric mean intensities are given for each treatment group as well as corresponding contrasts between treatments, which have an interpretation in terms of \(\log_2\) transformed fold changes (FC).

  • \(\log_2\hat{\mu}_{g1n0}=\hat\beta_0\), \(\log_2 \hat{\mu}_{g3n0}=\hat\beta_0+\hat\beta_{g3}\) –> \(\log_2 \widehat{FC}_{g3n0-g1n0}=\hat\beta_{g3}\)

  • \(\log_2 \hat{\mu}_{g1n1}=\hat\beta_0+\hat\beta_{n1}\), \(\log_2 \hat {\mu}_{g3n1}=\hat\beta_0+\hat\beta_{g3}+\hat\beta_{n1}+\hat\beta_{g3n1}\) –> \(\log_2 \widehat{FC}_{g3n1-g1n1}=\hat \beta_{g3} +\hat\beta_{g3n1}\)

  • Similarly, \(\log_2 \widehat{FC}_{g1n1-g1n0}=\hat\beta_{n1}\), \(\log_2 \widehat{FC}_{g3n1-g3n0}=\hat\beta_{n1}+\hat\beta_{g3n1}\)

  • \(\log_2\frac{\widehat{FC}_{g3n1-g1n1}}{\widehat{FC}_{g3n0-g1n0}}=\log_2\frac{\widehat{FC}_{g3n1-g3n0}}{\widehat{FC}_{g1n1-g1n0}}=\hat\beta_{g3n1}\)

with \(\log_2\hat{\mu}_{g1n0}\), \(\log_2\hat{\mu}_{g3n0}\), \(\log_2\hat {\mu}_{g1n1}\) and \(\log_2\hat{\mu}_{g3n1}\) the estimated mean \(\log_2\) transformed intensity for patients with grade 1 and node 0 status, grade 3 and node 0 status, grade 1 and node 1 status and grade 3 and node 1 status, respectively. With \(\log_2 \widehat{FC}_{b-a}\) we indicate \(\log_2\) transformed fold change estimates between treatment b and treatment a, i.e. \(\log_2 \widehat{FC}_{b-a}=\log_2 \hat{\mu}_{b}-\log_2 \hat{\mu}_a=\log_2 \frac{\hat{\mu}_{b}}{\hat{\mu}_{a}}\).

The model immediately provides statistical tests for assessing the significance of fold changes between grade 3 and grade 1 for patients with unaffected lymph nodes (n=0) \(\log_2 {FC}_{g3n0-g1n0}\), fold changes between the grade 1-node 1 patients and grade 1- node 0 patients \(\log_2 {FC}_{g1n1-g3n0}\) and for differences in fold change related to histological grade for node 1 patients and node 0 patients. \(\log_2\frac{{FC}_{g3n1-g1n1}}{{FC}_{g3n0-g1n0}}\), the interaction term.

Interpretation of the model parameters in the model output:

  • The geometric mean intensity for grade 1 patients with unaffected lymph nodes equals \(\exp(\hat \beta_0)\)= 178.48.
    • When lymph nodes are unaffected, the expression is on average 3.18 times higher for patients with histological grade 3 than patients with histological grade 1.
    • The gene expression in histological grade 1 patients with affected lymph nodes is on average 1.58 times higher than for grade 1 patients with unaffected lymph nodes.
  • The fold change corresponding to histological grade is on average 1.71 times lower in patients with affected lymph nodes as compared to patients with unaffected lymph node.

For the remaining hypothesis of interest we will have to define contrasts: linear combinations of the model parameters and evaluate the contrasts with the multcomp package.

The F-test showed an extremely significant association of the node status, hystological grade and/or the interaction between the node status and the grade (p<<0.001).

4 Assessing the significance of all hypothesis of interest

We can assess all contrasts of interest using the multcomp package. This will also allow us to correct for multiple testing, since we assess multiple hypotheses to answer the relevant research question.

  • \(H_0: \log_2{FC}_{g3n0-g1n0}= \beta_{g3}=0\) \(\rightarrow\) “grade3 = 0”
  • \(H_0: \log_2{FC}_{g3n1-g1n1}= \beta_{g3} + \hat\beta_{g3n1}=0\) \(\rightarrow\) “grade3+grade3:nodeRemoved = 0”
  • \(H_0: \log_2{FC}_{g1n1-g1n0}= \beta_{n1}\) \(\rightarrow\) “nodeRemoved = 0”
  • \(H_0: \log_2{FC}_{g3n1-g3n0}= \beta_{n1} + \hat\beta_{g3n1}=0\) \(\rightarrow\) “nodeRemoved+grade3:nodeRemoved = 0”
  • \(H_0: \log_2{FC}_{g3n1-g1n1} - \log_2{FC}_{g3n0-g1n0} = \hat\beta_{g3n1}=0\), note that the latter hypothesis is also equivalent to \(H_0: \log_2{FC}_{g3n1-g3n0} - \log_2{FC}_{g1n1-g1n0} = \hat\beta_{g3n1}=0\) \(\rightarrow\) “grade3:nodeRemoved = 0”
## glht() function from the multcomp package
fitGlht <- glht(fit,
  linfct = c(
    "grade3 = 0",
    "grade3+grade3:nodeRemoved = 0",
    "nodeRemoved = 0",
    "nodeRemoved+grade3:nodeRemoved = 0",
    "grade3:nodeRemoved = 0"
  )
)

summary(fitGlht)

     Simultaneous Tests for General Linear Hypotheses

Fit: lm(formula = log2(gene) ~ grade * node, data = kpna2)

Linear Hypotheses:
                                      Estimate Std. Error t value
grade3 == 0                             1.6675     0.1827   9.127
grade3 + grade3:nodeRemoved == 0        0.8928     0.1827   4.886
nodeRemoved == 0                        0.6577     0.1827   3.600
nodeRemoved + grade3:nodeRemoved == 0  -0.1170     0.1827  -0.640
grade3:nodeRemoved == 0                -0.7748     0.2584  -2.998
                                      Pr(>|t|)    
grade3 == 0                            < 0.001 ***
grade3 + grade3:nodeRemoved == 0       < 0.001 ***
nodeRemoved == 0                       0.00734 ** 
nodeRemoved + grade3:nodeRemoved == 0  0.89816    
grade3:nodeRemoved == 0                0.02653 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Adjusted p values reported -- single-step method)
confint(fitGlht)

     Simultaneous Confidence Intervals

Fit: lm(formula = log2(gene) ~ grade * node, data = kpna2)

Quantile = 2.6964
95% family-wise confidence level
 

Linear Hypotheses:
                                      Estimate lwr      upr     
grade3 == 0                            1.66754  1.17488  2.16020
grade3 + grade3:nodeRemoved == 0       0.89279  0.40013  1.38545
nodeRemoved == 0                       0.65773  0.16507  1.15039
nodeRemoved + grade3:nodeRemoved == 0 -0.11702 -0.60968  0.37564
grade3:nodeRemoved == 0               -0.77475 -1.47148 -0.07802
2^confint(fitGlht)$confint
                                  Estimate       lwr       upr
grade3                           3.1767209 2.2572643 4.4707019
grade3 + grade3:nodeRemoved      1.8567602 1.3193474 2.6130786
nodeRemoved                      1.5775997 1.1209860 2.2202070
nodeRemoved + grade3:nodeRemoved 0.9220906 0.6552046 1.2976879
grade3:nodeRemoved               0.5844896 0.3605058 0.9476355
attr(,"conf.level")
[1] 0.95
attr(,"calpha")
[1] 2.698031

5 Conclusion

  • There is an extremely significant association between the KPNA2 expression and hystological grade in patients with unaffected as well as in patients with affected lymph nodes (both \(p<<0.001\)). When lymph nodes are unaffected, the expression is on average 3.18 times higher for patients with histological grade 3 than patients with histological grade 1 (95% CI [2.26, 4.47]). For patients with affected lymph nodes the expression is on average 1.86 times higher for patients with histological grade 3 tumors than patients with histological grade 1 tumors (95% CI [1.32, 2.61]).

  • The association between the KPNA2 expression with the lymph node status in grade 1 patients is very significant (\(p=\) 0.007). The KPNA2 expression in histological grade 1 patients with affected lymph nodes is on average 1.58 times higher than for grade 1 patients with unaffected lymph nodes (95% CI [1.12, 2.22]). In grade 3 patients, however, this association is not significant (\(p=\) 0.9, 95% CI [0.66, 1.3] ).

  • There is also a significant interaction between the hystological grade and the lymph node status. So the association between the KPNA2 expression and the histological grade depends on the lymph node status and vice versa (\(p=\) 0.027). The fold change corresponding to histological grade is on average 1.71 times lower in patients with affected lymph nodes as compared to patients with unaffected lymph node (95% CI [1.06, 2.77]). (Similarly, the fold change corresponding to the node status is on average 1.71 times lower in patients with grade 3 tumors as compared to patients with grade 1 tumors, 95% CI [1.06, 2.77])

LS0tCnRpdGxlOiAiOC40LiBNdWx0aXBsZSBSZWdyZXNzaW9uOiBLUE5BMiBleGFtcGxlIC0gc29sdXRpb24iCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IGFuZCBNaWxhbiBNYWxmYWl0IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgotLS0KCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIGNhY2hlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gVFJVRQopCmBgYAoKIyBCYWNrZ3JvdW5kCgpIaXN0b2xvZ2ljIGdyYWRlIGluIGJyZWFzdCBjYW5jZXIgKEJDKSBwcm92aWRlcyBjbGluaWNhbGx5IGltcG9ydGFudCBwcm9nbm9zdGljCmluZm9ybWF0aW9uLiBSZXNlYXJjaGVycyBleGFtaW5lZCB3aGV0aGVyIGhpc3RvbG9naWMgZ3JhZGUgd2FzIGFzc29jaWF0ZWQgd2l0aApnZW5lIGV4cHJlc3Npb24gcHJvZmlsZXMgb2YgYnJlYXN0IGNhbmNlcnMgYW5kIHdoZXRoZXIgc3VjaCBwcm9maWxlcyBjb3VsZCBiZQp1c2VkIHRvIGltcHJvdmUgaGlzdG9sb2dpYyBncmFkaW5nLiBJbiB0aGlzIHR1dG9yaWFsIHdlIHdpbGwgYXNzZXNzIHRoZQphc3NvY2lhdGlvbiBiZXR3ZWVuIGhpc3RvbG9naWMgZ3JhZGUgYW5kIHRoZSBleHByZXNzaW9uIG9mIHRoZSBLUE5BMiBnZW5lIHRoYXQKaXMga25vd24gdG8gYmUgYXNzb2NpYXRlZCB3aXRoIHBvb3IgQkMgcHJvZ25vc2lzLiBUaGUgcGF0aWVudHMsIGhvd2V2ZXIsIGRvIG5vdApvbmx5IGRpZmZlciBpbiB0aGUgaGlzdG9sb2dpYyBncmFkZSwgYnV0IGFsc28gb24gdGhlaXIgbHltcGggbm9kZSBzdGF0dXMuCgpUaGUgbHltcGggbm9kZXMgd2VyZSBub3QgYWZmZWN0ZWQgKDApIG9yIHN1cmdpY2FsbHkgcmVtb3ZlZCAoMSkuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShjYXIpCmxpYnJhcnkobXVsdGNvbXApCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKCiMjIFNldCBkZWZhdWx0IHRoZW1lIGZvciBnZ3Bsb3QyCnRoZW1lX3NldCh0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkpCmBgYAoKIyBEYXRhIGFuYWx5c2lzCgojIyBJbXBvcnQgS1BOQTIgZGF0YSBpbiBSCgpgYGB7cn0Ka3BuYTIgPC0gcmVhZF90YWJsZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9TR0EyMS9tYXN0ZXIvZGF0YS9rcG5hMi50eHQiKQprcG5hMgpgYGAKCiMjIFRyYW5zZm9ybSB0aGUgdmFyaWFibGUgZ3JhZGUgYW5kIG5vZGUgdG8gYSBmYWN0b3IKYGBge3J9CmtwbmEyIDwtIGtwbmEyICU+JQogIG11dGF0ZSgKICAgIGdyYWRlID0gYXMuZmFjdG9yKGdyYWRlKSwKICAgIG5vZGUgPSBhcy5mYWN0b3Iobm9kZSksCiAgICBub2RlID0gZmN0X3JlY29kZShub2RlLCBVbmFmZmVjdGVkID0gIjAiLCBSZW1vdmVkID0gIjEiKQogICkKa3BuYTIKYGBgCgojIyBEYXRhIGV4cGxvcmF0aW9uCgpIaXN0b2xvZ2ljIGdyYWRlIGFuZCBseW1waCBub2RlIHN0YXR1cyBjYW4gYmUgYXNzb2NpYXRlZCB3aXRoIHRoZSBrcG5hMiBnZW5lIGV4cHJlc3Npb24uIE1vcmVvdmVyLCBpdCBpcyBhbHNvIHBvc3NpYmxlIHRoYXQgdGhlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFzc29jaWF0ZWQgd2l0aCBoaXN0b2xvZ2ljYWwgZ3JhZGUgaXMgZGlmZmVyZW50IGluIHBhdGllbnRzIHRoYXQgaGF2ZSB1bmFmZmVjdGVkIGx5bXBoIG5vZGVzIGFuZCBwYXRpZW50cyBmb3Igd2hpY2ggdGhlIGx5bXBoIG5vZGVzIGhhZCB0byBiZSByZW1vdmVkLgoKYGBge3J9CmdncGxvdChrcG5hMiwgYWVzKHggPSBncmFkZSwgeSA9IGdlbmUsIGZpbGwgPSBub2RlKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoKSwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIpICsKICBsYWJzKAogICAgeCA9ICJIaXN0b2xvZ2ljIGdyYWRlIiwgeSA9ICJLUE5BMiBleHByZXNzaW9uIiwKICAgIGZpbGwgPSAiTHltcGggbm9kZSBzdGF0dXMiCiAgKSArCiAgZ2d0aXRsZSgiS1BOQTIgZ2VuZSBleHByZXNzaW9uIGluIGJyZWFzdCBjYW5jZXIgcGF0aWVudHMiKQpgYGAKClRoZSBwbG90IHN1Z2dlc3RzCgotIEFuIGVmZmVjdCBvZiB0aGUgaGlzdG9sb2dpY2FsIGdyYWRlCi0gQW4gZWZmZWN0IG9mIG5vZGUgc3RhdHVzCi0gVGhlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFzc29jaWF0ZWQgdG8gZ3JhZGUgc2VlbXMgdG8gZGlmZmVyIGFjY29yZGluZyB0byB0aGUgbHltcGggbm9kZSBzdGF0dXMgKGludGVyYWN0aW9uKQotIE1lYW4gdmFyaWFuY2UgcmVsYXRpb24/CgojIyBNb2RlbAoKSGlzdG9sb2dpYyBncmFkZSBhbmQgbHltcGggbm9kZSBzdGF0dXMgY2FuIGJlIGFzc29jaWF0ZWQgd2l0aCB0aGUga3BuYTIgZ2VuZSBleHByZXNzaW9uLiBNb3Jlb3ZlciwgaXQgaXMgYWxzbyBwb3NzaWJsZSB0aGF0IHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhc3NvY2lhdGVkIHdpdGggaGlzdG9sb2dpY2FsIGdyYWRlIGlzIGRpZmZlcmVudCBpbiBwYXRpZW50cyB0aGF0IGhhdmUgdW5hZmZlY3RlZCBseW1waCBub2RlcyBhbmQgcGF0aWVudHMgZm9yIHdoaWNoIHRoZSBseW1waCBub2RlcyBoYWQgdG8gYmUgcmVtb3ZlZC4gSGVuY2UsIHdlIHdpbGwgaGF2ZSB0byBtb2RlbCB0aGUgZ2VuZSBleHByZXNzaW9uIGJ5IHVzaW5nIG1haW4gZWZmZWN0cyBmb3IgZ3JhZGUsIG5vZGUgYW5kIGEgZ3JhZGUgeCBub2RlIGludGVyYWN0aW9uLgoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmFzcD0xfQojIE1vZGVsIHdpdGggbWFpbiBlZmZlY3RzIGZvciBoaXN0b2xvZ2ljYWwgZ3JhZGUgYW5kIG5vZGUgYW5kIGdyYWRlIHggbm9kZSBpbnRlcmFjdGlvbgpmaXQgPC0gbG0oZ2VuZSB+IGdyYWRlICogbm9kZSwgZGF0YSA9IGtwbmEyKQoKcGFyKG1mcm93ID0gYygyLCAyKSkKcGxvdChmaXQpCmBgYAoKVGhlIHZhcmlhbmNlIHNlZW1zIHRvIGluY3JlYXNlIHdpdGggdGhlIG1lYW4sIGkuZS4gdGhlIHJlc2lkdWFscyBkbyBub3Qgc2VlbSB0bwpiZSAqKmhvbW9zY2VkYXN0aWMqKi4gIFRoZSBRUS1wbG90IG9mIHRoZSByZXNpZHVhbHMgc2hvd3MgZGV2aWF0aW9ucyBmcm9tCm5vcm1hbGl0eSBvciBzb21lIG91dGxpZXJzLgoKV2Ugd2lsbCBmaXJzdCBsb2cyIHRyYW5zZm9ybSB0aGUgZGF0YS4KCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5hc3A9MX0KZml0IDwtIGxtKGxvZzIoZ2VuZSkgfiBncmFkZSAqIG5vZGUsIGRhdGEgPSBrcG5hMikKCnBhcihtZnJvdyA9IGMoMiwgMikpCnBsb3QoZml0KQpgYGAKCi0gVGhlIHZhcmlhbmNlIGlzIG5vdyBtb3JlIG9yIGxlc3MgZXF1YWwgZm9yIGV2ZXJ5IHRyZWF0bWVudCB4IG5vZGUgY29tYmluYXRpb24uCi0gVGhlIFFRLXBsb3Qgb2YgdGhlIHJlc2lkdWFscyBzaG93cyBubyBkZXZpYXRpb25zIGZyb20gbm9ybWFsaXR5LgoKCiMjIEluZmVyZW5jZQoKV2UgcGVyZm9ybSBhICoqdHlwZSBJSUkgQU5PVkEqKiB0byB0ZXN0IHRoZSBpbnRlcmFjdGlvbiBlZmZlY3QuIE5vdGUgdGhhdCB3ZSB1c2UKdGhlIGBBbm92YSgpYCBmdW5jdGlvbiAod2l0aCBjYXBpdGFsIEEpIGZyb20gdGhlICoqY2FyKiogcGFja2FnZSBoZXJlLiBUaGlzCmZ1bmN0aW9uIGFsbG93cyB0byB0ZXN0IHR5cGUtSUkgYW5kIHR5cGUtSUlJIHRlc3RzLiBUaGUgZGVmYXVsdCBgYW5vdmEoKWAgZnJvbQpiYXNlIFIgb25seSBwZXJmb3JtcyB0eXBlLUkgdGVzdHMuCgpgYGB7cn0KIyMgQW5vdmEgZnJvbSBjYXIgcGFja2FnZSwgbWFrZSBzdXJlIGl0J3MgbG9hZGVkIHdpdGggYGxpYnJhcnkoY2FyKWAKYW5vdmFfcmVzIDwtIEFub3ZhKGZpdCwgdHlwZSA9ICJJSUkiKQphbm92YV9yZXMKYGBgCgpUaGUgb3V0cHV0IHNob3dzIHRoYXQgdGhlcmUgaXMgYSB2ZXJ5IHNpZ25pZmljYW50IGludGVyYWN0aW9uCigkcD0kIGByIGZvcm1hdChhbm92YV9yZXNbImdyYWRlOm5vZGUiLDRdLCBkaWdpdHM9MilgKS4KSGVuY2UsIHRoZSBhc3NvY2lhdGlvbiBvZiB0aGUgaGlzdG9sb2dpY2FsIGdyYWRlIG9uIHRoZSBnZW5lIGV4cHJlc3Npb24gZGlmZmVycwphY2NvcmRpbmcgdG8gdGhlIGx5bXBoIG5vZGUgc3RhdHVzIGFuZCB2aWNlIHZlcnNhLgoKVGhlIHJlc2VhcmNoZXJzIGFyZSB0aGVyZWZvcmUgaW50ZXJlc3RlZCBpbiBzdHVkeWluZyBhbmQgcmVwb3J0aW5nIG9uIHRoZSBmb2xsb3dpbmcgaHlwb3RoZXNlczoKCi0gSXMgdGhlIEtQTkEyIGV4cHJlc3Npb24gb24gYXZlcmFnZSBkaWZmZXJlbnQgYmV0d2VlbiBncmFkZSAzIGFuZCBncmFkZSAxIHR1bW9ycyBmcm9tIHBhdGllbnRzIHdpdGggdW5hZmZlY3RlZCBseW1waCBub2RlcyAoYnkgdGVzdGluZyAkSF8wOiBcbG9nXzJ7RkN9X3tnM24wLWcxbjB9PTBcdGV4dHsgdnMgfUgxOiBcbG9nXzJ7RkN9X3tnM24wLWcxbjB9XG5lcSAwJCkKLSBJcyB0aGUgS1BOQTIgZXhwcmVzc2lvbiBvbiBhdmVyYWdlIGRpZmZlcmVudCBiZXR3ZWVuIGdyYWRlIDMgYW5kIGdyYWRlIDEgdHVtb3JzIGZyb20gcGF0aWVudHMgd2l0aCBhZmZlY3RlZCBseW1waCBub2RlcyAoYnkgdGVzdGluZyAkSF8wOiBcbG9nXzJ7RkN9X3tnM24xLWcxbjF9PTBcdGV4dHsgdnMgfUgxOiBcbG9nXzJ7RkN9X3tnM24xLWcxbjF9XG5lcSAwJCkKCi0gSXMgdGhlIEtQTkEyIGV4cHJlc3Npb24gb24gYXZlcmFnZSBkaWZmZXJlbnQgaW4gZ3JhZGUgMSB0dW1vcnMgb2YgcGF0aWVudHMgd2l0aCBhZmZlY3RlZCBhbmQgcGF0aWVudHMgd2l0aCB1bmFmZmVjdGVkIGx5bXBoIG5vZGVzIChieSB0ZXN0aW5nICRIXzA6IFxsb2dfMntGQ31fe2cxbjEtZzFuMH09MFx0ZXh0eyB2cyB9SDE6IFxsb2dfMntGQ31fe2cxbjEtZzFuMH1cbmVxIDAkKQoKLSBJcyB0aGUgS1BOQTIgZXhwcmVzc2lvbiBvbiBhdmVyYWdlIGRpZmZlcmVudCBpbiBncmFkZSAzIHR1bW9ycyBvZiBwYXRpZW50cyB3aXRoIGFmZmVjdGVkIGFuZCBwYXRpZW50cyB3aXRoIHVuYWZmZWN0ZWQgbHltcGggbm9kZXMgKGJ5IHRlc3RpbmcgJEhfMDogXGxvZ18ye0ZDfV97ZzNuMS1nM24wfT0wXHRleHR7IHZzIH1IMTogXGxvZ18ye0ZDfV97ZzNuMS1nM24wfVxuZXEgMCQpCgotIElzIHRoZSBmb2xkIGNoYW5nZSBvZiB0aGUgS1BOQTIgZ2VuZSBiZXR3ZWVuIGdyYWRlIDMgYW5kIGdyYWRlIDEgZGlmZmVyZW50IGFjY29yZGluZyB0byB0aGUgbHltcGggbm9kZSBzdGF0dXMgYW5kIHZpY2UgdmVyc2EgKHRlc3RlZCBhbHJlYWR5IGJ5IGFzc2Vzc2luZyB0aGUgaW50ZXJhY3Rpb246ICRIXzA6IFxsb2dfMntGQ31fe2czbjAtZzFuMH09XGxvZ18ye0ZDfV97ZzNuMS1nMW4xfSBcdGV4dHsgdnMgfUgxOlxsb2dfMntGQ31fe2czbjAtZzFuMH1cbmVxXGxvZ18ye0ZDfV97ZzNuMS1nMW4xfSQpLgoKCiMgSW50ZXJwcmV0YXRpb24gb2YgbW9kZWwgcGFyYW1ldGVycyBhbmQgc3RhdGlzdGljYWwgdGVzdHMKCmBgYHtyfQpFeHBsb3JlTW9kZWxNYXRyaXg6OlZpc3VhbGl6ZURlc2lnbihrcG5hMiwgfiBncmFkZSAqIG5vZGUpJHBsb3RsaXN0W1sxXV0KYGBgCgpgYGB7cn0Kc3VtbWFyeShmaXQpCgojIENhbGN1bGF0ZSBjb25maWRlbmNlIGludGVydmFscyBmb3IgcGFyYW1ldGVycyBvZiBtb2RlbApDSWZpdCA8LSBjb25maW50KGZpdCkKCiMgbG9nXzIgRkMgYmV0d2VlbiBnM24wLWcxbjAsIGcxbjEtZzFuMAojIGFuZCBsb2dfMiBkaWZmZXJlbmNlIGluIEZDIGczbjEtZzFuMSBhbmQgRkMgZzNuMC1nMW4wCkNJZml0CgojIFRyYW5zZm9ybSBwYXJhbWV0ZXJzIGFuZCB0aGUgQ0kgYmFjayB0byB0aGUgb3JpZ2luYWwgc2NhbGUKMl5jb2VmKGZpdCkKMl5DSWZpdApgYGAKCldlIG1vZGVsIHRoZSBsb2ckXzIkLXRyYW5zZm9ybWVkIGludGVuc2l0aWVzIHdpdGggdGhlIGZvbGxvd2luZyBtb2RlbDoKJCQKeT1cYmV0YV8wK1xiZXRhX3tnM314X3tnM30rXGJldGFfe24xfXhfe24xfStcYmV0YV97ZzNuMX14X3tnM314X3tuMX0sCiQkCgp3aXRoICRcYmV0YV8wJCB0aGUgaW50ZXJjZXB0LCAkXGJldGFfe2czfSQgdGhlIG1haW4gZWZmZWN0IGZvciBncmFkZSwgJHhfe2czfSQgYSBkdW1teSB2YXJpYWJsZSBmb3IgZ3JhZGUgd2hpY2ggaXMgMCBmb3IgdGhlIGNvbnRyb2wgdHJlYXRtZW50IGluIHRoZSBhYnNlbmNlIG9mIGdyYWRlIGFuZCAxIGZvciB0aGUgdHJlYXRtZW50IHdpdGggZ3JhZGUsICRcYmV0YV97bjF9JCB0aGUgbWFpbiBlZmZlY3QgZm9yIG5vZGUsICR4X3tuMX0kIGEgZHVtbXkgdmFyaWFibGUgdGhhdCBpcyAwIGZvciB0aGUgbWVhc3VyZW1lbnRzIG9mIHBhdGllbnRzIHdpdGggdW5hZmZlY3RlZCBseW1waCBub2RlcyBhbmQgMSBmb3IgcGF0aWVudHMgZm9yIHdoaWNoIHRoZSBseW1waCBub2RlcyB3ZXJlIHJlbW92ZWQgYW5kICRcYmV0YV97ZzNuMX0kIHRoZSBpbnRlcmFjdGlvbiBlZmZlY3QgYmV0d2VlbiBncmFkZSBhbmQgbm9kZS4KVG8gZWFzZSB0aGUgaW50ZXJwcmV0YXRpb24gb2YgdGhlIHBhcmFtZXRlcnMsICRcbG9nXzIkIHRyYW5zZm9ybWVkIGdlb21ldHJpYyBtZWFuIGludGVuc2l0aWVzIGFyZSBnaXZlbiBmb3IgZWFjaCB0cmVhdG1lbnQgZ3JvdXAgYXMgd2VsbCBhcyBjb3JyZXNwb25kaW5nIGNvbnRyYXN0cyBiZXR3ZWVuIHRyZWF0bWVudHMsIHdoaWNoIGhhdmUgYW4gaW50ZXJwcmV0YXRpb24gaW4gdGVybXMgb2YgJFxsb2dfMiQgdHJhbnNmb3JtZWQgZm9sZCBjaGFuZ2VzIChGQykuCgotICRcbG9nXzJcaGF0e1xtdX1fe2cxbjB9PVxoYXRcYmV0YV8wJCwgJFxsb2dfMiBcaGF0e1xtdX1fe2czbjB9PVxoYXRcYmV0YV8wK1xoYXRcYmV0YV97ZzN9JCAtLT4gJFxsb2dfMiBcd2lkZWhhdHtGQ31fe2czbjAtZzFuMH09XGhhdFxiZXRhX3tnM30kCgotICRcbG9nXzIgXGhhdHtcbXV9X3tnMW4xfT1caGF0XGJldGFfMCtcaGF0XGJldGFfe24xfSQsICRcbG9nXzIgXGhhdCB7XG11fV97ZzNuMX09XGhhdFxiZXRhXzArXGhhdFxiZXRhX3tnM30rXGhhdFxiZXRhX3tuMX0rXGhhdFxiZXRhX3tnM24xfSQgLS0+ICRcbG9nXzIgXHdpZGVoYXR7RkN9X3tnM24xLWcxbjF9PVxoYXQgXGJldGFfe2czfSArXGhhdFxiZXRhX3tnM24xfSQKCi0gU2ltaWxhcmx5LCAkXGxvZ18yIFx3aWRlaGF0e0ZDfV97ZzFuMS1nMW4wfT1caGF0XGJldGFfe24xfSQsICRcbG9nXzIgXHdpZGVoYXR7RkN9X3tnM24xLWczbjB9PVxoYXRcYmV0YV97bjF9K1xoYXRcYmV0YV97ZzNuMX0kCgotICRcbG9nXzJcZnJhY3tcd2lkZWhhdHtGQ31fe2czbjEtZzFuMX19e1x3aWRlaGF0e0ZDfV97ZzNuMC1nMW4wfX09XGxvZ18yXGZyYWN7XHdpZGVoYXR7RkN9X3tnM24xLWczbjB9fXtcd2lkZWhhdHtGQ31fe2cxbjEtZzFuMH19PVxoYXRcYmV0YV97ZzNuMX0kCgp3aXRoICRcbG9nXzJcaGF0e1xtdX1fe2cxbjB9JCwgJFxsb2dfMlxoYXR7XG11fV97ZzNuMH0kLCAkXGxvZ18yXGhhdCB7XG11fV97ZzFuMX0kIGFuZCAkXGxvZ18yXGhhdHtcbXV9X3tnM24xfSQgdGhlIGVzdGltYXRlZCBtZWFuICRcbG9nXzIkIHRyYW5zZm9ybWVkIGludGVuc2l0eSBmb3IgcGF0aWVudHMgd2l0aCBncmFkZSAxIGFuZCBub2RlIDAgc3RhdHVzLCBncmFkZSAzIGFuZCBub2RlIDAgc3RhdHVzLCBncmFkZSAxIGFuZCBub2RlIDEgc3RhdHVzIGFuZCBncmFkZSAzIGFuZCBub2RlIDEgc3RhdHVzLCByZXNwZWN0aXZlbHkuIFdpdGggJFxsb2dfMiBcd2lkZWhhdHtGQ31fe2ItYX0kIHdlIGluZGljYXRlICRcbG9nXzIkIHRyYW5zZm9ybWVkIGZvbGQgY2hhbmdlIGVzdGltYXRlcyBiZXR3ZWVuIHRyZWF0bWVudCBiIGFuZCB0cmVhdG1lbnQgYSwgaS5lLiAkXGxvZ18yIFx3aWRlaGF0e0ZDfV97Yi1hfT1cbG9nXzIgXGhhdHtcbXV9X3tifS1cbG9nXzIgXGhhdHtcbXV9X2E9XGxvZ18yIFxmcmFje1xoYXR7XG11fV97Yn19e1xoYXR7XG11fV97YX19JC4KClRoZSBtb2RlbCBpbW1lZGlhdGVseSBwcm92aWRlcyBzdGF0aXN0aWNhbCB0ZXN0cyBmb3IgYXNzZXNzaW5nIHRoZSBzaWduaWZpY2FuY2Ugb2YgZm9sZCBjaGFuZ2VzIGJldHdlZW4gZ3JhZGUgMyBhbmQgZ3JhZGUgMSBmb3IgcGF0aWVudHMgd2l0aCB1bmFmZmVjdGVkIGx5bXBoIG5vZGVzIChuPTApICRcbG9nXzIge0ZDfV97ZzNuMC1nMW4wfSQsICBmb2xkIGNoYW5nZXMgYmV0d2VlbiB0aGUgZ3JhZGUgMS1ub2RlIDEgcGF0aWVudHMgYW5kIGdyYWRlIDEtIG5vZGUgMCBwYXRpZW50cyAkXGxvZ18yIHtGQ31fe2cxbjEtZzNuMH0kIGFuZCBmb3IgZGlmZmVyZW5jZXMgaW4gZm9sZCBjaGFuZ2UgcmVsYXRlZCB0byBoaXN0b2xvZ2ljYWwgZ3JhZGUgZm9yIG5vZGUgMSBwYXRpZW50cyBhbmQgbm9kZSAwIHBhdGllbnRzLiAkXGxvZ18yXGZyYWN7e0ZDfV97ZzNuMS1nMW4xfX17e0ZDfV97ZzNuMC1nMW4wfX0kLCB0aGUgaW50ZXJhY3Rpb24gdGVybS4KCkludGVycHJldGF0aW9uIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGluIHRoZSBtb2RlbCBvdXRwdXQ6CgotIFRoZSBnZW9tZXRyaWMgbWVhbiBpbnRlbnNpdHkgZm9yIGdyYWRlIDEgcGF0aWVudHMgd2l0aCB1bmFmZmVjdGVkIGx5bXBoIG5vZGVzIGVxdWFscyAkXGV4cChcaGF0IFxiZXRhXzApJD0KYHIgcm91bmQoMl5jb2VmKGZpdClbIihJbnRlcmNlcHQpIl0sMilgLgoJLSBXaGVuIGx5bXBoIG5vZGVzIGFyZSB1bmFmZmVjdGVkLCB0aGUgZXhwcmVzc2lvbiBpcyBvbiBhdmVyYWdlIGByIHJvdW5kKDJeY29lZihmaXQpWyJncmFkZTMiXSwyKWAgdGltZXMgaGlnaGVyIGZvciBwYXRpZW50cyB3aXRoIGhpc3RvbG9naWNhbCBncmFkZSAzIHRoYW4gcGF0aWVudHMgd2l0aCBoaXN0b2xvZ2ljYWwgZ3JhZGUgMS4KCS0gVGhlIGdlbmUgZXhwcmVzc2lvbiBpbiBoaXN0b2xvZ2ljYWwgZ3JhZGUgMSBwYXRpZW50cyB3aXRoIGFmZmVjdGVkIGx5bXBoIG5vZGVzIGlzIG9uIGF2ZXJhZ2UgYHIgcm91bmQoMl5jb2VmKGZpdClbIm5vZGVSZW1vdmVkIl0sMilgIHRpbWVzIGhpZ2hlciB0aGFuIGZvciBncmFkZSAxIHBhdGllbnRzIHdpdGggdW5hZmZlY3RlZCBseW1waCBub2Rlcy4KLSBUaGUgZm9sZCBjaGFuZ2UgY29ycmVzcG9uZGluZyB0byBoaXN0b2xvZ2ljYWwgZ3JhZGUgaXMgb24gYXZlcmFnZSBgciByb3VuZCgxLzJeY29lZihmaXQpWyJncmFkZTM6bm9kZVJlbW92ZWQiXSwyKWAgdGltZXMgbG93ZXIgaW4gcGF0aWVudHMgd2l0aCBhZmZlY3RlZCBseW1waCBub2RlcyBhcyBjb21wYXJlZCB0byBwYXRpZW50cyB3aXRoIHVuYWZmZWN0ZWQgbHltcGggbm9kZS4KCgpGb3IgdGhlIHJlbWFpbmluZyBoeXBvdGhlc2lzIG9mIGludGVyZXN0IHdlIHdpbGwgaGF2ZSB0byBkZWZpbmUgY29udHJhc3RzOiBsaW5lYXIgY29tYmluYXRpb25zIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGFuZCBldmFsdWF0ZSB0aGUgY29udHJhc3RzIHdpdGggdGhlIG11bHRjb21wIHBhY2thZ2UuCgpUaGUgRi10ZXN0IHNob3dlZCBhbiBleHRyZW1lbHkgc2lnbmlmaWNhbnQgYXNzb2NpYXRpb24gb2YgdGhlIG5vZGUgc3RhdHVzLCBoeXN0b2xvZ2ljYWwgZ3JhZGUgYW5kL29yIHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIHRoZSBub2RlIHN0YXR1cyBhbmQgdGhlIGdyYWRlIChwPDwwLjAwMSkuCgojIEFzc2Vzc2luZyB0aGUgc2lnbmlmaWNhbmNlIG9mIGFsbCBoeXBvdGhlc2lzIG9mIGludGVyZXN0CgpXZSBjYW4gYXNzZXNzIGFsbCBjb250cmFzdHMgb2YgaW50ZXJlc3QgdXNpbmcgdGhlIG11bHRjb21wIHBhY2thZ2UuIFRoaXMgd2lsbCBhbHNvIGFsbG93IHVzIHRvIGNvcnJlY3QgZm9yIG11bHRpcGxlIHRlc3RpbmcsIHNpbmNlIHdlIGFzc2VzcyBtdWx0aXBsZSBoeXBvdGhlc2VzIHRvIGFuc3dlciB0aGUgcmVsZXZhbnQgcmVzZWFyY2ggcXVlc3Rpb24uCgoKLSAkSF8wOiBcbG9nXzJ7RkN9X3tnM24wLWcxbjB9PSBcYmV0YV97ZzN9PTAkICRccmlnaHRhcnJvdyQgImdyYWRlMyA9IDAiCi0gJEhfMDogXGxvZ18ye0ZDfV97ZzNuMS1nMW4xfT0gXGJldGFfe2czfSArIFxoYXRcYmV0YV97ZzNuMX09MCQgJFxyaWdodGFycm93JCAiZ3JhZGUzK2dyYWRlMzpub2RlUmVtb3ZlZCA9IDAiCi0gJEhfMDogXGxvZ18ye0ZDfV97ZzFuMS1nMW4wfT0gXGJldGFfe24xfSQgICRccmlnaHRhcnJvdyQgIm5vZGVSZW1vdmVkID0gMCIKLSAkSF8wOiBcbG9nXzJ7RkN9X3tnM24xLWczbjB9PSBcYmV0YV97bjF9ICsgXGhhdFxiZXRhX3tnM24xfT0wJCAkXHJpZ2h0YXJyb3ckICJub2RlUmVtb3ZlZCtncmFkZTM6bm9kZVJlbW92ZWQgPSAwIgotICRIXzA6IFxsb2dfMntGQ31fe2czbjEtZzFuMX0gLSBcbG9nXzJ7RkN9X3tnM24wLWcxbjB9ID0gXGhhdFxiZXRhX3tnM24xfT0wJCwgbm90ZSB0aGF0IHRoZSBsYXR0ZXIgaHlwb3RoZXNpcyBpcyBhbHNvIGVxdWl2YWxlbnQgdG8gJEhfMDogXGxvZ18ye0ZDfV97ZzNuMS1nM24wfSAtIFxsb2dfMntGQ31fe2cxbjEtZzFuMH0gPSBcaGF0XGJldGFfe2czbjF9PTAkICRccmlnaHRhcnJvdyQgImdyYWRlMzpub2RlUmVtb3ZlZCA9IDAiCgpgYGB7cn0KIyMgZ2xodCgpIGZ1bmN0aW9uIGZyb20gdGhlIG11bHRjb21wIHBhY2thZ2UKZml0R2xodCA8LSBnbGh0KGZpdCwKICBsaW5mY3QgPSBjKAogICAgImdyYWRlMyA9IDAiLAogICAgImdyYWRlMytncmFkZTM6bm9kZVJlbW92ZWQgPSAwIiwKICAgICJub2RlUmVtb3ZlZCA9IDAiLAogICAgIm5vZGVSZW1vdmVkK2dyYWRlMzpub2RlUmVtb3ZlZCA9IDAiLAogICAgImdyYWRlMzpub2RlUmVtb3ZlZCA9IDAiCiAgKQopCgpzdW1tYXJ5KGZpdEdsaHQpCgpjb25maW50KGZpdEdsaHQpCjJeY29uZmludChmaXRHbGh0KSRjb25maW50CmBgYAoKIyBDb25jbHVzaW9uCgotIFRoZXJlIGlzIGFuIGV4dHJlbWVseSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBLUE5BMiBleHByZXNzaW9uIGFuZCBoeXN0b2xvZ2ljYWwgZ3JhZGUgaW4gcGF0aWVudHMgd2l0aCB1bmFmZmVjdGVkIGFzIHdlbGwgYXMgaW4gcGF0aWVudHMgd2l0aCBhZmZlY3RlZCBseW1waCBub2RlcyAoYm90aCAkcDw8MC4wMDEkKS4KICBXaGVuIGx5bXBoIG5vZGVzIGFyZSB1bmFmZmVjdGVkLCB0aGUgZXhwcmVzc2lvbiBpcyBvbiBhdmVyYWdlIGByIHJvdW5kKDJeY29uZmludChmaXRHbGh0KSRjb25maW50WyJncmFkZTMiLDFdLDIpYCB0aW1lcyBoaWdoZXIgZm9yIHBhdGllbnRzIHdpdGggaGlzdG9sb2dpY2FsIGdyYWRlIDMgdGhhbiBwYXRpZW50cyB3aXRoIGhpc3RvbG9naWNhbCBncmFkZSAxICg5NSUgQ0kgW2ByIHJvdW5kKDJeY29uZmludChmaXRHbGh0KSRjb25maW50WyJncmFkZTMiLDI6M10sMilgXSkuCiAgRm9yIHBhdGllbnRzIHdpdGggYWZmZWN0ZWQgbHltcGggbm9kZXMgdGhlIGV4cHJlc3Npb24gaXMgb24gYXZlcmFnZSBgciByb3VuZCgyXmNvbmZpbnQoZml0R2xodCkkY29uZmludFsiZ3JhZGUzICsgZ3JhZGUzOm5vZGVSZW1vdmVkIiwxXSwyKWAgdGltZXMgaGlnaGVyIGZvciBwYXRpZW50cyB3aXRoIGhpc3RvbG9naWNhbCBncmFkZSAzIHR1bW9ycyB0aGFuIHBhdGllbnRzIHdpdGggaGlzdG9sb2dpY2FsIGdyYWRlIDEgdHVtb3JzICg5NSUgQ0kgW2ByIHJvdW5kKDJeY29uZmludChmaXRHbGh0KSRjb25maW50WyJncmFkZTMgKyBncmFkZTM6bm9kZVJlbW92ZWQiLDI6M10sMilgXSkuCgotIFRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBLUE5BMiBleHByZXNzaW9uIHdpdGggdGhlIGx5bXBoIG5vZGUgc3RhdHVzIGluIGdyYWRlIDEgcGF0aWVudHMgaXMgdmVyeSBzaWduaWZpY2FudCAoJHA9JCBgciBmb3JtYXQoc3VtbWFyeShmaXRHbGh0KSR0ZXN0JHB2YWx1ZXNbM10sZGlnaXRzPTIpYCkuClRoZSBLUE5BMiBleHByZXNzaW9uIGluIGhpc3RvbG9naWNhbCBncmFkZSAxIHBhdGllbnRzIHdpdGggYWZmZWN0ZWQgbHltcGggbm9kZXMgaXMgb24gYXZlcmFnZSBgciByb3VuZCgyXmNvbmZpbnQoZml0R2xodCkkY29uZmludFsibm9kZVJlbW92ZWQiLDFdLDIpYCB0aW1lcyBoaWdoZXIgdGhhbiBmb3IgZ3JhZGUgMSBwYXRpZW50cyB3aXRoIHVuYWZmZWN0ZWQgbHltcGggbm9kZXMgKDk1JSBDSSBbYHIgcm91bmQoMl5jb25maW50KGZpdEdsaHQpJGNvbmZpbnRbIm5vZGVSZW1vdmVkIiwyOjNdLDIpYF0pLgpJbiBncmFkZSAzIHBhdGllbnRzLCBob3dldmVyLCB0aGlzIGFzc29jaWF0aW9uIGlzIG5vdCBzaWduaWZpY2FudCAoJHA9JCBgciBmb3JtYXQoc3VtbWFyeShmaXRHbGh0KSR0ZXN0JHB2YWx1ZXNbNF0sZGlnaXRzPTIpYCwgOTUlIENJIFtgciByb3VuZCgyXmNvbmZpbnQoZml0R2xodCkkY29uZmludFsibm9kZVJlbW92ZWQgKyBncmFkZTM6bm9kZVJlbW92ZWQiLDI6M10sMilgXSApLgoKLSBUaGVyZSBpcyBhbHNvIGEgc2lnbmlmaWNhbnQgaW50ZXJhY3Rpb24gYmV0d2VlbiB0aGUgaHlzdG9sb2dpY2FsIGdyYWRlIGFuZCB0aGUgbHltcGggbm9kZSBzdGF0dXMuIFNvIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBLUE5BMiBleHByZXNzaW9uIGFuZCB0aGUgaGlzdG9sb2dpY2FsIGdyYWRlIGRlcGVuZHMgb24gdGhlIGx5bXBoIG5vZGUgc3RhdHVzIGFuZCB2aWNlIHZlcnNhICgkcD0kIGByIGZvcm1hdChzdW1tYXJ5KGZpdEdsaHQpJHRlc3QkcHZhbHVlc1s1XSxkaWdpdHM9MilgKS4gVGhlIGZvbGQgY2hhbmdlIGNvcnJlc3BvbmRpbmcgdG8gaGlzdG9sb2dpY2FsIGdyYWRlIGlzIG9uIGF2ZXJhZ2UgYHIgcm91bmQoMS8yXmNvbmZpbnQoZml0R2xodCkkY29uZmludFsiZ3JhZGUzOm5vZGVSZW1vdmVkIiwxXSwyKWAgdGltZXMgbG93ZXIgaW4gcGF0aWVudHMgd2l0aCBhZmZlY3RlZCBseW1waCBub2RlcyBhcyBjb21wYXJlZCB0byBwYXRpZW50cyB3aXRoIHVuYWZmZWN0ZWQgbHltcGggbm9kZSAoOTUlIENJIFtgciByb3VuZCgxLzJeY29uZmludChmaXRHbGh0KSRjb25maW50WyJncmFkZTM6bm9kZVJlbW92ZWQiLDM6Ml0sMilgXSkuIChTaW1pbGFybHksIHRoZSBmb2xkIGNoYW5nZSBjb3JyZXNwb25kaW5nIHRvIHRoZSBub2RlIHN0YXR1cyBpcyBvbiBhdmVyYWdlIGByIHJvdW5kKDEvMl5jb25maW50KGZpdEdsaHQpJGNvbmZpbnRbImdyYWRlMzpub2RlUmVtb3ZlZCIsMV0sMilgIHRpbWVzIGxvd2VyIGluIHBhdGllbnRzIHdpdGggZ3JhZGUgMyB0dW1vcnMgYXMgY29tcGFyZWQgdG8gcGF0aWVudHMgd2l0aCBncmFkZSAxIHR1bW9ycywgOTUlIENJIFtgciByb3VuZCgxLzJeY29uZmludChmaXRHbGh0KSRjb25maW50WyJncmFkZTM6bm9kZVJlbW92ZWQiLDM6Ml0sMilgXSkK