<<BACK

My unofficial mantra:

Adam Savage via Pintrest

“Adam Savage via Pintrest”

Data is a fundamental part of ‘doing science’ and spreadsheets are an important, perfectly valid1, tool for inputting and organizing your data.

What not to do with Excel

This title sounds negative, but I think by first showing you what not to do will help you use Excel (and other spreadsheet software) appropriately

Be wary of dates

Excel is great for data entry, but as soon as you attempt more than rudimentary statistical analyses or data visualizations, it quickly becomes less than optimal. The options for these are rather limited and the details of how you calculated these things are hidden in cells or figure options. Worse yet, it does things to ‘help’ you, such as auto-formatting dates, which can be tremendously problematic if it goes unnoticed. For example, this article on how 1 in 5 genetics papers may have and Excel induced error. This kind of thing gives me nightmares!

Pro-Tip

While there are many correct ways to input your dates into Excel, I find that the best2 way is to split it information over multiple columns. Either year, month, and day, or even better year, and DayOfYear (i.e. 1 to 365). See here for more info on converting date formatting in Excel.

Keep your data tidy

(tldr: tidy data = quality of life improved)

The ‘tidy’ concept is something we will revisit in the R section, but the rules of tidy data are3:

  1. Each variable you measure should be in one column
  2. Each different observation of that variable should be in a different row
  3. There should be one table for each “kind” of variable
  4. If you have multiple tables, they should include a column in the table that allows them to be linked

Pro-Tips

  • In practice, these rules generally translate into keeping your data ‘square’ (or rectangular), and not having multiple tables within one spreadsheet.
  • locationID, or organismID make great unique identifiers for ‘linking’ tables as per rule 4

Following these rules makes your data more human and machine readable. In my opinion the first 2 rules (and the 4th if you have multiple tables) are totally non-negotiable. Rule 3 for me is a little fuzzy since “kind” is a little ambiguous in my mind, and doesn’t mesh with what I consider ‘best-practice’. My rule of thumb is that if data were collected at the same spatial and temporal scales, they will be going into 1 table. For example, conductivity (salinity), temperature, and depth of the ocean data from a CTD is often recorded at the exact same time and place since all 3 sensors are built into the same instrument. Therefore, I would keep conductivity, temperature, and depth of the ocean in 1 table since I would otherwise be repeating identical time/space data. Conversely, a sample from a plankton net will not have the same temporal resolution as a CTD therefore should be in different tables, but these instruments can sample the same site so locationID would make a great column to link between tables.

NEVER save as .xls or .xlsx (seriously)

(tldr: re-read the title, it’s the most important rule!!!)

In science, it is important to write everything down (see Adam above), but it is also just as important very important to be able to read what you have written! Excel by default will save your spreadsheet in it’s proprietary format, which means that if you don’t have Excel you can’t read your file4! This is also not just a rule about Excel, but rather any proprietary software. Always save in an open format rather than a proprietary format.*

Pro-Tip

If you have entered your data in an Excel spreadsheet, simply click on ‘Save As’ and select type ‘CSV (Comma delimited)’

I recommend that everyone should save their data as a .csv (stands for comma separated values, the name of the format gives you a clue as to how the data is formatted!) instead of .xlsx because:

  1. It’s easy to do
  2. You can still use Excel to enter your data
  3. It’s stored as a simple text file and is nearly universally readable
  4. It avoids common Excel pitfalls

These pitfalls are an interesting point. How many times have you used:

  • cell color (or bold text, etc) to convey information
  • multiple tabs
  • comments (the bubble inserts)

All these things are big no-no’s since they will likely get scrambled, or not appear at all if you try to open in anything but Excel. Saving as .csv is a self reinforcing guarantee that you do not use these things since it will not save them. Multiple tabs should be multiple files, and comments (plus any other information encoded by special formatting) should be recorded in columns reserved for that use.

EXERCISE

  • Open new spreadsheet in Excel, write a few rows of data into your spreadsheet and save your file as both a .csv and a .xlsx.
  • Close Excel
  • Open both files using Excel
  • Open both files using a basic text editor (e.g. Notepad on Windows, or TextEdit on Mac) Do the files look identical in Excel? In the text editor? Which format seems better to you and why?

Don’t re-invent the wheel

For column headers CHONe recommends you use the Darwin Core Terms It contains helpful information about how to use standard column headers. It will help others (and yourself a few months after writing your data) understand your data. It also will streamline the process when you submit your data to be archived with OBIS.

Some common ones you will all likely use are for date/time: year, month, day, eventTime, eventDate, or for location: locationID, decimalLongitude and decimalLatitude.

For latitude and longitude, it’s better to write: -41.0983423 and -121.1761111 and NOT: 47° 33’ 37.9404’‘N and 52° 42’ 46.1880’‘W because the decimal version will be easier for the computer to read and it is ’according to standard’!

Foreventdate here are a few examples: - 1963-03-08T14:07-0600 is 8 Mar 1963 2:07pm in the time zone six hours earlier than UTC - 2009-02-20T08:40Z is 20 Feb 2009 8:40am UTC - 1809-02-12 is 12 Feb 1809 - 1906-06 is Jun 1906 - 1971 is just that year - 2007-03-01T13:00:00Z/2008-05-11T15:30:00Z is the interval between 1 Mar 2007 1pm UTC and 11 May 2008 3:30pm UTC - 2007-11-13/15 is the interval between 13 Nov 2007 and 15 Nov 2007.

But I am personally uneasy about typing all of that into Excel, it may try to reinterpret what you wrote while trying to ‘help’ you. I would recommend keeping that information separated into the year, month, day, and eventTime columns

  • year : 2008
  • month : 1 (not “January”)
  • day: 28
  • eventTime: “14:07-0600” is 2:07pm in the time zone six hours earlier than UTC
  • eventTime: “08:40:21Z” is 8:40:21am UTC
  • eventTime: “13:00:00Z/15:30:00Z” is the interval between 1pm UTC and 3:30pm UTC.

That way you are still following the standard, yet keeping Excel’s eccentricities at bay and as a bonus, I think it’s easier to work with the pre-separated variables in R. You can also generate an evenDate column in R by pasting all the rows together. (If the code below seems like gibberish, that’s totally OK, we will explain all the steps when we get into R in the later lessons, just remember this code is here!)

