Work done by Francisco Bischoff and João Almeida.

Using the database osa_simulated_523.csv which includes data from 523 patients who were referred to sleep consultation for risk of obstructive sleep apnea.

a) Present a descriptive analysis of the dataset.

all variables are categorical and have the frequency shown in the graph.

cats <- inspect_cat(data)
cats.ix <- sort(sort(cats$common_pcnt, index.return = TRUE, decreasing = T)$ix, index.return = TRUE)$ix
lab <- names(cats$levels)
lab <- paste(sprintf("%02d", cats.ix), lab)
names(cats$levels) <- lab
show_plot(cats)

we created a univariate logistic regression in order to assess the significance of each variable on their own and their impact on predicting the outcome

l.coef <- vector()
l.sign <- vector()
for (var in seq(length(data) - 1)) {
  l.model <- glm(OSA ~ ., family = binomial(link = "logit"), data = data[, c(1, var + 1)])
  l.results <- summary(l.model)
  l.coef[var] <- l.results$coefficients[2, 1]
  l.sign[var] <- l.results$coefficients[2, 4]
}
model.list <- data.frame(variables = names(data)[2:39], coefficients = l.coef, significance = l.sign)
model.list$below30pcnt <- ifelse(model.list$significance < 0.3, TRUE, FALSE)
model.list[model.list$significance < 0.3, ]
model.list[order(-abs(model.list$coefficients)), ]

Checking the most significant and impactful variables

cross <- xtabs(~ Race + OSA, data = data, subset = NULL)

ftable(cross)
          OSA False True
Race                    
African         152    7
Caucasian        12  342
summary(cross)
Call: xtabs(formula = ~Race + OSA, data = data, subset = NULL)
Number of cases in table: 513 
Number of factors: 2 
Test for independence of all factors:
    Chisq = 428.9, df = 1, p-value = 2.784e-95
cross <- xtabs(~ Decreased.Libido + OSA, data = data, subset = NULL)

ftable(cross)
                 OSA False True
Decreased.Libido               
False                   62    2
True                   102  350
summary(cross)
Call: xtabs(formula = ~Decreased.Libido + OSA, data = data, subset = NULL)
Number of cases in table: 516 
Number of factors: 2 
Test for independence of all factors:
    Chisq = 142.78, df = 1, p-value = 6.574e-33

b) Identify covariates significantly associated with the outcome “OSA”, presenting the effect of that association (e.g. OR) and the corresponding significance (e.g. p-value or 95%CI).

Using forward and Backward stepwise selection, we look for the best associated variables with the outcome OSA.

For practical purposes, we show here an example of the process with the first 12 variables.

model1 <- glm(OSA ~ ., family = binomial(link = "logit"), data = data[, c(1, 2:13)])
k1 <- blr_step_p_backward(model1, prem = 0.1)
Backward Elimination Method 
---------------------------

Candidate Terms: 

1 . Gender 
2 . Depression 
3 . Headaches 
4 . Decreased.Libido 
5 . Smoking 
6 . Alcohol 
7 . Sedatives 
8 . Humor 
9 . Age.Cat 
10 . MI 
11 . Hypothyroidism 
12 . Coffee 

We are eliminating variables based on p value...

Variables Removed: 

✖ Depression 
✖ Coffee 
✖ MI 
✖ Sedatives 
✖ Alcohol 
✖ Humor 
✖ Smoking 

No more variables satisfy the condition of p value = 0.1


Final Model Output 
------------------

✔ Creating model overview. 
✔ Creating response profile. 
✔ Extracting maximum likelihood estimates. 
✔ Estimating concordant and discordant pairs. 

                             Model Overview                              
------------------------------------------------------------------------
Data Set    Resp Var    Obs.    Df. Model    Df. Residual    Convergence 
------------------------------------------------------------------------
  data        OSA       523        497           490            TRUE     
------------------------------------------------------------------------

                    Response Summary                     
--------------------------------------------------------
Outcome        Frequency        Outcome        Frequency 
--------------------------------------------------------
   0              166              1              355    
--------------------------------------------------------

                       Maximum Likelihood Estimates                        
--------------------------------------------------------------------------
     Parameter          DF    Estimate    Std. Error    z value    Pr(>|z|) 
--------------------------------------------------------------------------
    (Intercept)         1     -6.2506        0.8976    -6.9638      0.0000 
     GenderMale         1      1.1256        0.2954     3.8099       1e-04 
   HeadachesTrue        1      0.6098        0.2851     2.1391      0.0324 
Decreased.LibidoTrue    1      4.4926        0.7689     5.8433      0.0000 
    Age.Cat40-54        1      0.8739        0.4151     2.1054      0.0353 
    Age.Cat55-69        1      2.2918        0.4262     5.3772      0.0000 
    Age.Cat>=70         1      3.2296        0.5417     5.9621      0.0000 
 HypothyroidismTrue     1      0.6460        0.2712     2.3820      0.0172 
--------------------------------------------------------------------------

 Association of Predicted Probabilities and Observed Responses  
---------------------------------------------------------------
% Concordant          0.8494          Somers' D        0.7351   
% Discordant          0.1297          Gamma            0.7197   
% Tied                0.0209          Tau-a            0.3135   
Pairs                 53901           c                0.8599   
---------------------------------------------------------------

So our method was to apply the method exemplified above to the full dataset and variables. Due to problems like glm.fit: algorithm did not converge and glm.fit: fitted probabilities numerically 0 or 1 occurred, we could not use the whole set of variables in one pass, so we used multiple passes, removing variables, until we got a unique model.

After all the calculations were done (calculation time: 28.634999 s) The variables we found highly associated with the OSA outcome are the following:

Forward stepwise : AF, Decreased.Libido, Race
                             Model Overview                              
------------------------------------------------------------------------
Data Set    Resp Var    Obs.    Df. Model    Df. Residual    Convergence 
------------------------------------------------------------------------
  data        OSA       501        500           497            TRUE     
------------------------------------------------------------------------

                    Response Summary                     
--------------------------------------------------------
Outcome        Frequency        Outcome        Frequency 
--------------------------------------------------------
   0              162              1              339    
--------------------------------------------------------

                       Maximum Likelihood Estimates                        
--------------------------------------------------------------------------
     Parameter          DF    Estimate    Std. Error    z value    Pr(>|z|) 
--------------------------------------------------------------------------
    (Intercept)         1     -12.0985       1.6842    -7.1837      0.0000 
Decreased.LibidoTrue    1      8.4038        1.4672     5.7278      0.0000 
   RaceCaucasian        1      9.2286        1.1781     7.8332      0.0000 
       AFTrue           1      3.7382        0.8471     4.4130      0.0000 
