Learning Outcomes

Upon completion of this tutorial, you will be able to:

  • Build flexible models in Excel and Google Sheet

  • Load data from files and the web

  • Analyze data in tables and pivot tables

  • Shape data through text processing

  • Handle errors in formulas

  • Use lookup tables

Introduction

This lesson provides a primer on the use of spreadsheets that follow the standards set by Microsoft Excel. At its core, spreadsheets are a type of computer application that allows one to organize, analyze, and store data in tabular format. A spreadsheet is a computerized version of a paper accounting worksheet that was commonly used in accounting prior to the creation of electronic spreadsheets; the first of which was VisiCalc which was followed by Lotus 1-2-3 and then Microsoft Excel, Apple Pages, Google Sheet, and Zoho Sheet, among others.

A spreadsheet is an arrangement of data into tables consisting of columns and rows. Numeric, date, currency, and other data as well as text can be stored in each cell. Cells can also contain formulas which automatically calculate and display a value based on other cells’ contents. Any stored value can be adjusted in a spreadsheet and the effect observed on the calculated values can be observed. As a result, the spreadsheet can be utilized for “what-if” analysis as many cases can be quickly investigated without the need for manual recalculation. Spreadsheets are a type of document containing structured information data objects.

Structured information objects have properties in the form of attributes. For example, instances of a Course have attributes such as title, length, credits, among others, depending on the use cases. Such information must often be externalized and stored in some structure where they can be shared and queried. A tabular organization is a common format for the externalization of structured information objects.

Today, spreadsheets are generally referred to as worksheets or, simply, sheets. Worksheets are organized into workbooks. Multiple sheets can be interconnected to represent relationships, and data can be displayed as text, numbers, or graphics. Interconnected worksheets are a form of relational data and a workbook can be looked at as a relational data store – in fact, some spreadsheet applications, such as Excel, allow SQL queries on workbooks.

Spreadsheet programs such as Excel are a popular end-user development tool (EUD). EUD refers to actions or methods used by non-professional developers to build computational data objects and automated behavior without requiring a deep understanding of programming or programming languages. In many ways using spreadsheets to express computational structure is more convenient and quicker than creating a typical program that performs the same function, although languages such as R often allow rapid development of sophisticated data-driven code. Such as end-user developed spreadsheet if sometimes called a spreadsheet program or a spreadsheet model.

Tabular Structures

Information objects are stored in tabular form in:

  • CSV text data files
  • Excel (and other spreadsheet program) worksheets
  • Data frames in R and Python
  • Relational database tables
  • Two-Level XML documents

All tabular structures have the same format: rows with columns. Each row is an instance of an information object, while each column is an attribute value. Rows are generally numbered while columns are named.

CSV

The example below shows data in a CSV. Note the separation of columns by commas.

Product,CerealName,Manufacturer,Calories,Sodium,Fiber,Carbs,Sugars,Shelf,Year,,
1,100% Bran,Nabisco,70,130,10,5,6,3,1942,,
2,All-Bran,Kellogg,70,260,9,7,5,3,1916,,
3,All-Bran w/Extra Fiber,Kellogg,50,140,14,8,0,3,1916,,

A cell or a range of cells cannot be directly specified until the CSV is loaded into a program for processing.

Excel

The image below shows an example of a tabular structure in Excel. Columns are letters (A..Z, AA-ZZ, etc.) and rows are numbered; each intersection of a column and a row is a cell. In addition to data values, cells can also contain formulas which are algebraic expressions referencing cells or ranges of cells. A range of cells is similar to a vector, array, or a matrix in R.

Sample Tabular Structure in an Excel Worksheet
Sample Tabular Structure in an Excel Worksheet

A cell in Excel is referenced as a column/row pair, e.g., D4 references the Calories attribute of Product instance 3 and has the value 50. A range of cells can be specified by a starting and ending cell, e.g., D2:D8 is the vector of values \(\{70,70,50,110,110,110,130\}\).

Data Frames

Data frames are in-memory tabular structures common in several programming languages, including R and Python. While they can be programmatically generated, they are typically the result of loading a CSV file, Excel worksheet, or SQL query result into a data frame.

For more information on working with data frames in R, see Lesson 6.103 Working with Vectors and Data Frames in R and for more information on reading files into data frames, see Lesson 6.106 Import Data into R from CSV, TSV, and Excel Files

XML

In some situations, XML documents where elements directly underneath the root represent rows and the child elements under the rows represents columns are used as an alternative to CSV. An example is shown below where each element is a row and the columns are , , and .

<?xml version="1.0"?>

<document>
  <row>
    <Girth>8.3</Girth>
    <Height>70</Height>
    <Volume>10.3</Volume>
  </row>
  <row>
    <Girth>8.6</Girth>
    <Height>65</Height>
    <Volume>10.3</Volume>
  </row>
  ...
</document>

Most commonly, such XML files are converted to a CSV or read into a programming language as a table. For example, in R, the function xmlToDataFrame() is often used to read such a specially-formatted XML into a data frame.

For more information on using xmlToDataFrame(), see Lesson 6.323 Load Simple XML into Dataframe in R using xmlToDataFrame.

Data Analytics Pipeline

Data analysis follows a process and must be methodical. For that purpose, industry standard data project management methodologies, such as CRISP-DM, have been developed.

Data Analytics Pipeline
Data Analytics Pipeline

Essentials of Excel and Sheet

Objectives

  • Distinguish between values, types, and format of a cell
  • Apply conditional formatting

Tutorial

Watch the tutorial below to get an overview of Excel and Google Sheet.

Slide Deck: Information Processing with Excel and Google Sheet: A Primer

References, Ranges, and Simple Formulas

Objectives

  • Create references
  • Build simple formulas
  • Use anchoring of cell references
  • Define named ranges

Tutorial

Watch the tutorial below for details, examples, and demonstrations on the concepts of this section.

Slide Deck: Information Processing with Excel and Google Sheet: A Primer

Text Processing

Some attributes of data objects are textual and thos attributes do not often come in a ready to process form. Text processing helps shape text attributes into analyzable formats.

Furthermore, text data is not the same as numeric data, and text must be often be converted to numeric format before calculations can be performed on those values. We will see a number of different text processing and text parsing function, plus the IF function for cases where text patterns have exceptions.

Tutorial

Watch the tutorial below for details, examples, and demonstrations on the concepts of this section.

Slide Deck: Information Processing with Excel and Google Sheet: A Primer

Worked Example