require(tidyverse)
data <- data.frame(
    year = c(2008,2003,2009),
    month = c(1,2,3),
    day = c(28,12,12),
    eventTime = c("12:00-0600","01:15-0600","14:07-0600")
)

# you may notice that my year, month, and day columns are numeric and won't have the require leading 0's
# we can fix that with sprintf:
sprintf("%02d",data$month)

# here's a 'one-liner' that will add leading zeros, paste all the columns together, and seperate them by the required '-'

data <- data %>% 
    mutate(eventDate=paste(sprintf("%04d",year),
                           sprintf("%02d",month),
                           sprintf("%02d",day),
                           eventTime,
                           sep="-")
           )

data

Or alternatively, if you’re like me and want to keep the time numeric for ease of programming, consider this (but be sure to recreate an eventTime that includes time zone information):

data <- data.frame(
    year = c(2008,2003,2009),
    month = c(1,2,3),
    day = c(28,12,12),
    hour = c(12,1,14),
    minute = c(0,15,7)
)

data <- data %>% 
    mutate(eventTime=paste0(sprintf("%02d",hour),
                            ":",
                            sprintf("%02d",minute),
                            "-0600")
           )

data

Avoid other common headaches

  • Not filling in zeros
  • Using problematic null values
  • Using problematic field names
  • Using special characters in data

Zeros and null values are very different computationally and statistically! A zero is when you measured a 0, so that is useful information, and a null value is when there is no data, no information (e.g. measurement was not taken or was lost). Zeros should always be recorded 0 while null values are a bit trickier; either leaving the cell blank or inserting an NA are usually the least problematic options.

Many of the statistical software options are very fussy about spaces, periods, and slashes in field names (column headers). Underscores (_) are a good alternative to spaces. Consider writing names in camel case (like this: ExampleFileName) to improve readability. Remember that abbreviations that make sense at the moment may not be so obvious in 6 months, but don’t overdo it with names that are excessively long. Including the units in the field names avoids confusion and enables others to readily interpret your fields. Also, as always, check the standard (Darwin Core Terms) in case you should be using something specific, these are just general instructions for when yo need to make a new column name.

Examples

Good Name Good Alternative Avoid
Max_temp_C MaxTemp Maximum Temp (°C)
Precipitation_mm Precipitation precmm
Mean_year_growth MeanYearGrowth Mean growth/year
sex sex M/F
weight weight w.
cell_type CellType Cell Type
Observation_01 first_observation 1st Obs

  1. You may have heard some people, including myself, express great frustration regarding spreadsheet programs, namely MS Excel. This is not because Excel in itself is problematic to the process of good reproducible science, but rather the problem is that it is often misused! This problem is not unique to Excel, but rather these issues crop up in all spreadsheet programs. I’ll refer to Excel throughout the lesson referring to spreadsheet programs in general. More on this here.

  2. By ‘best’ I mean that it avoids the common Excel problems and doesn’t cause any problems in any downstream analysis in R or other.

  3. Jeff Leek, The Elements of Data Analytic Style, Leanpub, 2015-03-02

  4. OK, I know there are other ways of opening an Excel file, but there is still an interoperability problem. Weird, unexpected things can often happen (e.g. again, dates!) when opening Excel files using alternative software (e.g. Open Office). Additionally, the proprietary Excel format changes over time, you may not be able to open old data files in the future.