--------------------------------------------------------------------------

                         Odds Ratio Estimates                          
----------------------------------------------------------------------
      Effects               Estimate             95% Wald Conf. Limit 
----------------------------------------------------------------------
Decreased.LibidoTrue       4464.0921         385.2467      148734.1006 
   RaceCaucasian           10183.7721        1514.5293     219256.8015 
       AFTrue               42.0217           8.6387          258.5099 
----------------------------------------------------------------------

 Association of Predicted Probabilities and Observed Responses  
---------------------------------------------------------------
% Concordant          0.9888          Somers' D        0.9979   
% Discordant          0.0010          Gamma            0.9877   
% Tied                0.0102          Tau-a            0.4331   
Pairs                 54918           c                0.9939   
---------------------------------------------------------------
Backward stepwise (p-value: remove >0.10): Conc.decrease, Daytime.Sleepiness, Decreased.Libido, GE.Reflux, PHT, Race, VehicleCrashes
                             Model Overview                              
------------------------------------------------------------------------
Data Set    Resp Var    Obs.    Df. Model    Df. Residual    Convergence 
------------------------------------------------------------------------
  data        OSA       485        484           477            TRUE     
------------------------------------------------------------------------

                    Response Summary                     
--------------------------------------------------------
Outcome        Frequency        Outcome        Frequency 
--------------------------------------------------------
   0              157              1              328    
--------------------------------------------------------

                        Maximum Likelihood Estimates                         
----------------------------------------------------------------------------
      Parameter           DF    Estimate    Std. Error    z value    Pr(>|z|) 
----------------------------------------------------------------------------
     (Intercept)          1     -13.4282       3.3932    -3.9574       1e-04 
 Decreased.LibidoTrue     1     10.4685        2.6555     3.9422       1e-04 
    RaceCaucasian         1     12.7373        2.7638     4.6086      0.0000 
Daytime.SleepinessTrue    1     -3.7971        1.9008    -1.9976      0.0458 
    GE.RefluxTrue         1      6.0412        2.0033     3.0156      0.0026 
  Conc.decreaseTrue       1     -6.4543        2.2963    -2.8107      0.0049 
  VehicleCrashesTrue      1      3.4229        1.8814     1.8193      0.0689 
       PHTTrue            1      6.3001        1.9974     3.1542      0.0016 
----------------------------------------------------------------------------

                            Odds Ratio Estimates                              
-----------------------------------------------------------------------------
       Effects                 Estimate                95% Wald Conf. Limit  
-----------------------------------------------------------------------------
 Decreased.LibidoTrue         35188.0840           608.0737      42958071.3815 
    RaceCaucasian             340213.1960         5690.6647      652278401.2327 
Daytime.SleepinessTrue          0.0224              3e-04              0.6876 
    GE.RefluxTrue              420.3814            17.7781         55256.3055 
  Conc.decreaseTrue             0.0016              0.0000             0.0972 
  VehicleCrashesTrue            30.6586             1.1636          2624.1873 
       PHTTrue                 544.6205            13.1280         57070.3793 
-----------------------------------------------------------------------------

 Association of Predicted Probabilities and Observed Responses  
---------------------------------------------------------------
% Concordant          0.9972          Somers' D        0.9957   
% Discordant          0.0022          Gamma            0.9951   
% Tied                6e-04           Tau-a            0.4366   
Pairs                 51496           c                0.9975   
---------------------------------------------------------------

c) Build a multivariable logistic regression model, using any appropriate covariate selection method.

Besides the variables selected by stepwise algorithm, we added the following variables as we find them important due to clinical logic reasoning: Alcohol due to its muscular relaxing properties. So, providing a larger muscular relaxation, it can enhance the effects of the OSA. That said, the final list consisted of:
Race, Decreased.Libido, AF, Daytime.Sleepiness, GE.Reflux, Conc.decrease, VehicleCrashes, PHT, Alcohol

First, we used the blorr package to build a model.

covariates <- unique(c(forward$predictors, backward$predictors, "Alcohol"))
preds <- which(names(data) %in% covariates)
data3 <- data[, c(1, preds)]
data3 <- dplyr::tbl_df(data3[complete.cases(data3), ])

data3_sim <- data_sim[, c(1, preds)]
data3_sim <- dplyr::tbl_df(data3_sim[complete.cases(data3_sim), ])

model <- glm(OSA ~ ., family = binomial(link = "logit"), data = data3)
def_model <- blr_regress(model, odd_conf_limit = TRUE)
✔ Creating model overview. 
✔ Creating response profile. 
✔ Extracting maximum likelihood estimates. 
✔ Computing odds ratio estimates. 
✔ Estimating concordant and discordant pairs. 
def_model
                             Model Overview                              
------------------------------------------------------------------------
Data Set    Resp Var    Obs.    Df. Model    Df. Residual    Convergence 
------------------------------------------------------------------------
  data        OSA       474        473           464            TRUE     
------------------------------------------------------------------------

                    Response Summary                     
--------------------------------------------------------
Outcome        Frequency        Outcome        Frequency 
--------------------------------------------------------
   0              156              1              318    
--------------------------------------------------------

                        Maximum Likelihood Estimates                         
----------------------------------------------------------------------------
      Parameter           DF    Estimate    Std. Error    z value    Pr(>|z|) 
----------------------------------------------------------------------------
     (Intercept)          1     -15.2534       4.3881    -3.4761       5e-04 
 Decreased.LibidoTrue     1      9.8521        2.7616     3.5675       4e-04 
     AlcoholTrue          1      2.1614        1.4782     1.4622      0.1437 
    RaceCaucasian         1     13.3183        3.2672     4.0764      0.0000 
        AFTrue            1      1.7261        2.2544     0.7656      0.4439 
Daytime.SleepinessTrue    1     -2.9885        2.4691    -1.2104      0.2261 
    GE.RefluxTrue         1      5.2490        2.9092     1.8043      0.0712 
  Conc.decreaseTrue       1     -7.0191        2.7020    -2.5977      0.0094 
  VehicleCrashesTrue      1      3.3304        2.0149     1.6529      0.0984 
       PHTTrue            1      6.3048        1.9863     3.1741      0.0015 
----------------------------------------------------------------------------

                            Odds Ratio Estimates                              
-----------------------------------------------------------------------------
       Effects                 Estimate                95% Wald Conf. Limit  
-----------------------------------------------------------------------------
 Decreased.LibidoTrue         18998.5739           318.3644      29733682.4229 
     AlcoholTrue                8.6830              0.6638           348.1881 
    RaceCaucasian             608211.8862         6076.0510      7871669728.7739 
        AFTrue                  5.6185              0.0743          1416.4247 