Load the workbook textprocessing.xslx into Excel or Google Sheet and then answer the following questions:

  1. In the worksheet “Exercise” are three rows of text data. Extract the each member’s name and the fee and place them into the two marked columns.
  2. Note that it is possible that some text data fields do not have a member name. How would you deal with that scenario?
  3. Convert the fees to numbers and then calculate the sum of the fees.
  4. Format the fees column in Accounting Format.

The tutorial below go through a solution approach. Of course, only watch it after you have diligently and honestly tried to work out the solution for yourself.

Table Lookup

Watch the tutorial below for details, examples, and demonstrations on the concepts of this section.

Slide Deck: Information Processing with Excel and Google Sheet: A Primer

Data Validation

Watch the tutorial below for details, examples, and demonstrations on the concepts of this section.

Slide Deck: Information Processing with Excel and Google Sheet: A Primer

Excel vs R

Both Excel and R are excellent tools for analyzing tabular data, but R has the distinct benefit, especially with the use of R Notebooks, if making the analysis reproducible. Reproducability is critical for analytics, data mining, and predictive modeling as it allows the process to be inspected and audited – one knows precisely how the result was produced. This is not easy to do in Excel.

In fact, there have been numerous cases where a bad formula or an incorrect cell reference led to incorrect conclusions. One such instance occurred in 2013 when UMass-Amherst graduate student Thomas Herndon uncovered major errors in the spreadsheet used by the economists Reinhart and Rogoff in their influential 2010 paper Growth in a Time of Debt. Their work was used to drive major economic policy which led to the implementation of the 2010-2013 European austerity programs. Unfortunately, the policy decision were based on incorrect conclusions from a flawed Excel model – an outcome that likely could have been avoided if reproducible analysis within an R Notebook (or a similar language) had been used.

Excel is not very good at summarizing data, grouping data, or finding multiple matching values. For that, R and SQL are much better, although some of those types of “queries” can be done in Excel using Pivot Tables or by writing VBA macros.

Nevertheless, Excel has one significant benefit: what-if analysis. Cells values can be changed interactively to explore outcomes of models interactively. This can only be done if we build R Dashboards using packages such as shiny. So, there are still good use cases for spreadsheet programs, but the arsenal of the data analyst must also include R (and similar languages).

Summary

This lesson provided a primer on working with tabular information objects in Excel and Google Sheet.


Files & Resources

All Files for Lesson 56.800

References

None.

Errata

Let us know.

