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.
- Shuffle. A permutation, size equal to number of observations.
- Sample. Draws without replacement, size less than or equal to number of observations.
- 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=