Introduction

This document presents a step-by-step demonstration of how the GSDtools package created by Brett Eaton and Dan Moore can be applied to your bed surface grain size data. The package implements the use of binomial sampling theory to estimate percentile confidence ranges, as described by Eaton et. al (in review). The package contains a number of functions to easily visualize the data, but this example focuses on how to generate estimates of the upper and lower confidence bounds, and how to export them for use in a spreadsheet.

Setting up your working environment

We assume that you have already installed the R language on your computer, and that you have a graphical interface in which to run the code we present in this document. To install R, start at the R Project website. We recommend using the R Studio graphical interface to run R code (which can be downloaded here), but you may use whatever interface you are most comfortable with.

Installing the GSDtools package

The GSDtools package is hosted on Brett Eaton’s GitHub page, and is freely accessible to download. To do this, we will use commands in the devtools package. If you have not installed devtools yet, you can simply run the following command.

if("devtools" %in% rownames(installed.packages()) == FALSE) 
  {install.packages("devtools")}

Now we can install the GSDtools package from GitHub.

if("GSDtools" %in% rownames(installed.packages()) == FALSE){
  devtools::install_github("bceaton/GSDtools")}

Finally, we need to tell R that we wish to use the functions in the GSDtools package by running the following command.

At this point, we should be ready to go with our analysis.

Entering the data

Users familiar with R will know that there are various ways of importing data and creating the necessary variables for analysis. To keep things simple, we will enter the grain size data as a string of numbers, the cumulative percent finer data as another string of data, and then combine them into a single table of data called a data.frame in R. The following line of code creates a list of grain size data in the standard Wentworth size classes.

Now lets enter the cumulative proportion finer data that corresponds to each size.

Finally, we combine these two strings of number into a single data frame for analysis.

You can verify that the data match up properly by looking at the table.

print(my.data)

We can also plot the data to ensure that it all looks right.

plot(my.data, type = "b", log = "x", xlim = c(1, 1000))

Estimating the confidence bounds

Once we have a data.frame with the necessary data that has variables called size and probs, we can calculate any percentile of interest (e.g. \(D_{50}\)), and its associated confidence range, but only if we know the number of stones that were measured to define the grain size distribution. Let’s assume that our distribution was based on a Wolman sample of 103 stones.

This can be done for a single percentile as follows:

This produces a data.frame that records the percentile being estimated, the estimate of the percentile, and the upper and lower bounds for that estimate.

print(my.D50)

A more useful example would be to estimate the percentiles between \(D_{10}\) and \(D_{90}\) in increments of 5.

This produces a data.frame with several lines of data, each representing an estimated percentile, along with its confidence interval.

head(my.Dvalues)  #this command only shows the first few lines of data

Exporting the data

To export the data as a .csv file, we simply specify a file name, and run the following command.

The file created by this command will be saved to whatever your working director is. If you don’t know what your working directory is, you can find out by running the command.

getwd()

You can use setwd or the user interface menus to navigate to the directory where you want to save your file. In R Studio, you go first to the Session menu, then to Set Working Directory, and finally you choose Choose Directory.

The file you just generated can be imported into a spreadsheet, and you can generate whatever kind of plots you would like using the data. If you

Visualizing the data

The GSDtools package also includes functions to make it easier to plot the confidence bounds. The key one is PolyCI. Below, we plot the grain size data as before, then add a polygon the represents the confidence interval using the same inputs as were used above to generate my.Dvalues.

{plot(my.data, type = "b", log = "x", xlim = c(1, 1000))
my.polygon = PolyCI(cfd = my.data, n = my.n, P = my.percentile, alpha = my.alpha)
polygon(my.polygon, lty = 0, col = rgb(0,0,1,0.25))  #makes a blue polygon 
abline(h = c(0.1, 0.9), lty = 2)}  #add lines indicating range of confidence interval

Comparing two distributions

There are two tools for comparing samples to determine if they are statistically similar or not. One tool uses raw data comprising measurements of b axis diameters for individual stones. The other tool uses data binned into size classes. We will use a random number generator to produce two samples of raw data to demonstrate the use of the first tool (CompareRAWs), then we will bin that data to produce a cumulative frequency distribution to demonstrate the use of the second tool (CompareCFDs).