LS0tCnRpdGxlOiAiUHJpbWVyIG9uIEV4Y2VsIGFuZCBHb29nbGUgU2hlZXQiCnBhcmFtczoKICBjYXRlZ29yeTogNTYKICBudW1iZXI6IDgwMAogIHRpbWU6ICIxMjAgbWluIgogIGxldmVsOiBiZWdpbm5lcgogIHRhZ3M6IGV4Y2VsLGdvb2dsZSBzaGVldCxzcHJlYWRzaGVldCx0YWJ1bGFyIGRhdGEsdGFibGVzLGNoYXJ0cwogIGRlc2NyaXB0aW9uOiAiU3ByZWFkc2hlZXRzIGFyZSBhIGNvbW1vbiB0YWJ1bGFyIGV4Y2hhbmdlIGZvcm1hdCBmb3Igc3RydWN0dXJlZCAKICAgICAgICAgICAgICAgIGluZm9ybWF0aW9uIG9iamVjdHMuIFRoaXMgbGVzc29uIHByb3ZpZGVzIGEgcHJpbWVyIG9uIHVzaW5nCiAgICAgICAgICAgICAgICBNaWNyb3NvZnQgRXhjZWwgYW5kIEdvb2dsZSBTaGVldCB0byBtYW5pcHVsYXRlIGluZm9ybWF0aW9uCiAgICAgICAgICAgICAgICBvYmplY3RzIHJlcHJlc2VudGVkIGluIHRhYnVsYXIgc3ByZWFkc2hlZXRzLiIKZGF0ZTogIjxzbWFsbD5gciBTeXMuRGF0ZSgpYDwvc21hbGw+IgphdXRob3I6ICI8c21hbGw+TWFydGluIFNjaGVkbGJhdWVyPC9zbWFsbD4iCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1IgphZmZpbGl0YXRpb246ICJOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19pbnNlcnQyREIuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAKCiMjIExlYXJuaW5nIE91dGNvbWVzCgpVcG9uIGNvbXBsZXRpb24gb2YgdGhpcyB0dXRvcmlhbCwgeW91IHdpbGwgYmUgYWJsZSB0bzoKCi0gICBCdWlsZCBmbGV4aWJsZSBtb2RlbHMgaW4gRXhjZWwgYW5kIEdvb2dsZSBTaGVldAoKLSAgIExvYWQgZGF0YSBmcm9tIGZpbGVzIGFuZCB0aGUgd2ViCgotICAgQW5hbHl6ZSBkYXRhIGluIHRhYmxlcyBhbmQgcGl2b3QgdGFibGVzCgotICAgU2hhcGUgZGF0YSB0aHJvdWdoIHRleHQgcHJvY2Vzc2luZwoKLSAgIEhhbmRsZSBlcnJvcnMgaW4gZm9ybXVsYXMKCi0gICBVc2UgbG9va3VwIHRhYmxlcwoKIyMgSW50cm9kdWN0aW9uCgpUaGlzIGxlc3NvbiBwcm92aWRlcyBhIHByaW1lciBvbiB0aGUgdXNlIG9mIHNwcmVhZHNoZWV0cyB0aGF0IGZvbGxvdyB0aGUKc3RhbmRhcmRzIHNldCBieSBNaWNyb3NvZnQgRXhjZWwuIEF0IGl0cyBjb3JlLCBzcHJlYWRzaGVldHMgYXJlIGEgdHlwZQpvZiBjb21wdXRlciBhcHBsaWNhdGlvbiB0aGF0IGFsbG93cyBvbmUgdG8gb3JnYW5pemUsIGFuYWx5emUsIGFuZCBzdG9yZQpkYXRhIGluIHRhYnVsYXIgZm9ybWF0LiBBIHNwcmVhZHNoZWV0IGlzIGEgY29tcHV0ZXJpemVkIHZlcnNpb24gb2YgYQpwYXBlciBhY2NvdW50aW5nIHdvcmtzaGVldCB0aGF0IHdhcyBjb21tb25seSB1c2VkIGluIGFjY291bnRpbmcgcHJpb3IgdG8KdGhlIGNyZWF0aW9uIG9mIGVsZWN0cm9uaWMgc3ByZWFkc2hlZXRzOyB0aGUgZmlyc3Qgb2Ygd2hpY2ggd2FzIFZpc2lDYWxjCndoaWNoIHdhcyBmb2xsb3dlZCBieSBMb3R1cyAxLTItMyBhbmQgdGhlbiBNaWNyb3NvZnQgRXhjZWwsIEFwcGxlIFBhZ2VzLApHb29nbGUgU2hlZXQsIGFuZCBab2hvIFNoZWV0LCBhbW9uZyBvdGhlcnMuCgpBIHNwcmVhZHNoZWV0IGlzIGFuIGFycmFuZ2VtZW50IG9mIGRhdGEgaW50byB0YWJsZXMgY29uc2lzdGluZyBvZgpjb2x1bW5zIGFuZCByb3dzLiBOdW1lcmljLCBkYXRlLCBjdXJyZW5jeSwgYW5kIG90aGVyIGRhdGEgYXMgd2VsbCBhcwp0ZXh0IGNhbiBiZSBzdG9yZWQgaW4gZWFjaCBjZWxsLiBDZWxscyBjYW4gYWxzbyBjb250YWluIGZvcm11bGFzIHdoaWNoCmF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlIGFuZCBkaXNwbGF5IGEgdmFsdWUgYmFzZWQgb24gb3RoZXIgY2VsbHMnCmNvbnRlbnRzLiBBbnkgc3RvcmVkIHZhbHVlIGNhbiBiZSBhZGp1c3RlZCBpbiBhIHNwcmVhZHNoZWV0IGFuZCB0aGUKZWZmZWN0IG9ic2VydmVkIG9uIHRoZSBjYWxjdWxhdGVkIHZhbHVlcyBjYW4gYmUgb2JzZXJ2ZWQuIEFzIGEgcmVzdWx0LAp0aGUgc3ByZWFkc2hlZXQgY2FuIGJlIHV0aWxpemVkIGZvciAid2hhdC1pZiIgYW5hbHlzaXMgYXMgbWFueSBjYXNlcyBjYW4KYmUgcXVpY2tseSBpbnZlc3RpZ2F0ZWQgd2l0aG91dCB0aGUgbmVlZCBmb3IgbWFudWFsIHJlY2FsY3VsYXRpb24uClNwcmVhZHNoZWV0cyBhcmUgYSB0eXBlIG9mIGRvY3VtZW50IGNvbnRhaW5pbmcgc3RydWN0dXJlZCBpbmZvcm1hdGlvbgpkYXRhIG9iamVjdHMuCgpTdHJ1Y3R1cmVkIGluZm9ybWF0aW9uIG9iamVjdHMgaGF2ZSBwcm9wZXJ0aWVzIGluIHRoZSBmb3JtIG9mCmF0dHJpYnV0ZXMuIEZvciBleGFtcGxlLCBpbnN0YW5jZXMgb2YgYSAqQ291cnNlKiBoYXZlIGF0dHJpYnV0ZXMgc3VjaCBhcwoqdGl0bGUqLCAqbGVuZ3RoKiwgKmNyZWRpdHMqLCBhbW9uZyBvdGhlcnMsIGRlcGVuZGluZyBvbiB0aGUgdXNlIGNhc2VzLgpTdWNoIGluZm9ybWF0aW9uIG11c3Qgb2Z0ZW4gYmUgZXh0ZXJuYWxpemVkIGFuZCBzdG9yZWQgaW4gc29tZSBzdHJ1Y3R1cmUKd2hlcmUgdGhleSBjYW4gYmUgc2hhcmVkIGFuZCBxdWVyaWVkLiBBIHRhYnVsYXIgb3JnYW5pemF0aW9uIGlzIGEgY29tbW9uCmZvcm1hdCBmb3IgdGhlIGV4dGVybmFsaXphdGlvbiBvZiBzdHJ1Y3R1cmVkIGluZm9ybWF0aW9uIG9iamVjdHMuCgpUb2RheSwgc3ByZWFkc2hlZXRzIGFyZSBnZW5lcmFsbHkgcmVmZXJyZWQgdG8gYXMgKndvcmtzaGVldHMqIG9yLApzaW1wbHksICpzaGVldHMqLiBXb3Jrc2hlZXRzIGFyZSBvcmdhbml6ZWQgaW50byAqd29ya2Jvb2tzKi4gTXVsdGlwbGUKc2hlZXRzIGNhbiBiZSBpbnRlcmNvbm5lY3RlZCB0byByZXByZXNlbnQgcmVsYXRpb25zaGlwcywgYW5kIGRhdGEgY2FuIGJlCmRpc3BsYXllZCBhcyB0ZXh0LCBudW1iZXJzLCBvciBncmFwaGljcy4gSW50ZXJjb25uZWN0ZWQgd29ya3NoZWV0cyBhcmUgYQpmb3JtIG9mIHJlbGF0aW9uYWwgZGF0YSBhbmQgYSB3b3JrYm9vayBjYW4gYmUgbG9va2VkIGF0IGFzIGEgKnJlbGF0aW9uYWwKZGF0YSBzdG9yZSogLS0gaW4gZmFjdCwgc29tZSBzcHJlYWRzaGVldCBhcHBsaWNhdGlvbnMsIHN1Y2ggYXMgRXhjZWwsCmFsbG93IFNRTCBxdWVyaWVzIG9uIHdvcmtib29rcy4KClNwcmVhZHNoZWV0IHByb2dyYW1zIHN1Y2ggYXMgRXhjZWwgYXJlIGEgcG9wdWxhciAqZW5kLXVzZXIgZGV2ZWxvcG1lbnQKdG9vbCAoRVVEKSouIEVVRCByZWZlcnMgdG8gYWN0aW9ucyBvciBtZXRob2RzIHVzZWQgYnkgbm9uLXByb2Zlc3Npb25hbApkZXZlbG9wZXJzIHRvIGJ1aWxkIGNvbXB1dGF0aW9uYWwgZGF0YSBvYmplY3RzIGFuZCBhdXRvbWF0ZWQgYmVoYXZpb3IKd2l0aG91dCByZXF1aXJpbmcgYSBkZWVwIHVuZGVyc3RhbmRpbmcgb2YgcHJvZ3JhbW1pbmcgb3IgcHJvZ3JhbW1pbmcKbGFuZ3VhZ2VzLiBJbiBtYW55IHdheXMgdXNpbmcgc3ByZWFkc2hlZXRzIHRvIGV4cHJlc3MgY29tcHV0YXRpb25hbApzdHJ1Y3R1cmUgaXMgbW9yZSBjb252ZW5pZW50IGFuZCBxdWlja2VyIHRoYW4gY3JlYXRpbmcgYSB0eXBpY2FsIHByb2dyYW0KdGhhdCBwZXJmb3JtcyB0aGUgc2FtZSBmdW5jdGlvbiwgYWx0aG91Z2ggbGFuZ3VhZ2VzIHN1Y2ggYXMgUiBvZnRlbgphbGxvdyByYXBpZCBkZXZlbG9wbWVudCBvZiBzb3BoaXN0aWNhdGVkIGRhdGEtZHJpdmVuIGNvZGUuIFN1Y2ggYXMKZW5kLXVzZXIgZGV2ZWxvcGVkIHNwcmVhZHNoZWV0IGlmIHNvbWV0aW1lcyBjYWxsZWQgYSAqc3ByZWFkc2hlZXQKcHJvZ3JhbSogb3IgYSAqc3ByZWFkc2hlZXQgbW9kZWwqLgoKIyMgVGFidWxhciBTdHJ1Y3R1cmVzCgpJbmZvcm1hdGlvbiBvYmplY3RzIGFyZSBzdG9yZWQgaW4gdGFidWxhciBmb3JtIGluOgoKLSAgIENTViB0ZXh0IGRhdGEgZmlsZXMKLSAgIEV4Y2VsIChhbmQgb3RoZXIgc3ByZWFkc2hlZXQgcHJvZ3JhbSkgd29ya3NoZWV0cwotICAgRGF0YSBmcmFtZXMgaW4gUiBhbmQgUHl0aG9uCi0gICBSZWxhdGlvbmFsIGRhdGFiYXNlIHRhYmxlcwotICAgVHdvLUxldmVsIFhNTCBkb2N1bWVudHMKCkFsbCB0YWJ1bGFyIHN0cnVjdHVyZXMgaGF2ZSB0aGUgc2FtZSBmb3JtYXQ6IHJvd3Mgd2l0aCBjb2x1bW5zLiBFYWNoIHJvdwppcyBhbiBpbnN0YW5jZSBvZiBhbiBpbmZvcm1hdGlvbiBvYmplY3QsIHdoaWxlIGVhY2ggY29sdW1uIGlzIGFuCmF0dHJpYnV0ZSB2YWx1ZS4gUm93cyBhcmUgZ2VuZXJhbGx5IG51bWJlcmVkIHdoaWxlIGNvbHVtbnMgYXJlIG5hbWVkLgoKIyMjIENTVgoKVGhlIGV4YW1wbGUgYmVsb3cgc2hvd3MgZGF0YSBpbiBhIENTVi4gTm90ZSB0aGUgc2VwYXJhdGlvbiBvZiBjb2x1bW5zIGJ5CmNvbW1hcy4KCmBgYCAgICAgICAgIApQcm9kdWN0LENlcmVhbE5hbWUsTWFudWZhY3R1cmVyLENhbG9yaWVzLFNvZGl1bSxGaWJlcixDYXJicyxTdWdhcnMsU2hlbGYsWWVhciwsCjEsMTAwJSBCcmFuLE5hYmlzY28sNzAsMTMwLDEwLDUsNiwzLDE5NDIsLAoyLEFsbC1CcmFuLEtlbGxvZ2csNzAsMjYwLDksNyw1LDMsMTkxNiwsCjMsQWxsLUJyYW4gdy9FeHRyYSBGaWJlcixLZWxsb2dnLDUwLDE0MCwxNCw4LDAsMywxOTE2LCwKYGBgCgpBIGNlbGwgb3IgYSByYW5nZSBvZiBjZWxscyBjYW5ub3QgYmUgZGlyZWN0bHkgc3BlY2lmaWVkIHVudGlsIHRoZSBDU1YgaXMKbG9hZGVkIGludG8gYSBwcm9ncmFtIGZvciBwcm9jZXNzaW5nLgoKIyMjIEV4Y2VsCgpUaGUgaW1hZ2UgYmVsb3cgc2hvd3MgYW4gZXhhbXBsZSBvZiBhIHRhYnVsYXIgc3RydWN0dXJlIGluIEV4Y2VsLgpDb2x1bW5zIGFyZSBsZXR0ZXJzIChBLi5aLCBBQS1aWiwgZXRjLikgYW5kIHJvd3MgYXJlIG51bWJlcmVkOyBlYWNoCmludGVyc2VjdGlvbiBvZiBhIGNvbHVtbiBhbmQgYSByb3cgaXMgYSAqY2VsbCouIEluIGFkZGl0aW9uIHRvIGRhdGEKdmFsdWVzLCBjZWxscyBjYW4gYWxzbyBjb250YWluIGZvcm11bGFzIHdoaWNoIGFyZSBhbGdlYnJhaWMgZXhwcmVzc2lvbnMKcmVmZXJlbmNpbmcgY2VsbHMgb3IgcmFuZ2VzIG9mIGNlbGxzLiBBIHJhbmdlIG9mIGNlbGxzIGlzIHNpbWlsYXIgdG8gYQp2ZWN0b3IsIGFycmF5LCBvciBhIG1hdHJpeCBpbiBSLgoKIVtTYW1wbGUgVGFidWxhciBTdHJ1Y3R1cmUgaW4gYW4gRXhjZWwKV29ya3NoZWV0XShpbWFnZXMvU2FtcGxlRXhjZWwuanBnKXt3aWR0aD0iNTAlIn0KCkEgY2VsbCBpbiBFeGNlbCBpcyByZWZlcmVuY2VkIGFzIGEgY29sdW1uL3JvdyBwYWlyLCAqZS5nLiosICpENCoKcmVmZXJlbmNlcyB0aGUgKkNhbG9yaWVzKiBhdHRyaWJ1dGUgb2YgKlByb2R1Y3QqIGluc3RhbmNlIDMgYW5kIGhhcyB0aGUKdmFsdWUgKjUwKi4gQSByYW5nZSBvZiBjZWxscyBjYW4gYmUgc3BlY2lmaWVkIGJ5IGEgc3RhcnRpbmcgYW5kIGVuZGluZwpjZWxsLCAqZS5nLiosICpEMjpEOCogaXMgdGhlIHZlY3RvciBvZiB2YWx1ZXMKJFx7NzAsNzAsNTAsMTEwLDExMCwxMTAsMTMwXH0kLgoKIyMjIERhdGEgRnJhbWVzCgpEYXRhIGZyYW1lcyBhcmUgaW4tbWVtb3J5IHRhYnVsYXIgc3RydWN0dXJlcyBjb21tb24gaW4gc2V2ZXJhbApwcm9ncmFtbWluZyBsYW5ndWFnZXMsIGluY2x1ZGluZyBSIGFuZCBQeXRob24uIFdoaWxlIHRoZXkgY2FuIGJlCnByb2dyYW1tYXRpY2FsbHkgZ2VuZXJhdGVkLCB0aGV5IGFyZSB0eXBpY2FsbHkgdGhlIHJlc3VsdCBvZiBsb2FkaW5nIGEKQ1NWIGZpbGUsIEV4Y2VsIHdvcmtzaGVldCwgb3IgU1FMIHF1ZXJ5IHJlc3VsdCBpbnRvIGEgZGF0YSBmcmFtZS4KCkZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHdvcmtpbmcgd2l0aCBkYXRhIGZyYW1lcyBpbiBSLCBzZWUgW0xlc3NvbiA2LjEwMwpXb3JraW5nIHdpdGggVmVjdG9ycyBhbmQgRGF0YSBGcmFtZXMgaW4KUl0oaHR0cDovL2FydGlmaWNpdW0udXMvbGVzc29ucy8wNi5yL2wtNi0xMDMtdmVjcy1hbmQtZGZzL2wtNi0xMDMuaHRtbCkKYW5kIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHJlYWRpbmcgZmlsZXMgaW50byBkYXRhIGZyYW1lcywgc2VlIFtMZXNzb24KNi4xMDYgSW1wb3J0IERhdGEgaW50byBSIGZyb20gQ1NWLCBUU1YsIGFuZCBFeGNlbApGaWxlc10oaHR0cDovL2FydGlmaWNpdW0udXMvbGVzc29ucy8wNi5yL2wtNi0xMDYtbG9hZC1jc3YtdHN2LWV4Y2VsLWZpbGVzL2wtNi0xMDYuaHRtbCkKCiMjIyBYTUwKCkluIHNvbWUgc2l0dWF0aW9ucywgWE1MIGRvY3VtZW50cyB3aGVyZSBlbGVtZW50cyBkaXJlY3RseSB1bmRlcm5lYXRoIHRoZQpyb290IHJlcHJlc2VudCByb3dzIGFuZCB0aGUgY2hpbGQgZWxlbWVudHMgdW5kZXIgdGhlIHJvd3MgcmVwcmVzZW50cwpjb2x1bW5zIGFyZSB1c2VkIGFzIGFuIGFsdGVybmF0aXZlIHRvIENTVi4gQW4gZXhhbXBsZSBpcyBzaG93biBiZWxvdwp3aGVyZSBlYWNoIDxyb3c+IGVsZW1lbnQgaXMgYSByb3cgYW5kIHRoZSBjb2x1bW5zIGFyZSA8R2lydGg+LCA8SGVpZ2h0PiwKYW5kIDxWb2x1bWU+LgoKYGBgIHhtbAo8P3htbCB2ZXJzaW9uPSIxLjAiPz4KCjxkb2N1bWVudD4KICA8cm93PgogICAgPEdpcnRoPjguMzwvR2lydGg+CiAgICA8SGVpZ2h0PjcwPC9IZWlnaHQ+CiAgICA8Vm9sdW1lPjEwLjM8L1ZvbHVtZT4KICA8L3Jvdz4KICA8cm93PgogICAgPEdpcnRoPjguNjwvR2lydGg+CiAgICA8SGVpZ2h0PjY1PC9IZWlnaHQ+CiAgICA8Vm9sdW1lPjEwLjM8L1ZvbHVtZT4KICA8L3Jvdz4KICAuLi4KPC9kb2N1bWVudD4KYGBgCgpNb3N0IGNvbW1vbmx5LCBzdWNoIFhNTCBmaWxlcyBhcmUgY29udmVydGVkIHRvIGEgQ1NWIG9yIHJlYWQgaW50byBhCnByb2dyYW1taW5nIGxhbmd1YWdlIGFzIGEgdGFibGUuIEZvciBleGFtcGxlLCBpbiBSLCB0aGUgZnVuY3Rpb24KYHhtbFRvRGF0YUZyYW1lKClgIGlzIG9mdGVuIHVzZWQgdG8gcmVhZCBzdWNoIGEgc3BlY2lhbGx5LWZvcm1hdHRlZCBYTUwKaW50byBhIGRhdGEgZnJhbWUuCgpGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB1c2luZyBgeG1sVG9EYXRhRnJhbWUoKWAsIHNlZSBbTGVzc29uIDYuMzIzIExvYWQKU2ltcGxlIFhNTCBpbnRvIERhdGFmcmFtZSBpbiBSIHVzaW5nCnhtbFRvRGF0YUZyYW1lXShodHRwOi8vYXJ0aWZpY2l1bS51cy9sZXNzb25zLzA2LnIvbC02LTMyMy1sb2FkLXhtbC14bWxUb0RhdGFGcmFtZS9sLTYtMzIzLmh0bWwpLgoKIyMgRGF0YSBBbmFseXRpY3MgUGlwZWxpbmUKCkRhdGEgYW5hbHlzaXMgZm9sbG93cyBhIHByb2Nlc3MgYW5kIG11c3QgYmUgbWV0aG9kaWNhbC4gRm9yIHRoYXQKcHVycG9zZSwgaW5kdXN0cnkgc3RhbmRhcmQgZGF0YSBwcm9qZWN0IG1hbmFnZW1lbnQgbWV0aG9kb2xvZ2llcywgc3VjaAphcwpbQ1JJU1AtRE1dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nyb3NzLWluZHVzdHJ5X3N0YW5kYXJkX3Byb2Nlc3NfZm9yX2RhdGFfbWluaW5nKSwKaGF2ZSBiZWVuIGRldmVsb3BlZC4KCiFbRGF0YSBBbmFseXRpY3MgUGlwZWxpbmVdKGltYWdlcy9pLTU2LTgwMC1kYXRhLWFuYWx5dGljcy1wcm9jZXNzLmpwZykKCiMjIEVzc2VudGlhbHMgb2YgRXhjZWwgYW5kIFNoZWV0CgojIyMgT2JqZWN0aXZlcwoKLSAgIERpc3Rpbmd1aXNoIGJldHdlZW4gdmFsdWVzLCB0eXBlcywgYW5kIGZvcm1hdCBvZiBhIGNlbGwKLSAgIEFwcGx5IGNvbmRpdGlvbmFsIGZvcm1hdHRpbmcKCiMjIyBUdXRvcmlhbAoKV2F0Y2ggdGhlIHR1dG9yaWFsIGJlbG93IHRvIGdldCBhbiBvdmVydmlldyBvZiBFeGNlbCBhbmQgR29vZ2xlIFNoZWV0LgoKPGlmcmFtZSBzcmM9Imh0dHBzOi8vbm9ydGhlYXN0ZXJuLmhvc3RlZC5wYW5vcHRvLmNvbS9QYW5vcHRvL1BhZ2VzL0VtYmVkLmFzcHg/aWQ9ZjExMGM3NDYtYzllOC00MWZhLWEyOTUtYWY4ODAwZTJjZThkJmFtcDthdXRvcGxheT1mYWxzZSZhbXA7b2ZmZXJ2aWV3ZXI9dHJ1ZSZhbXA7c2hvd3RpdGxlPWZhbHNlJmFtcDtzaG93YnJhbmQ9ZmFsc2UmYW1wO2NhcHRpb25zPWZhbHNlJmFtcDtpbnRlcmFjdGl2aXR5PWFsbCIgaGVpZ2h0PSIyNzAiIHdpZHRoPSI0ODAiIHN0eWxlPSJib3JkZXI6IDFweCBzb2xpZCAjNDY0NjQ2OyIgZGF0YS1leHRlcm5hbD0iMSIgLz4KCioqU2xpZGUgRGVjayoqOiBbSW5mb3JtYXRpb24gUHJvY2Vzc2luZyB3aXRoIEV4Y2VsIGFuZCBHb29nbGUgU2hlZXQ6IEEKUHJpbWVyXShzLTU2LTgwMC1leGNlbC1wcmltZXIucHB0eCkKCiMjIFJlZmVyZW5jZXMsIFJhbmdlcywgYW5kIFNpbXBsZSBGb3JtdWxhcwoKIyMjIE9iamVjdGl2ZXMKCi0gICBDcmVhdGUgcmVmZXJlbmNlcwotICAgQnVpbGQgc2ltcGxlIGZvcm11bGFzCi0gICBVc2UgYW5jaG9yaW5nIG9mIGNlbGwgcmVmZXJlbmNlcwotICAgRGVmaW5lIG5hbWVkIHJhbmdlcwoKIyMjIFR1dG9yaWFsCgpXYXRjaCB0aGUgdHV0b3JpYWwgYmVsb3cgZm9yIGRldGFpbHMsIGV4YW1wbGVzLCBhbmQgZGVtb25zdHJhdGlvbnMgb24KdGhlIGNvbmNlcHRzIG9mIHRoaXMgc2VjdGlvbi4KCjxpZnJhbWUgc3JjPSJodHRwczovL25vcnRoZWFzdGVybi5ob3N0ZWQucGFub3B0by5jb20vUGFub3B0by9QYWdlcy9FbWJlZC5hc3B4P2lkPTc2ZDQ4Njg0LTU2OWUtNDVhMi04OTQ2LWFmODgwMTA4ZTA5NSZhbXA7YXV0b3BsYXk9ZmFsc2UmYW1wO29mZmVydmlld2VyPXRydWUmYW1wO3Nob3d0aXRsZT1mYWxzZSZhbXA7c2hvd2JyYW5kPWZhbHNlJmFtcDtjYXB0aW9ucz1mYWxzZSZhbXA7aW50ZXJhY3Rpdml0eT1hbGwiIGhlaWdodD0iMjcwIiB3aWR0aD0iNDgwIiBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgIzQ2NDY0NjsiIGRhdGEtZXh0ZXJuYWw9IjEiIC8+CgoqKlNsaWRlIERlY2sqKjogW0luZm9ybWF0aW9uIFByb2Nlc3Npbmcgd2l0aCBFeGNlbCBhbmQgR29vZ2xlIFNoZWV0OiBBClByaW1lcl0ocy01Ni04MDAtZXhjZWwtcHJpbWVyLnBwdHgpCgojIyBUZXh0IFByb2Nlc3NpbmcKClNvbWUgYXR0cmlidXRlcyBvZiBkYXRhIG9iamVjdHMgYXJlIHRleHR1YWwgYW5kIHRob3MgYXR0cmlidXRlcyBkbyBub3QKb2Z0ZW4gY29tZSBpbiBhIHJlYWR5IHRvIHByb2Nlc3MgZm9ybS4gVGV4dCBwcm9jZXNzaW5nIGhlbHBzIHNoYXBlIHRleHQKYXR0cmlidXRlcyBpbnRvIGFuYWx5emFibGUgZm9ybWF0cy4KCkZ1cnRoZXJtb3JlLCB0ZXh0IGRhdGEgaXMgbm90IHRoZSBzYW1lIGFzIG51bWVyaWMgZGF0YSwgYW5kIHRleHQgbXVzdCBiZQpvZnRlbiBiZSBjb252ZXJ0ZWQgdG8gbnVtZXJpYyBmb3JtYXQgYmVmb3JlIGNhbGN1bGF0aW9ucyBjYW4gYmUKcGVyZm9ybWVkIG9uIHRob3NlIHZhbHVlcy4gV2Ugd2lsbCBzZWUgYSBudW1iZXIgb2YgZGlmZmVyZW50IHRleHQKcHJvY2Vzc2luZyBhbmQgdGV4dCBwYXJzaW5nIGZ1bmN0aW9uLCBwbHVzIHRoZSBgSUZgIGZ1bmN0aW9uIGZvciBjYXNlcwp3aGVyZSB0ZXh0IHBhdHRlcm5zIGhhdmUgZXhjZXB0aW9ucy4KCiMjIyBUdXRvcmlhbAoKV2F0Y2ggdGhlIHR1dG9yaWFsIGJlbG93IGZvciBkZXRhaWxzLCBleGFtcGxlcywgYW5kIGRlbW9uc3RyYXRpb25zIG9uCnRoZSBjb25jZXB0cyBvZiB0aGlzIHNlY3Rpb24uCgo8aWZyYW1lIHNyYz0iaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tL3ZpZGVvLzc4OTQ0ODAzMD9oPThiMDMwYzdjY2YiIHdpZHRoPSI0ODAiIGhlaWdodD0iMjcwIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImF1dG9wbGF5OyBmdWxsc2NyZWVuOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbiBkYXRhLWV4dGVybmFsPSIxIiAvPgoKKipTbGlkZSBEZWNrKio6IFtJbmZvcm1hdGlvbiBQcm9jZXNzaW5nIHdpdGggRXhjZWwgYW5kIEdvb2dsZSBTaGVldDogQQpQcmltZXJdKHMtNTYtODAwLWV4Y2VsLXByaW1lci5wcHR4KQoKIyMjIFdvcmtlZCBFeGFtcGxlCgpMb2FkIHRoZSB3b3JrYm9vayBbdGV4dHByb2Nlc3NpbmcueHNseF0oZGF0YS1maWxlcy90ZXh0cHJvY2Vzc2luZy54bHN4KQppbnRvIEV4Y2VsIG9yIEdvb2dsZSBTaGVldCBhbmQgdGhlbiBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CgoxLiAgSW4gdGhlIHdvcmtzaGVldCAiRXhlcmNpc2UiIGFyZSB0aHJlZSByb3dzIG9mIHRleHQgZGF0YS4gRXh0cmFjdCB0aGUKICAgIGVhY2ggbWVtYmVyJ3MgbmFtZSBhbmQgdGhlIGZlZSBhbmQgcGxhY2UgdGhlbSBpbnRvIHRoZSB0d28gbWFya2VkCiAgICBjb2x1bW5zLgoyLiAgTm90ZSB0aGF0IGl0IGlzIHBvc3NpYmxlIHRoYXQgc29tZSB0ZXh0IGRhdGEgZmllbGRzIGRvIG5vdCBoYXZlIGEKICAgIG1lbWJlciBuYW1lLiBIb3cgd291bGQgeW91IGRlYWwgd2l0aCB0aGF0IHNjZW5hcmlvPwozLiAgQ29udmVydCB0aGUgZmVlcyB0byBudW1iZXJzIGFuZCB0aGVuIGNhbGN1bGF0ZSB0aGUgc3VtIG9mIHRoZSBmZWVzLgo0LiAgRm9ybWF0IHRoZSBmZWVzIGNvbHVtbiBpbiAqQWNjb3VudGluZyBGb3JtYXQqLgoKVGhlIHR1dG9yaWFsIGJlbG93IGdvIHRocm91Z2ggYSBzb2x1dGlvbiBhcHByb2FjaC4gT2YgY291cnNlLCBvbmx5IHdhdGNoCml0IGFmdGVyIHlvdSBoYXZlIGRpbGlnZW50bHkgYW5kIGhvbmVzdGx5IHRyaWVkIHRvIHdvcmsgb3V0IHRoZSBzb2x1dGlvbgpmb3IgeW91cnNlbGYuCgpgYGB7PWh0bWx9CjxpZnJhbWUgd2lkdGg9IjQ4MCIgaGVpZ2h0PSIyNzAiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQva1daa3ZnMTdYTEkiIHRpdGxlPSJUZXh0IFByb2Nlc3NpbmcgaW4gRXhjZWwiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZTsgd2ViLXNoYXJlIiBhbGxvd2Z1bGxzY3JlZW4gZGF0YS1leHRlcm5hbD0iMSI+PC9pZnJhbWU+CmBgYAojIyBUYWJsZSBMb29rdXAKCldhdGNoIHRoZSB0dXRvcmlhbCBiZWxvdyBmb3IgZGV0YWlscywgZXhhbXBsZXMsIGFuZCBkZW1vbnN0cmF0aW9ucyBvbgp0aGUgY29uY2VwdHMgb2YgdGhpcyBzZWN0aW9uLgoKPGlmcmFtZSBzcmM9Imh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbS92aWRlby83ODk3MDcwMjk/aD0wNzBlYmUwMTBiJmFtcDt0aXRsZT0wJmFtcDtieWxpbmU9MCZhbXA7cG9ydHJhaXQ9MCZhbXA7c3BlZWQ9MCZhbXA7YmFkZ2U9MCZhbXA7YXV0b3BhdXNlPTAmYW1wO3BsYXllcl9pZD0wJmFtcDthcHBfaWQ9NTg0NzkiIHdpZHRoPSI0ODAiIGhlaWdodD0iMjcwIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImF1dG9wbGF5OyBmdWxsc2NyZWVuOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbiB0aXRsZT0iVGFibGUgTG9va3VwIHdpdGggVkxPT0tVUCIgZGF0YS1leHRlcm5hbD0iMSIgLz4KCioqU2xpZGUgRGVjayoqOiBbSW5mb3JtYXRpb24gUHJvY2Vzc2luZyB3aXRoIEV4Y2VsIGFuZCBHb29nbGUgU2hlZXQ6IEEKUHJpbWVyXShzLTU2LTgwMC1leGNlbC1wcmltZXIucHB0eCkKCiMjIERhdGEgVmFsaWRhdGlvbgoKV2F0Y2ggdGhlIHR1dG9yaWFsIGJlbG93IGZvciBkZXRhaWxzLCBleGFtcGxlcywgYW5kIGRlbW9uc3RyYXRpb25zIG9uCnRoZSBjb25jZXB0cyBvZiB0aGlzIHNlY3Rpb24uCgo8aWZyYW1lIHNyYz0iaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tL3ZpZGVvLzc5MDgzMjQ4Mz9oPTJjN2Q1YjJkMGIiIHdpZHRoPSI0ODAiIGhlaWdodD0iMzM4IiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImF1dG9wbGF5OyBmdWxsc2NyZWVuOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbiBkYXRhLWV4dGVybmFsPSIxIj4KCjwvaWZyYW1lPgoKKipTbGlkZSBEZWNrKio6IFtJbmZvcm1hdGlvbiBQcm9jZXNzaW5nIHdpdGggRXhjZWwgYW5kIEdvb2dsZSBTaGVldDogQQpQcmltZXJdKHMtNTYtODAwLWV4Y2VsLXByaW1lci5wcHR4KQoKIyMgRXhjZWwgdnMgUgoKQm90aCBFeGNlbCBhbmQgUiBhcmUgZXhjZWxsZW50IHRvb2xzIGZvciBhbmFseXppbmcgdGFidWxhciBkYXRhLCBidXQgUgpoYXMgdGhlIGRpc3RpbmN0IGJlbmVmaXQsIGVzcGVjaWFsbHkgd2l0aCB0aGUgdXNlIG9mIFIgTm90ZWJvb2tzLCBpZgptYWtpbmcgdGhlIGFuYWx5c2lzICpyZXByb2R1Y2libGUqLiBSZXByb2R1Y2FiaWxpdHkgaXMgY3JpdGljYWwgZm9yCmFuYWx5dGljcywgZGF0YSBtaW5pbmcsIGFuZCBwcmVkaWN0aXZlIG1vZGVsaW5nIGFzIGl0IGFsbG93cyB0aGUgcHJvY2Vzcwp0byBiZSBpbnNwZWN0ZWQgYW5kIGF1ZGl0ZWQgLS0gb25lIGtub3dzIHByZWNpc2VseSBob3cgdGhlIHJlc3VsdCB3YXMKcHJvZHVjZWQuIFRoaXMgaXMgbm90IGVhc3kgdG8gZG8gaW4gRXhjZWwuCgpJbiBmYWN0LCB0aGVyZSBoYXZlIGJlZW4gbnVtZXJvdXMgY2FzZXMgd2hlcmUgYSBiYWQgZm9ybXVsYSBvciBhbgppbmNvcnJlY3QgY2VsbCByZWZlcmVuY2UgbGVkIHRvIGluY29ycmVjdCBjb25jbHVzaW9ucy4gT25lIHN1Y2ggaW5zdGFuY2UKb2NjdXJyZWQgaW4gMjAxMyB3aGVuIFVNYXNzLUFtaGVyc3QgZ3JhZHVhdGUgc3R1ZGVudCBUaG9tYXMgSGVybmRvbgp1bmNvdmVyZWQgbWFqb3IgZXJyb3JzIGluIHRoZSBzcHJlYWRzaGVldCB1c2VkIGJ5IHRoZSBlY29ub21pc3RzClJlaW5oYXJ0IGFuZCBSb2dvZmYgaW4gdGhlaXIgaW5mbHVlbnRpYWwgMjAxMCBwYXBlciAqR3Jvd3RoIGluIGEgVGltZSBvZgpEZWJ0Ki4gVGhlaXIgd29yayB3YXMgdXNlZCB0byBkcml2ZSBtYWpvciBlY29ub21pYyBwb2xpY3kgd2hpY2ggbGVkIHRvCnRoZSBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgMjAxMC0yMDEzIEV1cm9wZWFuIGF1c3Rlcml0eSBwcm9ncmFtcy4KVW5mb3J0dW5hdGVseSwgdGhlIHBvbGljeSBkZWNpc2lvbiB3ZXJlIGJhc2VkIG9uIGluY29ycmVjdCBjb25jbHVzaW9ucwpmcm9tIGEgZmxhd2VkIEV4Y2VsIG1vZGVsIC0tIGFuIG91dGNvbWUgdGhhdCBsaWtlbHkgY291bGQgaGF2ZSBiZWVuCmF2b2lkZWQgaWYgcmVwcm9kdWNpYmxlIGFuYWx5c2lzIHdpdGhpbiBhbiBSIE5vdGVib29rIChvciBhIHNpbWlsYXIKbGFuZ3VhZ2UpIGhhZCBiZWVuIHVzZWQuCgpFeGNlbCBpcyBub3QgdmVyeSBnb29kIGF0IHN1bW1hcml6aW5nIGRhdGEsIGdyb3VwaW5nIGRhdGEsIG9yIGZpbmRpbmcKbXVsdGlwbGUgbWF0Y2hpbmcgdmFsdWVzLiBGb3IgdGhhdCwgUiBhbmQgU1FMIGFyZSBtdWNoIGJldHRlciwgYWx0aG91Z2gKc29tZSBvZiB0aG9zZSB0eXBlcyBvZiAicXVlcmllcyIgY2FuIGJlIGRvbmUgaW4gRXhjZWwgdXNpbmcgUGl2b3QgVGFibGVzCm9yIGJ5IHdyaXRpbmcgVkJBIG1hY3Jvcy4KCk5ldmVydGhlbGVzcywgRXhjZWwgaGFzIG9uZSBzaWduaWZpY2FudCBiZW5lZml0OiAqd2hhdC1pZiBhbmFseXNpcyouCkNlbGxzIHZhbHVlcyBjYW4gYmUgY2hhbmdlZCBpbnRlcmFjdGl2ZWx5IHRvIGV4cGxvcmUgb3V0Y29tZXMgb2YgbW9kZWxzCmludGVyYWN0aXZlbHkuIFRoaXMgY2FuIG9ubHkgYmUgZG9uZSBpZiB3ZSBidWlsZCBSIERhc2hib2FyZHMgdXNpbmcKcGFja2FnZXMgc3VjaCBhcyAqKnNoaW55KiouIFNvLCB0aGVyZSBhcmUgc3RpbGwgZ29vZCB1c2UgY2FzZXMgZm9yCnNwcmVhZHNoZWV0IHByb2dyYW1zLCBidXQgdGhlIGFyc2VuYWwgb2YgdGhlIGRhdGEgYW5hbHlzdCBtdXN0IGFsc28KaW5jbHVkZSBSIChhbmQgc2ltaWxhciBsYW5ndWFnZXMpLgoKIyMgU3VtbWFyeQoKVGhpcyBsZXNzb24gcHJvdmlkZWQgYSBwcmltZXIgb24gd29ya2luZyB3aXRoIHRhYnVsYXIgaW5mb3JtYXRpb24Kb2JqZWN0cyBpbiBFeGNlbCBhbmQgR29vZ2xlIFNoZWV0LgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBGaWxlcyAmIFJlc291cmNlcwoKYGBge3IgemlwRmlsZXMsIGVjaG89RkFMU0V9CnppcE5hbWUgPSBzcHJpbnRmKCJMZXNzb25GaWxlcy0lcy0lcy56aXAiLCAKICAgICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksCiAgICAgICAgICAgICAgICAgcGFyYW1zJG51bWJlcikKCnRleHRBTGluayA9IHBhc3RlMCgiQWxsIEZpbGVzIGZvciBMZXNzb24gIiwgCiAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwiLiIscGFyYW1zJG51bWJlcikKCiMgZG93bmxvYWRGaWxlc0xpbmsoKSBpcyBpbmNsdWRlZCBmcm9tIF9pbnNlcnQyREIuUgprbml0cjo6cmF3X2h0bWwoZG93bmxvYWRGaWxlc0xpbmsoIi4iLCB6aXBOYW1lLCB0ZXh0QUxpbmspKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgUmVmZXJlbmNlcwoKTm9uZS4KCiMjIEVycmF0YQoKW0xldCB1cwprbm93XShodHRwczovL2Zvcm0uam90Zm9ybS5jb20vMjEyMTg3MDcyNzg0MTU3KXt0YXJnZXQ9Il9ibGFuayJ9LgoK