LS0tDQp0aXRsZTogIkRhdGEgb3JnYW5pemF0aW9uIHdpdGggc3ByZWFkc2hlZXRzIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQotLS0NCls8PEJBQ0tdKGh0dHBzOi8vcmVtaS1kYWlnbGUuZ2l0aHViLmlvLzIwMTctQ0hPTmUtRGF0YS8pDQoNCk15IHVub2ZmaWNpYWwgbWFudHJhOg0KDQohWyJBZGFtIFNhdmFnZSB2aWEgUGludHJlc3QiXShodHRwczovL3MtbWVkaWEtY2FjaGUtYWswLnBpbmltZy5jb20vNTY0eC9lOS9mMi8xOS9lOWYyMTlkY2UzMGYxMzY3MDE1ODgzMjMxMGIwZTQyYy5qcGcpDQoNCg0KRGF0YSBpcyBhIGZ1bmRhbWVudGFsIHBhcnQgb2YgJ2RvaW5nIHNjaWVuY2UnIGFuZCBzcHJlYWRzaGVldHMgYXJlIGFuIGltcG9ydGFudCwgcGVyZmVjdGx5IHZhbGlkW14xXSwgdG9vbCBmb3IgaW5wdXR0aW5nIGFuZCBvcmdhbml6aW5nIHlvdXIgZGF0YS4gDQoNClteMV06IFlvdSBtYXkgaGF2ZSBoZWFyZCBzb21lIHBlb3BsZSwgaW5jbHVkaW5nIG15c2VsZiwgZXhwcmVzcyBncmVhdCBmcnVzdHJhdGlvbiByZWdhcmRpbmcgc3ByZWFkc2hlZXQgcHJvZ3JhbXMsIG5hbWVseSBNUyBFeGNlbC4gVGhpcyBpcyBub3QgYmVjYXVzZSBFeGNlbCBpbiBpdHNlbGYgaXMgcHJvYmxlbWF0aWMgdG8gdGhlIHByb2Nlc3Mgb2YgZ29vZCByZXByb2R1Y2libGUgc2NpZW5jZSwgYnV0IHJhdGhlciB0aGUgcHJvYmxlbSBpcyB0aGF0IGl0IGlzIG9mdGVuIG1pc3VzZWQhIFRoaXMgcHJvYmxlbSBpcyBub3QgdW5pcXVlIHRvIEV4Y2VsLCBidXQgcmF0aGVyIHRoZXNlIGlzc3VlcyBjcm9wIHVwIGluIGFsbCBzcHJlYWRzaGVldCBwcm9ncmFtcy4gSSdsbCByZWZlciB0byBFeGNlbCB0aHJvdWdob3V0IHRoZSBsZXNzb24gcmVmZXJyaW5nIHRvIHNwcmVhZHNoZWV0IHByb2dyYW1zIGluIGdlbmVyYWwuIE1vcmUgb24gdGhpcyBbaGVyZV0oZmlsZTovLy9DOi9Vc2Vycy9SZW1pLVdvcmsvRGVza3RvcC8yMDE3LUNIT05lLURhdGEvb3JnYW5pemF0aW9uLm5iLmh0bWwjMV93aGF0X25vdF90b19kb193aXRoX2V4Y2VsKS4NCg0KIyBXaGF0IG5vdCB0byBkbyB3aXRoIEV4Y2VsDQoNClRoaXMgdGl0bGUgc291bmRzIG5lZ2F0aXZlLCBidXQgSSB0aGluayBieSBmaXJzdCBzaG93aW5nIHlvdSB3aGF0IG5vdCB0byBkbyB3aWxsIGhlbHAgeW91IHVzZSBFeGNlbCAoYW5kIG90aGVyIHNwcmVhZHNoZWV0IHNvZnR3YXJlKSBhcHByb3ByaWF0ZWx5DQoNCiMjIEJlIHdhcnkgb2YgZGF0ZXMNCg0KRXhjZWwgaXMgZ3JlYXQgZm9yIGRhdGEgZW50cnksIGJ1dCBhcyBzb29uIGFzIHlvdSBhdHRlbXB0IG1vcmUgdGhhbiBydWRpbWVudGFyeSBzdGF0aXN0aWNhbCBhbmFseXNlcyBvciBkYXRhIHZpc3VhbGl6YXRpb25zLCBpdCBxdWlja2x5IGJlY29tZXMgbGVzcyB0aGFuIG9wdGltYWwuIFRoZSBvcHRpb25zIGZvciB0aGVzZSBhcmUgcmF0aGVyIGxpbWl0ZWQgYW5kIHRoZSBkZXRhaWxzIG9mIGhvdyB5b3UgY2FsY3VsYXRlZCB0aGVzZSB0aGluZ3MgYXJlIGhpZGRlbiBpbiBjZWxscyBvciBmaWd1cmUgb3B0aW9ucy4gV29yc2UgeWV0LCBpdCBkb2VzIHRoaW5ncyB0byAnaGVscCcgeW91LCBzdWNoIGFzIGF1dG8tZm9ybWF0dGluZyBkYXRlcywgd2hpY2ggY2FuIGJlIHRyZW1lbmRvdXNseSBwcm9ibGVtYXRpYyBpZiBpdCBnb2VzIHVubm90aWNlZC4gRm9yIGV4YW1wbGUsIFt0aGlzIGFydGljbGVdKGh0dHBzOi8vd3d3Lndhc2hpbmd0b25wb3N0LmNvbS9uZXdzL3dvbmsvd3AvMjAxNi8wOC8yNi9hbi1hbGFybWluZy1udW1iZXItb2Ytc2NpZW50aWZpYy1wYXBlcnMtY29udGFpbi1leGNlbC1lcnJvcnMvP3Bvc3RzaGFyZT00MTYxNDcyMjExMjU1NzQwJnRpZD1zc190dykgb24gaG93IDEgaW4gNSBnZW5ldGljcyBwYXBlcnMgbWF5IGhhdmUgYW5kIEV4Y2VsIGluZHVjZWQgZXJyb3IuIFRoaXMga2luZCBvZiB0aGluZyBnaXZlcyBtZSBuaWdodG1hcmVzIQ0KDQo+ICoqUHJvLVRpcCoqDQo+DQo+V2hpbGUgdGhlcmUgYXJlIG1hbnkgY29ycmVjdCB3YXlzIHRvIGlucHV0IHlvdXIgZGF0ZXMgaW50byBFeGNlbCwgSSBmaW5kIHRoYXQgdGhlIGJlc3RbXjJdIHdheSBpcyB0byBzcGxpdCBpdCBpbmZvcm1hdGlvbiBvdmVyIG11bHRpcGxlIGNvbHVtbnMuIEVpdGhlciBgeWVhcmAsIGBtb250aGAsIGFuZCBgZGF5YCwgb3IgZXZlbiBiZXR0ZXIgYHllYXJgLCBhbmQgYERheU9mWWVhcmAgKGkuZS4gMSB0byAzNjUpLiBTZWUgW2hlcmVdKGh0dHA6Ly93d3cuZGF0YWNhcnBlbnRyeS5vcmcvc3ByZWFkc2hlZXQtZWNvbG9neS1sZXNzb24vMDMtZGF0ZXMtYXMtZGF0YS8pIGZvciBtb3JlIGluZm8gb24gY29udmVydGluZyBkYXRlIGZvcm1hdHRpbmcgaW4gRXhjZWwuDQoNClteMl06IEJ5ICdiZXN0JyBJIG1lYW4gdGhhdCBpdCBhdm9pZHMgdGhlIGNvbW1vbiBFeGNlbCBwcm9ibGVtcyBhbmQgZG9lc24ndCBjYXVzZSBhbnkgcHJvYmxlbXMgaW4gYW55IGRvd25zdHJlYW0gYW5hbHlzaXMgaW4gUiBvciBvdGhlci4NCg0KDQoNCiMjIEtlZXAgeW91ciBkYXRhIHRpZHkNCg0KKCoqdGxkcjogdGlkeSBkYXRhID0gcXVhbGl0eSBvZiBsaWZlIGltcHJvdmVkKiopDQoNClRoZSAndGlkeScgY29uY2VwdCBpcyBzb21ldGhpbmcgd2Ugd2lsbCByZXZpc2l0IGluIHRoZSBSIHNlY3Rpb24sIGJ1dCB0aGUgcnVsZXMgb2YgdGlkeSBkYXRhIGFyZVteM106DQoNCjEuIEVhY2ggdmFyaWFibGUgeW91IG1lYXN1cmUgc2hvdWxkIGJlIGluIG9uZSBjb2x1bW4NCjIuIEVhY2ggZGlmZmVyZW50IG9ic2VydmF0aW9uIG9mIHRoYXQgdmFyaWFibGUgc2hvdWxkIGJlIGluIGEgZGlmZmVyZW50IHJvdw0KMy4gVGhlcmUgc2hvdWxkIGJlIG9uZSB0YWJsZSBmb3IgZWFjaCDigJxraW5k4oCdIG9mIHZhcmlhYmxlDQo0LiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSB0YWJsZXMsIHRoZXkgc2hvdWxkIGluY2x1ZGUgYSBjb2x1bW4gaW4gdGhlIHRhYmxlIHRoYXQgYWxsb3dzIHRoZW0gdG8gYmUgbGlua2VkDQoNClteM106IFtKZWZmIExlZWssIFRoZSBFbGVtZW50cyBvZiBEYXRhIEFuYWx5dGljIFN0eWxlLCBMZWFucHViLCAyMDE1LTAzLTAyXShodHRwczovL2xlYW5wdWIuY29tL2RhdGFzdHlsZSkNCg0KPiAqKlByby1UaXBzKioNCj4NCj4gLSBJbiBwcmFjdGljZSwgdGhlc2UgcnVsZXMgZ2VuZXJhbGx5IHRyYW5zbGF0ZSBpbnRvIGtlZXBpbmcgeW91ciBkYXRhICdzcXVhcmUnIChvciByZWN0YW5ndWxhciksIGFuZCBub3QgaGF2aW5nIG11bHRpcGxlIHRhYmxlcyB3aXRoaW4gb25lIHNwcmVhZHNoZWV0Lg0KPiAtIGBsb2NhdGlvbklEYCwgb3IgYG9yZ2FuaXNtSURgIG1ha2UgZ3JlYXQgdW5pcXVlIGlkZW50aWZpZXJzIGZvciAnbGlua2luZycgdGFibGVzIGFzIHBlciBydWxlIDQNCg0KRm9sbG93aW5nIHRoZXNlIHJ1bGVzIG1ha2VzIHlvdXIgZGF0YSBtb3JlIGh1bWFuIGFuZCBtYWNoaW5lIHJlYWRhYmxlLiBJbiBteSBvcGluaW9uIHRoZSBmaXJzdCAyIHJ1bGVzIChhbmQgdGhlIDR0aCBpZiB5b3UgaGF2ZSBtdWx0aXBsZSB0YWJsZXMpIGFyZSB0b3RhbGx5IG5vbi1uZWdvdGlhYmxlLiBSdWxlIDMgZm9yIG1lIGlzIGEgbGl0dGxlIGZ1enp5IHNpbmNlICJraW5kIiBpcyBhIGxpdHRsZSBhbWJpZ3VvdXMgaW4gbXkgbWluZCwgYW5kIGRvZXNuJ3QgbWVzaCB3aXRoIHdoYXQgSSBjb25zaWRlciAnYmVzdC1wcmFjdGljZScuIE15IHJ1bGUgb2YgdGh1bWIgaXMgdGhhdCBpZiBkYXRhIHdlcmUgY29sbGVjdGVkIGF0IHRoZSBzYW1lIHNwYXRpYWwgYW5kIHRlbXBvcmFsIHNjYWxlcywgdGhleSB3aWxsIGJlIGdvaW5nIGludG8gMSB0YWJsZS4gRm9yIGV4YW1wbGUsIGNvbmR1Y3Rpdml0eSAoc2FsaW5pdHkpLCB0ZW1wZXJhdHVyZSwgYW5kIGRlcHRoIG9mIHRoZSBvY2VhbiBkYXRhIGZyb20gYSBDVEQgaXMgb2Z0ZW4gcmVjb3JkZWQgYXQgdGhlIGV4YWN0IHNhbWUgdGltZSBhbmQgcGxhY2Ugc2luY2UgYWxsIDMgc2Vuc29ycyBhcmUgYnVpbHQgaW50byB0aGUgc2FtZSBpbnN0cnVtZW50LiBUaGVyZWZvcmUsIEkgd291bGQga2VlcCBjb25kdWN0aXZpdHksIHRlbXBlcmF0dXJlLCBhbmQgZGVwdGggb2YgdGhlIG9jZWFuIGluIDEgdGFibGUgc2luY2UgSSB3b3VsZCBvdGhlcndpc2UgYmUgcmVwZWF0aW5nIGlkZW50aWNhbCB0aW1lL3NwYWNlIGRhdGEuIENvbnZlcnNlbHksIGEgc2FtcGxlIGZyb20gYSBwbGFua3RvbiBuZXQgd2lsbCBub3QgaGF2ZSB0aGUgc2FtZSB0ZW1wb3JhbCByZXNvbHV0aW9uIGFzIGEgQ1REIHRoZXJlZm9yZSBzaG91bGQgYmUgaW4gZGlmZmVyZW50IHRhYmxlcywgYnV0IHRoZXNlIGluc3RydW1lbnRzIGNhbiBzYW1wbGUgdGhlIHNhbWUgc2l0ZSBzbyBgbG9jYXRpb25JRGAgd291bGQgbWFrZSBhIGdyZWF0IGNvbHVtbiB0byBsaW5rIGJldHdlZW4gdGFibGVzLiANCg0KIyMgTkVWRVIgc2F2ZSBhcyAueGxzIG9yIC54bHN4IChzZXJpb3VzbHkpDQoNCigqKnRsZHI6IHJlLXJlYWQgdGhlIHRpdGxlLCBpdCdzIHRoZSBtb3N0IGltcG9ydGFudCBydWxlISEhKiopDQoNCg0KSW4gc2NpZW5jZSwgaXQgaXMgaW1wb3J0YW50IHRvIHdyaXRlIGV2ZXJ5dGhpbmcgZG93biAoc2VlIEFkYW0gYWJvdmUpLCBidXQgaXQgaXMgYWxzbyBqdXN0IGFzIGltcG9ydGFudCB2ZXJ5IGltcG9ydGFudCB0byBiZSBhYmxlIHRvIHJlYWQgd2hhdCB5b3UgaGF2ZSB3cml0dGVuISBFeGNlbCBieSBkZWZhdWx0IHdpbGwgc2F2ZSB5b3VyIHNwcmVhZHNoZWV0IGluIGl0J3MgcHJvcHJpZXRhcnkgZm9ybWF0LCB3aGljaCBtZWFucyB0aGF0IGlmIHlvdSBkb24ndCBoYXZlIEV4Y2VsIHlvdSBjYW4ndCByZWFkIHlvdXIgZmlsZVteNF0hIFRoaXMgaXMgYWxzbyBub3QganVzdCBhIHJ1bGUgYWJvdXQgRXhjZWwsIGJ1dCByYXRoZXIgYW55IHByb3ByaWV0YXJ5IHNvZnR3YXJlLiAqKkFsd2F5cyBzYXZlIGluIGFuIG9wZW4gZm9ybWF0IHJhdGhlciB0aGFuIGEgcHJvcHJpZXRhcnkgZm9ybWF0LioqKg0KDQpbXjRdOiBPSywgSSBrbm93IHRoZXJlIGFyZSBvdGhlciB3YXlzIG9mIG9wZW5pbmcgYW4gRXhjZWwgZmlsZSwgYnV0IHRoZXJlIGlzIHN0aWxsIGFuIGludGVyb3BlcmFiaWxpdHkgcHJvYmxlbS4gV2VpcmQsIHVuZXhwZWN0ZWQgdGhpbmdzIGNhbiBvZnRlbiBoYXBwZW4gKGUuZy4gYWdhaW4sIGRhdGVzISkgd2hlbiBvcGVuaW5nIEV4Y2VsIGZpbGVzIHVzaW5nIGFsdGVybmF0aXZlIHNvZnR3YXJlIChlLmcuIE9wZW4gT2ZmaWNlKS4gQWRkaXRpb25hbGx5LCB0aGUgcHJvcHJpZXRhcnkgRXhjZWwgZm9ybWF0IGNoYW5nZXMgb3ZlciB0aW1lLCB5b3UgbWF5IG5vdCBiZSBhYmxlIHRvIG9wZW4gb2xkIGRhdGEgZmlsZXMgaW4gdGhlIGZ1dHVyZS4NCg0KDQo+ICoqUHJvLVRpcCoqDQo+DQo+IElmIHlvdSBoYXZlIGVudGVyZWQgeW91ciBkYXRhIGluIGFuIEV4Y2VsIHNwcmVhZHNoZWV0LCBzaW1wbHkgY2xpY2sgb24gJ1NhdmUgQXMnIGFuZCBzZWxlY3QgdHlwZSAnQ1NWIChDb21tYSBkZWxpbWl0ZWQpJw0KDQpJIHJlY29tbWVuZCB0aGF0IGV2ZXJ5b25lIHNob3VsZCBzYXZlIHRoZWlyIGRhdGEgYXMgYSBgLmNzdmAgKHN0YW5kcyBmb3IgY29tbWEgc2VwYXJhdGVkIHZhbHVlcywgdGhlIG5hbWUgb2YgdGhlIGZvcm1hdCBnaXZlcyB5b3UgYSBjbHVlIGFzIHRvIGhvdyB0aGUgZGF0YSBpcyBmb3JtYXR0ZWQhKSBpbnN0ZWFkIG9mIGAueGxzeGAgYmVjYXVzZToNCg0KMS4gSXQncyBlYXN5IHRvIGRvDQoyLiBZb3UgY2FuIHN0aWxsIHVzZSBFeGNlbCB0byBlbnRlciB5b3VyIGRhdGENCjMuIEl0J3Mgc3RvcmVkIGFzIGEgc2ltcGxlIHRleHQgZmlsZSBhbmQgaXMgbmVhcmx5IHVuaXZlcnNhbGx5IHJlYWRhYmxlIA0KNC4gSXQgYXZvaWRzIGNvbW1vbiBFeGNlbCBwaXRmYWxscw0KDQpUaGVzZSBwaXRmYWxscyBhcmUgYW4gaW50ZXJlc3RpbmcgcG9pbnQuIEhvdyBtYW55IHRpbWVzIGhhdmUgeW91IHVzZWQ6DQoNCi0gY2VsbCBjb2xvciAob3IgYm9sZCB0ZXh0LCBldGMpIHRvIGNvbnZleSBpbmZvcm1hdGlvbg0KLSBtdWx0aXBsZSB0YWJzDQotIGNvbW1lbnRzICh0aGUgYnViYmxlIGluc2VydHMpDQoNCkFsbCB0aGVzZSB0aGluZ3MgYXJlIGJpZyBuby1ubydzIHNpbmNlIHRoZXkgd2lsbCBsaWtlbHkgZ2V0IHNjcmFtYmxlZCwgb3Igbm90IGFwcGVhciBhdCBhbGwgaWYgeW91IHRyeSB0byBvcGVuIGluIGFueXRoaW5nIGJ1dCBFeGNlbC4gU2F2aW5nIGFzIGAuY3N2YCBpcyBhIHNlbGYgcmVpbmZvcmNpbmcgZ3VhcmFudGVlIHRoYXQgeW91IGRvIG5vdCB1c2UgdGhlc2UgdGhpbmdzIHNpbmNlIGl0IHdpbGwgbm90IHNhdmUgdGhlbS4gTXVsdGlwbGUgdGFicyBzaG91bGQgYmUgbXVsdGlwbGUgZmlsZXMsIGFuZCBjb21tZW50cyAocGx1cyBhbnkgb3RoZXIgaW5mb3JtYXRpb24gZW5jb2RlZCBieSBzcGVjaWFsIGZvcm1hdHRpbmcpIHNob3VsZCBiZSByZWNvcmRlZCBpbiBjb2x1bW5zIHJlc2VydmVkIGZvciB0aGF0IHVzZS4NCg0KPioqRVhFUkNJU0UqKg0KPg0KPiAtIE9wZW4gbmV3IHNwcmVhZHNoZWV0IGluIEV4Y2VsLCB3cml0ZSBhIGZldyByb3dzIG9mIGRhdGEgaW50byB5b3VyIHNwcmVhZHNoZWV0IGFuZCBzYXZlIHlvdXIgZmlsZSBhcyBib3RoIGEgYC5jc3ZgIGFuZCBhIGAueGxzeGAuDQotIENsb3NlIEV4Y2VsDQotIE9wZW4gYm90aCBmaWxlcyB1c2luZyBFeGNlbA0KLSBPcGVuIGJvdGggZmlsZXMgdXNpbmcgYSBiYXNpYyB0ZXh0IGVkaXRvciAoZS5nLiBOb3RlcGFkIG9uIFdpbmRvd3MsIG9yIFRleHRFZGl0IG9uIE1hYykNCkRvIHRoZSBmaWxlcyBsb29rIGlkZW50aWNhbCBpbiBFeGNlbD8gSW4gdGhlIHRleHQgZWRpdG9yPyBXaGljaCBmb3JtYXQgc2VlbXMgYmV0dGVyIHRvIHlvdSBhbmQgd2h5Pw0KDQojIyBEb24ndCByZS1pbnZlbnQgdGhlIHdoZWVsDQpGb3IgY29sdW1uIGhlYWRlcnMgQ0hPTmUgcmVjb21tZW5kcyB5b3UgdXNlIHRoZSBbRGFyd2luIENvcmUgVGVybXNdKGh0dHA6Ly9ycy50ZHdnLm9yZy9kd2MvdGVybXMvKQ0KSXQgY29udGFpbnMgaGVscGZ1bCBpbmZvcm1hdGlvbiBhYm91dCBob3cgdG8gdXNlIHN0YW5kYXJkIGNvbHVtbiBoZWFkZXJzLiBJdCB3aWxsIGhlbHAgb3RoZXJzIChhbmQgeW91cnNlbGYgYSBmZXcgbW9udGhzIGFmdGVyIHdyaXRpbmcgeW91ciBkYXRhKSB1bmRlcnN0YW5kIHlvdXIgZGF0YS4gSXQgYWxzbyB3aWxsIHN0cmVhbWxpbmUgdGhlIHByb2Nlc3Mgd2hlbiB5b3Ugc3VibWl0IHlvdXIgZGF0YSB0byBiZSBhcmNoaXZlZCB3aXRoIFtPQklTXShodHRwOi8vd3d3LmlvYmlzLm9yZy8pLg0KDQpTb21lIGNvbW1vbiBvbmVzIHlvdSB3aWxsIGFsbCBsaWtlbHkgdXNlIGFyZSBmb3IgZGF0ZS90aW1lOiBgeWVhcmAsIGBtb250aGAsIGBkYXlgLCBgZXZlbnRUaW1lYCwgYGV2ZW50RGF0ZWAsIG9yIGZvciBsb2NhdGlvbjogYGxvY2F0aW9uSURgLCBgZGVjaW1hbExvbmdpdHVkZWAgYW5kIGBkZWNpbWFsTGF0aXR1ZGVgLiANCg0KRm9yIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUsIGl0J3MgYmV0dGVyIHRvIHdyaXRlOiBgLTQxLjA5ODM0MjNgIGFuZCBgLTEyMS4xNzYxMTExYCAgYW5kIE5PVDogNDfCsCAzMycgMzcuOTQwNCcnIE4gYW5kIDUywrAgNDInIDQ2LjE4ODAnJyBXIGJlY2F1c2UgdGhlIGRlY2ltYWwgdmVyc2lvbiB3aWxsIGJlIGVhc2llciBmb3IgdGhlIGNvbXB1dGVyIHRvIHJlYWQgYW5kIGl0IGlzICdhY2NvcmRpbmcgdG8gc3RhbmRhcmQnIQ0KIA0KRm9yYGV2ZW50ZGF0ZWAgaGVyZSBhcmUgYSBmZXcgZXhhbXBsZXM6IA0KLSBgMTk2My0wMy0wOFQxNDowNy0wNjAwYCBpcyA4IE1hciAxOTYzIDI6MDdwbSBpbiB0aGUgdGltZSB6b25lIHNpeCBob3VycyBlYXJsaWVyIHRoYW4gVVRDDQotIGAyMDA5LTAyLTIwVDA4OjQwWmAgaXMgMjAgRmViIDIwMDkgODo0MGFtIFVUQw0KLSBgMTgwOS0wMi0xMmAgaXMgMTIgRmViIDE4MDkNCi0gYDE5MDYtMDZgIGlzIEp1biAxOTA2DQotIGAxOTcxYCBpcyBqdXN0IHRoYXQgeWVhcg0KLSBgMjAwNy0wMy0wMVQxMzowMDowMFovMjAwOC0wNS0xMVQxNTozMDowMFpgIGlzIHRoZSBpbnRlcnZhbCBiZXR3ZWVuIDEgTWFyIDIwMDcgMXBtIFVUQyBhbmQgMTEgTWF5IDIwMDggMzozMHBtIFVUQw0KLSBgMjAwNy0xMS0xMy8xNWAgaXMgdGhlIGludGVydmFsIGJldHdlZW4gMTMgTm92IDIwMDcgYW5kIDE1IE5vdiAyMDA3Lg0KIA0KQnV0IEkgYW0gcGVyc29uYWxseSB1bmVhc3kgYWJvdXQgdHlwaW5nIGFsbCBvZiB0aGF0IGludG8gRXhjZWwsIGl0IG1heSB0cnkgdG8gcmVpbnRlcnByZXQgd2hhdCB5b3Ugd3JvdGUgd2hpbGUgdHJ5aW5nIHRvICdoZWxwJyB5b3UuIEkgd291bGQgcmVjb21tZW5kIGtlZXBpbmcgdGhhdCBpbmZvcm1hdGlvbiBzZXBhcmF0ZWQgaW50byB0aGUgYHllYXJgLCBgbW9udGhgLCBgZGF5YCwgYW5kIGBldmVudFRpbWVgIGNvbHVtbnMNCg0KLSBgeWVhcmAgOiAyMDA4DQotIGBtb250aGAgOiAxIChub3QgIkphbnVhcnkiKQ0KLSBgZGF5YDogMjgNCi0gYGV2ZW50VGltZWA6ICIxNDowNy0wNjAwIiBpcyAyOjA3cG0gaW4gdGhlIHRpbWUgem9uZSBzaXggaG91cnMgZWFybGllciB0aGFuIFVUQw0KLSBgZXZlbnRUaW1lYDogIjA4OjQwOjIxWiIgaXMgODo0MDoyMWFtIFVUQw0KLSBgZXZlbnRUaW1lYDogIjEzOjAwOjAwWi8xNTozMDowMFoiIGlzIHRoZSBpbnRlcnZhbCBiZXR3ZWVuIDFwbSBVVEMgYW5kIDM6MzBwbSBVVEMuDQoNClRoYXQgd2F5IHlvdSBhcmUgc3RpbGwgZm9sbG93aW5nIHRoZSBzdGFuZGFyZCwgeWV0IGtlZXBpbmcgRXhjZWwncyBlY2NlbnRyaWNpdGllcyBhdCBiYXkgYW5kIGFzIGEgYm9udXMsIEkgdGhpbmsgaXQncyBlYXNpZXIgdG8gd29yayB3aXRoIHRoZSBwcmUtc2VwYXJhdGVkIHZhcmlhYmxlcyBpbiBSLiBZb3UgY2FuIGFsc28gZ2VuZXJhdGUgYW4gYGV2ZW5EYXRlYCBjb2x1bW4gaW4gUiBieSBwYXN0aW5nIGFsbCB0aGUgcm93cyB0b2dldGhlci4gKElmIHRoZSBjb2RlIGJlbG93IHNlZW1zIGxpa2UgZ2liYmVyaXNoLCB0aGF0J3MgdG90YWxseSBPSywgd2Ugd2lsbCBleHBsYWluIGFsbCB0aGUgc3RlcHMgd2hlbiB3ZSBnZXQgaW50byBSIGluIHRoZSBsYXRlciBsZXNzb25zLCBqdXN0IHJlbWVtYmVyIHRoaXMgY29kZSBpcyBoZXJlISkNCg0KYGBge3IsbWVzc2FnZT1GQUxTRX0NCnJlcXVpcmUodGlkeXZlcnNlKQ0KYGBgDQpgYGB7cn0NCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAgICB5ZWFyID0gYygyMDA4LDIwMDMsMjAwOSksDQogICAgbW9udGggPSBjKDEsMiwzKSwNCiAgICBkYXkgPSBjKDI4LDEyLDEyKSwNCiAgICBldmVudFRpbWUgPSBjKCIxMjowMC0wNjAwIiwiMDE6MTUtMDYwMCIsIjE0OjA3LTA2MDAiKQ0KKQ0KDQojIHlvdSBtYXkgbm90aWNlIHRoYXQgbXkgeWVhciwgbW9udGgsIGFuZCBkYXkgY29sdW1ucyBhcmUgbnVtZXJpYyBhbmQgd29uJ3QgaGF2ZSB0aGUgcmVxdWlyZSBsZWFkaW5nIDAncw0KIyB3ZSBjYW4gZml4IHRoYXQgd2l0aCBzcHJpbnRmOg0Kc3ByaW50ZigiJTAyZCIsZGF0YSRtb250aCkNCg0KIyBoZXJlJ3MgYSAnb25lLWxpbmVyJyB0aGF0IHdpbGwgYWRkIGxlYWRpbmcgemVyb3MsIHBhc3RlIGFsbCB0aGUgY29sdW1ucyB0b2dldGhlciwgYW5kIHNlcGVyYXRlIHRoZW0gYnkgdGhlIHJlcXVpcmVkICctJw0KDQpkYXRhIDwtIGRhdGEgJT4lIA0KICAgIG11dGF0ZShldmVudERhdGU9cGFzdGUoc3ByaW50ZigiJTA0ZCIseWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlMDJkIixtb250aCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlMDJkIixkYXkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnRUaW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwPSItIikNCiAgICAgICAgICAgKQ0KDQpkYXRhDQpgYGANCg0KT3IgYWx0ZXJuYXRpdmVseSwgaWYgeW91J3JlIGxpa2UgbWUgYW5kIHdhbnQgdG8ga2VlcCB0aGUgdGltZSBudW1lcmljIGZvciBlYXNlIG9mIHByb2dyYW1taW5nLCBjb25zaWRlciB0aGlzIChidXQgYmUgc3VyZSB0byByZWNyZWF0ZSBhbiBgZXZlbnRUaW1lYCB0aGF0IGluY2x1ZGVzIHRpbWUgem9uZSBpbmZvcm1hdGlvbik6DQoNCmBgYHtyfQ0KZGF0YSA8LSBkYXRhLmZyYW1lKA0KICAgIHllYXIgPSBjKDIwMDgsMjAwMywyMDA5KSwNCiAgICBtb250aCA9IGMoMSwyLDMpLA0KICAgIGRheSA9IGMoMjgsMTIsMTIpLA0KICAgIGhvdXIgPSBjKDEyLDEsMTQpLA0KICAgIG1pbnV0ZSA9IGMoMCwxNSw3KQ0KKQ0KDQpkYXRhIDwtIGRhdGEgJT4lIA0KICAgIG11dGF0ZShldmVudFRpbWU9cGFzdGUwKHNwcmludGYoIiUwMmQiLGhvdXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICI6IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlMDJkIixtaW51dGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICItMDYwMCIpDQogICAgICAgICAgICkNCg0KZGF0YQ0KYGBgDQoNCg0KIyMgQXZvaWQgb3RoZXIgY29tbW9uIGhlYWRhY2hlcw0KDQotIE5vdCBmaWxsaW5nIGluIHplcm9zDQotIFVzaW5nIHByb2JsZW1hdGljIG51bGwgdmFsdWVzDQotIFVzaW5nIHByb2JsZW1hdGljIGZpZWxkIG5hbWVzDQotIFVzaW5nIHNwZWNpYWwgY2hhcmFjdGVycyBpbiBkYXRhDQoNClplcm9zIGFuZCBudWxsIHZhbHVlcyBhcmUgdmVyeSBkaWZmZXJlbnQgY29tcHV0YXRpb25hbGx5IGFuZCBzdGF0aXN0aWNhbGx5ISBBIHplcm8gaXMgd2hlbiB5b3UgbWVhc3VyZWQgYSAwLCBzbyB0aGF0IGlzIHVzZWZ1bCBpbmZvcm1hdGlvbiwgYW5kIGEgbnVsbCB2YWx1ZSBpcyB3aGVuIHRoZXJlIGlzIG5vIGRhdGEsIG5vIGluZm9ybWF0aW9uIChlLmcuIG1lYXN1cmVtZW50IHdhcyBub3QgdGFrZW4gb3Igd2FzIGxvc3QpLiBaZXJvcyBzaG91bGQgYWx3YXlzIGJlIHJlY29yZGVkIGAwYCB3aGlsZSBudWxsIHZhbHVlcyBhcmUgYSBiaXQgdHJpY2tpZXI7IGVpdGhlciBsZWF2aW5nIHRoZSBjZWxsIGJsYW5rIG9yIGluc2VydGluZyBhbiBgTkFgIGFyZSB1c3VhbGx5IHRoZSBsZWFzdCBwcm9ibGVtYXRpYyBvcHRpb25zLg0KDQpNYW55IG9mIHRoZSBzdGF0aXN0aWNhbCBzb2Z0d2FyZSBvcHRpb25zIGFyZSB2ZXJ5IGZ1c3N5IGFib3V0IHNwYWNlcywgcGVyaW9kcywgYW5kIHNsYXNoZXMgaW4gZmllbGQgbmFtZXMgKGNvbHVtbiBoZWFkZXJzKS4gVW5kZXJzY29yZXMgKGBfYCkgYXJlIGEgZ29vZCBhbHRlcm5hdGl2ZSB0byBzcGFjZXMuIENvbnNpZGVyIHdyaXRpbmcgbmFtZXMgaW4gY2FtZWwgY2FzZSAobGlrZSB0aGlzOiBFeGFtcGxlRmlsZU5hbWUpIHRvIGltcHJvdmUNCnJlYWRhYmlsaXR5LiBSZW1lbWJlciB0aGF0IGFiYnJldmlhdGlvbnMgdGhhdCBtYWtlIHNlbnNlIGF0IHRoZSBtb21lbnQgbWF5IG5vdCBiZSBzbyBvYnZpb3VzIGluIDYgbW9udGhzLCBidXQgZG9uJ3Qgb3ZlcmRvIGl0IHdpdGggbmFtZXMgdGhhdCBhcmUgZXhjZXNzaXZlbHkgbG9uZy4gSW5jbHVkaW5nIHRoZSB1bml0cyBpbiB0aGUgZmllbGQgbmFtZXMgYXZvaWRzIGNvbmZ1c2lvbiBhbmQgZW5hYmxlcyBvdGhlcnMgdG8gcmVhZGlseSBpbnRlcnByZXQgeW91ciBmaWVsZHMuIEFsc28sIGFzIGFsd2F5cywgY2hlY2sgdGhlIHN0YW5kYXJkIChbRGFyd2luIENvcmUgVGVybXNdKGh0dHA6Ly9ycy50ZHdnLm9yZy9kd2MvdGVybXMvKSkgaW4gY2FzZSB5b3Ugc2hvdWxkIGJlIHVzaW5nIHNvbWV0aGluZyBzcGVjaWZpYywgdGhlc2UgYXJlIGp1c3QgZ2VuZXJhbCBpbnN0cnVjdGlvbnMgZm9yIHdoZW4geW8gbmVlZCB0byBtYWtlIGEgbmV3IGNvbHVtbiBuYW1lLg0KDQoqKkV4YW1wbGVzKiogIA0KDQp8IEdvb2QgTmFtZSAgICAgICAgfCBHb29kIEFsdGVybmF0aXZlICB8IEF2b2lkICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBNYXhfdGVtcF9DICAgICAgIHwgTWF4VGVtcCAgICAgICAgICAgfCBNYXhpbXVtIFRlbXAgKMKwQykgfA0KfCBQcmVjaXBpdGF0aW9uX21tIHwgUHJlY2lwaXRhdGlvbiAgICAgfCBwcmVjbW0gICAgICAgICAgICB8DQp8IE1lYW5feWVhcl9ncm93dGggfCBNZWFuWWVhckdyb3d0aCAgICB8IE1lYW4gZ3Jvd3RoL3llYXIgIHwNCnwgc2V4ICAgICAgICAgICAgICB8IHNleCAgICAgICAgICAgICAgIHwgTS9GICAgICAgICAgICAgICAgfA0KfCB3ZWlnaHQgICAgICAgICAgIHwgd2VpZ2h0ICAgICAgICAgICAgfCB3LiAgICAgICAgICAgICAgICB8DQp8IGNlbGxfdHlwZSAgICAgICAgfCBDZWxsVHlwZSAgICAgICAgICB8IENlbGwgVHlwZSAgICAgICAgIHwNCnwgT2JzZXJ2YXRpb25fMDEgICB8IGZpcnN0X29ic2VydmF0aW9uIHwgMXN0IE9icyAgICAgICAgICAgfA0KDQojIEltcG9ydGFudCBsaW5rcw0KVGhpcyBzZWN0aW9uIGhhcyBiZWVuIGEgc2hvcnRlbmVkIHZlcnNpb24gb2YgdGhlIERhdGEgQ2FycGVudHJ5IG1hdGVyaWFsIG9uIFtzcHJlYWRzaGVldCBvcmdhbml6YXRpb25dKGh0dHA6Ly93d3cuZGF0YWNhcnBlbnRyeS5vcmcvc3ByZWFkc2hlZXQtZWNvbG9neS1sZXNzb24vKQ0KDQpUaGVyZSBpcyBhIHR3aXR0ZXIgaGFzaHRhZyBjYWxsZWQgWyNvdGhlcnBlb3BsZXNkYXRhXShodHRwczovL3R3aXR0ZXIuY29tL2hhc2h0YWcvb3RoZXJwZW9wbGVzZGF0YT9sYW5nPWVuKSBmb3IgcGVvcGxlIHZlbnRpbmcgYWJvdXQgcHJvYmxlbXMgd2hpbGUgdXNpbmcgb3RoZXIgcGVvcGxlJ3MgZGF0YSwgaG9wZWZ1bGx5IHRoaXMgd29ya3Nob3Agd2lsbCBhbGxvdyB5b3UgdG8gYXZvaWQgdGhhdCBoYXNodGFnIQ0KDQpbPDxCQUNLXShodHRwczovL3JlbWktZGFpZ2xlLmdpdGh1Yi5pby8yMDE3LUNIT05lLURhdGEvKQ0K