We can create two samples as follows:

The CompareRAWs tool uses a re-sampling (with replacement) approach to produce bootstrap confidence intervals for the differences in user-specified percentiles.

first.comparison = CompareRAWs(Raw1,Raw2, P = 50)  #compare the 50th percentile
print(first.comparison)

Hint: You can play around with the sample size (n1 and n2) to figure out when the differences in the 50th percentile are statistically significant, and when they are not.

We can also compare a number of percentiles at the same time.

scnd.comparison = CompareRAWs(Raw1,Raw2, P = seq(10,90,10))  #compare the 50th percentile
print(scnd.comparison)

hint: try running the sample generation code (i.e., Raw1 = 2^rnorm(n1, mean = 4.1, sd = 1)) a few times with the same values and see how the results change.

Usually, we do not have measurements of individual grain sizes, we have binned data. We can transform our samples into cumulative frequency distributions as follows.

GSD1 = MakeCFD(Raw1)
GSD2 = MakeCFD(Raw2)
head(GSD1)  #lets look at first few lines of the results for our first sample

We can use the inverse transform sampling approach to get a bootstrap estimate of the confidence interval for the differences between percentiles using the CompareCFDs tool.

thrd.comparison = CompareCFDs(GSD1, GSD2, n1, n2, P = seq(10,90,10))
print(thrd.comparison)

Because we are using binned data, the CompareCFDs tool will sometimes produce slightly different results than the CompareRAWs tool, but our tests of the tools shows that they are generally produce relatively similar results. The differences are presumably introduced by the act of binning the raw data into 0.5\(\phi\) classes.