Daytime.SleepinessTrue          0.0504              3e-04              5.7313 
    GE.RefluxTrue              190.3748             1.6801        561034.0901 
  Conc.decreaseTrue              9e-04              0.0000             0.0835 
  VehicleCrashesTrue            27.9482             0.7739          3166.5777 
       PHTTrue                 547.1886            11.7915         49719.5039 
-----------------------------------------------------------------------------

 Association of Predicted Probabilities and Observed Responses  
---------------------------------------------------------------
% Concordant          0.9993          Somers' D        0.9987   
% Discordant          7e-04           Gamma            0.9986   
% Tied                1e-04           Tau-a            0.4419   
Pairs                 49608           c                0.9993   
---------------------------------------------------------------

Then we used the caret package to build the model as well. The metric aimed for was ROC and evaluation was used leave-one-out and leave-group-out (aka train test)

## LOO
control <- trainControl(method = "LOOCV", classProbs = TRUE, savePredictions = TRUE)
fit.glm <- train(OSA ~ ., data = data3, method = "glm", metric = "ROC", trControl = control)
fit.glm$finalModel

Call:  NULL

Coefficients:
           (Intercept)    Decreased.LibidoTrue             AlcoholTrue           RaceCaucasian                  AFTrue  
               -15.253                   9.852                   2.161                  13.318                   1.726  
Daytime.SleepinessTrue           GE.RefluxTrue       Conc.decreaseTrue      VehicleCrashesTrue                 PHTTrue  
                -2.989                   5.249                  -7.019                   3.330                   6.305  

Degrees of Freedom: 473 Total (i.e. Null);  464 Residual
Null Deviance:      600.6 
Residual Deviance: 22.58    AIC: 42.58
### train test
control2 <- trainControl(method = "LGOCV", classProbs = TRUE, repeats = 3, p = 0.25, savePredictions = TRUE, summaryFunction = twoClassSummary)
fit.glm2 <- train(OSA ~ ., data = data3, method = "glm", metric = "ROC", trControl = control2)
fit.glm2$finalModel

Call:  NULL

Coefficients:
           (Intercept)    Decreased.LibidoTrue             AlcoholTrue           RaceCaucasian                  AFTrue  
               -15.253                   9.852                   2.161                  13.318                   1.726  
Daytime.SleepinessTrue           GE.RefluxTrue       Conc.decreaseTrue      VehicleCrashesTrue                 PHTTrue  
                -2.989                   5.249                  -7.019                   3.330                   6.305  

Degrees of Freedom: 473 Total (i.e. Null);  464 Residual
Null Deviance:      600.6 
Residual Deviance: 22.58    AIC: 42.58

d) Evaluate the derived model, using any appropriate model evaluation strategy, presenting estimates of the generalizability of using the model as diagnostic predictor for new patients.

Then we plotted the roc curves for all models.

# blorr
k <- blr_gains_table(model)
blr_roc_curve(k)

k

# leave one out
predobj <- prediction(predictions = fit.glm$pred$True, labels = fit.glm$pred$obs)
perf <- performance(predobj, measure = "tpr", x.measure = "fpr")
plot(perf)

twoClassSummary(fit.glm$pred, lev = levels(fit.glm$pred$obs))
      ROC      Sens      Spec 
0.9837929 0.9807692 0.9811321 
# train test
predobj2 <- prediction(predictions = fit.glm2$pred$True, labels = fit.glm2$pred$obs)
perf2 <- performance(predobj2, measure = "tpr", x.measure = "fpr")
plot(perf2)

twoClassSummary(fit.glm2$pred, lev = levels(fit.glm2$pred$obs))
      ROC      Sens      Spec 
0.9920217 0.9634188 0.9805042 

e) Comment on how different your approach and final solution would need to be if applied to the larger osa_simulated.csv dataset, discussing on the implications for traditional analysis of having “too large” datasets.

For large datasets, a few things should be handled different. First the evaluation of the significance in large data sets tend to be significance, since it is impacted by row numbers. That said, semi-automatic models like forward and backward stepwise selections can be difficult to apply as is to such datasets. However, there are different metrics and statistic method to overcome this, like AIC and BIC metrics. Furthermore, the metric used for assessing quality - the Leave One Out is not very big data friendly, since it is computational demanding. Nevertheless, there are a few others metrics for assessing model quality and generalization capabilities.

Last but not least, it is in these scenarios that data scientists can be of great importance, taking into account the domain they are working on, adding variables and creating new ones based on their knowledge of the problem trying to be solved.

