I. Sampling Techniques in the Mosaic Package

We have three main sampling functions in the Mosaic package for R that help produce randomized versions of statistical tests and confidence intervals.

  1. Shuffle. A permutation, size equal to number of observations.
  2. Sample. Draws without replacement, size less than or equal to number of observations.
  3. Resample. Draws with replacement, size unlimited.

Let’s create a sample vector Prime so we can see how these functions work.

Prime = c(2,3,5,7,11,13,17,19,23,29)
Prime
 [1]  2  3  5  7 11 13 17 19 23 29

1. Shuffle

The shuffle function permutes the values in the vector.

shuffle(Prime)
 [1] 23  3  5 13  7  2 11 19 29 17

Draws are without replacement, and the number of draws must be equal to the number of observations.

2. Sample

The sample function draws without replacement so the number of draws must be less than or equal to the number of observations.

sample(Prime, size = 6)
[1] 23 13  3  7  5 29

Left on its default setting for the size of draw, sample is equivalent to shuffle because the draws will equal the number of observations.

sample(Prime)
 [1] 29 23 11  7  2 19 17 13  5  3

3. Resample

The resample function draws with replacement, so the number of draws is unlimited.

resample(Prime, size = 20)
 [1]  7  7  2 17 11 19 23 17  2 29  2 19  2  2 19  7 13 17  7  2

If left to its default setting, the draws will equal the number of observations. Since a single observation may repeat multiple times, resample is not equivalent to either shuffle or sample, except by accident.

resample(Prime)
 [1] 29 29 23  7 11 13 23 11 11 13

II.Toy Data Frames

Along with the Primes vector, we will need a couple of toy data frames to demonstrate the randomization techniques for \(t\)-tests, correlation and proportion tests.

Zoo Data Frame

Zoo = as.data.frame(matrix(c(5:12,1:8),nrow=16))
colnames(Zoo) = "Number"
Animal = c("Lion","Lion","Lion","Lion","Lion","Lion","Lion","Lion","Zebra","Zebra","Zebra","Zebra","Zebra","Zebra","Zebra","Zebra")
Zoo$Animal = Animal
Zoo

We can use the t.test function on the Zoo data frame.

t.test(Number ~ Animal, data = Dinner)

    Welch Two Sample t-test

data:  Number by Animal
t = 3.266, df = 14, p-value = 0.005631
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 1.373184 6.626816
sample estimates:
 mean in group Lion mean in group Zebra 
                8.5                 4.5 

Dinner Data Frame

Dinner = as.data.frame((matrix(c(3, 4, 5, 8, 9, 11,150, 175, 325, 375, 475, 525),nrow=6)))
colnames(Dinner) = c("Predator", "Prey")
Dinner

We can now create a linear model using the lm function on the Dinner data frame.

lm(Predator ~ Prey, data = Dinner)

Call:
lm(formula = Predator ~ Prey, data = Dinner)

Coefficients:
(Intercept)         Prey  
   -0.02933      0.01984  

III. Bootstrapping

For one-sample \(t\)-tests and \(t\)-interval estimates, we use a randomization method called bootstrapping. We repeatedly resample the observations from the data frame to generate a distribution.

Confidence Interval

To create a randomized version of the \(t\)-interval, we draw 500 resamples and load their means into a data frame called bootstrap. Once we find the percentiles corresponding to the endpoints of the interval, we’re done.

bootstrap = do(500) * mean(resample(Prime))
qdata(~mean, p=c(0.025, 0.975), data = bootstrap)
   2.5%   97.5% 
 7.7475 18.1525 

\(t\)-test

Consider a one-sample \(t\)-test on Prime using the hypothesis \[H_0 : \mu_p = 16\\H_a : \mu_p > 16\] To create a randomized version, we input a logical operation into the sum function so that it will count for us. Again, we use the bootstrap distribution, and count the number of times the mean is greater than 16.

sum(bootstrap$mean > 16)
[1] 60

So our randomized \(p\)-value is \[p=\frac{56}{500}=\frac{14}{125}= .112\] and we fail to reject the null. Note the \(p-value\) from the \(t\)-test would be

t.test(~Prime, mu = 16, alternative = "less")

    One Sample t-test

data:  Prime
t = -1.0863, df = 9, p-value = 0.1528
alternative hypothesis: true mean is less than 16
95 percent confidence interval:
     -Inf 18.13107