LS0tCnRpdGxlOiAiY2FsY3VsYXRpbmcgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHN1cmZhY2UgZ3JhaW4gc2l6ZSBzYW1wbGVzIgphdXRob3I6ICJCcmV0dCBFYXRvbiIKZGF0ZTogIk1heSAyNCwgMjAxOSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IHByZXNlbnRzIGEgc3RlcC1ieS1zdGVwIGRlbW9uc3RyYXRpb24gb2YgaG93IHRoZSBgR1NEdG9vbHNgIHBhY2thZ2UgY3JlYXRlZCBieSBbQnJldHQgRWF0b25dKGh0dHBzOi8vYmxvZ3MudWJjLmNhL2JlYXRvbi8pIGFuZCBbRGFuIE1vb3JlXShodHRwOi8vaWJpcy5nZW9nLnViYy5jYS9+cmRtb29yZS8pIGNhbiBiZSBhcHBsaWVkIHRvIHlvdXIgYmVkIHN1cmZhY2UgZ3JhaW4gc2l6ZSBkYXRhLiBUaGUgcGFja2FnZSBpbXBsZW1lbnRzIHRoZSB1c2Ugb2YgYmlub21pYWwgc2FtcGxpbmcgdGhlb3J5IHRvIGVzdGltYXRlIHBlcmNlbnRpbGUgY29uZmlkZW5jZSByYW5nZXMsIGFzIGRlc2NyaWJlZCBieSBFYXRvbiBldC4gYWwgKGluIHJldmlldykuIFRoZSBwYWNrYWdlIGNvbnRhaW5zIGEgbnVtYmVyIG9mIGZ1bmN0aW9ucyB0byBlYXNpbHkgdmlzdWFsaXplIHRoZSBkYXRhLCBidXQgdGhpcyBleGFtcGxlIGZvY3VzZXMgb24gaG93IHRvIGdlbmVyYXRlIGVzdGltYXRlcyBvZiB0aGUgdXBwZXIgYW5kIGxvd2VyIGNvbmZpZGVuY2UgYm91bmRzLCBhbmQgaG93IHRvIGV4cG9ydCB0aGVtIGZvciB1c2UgaW4gYSBzcHJlYWRzaGVldC4KCiMgU2V0dGluZyB1cCB5b3VyIHdvcmtpbmcgZW52aXJvbm1lbnQKCldlIGFzc3VtZSB0aGF0IHlvdSBoYXZlIGFscmVhZHkgaW5zdGFsbGVkIHRoZSBSIGxhbmd1YWdlIG9uIHlvdXIgY29tcHV0ZXIsIGFuZCB0aGF0IHlvdSBoYXZlIGEgZ3JhcGhpY2FsIGludGVyZmFjZSBpbiB3aGljaCB0byBydW4gdGhlIGNvZGUgd2UgcHJlc2VudCBpbiB0aGlzIGRvY3VtZW50LiBUbyBpbnN0YWxsIFIsIHN0YXJ0IGF0IHRoZSBbUiBQcm9qZWN0XShodHRwczovL3d3dy5yLXByb2plY3Qub3JnLykgd2Vic2l0ZS4gV2UgcmVjb21tZW5kIHVzaW5nIHRoZSBSIFN0dWRpbyBncmFwaGljYWwgaW50ZXJmYWNlIHRvIHJ1biBSIGNvZGUgKHdoaWNoIGNhbiBiZSBkb3dubG9hZGVkIFtoZXJlXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS8pKSwgYnV0IHlvdSBtYXkgdXNlIHdoYXRldmVyIGludGVyZmFjZSAgeW91IGFyZSBtb3N0IGNvbWZvcnRhYmxlIHdpdGguCgojIyBJbnN0YWxsaW5nIHRoZSBHU0R0b29scyBwYWNrYWdlClRoZSBgR1NEdG9vbHNgIHBhY2thZ2UgaXMgaG9zdGVkIG9uIEJyZXR0IEVhdG9uJ3MgR2l0SHViIHBhZ2UsIGFuZCBpcyBmcmVlbHkgYWNjZXNzaWJsZSB0byBkb3dubG9hZC4gVG8gZG8gdGhpcywgd2Ugd2lsbCB1c2UgY29tbWFuZHMgaW4gdGhlIGBkZXZ0b29sc2AgcGFja2FnZS4gSWYgeW91IGhhdmUgbm90IGluc3RhbGxlZCBgZGV2dG9vbHNgIHlldCwgeW91IGNhbiBzaW1wbHkgcnVuIHRoZSBmb2xsb3dpbmcgY29tbWFuZC4KCmBgYHtyfQppZigiZGV2dG9vbHMiICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpID09IEZBTFNFKXsKICBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpfQpgYGAKCk5vdyB3ZSBjYW4gaW5zdGFsbCB0aGUgYEdTRHRvb2xzYCBwYWNrYWdlIGZyb20gR2l0SHViLgoKYGBge3J9CmlmKCJHU0R0b29scyIgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkgPT0gRkFMU0UpewogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiYmNlYXRvbi9HU0R0b29scyIpfQpgYGAKCkZpbmFsbHksIHdlIG5lZWQgdG8gdGVsbCBSIHRoYXQgd2Ugd2lzaCB0byB1c2UgdGhlIGZ1bmN0aW9ucyBpbiB0aGUgYEdTRHRvb2xzYCBwYWNrYWdlIGJ5IHJ1bm5pbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kLgoKYGBge3J9CmxpYnJhcnkoR1NEdG9vbHMpCmBgYAoKQXQgdGhpcyBwb2ludCwgd2Ugc2hvdWxkIGJlIHJlYWR5IHRvIGdvIHdpdGggb3VyIGFuYWx5c2lzLgoKIyBFbnRlcmluZyB0aGUgZGF0YQpVc2VycyBmYW1pbGlhciB3aXRoIFIgd2lsbCBrbm93IHRoYXQgdGhlcmUgYXJlIHZhcmlvdXMgd2F5cyBvZiBpbXBvcnRpbmcgZGF0YSBhbmQgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSB2YXJpYWJsZXMgZm9yIGFuYWx5c2lzLiBUbyBrZWVwIHRoaW5ncyBzaW1wbGUsIHdlIHdpbGwgZW50ZXIgdGhlIGdyYWluIHNpemUgZGF0YSBhcyBhIHN0cmluZyBvZiBudW1iZXJzLCB0aGUgY3VtdWxhdGl2ZSBwZXJjZW50IGZpbmVyIGRhdGEgYXMgYW5vdGhlciBzdHJpbmcgb2YgZGF0YSwgYW5kIHRoZW4gY29tYmluZSB0aGVtIGludG8gYSBzaW5nbGUgdGFibGUgb2YgZGF0YSBjYWxsZWQgYSBgZGF0YS5mcmFtZWAgaW4gUi4gVGhlIGZvbGxvd2luZyBsaW5lIG9mIGNvZGUgY3JlYXRlcyBhIGxpc3Qgb2YgZ3JhaW4gc2l6ZSBkYXRhIGluIHRoZSBzdGFuZGFyZCBXZW50d29ydGggc2l6ZSBjbGFzc2VzLgoKYGBge3J9CnNpemUgPSBjKDI1NiwgMTgyLCAxMjgsIDkwLCA2NCwgNDUsIDMyLCAyMi42LCAxNiwgMTEuMywgOCwgNS42LCA0KQpgYGAKCk5vdyBsZXRzIGVudGVyIHRoZSBjdW11bGF0aXZlIHByb3BvcnRpb24gZmluZXIgZGF0YSB0aGF0IGNvcnJlc3BvbmRzIHRvIGVhY2ggc2l6ZS4KCmBgYHtyfQpwcm9icyA9IGMoMS4wMCwgMC45NywgMC44MywgMC43NiwgMC42MywgMC41MywgMC40MywgMC4zMiwgMC4yMSwgMC4xNSwgMC4xLCAwLjA1LCAwKQpgYGAKCkZpbmFsbHksIHdlIGNvbWJpbmUgdGhlc2UgdHdvIHN0cmluZ3Mgb2YgbnVtYmVyIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZSBmb3IgYW5hbHlzaXMuCgpgYGB7cn0KbXkuZGF0YSA9IGRhdGEuZnJhbWUoc2l6ZSwgcHJvYnMpCmBgYAoKWW91IGNhbiB2ZXJpZnkgdGhhdCB0aGUgZGF0YSBtYXRjaCB1cCBwcm9wZXJseSBieSBsb29raW5nIGF0IHRoZSB0YWJsZS4KCmBgYHtyfQpwcmludChteS5kYXRhKQpgYGAKCldlIGNhbiBhbHNvIHBsb3QgdGhlIGRhdGEgdG8gZW5zdXJlIHRoYXQgaXQgYWxsIGxvb2tzIHJpZ2h0LgoKYGBge3J9CnBsb3QobXkuZGF0YSwgdHlwZSA9ICJiIiwgbG9nID0gIngiLCB4bGltID0gYygxLCAxMDAwKSkKYGBgCgoKIyBFc3RpbWF0aW5nIHRoZSBjb25maWRlbmNlIGJvdW5kcwpPbmNlIHdlIGhhdmUgYSBgZGF0YS5mcmFtZWAgd2l0aCB0aGUgbmVjZXNzYXJ5IGRhdGEgdGhhdCBoYXMgdmFyaWFibGVzIGNhbGxlZCBgc2l6ZWAgYW5kIGBwcm9ic2AsIHdlIGNhbiBjYWxjdWxhdGUgYW55IHBlcmNlbnRpbGUgb2YgaW50ZXJlc3QgKGUuZy4gJERfezUwfSQpLCBhbmQgaXRzIGFzc29jaWF0ZWQgY29uZmlkZW5jZSByYW5nZSwgYnV0IG9ubHkgaWYgd2Uga25vdyB0aGUgbnVtYmVyIG9mIHN0b25lcyB0aGF0IHdlcmUgbWVhc3VyZWQgdG8gZGVmaW5lIHRoZSBncmFpbiBzaXplIGRpc3RyaWJ1dGlvbi4gTGV0J3MgYXNzdW1lIHRoYXQgb3VyIGRpc3RyaWJ1dGlvbiB3YXMgYmFzZWQgb24gYSBXb2xtYW4gc2FtcGxlIG9mIDEwMyBzdG9uZXMuCgpgYGB7cn0KbXkubiA9IDEwMwpgYGAKClRoaXMgY2FuIGJlIGRvbmUgZm9yIGEgc2luZ2xlIHBlcmNlbnRpbGUgYXMgZm9sbG93czoKCmBgYHtyfQpteS5wZXJjZW50aWxlID0gNTAgICNlc3RpbWF0ZSB0aGUgNTB0aCBwZXJjZW50aWxlCm15LmFscGhhID0gMC4wNSAgI3NldCB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCB0byBjb3ZlciA5NSUgb2YgdGhlIGRhdGEKbXkuRDUwID0gV29sbWFuQ0koY2ZkID0gbXkuZGF0YSwgbiA9IG15Lm4sIFAgPSBteS5wZXJjZW50aWxlLCBhbHBoYSA9IG15LmFscGhhKQpgYGAKClRoaXMgcHJvZHVjZXMgYSBgZGF0YS5mcmFtZWAgdGhhdCByZWNvcmRzIHRoZSBwZXJjZW50aWxlIGJlaW5nIGVzdGltYXRlZCwgdGhlIGVzdGltYXRlIG9mIHRoZSBwZXJjZW50aWxlLCBhbmQgdGhlIHVwcGVyIGFuZCBsb3dlciBib3VuZHMgZm9yIHRoYXQgZXN0aW1hdGUuCgpgYGB7cn0KcHJpbnQobXkuRDUwKQpgYGAKCkEgbW9yZSB1c2VmdWwgZXhhbXBsZSB3b3VsZCBiZSB0byBlc3RpbWF0ZSB0aGUgcGVyY2VudGlsZXMgYmV0d2VlbiAkRF97MTB9JCBhbmQgJERfezkwfSQgaW4gaW5jcmVtZW50cyBvZiA1LgoKYGBge3J9Cm15LnBlcmNlbnRpbGUgPSBjKDEwLCAxNSwgMjAsIDI1LCAzMCwgMzUsIDQwLCA0NSwgNTAsIAogICAgICAgICAgICAgNTUsIDYwLCA2NSwgNzAsIDc1LCA4MCwgODUsIDkwKQoKIyAgQWx0ZXJuYXRpdmUgY29kZSB0byBnZW5lcmF0ZSB5b3UgbGlzdCBvZiBwZXJjZW50aWxlcyB0byBlc3RpbWF0ZQojbXkucGVyY2VudGlsZXMgPSBzZXEoZnJvbSA9IDEwLCB0byA9IDkwLCBieSA9IDUpICAjZG9lcyB0aGUgc2FtZSB0aGluZyBhcyBhYm92ZQojbXkucGVyY2VudGlsZSA9IHNlcShmcm9tID0gMSwgdG8gPSA5MCwgYnkgPSAxKSAgI2dlbmVyYXRlcyBhbGwgcGVyY2VudGlsZXMsIDEwIHRvIDkwCgpteS5EdmFsdWVzID0gV29sbWFuQ0koY2ZkID0gbXkuZGF0YSwgbiA9IG15Lm4sIFAgPSBteS5wZXJjZW50aWxlLCBhbHBoYSA9IG15LmFscGhhKQpgYGAKClRoaXMgcHJvZHVjZXMgYSBgZGF0YS5mcmFtZWAgd2l0aCBzZXZlcmFsIGxpbmVzIG9mIGRhdGEsIGVhY2ggcmVwcmVzZW50aW5nIGFuIGVzdGltYXRlZCBwZXJjZW50aWxlLCBhbG9uZyB3aXRoIGl0cyBjb25maWRlbmNlIGludGVydmFsLgoKYGBge3J9CmhlYWQobXkuRHZhbHVlcykgICN0aGlzIGNvbW1hbmQgb25seSBzaG93cyB0aGUgZmlyc3QgZmV3IGxpbmVzIG9mIGRhdGEKYGBgCgojIEV4cG9ydGluZyB0aGUgZGF0YQpUbyBleHBvcnQgdGhlIGRhdGEgYXMgYSBgLmNzdmAgZmlsZSwgd2Ugc2ltcGx5IHNwZWNpZnkgYSBmaWxlIG5hbWUsIGFuZCBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kLgpgYGB7cn0KbXkuZmlsZSA9ICJzYW1wbGVfZGF0YS5jc3YiCndyaXRlLnRhYmxlKG15LkR2YWx1ZXMsIG15LmZpbGUsIHJvdy5uYW1lcyA9IEYsIHNlcCA9ICIsIikKYGBgCgpUaGUgZmlsZSBjcmVhdGVkIGJ5IHRoaXMgY29tbWFuZCB3aWxsIGJlIHNhdmVkIHRvIHdoYXRldmVyIHlvdXIgd29ya2luZyBkaXJlY3RvciBpcy4gSWYgeW91IGRvbid0IGtub3cgd2hhdCB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IGlzLCB5b3UgY2FuIGZpbmQgb3V0IGJ5IHJ1bm5pbmcgdGhlIGNvbW1hbmQuCgpgYGB7cn0KZ2V0d2QoKQpgYGAKCgpZb3UgY2FuIHVzZSBgc2V0d2RgIG9yIHRoZSB1c2VyIGludGVyZmFjZSBtZW51cyB0byBuYXZpZ2F0ZSB0byB0aGUgZGlyZWN0b3J5IHdoZXJlIHlvdSB3YW50IHRvIHNhdmUgeW91ciBmaWxlLiBJbiBgUiBTdHVkaW9gLCB5b3UgZ28gZmlyc3QgdG8gdGhlIGBTZXNzaW9uYCBtZW51LCB0aGVuIHRvIGBTZXQgV29ya2luZyBEaXJlY3RvcnlgLCBhbmQgZmluYWxseSB5b3UgY2hvb3NlIGBDaG9vc2UgRGlyZWN0b3J5YC4KClRoZSBmaWxlIHlvdSBqdXN0IGdlbmVyYXRlZCBjYW4gYmUgaW1wb3J0ZWQgaW50byBhIHNwcmVhZHNoZWV0LCBhbmQgeW91IGNhbiBnZW5lcmF0ZSB3aGF0ZXZlciBraW5kIG9mIHBsb3RzIHlvdSB3b3VsZCBsaWtlIHVzaW5nIHRoZSBkYXRhLiAgSWYgeW91CgojIFZpc3VhbGl6aW5nIHRoZSBkYXRhClRoZSBgR1NEdG9vbHNgIHBhY2thZ2UgYWxzbyBpbmNsdWRlcyBmdW5jdGlvbnMgdG8gbWFrZSBpdCBlYXNpZXIgdG8gcGxvdCB0aGUgY29uZmlkZW5jZSBib3VuZHMuIFRoZSBrZXkgb25lIGlzIGBQb2x5Q0lgLiBCZWxvdywgd2UgcGxvdCB0aGUgZ3JhaW4gc2l6ZSBkYXRhIGFzIGJlZm9yZSwgdGhlbiBhZGQgYSBwb2x5Z29uIHRoZSByZXByZXNlbnRzIHRoZSBjb25maWRlbmNlIGludGVydmFsIHVzaW5nIHRoZSBzYW1lIGlucHV0cyBhcyB3ZXJlIHVzZWQgYWJvdmUgdG8gZ2VuZXJhdGUgYG15LkR2YWx1ZXNgLiAKYGBge3J9CntwbG90KG15LmRhdGEsIHR5cGUgPSAiYiIsIGxvZyA9ICJ4IiwgeGxpbSA9IGMoMSwgMTAwMCkpCm15LnBvbHlnb24gPSBQb2x5Q0koY2ZkID0gbXkuZGF0YSwgbiA9IG15Lm4sIFAgPSBteS5wZXJjZW50aWxlLCBhbHBoYSA9IG15LmFscGhhKQpwb2x5Z29uKG15LnBvbHlnb24sIGx0eSA9IDAsIGNvbCA9IHJnYigwLDAsMSwwLjI1KSkgICNtYWtlcyBhIGJsdWUgcG9seWdvbiAKYWJsaW5lKGggPSBjKDAuMSwgMC45KSwgbHR5ID0gMil9ICAjYWRkIGxpbmVzIGluZGljYXRpbmcgcmFuZ2Ugb2YgY29uZmlkZW5jZSBpbnRlcnZhbApgYGAKCiMgQ29tcGFyaW5nIHR3byBkaXN0cmlidXRpb25zCgpUaGVyZSBhcmUgdHdvIHRvb2xzIGZvciBjb21wYXJpbmcgc2FtcGxlcyB0byBkZXRlcm1pbmUgaWYgdGhleSBhcmUgc3RhdGlzdGljYWxseSBzaW1pbGFyIG9yIG5vdC4gT25lIHRvb2wgdXNlcyByYXcgZGF0YSBjb21wcmlzaW5nIG1lYXN1cmVtZW50cyBvZiBiIGF4aXMgZGlhbWV0ZXJzIGZvciBpbmRpdmlkdWFsIHN0b25lcy4gVGhlIG90aGVyIHRvb2wgdXNlcyBkYXRhIGJpbm5lZCBpbnRvIHNpemUgY2xhc3Nlcy4gV2Ugd2lsbCB1c2UgYSByYW5kb20gbnVtYmVyIGdlbmVyYXRvciB0byBwcm9kdWNlIHR3byBzYW1wbGVzIG9mIHJhdyBkYXRhIHRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdGhlIGZpcnN0IHRvb2wgKGBDb21wYXJlUkFXc2ApLCB0aGVuIHdlIHdpbGwgYmluIHRoYXQgZGF0YSB0byBwcm9kdWNlIGEgY3VtdWxhdGl2ZSBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uIHRvIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgdGhlIHNlY29uZCB0b29sIChgQ29tcGFyZUNGRHNgKS4KCldlIGNhbiBjcmVhdGUgdHdvIHNhbXBsZXMgYXMgZm9sbG93czoKCmBgYHtyfQpuMSA9IDE5NSAgI2RldGVybWluZSB0aGUgbnVtYmVyIG9mICJtZWFzdXJlbWVudHMiIHRvIG1ha2UgZm9yIHNhbXBsZSAxClJhdzEgPSAyXnJub3JtKG4xLCBtZWFuID0gNC4xLCBzZCA9IDEpICAjZ2VuZXJhdGUgYSBsb2ctbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoIHNwZWMuIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbgpuMiA9IDIwMyAgI251bWJlciBvZiBtZWFzdXJlbWVudHMsIHNhbXBsZSAyClJhdzIgPSAyXnJub3JtKG4yLCBtZWFuID0gNC4zLCBzZCA9IDEpICAjbG9nLW5vcm1hbCBkaXN0cmlidXRpb24sIGRpZmZlcmVudCBtZWFuCmBgYAoKVGhlIGBDb21wYXJlUkFXc2AgdG9vbCB1c2VzIGEgcmUtc2FtcGxpbmcgKHdpdGggcmVwbGFjZW1lbnQpIGFwcHJvYWNoIHRvIHByb2R1Y2UgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGZvciB0aGUgZGlmZmVyZW5jZXMgaW4gdXNlci1zcGVjaWZpZWQgcGVyY2VudGlsZXMuCgpgYGB7cn0KZmlyc3QuY29tcGFyaXNvbiA9IENvbXBhcmVSQVdzKFJhdzEsUmF3MiwgUCA9IDUwKSAgI2NvbXBhcmUgdGhlIDUwdGggcGVyY2VudGlsZQpwcmludChmaXJzdC5jb21wYXJpc29uKQpgYGAKSGludDogWW91IGNhbiBwbGF5IGFyb3VuZCB3aXRoIHRoZSBzYW1wbGUgc2l6ZSAoYG4xYCBhbmQgYG4yYCkgdG8gZmlndXJlIG91dCB3aGVuIHRoZSBkaWZmZXJlbmNlcyBpbiB0aGUgNTB0aCBwZXJjZW50aWxlIGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBhbmQgd2hlbiB0aGV5IGFyZSBub3QuCgpXZSBjYW4gYWxzbyBjb21wYXJlIGEgbnVtYmVyIG9mIHBlcmNlbnRpbGVzIGF0IHRoZSBzYW1lIHRpbWUuCgpgYGB7cn0Kc2NuZC5jb21wYXJpc29uID0gQ29tcGFyZVJBV3MoUmF3MSxSYXcyLCBQID0gc2VxKDEwLDkwLDEwKSkgICNjb21wYXJlIHRoZSA1MHRoIHBlcmNlbnRpbGUKcHJpbnQoc2NuZC5jb21wYXJpc29uKQpgYGAKaGludDogdHJ5IHJ1bm5pbmcgdGhlIHNhbXBsZSBnZW5lcmF0aW9uIGNvZGUgKGkuZS4sIGBSYXcxID0gMl5ybm9ybShuMSwgbWVhbiA9IDQuMSwgc2QgPSAxKWApIGEgZmV3IHRpbWVzIHdpdGggdGhlIHNhbWUgdmFsdWVzIGFuZCBzZWUgaG93IHRoZSByZXN1bHRzIGNoYW5nZS4KClVzdWFsbHksIHdlIGRvIG5vdCBoYXZlIG1lYXN1cmVtZW50cyBvZiBpbmRpdmlkdWFsIGdyYWluIHNpemVzLCB3ZSBoYXZlIGJpbm5lZCBkYXRhLiBXZSBjYW4gdHJhbnNmb3JtIG91ciBzYW1wbGVzIGludG8gY3VtdWxhdGl2ZSBmcmVxdWVuY3kgZGlzdHJpYnV0aW9ucyBhcyBmb2xsb3dzLgoKYGBge3J9CkdTRDEgPSBNYWtlQ0ZEKFJhdzEpCkdTRDIgPSBNYWtlQ0ZEKFJhdzIpCmhlYWQoR1NEMSkgICNsZXRzIGxvb2sgYXQgZmlyc3QgZmV3IGxpbmVzIG9mIHRoZSByZXN1bHRzIGZvciBvdXIgZmlyc3Qgc2FtcGxlCmBgYAoKV2UgY2FuIHVzZSB0aGUgaW52ZXJzZSB0cmFuc2Zvcm0gc2FtcGxpbmcgYXBwcm9hY2ggdG8gZ2V0IGEgYm9vdHN0cmFwIGVzdGltYXRlIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBwZXJjZW50aWxlcyB1c2luZyB0aGUgYENvbXBhcmVDRkRzYCB0b29sLgoKYGBge3J9CnRocmQuY29tcGFyaXNvbiA9IENvbXBhcmVDRkRzKEdTRDEsIEdTRDIsIG4xLCBuMiwgUCA9IHNlcSgxMCw5MCwxMCkpCnByaW50KHRocmQuY29tcGFyaXNvbikKYGBgCkJlY2F1c2Ugd2UgYXJlIHVzaW5nIGJpbm5lZCBkYXRhLCB0aGUgYENvbXBhcmVDRkRzYCB0b29sIHdpbGwgc29tZXRpbWVzIHByb2R1Y2Ugc2xpZ2h0bHkgZGlmZmVyZW50IHJlc3VsdHMgdGhhbiB0aGUgYENvbXBhcmVSQVdzYCB0b29sLCBidXQgb3VyIHRlc3RzIG9mIHRoZSB0b29scyBzaG93cyB0aGF0IHRoZXkgYXJlIGdlbmVyYWxseSBwcm9kdWNlIHJlbGF0aXZlbHkgc2ltaWxhciByZXN1bHRzLiBUaGUgZGlmZmVyZW5jZXMgYXJlIHByZXN1bWFibHkgaW50cm9kdWNlZCBieSB0aGUgYWN0IG9mIGJpbm5pbmcgdGhlIHJhdyBkYXRhIGludG8gMC41JFxwaGkkIGNsYXNzZXMuCg==