LS0tCnRpdGxlOiAiQW5hbHl6ZSBBc3NpZ25tZW50IgpvdXRwdXQ6IAogIAogIGh0bWxfbm90ZWJvb2s6IAogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCi0tLQpXb3JrIGRvbmUgYnkgRnJhbmNpc2NvIEJpc2Nob2ZmIGFuZCBKb8OjbyBBbG1laWRhLiAgCgpVc2luZyB0aGUgZGF0YWJhc2Ugb3NhX3NpbXVsYXRlZF81MjMuY3N2IHdoaWNoIGluY2x1ZGVzIGRhdGEgZnJvbSA1MjMgcGF0aWVudHMgd2hvIHdlcmUgcmVmZXJyZWQgdG8gc2xlZXAgY29uc3VsdGF0aW9uIGZvciByaXNrIG9mIG9ic3RydWN0aXZlIHNsZWVwIGFwbmVhLgoKYGBge3IgU2V0dXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cm9wdGlvbnMoY3JheW9uLmVuYWJsZWQgPSBGQUxTRSkKbGlicmFyeShyZWFkcikKbGlicmFyeShibG9ycikKbGlicmFyeShpbnNwZWN0ZGYpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoUk9DUikKCm9zYV9zaW11bGF0ZWRfNTIzIDwtIHJlYWRfY3N2KCJvc2Ffc2ltdWxhdGVkXzUyMy5jc3YiKQpkYXRhIDwtIGxhcHBseShvc2Ffc2ltdWxhdGVkXzUyMywgZnVuY3Rpb24oeCkgewogIHhbeCA9PSAiWWVzIiAmICFpcy5uYSh4KV0gPC0gIlRydWUiCiAgeFt4ID09ICJObyIgJiAhaXMubmEoeCldIDwtICJGYWxzZSIKICB4IDwtIGZhY3Rvcih4KQoKICAjIGlmIChsZW5ndGgobGV2ZWxzKHgpKSA9PSAyICYmIGFsbChsZXZlbHMoeCkgJWluJSBjKCJUcnVlIiwgIkZhbHNlIikpKSB7CiAgIyAgICMgSnVzdCB0cnVlIG9yIGZhbHNlIChvciBOQSkKICAjICAgeCA8LSBhcy5sb2dpY2FsKHgpCiAgIyB9CiAgeAp9KQpkYXRhIDwtIGFzLmRhdGEuZnJhbWUoZGF0YSkKIyBDYXRlZ29yeSBvcmRlciBtYXkgYmUgcmVsZXZhbnQKZGF0YSRBZ2UuQ2F0IDwtIGZhY3Rvcihvc2Ffc2ltdWxhdGVkXzUyMyRBZ2UuQ2F0LCBsZXZlbHMgPSBjKCI8NDAiLCAiNDAtNTQiLCAiNTUtNjkiLCAiPj03MCIpKQoKb3NhX3NpbXVsYXRlZCA8LSByZWFkX2Nzdigib3NhX3NpbXVsYXRlZC5jc3YiKQpkYXRhX3NpbSA8LSBsYXBwbHkob3NhX3NpbXVsYXRlZCwgZnVuY3Rpb24oeCkgewogIHhbeCA9PSAiWWVzIiAmICFpcy5uYSh4KV0gPC0gIlRydWUiCiAgeFt4ID09ICJObyIgJiAhaXMubmEoeCldIDwtICJGYWxzZSIKICB4IDwtIGZhY3Rvcih4KQoKICAjIGlmIChsZW5ndGgobGV2ZWxzKHgpKSA9PSAyICYmIGFsbChsZXZlbHMoeCkgJWluJSBjKCJUcnVlIiwgIkZhbHNlIikpKSB7CiAgIyAgICMgSnVzdCB0cnVlIG9yIGZhbHNlIChvciBOQSkKICAjICAgeCA8LSBhcy5sb2dpY2FsKHgpCiAgIyB9CiAgeAp9KQpkYXRhX3NpbSA8LSBhcy5kYXRhLmZyYW1lKGRhdGFfc2ltKQojIENhdGVnb3J5IG9yZGVyIG1heSBiZSByZWxldmFudApkYXRhX3NpbSRBZ2UuQ2F0IDwtIGZhY3Rvcihvc2Ffc2ltdWxhdGVkJEFnZS5DYXQsIGxldmVscyA9IGMoIjw0MCIsICI0MC01NCIsICI1NS02OSIsICI+PTcwIikpCgppZiAoc3VtKGlzLm5hKG9zYV9zaW11bGF0ZWRfNTIzKSkgIT0gc3VtKGlzLm5hKGRhdGEpKSkgewogIHN0b3AoIk5BIHZhbHVlcyBkbyBub3QgYWdyZWUiKQp9CmBgYAoKKiphKSBQcmVzZW50IGEgZGVzY3JpcHRpdmUgYW5hbHlzaXMgb2YgdGhlIGRhdGFzZXQuKioKCmFsbCB2YXJpYWJsZXMgYXJlIGNhdGVnb3JpY2FsIGFuZCBoYXZlIHRoZSBmcmVxdWVuY3kgc2hvd24gaW4gdGhlIGdyYXBoLgpgYGB7ciBEZXNjcmlwdGl2ZSBBbmFseXNpc30KY2F0cyA8LSBpbnNwZWN0X2NhdChkYXRhKQpjYXRzLml4IDwtIHNvcnQoc29ydChjYXRzJGNvbW1vbl9wY250LCBpbmRleC5yZXR1cm4gPSBUUlVFLCBkZWNyZWFzaW5nID0gVCkkaXgsIGluZGV4LnJldHVybiA9IFRSVUUpJGl4CmxhYiA8LSBuYW1lcyhjYXRzJGxldmVscykKbGFiIDwtIHBhc3RlKHNwcmludGYoIiUwMmQiLCBjYXRzLml4KSwgbGFiKQpuYW1lcyhjYXRzJGxldmVscykgPC0gbGFiCnNob3dfcGxvdChjYXRzKQpgYGAKCndlIGNyZWF0ZWQgYSB1bml2YXJpYXRlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaW4gb3JkZXIgdG8gYXNzZXNzIHRoZSBzaWduaWZpY2FuY2Ugb2YgZWFjaCB2YXJpYWJsZSBvbiB0aGVpciBvd24gYW5kIHRoZWlyIGltcGFjdCBvbiBwcmVkaWN0aW5nIHRoZSBvdXRjb21lCgpgYGB7ciB1bml2YXJpYXRlfQpsLmNvZWYgPC0gdmVjdG9yKCkKbC5zaWduIDwtIHZlY3RvcigpCmZvciAodmFyIGluIHNlcShsZW5ndGgoZGF0YSkgLSAxKSkgewogIGwubW9kZWwgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGFbLCBjKDEsIHZhciArIDEpXSkKICBsLnJlc3VsdHMgPC0gc3VtbWFyeShsLm1vZGVsKQogIGwuY29lZlt2YXJdIDwtIGwucmVzdWx0cyRjb2VmZmljaWVudHNbMiwgMV0KICBsLnNpZ25bdmFyXSA8LSBsLnJlc3VsdHMkY29lZmZpY2llbnRzWzIsIDRdCn0KbW9kZWwubGlzdCA8LSBkYXRhLmZyYW1lKHZhcmlhYmxlcyA9IG5hbWVzKGRhdGEpWzI6MzldLCBjb2VmZmljaWVudHMgPSBsLmNvZWYsIHNpZ25pZmljYW5jZSA9IGwuc2lnbikKbW9kZWwubGlzdCRiZWxvdzMwcGNudCA8LSBpZmVsc2UobW9kZWwubGlzdCRzaWduaWZpY2FuY2UgPCAwLjMsIFRSVUUsIEZBTFNFKQptb2RlbC5saXN0W21vZGVsLmxpc3Qkc2lnbmlmaWNhbmNlIDwgMC4zLCBdCm1vZGVsLmxpc3Rbb3JkZXIoLWFicyhtb2RlbC5saXN0JGNvZWZmaWNpZW50cykpLCBdCmBgYApDaGVja2luZyB0aGUgbW9zdCBzaWduaWZpY2FudCBhbmQgaW1wYWN0ZnVsIHZhcmlhYmxlcwpgYGB7ciBmdXJ0aGVyIGFuYWx5c2lzfQpjcm9zcyA8LSB4dGFicyh+IFJhY2UgKyBPU0EsIGRhdGEgPSBkYXRhLCBzdWJzZXQgPSBOVUxMKQoKZnRhYmxlKGNyb3NzKQpzdW1tYXJ5KGNyb3NzKQoKY3Jvc3MgPC0geHRhYnMofiBEZWNyZWFzZWQuTGliaWRvICsgT1NBLCBkYXRhID0gZGF0YSwgc3Vic2V0ID0gTlVMTCkKCmZ0YWJsZShjcm9zcykKc3VtbWFyeShjcm9zcykKYGBgCioqYikgSWRlbnRpZnkgY292YXJpYXRlcyBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCB0aGUgb3V0Y29tZSDigJxPU0HigJ0sIHByZXNlbnRpbmcgdGhlIGVmZmVjdCBvZiB0aGF0IGFzc29jaWF0aW9uIChlLmcuIE9SKSBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgc2lnbmlmaWNhbmNlIChlLmcuIHAtdmFsdWUgb3IgOTUlQ0kpLioqCgpVc2luZyBmb3J3YXJkIGFuZCBCYWNrd2FyZCBzdGVwd2lzZSBzZWxlY3Rpb24sIHdlIGxvb2sgZm9yIHRoZSBiZXN0IGFzc29jaWF0ZWQgdmFyaWFibGVzIHdpdGggdGhlIG91dGNvbWUgYE9TQWAuCgpGb3IgcHJhY3RpY2FsIHB1cnBvc2VzLCB3ZSBzaG93IGhlcmUgYW4gZXhhbXBsZSBvZiB0aGUgcHJvY2VzcyB3aXRoIHRoZSBmaXJzdCAxMiB2YXJpYWJsZXMuCgpgYGB7ciBTYW1wbGV9Cm1vZGVsMSA8LSBnbG0oT1NBIH4gLiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCBkYXRhID0gZGF0YVssIGMoMSwgMjoxMyldKQprMSA8LSBibHJfc3RlcF9wX2JhY2t3YXJkKG1vZGVsMSwgcHJlbSA9IDAuMSkKYGBgClNvIG91ciBtZXRob2Qgd2FzIHRvIGFwcGx5IHRoZSBtZXRob2QgZXhlbXBsaWZpZWQgYWJvdmUgdG8gdGhlIGZ1bGwgZGF0YXNldCBhbmQgdmFyaWFibGVzLiBEdWUgdG8gcHJvYmxlbXMgbGlrZSBgZ2xtLmZpdDogYWxnb3JpdGhtIGRpZCBub3QgY29udmVyZ2VgIGFuZCBgZ2xtLmZpdDogZml0dGVkIHByb2JhYmlsaXRpZXMgbnVtZXJpY2FsbHkgMCBvciAxIG9jY3VycmVkYCwgd2UgY291bGQgbm90IHVzZSB0aGUgd2hvbGUgc2V0IG9mIHZhcmlhYmxlcyBpbiBvbmUgcGFzcywgc28gd2UgdXNlZCBtdWx0aXBsZSBwYXNzZXMsIHJlbW92aW5nIHZhcmlhYmxlcywgdW50aWwgd2UgZ290IGEgdW5pcXVlIG1vZGVsLgoKYGBge3IgSWRlbnRpZnkgQ292YXJpYXRlcywgaW5jbHVkZT1GQUxTRX0KIyBNb2RlbGxpbmcgd2l0aCBhbGwgdmFyaWFibGVzIGRvZXMgbm90IGNvbnZlcmdlLCBzbyBsZXQncyBtYWtlIHBhcnRpYWxzCnN0YXJ0LnRpbWUgPC0gU3lzLnRpbWUoKQpjYXB0dXJlLm91dHB1dCh7ICMgY2FwdHVyZS5vdXRwdXQgdG8gYXZvaWQgcHJpbnQgZGVsYXkKICBtb2RlbDEuYiA8LSBnbG0oT1NBIH4gLiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCBkYXRhID0gZGF0YVssIGMoMSwgMjoxMyldKQogIG1vZGVsMi5iIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCAxNDoyOSldKQogIG1vZGVsMy5iIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCAzMDozOSldKQogIGsxLmIgPC0gYmxyX3N0ZXBfcF9iYWNrd2FyZChtb2RlbDEuYiwgcGVudCA9IDAuMDUsIHByZW0gPSAwLjEsIGRldGFpbHMgPSBGQUxTRSkKICBrMi5iIDwtIGJscl9zdGVwX3BfYmFja3dhcmQobW9kZWwyLmIsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgazMuYiA8LSBibHJfc3RlcF9wX2JhY2t3YXJkKG1vZGVsMy5iLCBwZW50ID0gMC4wNSwgcHJlbSA9IDAuMSwgZGV0YWlscyA9IEZBTFNFKQogIGsxLmIkcHJlZGljdG9ycyA8LSBrMS5iJGluZHZhclshKGsxLmIkaW5kdmFyICVpbiUgazEuYiRyZW1vdmVkKV0KICBrMi5iJHByZWRpY3RvcnMgPC0gazIuYiRpbmR2YXJbIShrMi5iJGluZHZhciAlaW4lIGsyLmIkcmVtb3ZlZCldCiAgazMuYiRwcmVkaWN0b3JzIDwtIGszLmIkaW5kdmFyWyEoazMuYiRpbmR2YXIgJWluJSBrMy5iJHJlbW92ZWQpXQogIHByZWRzLmIgPC0gd2hpY2gobmFtZXMoZGF0YSkgJWluJSBjKGsxLmIkcHJlZGljdG9ycywgazIuYiRwcmVkaWN0b3JzLCBrMy5iJHByZWRpY3RvcnMpKQogIG1vZGVsNC5iIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCBoZWFkKHByZWRzLmIsIDcpKV0pCiAgbW9kZWw1LmIgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGFbLCBjKDEsIHRhaWwocHJlZHMuYiwgLTcpKV0pCiAgazQuYiA8LSBibHJfc3RlcF9wX2JhY2t3YXJkKG1vZGVsNC5iLCBwZW50ID0gMC4wNSwgcHJlbSA9IDAuMSwgZGV0YWlscyA9IEZBTFNFKQogIGs1LmIgPC0gYmxyX3N0ZXBfcF9iYWNrd2FyZChtb2RlbDUuYiwgcGVudCA9IDAuMDUsIHByZW0gPSAwLjEsIGRldGFpbHMgPSBGQUxTRSkKICBrNC5iJHByZWRpY3RvcnMgPC0gazQuYiRpbmR2YXJbIShrNC5iJGluZHZhciAlaW4lIGs0LmIkcmVtb3ZlZCldCiAgazUuYiRwcmVkaWN0b3JzIDwtIGs1LmIkaW5kdmFyWyEoazUuYiRpbmR2YXIgJWluJSBrNS5iJHJlbW92ZWQpXQogIHByZWRzMi5iIDwtIHdoaWNoKG5hbWVzKGRhdGEpICVpbiUgYyhrNC5iJHByZWRpY3RvcnMsIGs1LmIkcHJlZGljdG9ycykpCiAgbW9kZWw2LmIgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGFbLCBjKDEsIGhlYWQocHJlZHMyLmIsIC0xKSldKQogIG1vZGVsNy5iIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCB0YWlsKHByZWRzMi5iLCAtMSkpXSkKICBrNi5iIDwtIGJscl9zdGVwX3BfYmFja3dhcmQobW9kZWw2LmIsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgazcuYiA8LSBibHJfc3RlcF9wX2JhY2t3YXJkKG1vZGVsNy5iLCBwZW50ID0gMC4wNSwgcHJlbSA9IDAuMSwgZGV0YWlscyA9IEZBTFNFKQogIGs2LmIkcHJlZGljdG9ycyA8LSBrNi5iJGluZHZhclshKGs2LmIkaW5kdmFyICVpbiUgazYuYiRyZW1vdmVkKV0KICBrNy5iJHByZWRpY3RvcnMgPC0gazcuYiRpbmR2YXJbIShrNy5iJGluZHZhciAlaW4lIGs3LmIkcmVtb3ZlZCldCiAgcHJlZHMzLmIgPC0gd2hpY2gobmFtZXMoZGF0YSkgJWluJSB1bmlxdWUoYyhrNi5iJHByZWRpY3RvcnMsIGs3LmIkcHJlZGljdG9ycykpKQogIG1vZGVsOC5iIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCBwcmVkczMuYildKQogIGs4LmIgPC0gYmxyX3N0ZXBfcF9iYWNrd2FyZChtb2RlbDguYiwgcGVudCA9IDAuMDUsIHByZW0gPSAwLjEsIGRldGFpbHMgPSBGQUxTRSkKICBrOC5iJHByZWRpY3RvcnMgPC0gazguYiRpbmR2YXJbIShrOC5iJGluZHZhciAlaW4lIGs4LmIkcmVtb3ZlZCldCiAgcHJlZHM0LmIgPC0gd2hpY2gobmFtZXMoZGF0YSkgJWluJSBrOC5iJHByZWRpY3RvcnMpCiAgZGF0YTIuYiA8LSBkYXRhWywgYygxLCBwcmVkczQuYildCiAgZGF0YTIuYiA8LSBkYXRhMi5iW2NvbXBsZXRlLmNhc2VzKGRhdGEyLmIpLCBdCiAgbW9kZWwuYiA8LSBnbG0oT1NBIH4gLiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCBkYXRhID0gZGF0YTIuYikKICBiYWNrd2FyZCA8LSBrOC5iCn0pCmBgYAoKYGBge3IgSWRlbnRpZnkgQ292YXJpYXRlczIsIGluY2x1ZGU9RkFMU0V9CmNhcHR1cmUub3V0cHV0KHsgIyBjYXB0dXJlLm91dHB1dCB0byBhdm9pZCBwcmludCBkZWxheQogIG1vZGVsMS5mIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCAyOjEzKV0pCiAgbW9kZWwyLmYgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGFbLCBjKDEsIDE0OjI5KV0pCiAgbW9kZWwzLmYgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGFbLCBjKDEsIDMwOjM5KV0pCiAgazEuZiA8LSBibHJfc3RlcF9wX2ZvcndhcmQobW9kZWwxLmYsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgazIuZiA8LSBibHJfc3RlcF9wX2ZvcndhcmQobW9kZWwyLmYsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgazMuZiA8LSBibHJfc3RlcF9wX2ZvcndhcmQobW9kZWwzLmYsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgcHJlZHMuZiA8LSB3aGljaChuYW1lcyhkYXRhKSAlaW4lIGMoazEuZiRwcmVkaWN0b3JzLCBrMi5mJHByZWRpY3RvcnMsIGszLmYkcHJlZGljdG9ycykpCiAgbW9kZWw0LmYgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGFbLCBjKDEsIGhlYWQocHJlZHMuZiwgNykpXSkKICBtb2RlbDUuZiA8LSBnbG0oT1NBIH4gLiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCBkYXRhID0gZGF0YVssIGMoMSwgdGFpbChwcmVkcy5mLCAtNykpXSkKICBrNC5mIDwtIGJscl9zdGVwX3BfZm9yd2FyZChtb2RlbDQuZiwgcGVudCA9IDAuMDUsIHByZW0gPSAwLjEsIGRldGFpbHMgPSBGQUxTRSkKICBrNS5mIDwtIGJscl9zdGVwX3BfZm9yd2FyZChtb2RlbDUuZiwgcGVudCA9IDAuMDUsIHByZW0gPSAwLjEsIGRldGFpbHMgPSBGQUxTRSkKICBwcmVkczIuZiA8LSB3aGljaChuYW1lcyhkYXRhKSAlaW4lIGMoazQuZiRwcmVkaWN0b3JzLCBrNS5mJHByZWRpY3RvcnMpKQogIG1vZGVsNi5mIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCBoZWFkKHByZWRzMi5mLCAtMSkpXSkKICBtb2RlbDcuZiA8LSBnbG0oT1NBIH4gLiwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCBkYXRhID0gZGF0YVssIGMoMSwgdGFpbChwcmVkczIuZiwgLTEpKV0pCiAgazYuZiA8LSBibHJfc3RlcF9wX2ZvcndhcmQobW9kZWw2LmYsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgazcuZiA8LSBibHJfc3RlcF9wX2ZvcndhcmQobW9kZWw3LmYsIHBlbnQgPSAwLjA1LCBwcmVtID0gMC4xLCBkZXRhaWxzID0gRkFMU0UpCiAgcHJlZHMzLmYgPC0gd2hpY2gobmFtZXMoZGF0YSkgJWluJSB1bmlxdWUoYyhrNi5mJHByZWRpY3RvcnMsIGs3LmYkcHJlZGljdG9ycykpKQogIG1vZGVsOC5mIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhWywgYygxLCBwcmVkczMuZildKQogIGs4LmYgPC0gYmxyX3N0ZXBfcF9mb3J3YXJkKG1vZGVsOC5mLCBwZW50ID0gMC4wNSwgcHJlbSA9IDAuMSwgZGV0YWlscyA9IEZBTFNFKQogIHByZWRzNC5mIDwtIHdoaWNoKG5hbWVzKGRhdGEpICVpbiUgazguZiRwcmVkaWN0b3JzKQogIGRhdGEyLmYgPC0gZGF0YVssIGMoMSwgcHJlZHM0LmYpXQogIGRhdGEyLmYgPC0gZGF0YTIuZltjb21wbGV0ZS5jYXNlcyhkYXRhMi5mKSwgXQogIG1vZGVsLmYgPC0gZ2xtKE9TQSB+IC4sIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGRhdGEyLmYpCiAgZm9yd2FyZCA8LSBrOC5mCgogIGJscl9tb2QuZiA8LSBibHJfcmVncmVzcyhtb2RlbC5mLCBvZGRfY29uZl9saW1pdCA9IFRSVUUpCiAgYmxyX21vZC5iIDwtIGJscl9yZWdyZXNzKG1vZGVsLmIsIG9kZF9jb25mX2xpbWl0ID0gVFJVRSkKfSkKZW5kLnRpbWUgPC0gU3lzLnRpbWUoKQp0aW1lLnRha2VuIDwtIGVuZC50aW1lIC0gc3RhcnQudGltZQp0aW1lLnRha2VuCmBgYAoKQWZ0ZXIgYWxsIHRoZSBjYWxjdWxhdGlvbnMgd2VyZSBkb25lIChjYWxjdWxhdGlvbiB0aW1lOiBgciB0aW1lLnRha2VuYCBzKSBUaGUgdmFyaWFibGVzIHdlIGZvdW5kIGhpZ2hseSBhc3NvY2lhdGVkIHdpdGggdGhlIGBPU0FgIG91dGNvbWUgYXJlIHRoZSBmb2xsb3dpbmc6CgpgYGB7ciBTaG93IE1vZGVscywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KbWVzc2FnZSgiRm9yd2FyZCBzdGVwd2lzZSA6ICIsIHBhc3RlKHNvcnQoZm9yd2FyZCRwcmVkaWN0b3JzKSwgY29sbGFwc2UgPSAiLCAiKSkKYmxyX21vZC5mCm1lc3NhZ2UoIkJhY2t3YXJkIHN0ZXB3aXNlIChwLXZhbHVlOiByZW1vdmUgPjAuMTApOiAiLCBwYXN0ZShzb3J0KGJhY2t3YXJkJHByZWRpY3RvcnMpLCBjb2xsYXBzZSA9ICIsICIpKQpibHJfbW9kLmIKYGBgCgoKKipjKSBCdWlsZCBhIG11bHRpdmFyaWFibGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCwgdXNpbmcgYW55IGFwcHJvcHJpYXRlIGNvdmFyaWF0ZSBzZWxlY3Rpb24gbWV0aG9kLioqCgpCZXNpZGVzIHRoZSB2YXJpYWJsZXMgc2VsZWN0ZWQgYnkgc3RlcHdpc2UgYWxnb3JpdGhtLCB3ZSBhZGRlZCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyBhcyB3ZSBmaW5kIHRoZW0gaW1wb3J0YW50IGR1ZSB0byBjbGluaWNhbCBsb2dpYyByZWFzb25pbmc6IGBBbGNvaG9sYCBkdWUgdG8gaXRzIG11c2N1bGFyIHJlbGF4aW5nIHByb3BlcnRpZXMuIFNvLCBwcm92aWRpbmcgYSBsYXJnZXIgbXVzY3VsYXIgcmVsYXhhdGlvbiwgaXQgY2FuIGVuaGFuY2UgdGhlIGVmZmVjdHMgb2YgdGhlIE9TQS4gClRoYXQgc2FpZCwgdGhlIGZpbmFsIGxpc3QgY29uc2lzdGVkIG9mOiAgCioqYHIgdW5pcXVlKGMoZm9yd2FyZCRwcmVkaWN0b3JzLCBiYWNrd2FyZCRwcmVkaWN0b3JzLCJBbGNvaG9sIikpYCoqCgpGaXJzdCwgd2UgdXNlZCB0aGUgYGJsb3JyYCBwYWNrYWdlIHRvIGJ1aWxkIGEgbW9kZWwuCgpgYGB7ciBNb2RlbCwgd2FybmluZz1GQUxTRX0KY292YXJpYXRlcyA8LSB1bmlxdWUoYyhmb3J3YXJkJHByZWRpY3RvcnMsIGJhY2t3YXJkJHByZWRpY3RvcnMsICJBbGNvaG9sIikpCnByZWRzIDwtIHdoaWNoKG5hbWVzKGRhdGEpICVpbiUgY292YXJpYXRlcykKZGF0YTMgPC0gZGF0YVssIGMoMSwgcHJlZHMpXQpkYXRhMyA8LSBkcGx5cjo6dGJsX2RmKGRhdGEzW2NvbXBsZXRlLmNhc2VzKGRhdGEzKSwgXSkKCmRhdGEzX3NpbSA8LSBkYXRhX3NpbVssIGMoMSwgcHJlZHMpXQpkYXRhM19zaW0gPC0gZHBseXI6OnRibF9kZihkYXRhM19zaW1bY29tcGxldGUuY2FzZXMoZGF0YTNfc2ltKSwgXSkKCm1vZGVsIDwtIGdsbShPU0EgfiAuLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSBkYXRhMykKZGVmX21vZGVsIDwtIGJscl9yZWdyZXNzKG1vZGVsLCBvZGRfY29uZl9saW1pdCA9IFRSVUUpCmRlZl9tb2RlbApgYGAKIFRoZW4gd2UgdXNlZCB0aGUgYGNhcmV0YCBwYWNrYWdlIHRvIGJ1aWxkIHRoZSBtb2RlbCBhcyB3ZWxsLiAKIFRoZSBtZXRyaWMgYWltZWQgZm9yIHdhcyBST0MgYW5kIGV2YWx1YXRpb24gd2FzIHVzZWQgKipsZWF2ZS1vbmUtb3V0KiogYW5kICoqbGVhdmUtZ3JvdXAtb3V0IChha2EgdHJhaW4gdGVzdCkqKiAKIApgYGB7ciB0cmFpbmluZzIsIHdhcm5pbmc9RkFMU0V9CiMjIExPTwpjb250cm9sIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiTE9PQ1YiLCBjbGFzc1Byb2JzID0gVFJVRSwgc2F2ZVByZWRpY3Rpb25zID0gVFJVRSkKZml0LmdsbSA8LSB0cmFpbihPU0EgfiAuLCBkYXRhID0gZGF0YTMsIG1ldGhvZCA9ICJnbG0iLCBtZXRyaWMgPSAiUk9DIiwgdHJDb250cm9sID0gY29udHJvbCkKZml0LmdsbSRmaW5hbE1vZGVsCgoKIyMjIHRyYWluIHRlc3QKY29udHJvbDIgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJMR09DViIsIGNsYXNzUHJvYnMgPSBUUlVFLCByZXBlYXRzID0gMywgcCA9IDAuMjUsIHNhdmVQcmVkaWN0aW9ucyA9IFRSVUUsIHN1bW1hcnlGdW5jdGlvbiA9IHR3b0NsYXNzU3VtbWFyeSkKZml0LmdsbTIgPC0gdHJhaW4oT1NBIH4gLiwgZGF0YSA9IGRhdGEzLCBtZXRob2QgPSAiZ2xtIiwgbWV0cmljID0gIlJPQyIsIHRyQ29udHJvbCA9IGNvbnRyb2wyKQpmaXQuZ2xtMiRmaW5hbE1vZGVsCmBgYAoKKipkKSBFdmFsdWF0ZSB0aGUgZGVyaXZlZCBtb2RlbCwgdXNpbmcgYW55IGFwcHJvcHJpYXRlIG1vZGVsIGV2YWx1YXRpb24gc3RyYXRlZ3ksIHByZXNlbnRpbmcgZXN0aW1hdGVzIG9mIHRoZSBnZW5lcmFsaXphYmlsaXR5IG9mIHVzaW5nIHRoZSBtb2RlbCBhcyBkaWFnbm9zdGljIHByZWRpY3RvciBmb3IgbmV3IHBhdGllbnRzLioqCgpUaGVuIHdlIHBsb3R0ZWQgdGhlIHJvYyBjdXJ2ZXMgZm9yIGFsbCBtb2RlbHMuCgpgYGB7ciB9CiMgYmxvcnIKayA8LSBibHJfZ2FpbnNfdGFibGUobW9kZWwpCmJscl9yb2NfY3VydmUoaykKawoKIyBsZWF2ZSBvbmUgb3V0CnByZWRvYmogPC0gcHJlZGljdGlvbihwcmVkaWN0aW9ucyA9IGZpdC5nbG0kcHJlZCRUcnVlLCBsYWJlbHMgPSBmaXQuZ2xtJHByZWQkb2JzKQpwZXJmIDwtIHBlcmZvcm1hbmNlKHByZWRvYmosIG1lYXN1cmUgPSAidHByIiwgeC5tZWFzdXJlID0gImZwciIpCnBsb3QocGVyZikKdHdvQ2xhc3NTdW1tYXJ5KGZpdC5nbG0kcHJlZCwgbGV2ID0gbGV2ZWxzKGZpdC5nbG0kcHJlZCRvYnMpKQoKCiMgdHJhaW4gdGVzdApwcmVkb2JqMiA8LSBwcmVkaWN0aW9uKHByZWRpY3Rpb25zID0gZml0LmdsbTIkcHJlZCRUcnVlLCBsYWJlbHMgPSBmaXQuZ2xtMiRwcmVkJG9icykKcGVyZjIgPC0gcGVyZm9ybWFuY2UocHJlZG9iajIsIG1lYXN1cmUgPSAidHByIiwgeC5tZWFzdXJlID0gImZwciIpCnBsb3QocGVyZjIpCnR3b0NsYXNzU3VtbWFyeShmaXQuZ2xtMiRwcmVkLCBsZXYgPSBsZXZlbHMoZml0LmdsbTIkcHJlZCRvYnMpKQpgYGAKCgoqKmUpIENvbW1lbnQgb24gaG93IGRpZmZlcmVudCB5b3VyIGFwcHJvYWNoIGFuZCBmaW5hbCBzb2x1dGlvbiB3b3VsZCBuZWVkIHRvIGJlIGlmIGFwcGxpZWQgdG8gdGhlIGxhcmdlciBvc2Ffc2ltdWxhdGVkLmNzdiBkYXRhc2V0LCBkaXNjdXNzaW5nIG9uIHRoZSBpbXBsaWNhdGlvbnMgZm9yIHRyYWRpdGlvbmFsIGFuYWx5c2lzIG9mIGhhdmluZyDigJx0b28gbGFyZ2XigJ0gZGF0YXNldHMuKioKCkZvciBsYXJnZSBkYXRhc2V0cywgYSBmZXcgdGhpbmdzIHNob3VsZCBiZSBoYW5kbGVkIGRpZmZlcmVudC4gRmlyc3QgdGhlIGV2YWx1YXRpb24gb2YgdGhlIHNpZ25pZmljYW5jZSBpbiBsYXJnZSBkYXRhIHNldHMgdGVuZCB0byBiZSBzaWduaWZpY2FuY2UsIHNpbmNlIGl0IGlzIGltcGFjdGVkIGJ5IHJvdyBudW1iZXJzLiBUaGF0IHNhaWQsIHNlbWktYXV0b21hdGljIG1vZGVscyBsaWtlIGZvcndhcmQgYW5kIGJhY2t3YXJkIHN0ZXB3aXNlIHNlbGVjdGlvbnMgY2FuIGJlIGRpZmZpY3VsdCB0byBhcHBseSBhcyBpcyB0byBzdWNoIGRhdGFzZXRzLiBIb3dldmVyLCB0aGVyZSBhcmUgZGlmZmVyZW50IG1ldHJpY3MgYW5kIHN0YXRpc3RpYyBtZXRob2QgdG8gb3ZlcmNvbWUgdGhpcywgbGlrZSBBSUMgYW5kIEJJQyBtZXRyaWNzLiBGdXJ0aGVybW9yZSwgdGhlIG1ldHJpYyB1c2VkIGZvciBhc3Nlc3NpbmcgcXVhbGl0eSAtIHRoZSBMZWF2ZSBPbmUgT3V0IGlzIG5vdCB2ZXJ5IGJpZyBkYXRhIGZyaWVuZGx5LCBzaW5jZSBpdCBpcyBjb21wdXRhdGlvbmFsIGRlbWFuZGluZy4gTmV2ZXJ0aGVsZXNzLCB0aGVyZSBhcmUgYSBmZXcgb3RoZXJzIG1ldHJpY3MgZm9yIGFzc2Vzc2luZyBtb2RlbCBxdWFsaXR5IGFuZCBnZW5lcmFsaXphdGlvbiBjYXBhYmlsaXRpZXMuCgpMYXN0IGJ1dCBub3QgbGVhc3QsIGl0IGlzIGluIHRoZXNlIHNjZW5hcmlvcyB0aGF0IGRhdGEgc2NpZW50aXN0cyBjYW4gYmUgb2YgZ3JlYXQgaW1wb3J0YW5jZSwgdGFraW5nIGludG8gYWNjb3VudCB0aGUgZG9tYWluIHRoZXkgYXJlIHdvcmtpbmcgb24sIGFkZGluZyB2YXJpYWJsZXMgYW5kIGNyZWF0aW5nIG5ldyBvbmVzIGJhc2VkIG9uIHRoZWlyIGtub3dsZWRnZSBvZiB0aGUgcHJvYmxlbSB0cnlpbmcgdG8gYmUgc29sdmVkLgo=