sample estimates:
mean of x 
     12.9 

For some reason, the \(t\)-statistic is negative which forces us to reverse the inequality from our hypothesis. Still, the bootstrapping \(p\)-value (0.112) appears to be reasonable given \(p\)-value from the \(t\)-test \((p=0.153)\).

IV. Permutation Tests

For permutation tests, we shuffle the observations of the dependent variable.

Test of Significant Correlation

Consider the the linear model \[\text{Predator} \sim \text{Prey}\] which has a significant correlation.

mod = lm(Predator ~ Prey, data = Dinner)
summary(mod)

Call:
lm(formula = Predator ~ Prey, data = Dinner)

Residuals:
       1        2        3        4        5        6 
 0.05333  0.55733 -1.41867  0.58933 -0.39467  0.61333 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)   
(Intercept) -0.029333   0.955223  -0.031  0.97697   
Prey         0.019840   0.002615   7.587  0.00162 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8952 on 4 degrees of freedom
Multiple R-squared:  0.935, Adjusted R-squared:  0.9188 
F-statistic: 57.56 on 1 and 4 DF,  p-value: 0.001619

To create a permutation test, we choose a random permutation of the dependent variable and pair those values with the independent variable. In general, we need several thousand permutations to generate accurate results.

perm = do(10000) * coef(lm(shuffle(Predator) ~ Prey, data = Dinner))
perm

We are testing the hypothesis that \[H_0 : \beta = 0\\H_a : \beta \neq 0\] By entering a logical expression into the function sum, we can count the number of randomized models that had slope greater than 0.0198.

sum(abs(perm$Prey) > 0.0198)

The estimated significance of the slope coefficient is \[p=\frac{28}{10,000} = 0.0028\] which is reasonable given what the linear regression \(t\)-test results were (\(p = 0.0016\)). We used a two-tailed test by taking the absolute value of the shuffled model slopes. We can randomize a one-tailed test by removing the absolute value and adjusting the inequality. Either way, we have strong evidence that the slope (or correlation) is non-zero.

Estimates of the Slope Coefficient

We can use a bootstrapping approach to estimate the slope coefficient with 95% confidence.

boots = do(500) * coef(lm(Predator ~ Prey, data=resample(Dinner)))
qdata(boots$Prey, c(0.025, 0.975))
      2.5%      97.5% 
0.01518438 0.02830419 

Independent Samples \(t\)-test

We can permute the dependent variable so that its association with the grouping variable is random.

perm = do(1000) * mean(shuffle(Number) ~ Animal, data = Zoo)
perm$diff = perm$Lion - perm$Zebra
perm

The observed mean difference in the between Lions and Zerbra was 4. To estimate the \(p\)-value for the difference in means, we need to count how many of the randomized differences were greater than or equal to 4.

sum(perm$diff >= 4)
[1] 6

Thus, we have an estimated \(p\)-value of \[p=\frac{4}{1000}=0.004\] and, therefore, strong evidence for a difference in group means.

LS0tDQp0aXRsZTogIlJhbmRvbWl6YXRpb24gVHV0b3JpYWwiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5JLiBTYW1wbGluZyBUZWNobmlxdWVzIGluIHRoZSBNb3NhaWMgUGFja2FnZTwvc3Bhbj4NCg0KV2UgaGF2ZSB0aHJlZSBtYWluIHNhbXBsaW5nIGZ1bmN0aW9ucyBpbiB0aGUgPGEgaHJlZiA9IGh0dHBzOi8vcmRyci5pby9jcmFuL21vc2FpYy8+TW9zYWljIHBhY2thZ2UgZm9yIFI8L2E+IHRoYXQgaGVscCBwcm9kdWNlIHJhbmRvbWl6ZWQgdmVyc2lvbnMgb2Ygc3RhdGlzdGljYWwgdGVzdHMgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLg0KDQoxLiAqKlNodWZmbGUqKi4gQSBwZXJtdXRhdGlvbiwgc2l6ZSAqZXF1YWwqIHRvIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuDQoyLiAqKlNhbXBsZSoqLiBEcmF3cyB3aXRob3V0IHJlcGxhY2VtZW50LCBzaXplICpsZXNzIHRoYW4gb3IgZXF1YWwqIHRvIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuDQozLiAqKlJlc2FtcGxlKiouIERyYXdzIHdpdGggcmVwbGFjZW1lbnQsIHNpemUgKnVubGltaXRlZCouDQoNCkxldCdzIGNyZWF0ZSBhIHNhbXBsZSB2ZWN0b3IgKipQcmltZSoqIHNvIHdlIGNhbiBzZWUgaG93IHRoZXNlIGZ1bmN0aW9ucyB3b3JrLg0KYGBge3J9DQpQcmltZSA9IGMoMiwzLDUsNywxMSwxMywxNywxOSwyMywyOSkNClByaW1lDQpgYGANCg0KIyMgMS4gU2h1ZmZsZQ0KDQpUaGUgKipzaHVmZmxlKiogZnVuY3Rpb24gcGVybXV0ZXMgdGhlIHZhbHVlcyBpbiB0aGUgdmVjdG9yLiANCmBgYHtyfQ0Kc2h1ZmZsZShQcmltZSkNCmBgYA0KDQpEcmF3cyBhcmUgd2l0aG91dCByZXBsYWNlbWVudCwgYW5kIHRoZSBudW1iZXIgb2YgZHJhd3MgKiptdXN0IGJlIGVxdWFsKiogdG8gdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuDQoNCiMjIDIuIFNhbXBsZQ0KDQpUaGUgKipzYW1wbGUqKiBmdW5jdGlvbiBkcmF3cyB3aXRob3V0IHJlcGxhY2VtZW50IHNvIHRoZSBudW1iZXIgb2YgZHJhd3MgbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuDQpgYGB7cn0NCnNhbXBsZShQcmltZSwgc2l6ZSA9IDYpDQpgYGANCg0KTGVmdCBvbiBpdHMgZGVmYXVsdCBzZXR0aW5nIGZvciB0aGUgc2l6ZSBvZiBkcmF3LCBzYW1wbGUgaXMgZXF1aXZhbGVudCB0byBzaHVmZmxlIGJlY2F1c2UgdGhlIGRyYXdzIHdpbGwgZXF1YWwgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuDQpgYGB7cn0NCnNhbXBsZShQcmltZSkNCmBgYA0KDQojIyAzLiBSZXNhbXBsZQ0KDQpUaGUgKipyZXNhbXBsZSoqIGZ1bmN0aW9uIGRyYXdzIHdpdGggcmVwbGFjZW1lbnQsIHNvIHRoZSBudW1iZXIgb2YgZHJhd3MgaXMgdW5saW1pdGVkLg0KYGBge3J9DQpyZXNhbXBsZShQcmltZSwgc2l6ZSA9IDIwKQ0KYGBgDQoNCklmIGxlZnQgdG8gaXRzIGRlZmF1bHQgc2V0dGluZywgdGhlIGRyYXdzIHdpbGwgZXF1YWwgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuIFNpbmNlIGEgc2luZ2xlIG9ic2VydmF0aW9uIG1heSByZXBlYXQgbXVsdGlwbGUgdGltZXMsIHJlc2FtcGxlIGlzIG5vdCBlcXVpdmFsZW50IHRvIGVpdGhlciBzaHVmZmxlIG9yIHNhbXBsZSwgZXhjZXB0IGJ5IGFjY2lkZW50Lg0KDQpgYGB7cn0NCnJlc2FtcGxlKFByaW1lKQ0KYGBgDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPklJLlRveSBEYXRhIEZyYW1lczwvc3Bhbj4NCg0KQWxvbmcgd2l0aCB0aGUgKipQcmltZXMqKiB2ZWN0b3IsIHdlIHdpbGwgbmVlZCBhIGNvdXBsZSBvZiB0b3kgZGF0YSBmcmFtZXMgdG8gZGVtb25zdHJhdGUgdGhlIHJhbmRvbWl6YXRpb24gdGVjaG5pcXVlcyBmb3IgJHQkLXRlc3RzLCBjb3JyZWxhdGlvbiBhbmQgcHJvcG9ydGlvbiB0ZXN0cy4NCg0KIyMgWm9vIERhdGEgRnJhbWUNCmBgYHtyfQ0KWm9vID0gYXMuZGF0YS5mcmFtZShtYXRyaXgoYyg1OjEyLDE6OCksbnJvdz0xNikpDQpjb2xuYW1lcyhab28pID0gIk51bWJlciINCkFuaW1hbCA9IGMoIkxpb24iLCJMaW9uIiwiTGlvbiIsIkxpb24iLCJMaW9uIiwiTGlvbiIsIkxpb24iLCJMaW9uIiwiWmVicmEiLCJaZWJyYSIsIlplYnJhIiwiWmVicmEiLCJaZWJyYSIsIlplYnJhIiwiWmVicmEiLCJaZWJyYSIpDQpab28kQW5pbWFsID0gQW5pbWFsDQpab28NCmBgYA0KDQpXZSBjYW4gdXNlIHRoZSAqKnQudGVzdCoqIGZ1bmN0aW9uIG9uIHRoZSAqKlpvbyoqIGRhdGEgZnJhbWUuDQpgYGB7cn0NCnQudGVzdChOdW1iZXIgfiBBbmltYWwsIGRhdGEgPSBEaW5uZXIpDQpgYGANCg0KIyMgRGlubmVyIERhdGEgRnJhbWUNCmBgYHtyfQ0KRGlubmVyID0gYXMuZGF0YS5mcmFtZSgobWF0cml4KGMoMywgNCwgNSwgOCwgOSwgMTEsMTUwLCAxNzUsIDMyNSwgMzc1LCA0NzUsIDUyNSksbnJvdz02KSkpDQpjb2xuYW1lcyhEaW5uZXIpID0gYygiUHJlZGF0b3IiLCAiUHJleSIpDQpEaW5uZXINCmBgYA0KDQpXZSBjYW4gbm93IGNyZWF0ZSBhIGxpbmVhciBtb2RlbCB1c2luZyB0aGUgICoqbG0qKiBmdW5jdGlvbiBvbiB0aGUgKipEaW5uZXIqKiBkYXRhIGZyYW1lLg0KDQpgYGB7cn0NCmxtKFByZWRhdG9yIH4gUHJleSwgZGF0YSA9IERpbm5lcikNCmBgYA0KDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SUlJLiBCb290c3RyYXBwaW5nPC9zcGFuPg0KDQpGb3Igb25lLXNhbXBsZSAkdCQtdGVzdHMgYW5kICR0JC1pbnRlcnZhbCBlc3RpbWF0ZXMsIHdlIHVzZSBhIHJhbmRvbWl6YXRpb24gbWV0aG9kIGNhbGxlZCBib290c3RyYXBwaW5nLiBXZSByZXBlYXRlZGx5IHJlc2FtcGxlIHRoZSBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgZGF0YSBmcmFtZSB0byBnZW5lcmF0ZSBhIGRpc3RyaWJ1dGlvbi4NCg0KIyMgQ29uZmlkZW5jZSBJbnRlcnZhbA0KDQpUbyBjcmVhdGUgYSByYW5kb21pemVkIHZlcnNpb24gb2YgdGhlICR0JC1pbnRlcnZhbCwgd2UgZHJhdyA1MDAgcmVzYW1wbGVzIGFuZCBsb2FkIHRoZWlyIG1lYW5zIGludG8gYSBkYXRhIGZyYW1lIGNhbGxlZCAqKmJvb3RzdHJhcCoqLiBPbmNlIHdlIGZpbmQgdGhlIHBlcmNlbnRpbGVzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGVuZHBvaW50cyBvZiB0aGUgaW50ZXJ2YWwsIHdlJ3JlIGRvbmUuDQoNCmBgYHtyfQ0KYm9vdHN0cmFwID0gZG8oNTAwKSAqIG1lYW4ocmVzYW1wbGUoUHJpbWUpKQ0KcWRhdGEofm1lYW4sIHA9YygwLjAyNSwgMC45NzUpLCBkYXRhID0gYm9vdHN0cmFwKQ0KYGBgDQoNCiMjICR0JC10ZXN0DQoNCkNvbnNpZGVyIGEgb25lLXNhbXBsZSAkdCQtdGVzdCBvbiAqKlByaW1lKiogdXNpbmcgdGhlIGh5cG90aGVzaXMgJCRIXzAgOiBcbXVfcCA9IDE2XFxIX2EgOiBcbXVfcCA+IDE2JCQgVG8gY3JlYXRlIGEgcmFuZG9taXplZCB2ZXJzaW9uLCB3ZSBpbnB1dCBhIGxvZ2ljYWwgb3BlcmF0aW9uIGludG8gdGhlICoqc3VtKiogZnVuY3Rpb24gc28gdGhhdCBpdCB3aWxsIGNvdW50IGZvciB1cy4gQWdhaW4sIHdlIHVzZSB0aGUgKipib290c3RyYXAqKiBkaXN0cmlidXRpb24sIGFuZCBjb3VudCB0aGUgbnVtYmVyIG9mIHRpbWVzIHRoZSBtZWFuIGlzIGdyZWF0ZXIgdGhhbiAxNi4NCg0KYGBge3J9DQpzdW0oYm9vdHN0cmFwJG1lYW4gPiAxNikNCmBgYA0KU28gb3VyIHJhbmRvbWl6ZWQgJHAkLXZhbHVlIGlzICQkcD1cZnJhY3s1Nn17NTAwfT1cZnJhY3sxNH17MTI1fT0gLjExMiQkIGFuZCB3ZSBmYWlsIHRvIHJlamVjdCB0aGUgbnVsbC4gTm90ZSB0aGUgJHAtdmFsdWUkIGZyb20gdGhlICR0JC10ZXN0IHdvdWxkIGJlDQoNCmBgYHtyfQ0KdC50ZXN0KH5QcmltZSwgbXUgPSAxNiwgYWx0ZXJuYXRpdmUgPSAibGVzcyIpDQpgYGANCkZvciBzb21lIHJlYXNvbiwgdGhlICR0JC1zdGF0aXN0aWMgaXMgbmVnYXRpdmUgd2hpY2ggZm9yY2VzIHVzIHRvIHJldmVyc2UgdGhlIGluZXF1YWxpdHkgZnJvbSBvdXIgaHlwb3RoZXNpcy4gU3RpbGwsIHRoZSBib290c3RyYXBwaW5nICRwJC12YWx1ZSAoMC4xMTIpIGFwcGVhcnMgdG8gYmUgcmVhc29uYWJsZSBnaXZlbiAkcCQtdmFsdWUgZnJvbSB0aGUgJHQkLXRlc3QgJChwPTAuMTUzKSQuDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SVYuIFBlcm11dGF0aW9uIFRlc3RzPC9zcGFuPg0KDQpGb3IgcGVybXV0YXRpb24gdGVzdHMsIHdlICoqc2h1ZmZsZSoqIHRoZSBvYnNlcnZhdGlvbnMgb2YgdGhlIGRlcGVuZGVudCB2YXJpYWJsZS4NCg0KIyMgVGVzdCBvZiBTaWduaWZpY2FudCBDb3JyZWxhdGlvbg0KDQpDb25zaWRlciB0aGUgdGhlIGxpbmVhciBtb2RlbCAkJFx0ZXh0e1ByZWRhdG9yfSBcc2ltIFx0ZXh0e1ByZXl9JCQgd2hpY2ggaGFzIGEgc2lnbmlmaWNhbnQgY29ycmVsYXRpb24uDQoNCmBgYHtyfQ0KbW9kID0gbG0oUHJlZGF0b3IgfiBQcmV5LCBkYXRhID0gRGlubmVyKQ0Kc3VtbWFyeShtb2QpDQpgYGANCg0KVG8gY3JlYXRlIGEgcGVybXV0YXRpb24gdGVzdCwgd2UgY2hvb3NlIGEgcmFuZG9tIHBlcm11dGF0aW9uIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHBhaXIgdGhvc2UgdmFsdWVzIHdpdGggdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlLiBJbiBnZW5lcmFsLCB3ZSBuZWVkIHNldmVyYWwgdGhvdXNhbmQgcGVybXV0YXRpb25zIHRvIGdlbmVyYXRlIGFjY3VyYXRlIHJlc3VsdHMuDQoNCmBgYHtyfQ0KcGVybSA9IGRvKDEwMDAwKSAqIGNvZWYobG0oc2h1ZmZsZShQcmVkYXRvcikgfiBQcmV5LCBkYXRhID0gRGlubmVyKSkNCnBlcm0NCmBgYA0KDQpXZSBhcmUgdGVzdGluZyB0aGUgaHlwb3RoZXNpcyB0aGF0ICQkSF8wIDogXGJldGEgPSAwXFxIX2EgOiBcYmV0YSBcbmVxIDAkJA0KQnkgZW50ZXJpbmcgYSBsb2dpY2FsIGV4cHJlc3Npb24gaW50byB0aGUgZnVuY3Rpb24gKipzdW0qKiwgd2UgY2FuIGNvdW50IHRoZSBudW1iZXIgb2YgcmFuZG9taXplZCBtb2RlbHMgdGhhdCBoYWQgc2xvcGUgZ3JlYXRlciB0aGFuIDAuMDE5OC4NCg0KYGBge3J9DQpzdW0oYWJzKHBlcm0kUHJleSkgPiAwLjAxOTgpDQpgYGANCg0KVGhlIGVzdGltYXRlZCBzaWduaWZpY2FuY2Ugb2YgdGhlIHNsb3BlIGNvZWZmaWNpZW50IGlzICQkcD1cZnJhY3syOH17MTAsMDAwfSA9IDAuMDAyOCQkIHdoaWNoIGlzIHJlYXNvbmFibGUgZ2l2ZW4gd2hhdCB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gJHQkLXRlc3QgcmVzdWx0cyB3ZXJlICgkcCA9IDAuMDAxNiQpLiBXZSB1c2VkIGEgdHdvLXRhaWxlZCB0ZXN0IGJ5IHRha2luZyB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIHNodWZmbGVkIG1vZGVsIHNsb3Blcy4gV2UgY2FuIHJhbmRvbWl6ZSBhIG9uZS10YWlsZWQgdGVzdCBieSByZW1vdmluZyB0aGUgYWJzb2x1dGUgdmFsdWUgYW5kIGFkanVzdGluZyB0aGUgaW5lcXVhbGl0eS4gRWl0aGVyIHdheSwgd2UgaGF2ZSBzdHJvbmcgZXZpZGVuY2UgdGhhdCB0aGUgc2xvcGUgKG9yIGNvcnJlbGF0aW9uKSBpcyBub24temVyby4NCg0KDQojIyBFc3RpbWF0ZXMgb2YgdGhlIFNsb3BlIENvZWZmaWNpZW50DQoNCldlIGNhbiB1c2UgYSBib290c3RyYXBwaW5nIGFwcHJvYWNoIHRvIGVzdGltYXRlIHRoZSBzbG9wZSBjb2VmZmljaWVudCB3aXRoIDk1JSBjb25maWRlbmNlLg0KDQpgYGB7cn0NCmJvb3RzID0gZG8oNTAwKSAqIGNvZWYobG0oUHJlZGF0b3IgfiBQcmV5LCBkYXRhPXJlc2FtcGxlKERpbm5lcikpKQ0KcWRhdGEoYm9vdHMkUHJleSwgYygwLjAyNSwgMC45NzUpKQ0KYGBgDQoNCiMjIEluZGVwZW5kZW50IFNhbXBsZXMgJHQkLXRlc3QNCg0KV2UgY2FuIHBlcm11dGUgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBzbyB0aGF0IGl0cyBhc3NvY2lhdGlvbiB3aXRoIHRoZSBncm91cGluZyB2YXJpYWJsZSBpcyByYW5kb20uDQoNCmBgYHtyfQ0KcGVybSA9IGRvKDEwMDApICogbWVhbihzaHVmZmxlKE51bWJlcikgfiBBbmltYWwsIGRhdGEgPSBab28pDQpwZXJtJGRpZmYgPSBwZXJtJExpb24gLSBwZXJtJFplYnJhDQpwZXJtDQpgYGANCg0KVGhlIG9ic2VydmVkIG1lYW4gZGlmZmVyZW5jZSBpbiB0aGUgYmV0d2VlbiAqKkxpb25zKiogYW5kICoqWmVyYnJhKiogd2FzIDQuIFRvIGVzdGltYXRlIHRoZSAkcCQtdmFsdWUgZm9yIHRoZSBkaWZmZXJlbmNlIGluIG1lYW5zLCB3ZSBuZWVkIHRvIGNvdW50IGhvdyBtYW55IG9mIHRoZSByYW5kb21pemVkIGRpZmZlcmVuY2VzIHdlcmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDQuDQoNCmBgYHtyfQ0Kc3VtKHBlcm0kZGlmZiA+PSA0KQ0KYGBgDQoNClRodXMsIHdlIGhhdmUgYW4gZXN0aW1hdGVkICRwJC12YWx1ZSBvZiAkJHA9XGZyYWN7NH17MTAwMH09MC4wMDQkJCBhbmQsIHRoZXJlZm9yZSwgc3Ryb25nIGV2aWRlbmNlIGZvciBhIGRpZmZlcmVuY2UgaW4gZ3JvdXAgbWVhbnMuDQoNCg0KDQo=