Note:

-An R Notebook is an R Markdown document with chunks that can be executed independently and interactively, with output visible immediately beneath the input.

-Notebook output are available as HTML, PDF, Word, or Latex.

-This Notebook as HTML is preferably open with Google Chrome.

-R-Code can be extracted as Rmd file under the button “Code” in the notebook.

-This Notebook using iterative development. It means the process starts with a simple implementation of a small set of idea requirements and iteratively enhances the evolving versions until the complete version is implemented and perfect.


Welcome to OpenRefine!

#Link: https://www.pilsudski.org/en/news/blog/870-oczyszczanie-danych-z-uzyciem-openrefine-2

What is OpenRefine?

OpenRefine (formerly Google Refine) is a powerful tool for working with messy data: cleaning it; transforming it from one format into another; and extending it with web services and external data.

  • Formerly known as “Google Refine”
  • Free & open-source
  • Tool for cleaning large datasets
  • Can create links between metadata sets
  • Desktop application - run locally (without worry about data privacy)
  • http://openrefine.org/

Big Idea of OpenRefine:

What -A messy, unstructured, inconsistent dataset can be explored using open refine. In general, it will be very difficult to explore data through redundancies and inconsistencies.But, OpenRefine gives several functions through which one can filter the data, edit the inconsistencies, and view the data. It’s a tool to clean the data.

Why -Spreadsheets can also refine a dataset but they are not the best tool for it as Openrefine cleans data in a more systematic controlled manner. While using historical data, we come across issues like blank fields, duplicate records, inconsistent formats and using Openrefine tool can help to resolve such issues.

When -Now data analysis play an important role in business. Data analysts improve decision making, cut costs and identify new business opportunities. Analysis of data is a process of inspecting, cleaning, transforming, and modelling data with the goal of discovering useful information, suggesting conclusions, and supporting decision making. So, to ensure the accuracy of our analysis, we have to clean our data

What can OpenRefine do:

  • Cleaning messy data: for example if working with a text file with some semi-structured data, it can be edited using transformations, facets and clustering to make the data cleanly structured.[8]
  • Transformation of data: converting values to other formats, normalizing and denormalizing.
  • Parsing data from web sites: OpenRefine has a URL fetch feature and jsoup HTML parser and DOM engine.[9]
  • Adding data to dataset by fetching it from webservices (i.e. returning json).[10] For example, can be used for geocoding addresses to geographic coordinates.[11]
  • Aligning to Wikidata (formerly Freebase[12]): this involves reconciliation - mapping string values in cells to entities in Wikidata.
  • Data Normalization
  • Column Reorganization
  • Faceting and Clustering
  • Tracking Operations
  • Exporting Data
#Link: https://sites.temple.edu/tudsc/2016/12/13/preparing-data-with-openrefine-part-ii-assign-unique-numerical-identifiers/

Why OpenRefine is a better tool?

#link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf

OpenRefine Strengths and Weaknesses:

#link: https://guides.library.illinois.edu/openrefine/about

Strengths:

  1. OpenRefine is a desktop application. It opens in the browser as a Local Webserver. So, the data is safe and it doesn’t get uploaded to the Google server.

  2. It has facets which is used to filter the data into subsets and these clusters can be customized and organised into meaningful data.

  3. It has a Browser based interface, and so can handle more data efficiently.

  4. Openrefine has a strong feature in extending data – user can use it to find Meta Data and it can be used to correlate with it.

Weakness:

  1. The UI of Openrefine is not user friendly. Although the features and functions are strong, the UI make Openrefine looks boring. Besides, in the visualization, the function is not scalable. For instance, Openrefine give user a view of data, but the image is not big enough to figure out complex distribution.

  2. Unfortunately Google has removed support for this tool, making few of its features redundant.

FAQ:

  1. OpenRefine opens on my browser. So do I require internet to run it? Ans. No. OpenRefine doesn’t require internet for running. It’s a normal application, however runs on a local server.

  2. What is the index of the first characteristic of one cell? Ans: It should be 0. So if you want the first two characteristic, you should write as value[0,1].

  3. Is OpenRefine only for Windows Operating System? Ans. OpenRefine is compatible with both Windows Operating System and Mac OS as well.

  4. Is my data safe in Openrefine? Ans: Yes it is safe because it runs on local server and data is stored on your computer’s directory.


1-Getting started

Learning Objectives:

  • The principles of data preparation
  • The OpenRefine community and the software interface
  • Installing and using OpenRefine

Introduction to data quality and integration:

#Link: https://www.google.com/search?q=the+data+processing+pipeline&rlz=1C1GGRV_enDE813DE813&source=lnms&tbm=isch&sa=X&ved=0ahUKEwiE64CR6b_fAhXGdCwKHRhlCecQ_AUIDigB&biw=1366&bih=617#imgdii=H1DvabcYs-D1wM:&imgrc=wj9EOAJ47u1rkM:

Data Quality & Integration is Time Consuming (Popular phrase: fast 80% of data analytics time consuming)

  • Duplicate values & typos
  • Multi-value cells
  • Data in wrong field
  • Missing / Partial Values
  • Encoding Errors
  • Change formats (text, number, date)
  • Flat to relational data sets
  • Schema allignment
  • Transpose rows and columns
  • Join data sets
  • Enrichment from other sources (MDM, API calls)

Data Quality & Integration Solutions

#Link: https://courses.cognitiveclass.ai/courses/course-v1:BigDataUniversity+DP0101EN+2016/courseware/979efca08061457fb8238554799a17ab/3e67bdd387594e6a83f0120aef7b6e44/

Conclusion about Data Quality & Integration with OpenRefine.

In today’s fast-paced data environment, data engineers, scientists, and analysts are rare and can’t keep pace with the volume of requests. Domain experts are limited by the spreadsheet software functionality.Open Refine empowers domain experts to work on their own data via self service data preparation solution that addresses the skill gap

Moving toward and agile data process:

#Link: https://courses.cognitiveclass.ai/courses/course-v1:BigDataUniversity+DP0101EN+2016/courseware/979efca08061457fb8238554799a17ab/3e67bdd387594e6a83f0120aef7b6e44/

Conclusion about Agile Data Process with OpenRefine.

OpenRefine is a powerful interface for Subject Matters Experts, allowing Business Analysts and Consultants to discover, normalize, and enrich their data with only limited technical knowledge. OpenRefine addresses the skill gap between domain and data experts. Domain experts drive the data process from discovery to preparation while data engineers provide expertise through scaling key process

OpenRefine history and community:

  • Gridworks era 2009 - 2010 from MetaWeb Inc. (Gridworks is open source under the BSD license)

  • Google acquires MetaWeb Inc. in 2010 and Gridworks is rebranden as Google Refine

  • Google Refine 2.0 is released in 2010

  • Google Refine 2.5 is released in 2011

  • In November 2012: Google stoppped supporting Google Refine, opening the project to the community. The Community moved the project to Github and rebranded it as OpenRefine

  • In 2013 OpenRefine2.6-beta is released

#Link: https://sites.temple.edu/tudsc/2016/12/13/preparing-data-with-openrefine-part-ii-assign-unique-numerical-identifiers/
#Link: https://courses.cognitiveclass.ai/courses/course-v1:BigDataUniversity+DP0101EN+2016/courseware/979efca08061457fb8238554799a17ab/3e67bdd387594e6a83f0120aef7b6e44/

OpenRefine interface tour:

#Link: https://journal.code4lib.org/articles/9652

Installing OpenRefine:

For Windows->

  • Go to the OpenRefine download page-> http://openrefine.org/download.html
  • Click on Windows kit to download the install file
  • To use it, unzip, and double-click on google-refine.exe (if you’re having issues with google-refine.exe try refine.bat instead)
  • Google Refine will then open in your web browser.
  • If it doesn’t open automatically, open a web broswer after you’ve started the program and go to the URL http://localhost:3333 and you should see OpenRefine (with chrome or firefox).

For Mac->

  • Download the DMG file.
  • Open the disk image and drag the OpenRefine icon into the Applications folder.
  • Double-click on the icon to start OpenRefine.

For Linux->

  • Download the gzipped tarball.
  • Extract the folder to your home directory.
  • In a terminal, enter ./refine to start.

Note: OpenRefine will allocate only 1 GB of RAM. For more capacity see the another explanation about “for more memory”.

Creating a new project:

The start screen of OpenRefine.

# Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

Create Project from different sources.

  • This Computer: Select a file stored on your local machine
  • Web Addresses (URLs): Import data directly from an online source
  • Clipboard: Copy-paste your data into a text field
  • Google Data: Enable access to a Google Spreadsheet or Fusion Table

Open Project: Previous Project

Import Project: Open the Project

File formats supported by OpenRefine:

  • Comma-Separated Values (CSV), Tab-Separated Values (TSV), and other *SV
  • MS Excel documents (both .XLS and .XLSX) and Open Document Format (ODF) spreadsheets (.ODS), although the latter is not explicitly mentioned
  • JavaScript Object Notation (JSON)
  • XML and Resource Description Framework (RDF) as XML
  • Line-based formats (logs)

If you need other formats, you can add them by way of OpenRefine extensions.

OpenRefine consists of three simple steps: selecting your file , previewing the import, and validating. The setting for validating step is in the following screenshot.

Exploring the data:

#http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf
  1. Total number of rows
  2. Display options
  3. Column headers and menus
  4. Cell contents:

Manipulating columns:

  • Collapsing and expanding columns: View | Collapse all other columns on the column Categories.

  • Moving columns around: The View option offers a quick way to collapse or expand all columns, while Edit columns | Re-order / remove columns…

  • Renaming and removing columns: Under the same Edit column menu item.

Project history:

Click on the Undo / Redo tab or extracted in JSON format by clicking on the Extract… button just under Undo / Redo.

#http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf
#http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

Exporting a project:

The Export menu in the top-right of the screen allows you to do just that:

Some of choice are:

  • Export project
  • HTML table
  • Triple loader and MQLWrite
  • Custom tabular exporter and templating
  • Templating

For more memory:

  • Windows

On Windows, you will have to edit the openrefine.l4j.ini file in OpenRefine’s main folder. Find the line that starts with -Xmx (which is Java speak for “maximum heap size”), which will show the default allocated memory: 1024M (meaning 1024 MB or 1 GB). Increase this as you see fit, for instance to 2048 M. The new settings will be in effect the next time you start OpenRefine.

  • Mac

The instructions for Mac are a bit more complicated, as this operating system hides the configuration files from sight. After closing OpenRefine, hold control and click on its icon, selecting Show package contents from the pop-up menu. Then, open the info. plist file from the Contents folder. You should now see a list of OpenRefine settings. Navigate to the Java settings and edit the value of VMOptions (these are the properties of the Java Virtual Machine). Look for the part that starts with -Xmx and change its default value of 1024 M to the desired amount of memory, for instance, -Xmx2048M.

  • Linux

This might come in as a surprise, but increasing allocated memory is easiest in Linux. Instead of starting OpenRefine with ./refine as you usually would do, just type in ´./refine -m 2048M, where 2048 is the desired amount of memory in MB. To make the change permanent, you can create an alias in the hidden.bashrc` file located in your home folder by adding the following line at the end of the file:

alias refine='cd path_to_refine ; ./refine -m 2048M'

Here, path_to_refine is the relative path from your home folder to the OpenRefine folder. Then, the next time you start OpenRefine with ./refine, it will be allocated 2 GB by default.


2. Key features

Learning Objectives:

  • Importing data
  • Sorting data
  • Faceting data (augmented)
  • Detecting duplicates
  • Applying a text filter
  • Using simple cell transformations
  • Removing matching rows

_Importing data

Get the data from various external sources. It has two parts; 1. Creation of Project and 2. Parsing Datas

1. Creation of Project:

Navigation->

  • OpenRefine
  • Click on “Create Proeject”
  • Select from the list the sheet or data
  • Click on Choose File
  • Next and Create Project

Steps->

  • Open Google Refine
  • Click on Choose File to browse through your documents and to select the particular document to play with.
  • You can even choose a website, or from your clipboard, or even google data.
  • Click on Next
  • The file is uploaded.
  • Give a name to the project, and click on create project

Sopporting format are TSV, CSV, *SV, .xls, .xlsx, JSON, XML, RDF as XML and google documents.

2. Parsing Data:

Parsing the Data such as the number of rows, blank rows etc.

_Sorting data

The Sort menu appearing at the top every columns as shown in the following screenshot:

_Faceting/filtering data

It is a method to filter data into subsets. Facets also allow you to apply a transformation to a subset of your data for text, number and dates.

Types of facets/filtering:

  1. Text: It shows number of rows for each group and gives a larger picture of data. Text facets can be applied on several columns. Facet-> Text facet
#Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf
  1. Numeric: This facet groups numbers into numeric range bins. Then we can select any range for use showing consecutive numbers
#Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

Before moving to customized facets, let’s quickly mention two other ways for faceting that are related to the numeric facet: the timeline facet and scatterplot facet.

A timeline facet requires dates, so text strings such as 17/10/1890 need to be converted to the date format first. You can try that on the Production Date column, but notice that real dates are a minority, since it also contains years such as 1984 and ranges such as 2006 to 2007. We can nonetheless navigate to Edit cells | Common transforms | To date in that column menu, transforming 79 cells into date format; for instance, 17/10/1890 will be converted to 1890-10-17T00:00:00Z, with the zeros indicating the time of day in hours, minutes, and seconds.

Clearly, 79 cells out of a total of 75,814 is not a lot, but a timeline facet on these values would still show objects created on a given date range from 26 February, 1880 to 31 January, 1952, while most values are either not time expressions (19,820) or blank (55,915).

The following screenshot shows what can be obtained with a timeline facet on the Production Date column after converting dates to OpenRefine’s internal time format:

#Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf
  1. Custom Text Facet: This is a text facet in which you can split the column data using expression (value.split("")[0]) without creating new column. Groups will be made according to spilt data sorted by their counts.
#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf
  1. Custom Numerical Facets: This facet allows you to customize the numeric facets. The numeric values can be grouped by their logs, modulus, length of string etc. This methoden need GREL (General Refine Expression Language)

  2. Customized facets: There are various types of customizable facets. They include Word Facet, Duplicate Facets, Numeric log facet, 1- bounded numeric log facet, text length facet, Log of text length facet, Unicode char-code facet, Facet by error, Facet by Blank.

#Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf
  1. Faceting by star or flag: Stars can be used to mark good rows or favorite rows that you want to pick up in order to come back to them later; conversely, flags can be used to indicate bad rows or problematic rows that will need special attention further on. Note that this is just a suggestion; you could use stars and flags to mean something completely different.

_Editing Cells/Columns/ Rows

1. Editing cells by using common Transforms:

The navigation for these functions is edit cells, Common Transform. Some of them are for removing whitespaces, applying capitalization styles and to convert the data into the desired data type.

#Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

2. Transforming Data extraction from existing column:

Suppose if we have uploaded text file for all students of UMD consisting of their courses, year, age etc. then we can extract year or any other data to make a new column for easy usage. New column can be made from existing columns.

  1. Navigation

Edit Cells , ???Transform

  1. Steps

We can remove space or any other unwanted symbols from the data too. Imported text file. The text file had some blank rows but while importing text file, we can select option not to store blank rows and it filters the data while creating project only.

#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf
    1. Using the expression value.replace(“**“,”“) to remove double stars.
#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf
    1. To remove year prefixed, select option “add column based on this column”
#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf
    1. Use expression value[1,5] which specifies the character range to separate years as below
#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf
    1. Using character string “value.substring(5)” which displays the data excluding year
#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf

3. Understanding Expressions:

OpenRefine support ‘Expressions’. And these are used to transform existing data or create new data based on existing data .This sounds similar to the ‘Formula’ which we used to have in Excel. But there is a big difference between them. The ‘Formula’ in the Excel can only be used to store various formulae for each cell for that specific column. Whereas, in Expressions, here by making use of “GREL”, we can access every row and column and can set up conditions according to that.click edit Cells , Transform.

Function 1: value + " (string)"

#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf

Function 2: value.trim().length()

#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf

Some Functions at a Glance:

  1. Syntax: - “Mr.” + value Explanation: - used to concatenate two strings

  2. Syntax: - value + 3.9 Explanation:-add two numbers, and if the value other than numbers, then it concatenates string

  3. Syntax: - value.trim().length() Explanation:-trims the leading and trailing whitespace

  4. Syntax: - value.substring(0,3) Explanation: - take the substring of value from character index 0 up to and excluding character index 3

_Detecting duplicates

Duplicates are annoying records that happen to appear twice (or more) in a dataset.

_applying a text filter

When you want to find rows matching a certain string, it is easier to rely on a simple text filter than on cumbersome facets.

_Removing matching rows

To remove rows, be sure to have a facet or filter in place first, otherwise you will remove all rows in the dataset.

Let’s start from the clean project again (import it for a second time or toggle the Undo / Redo tab and select 0. Create project to cancel all modifications) and see what we can do to clean up this dataset. Also, check that OpenRefine shows your data as rows, not records.

#Link: http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

_Exporting data

Export data from an existing OpenRefine project in several formats:

  • Tab separated values (TSV)
  • Comma separated values (CSV)
  • Excel
  • HTML table

Just click on the Export button at the top right corner and select the format that we want.

_Undo/ Redo

The flexibility to make mistakes and to rectify them. Gives you an opportunity to make a lot of trials and error on data.

    1. Before Undo/Redo

Here, you can see that on the left side of the panel, there are five steps which have been performed by the user .Out of which, the last one is greyed. The greyed step number 5 explains that Undo has already been performed once. To prove this point, we perform ‘Undo’ once again.

#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf
    1. After Undo/Redo

Here, you can see the same five steps with two greyed steps: step number 4 and step number 5.Here, we can see that the Undo function is performed and you can also see the data being altered to the previous step; which is making the first alphabet of the ‘first_name’ column capital.

#Link: https://casci.umd.edu/wp-content/uploads/2013/12/OpenRefine-tutorial-v1.5.pdf


3. Advanced features

_Handling multi-valued cells-rows

Use case:

Cevi Herdian, 017632811289, 017632811288

We have one Person with 2 different phone number. We want just the right one.

  1. Edit cells, Split Multiple cells with separator ,

Cevi Herdian

017632811289

017632811288

  1. We have 3 row now. And then we go to number or text facet (if a number or text) and make the right one. After that the wrong number will delete and the rest is like this:

Cevi Herdian

017632811289

  1. Finally, make sure this two rows in one cells again with join multi valued cells. And the final version of the person and the phone number are Cevi Herdian, 017632811289

More info about splitting values in OpenRefine: https://guides.library.illinois.edu/openrefine/splitting

_Alternating between rows and records mode

A row is a single line of data in your dataset. A record consists of all rows that belong to a single object. The first row of a record starts with non-null cells that identify the record; in subsequent rows, those identifying values are blank to indicate they belong to the same record.

Matching records that fit multiple criteria What if we want to match all records that are in the category Numismatics and also in the category Medals? To do this, we make sure that we are in records mode and we add a second text facet on the Categories field. In the first facet, we select Numismatics, and in the second facet, we select Medals. We now see all the records that are in both categories. Now what happens if we switch back to rows mode? Suddenly, zero records are matching our selection. This seems strange at first, but it is actually pretty logical: no single row has a category which is equal to Numismatics and Medals at the same time; each row contains at most one of these two. Therefore, complex selections such as this one should be made in records mode.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

_Clustering similar cells

Edit cells | Cluster and edit

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

What are clustering methods? OpenRefine offers two different clustering methods, key collision and nearest neighbor, which fundamentally differ in how they function. With key collision, the idea is that a keying function is used to map a field value to a certain key. Values that are mapped to the same key are placed inside the same cluster. For instance, suppose we have a keying function which removes all spaces; then, A B C, AB C, and ABC will be mapped to the same key: ABC. In practice, the keying functions are constructed in a more sophisticated and helpful way. Nearest neighbor, on the other hand, is a technique in which each unique value is compared to every other unique value using a distance function. For instance, if we count every modification as one unit, the distance between Boot and Bots is 2: one addition and one deletion. This corresponds to an actual distance function in OpenRefine, namely levenshtein.

_Transforming cell values

Edit cells | Transform

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

The heart of this dialog is Expression, a small script that explains OpenRefine how each of the values should change. The Language list allows us to choose the language for the expression, with current support for the General Refine Expression Language (GREL), Jython (Python implemented in Java), and Clojure (a functional language that resembles Lisp). If you are familiar with the latter two, you might find it easier to write expressions in those languages. However, GREL was specifically created with simple transformations in mind

Mastering GREL is easy This recipe introduced a few examples, but what if that doesn’t fulfill your needs? Appendix A, Regular Expressions and GREL will introduce you to GREL so you can learn how to build expressions yourself.

_Adding derived columns

  1. Edit column and Add column based on this column.

  2. Write the GREL expression

_Splitting data across columns

Edit column | Split into several columns.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

_ Transposing rows and columns

Transpose | Transpose cells across columns into rows

Edit column | Split into several columns.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf


4. Linking data

_Reconciling values with Freebase

When you want to transform your cell values from simple strings to URLs, different choices are possible. Some of them are Freebase, Auto-match candidates with high confidence, and reconciliation service provider.

The Reconciliation feature is used to link text names or values in the columns of your data to database identifiers in various database ID spaces. It helps you to develop Metadata to your data.

To start reconciliation, go to the Categories dropdown and navigate to Reconcile | Start reconciling..

With Freebase:

  • Freebase Query-based Reconciliation: This is useful if your column values are already Freebase IDs (such as /en/solar_system) or GUIDs (hexadecimal identifiers).

  • Freebase Reconciliation Service: This offers a more general approach for terms that are not necessarily related to Freebase identifiers.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

With Auto-match candidates with high confidence:

The auto-match option is on by default, and it means that if the score is sufficiently high, OpenRefine will assume it has made the right choice and declare it a match. For other cell values (or if you have unticked the checkbox), you will have to confirm the match manually.

The third and final option allows you to send additional data to the reconciliation service. Please find the reconciliation service that fit for your case.

More about date reconciliation: https://www.experian.co.uk/business/glossary/data-reconciliation/

_Installing extensions

While OpenRefine allows you out-of-the-box to add new reconciliation services, these are only services that work in a certain way under the hood.

OpenRefine extensions are available, including the following points:

  • The RDF extension by Digital Enterprise Research Institute (DERI), which adds support for RDF export and reconciliation with SPARQL endpoints. We’ll explain both terms in the next recipe.

  • The Named-Entity Recognition (NER) extension written by one of the authors of this book, which allows you to extract URLs from full-text fields. Usage of this extension is covered in detail in the last recipe of this chapter

Like OpenRefine, all extensions are available freely. An up-to-date list of available extensions is maintained at https://github.com/OpenRefine/OpenRefine/wiki/ Extensions

First, you will have to find the path where extensions need to be installed. This depends on your operating system, but OpenRefine can help you find it. At the bottom of the starting page, there is a link called Browse workspace directory.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

The next step is to download an extension and to place it in the folder. For instance, let’s install the RDF extension.

Now restart OpenRefine to make the extension active. Then, start OpenRefine again as usual and open a project. When the project has loaded, a new RDF button in the top-right tells you that the installation has been successful:

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

_Adding a reconciliation service

The Resource Description Framework (RDF) is a model for data that can be interpreted by machines. While humans can read HTML on the Web, machines do not understand natural language and must therefore be given information in another form.

The SPARQL Protocol and RDF Query Language (a recursive acronym for SPARQL) is a language for querying RDF datasources. Traditional relational databases use SQL as a query language; RDF databases and important for us, reconciliation services, communicate in SPARQL.

When you installed the RDF extension, you already added support for SPARQL to OpenRefine. However, before we can reconcile our cell values to URLs, we must configure the datasource. To do this, click on the new RDF button in the top-right and navigate to Add reconciliation service | Based on SPARQL endpoint.. Note that you can also reconcile with a local RDF file, which is handy if you have your own dataset of URLs. OpenRefine shows you the Add SPARQL-based reconciliation service dialog.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

_Reconciling with Linked Data

Tim Berners-Lee, inventor of the Web and one of the creators of the Semantic Web vision, realized this and launched the Linked Data principles (http://www.w3.org/DesignIssues/LinkedData.html). These principles shifted the focus of the Semantic Web to the creation of data that was interlinked with other datasets. The principles are as follows:

  1. Use URIs as names for things
  2. Use HTTP URIs so that people can look up those names
  3. When someone looks up a URI, provide useful information using the standards (RDF, SPARQL)
  4. Include links to other URIs so that they can discover more things
#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

_Extracting named entities

Reconciliation works great for those fields in your dataset that contain single terms, such as names of people, countries, or works of art. However, if your column contains running text, then reconciliation cannot help you, since it can only search for single terms in the datasets it uses. Fortunately, another technique called named-entity extraction can help us. An extraction algorithm searches texts for named entities which are text elements, such as names of persons, locations, values, organizations, and other widely-known things. In addition to just extracting the terms, most algorithms also try to perform disambiguation.

OpenRefine does not support named-entity recognition natively, but the Named-Entity Recognition extension adds this for you. Before continuing with this recipe, download the extension from http://software.freeyourmetadata.org/ner-extension/ and follow the Installing extensions recipe. If the installation was successful, you are greeted by the Named-entity recognition button in the top-right of your screen after restarting OpenRefine


5. Regular expressions for text patterns

_Character classes

  • The pattern Aar will look for all texts that contain a capital A followed by a small a and r. If the case sensitive box is not ticked, the capitalization will not matter.
  • The pattern 123 finds all texts that contain this number. Note that texts with the number 41235 are also matched, since 123 is a textual part of that.
  • As you can see, this does not differ from regular text matching yet. With regular expressions, we can also say that we expect any letter or any number. We can give a set of characters from which can be chosen by surrounding the alternatives with square brackets []. We can indicate a character range in those brackets by separating the limits with a hyphen.
  • The pattern [0123456789] matches all texts that contain a number.
  • The pattern [0-9] does the same, only it is more condense. It says everything between 0 and 9 is fine.
  • Similarly, the pattern [a-z] matches all lowercase letters (and also uppercase if the case-sensitive option is not used). [A-Z] matches uppercase letters and [a-zA-Z] matches all letters, regardless of the case-sensitive option.
  • If you want to look for numbers and letters, use [0-9a-zA-Z]. Read this as “every character between 0 and 9, between a and z, or between A and Z”.
  • As in the earlier examples, we can put several matchers next to each other. analy[sz]e will match both American (analyze) and British (analyse) spellings.
  • Similarly, the expression [0-9][a-z] will find numbers directly followed by at least one letter. The expression [a-z][0-9][0-9][0-9] finds letters directly followed by at least three numbers.
  • If you want to find measurements such as 1 cm or 25 in, you will not find them with the preceding expressions because of the space in between. Luckily, a space is also a symbol, so the expression [0-9] [a-z] will find them. Note the space in between the bracket pairs, and note the fact that this will even find longer measurements such as 12345 meters. Indeed, the expression matches a number followed by a space and a letter, so in this case, 5 m. It doesn’t matter whether other numbers or letters are also present.
  • If you’re just looking for measurements in inches, the expression [0-9] in will do the job.
  • It might be a bit cumbersome to write [0-9] in full every time. This is why shorthand character classes were introduced. They are symbols that stand for a set of characters. For instance, the symbol stands for any digit and is thus equivalent to [0-9], but a lot faster to write. The opposite is , which means anything that is not a digit and includes letters as well as symbols. Unfortunately, there is no shorthand for any letter, but there is a shorthand for any letter, number, or underscore, which is , which stands for any word character. Again, the opposite is , which matches for all non-letters and non-numbers that are not underscores either.
  • will again match for texts with measurements: any number followed by a space and a letter.
  • matches texts with numbers with a length of at least three.
  • matches texts that have at least two consecutive non-numbers. If you’re surprised to see texts with numbers as well, think about it: the expression only says that the text should contain a non-number followed by a non-number; it doesn’t say that there should be no numbers at all. However, if a text field only contains numbers, it won’t be matched. To rephrase, the expression means “I’m looking for two non-numbers in a row, do you have them?”
  • You might wonder how works. Does it then translate to a huge set that includes everything but numbers? The answer is more simple: using a caret ^ as the first character in braces means none of the characters should be present in the pattern. Therefore, stands for [^0-9].
  • The expression [^a-zA-Z0-9] looks for texts that contain something which is not a letter or number. Most texts will match, as for instance spaces and punctuation marks are still allowed. However, empty fields will not match, as there must be at least one character which is not a letter or number.
  • The expression [^a-zA-Z0-9]means any digit surrounded by non-letters or non-numbers. For instance, we see that single digits in parentheses are matched. Note that items such as (123) will not be matched, but (3) will, as we explicitly say that it should be a single digit.
  • The pattern a.a.a matches any text where an a is followed by any character, another a, any character, and another a. For instance, texts with the words dulcamara, alabaster, and salamander will match.
  • The pattern 19.. (there is a space before and after) will match years in the 20th century.
  • However, you should be careful with the dot: the last pattern also matches 19th and 19M$, because a dot really means anything. If a year is what you want, 19is more accurate.
  • To find texts that have three consecutive dots in them, use .... (This can actually be done in a more handy way, as we’ll see in the next section.)
  • To find texts with a backslash, use \. (There are none in the dataset.)
  • Texts that contain an opening or a closing square bracket are found with [
    []]. This looks complicated, but it is quite logical: the first and last bracket say “choose any of the things within”. And the things within are actual square brackets, but they have to be escaped, so they become \[ and \].
  • With [2],you find texts that contain the number 2 (“choose any of the things within”, and the only thing within is a 2). With \[2\], you find texts with the number 2 surrounded in square brackets, as the brackets are escaped this time and thus have no special meaning anymore.

_Quantifiers

Quantifiers can express repetition. There are three simple quantifiers: a plus sign +, which means one or more times, an asterisk *, which means zero or more times, and a question mark ?, which means zero or one time. They only exert an effect on the symbol that is directly to the left of them:

  • bre+d matches texts that contain bred, breed, or breeed with any number of e, as long as at least one e is present.
  • bre*d matches texts that contain brd, bred, breed, or breeed with any number of e, even without. Note how brd is matched with the asterisk, but not with the plus sign.
  • bre?d matches brd and bred, but not breed or any other number of es. Put simply, it makes the e optional.
  • Combinations are also possible. br?e+d matches bed, bred, beed, breed, beeed, breeed, and so on.
  • In addition, you can be explicit about the number of times you would like a symbol to occur by using curly braces {min,max}. You can specify the minimum and maximum number of times it can occur. Either one can be empty, in which case there is no minimum or maximum. Leave the comma in so OpenRefine knows whether you specified the minimum or the maximum. If you just supply a single number without a comma, the exact number of times will be matched.
  • N, matches texts that contain a code that starts with N followed by five, six, seven, or eight digits, and then a comma.
  • N, matches texts that contain a code that starts with N, at least five digits, and then a comma.
  • N, matches texts which contain a code that starts with N, at most eight digits, and then a comma.
  • N, matches texts which contain a code that starts with N, exactly five digits, and then a comma. This is equivalent to Nbut much more compact (especially if numbers get large).
  • Needless to say, the quantifiers and braces are special symbols, so if you want to match them literally, you should escape them with a backslash. For instance, question marks can be matched with ?.

_Anchors

Sometimes, you don’t only want to say how many characters to match, but also where they should be matched. This is possible with anchors. A caret ^ indicates that the match should happen at the beginning of a line, while a dollar sign $ indicates that the match should stop at the end of a line.

Additionally, we can indicate that the match should begin or end at a word boundary with the anchor :

  • ^matches all texts that begin with a number.
  • $ matches all texts that end with a number.
  • ^.*$ matches all texts that begin and end with a number. Read this expression as: start of the text, a number, zero or more times any character (the dot), a number, end of the text. If we would use ^+$ instead, we would have all texts that contain only a number (of any length).
  • searches for texts that contain at least one number of exactly three digits, since the anchor matches at word boundaries. If the text contains four-digit numbers but no three-digit numbers, it does not match. (If we would remove the anchors, it would.)
  • ^finds texts that start with a three-digit number.

_Choices

Square brackets give regular expressions the possibility to choose one of the many characters: [a-z123] searches for texts with at least one lowercase letter or any of the digits 1, 2, and 3. Often, the choices are larger, as they can be several letters or words long. For this, the or operator | was introduced. It works as an OR operator between several alternatives:

  • glass|wood|steel will match texts that contain glass, wood, or steel.
  • +|many|few matches either a number, many or few.
  • N,|N, matches either five-digit or eight-digit numbers that start with an N and end with a comma, but nothing in between (so no six-digit numbers for instance).

_Groups

If you want to use quantifiers on a group of characters instead of on a single character, you have to enclose them in parentheses ():

  • While la+ matches texts that contain la, laa, laaa, and so on, the expression (la)+ finds texts that contain la, lala, lalala, and so on.
  • The expression analyz|se would match texts that contain analyz and texts that contain se. This is probably not that useful. On the other hand, the expression analy(z|s)e matches both analyze and analyse. Note that in this case, this is equivalent to analy[zs]e because the choice consists of a single letter. However, this would not be the case with analyz(e|ing), which would match analyze and analyzing.

_Overview

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf


6. General Refine Expression Language (GREL)

_Transforming data

You can either change cells in-place (by navigating to the respective column dropdown and then to Edit cells | Transform.) or make a new column with the transformed values (by navigating to the respective column dropdown and then to Edit column | Add column based on this column.)

  • "TITLE: " + value + ".". Adds the text TITLE: before the value and appends a dot to the end.
  • value.replace("stone", "stones"). To replace the string stone by stones in each cell
  • value.split("|").length(). To split the value whenever it encounters a vertical bar, and then uses the length function to count the number of resulting values.
  • value.split("|").uniques().join("|"). Removes duplicate values from the field.

_Creating custom facets

Let’s create a simple facet by clicking on the Object Title dropdown and navigating to Facet | Customized Facets | Facet by blank.

#Link:http://file.allitebooks.com/20151012/Using%20OpenRefine.pdf

We see that the expression form to fill with GREL

_Solving problems with GREL

Also, you’ll gain more and more experience with regular expressions and GREL as you gradually begin to master the basics. From that point onwards, it is a small step to the things that are increasingly complex.

For more information: https://github.com/OpenRefine/OpenRefine/wiki/Understanding-Expressions


Change log update

This Notebook using iterative development. More preferences and revision will be added in the next steps. Below are the timeline change:

  • 07.05.2016
  • 27.12.2018
  • 02.01.2019
  • 08.01.2019
  • 23.01.2019


License

MIT

LS0tDQp0aXRsZTogIk9wZW5SZWZpbmUgMTAxIg0Kc3VidGl0bGU6ICJTdW1tYXJpemluZyBzZXJpZXMgZnJvbSBleGNlbGxlbnQgYXV0aG9ycyINCmF1dGhvcjogIkNldmkgSGVyZGlhbiwgQi4gU2MiDQpkYXRlOiAiMjcuMTIuMjAxOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgdGhlbWU6IGNvc21vDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDUNCiAgICB0b2NfZmxvYXQ6IHllcw0KLS0tDQoNCioqTm90ZToqKg0KDQotQW4gUiBOb3RlYm9vayBpcyBhbiBSIE1hcmtkb3duIGRvY3VtZW50IHdpdGggY2h1bmtzIHRoYXQgY2FuIGJlIGV4ZWN1dGVkIGluZGVwZW5kZW50bHkgYW5kIGludGVyYWN0aXZlbHksIHdpdGggb3V0cHV0IHZpc2libGUgaW1tZWRpYXRlbHkgYmVuZWF0aCB0aGUgaW5wdXQuDQoNCi1Ob3RlYm9vayBvdXRwdXQgYXJlIGF2YWlsYWJsZSBhcyBIVE1MLCBQREYsIFdvcmQsIG9yIExhdGV4LiANCg0KLVRoaXMgTm90ZWJvb2sgYXMgSFRNTCBpcyBwcmVmZXJhYmx5IG9wZW4gd2l0aCBHb29nbGUgQ2hyb21lLg0KDQotUi1Db2RlIGNhbiBiZSBleHRyYWN0ZWQgYXMgUm1kIGZpbGUgdW5kZXIgdGhlIGJ1dHRvbiAiQ29kZSIgaW4gdGhlIG5vdGVib29rLg0KDQotVGhpcyBOb3RlYm9vayB1c2luZyBpdGVyYXRpdmUgZGV2ZWxvcG1lbnQuIEl0IG1lYW5zIHRoZSBwcm9jZXNzIHN0YXJ0cyB3aXRoIGEgc2ltcGxlIGltcGxlbWVudGF0aW9uIG9mIGEgc21hbGwgc2V0IG9mIGlkZWEgcmVxdWlyZW1lbnRzIGFuZCBpdGVyYXRpdmVseSBlbmhhbmNlcyB0aGUgZXZvbHZpbmcgdmVyc2lvbnMgdW50aWwgdGhlIGNvbXBsZXRlIHZlcnNpb24gaXMgaW1wbGVtZW50ZWQgYW5kIHBlcmZlY3QuDQoNCg0KDQoNCjxicj4NCg0KI1dlbGNvbWUgdG8gT3BlblJlZmluZSENCg0KIVtdKE9wZW5SZWZpbmUuUE5HKQ0KDQoNCg0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCg0KI0xpbms6IGh0dHBzOi8vd3d3LnBpbHN1ZHNraS5vcmcvZW4vbmV3cy9ibG9nLzg3MC1vY3p5c3pjemFuaWUtZGFueWNoLXotdXp5Y2llbS1vcGVucmVmaW5lLTINCg0KYGBgDQoNCg0KDQoNCioqV2hhdCBpcyBPcGVuUmVmaW5lPyoqDQoNCk9wZW5SZWZpbmUgKGZvcm1lcmx5IEdvb2dsZSBSZWZpbmUpIGlzIGEgcG93ZXJmdWwgdG9vbCBmb3Igd29ya2luZyB3aXRoIG1lc3N5IGRhdGE6IGNsZWFuaW5nIGl0OyB0cmFuc2Zvcm1pbmcgaXQgZnJvbSBvbmUgZm9ybWF0IGludG8gYW5vdGhlcjsgYW5kIGV4dGVuZGluZyBpdCB3aXRoIHdlYiBzZXJ2aWNlcyBhbmQgZXh0ZXJuYWwgZGF0YS4NCg0KKiBGb3JtZXJseSBrbm93biBhcyAiR29vZ2xlIFJlZmluZSINCiogRnJlZSAmIG9wZW4tc291cmNlDQoqIFRvb2wgZm9yIGNsZWFuaW5nIGxhcmdlIGRhdGFzZXRzDQoqIENhbiBjcmVhdGUgbGlua3MgYmV0d2VlbiBtZXRhZGF0YSBzZXRzDQoqIERlc2t0b3AgYXBwbGljYXRpb24gLSBydW4gbG9jYWxseSAod2l0aG91dCB3b3JyeSBhYm91dCBkYXRhIHByaXZhY3kpDQoqIFtodHRwOi8vb3BlbnJlZmluZS5vcmcvXShodHRwOi8vb3BlbnJlZmluZS5vcmcvKQ0KDQoNCioqQmlnIElkZWEgb2YgT3BlblJlZmluZToqKg0KDQoqKldoYXQqKiAtQSBtZXNzeSwgdW5zdHJ1Y3R1cmVkLCBpbmNvbnNpc3RlbnQgZGF0YXNldCBjYW4gYmUgZXhwbG9yZWQgdXNpbmcgb3BlbiByZWZpbmUuIEluIGdlbmVyYWwsIGl0IHdpbGwgYmUgdmVyeSBkaWZmaWN1bHQgdG8gZXhwbG9yZSBkYXRhIHRocm91Z2ggcmVkdW5kYW5jaWVzIGFuZCBpbmNvbnNpc3RlbmNpZXMuQnV0LCBPcGVuUmVmaW5lIGdpdmVzIHNldmVyYWwgZnVuY3Rpb25zIHRocm91Z2ggd2hpY2ggb25lIGNhbiBmaWx0ZXIgdGhlIGRhdGEsIGVkaXQgdGhlIGluY29uc2lzdGVuY2llcywgYW5kIHZpZXcgdGhlIGRhdGEuIEl0J3MgYSB0b29sIHRvIGNsZWFuIHRoZSBkYXRhLg0KDQoqKldoeSoqIC1TcHJlYWRzaGVldHMgY2FuIGFsc28gcmVmaW5lIGEgZGF0YXNldCBidXQgdGhleSBhcmUgbm90IHRoZSBiZXN0IHRvb2wgZm9yIGl0IGFzDQpPcGVucmVmaW5lIGNsZWFucyBkYXRhIGluIGEgbW9yZSBzeXN0ZW1hdGljIGNvbnRyb2xsZWQgbWFubmVyLiBXaGlsZSB1c2luZyBoaXN0b3JpY2FsIGRhdGEsIHdlIGNvbWUgYWNyb3NzIGlzc3VlcyBsaWtlIGJsYW5rIGZpZWxkcywgZHVwbGljYXRlIHJlY29yZHMsIGluY29uc2lzdGVudCBmb3JtYXRzIGFuZCB1c2luZyBPcGVucmVmaW5lIHRvb2wgY2FuIGhlbHAgdG8gcmVzb2x2ZSBzdWNoIGlzc3Vlcy4NCg0KKipXaGVuKiogLU5vdyBkYXRhIGFuYWx5c2lzIHBsYXkgYW4gaW1wb3J0YW50IHJvbGUgaW4gYnVzaW5lc3MuIERhdGEgYW5hbHlzdHMgaW1wcm92ZSBkZWNpc2lvbiBtYWtpbmcsIGN1dCBjb3N0cyBhbmQgaWRlbnRpZnkgbmV3IGJ1c2luZXNzIG9wcG9ydHVuaXRpZXMuIEFuYWx5c2lzIG9mIGRhdGEgaXMgYSBwcm9jZXNzIG9mIGluc3BlY3RpbmcsIGNsZWFuaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZCBtb2RlbGxpbmcgZGF0YSB3aXRoIHRoZSBnb2FsIG9mIGRpc2NvdmVyaW5nIHVzZWZ1bCBpbmZvcm1hdGlvbiwgc3VnZ2VzdGluZyBjb25jbHVzaW9ucywgYW5kIHN1cHBvcnRpbmcgZGVjaXNpb24gbWFraW5nLiBTbywgdG8gZW5zdXJlIHRoZSBhY2N1cmFjeSBvZiBvdXIgYW5hbHlzaXMsIHdlIGhhdmUgdG8gY2xlYW4gb3VyIGRhdGENCg0KDQoNCioqV2hhdCBjYW4gT3BlblJlZmluZSBkbzoqKg0KDQoqIENsZWFuaW5nIG1lc3N5IGRhdGE6IGZvciBleGFtcGxlIGlmIHdvcmtpbmcgd2l0aCBhIHRleHQgZmlsZSB3aXRoIHNvbWUgc2VtaS1zdHJ1Y3R1cmVkIGRhdGEsIGl0IGNhbiBiZSBlZGl0ZWQgdXNpbmcgdHJhbnNmb3JtYXRpb25zLCBmYWNldHMgYW5kIGNsdXN0ZXJpbmcgdG8gbWFrZSB0aGUgZGF0YSBjbGVhbmx5IHN0cnVjdHVyZWQuWzhdDQoqIFRyYW5zZm9ybWF0aW9uIG9mIGRhdGE6IGNvbnZlcnRpbmcgdmFsdWVzIHRvIG90aGVyIGZvcm1hdHMsIG5vcm1hbGl6aW5nIGFuZCBkZW5vcm1hbGl6aW5nLg0KKiBQYXJzaW5nIGRhdGEgZnJvbSB3ZWIgc2l0ZXM6IE9wZW5SZWZpbmUgaGFzIGEgVVJMIGZldGNoIGZlYXR1cmUgYW5kIGpzb3VwIEhUTUwgcGFyc2VyIGFuZCBET00gZW5naW5lLls5XQ0KKiBBZGRpbmcgZGF0YSB0byBkYXRhc2V0IGJ5IGZldGNoaW5nIGl0IGZyb20gd2Vic2VydmljZXMgKGkuZS4gcmV0dXJuaW5nIGpzb24pLlsxMF0gRm9yIGV4YW1wbGUsIGNhbiBiZSB1c2VkIGZvciBnZW9jb2RpbmcgYWRkcmVzc2VzIHRvIGdlb2dyYXBoaWMgY29vcmRpbmF0ZXMuWzExXQ0KKiBBbGlnbmluZyB0byBXaWtpZGF0YSAoZm9ybWVybHkgRnJlZWJhc2VbMTJdKTogdGhpcyBpbnZvbHZlcyByZWNvbmNpbGlhdGlvbiAtIG1hcHBpbmcgc3RyaW5nIHZhbHVlcyBpbiBjZWxscyB0byBlbnRpdGllcyBpbiBXaWtpZGF0YS4NCiogRGF0YSBOb3JtYWxpemF0aW9uDQoqIENvbHVtbiBSZW9yZ2FuaXphdGlvbg0KKiBGYWNldGluZyBhbmQgQ2x1c3RlcmluZw0KKiBUcmFja2luZyBPcGVyYXRpb25zDQoqIEV4cG9ydGluZyBEYXRhDQoNCg0KIVtdKE9wZW5SZWZpbmUtbWFwLlBORykNCg0KDQpgYGB7cn0NCg0KDQojTGluazogaHR0cHM6Ly9zaXRlcy50ZW1wbGUuZWR1L3R1ZHNjLzIwMTYvMTIvMTMvcHJlcGFyaW5nLWRhdGEtd2l0aC1vcGVucmVmaW5lLXBhcnQtaWktYXNzaWduLXVuaXF1ZS1udW1lcmljYWwtaWRlbnRpZmllcnMvDQoNCg0KYGBgDQoNCioqV2h5IE9wZW5SZWZpbmUgaXMgYSBiZXR0ZXIgdG9vbD8qKg0KDQohW10oQS5wbmcpDQoNCg0KDQpgYGB7cn0NCg0KI2xpbms6IGh0dHBzOi8vY2FzY2kudW1kLmVkdS93cC1jb250ZW50L3VwbG9hZHMvMjAxMy8xMi9PcGVuUmVmaW5lLXR1dG9yaWFsLXYxLjUucGRmDQoNCmBgYA0KDQoNCg0KKipPcGVuUmVmaW5lIFN0cmVuZ3RocyBhbmQgV2Vha25lc3NlczoqKg0KDQohW10oQi5wbmcpDQoNCg0KYGBge3J9DQoNCiNsaW5rOiBodHRwczovL2d1aWRlcy5saWJyYXJ5LmlsbGlub2lzLmVkdS9vcGVucmVmaW5lL2Fib3V0DQoNCmBgYA0KDQoNCg0KU3RyZW5ndGhzOg0KDQoxLiBPcGVuUmVmaW5lIGlzIGEgZGVza3RvcCBhcHBsaWNhdGlvbi4gSXQgb3BlbnMgaW4gdGhlIGJyb3dzZXIgYXMgYSBMb2NhbCBXZWJzZXJ2ZXIuIFNvLA0KdGhlIGRhdGEgaXMgc2FmZSBhbmQgaXQgZG9lc24ndCBnZXQgdXBsb2FkZWQgdG8gdGhlIEdvb2dsZSBzZXJ2ZXIuDQoNCjIuIEl0IGhhcyBmYWNldHMgd2hpY2ggaXMgdXNlZCB0byBmaWx0ZXIgdGhlIGRhdGEgaW50byBzdWJzZXRzIGFuZCB0aGVzZSBjbHVzdGVycyBjYW4gYmUNCmN1c3RvbWl6ZWQgYW5kIG9yZ2FuaXNlZCBpbnRvIG1lYW5pbmdmdWwgZGF0YS4NCg0KMy4gSXQgaGFzIGEgQnJvd3NlciBiYXNlZCBpbnRlcmZhY2UsIGFuZCBzbyBjYW4gaGFuZGxlIG1vcmUgZGF0YSBlZmZpY2llbnRseS4NCg0KNC4gT3BlbnJlZmluZSBoYXMgYSBzdHJvbmcgZmVhdHVyZSBpbiBleHRlbmRpbmcgZGF0YSAtLSB1c2VyIGNhbiB1c2UgaXQgdG8gZmluZCBNZXRhIERhdGENCmFuZCBpdCBjYW4gYmUgdXNlZCB0byBjb3JyZWxhdGUgd2l0aCBpdC4NCg0KDQpXZWFrbmVzczoNCg0KMS4gVGhlIFVJIG9mIE9wZW5yZWZpbmUgaXMgbm90IHVzZXIgZnJpZW5kbHkuIEFsdGhvdWdoIHRoZSBmZWF0dXJlcyBhbmQgZnVuY3Rpb25zIGFyZQ0Kc3Ryb25nLCB0aGUgVUkgbWFrZSBPcGVucmVmaW5lIGxvb2tzIGJvcmluZy4gQmVzaWRlcywgaW4gdGhlIHZpc3VhbGl6YXRpb24sIHRoZSBmdW5jdGlvbg0KaXMgbm90IHNjYWxhYmxlLiBGb3IgaW5zdGFuY2UsIE9wZW5yZWZpbmUgZ2l2ZSB1c2VyIGEgdmlldyBvZiBkYXRhLCBidXQgdGhlIGltYWdlIGlzIG5vdA0KYmlnIGVub3VnaCB0byBmaWd1cmUgb3V0IGNvbXBsZXggZGlzdHJpYnV0aW9uLg0KDQoyLiBVbmZvcnR1bmF0ZWx5IEdvb2dsZSBoYXMgcmVtb3ZlZCBzdXBwb3J0IGZvciB0aGlzIHRvb2wsIG1ha2luZyBmZXcgb2YgaXRzIGZlYXR1cmVzDQpyZWR1bmRhbnQuDQoNCkZBUToNCg0KMSkgT3BlblJlZmluZSBvcGVucyBvbiBteSBicm93c2VyLiBTbyBkbyBJIHJlcXVpcmUgaW50ZXJuZXQgdG8gcnVuIGl0Pw0KQW5zLiBOby4gT3BlblJlZmluZSBkb2Vzbid0IHJlcXVpcmUgaW50ZXJuZXQgZm9yIHJ1bm5pbmcuIEl0J3MgYSBub3JtYWwgYXBwbGljYXRpb24sDQpob3dldmVyIHJ1bnMgb24gYSBsb2NhbCBzZXJ2ZXIuDQoNCjIpIFdoYXQgaXMgdGhlIGluZGV4IG9mIHRoZSBmaXJzdCBjaGFyYWN0ZXJpc3RpYyBvZiBvbmUgY2VsbD8NCkFuczogSXQgc2hvdWxkIGJlIDAuIFNvIGlmIHlvdSB3YW50IHRoZSBmaXJzdCB0d28gY2hhcmFjdGVyaXN0aWMsIHlvdSBzaG91bGQgd3JpdGUgYXMgdmFsdWVbMCwxXS4NCg0KMykgSXMgT3BlblJlZmluZSBvbmx5IGZvciBXaW5kb3dzIE9wZXJhdGluZyBTeXN0ZW0/DQpBbnMuIE9wZW5SZWZpbmUgaXMgY29tcGF0aWJsZSB3aXRoIGJvdGggV2luZG93cyBPcGVyYXRpbmcgU3lzdGVtIGFuZCBNYWMgT1MgYXMgd2VsbC4NCg0KNCkgSXMgbXkgZGF0YSBzYWZlIGluIE9wZW5yZWZpbmU/DQpBbnM6IFllcyBpdCBpcyBzYWZlIGJlY2F1c2UgaXQgcnVucyBvbiBsb2NhbCBzZXJ2ZXIgYW5kIGRhdGEgaXMgc3RvcmVkIG9uIHlvdXIgY29tcHV0ZXIncw0KZGlyZWN0b3J5Lg0KDQoNCjxCcj4NCg0KIzEtR2V0dGluZyBzdGFydGVkDQoNCioqTGVhcm5pbmcgT2JqZWN0aXZlczoqKg0KDQoqIFRoZSBwcmluY2lwbGVzIG9mIGRhdGEgcHJlcGFyYXRpb24NCiogVGhlIE9wZW5SZWZpbmUgY29tbXVuaXR5IGFuZCB0aGUgc29mdHdhcmUgaW50ZXJmYWNlDQoqIEluc3RhbGxpbmcgYW5kIHVzaW5nIE9wZW5SZWZpbmUNCg0KDQoqKkludHJvZHVjdGlvbiB0byBkYXRhIHF1YWxpdHkgYW5kIGludGVncmF0aW9uOioqDQoNCiFbXShwZW50YWhvXzEucG5nKQ0KDQpgYGB7cn0NCg0KDQojTGluazogaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9zZWFyY2g/cT10aGUrZGF0YStwcm9jZXNzaW5nK3BpcGVsaW5lJnJsej0xQzFHR1JWX2VuREU4MTNERTgxMyZzb3VyY2U9bG5tcyZ0Ym09aXNjaCZzYT1YJnZlZD0wYWhVS0V3aUU2NENSNmJfZkFoWEdkQ3dLSFJobENlY1FfQVVJRGlnQiZiaXc9MTM2NiZiaWg9NjE3I2ltZ2RpaT1IMUR2YWJjWXMtRDF3TTomaW1ncmM9d2o5RU9BSjQ3dTFya006DQoNCg0KDQoNCmBgYA0KDQoNCg0KRGF0YSBRdWFsaXR5ICYgSW50ZWdyYXRpb24gaXMgVGltZSBDb25zdW1pbmcgKFBvcHVsYXIgcGhyYXNlOiBmYXN0IDgwJSBvZiBkYXRhIGFuYWx5dGljcyB0aW1lIGNvbnN1bWluZykNCg0KKiBEdXBsaWNhdGUgdmFsdWVzICYgdHlwb3MNCiogTXVsdGktdmFsdWUgY2VsbHMNCiogRGF0YSBpbiB3cm9uZyBmaWVsZA0KKiBNaXNzaW5nIC8gUGFydGlhbCBWYWx1ZXMNCiogRW5jb2RpbmcgRXJyb3JzDQoqIENoYW5nZSBmb3JtYXRzICh0ZXh0LCBudW1iZXIsIGRhdGUpDQoqIEZsYXQgdG8gcmVsYXRpb25hbCBkYXRhIHNldHMNCiogU2NoZW1hIGFsbGlnbm1lbnQNCiogVHJhbnNwb3NlIHJvd3MgYW5kIGNvbHVtbnMNCiogSm9pbiBkYXRhIHNldHMNCiogRW5yaWNobWVudCBmcm9tIG90aGVyIHNvdXJjZXMgKE1ETSwgQVBJIGNhbGxzKQ0KDQoNCkRhdGEgUXVhbGl0eSAmIEludGVncmF0aW9uIFNvbHV0aW9ucw0KDQohW10oMS5wbmcpDQoNCg0KIVtdKDIucG5nKQ0KDQoNCg0KDQpgYGB7cn0NCg0KDQojTGluazogaHR0cHM6Ly9jb3Vyc2VzLmNvZ25pdGl2ZWNsYXNzLmFpL2NvdXJzZXMvY291cnNlLXYxOkJpZ0RhdGFVbml2ZXJzaXR5K0RQMDEwMUVOKzIwMTYvY291cnNld2FyZS85NzllZmNhMDgwNjE0NTdmYjgyMzg1NTQ3OTlhMTdhYi8zZTY3YmRkMzg3NTk0ZTZhODNmMDEyMGFlZjdiNmU0NC8NCg0KDQpgYGANCg0KQ29uY2x1c2lvbiBhYm91dCBEYXRhIFF1YWxpdHkgJiBJbnRlZ3JhdGlvbiB3aXRoIE9wZW5SZWZpbmUuDQoNCj4gSW4gdG9kYXkncyBmYXN0LXBhY2VkIGRhdGEgZW52aXJvbm1lbnQsIGRhdGEgZW5naW5lZXJzLCBzY2llbnRpc3RzLCBhbmQgYW5hbHlzdHMgYXJlIHJhcmUgYW5kIGNhbid0IGtlZXAgcGFjZSB3aXRoIHRoZSB2b2x1bWUgb2YgcmVxdWVzdHMuIERvbWFpbiBleHBlcnRzIGFyZSBsaW1pdGVkIGJ5IHRoZSBzcHJlYWRzaGVldCBzb2Z0d2FyZSBmdW5jdGlvbmFsaXR5Lk9wZW4gUmVmaW5lIGVtcG93ZXJzIGRvbWFpbiBleHBlcnRzIHRvIHdvcmsgb24gdGhlaXIgb3duIGRhdGEgdmlhIHNlbGYgc2VydmljZSBkYXRhIHByZXBhcmF0aW9uIHNvbHV0aW9uIHRoYXQgYWRkcmVzc2VzIHRoZSBza2lsbCBnYXANCg0KDQoqKk1vdmluZyB0b3dhcmQgYW5kIGFnaWxlIGRhdGEgcHJvY2VzczoqKg0KDQohW10oMy5wbmcpDQoNCiFbXSg0LnBuZykNCg0KDQpgYGB7cn0NCg0KDQojTGluazogaHR0cHM6Ly9jb3Vyc2VzLmNvZ25pdGl2ZWNsYXNzLmFpL2NvdXJzZXMvY291cnNlLXYxOkJpZ0RhdGFVbml2ZXJzaXR5K0RQMDEwMUVOKzIwMTYvY291cnNld2FyZS85NzllZmNhMDgwNjE0NTdmYjgyMzg1NTQ3OTlhMTdhYi8zZTY3YmRkMzg3NTk0ZTZhODNmMDEyMGFlZjdiNmU0NC8NCg0KDQpgYGANCg0KQ29uY2x1c2lvbiBhYm91dCBBZ2lsZSBEYXRhIFByb2Nlc3Mgd2l0aCBPcGVuUmVmaW5lLg0KDQo+T3BlblJlZmluZSBpcyBhIHBvd2VyZnVsIGludGVyZmFjZSBmb3IgU3ViamVjdCBNYXR0ZXJzIEV4cGVydHMsIGFsbG93aW5nIEJ1c2luZXNzIEFuYWx5c3RzIGFuZCBDb25zdWx0YW50cyB0byBkaXNjb3Zlciwgbm9ybWFsaXplLCBhbmQgZW5yaWNoIHRoZWlyIGRhdGEgd2l0aCBvbmx5IGxpbWl0ZWQgdGVjaG5pY2FsIGtub3dsZWRnZS4gT3BlblJlZmluZSBhZGRyZXNzZXMgdGhlIHNraWxsIGdhcCBiZXR3ZWVuIGRvbWFpbiBhbmQgZGF0YSBleHBlcnRzLiBEb21haW4gZXhwZXJ0cyBkcml2ZSB0aGUgZGF0YSBwcm9jZXNzIGZyb20gZGlzY292ZXJ5IHRvIHByZXBhcmF0aW9uIHdoaWxlIGRhdGEgZW5naW5lZXJzIHByb3ZpZGUgZXhwZXJ0aXNlIHRocm91Z2ggc2NhbGluZyBrZXkgcHJvY2Vzcw0KDQoNCioqT3BlblJlZmluZSBoaXN0b3J5IGFuZCBjb21tdW5pdHk6KioNCg0KKiBHcmlkd29ya3MgZXJhIDIwMDkgLSAyMDEwIGZyb20gTWV0YVdlYiBJbmMuIChHcmlkd29ya3MgaXMgb3BlbiBzb3VyY2UgdW5kZXIgdGhlIEJTRCBsaWNlbnNlKQ0KDQoqIEdvb2dsZSBhY3F1aXJlcyBNZXRhV2ViIEluYy4gaW4gMjAxMCBhbmQgR3JpZHdvcmtzIGlzIHJlYnJhbmRlbiBhcyBHb29nbGUgUmVmaW5lDQoNCiogR29vZ2xlIFJlZmluZSAyLjAgaXMgcmVsZWFzZWQgaW4gMjAxMA0KDQoqIEdvb2dsZSBSZWZpbmUgMi41IGlzIHJlbGVhc2VkIGluIDIwMTENCg0KKiBJbiBOb3ZlbWJlciAyMDEyOiBHb29nbGUgc3RvcHBwZWQgc3VwcG9ydGluZyBHb29nbGUgUmVmaW5lLCBvcGVuaW5nIHRoZSBwcm9qZWN0IHRvIHRoZSBjb21tdW5pdHkuIFRoZSBDb21tdW5pdHkgbW92ZWQgdGhlIHByb2plY3QgdG8gR2l0aHViIGFuZCByZWJyYW5kZWQgaXQgYXMgT3BlblJlZmluZQ0KDQoqIEluIDIwMTMgT3BlblJlZmluZTIuNi1iZXRhIGlzIHJlbGVhc2VkDQoNCg0KIVtdKE9wZW5SZWZpbmUtbWFwLlBORykNCg0KYGBge3J9DQoNCg0KI0xpbms6IGh0dHBzOi8vc2l0ZXMudGVtcGxlLmVkdS90dWRzYy8yMDE2LzEyLzEzL3ByZXBhcmluZy1kYXRhLXdpdGgtb3BlbnJlZmluZS1wYXJ0LWlpLWFzc2lnbi11bmlxdWUtbnVtZXJpY2FsLWlkZW50aWZpZXJzLw0KDQoNCmBgYA0KDQohW10oNS5wbmcpDQoNCiFbXSg2LnBuZykNCg0KDQoNCg0KDQoNCg0KYGBge3J9DQoNCg0KI0xpbms6IGh0dHBzOi8vY291cnNlcy5jb2duaXRpdmVjbGFzcy5haS9jb3Vyc2VzL2NvdXJzZS12MTpCaWdEYXRhVW5pdmVyc2l0eStEUDAxMDFFTisyMDE2L2NvdXJzZXdhcmUvOTc5ZWZjYTA4MDYxNDU3ZmI4MjM4NTU0Nzk5YTE3YWIvM2U2N2JkZDM4NzU5NGU2YTgzZjAxMjBhZWY3YjZlNDQvDQoNCg0KYGBgDQoNCg0KKipPcGVuUmVmaW5lIGludGVyZmFjZSB0b3VyOioqDQoNCiFbXSg3LnBuZykNCg0KDQpgYGB7cn0NCg0KDQojTGluazogaHR0cHM6Ly9qb3VybmFsLmNvZGU0bGliLm9yZy9hcnRpY2xlcy85NjUyDQoNCg0KYGBgDQoNCg0KKipJbnN0YWxsaW5nIE9wZW5SZWZpbmU6ICoqDQoNCkZvciBXaW5kb3dzLT4NCg0KKiBHbyB0byB0aGUgT3BlblJlZmluZSBkb3dubG9hZCBwYWdlLT4gW2h0dHA6Ly9vcGVucmVmaW5lLm9yZy9kb3dubG9hZC5odG1sXShodHRwOi8vb3BlbnJlZmluZS5vcmcvZG93bmxvYWQuaHRtbCkNCiogQ2xpY2sgb24gV2luZG93cyBraXQgdG8gZG93bmxvYWQgdGhlIGluc3RhbGwgZmlsZQ0KKiBUbyB1c2UgaXQsIHVuemlwLCBhbmQgZG91YmxlLWNsaWNrIG9uIGdvb2dsZS1yZWZpbmUuZXhlIChpZiB5b3UncmUgaGF2aW5nIGlzc3VlcyB3aXRoIGdvb2dsZS1yZWZpbmUuZXhlIHRyeSByZWZpbmUuYmF0IGluc3RlYWQpDQoqIEdvb2dsZSBSZWZpbmUgd2lsbCB0aGVuIG9wZW4gaW4geW91ciB3ZWIgYnJvd3Nlci4NCiogSWYgaXQgZG9lc24ndCBvcGVuIGF1dG9tYXRpY2FsbHksIG9wZW4gYSB3ZWIgYnJvc3dlciBhZnRlciB5b3UndmUgc3RhcnRlZCB0aGUgcHJvZ3JhbSBhbmQgZ28gdG8gdGhlIFVSTCBodHRwOi8vbG9jYWxob3N0OjMzMzMgYW5kIHlvdSBzaG91bGQgc2VlIE9wZW5SZWZpbmUgKHdpdGggY2hyb21lIG9yIGZpcmVmb3gpLg0KDQpGb3IgTWFjLT4NCg0KKiBEb3dubG9hZCB0aGUgRE1HIGZpbGUuDQoqIE9wZW4gdGhlIGRpc2sgaW1hZ2UgYW5kIGRyYWcgdGhlIE9wZW5SZWZpbmUgaWNvbiBpbnRvIHRoZSBBcHBsaWNhdGlvbnMgZm9sZGVyLg0KKiBEb3VibGUtY2xpY2sgb24gdGhlIGljb24gdG8gc3RhcnQgT3BlblJlZmluZS4NCg0KRm9yIExpbnV4LT4NCg0KKiBEb3dubG9hZCB0aGUgZ3ppcHBlZCB0YXJiYWxsLg0KKiBFeHRyYWN0IHRoZSBmb2xkZXIgdG8geW91ciBob21lIGRpcmVjdG9yeS4NCiogSW4gYSB0ZXJtaW5hbCwgZW50ZXIgLi9yZWZpbmUgdG8gc3RhcnQuDQoNCk5vdGU6IE9wZW5SZWZpbmUgd2lsbCBhbGxvY2F0ZSBvbmx5IDEgR0Igb2YgUkFNLiBGb3IgbW9yZSBjYXBhY2l0eSBzZWUgdGhlIGFub3RoZXIgZXhwbGFuYXRpb24gYWJvdXQgImZvciBtb3JlIG1lbW9yeSIuDQoNCg0KKipDcmVhdGluZyBhIG5ldyBwcm9qZWN0OioqIA0KDQpUaGUgc3RhcnQgc2NyZWVuIG9mIE9wZW5SZWZpbmUuDQohW10oOC5QTkcpDQoNCmBgYHtyfQ0KDQojIExpbms6IGh0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCmBgYA0KDQoqKkNyZWF0ZSBQcm9qZWN0KiogZnJvbSBkaWZmZXJlbnQgc291cmNlcy4NCg0KKiBUaGlzIENvbXB1dGVyOiBTZWxlY3QgYSBmaWxlIHN0b3JlZCBvbiB5b3VyIGxvY2FsIG1hY2hpbmUNCiogV2ViIEFkZHJlc3NlcyAoVVJMcyk6IEltcG9ydCBkYXRhIGRpcmVjdGx5IGZyb20gYW4gb25saW5lIHNvdXJjZQ0KKiBDbGlwYm9hcmQ6IENvcHktcGFzdGUgeW91ciBkYXRhIGludG8gYSB0ZXh0IGZpZWxkDQoqIEdvb2dsZSBEYXRhOiBFbmFibGUgYWNjZXNzIHRvIGEgR29vZ2xlIFNwcmVhZHNoZWV0IG9yIEZ1c2lvbiBUYWJsZQ0KDQoqKk9wZW4gUHJvamVjdDoqKiBQcmV2aW91cyBQcm9qZWN0DQoNCioqSW1wb3J0IFByb2plY3Q6KiogT3BlbiB0aGUgUHJvamVjdA0KDQpGaWxlIGZvcm1hdHMgc3VwcG9ydGVkIGJ5IE9wZW5SZWZpbmU6DQoNCiogQ29tbWEtU2VwYXJhdGVkIFZhbHVlcyAoQ1NWKSwgVGFiLVNlcGFyYXRlZCBWYWx1ZXMgKFRTViksIGFuZCBvdGhlciAqU1YNCiogTVMgRXhjZWwgZG9jdW1lbnRzIChib3RoIC5YTFMgYW5kIC5YTFNYKSBhbmQgT3BlbiBEb2N1bWVudCBGb3JtYXQNCihPREYpIHNwcmVhZHNoZWV0cyAoLk9EUyksIGFsdGhvdWdoIHRoZSBsYXR0ZXIgaXMgbm90IGV4cGxpY2l0bHkgbWVudGlvbmVkDQoqIEphdmFTY3JpcHQgT2JqZWN0IE5vdGF0aW9uIChKU09OKQ0KKiBYTUwgYW5kIFJlc291cmNlIERlc2NyaXB0aW9uIEZyYW1ld29yayAoUkRGKSBhcyBYTUwNCiogTGluZS1iYXNlZCBmb3JtYXRzIChsb2dzKQ0KDQo+IElmIHlvdSBuZWVkIG90aGVyIGZvcm1hdHMsIHlvdSBjYW4gYWRkIHRoZW0gYnkgd2F5IG9mIE9wZW5SZWZpbmUgZXh0ZW5zaW9ucy4NCg0KT3BlblJlZmluZSBjb25zaXN0cyBvZiB0aHJlZSBzaW1wbGUgc3RlcHM6IHNlbGVjdGluZyB5b3VyIGZpbGUgLCBwcmV2aWV3aW5nIHRoZSBpbXBvcnQsIGFuZCB2YWxpZGF0aW5nLiBUaGUgc2V0dGluZyBmb3IgdmFsaWRhdGluZyBzdGVwIGlzIGluIHRoZSBmb2xsb3dpbmcgc2NyZWVuc2hvdC4NCg0KIVtdKDkuUE5HKQ0KDQoNCioqRXhwbG9yaW5nIHRoZSBkYXRhOiAqKg0KDQohW10oMTAuUE5HKQ0KDQpgYGB7cn0NCg0KI2h0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCg0KYGBgDQoNCjEuIFRvdGFsIG51bWJlciBvZiByb3dzDQoyLiBEaXNwbGF5IG9wdGlvbnMNCjMuIENvbHVtbiBoZWFkZXJzIGFuZCBtZW51cw0KNC4gQ2VsbCBjb250ZW50czoNCiFbXSgxMS5QTkcpDQoNCioqTWFuaXB1bGF0aW5nIGNvbHVtbnM6ICoqDQoNCiogQ29sbGFwc2luZyBhbmQgZXhwYW5kaW5nIGNvbHVtbnM6ICBWaWV3IHwgQ29sbGFwc2UgYWxsIG90aGVyIGNvbHVtbnMgb24gdGhlIGNvbHVtbiBDYXRlZ29yaWVzLg0KIVtdKDEyLlBORykNCg0KKiBNb3ZpbmcgY29sdW1ucyBhcm91bmQ6IFRoZSBWaWV3IG9wdGlvbiBvZmZlcnMgYSBxdWljayB3YXkgdG8gY29sbGFwc2Ugb3IgZXhwYW5kIGFsbCBjb2x1bW5zLCB3aGlsZSBFZGl0IGNvbHVtbnMgfCBSZS1vcmRlciAvIHJlbW92ZSBjb2x1bW5zLi4uICANCiFbXSgxMy5QTkcpDQoNCiogUmVuYW1pbmcgYW5kIHJlbW92aW5nIGNvbHVtbnM6IFVuZGVyIHRoZSBzYW1lIEVkaXQgY29sdW1uIG1lbnUgaXRlbS4NCiFbXSgxNC5QTkcpDQoNCioqUHJvamVjdCBoaXN0b3J5OiAqKg0KDQpDbGljayBvbiB0aGUgVW5kbyAvIFJlZG8gdGFiIG9yIGV4dHJhY3RlZCBpbiBKU09OIGZvcm1hdCBieSBjbGlja2luZyBvbg0KdGhlIEV4dHJhY3QuLi4gYnV0dG9uIGp1c3QgdW5kZXIgVW5kbyAvIFJlZG8uIA0KDQohW10oMTUuUE5HKQ0KDQpgYGB7cn0NCg0KI2h0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCg0KYGBgDQoNCiFbXSgxNi5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KDQpgYGANCg0KKipFeHBvcnRpbmcgYSBwcm9qZWN0OiAqKg0KDQpUaGUgRXhwb3J0IG1lbnUgaW4gdGhlIHRvcC1yaWdodCBvZiB0aGUgc2NyZWVuIGFsbG93cyB5b3UgdG8gZG8ganVzdCB0aGF0Og0KIVtdKDE3LlBORykNCg0KDQpTb21lIG9mIGNob2ljZSBhcmU6DQoNCiogRXhwb3J0IHByb2plY3QNCiogSFRNTCB0YWJsZQ0KKiBUcmlwbGUgbG9hZGVyIGFuZCBNUUxXcml0ZQ0KKiBDdXN0b20gdGFidWxhciBleHBvcnRlciBhbmQgdGVtcGxhdGluZw0KKiBUZW1wbGF0aW5nDQoNCioqRm9yIG1vcmUgbWVtb3J5OiAqKg0KDQoqIFdpbmRvd3MNCg0KT24gV2luZG93cywgeW91IHdpbGwgaGF2ZSB0byBlZGl0IHRoZSBgb3BlbnJlZmluZS5sNGouaW5pYCBmaWxlIGluIE9wZW5SZWZpbmUncw0KbWFpbiBmb2xkZXIuIEZpbmQgdGhlIGxpbmUgdGhhdCBzdGFydHMgd2l0aCAtWG14ICh3aGljaCBpcyBKYXZhIHNwZWFrIGZvciAibWF4aW11bQ0KaGVhcCBzaXplIiksIHdoaWNoIHdpbGwgc2hvdyB0aGUgZGVmYXVsdCBhbGxvY2F0ZWQgbWVtb3J5OiAxMDI0TSAobWVhbmluZyAxMDI0IE1CDQpvciAxIEdCKS4gSW5jcmVhc2UgdGhpcyBhcyB5b3Ugc2VlIGZpdCwgZm9yIGluc3RhbmNlIHRvIDIwNDggTS4gVGhlIG5ldyBzZXR0aW5ncyB3aWxsIGJlIGluIGVmZmVjdCB0aGUgbmV4dCB0aW1lIHlvdSBzdGFydCBPcGVuUmVmaW5lLg0KDQoqIE1hYw0KDQpUaGUgaW5zdHJ1Y3Rpb25zIGZvciBNYWMgYXJlIGEgYml0IG1vcmUgY29tcGxpY2F0ZWQsIGFzIHRoaXMgb3BlcmF0aW5nIHN5c3RlbSBoaWRlcyB0aGUNCmNvbmZpZ3VyYXRpb24gZmlsZXMgZnJvbSBzaWdodC4gQWZ0ZXIgY2xvc2luZyBPcGVuUmVmaW5lLCBob2xkIGNvbnRyb2wgYW5kIGNsaWNrIG9uIGl0cw0KaWNvbiwgc2VsZWN0aW5nIFNob3cgcGFja2FnZSBjb250ZW50cyBmcm9tIHRoZSBwb3AtdXAgbWVudS4gVGhlbiwgb3BlbiB0aGUgYGluZm8uIHBsaXN0YCBmaWxlIGZyb20gdGhlIGBDb250ZW50c2AgZm9sZGVyLiBZb3Ugc2hvdWxkIG5vdyBzZWUgYSBsaXN0IG9mIE9wZW5SZWZpbmUgc2V0dGluZ3MuDQpOYXZpZ2F0ZSB0byB0aGUgSmF2YSBzZXR0aW5ncyBhbmQgZWRpdCB0aGUgdmFsdWUgb2YgYFZNT3B0aW9uc2AgKHRoZXNlIGFyZSB0aGUgcHJvcGVydGllcw0Kb2YgdGhlIEphdmEgVmlydHVhbCBNYWNoaW5lKS4gTG9vayBmb3IgdGhlIHBhcnQgdGhhdCBzdGFydHMgd2l0aCAtWG14IGFuZCBjaGFuZ2UgaXRzDQpkZWZhdWx0IHZhbHVlIG9mIDEwMjQgTSB0byB0aGUgZGVzaXJlZCBhbW91bnQgb2YgbWVtb3J5LCBmb3IgaW5zdGFuY2UsIGAtWG14MjA0OE1gLg0KDQoqIExpbnV4DQoNClRoaXMgbWlnaHQgY29tZSBpbiBhcyBhIHN1cnByaXNlLCBidXQgaW5jcmVhc2luZyBhbGxvY2F0ZWQgbWVtb3J5IGlzIGVhc2llc3QgaW4gTGludXguDQpJbnN0ZWFkIG9mIHN0YXJ0aW5nIE9wZW5SZWZpbmUgd2l0aCAuL3JlZmluZSBhcyB5b3UgdXN1YWxseSB3b3VsZCBkbywganVzdCB0eXBlIGluDQrCtC4vcmVmaW5lIC1tIDIwNDhNYCwgd2hlcmUgMjA0OCBpcyB0aGUgZGVzaXJlZCBhbW91bnQgb2YgbWVtb3J5IGluIE1CLiBUbyBtYWtlDQp0aGUgY2hhbmdlIHBlcm1hbmVudCwgeW91IGNhbiBjcmVhdGUgYW4gYWxpYXMgaW4gdGhlIGhpZGRlbiBgLmJhc2hyY2AgZmlsZSBsb2NhdGVkIGluDQp5b3VyIGhvbWUgZm9sZGVyIGJ5IGFkZGluZyB0aGUgZm9sbG93aW5nIGxpbmUgYXQgdGhlIGVuZCBvZiB0aGUgZmlsZToNCg0KYGFsaWFzIHJlZmluZT0nY2QgcGF0aF90b19yZWZpbmUgOyAuL3JlZmluZSAtbSAyMDQ4TSdgDQoNCkhlcmUsIHBhdGhfdG9fcmVmaW5lIGlzIHRoZSByZWxhdGl2ZSBwYXRoIGZyb20geW91ciBob21lIGZvbGRlciB0byB0aGUgT3BlblJlZmluZQ0KZm9sZGVyLiBUaGVuLCB0aGUgbmV4dCB0aW1lIHlvdSBzdGFydCBPcGVuUmVmaW5lIHdpdGggYC4vcmVmaW5lYCwgaXQgd2lsbCBiZSBhbGxvY2F0ZWQNCjIgR0IgYnkgZGVmYXVsdC4NCg0KDQoNCjxCcj4NCg0KIzIuIEtleSBmZWF0dXJlcw0KDQoqKkxlYXJuaW5nIE9iamVjdGl2ZXM6KioNCg0KKiBJbXBvcnRpbmcgZGF0YQ0KKiBTb3J0aW5nIGRhdGENCiogRmFjZXRpbmcgZGF0YSAoYXVnbWVudGVkKQ0KKiBEZXRlY3RpbmcgZHVwbGljYXRlcw0KKiBBcHBseWluZyBhIHRleHQgZmlsdGVyDQoqIFVzaW5nIHNpbXBsZSBjZWxsIHRyYW5zZm9ybWF0aW9ucw0KKiBSZW1vdmluZyBtYXRjaGluZyByb3dzDQoNCiMjX0ltcG9ydGluZyBkYXRhDQoNCkdldCB0aGUgZGF0YSBmcm9tIHZhcmlvdXMgZXh0ZXJuYWwNCnNvdXJjZXMuICBJdCBoYXMgdHdvIHBhcnRzOyAxLiBDcmVhdGlvbiBvZiBQcm9qZWN0IGFuZCAyLiBQYXJzaW5nIERhdGFzICAgIA0KDQoqKjEuIENyZWF0aW9uIG9mIFByb2plY3Q6KioNCg0KTmF2aWdhdGlvbi0+DQoNCiAgKiBPcGVuUmVmaW5lDQogICogQ2xpY2sgb24gIkNyZWF0ZSBQcm9lamVjdCINCiAgKiBTZWxlY3QgZnJvbSB0aGUgbGlzdCB0aGUgc2hlZXQgb3IgZGF0YSANCiAgKiBDbGljayBvbiBDaG9vc2UgRmlsZQ0KICAqIE5leHQgYW5kIENyZWF0ZSBQcm9qZWN0IA0KDQpTdGVwcy0+DQoNCiAgKiBPcGVuIEdvb2dsZSBSZWZpbmUNCiAgKiBDbGljayBvbiBDaG9vc2UgRmlsZSB0byBicm93c2UgdGhyb3VnaCB5b3VyIGRvY3VtZW50cyBhbmQgdG8gc2VsZWN0IHRoZSBwYXJ0aWN1bGFyDQogICAgZG9jdW1lbnQgdG8gcGxheSB3aXRoLg0KICAqIFlvdSBjYW4gZXZlbiBjaG9vc2UgYSB3ZWJzaXRlLCBvciBmcm9tIHlvdXIgY2xpcGJvYXJkLCBvciBldmVuIGdvb2dsZSBkYXRhLg0KICAqIENsaWNrIG9uIE5leHQgDQogICogVGhlIGZpbGUgaXMgdXBsb2FkZWQuDQogICogR2l2ZSBhIG5hbWUgdG8gdGhlIHByb2plY3QsIGFuZCBjbGljayBvbiBjcmVhdGUgcHJvamVjdA0KICANClNvcHBvcnRpbmcgZm9ybWF0IGFyZSBUU1YsIENTViwgKlNWLCAueGxzLCAueGxzeCwgSlNPTiwgWE1MLA0KUkRGIGFzIFhNTCBhbmQgZ29vZ2xlIGRvY3VtZW50cy4NCg0KDQoqKjIuIFBhcnNpbmcgRGF0YTogKioNCg0KUGFyc2luZyB0aGUgRGF0YSBzdWNoIGFzIHRoZSBudW1iZXIgb2Ygcm93cywgYmxhbmsgcm93cyBldGMuIA0KDQohW10oMTguUE5HKQ0KDQoNCg0KIyNfU29ydGluZyBkYXRhDQoNClRoZSBTb3J0IG1lbnUgYXBwZWFyaW5nIGF0IHRoZSB0b3AgZXZlcnkgY29sdW1ucyBhcyBzaG93biBpbiB0aGUgZm9sbG93aW5nIHNjcmVlbnNob3Q6DQoNCiFbXSgxOS5QTkcpDQoNCiFbXSgyMC5QTkcpDQoNCg0KIyNfRmFjZXRpbmcvZmlsdGVyaW5nIGRhdGENCg0KSXQgaXMgYSBtZXRob2QgdG8gZmlsdGVyIGRhdGEgaW50byBzdWJzZXRzLiBGYWNldHMgYWxzbyBhbGxvdyB5b3UgdG8gYXBwbHkNCmEgdHJhbnNmb3JtYXRpb24gdG8gYSBzdWJzZXQgb2YgeW91ciBkYXRhIGZvciB0ZXh0LCBudW1iZXIgYW5kIGRhdGVzLg0KDQoqKlR5cGVzIG9mIGZhY2V0cy9maWx0ZXJpbmc6KioNCg0KMS4gVGV4dDogIEl0IHNob3dzIG51bWJlciBvZiByb3dzIGZvciBlYWNoIGdyb3VwIGFuZCBnaXZlcyBhIGxhcmdlciBwaWN0dXJlIG9mIGRhdGEuDQpUZXh0IGZhY2V0cyBjYW4gYmUgYXBwbGllZCBvbiBzZXZlcmFsIGNvbHVtbnMuIGBGYWNldC0+IFRleHQgZmFjZXRgDQoNCiFbXSgyMS5QTkcpDQoNCiFbXSgyMi5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCg0KDQoyLiBOdW1lcmljOiANClRoaXMgZmFjZXQgZ3JvdXBzIG51bWJlcnMgaW50byBudW1lcmljIHJhbmdlIGJpbnMuIFRoZW4gd2UgY2FuIHNlbGVjdCBhbnkNCnJhbmdlIGZvciB1c2Ugc2hvd2luZyBjb25zZWN1dGl2ZSBudW1iZXJzDQoNCiFbXSgyMy5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCg0KQmVmb3JlIG1vdmluZyB0byBjdXN0b21pemVkIGZhY2V0cywgbGV0J3MgcXVpY2tseSBtZW50aW9uIHR3byBvdGhlciB3YXlzIGZvcg0KZmFjZXRpbmcgdGhhdCBhcmUgcmVsYXRlZCB0byB0aGUgbnVtZXJpYyBmYWNldDogdGhlIHRpbWVsaW5lIGZhY2V0IGFuZCBzY2F0dGVycGxvdCBmYWNldC4NCg0KQSB0aW1lbGluZSBmYWNldCByZXF1aXJlcyBkYXRlcywgc28gdGV4dCBzdHJpbmdzIHN1Y2ggYXMgMTcvMTAvMTg5MCBuZWVkIHRvIGJlDQpjb252ZXJ0ZWQgdG8gdGhlIGRhdGUgZm9ybWF0IGZpcnN0LiBZb3UgY2FuIHRyeSB0aGF0IG9uIHRoZSBQcm9kdWN0aW9uIERhdGUgY29sdW1uLA0KYnV0IG5vdGljZSB0aGF0IHJlYWwgZGF0ZXMgYXJlIGEgbWlub3JpdHksIHNpbmNlIGl0IGFsc28gY29udGFpbnMgeWVhcnMgc3VjaCBhcyAxOTg0IGFuZA0KcmFuZ2VzIHN1Y2ggYXMgMjAwNiB0byAyMDA3LiBXZSBjYW4gbm9uZXRoZWxlc3MgbmF2aWdhdGUgdG8gRWRpdCBjZWxscyB8IENvbW1vbg0KdHJhbnNmb3JtcyB8IFRvIGRhdGUgaW4gdGhhdCBjb2x1bW4gbWVudSwgdHJhbnNmb3JtaW5nIDc5IGNlbGxzIGludG8gZGF0ZSBmb3JtYXQ7DQpmb3IgaW5zdGFuY2UsIDE3LzEwLzE4OTAgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gMTg5MC0xMC0xN1QwMDowMDowMFosIHdpdGggdGhlIHplcm9zDQppbmRpY2F0aW5nIHRoZSB0aW1lIG9mIGRheSBpbiBob3VycywgbWludXRlcywgYW5kIHNlY29uZHMuDQoNCkNsZWFybHksIDc5IGNlbGxzIG91dCBvZiBhIHRvdGFsIG9mIDc1LDgxNCBpcyBub3QgYSBsb3QsIGJ1dCBhIHRpbWVsaW5lIGZhY2V0IG9uIHRoZXNlDQp2YWx1ZXMgd291bGQgc3RpbGwgc2hvdyBvYmplY3RzIGNyZWF0ZWQgb24gYSBnaXZlbiBkYXRlIHJhbmdlIGZyb20gMjYgRmVicnVhcnksDQoxODgwIHRvIDMxIEphbnVhcnksIDE5NTIsIHdoaWxlIG1vc3QgdmFsdWVzIGFyZSBlaXRoZXIgbm90IHRpbWUgZXhwcmVzc2lvbnMgKDE5LDgyMCkNCm9yIGJsYW5rICg1NSw5MTUpLg0KDQpUaGUgZm9sbG93aW5nIHNjcmVlbnNob3Qgc2hvd3Mgd2hhdCBjYW4gYmUgb2J0YWluZWQgd2l0aCBhIHRpbWVsaW5lIGZhY2V0IG9uIHRoZQ0KUHJvZHVjdGlvbiBEYXRlIGNvbHVtbiBhZnRlciBjb252ZXJ0aW5nIGRhdGVzIHRvIE9wZW5SZWZpbmUncyBpbnRlcm5hbCB0aW1lIGZvcm1hdDoNCg0KIVtdKDI0LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOiBodHRwOi8vZmlsZS5hbGxpdGVib29rcy5jb20vMjAxNTEwMTIvVXNpbmclMjBPcGVuUmVmaW5lLnBkZg0KDQpgYGANCg0KDQozLiBDdXN0b20gVGV4dCBGYWNldDoNClRoaXMgaXMgYSB0ZXh0IGZhY2V0IGluIHdoaWNoIHlvdSBjYW4gc3BsaXQgdGhlIGNvbHVtbiBkYXRhIHVzaW5nDQpleHByZXNzaW9uIGAodmFsdWUuc3BsaXQoIiIpWzBdKWAgd2l0aG91dCBjcmVhdGluZyBuZXcgY29sdW1uLiBHcm91cHMgd2lsbCBiZSBtYWRlDQphY2NvcmRpbmcgdG8gc3BpbHQgZGF0YSBzb3J0ZWQgYnkgdGhlaXIgY291bnRzLg0KDQohW10oMjUuUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6IGh0dHBzOi8vY2FzY2kudW1kLmVkdS93cC1jb250ZW50L3VwbG9hZHMvMjAxMy8xMi9PcGVuUmVmaW5lLXR1dG9yaWFsLXYxLjUucGRmDQoNCmBgYA0KDQoNCg0KNC4gQ3VzdG9tIE51bWVyaWNhbCBGYWNldHM6IA0KVGhpcyBmYWNldCBhbGxvd3MgeW91IHRvIGN1c3RvbWl6ZSB0aGUgbnVtZXJpYyBmYWNldHMuIFRoZQ0KbnVtZXJpYyB2YWx1ZXMgY2FuIGJlIGdyb3VwZWQgYnkgdGhlaXIgbG9ncywgbW9kdWx1cywgbGVuZ3RoIG9mIHN0cmluZyBldGMuDQpUaGlzIG1ldGhvZGVuIG5lZWQgR1JFTCAoR2VuZXJhbCBSZWZpbmUgRXhwcmVzc2lvbiBMYW5ndWFnZSkNCg0KDQoNCg0KNS4gQ3VzdG9taXplZCBmYWNldHM6DQpUaGVyZSBhcmUgdmFyaW91cyB0eXBlcyBvZiBjdXN0b21pemFibGUgZmFjZXRzLiBUaGV5IGluY2x1ZGUgV29yZA0KRmFjZXQsIER1cGxpY2F0ZSBGYWNldHMsIE51bWVyaWMgbG9nIGZhY2V0LCAxLSBib3VuZGVkIG51bWVyaWMgbG9nIGZhY2V0LCB0ZXh0IGxlbmd0aA0KZmFjZXQsIExvZyBvZiB0ZXh0IGxlbmd0aCBmYWNldCwgVW5pY29kZSBjaGFyLWNvZGUgZmFjZXQsIEZhY2V0IGJ5IGVycm9yLCBGYWNldCBieSBCbGFuay4NCg0KIVtdKDI2LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOiBodHRwOi8vZmlsZS5hbGxpdGVib29rcy5jb20vMjAxNTEwMTIvVXNpbmclMjBPcGVuUmVmaW5lLnBkZg0KDQpgYGANCg0KDQo2LiBGYWNldGluZyBieSBzdGFyIG9yIGZsYWc6DQpTdGFycyBjYW4gYmUgdXNlZCB0byBtYXJrIGdvb2QNCnJvd3Mgb3IgZmF2b3JpdGUgcm93cyB0aGF0IHlvdSB3YW50IHRvIHBpY2sgdXAgaW4gb3JkZXIgdG8gY29tZSBiYWNrIHRvIHRoZW0gbGF0ZXI7DQpjb252ZXJzZWx5LCBmbGFncyBjYW4gYmUgdXNlZCB0byBpbmRpY2F0ZSBiYWQgcm93cyBvciBwcm9ibGVtYXRpYyByb3dzIHRoYXQgd2lsbCBuZWVkDQpzcGVjaWFsIGF0dGVudGlvbiBmdXJ0aGVyIG9uLiBOb3RlIHRoYXQgdGhpcyBpcyBqdXN0IGEgc3VnZ2VzdGlvbjsgeW91IGNvdWxkIHVzZSBzdGFycw0KYW5kIGZsYWdzIHRvIG1lYW4gc29tZXRoaW5nIGNvbXBsZXRlbHkgZGlmZmVyZW50Lg0KDQoNCiMjX0VkaXRpbmcgQ2VsbHMvQ29sdW1ucy8gUm93cw0KDQojIyMxLiBFZGl0aW5nIGNlbGxzIGJ5IHVzaW5nIGNvbW1vbiBUcmFuc2Zvcm1zOiANClRoZSBuYXZpZ2F0aW9uIGZvciB0aGVzZSBmdW5jdGlvbnMgaXMgZWRpdCBjZWxscywgQ29tbW9uIFRyYW5zZm9ybS4gU29tZSBvZiB0aGVtIGFyZSBmb3IgcmVtb3Zpbmcgd2hpdGVzcGFjZXMsIGFwcGx5aW5nIGNhcGl0YWxpemF0aW9uIHN0eWxlcyBhbmQNCnRvIGNvbnZlcnQgdGhlIGRhdGEgaW50byB0aGUgZGVzaXJlZCBkYXRhIHR5cGUuDQoNCiFbXSgyNy5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCg0KIyMjMi4gVHJhbnNmb3JtaW5nIERhdGEgZXh0cmFjdGlvbiBmcm9tIGV4aXN0aW5nIGNvbHVtbjoNCg0KU3VwcG9zZSBpZiB3ZSBoYXZlIHVwbG9hZGVkIHRleHQgZmlsZSBmb3IgYWxsIHN0dWRlbnRzIG9mIFVNRCBjb25zaXN0aW5nIG9mIHRoZWlyIGNvdXJzZXMsDQp5ZWFyLCBhZ2UgZXRjLiB0aGVuIHdlIGNhbiBleHRyYWN0IHllYXIgb3IgYW55IG90aGVyIGRhdGEgdG8gbWFrZSBhIG5ldyBjb2x1bW4gZm9yIGVhc3kNCnVzYWdlLiBOZXcgY29sdW1uIGNhbiBiZSBtYWRlIGZyb20gZXhpc3RpbmcgY29sdW1ucy4gDQoNCkEpIE5hdmlnYXRpb24NCg0KRWRpdCBDZWxscyAsID8/P1RyYW5zZm9ybQ0KDQpCKSBTdGVwcw0KDQpXZSBjYW4gcmVtb3ZlIHNwYWNlIG9yIGFueSBvdGhlciB1bndhbnRlZCBzeW1ib2xzIGZyb20gdGhlIGRhdGEgdG9vLiBJbXBvcnRlZCB0ZXh0IGZpbGUuDQpUaGUgdGV4dCBmaWxlIGhhZCBzb21lIGJsYW5rIHJvd3MgYnV0IHdoaWxlIGltcG9ydGluZyB0ZXh0IGZpbGUsIHdlIGNhbiBzZWxlY3Qgb3B0aW9uIG5vdCB0byBzdG9yZSBibGFuayByb3dzIGFuZCBpdCBmaWx0ZXJzIHRoZSBkYXRhIHdoaWxlIGNyZWF0aW5nIHByb2plY3Qgb25seS4NCg0KIVtdKDI4LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOiBodHRwczovL2Nhc2NpLnVtZC5lZHUvd3AtY29udGVudC91cGxvYWRzLzIwMTMvMTIvT3BlblJlZmluZS10dXRvcmlhbC12MS41LnBkZg0KDQpgYGANCg0KDQogICogMSkgVXNpbmcgdGhlIGV4cHJlc3Npb24gdmFsdWUucmVwbGFjZSgiKioiLCIiKSB0byByZW1vdmUgZG91YmxlIHN0YXJzLg0KICANCiAgIVtdKDI5LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOiBodHRwczovL2Nhc2NpLnVtZC5lZHUvd3AtY29udGVudC91cGxvYWRzLzIwMTMvMTIvT3BlblJlZmluZS10dXRvcmlhbC12MS41LnBkZg0KDQpgYGANCiAgDQogICogMikgVG8gcmVtb3ZlIHllYXIgcHJlZml4ZWQsIHNlbGVjdCBvcHRpb24gImFkZCBjb2x1bW4gYmFzZWQgb24gdGhpcyBjb2x1bW4iDQogIA0KICAgIVtdKDMwLlBORykNCg0KYGBge3J9DQoNCiNMaW5rOiBodHRwczovL2Nhc2NpLnVtZC5lZHUvd3AtY29udGVudC91cGxvYWRzLzIwMTMvMTIvT3BlblJlZmluZS10dXRvcmlhbC12MS41LnBkZg0KDQpgYGANCiAgDQogICogMykgVXNlIGV4cHJlc3Npb24gdmFsdWVbMSw1XSB3aGljaCBzcGVjaWZpZXMgdGhlIGNoYXJhY3RlciByYW5nZSB0byBzZXBhcmF0ZSB5ZWFycyBhcyAgICAgICAgYmVsb3cNCiAgDQogICFbXSgzMS5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cHM6Ly9jYXNjaS51bWQuZWR1L3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDEzLzEyL09wZW5SZWZpbmUtdHV0b3JpYWwtdjEuNS5wZGYNCg0KYGBgDQoNCiAgKiA0KSBVc2luZyBjaGFyYWN0ZXIgc3RyaW5nICJ2YWx1ZS5zdWJzdHJpbmcoNSkiIHdoaWNoIGRpc3BsYXlzIHRoZSBkYXRhIGV4Y2x1ZGluZyB5ZWFyDQoNCiAhW10oMzIuUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6IGh0dHBzOi8vY2FzY2kudW1kLmVkdS93cC1jb250ZW50L3VwbG9hZHMvMjAxMy8xMi9PcGVuUmVmaW5lLXR1dG9yaWFsLXYxLjUucGRmDQoNCmBgYA0KDQoNCg0KIyMjMy4gVW5kZXJzdGFuZGluZyBFeHByZXNzaW9uczogDQoNCk9wZW5SZWZpbmUgc3VwcG9ydCAnRXhwcmVzc2lvbnMnLiBBbmQgdGhlc2UgYXJlIHVzZWQgdG8NCnRyYW5zZm9ybSBleGlzdGluZyBkYXRhIG9yIGNyZWF0ZSBuZXcgZGF0YSBiYXNlZCBvbiBleGlzdGluZyBkYXRhIC5UaGlzIHNvdW5kcyBzaW1pbGFyIHRvIHRoZSAnRm9ybXVsYScgd2hpY2ggd2UgdXNlZCB0byBoYXZlIGluIEV4Y2VsLiBCdXQgdGhlcmUgaXMgYSBiaWcgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZW0uIFRoZSAnRm9ybXVsYScgaW4gdGhlIEV4Y2VsIGNhbiBvbmx5IGJlIHVzZWQgdG8gc3RvcmUgdmFyaW91cyBmb3JtdWxhZSBmb3IgZWFjaCBjZWxsIGZvciB0aGF0IHNwZWNpZmljIGNvbHVtbi4gV2hlcmVhcywgaW4gRXhwcmVzc2lvbnMsIGhlcmUgYnkgbWFraW5nIHVzZSBvZiAiR1JFTCIsIHdlIGNhbiBhY2Nlc3MgZXZlcnkgcm93IGFuZCBjb2x1bW4gYW5kIGNhbiBzZXQgdXAgY29uZGl0aW9ucyBhY2NvcmRpbmcgdG8gdGhhdC5jbGljayBlZGl0IENlbGxzICwgVHJhbnNmb3JtLg0KDQpGdW5jdGlvbiAxOiB2YWx1ZSArICIgKHN0cmluZykiDQoNCiFbXSgzMy5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cHM6Ly9jYXNjaS51bWQuZWR1L3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDEzLzEyL09wZW5SZWZpbmUtdHV0b3JpYWwtdjEuNS5wZGYNCg0KYGBgDQoNCkZ1bmN0aW9uIDI6IHZhbHVlLnRyaW0oKS5sZW5ndGgoKSANCg0KIVtdKDM0LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOiBodHRwczovL2Nhc2NpLnVtZC5lZHUvd3AtY29udGVudC91cGxvYWRzLzIwMTMvMTIvT3BlblJlZmluZS10dXRvcmlhbC12MS41LnBkZg0KDQpgYGANCg0KDQpTb21lIEZ1bmN0aW9ucyBhdCBhIEdsYW5jZToNCg0KMSkgU3ludGF4OiAtICJNci4iICsgdmFsdWUNCkV4cGxhbmF0aW9uOiAtIHVzZWQgdG8gY29uY2F0ZW5hdGUgdHdvIHN0cmluZ3MNCg0KMikgU3ludGF4OiAtIHZhbHVlICsgMy45DQpFeHBsYW5hdGlvbjotYWRkIHR3byBudW1iZXJzLCBhbmQgaWYgdGhlIHZhbHVlIG90aGVyIHRoYW4gbnVtYmVycywgdGhlbiBpdCBjb25jYXRlbmF0ZXMNCnN0cmluZw0KDQozKSBTeW50YXg6IC0gdmFsdWUudHJpbSgpLmxlbmd0aCgpDQpFeHBsYW5hdGlvbjotdHJpbXMgdGhlIGxlYWRpbmcgYW5kIHRyYWlsaW5nIHdoaXRlc3BhY2UNCg0KNCkgU3ludGF4OiAtIHZhbHVlLnN1YnN0cmluZygwLDMpDQpFeHBsYW5hdGlvbjogLSB0YWtlIHRoZSBzdWJzdHJpbmcgb2YgdmFsdWUgZnJvbSBjaGFyYWN0ZXIgaW5kZXggMCB1cCB0byBhbmQgZXhjbHVkaW5nDQpjaGFyYWN0ZXIgaW5kZXggMw0KDQoNCiMjX0RldGVjdGluZyBkdXBsaWNhdGVzDQoNCkR1cGxpY2F0ZXMgYXJlIGFubm95aW5nIHJlY29yZHMgdGhhdCBoYXBwZW4gdG8gYXBwZWFyIHR3aWNlIChvcg0KbW9yZSkgaW4gYSBkYXRhc2V0LiANCg0KIVtdKDM1LlBORykNCg0KIyNfYXBwbHlpbmcgYSB0ZXh0IGZpbHRlcg0KDQpXaGVuIHlvdSB3YW50IHRvIGZpbmQgcm93cyBtYXRjaGluZyBhIGNlcnRhaW4gc3RyaW5nLCBpdCBpcyBlYXNpZXIgdG8gcmVseSBvbiBhIHNpbXBsZQ0KdGV4dCBmaWx0ZXIgdGhhbiBvbiBjdW1iZXJzb21lIGZhY2V0cy4gDQoNCiFbXSgzNi5QTkcpDQoNCiMjX1JlbW92aW5nIG1hdGNoaW5nIHJvd3MNCg0KVG8gcmVtb3ZlIHJvd3MsIGJlIHN1cmUgdG8gaGF2ZSBhIGZhY2V0IG9yIGZpbHRlciBpbiBwbGFjZSBmaXJzdCwgb3RoZXJ3aXNlIHlvdSB3aWxsDQpyZW1vdmUgYWxsIHJvd3MgaW4gdGhlIGRhdGFzZXQuDQoNCkxldCdzIHN0YXJ0IGZyb20gdGhlIGNsZWFuIHByb2plY3QgYWdhaW4gKGltcG9ydCBpdCBmb3IgYSBzZWNvbmQgdGltZSBvciB0b2dnbGUgdGhlIFVuZG8gLyBSZWRvIHRhYiBhbmQgc2VsZWN0IDAuIENyZWF0ZSBwcm9qZWN0IHRvIGNhbmNlbCBhbGwgbW9kaWZpY2F0aW9ucykgYW5kIHNlZSB3aGF0IHdlIGNhbiBkbyB0byBjbGVhbiB1cCB0aGlzIGRhdGFzZXQuIEFsc28sIGNoZWNrIHRoYXQgT3BlblJlZmluZSBzaG93cyB5b3VyIGRhdGEgYXMgcm93cywgbm90IHJlY29yZHMuDQoNCiFbXSgzNy5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCg0KIyNfRXhwb3J0aW5nIGRhdGENCg0KRXhwb3J0IGRhdGEgZnJvbSBhbiBleGlzdGluZyBPcGVuUmVmaW5lIHByb2plY3QgaW4gc2V2ZXJhbCBmb3JtYXRzOg0KDQoqIFRhYiBzZXBhcmF0ZWQgdmFsdWVzIChUU1YpDQoqIENvbW1hIHNlcGFyYXRlZCB2YWx1ZXMgKENTVikNCiogRXhjZWwNCiogSFRNTCB0YWJsZQ0KDQpKdXN0IGNsaWNrIG9uIHRoZSBFeHBvcnQgYnV0dG9uIGF0IHRoZSB0b3AgcmlnaHQgY29ybmVyIGFuZCBzZWxlY3QgdGhlIGZvcm1hdCB0aGF0IHdlIHdhbnQuIA0KDQojI19VbmRvLyBSZWRvDQoNClRoZSBmbGV4aWJpbGl0eSB0byBtYWtlIG1pc3Rha2VzIGFuZCB0byByZWN0aWZ5IHRoZW0uIEdpdmVzIHlvdSBhbiBvcHBvcnR1bml0eSB0byBtYWtlIGEgbG90IG9mIHRyaWFscyBhbmQgZXJyb3Igb24gZGF0YS4gDQoNCiogKGkpIEJlZm9yZSBVbmRvL1JlZG8NCg0KSGVyZSwgeW91IGNhbiBzZWUgdGhhdCBvbiB0aGUgbGVmdCBzaWRlIG9mIHRoZSBwYW5lbCwgdGhlcmUgYXJlIGZpdmUgc3RlcHMgd2hpY2ggaGF2ZSBiZWVuDQpwZXJmb3JtZWQgYnkgdGhlIHVzZXIgLk91dCBvZiB3aGljaCwgdGhlIGxhc3Qgb25lIGlzIGdyZXllZC4gVGhlIGdyZXllZCBzdGVwIG51bWJlciA1DQpleHBsYWlucyB0aGF0IFVuZG8gaGFzIGFscmVhZHkgYmVlbiBwZXJmb3JtZWQgb25jZS4gVG8gcHJvdmUgdGhpcyBwb2ludCwgd2UgcGVyZm9ybQ0KJ1VuZG8nIG9uY2UgYWdhaW4uDQoNCiFbXSgzOC5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cHM6Ly9jYXNjaS51bWQuZWR1L3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDEzLzEyL09wZW5SZWZpbmUtdHV0b3JpYWwtdjEuNS5wZGYNCg0KYGBgDQoNCg0KKiAoaWkpIEFmdGVyIFVuZG8vUmVkbw0KDQpIZXJlLCB5b3UgY2FuIHNlZSB0aGUgc2FtZSBmaXZlIHN0ZXBzIHdpdGggdHdvIGdyZXllZCBzdGVwczogc3RlcCBudW1iZXIgNCBhbmQgc3RlcA0KbnVtYmVyIDUuSGVyZSwgd2UgY2FuIHNlZSB0aGF0IHRoZSBVbmRvIGZ1bmN0aW9uIGlzIHBlcmZvcm1lZCBhbmQgeW91IGNhbiBhbHNvIHNlZSB0aGUNCmRhdGEgYmVpbmcgYWx0ZXJlZCB0byB0aGUgcHJldmlvdXMgc3RlcDsgd2hpY2ggaXMgbWFraW5nIHRoZSBmaXJzdCBhbHBoYWJldCBvZiB0aGUgJ2ZpcnN0X25hbWUNCicgY29sdW1uIGNhcGl0YWwuDQoNCiFbXSgzOS5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazogaHR0cHM6Ly9jYXNjaS51bWQuZWR1L3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDEzLzEyL09wZW5SZWZpbmUtdHV0b3JpYWwtdjEuNS5wZGYNCg0KYGBgDQoNCjxCcj4NCg0KIzMuIEFkdmFuY2VkIGZlYXR1cmVzDQoNCiMjX0hhbmRsaW5nIG11bHRpLXZhbHVlZCBjZWxscy1yb3dzDQoNClVzZSBjYXNlOiANCg0KQ2V2aSBIZXJkaWFuLCAwMTc2MzI4MTEyODksIDAxNzYzMjgxMTI4OA0KDQpXZSBoYXZlIG9uZSBQZXJzb24gd2l0aCAyIGRpZmZlcmVudCBwaG9uZSBudW1iZXIuIFdlIHdhbnQganVzdCB0aGUgcmlnaHQgb25lLg0KDQoxLiBFZGl0IGNlbGxzLCBTcGxpdCBNdWx0aXBsZSBjZWxscyB3aXRoIHNlcGFyYXRvciBgLGANCg0KQ2V2aSBIZXJkaWFuDQoNCjAxNzYzMjgxMTI4OQ0KDQowMTc2MzI4MTEyODgNCg0KMi4gV2UgaGF2ZSAzIHJvdyBub3cuIEFuZCB0aGVuIHdlIGdvIHRvIG51bWJlciBvciB0ZXh0IGZhY2V0IChpZiBhIG51bWJlciBvciB0ZXh0KSBhbmQgbWFrZSB0aGUgcmlnaHQgb25lLiBBZnRlciB0aGF0IHRoZSB3cm9uZyBudW1iZXIgd2lsbCBkZWxldGUgYW5kIHRoZSByZXN0IGlzIGxpa2UgdGhpczoNCg0KQ2V2aSBIZXJkaWFuDQoNCjAxNzYzMjgxMTI4OQ0KDQozLiBGaW5hbGx5LCBtYWtlIHN1cmUgdGhpcyB0d28gcm93cyBpbiBvbmUgY2VsbHMgYWdhaW4gd2l0aCBqb2luIG11bHRpIHZhbHVlZCBjZWxscy4gQW5kIHRoZSBmaW5hbCB2ZXJzaW9uIG9mIHRoZSBwZXJzb24gYW5kIHRoZSBwaG9uZSBudW1iZXIgYXJlIENldmkgSGVyZGlhbiwgMDE3NjMyODExMjg5DQoNCk1vcmUgaW5mbyBhYm91dCBzcGxpdHRpbmcgdmFsdWVzIGluIE9wZW5SZWZpbmU6IGh0dHBzOi8vZ3VpZGVzLmxpYnJhcnkuaWxsaW5vaXMuZWR1L29wZW5yZWZpbmUvc3BsaXR0aW5nDQoNCiMjX0FsdGVybmF0aW5nIGJldHdlZW4gcm93cyBhbmQNCnJlY29yZHMgbW9kZQ0KDQo+IEEgcm93IGlzIGEgc2luZ2xlIGxpbmUgb2YgZGF0YSBpbiB5b3VyIGRhdGFzZXQuDQpBIHJlY29yZCBjb25zaXN0cyBvZiBhbGwgcm93cyB0aGF0IGJlbG9uZyB0byBhIHNpbmdsZSBvYmplY3QuDQpUaGUgZmlyc3Qgcm93IG9mIGEgcmVjb3JkIHN0YXJ0cyB3aXRoIG5vbi1udWxsIGNlbGxzIHRoYXQNCmlkZW50aWZ5IHRoZSByZWNvcmQ7IGluIHN1YnNlcXVlbnQgcm93cywgdGhvc2UgaWRlbnRpZnlpbmcNCnZhbHVlcyBhcmUgYmxhbmsgdG8gaW5kaWNhdGUgdGhleSBiZWxvbmcgdG8gdGhlIHNhbWUgcmVjb3JkLg0KDQo+IE1hdGNoaW5nIHJlY29yZHMgdGhhdCBmaXQgbXVsdGlwbGUgY3JpdGVyaWENCldoYXQgaWYgd2Ugd2FudCB0byBtYXRjaCBhbGwgcmVjb3JkcyB0aGF0IGFyZSBpbiB0aGUgY2F0ZWdvcnkgTnVtaXNtYXRpY3MNCmFuZCBhbHNvIGluIHRoZSBjYXRlZ29yeSBNZWRhbHM/IFRvIGRvIHRoaXMsIHdlIG1ha2Ugc3VyZSB0aGF0IHdlIGFyZSBpbg0KcmVjb3JkcyBtb2RlIGFuZCB3ZSBhZGQgYSBzZWNvbmQgdGV4dCBmYWNldCBvbiB0aGUgQ2F0ZWdvcmllcyBmaWVsZC4gSW4NCnRoZSBmaXJzdCBmYWNldCwgd2Ugc2VsZWN0IE51bWlzbWF0aWNzLCBhbmQgaW4gdGhlIHNlY29uZCBmYWNldCwgd2Ugc2VsZWN0DQpNZWRhbHMuIFdlIG5vdyBzZWUgYWxsIHRoZSByZWNvcmRzIHRoYXQgYXJlIGluIGJvdGggY2F0ZWdvcmllcy4NCk5vdyB3aGF0IGhhcHBlbnMgaWYgd2Ugc3dpdGNoIGJhY2sgdG8gcm93cyBtb2RlPyBTdWRkZW5seSwgemVybw0KcmVjb3JkcyBhcmUgbWF0Y2hpbmcgb3VyIHNlbGVjdGlvbi4gVGhpcyBzZWVtcyBzdHJhbmdlIGF0IGZpcnN0LCBidXQgaXQgaXMNCmFjdHVhbGx5IHByZXR0eSBsb2dpY2FsOiBubyBzaW5nbGUgcm93IGhhcyBhIGNhdGVnb3J5IHdoaWNoIGlzIGVxdWFsIHRvDQpOdW1pc21hdGljcyBhbmQgTWVkYWxzIGF0IHRoZSBzYW1lIHRpbWU7IGVhY2ggcm93IGNvbnRhaW5zIGF0IG1vc3QNCm9uZSBvZiB0aGVzZSB0d28uIFRoZXJlZm9yZSwgY29tcGxleCBzZWxlY3Rpb25zIHN1Y2ggYXMgdGhpcyBvbmUgc2hvdWxkIGJlDQptYWRlIGluIHJlY29yZHMgbW9kZS4NCg0KDQohW10oNDAuUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6aHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCiMjX0NsdXN0ZXJpbmcgc2ltaWxhciBjZWxscw0KDQpFZGl0IGNlbGxzIHwgQ2x1c3RlciBhbmQgZWRpdA0KDQohW10oNDEuUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6aHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCj4gV2hhdCBhcmUgY2x1c3RlcmluZyBtZXRob2RzPw0KT3BlblJlZmluZSBvZmZlcnMgdHdvIGRpZmZlcmVudCBjbHVzdGVyaW5nIG1ldGhvZHMsIGtleSBjb2xsaXNpb24NCmFuZCBuZWFyZXN0IG5laWdoYm9yLCB3aGljaCBmdW5kYW1lbnRhbGx5IGRpZmZlciBpbiBob3cgdGhleQ0KZnVuY3Rpb24uIFdpdGgga2V5IGNvbGxpc2lvbiwgdGhlIGlkZWEgaXMgdGhhdCBhIGtleWluZyBmdW5jdGlvbiBpcyB1c2VkDQp0byBtYXAgYSBmaWVsZCB2YWx1ZSB0byBhIGNlcnRhaW4ga2V5LiBWYWx1ZXMgdGhhdCBhcmUgbWFwcGVkIHRvIHRoZQ0Kc2FtZSBrZXkgYXJlIHBsYWNlZCBpbnNpZGUgdGhlIHNhbWUgY2x1c3Rlci4gRm9yIGluc3RhbmNlLCBzdXBwb3NlIHdlDQpoYXZlIGEga2V5aW5nIGZ1bmN0aW9uIHdoaWNoIHJlbW92ZXMgYWxsIHNwYWNlczsgdGhlbiwgQSBCIEMsIEFCIEMsDQphbmQgQUJDIHdpbGwgYmUgbWFwcGVkIHRvIHRoZSBzYW1lIGtleTogQUJDLiBJbiBwcmFjdGljZSwgdGhlIGtleWluZw0KZnVuY3Rpb25zIGFyZSBjb25zdHJ1Y3RlZCBpbiBhIG1vcmUgc29waGlzdGljYXRlZCBhbmQgaGVscGZ1bCB3YXkuDQpOZWFyZXN0IG5laWdoYm9yLCBvbiB0aGUgb3RoZXIgaGFuZCwgaXMgYSB0ZWNobmlxdWUgaW4gd2hpY2ggZWFjaA0KdW5pcXVlIHZhbHVlIGlzIGNvbXBhcmVkIHRvIGV2ZXJ5IG90aGVyIHVuaXF1ZSB2YWx1ZSB1c2luZyBhDQpkaXN0YW5jZSBmdW5jdGlvbi4gRm9yIGluc3RhbmNlLCBpZiB3ZSBjb3VudCBldmVyeSBtb2RpZmljYXRpb24gYXMNCm9uZSB1bml0LCB0aGUgZGlzdGFuY2UgYmV0d2VlbiBCb290IGFuZCBCb3RzIGlzIDI6IG9uZSBhZGRpdGlvbg0KYW5kIG9uZSBkZWxldGlvbi4gVGhpcyBjb3JyZXNwb25kcyB0byBhbiBhY3R1YWwgZGlzdGFuY2UgZnVuY3Rpb24gaW4NCk9wZW5SZWZpbmUsIG5hbWVseSBsZXZlbnNodGVpbi4NCg0KDQoNCiMjX1RyYW5zZm9ybWluZyBjZWxsIHZhbHVlcw0KDQpFZGl0IGNlbGxzIHwgVHJhbnNmb3JtDQoNCiFbXSg0Mi5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazpodHRwOi8vZmlsZS5hbGxpdGVib29rcy5jb20vMjAxNTEwMTIvVXNpbmclMjBPcGVuUmVmaW5lLnBkZg0KDQpgYGANCiANClRoZSBoZWFydCBvZiB0aGlzIGRpYWxvZyBpcyBFeHByZXNzaW9uLCBhIHNtYWxsIHNjcmlwdCB0aGF0IGV4cGxhaW5zIE9wZW5SZWZpbmUgaG93DQplYWNoIG9mIHRoZSB2YWx1ZXMgc2hvdWxkIGNoYW5nZS4gVGhlIExhbmd1YWdlIGxpc3QgYWxsb3dzIHVzIHRvIGNob29zZSB0aGUgbGFuZ3VhZ2UNCmZvciB0aGUgZXhwcmVzc2lvbiwgd2l0aCBjdXJyZW50IHN1cHBvcnQgZm9yIHRoZSBHZW5lcmFsIFJlZmluZSBFeHByZXNzaW9uIExhbmd1YWdlDQooR1JFTCksIEp5dGhvbiAoUHl0aG9uIGltcGxlbWVudGVkIGluIEphdmEpLCBhbmQgQ2xvanVyZSAoYSBmdW5jdGlvbmFsIGxhbmd1YWdlDQp0aGF0IHJlc2VtYmxlcyBMaXNwKS4gSWYgeW91IGFyZSBmYW1pbGlhciB3aXRoIHRoZSBsYXR0ZXIgdHdvLCB5b3UgbWlnaHQgZmluZCBpdCBlYXNpZXIgdG8NCndyaXRlIGV4cHJlc3Npb25zIGluIHRob3NlIGxhbmd1YWdlcy4gSG93ZXZlciwgR1JFTCB3YXMgc3BlY2lmaWNhbGx5IGNyZWF0ZWQgd2l0aA0Kc2ltcGxlIHRyYW5zZm9ybWF0aW9ucyBpbiBtaW5kDQogDQo+IE1hc3RlcmluZyBHUkVMIGlzIGVhc3kNClRoaXMgcmVjaXBlIGludHJvZHVjZWQgYSBmZXcgZXhhbXBsZXMsIGJ1dCB3aGF0IGlmDQp0aGF0IGRvZXNuJ3QgZnVsZmlsbCB5b3VyIG5lZWRzPyBBcHBlbmRpeCBBLCBSZWd1bGFyDQpFeHByZXNzaW9ucyBhbmQgR1JFTCB3aWxsIGludHJvZHVjZSB5b3UgdG8gR1JFTCBzbw0KeW91IGNhbiBsZWFybiBob3cgdG8gYnVpbGQgZXhwcmVzc2lvbnMgeW91cnNlbGYuDQoNCiMjX0FkZGluZyBkZXJpdmVkIGNvbHVtbnMNCg0KMS4gRWRpdCBjb2x1bW4gYW5kIEFkZCBjb2x1bW4gYmFzZWQgb24gdGhpcyBjb2x1bW4uDQoNCjIuIFdyaXRlIHRoZSBHUkVMIGV4cHJlc3Npb24NCg0KDQoNCg0KIyNfU3BsaXR0aW5nIGRhdGEgYWNyb3NzIGNvbHVtbnMNCg0KRWRpdCBjb2x1bW4gfCBTcGxpdCBpbnRvIHNldmVyYWwgY29sdW1ucy4NCg0KIVtdKDQzLlBORykNCg0KYGBge3J9DQoNCiNMaW5rOmh0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCmBgYA0KDQoNCiMjXyBUcmFuc3Bvc2luZyByb3dzIGFuZCBjb2x1bW5zDQoNClRyYW5zcG9zZSB8IFRyYW5zcG9zZSBjZWxscyBhY3Jvc3MgY29sdW1ucyBpbnRvIHJvd3MNCg0KRWRpdCBjb2x1bW4gfCBTcGxpdCBpbnRvIHNldmVyYWwgY29sdW1ucy4NCg0KIVtdKDQ0LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOmh0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCmBgYA0KDQo8QnI+DQoNCiM0LiBMaW5raW5nIGRhdGENCg0KI19SZWNvbmNpbGluZyB2YWx1ZXMgd2l0aA0KRnJlZWJhc2UNCg0KV2hlbiB5b3Ugd2FudCB0byB0cmFuc2Zvcm0geW91ciBjZWxsIHZhbHVlcyBmcm9tIHNpbXBsZSBzdHJpbmdzIHRvIFVSTHMsIGRpZmZlcmVudA0KY2hvaWNlcyBhcmUgcG9zc2libGUuIFNvbWUgb2YgdGhlbSBhcmUgRnJlZWJhc2UsIEF1dG8tbWF0Y2ggY2FuZGlkYXRlcyB3aXRoIGhpZ2ggY29uZmlkZW5jZSwgYW5kIHJlY29uY2lsaWF0aW9uIHNlcnZpY2UgcHJvdmlkZXIuIA0KDQpUaGUgUmVjb25jaWxpYXRpb24gZmVhdHVyZSBpcyB1c2VkIHRvIGxpbmsgdGV4dCBuYW1lcyBvciB2YWx1ZXMgaW4gdGhlIGNvbHVtbnMgb2YgeW91ciBkYXRhIHRvIGRhdGFiYXNlIGlkZW50aWZpZXJzIGluIHZhcmlvdXMgZGF0YWJhc2UgSUQgc3BhY2VzLiBJdCBoZWxwcyB5b3UgdG8gZGV2ZWxvcCBNZXRhZGF0YSB0byB5b3VyIGRhdGEuDQoNClRvIHN0YXJ0IHJlY29uY2lsaWF0aW9uLCBnbyB0byB0aGUgQ2F0ZWdvcmllcyBkcm9wZG93biBhbmQgbmF2aWdhdGUgdG8gUmVjb25jaWxlIHwNClN0YXJ0IHJlY29uY2lsaW5nLi4gDQoNCldpdGggRnJlZWJhc2U6DQoNCiogRnJlZWJhc2UgUXVlcnktYmFzZWQgUmVjb25jaWxpYXRpb246IFRoaXMgaXMgdXNlZnVsIGlmIHlvdXIgY29sdW1uIHZhbHVlcw0KYXJlIGFscmVhZHkgRnJlZWJhc2UgSURzIChzdWNoIGFzIC9lbi9zb2xhcl9zeXN0ZW0pIG9yIEdVSURzDQooaGV4YWRlY2ltYWwgaWRlbnRpZmllcnMpLg0KDQoqIEZyZWViYXNlIFJlY29uY2lsaWF0aW9uIFNlcnZpY2U6IFRoaXMgb2ZmZXJzIGEgbW9yZSBnZW5lcmFsIGFwcHJvYWNoIGZvcg0KdGVybXMgdGhhdCBhcmUgbm90IG5lY2Vzc2FyaWx5IHJlbGF0ZWQgdG8gRnJlZWJhc2UgaWRlbnRpZmllcnMuDQoNCiFbXSg0NS5QTkcpDQoNCmBgYHtyfQ0KDQojTGluazpodHRwOi8vZmlsZS5hbGxpdGVib29rcy5jb20vMjAxNTEwMTIvVXNpbmclMjBPcGVuUmVmaW5lLnBkZg0KDQpgYGANCg0KDQoNCldpdGggQXV0by1tYXRjaCBjYW5kaWRhdGVzIHdpdGggaGlnaCBjb25maWRlbmNlOg0KDQpUaGUgYXV0by1tYXRjaCBvcHRpb24gaXMgb24gYnkgZGVmYXVsdCwgYW5kIGl0DQptZWFucyB0aGF0IGlmIHRoZSBzY29yZSBpcyBzdWZmaWNpZW50bHkgaGlnaCwgT3BlblJlZmluZSB3aWxsIGFzc3VtZSBpdCBoYXMgbWFkZSB0aGUNCnJpZ2h0IGNob2ljZSBhbmQgZGVjbGFyZSBpdCBhIG1hdGNoLiBGb3Igb3RoZXIgY2VsbCB2YWx1ZXMgKG9yIGlmIHlvdSBoYXZlIHVudGlja2VkIHRoZQ0KY2hlY2tib3gpLCB5b3Ugd2lsbCBoYXZlIHRvIGNvbmZpcm0gdGhlIG1hdGNoIG1hbnVhbGx5LiANCg0KDQoNClRoZSB0aGlyZCBhbmQgZmluYWwgb3B0aW9uIGFsbG93cyB5b3UgdG8gc2VuZCBhZGRpdGlvbmFsIGRhdGEgdG8gdGhlIHJlY29uY2lsaWF0aW9uDQpzZXJ2aWNlLiBQbGVhc2UgZmluZCB0aGUgcmVjb25jaWxpYXRpb24gc2VydmljZSB0aGF0IGZpdCBmb3IgeW91ciBjYXNlLg0KDQpNb3JlIGFib3V0IGRhdGUgcmVjb25jaWxpYXRpb246IGh0dHBzOi8vd3d3LmV4cGVyaWFuLmNvLnVrL2J1c2luZXNzL2dsb3NzYXJ5L2RhdGEtcmVjb25jaWxpYXRpb24vDQoNCg0KI19JbnN0YWxsaW5nIGV4dGVuc2lvbnMNCg0KV2hpbGUgT3BlblJlZmluZSBhbGxvd3MgeW91IG91dC1vZi10aGUtYm94IHRvIGFkZCBuZXcgcmVjb25jaWxpYXRpb24gc2VydmljZXMsDQp0aGVzZSBhcmUgb25seSBzZXJ2aWNlcyB0aGF0IHdvcmsgaW4gYSBjZXJ0YWluIHdheSB1bmRlciB0aGUgaG9vZC4NCg0KT3BlblJlZmluZSBleHRlbnNpb25zIGFyZSBhdmFpbGFibGUsIGluY2x1ZGluZyB0aGUgZm9sbG93aW5nIHBvaW50czoNCg0KKiBUaGUgUkRGIGV4dGVuc2lvbiBieSBEaWdpdGFsIEVudGVycHJpc2UgUmVzZWFyY2ggSW5zdGl0dXRlIChERVJJKSwgd2hpY2gNCmFkZHMgc3VwcG9ydCBmb3IgUkRGIGV4cG9ydCBhbmQgcmVjb25jaWxpYXRpb24gd2l0aCBTUEFSUUwgZW5kcG9pbnRzLg0KV2UnbGwgZXhwbGFpbiBib3RoIHRlcm1zIGluIHRoZSBuZXh0IHJlY2lwZS4NCg0KKiBUaGUgTmFtZWQtRW50aXR5IFJlY29nbml0aW9uIChORVIpIGV4dGVuc2lvbiB3cml0dGVuIGJ5IG9uZSBvZiB0aGUNCmF1dGhvcnMgb2YgdGhpcyBib29rLCB3aGljaCBhbGxvd3MgeW91IHRvIGV4dHJhY3QgVVJMcyBmcm9tIGZ1bGwtdGV4dCBmaWVsZHMuDQpVc2FnZSBvZiB0aGlzIGV4dGVuc2lvbiBpcyBjb3ZlcmVkIGluIGRldGFpbCBpbiB0aGUgbGFzdCByZWNpcGUgb2YgdGhpcyBjaGFwdGVyDQoNCkxpa2UgT3BlblJlZmluZSwgYWxsIGV4dGVuc2lvbnMgYXJlIGF2YWlsYWJsZSBmcmVlbHkuIEFuIHVwLXRvLWRhdGUgbGlzdCBvZiBhdmFpbGFibGUNCmV4dGVuc2lvbnMgaXMgbWFpbnRhaW5lZCBhdCBodHRwczovL2dpdGh1Yi5jb20vT3BlblJlZmluZS9PcGVuUmVmaW5lL3dpa2kvDQpFeHRlbnNpb25zDQoNCkZpcnN0LCB5b3Ugd2lsbCBoYXZlIHRvIGZpbmQgdGhlIHBhdGggd2hlcmUgZXh0ZW5zaW9ucyBuZWVkIHRvIGJlIGluc3RhbGxlZC4gVGhpcw0KZGVwZW5kcyBvbiB5b3VyIG9wZXJhdGluZyBzeXN0ZW0sIGJ1dCBPcGVuUmVmaW5lIGNhbiBoZWxwIHlvdSBmaW5kIGl0LiBBdCB0aGUNCmJvdHRvbSBvZiB0aGUgc3RhcnRpbmcgcGFnZSwgdGhlcmUgaXMgYSBsaW5rIGNhbGxlZCBCcm93c2Ugd29ya3NwYWNlIGRpcmVjdG9yeS4NCg0KIVtdKDQ2LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOmh0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCmBgYA0KDQoNClRoZSBuZXh0IHN0ZXAgaXMgdG8gZG93bmxvYWQgYW4gZXh0ZW5zaW9uIGFuZCB0byBwbGFjZSBpdCBpbiB0aGUgZm9sZGVyLiBGb3INCmluc3RhbmNlLCBsZXQncyBpbnN0YWxsIHRoZSBSREYgZXh0ZW5zaW9uLiANCg0KDQpOb3cgcmVzdGFydCBPcGVuUmVmaW5lIHRvIG1ha2UgdGhlIGV4dGVuc2lvbiBhY3RpdmUuIFRoZW4sIHN0YXJ0IE9wZW5SZWZpbmUgYWdhaW4gYXMgdXN1YWwgYW5kIG9wZW4gYSBwcm9qZWN0LiBXaGVuIHRoZSBwcm9qZWN0IGhhcyBsb2FkZWQsIGEgbmV3IFJERiBidXR0b24gaW4gdGhlIHRvcC1yaWdodCB0ZWxscyB5b3UgdGhhdCB0aGUgaW5zdGFsbGF0aW9uIGhhcyBiZWVuIHN1Y2Nlc3NmdWw6DQoNCg0KIVtdKDQ3LlBORykNCg0KYGBge3J9DQoNCiNMaW5rOmh0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCmBgYA0KDQoNCg0KI19BZGRpbmcgYSByZWNvbmNpbGlhdGlvbiBzZXJ2aWNlDQoNClRoZSBSZXNvdXJjZSBEZXNjcmlwdGlvbiBGcmFtZXdvcmsgKFJERikgaXMgYSBtb2RlbCBmb3IgZGF0YSB0aGF0IGNhbiBiZQ0KaW50ZXJwcmV0ZWQgYnkgbWFjaGluZXMuIFdoaWxlIGh1bWFucyBjYW4gcmVhZCBIVE1MIG9uIHRoZSBXZWIsIG1hY2hpbmVzIGRvDQpub3QgdW5kZXJzdGFuZCBuYXR1cmFsIGxhbmd1YWdlIGFuZCBtdXN0IHRoZXJlZm9yZSBiZSBnaXZlbiBpbmZvcm1hdGlvbiBpbiBhbm90aGVyDQpmb3JtLiANCg0KVGhlIFNQQVJRTCBQcm90b2NvbCBhbmQgUkRGIFF1ZXJ5IExhbmd1YWdlIChhIHJlY3Vyc2l2ZSBhY3JvbnltIGZvcg0KU1BBUlFMKSBpcyBhIGxhbmd1YWdlIGZvciBxdWVyeWluZyBSREYgZGF0YXNvdXJjZXMuIFRyYWRpdGlvbmFsIHJlbGF0aW9uYWwNCmRhdGFiYXNlcyB1c2UgU1FMIGFzIGEgcXVlcnkgbGFuZ3VhZ2U7IFJERiBkYXRhYmFzZXMgYW5kIGltcG9ydGFudCBmb3IgdXMsDQpyZWNvbmNpbGlhdGlvbiBzZXJ2aWNlcywgY29tbXVuaWNhdGUgaW4gU1BBUlFMLg0KDQpXaGVuIHlvdSBpbnN0YWxsZWQgdGhlIFJERiBleHRlbnNpb24sIHlvdSBhbHJlYWR5IGFkZGVkIHN1cHBvcnQgZm9yIFNQQVJRTCB0byBPcGVuUmVmaW5lLiBIb3dldmVyLA0KYmVmb3JlIHdlIGNhbiByZWNvbmNpbGUgb3VyIGNlbGwgdmFsdWVzIHRvIFVSTHMsIHdlIG11c3QgY29uZmlndXJlIHRoZSBkYXRhc291cmNlLg0KVG8gZG8gdGhpcywgY2xpY2sgb24gdGhlIG5ldyBSREYgYnV0dG9uIGluIHRoZSB0b3AtcmlnaHQgYW5kIG5hdmlnYXRlIHRvIEFkZA0KcmVjb25jaWxpYXRpb24gc2VydmljZSB8IEJhc2VkIG9uIFNQQVJRTCBlbmRwb2ludC4uIE5vdGUgdGhhdCB5b3UgY2FuIGFsc28NCnJlY29uY2lsZSB3aXRoIGEgbG9jYWwgUkRGIGZpbGUsIHdoaWNoIGlzIGhhbmR5IGlmIHlvdSBoYXZlIHlvdXIgb3duIGRhdGFzZXQgb2YgVVJMcy4NCk9wZW5SZWZpbmUgc2hvd3MgeW91IHRoZSBBZGQgU1BBUlFMLWJhc2VkIHJlY29uY2lsaWF0aW9uIHNlcnZpY2UgZGlhbG9nLg0KDQohW10oNDguUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6aHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCiNfUmVjb25jaWxpbmcgd2l0aCBMaW5rZWQgRGF0YQ0KDQpUaW0gQmVybmVycy1MZWUsIGludmVudG9yIG9mIHRoZSBXZWIgYW5kIG9uZSBvZiB0aGUgY3JlYXRvcnMNCm9mIHRoZSBTZW1hbnRpYyBXZWIgdmlzaW9uLCByZWFsaXplZCB0aGlzIGFuZCBsYXVuY2hlZCB0aGUgTGlua2VkIERhdGEgcHJpbmNpcGxlcw0KKGh0dHA6Ly93d3cudzMub3JnL0Rlc2lnbklzc3Vlcy9MaW5rZWREYXRhLmh0bWwpLiBUaGVzZSBwcmluY2lwbGVzIHNoaWZ0ZWQNCnRoZSBmb2N1cyBvZiB0aGUgU2VtYW50aWMgV2ViIHRvIHRoZSBjcmVhdGlvbiBvZiBkYXRhIHRoYXQgd2FzIGludGVybGlua2VkIHdpdGggb3RoZXINCmRhdGFzZXRzLiBUaGUgcHJpbmNpcGxlcyBhcmUgYXMgZm9sbG93czoNCg0KMS4gVXNlIFVSSXMgYXMgbmFtZXMgZm9yIHRoaW5ncw0KMi4gVXNlIEhUVFAgVVJJcyBzbyB0aGF0IHBlb3BsZSBjYW4gbG9vayB1cCB0aG9zZSBuYW1lcw0KMy4gV2hlbiBzb21lb25lIGxvb2tzIHVwIGEgVVJJLCBwcm92aWRlIHVzZWZ1bCBpbmZvcm1hdGlvbiB1c2luZyB0aGUNCnN0YW5kYXJkcyAoUkRGLCBTUEFSUUwpDQo0LiBJbmNsdWRlIGxpbmtzIHRvIG90aGVyIFVSSXMgc28gdGhhdCB0aGV5IGNhbiBkaXNjb3ZlciBtb3JlIHRoaW5ncw0KDQohW10oNDkuUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6aHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCg0KDQoNCg0KI19FeHRyYWN0aW5nIG5hbWVkIGVudGl0aWVzDQoNClJlY29uY2lsaWF0aW9uIHdvcmtzIGdyZWF0IGZvciB0aG9zZSBmaWVsZHMgaW4geW91ciBkYXRhc2V0IHRoYXQgY29udGFpbiBzaW5nbGUgdGVybXMsDQpzdWNoIGFzIG5hbWVzIG9mIHBlb3BsZSwgY291bnRyaWVzLCBvciB3b3JrcyBvZiBhcnQuIEhvd2V2ZXIsIGlmIHlvdXIgY29sdW1uDQpjb250YWlucyBydW5uaW5nIHRleHQsIHRoZW4gcmVjb25jaWxpYXRpb24gY2Fubm90IGhlbHAgeW91LCBzaW5jZSBpdCBjYW4gb25seSBzZWFyY2gNCmZvciBzaW5nbGUgdGVybXMgaW4gdGhlIGRhdGFzZXRzIGl0IHVzZXMuIEZvcnR1bmF0ZWx5LCBhbm90aGVyIHRlY2huaXF1ZSBjYWxsZWQNCm5hbWVkLWVudGl0eSBleHRyYWN0aW9uIGNhbiBoZWxwIHVzLiBBbiBleHRyYWN0aW9uIGFsZ29yaXRobSBzZWFyY2hlcyB0ZXh0cw0KZm9yIG5hbWVkIGVudGl0aWVzIHdoaWNoIGFyZSB0ZXh0IGVsZW1lbnRzLCBzdWNoIGFzIG5hbWVzIG9mIHBlcnNvbnMsIGxvY2F0aW9ucywNCnZhbHVlcywgb3JnYW5pemF0aW9ucywgYW5kIG90aGVyIHdpZGVseS1rbm93biB0aGluZ3MuIEluIGFkZGl0aW9uIHRvIGp1c3QgZXh0cmFjdGluZw0KdGhlIHRlcm1zLCBtb3N0IGFsZ29yaXRobXMgYWxzbyB0cnkgdG8gcGVyZm9ybSBkaXNhbWJpZ3VhdGlvbi4gDQoNCg0KT3BlblJlZmluZSBkb2VzIG5vdCBzdXBwb3J0IG5hbWVkLWVudGl0eSByZWNvZ25pdGlvbiBuYXRpdmVseSwgYnV0IHRoZSBOYW1lZC1FbnRpdHkNClJlY29nbml0aW9uIGV4dGVuc2lvbiBhZGRzIHRoaXMgZm9yIHlvdS4gQmVmb3JlIGNvbnRpbnVpbmcgd2l0aCB0aGlzIHJlY2lwZSwgZG93bmxvYWQNCnRoZSBleHRlbnNpb24gZnJvbSBodHRwOi8vc29mdHdhcmUuZnJlZXlvdXJtZXRhZGF0YS5vcmcvbmVyLWV4dGVuc2lvbi8gYW5kDQpmb2xsb3cgdGhlIEluc3RhbGxpbmcgZXh0ZW5zaW9ucyByZWNpcGUuIElmIHRoZSBpbnN0YWxsYXRpb24gd2FzIHN1Y2Nlc3NmdWwsIHlvdSBhcmUgZ3JlZXRlZA0KYnkgdGhlIE5hbWVkLWVudGl0eSByZWNvZ25pdGlvbiBidXR0b24gaW4gdGhlIHRvcC1yaWdodCBvZiB5b3VyIHNjcmVlbiBhZnRlciByZXN0YXJ0aW5nDQpPcGVuUmVmaW5lDQoNCg0KPEJyPg0KDQojNS4gUmVndWxhciBleHByZXNzaW9ucyBmb3IgdGV4dCBwYXR0ZXJucw0KDQoNCiMjX0NoYXJhY3RlciBjbGFzc2VzDQoNCiogVGhlIHBhdHRlcm4gQWFyIHdpbGwgbG9vayBmb3IgYWxsIHRleHRzIHRoYXQgY29udGFpbiBhIGNhcGl0YWwgQSBmb2xsb3dlZCBieSBhDQpzbWFsbCBhIGFuZCByLiBJZiB0aGUgY2FzZSBzZW5zaXRpdmUgYm94IGlzIG5vdCB0aWNrZWQsIHRoZSBjYXBpdGFsaXphdGlvbiB3aWxsDQpub3QgbWF0dGVyLg0KKiBUaGUgcGF0dGVybiAxMjMgZmluZHMgYWxsIHRleHRzIHRoYXQgY29udGFpbiB0aGlzIG51bWJlci4gTm90ZSB0aGF0IHRleHRzIHdpdGgNCnRoZSBudW1iZXIgNDEyMzUgYXJlIGFsc28gbWF0Y2hlZCwgc2luY2UgMTIzIGlzIGEgdGV4dHVhbCBwYXJ0IG9mIHRoYXQuDQoqIEFzIHlvdSBjYW4gc2VlLCB0aGlzIGRvZXMgbm90IGRpZmZlciBmcm9tIHJlZ3VsYXIgdGV4dCBtYXRjaGluZyB5ZXQuIFdpdGgNCnJlZ3VsYXIgZXhwcmVzc2lvbnMsIHdlIGNhbiBhbHNvIHNheSB0aGF0IHdlIGV4cGVjdCBhbnkgbGV0dGVyIG9yIGFueSBudW1iZXIuDQpXZSBjYW4gZ2l2ZSBhIHNldCBvZiBjaGFyYWN0ZXJzIGZyb20gd2hpY2ggY2FuIGJlIGNob3NlbiBieSBzdXJyb3VuZGluZw0KdGhlIGFsdGVybmF0aXZlcyB3aXRoIHNxdWFyZSBicmFja2V0cyBbXS4gV2UgY2FuIGluZGljYXRlIGEgY2hhcmFjdGVyIHJhbmdlIGluDQp0aG9zZSBicmFja2V0cyBieSBzZXBhcmF0aW5nIHRoZSBsaW1pdHMgd2l0aCBhIGh5cGhlbi4NCiogVGhlIHBhdHRlcm4gWzAxMjM0NTY3ODldIG1hdGNoZXMgYWxsIHRleHRzIHRoYXQgY29udGFpbiBhIG51bWJlci4NCiogVGhlIHBhdHRlcm4gWzAtOV0gZG9lcyB0aGUgc2FtZSwgb25seSBpdCBpcyBtb3JlIGNvbmRlbnNlLiBJdCBzYXlzIGV2ZXJ5dGhpbmcNCmJldHdlZW4gMCBhbmQgOSBpcyBmaW5lLg0KKiBTaW1pbGFybHksIHRoZSBwYXR0ZXJuIFthLXpdIG1hdGNoZXMgYWxsIGxvd2VyY2FzZSBsZXR0ZXJzIChhbmQgYWxzbyB1cHBlcmNhc2UNCmlmIHRoZSBjYXNlLXNlbnNpdGl2ZSBvcHRpb24gaXMgbm90IHVzZWQpLiBbQS1aXSBtYXRjaGVzIHVwcGVyY2FzZSBsZXR0ZXJzIGFuZA0KW2EtekEtWl0gbWF0Y2hlcyBhbGwgbGV0dGVycywgcmVnYXJkbGVzcyBvZiB0aGUgY2FzZS1zZW5zaXRpdmUgb3B0aW9uLg0KKiBJZiB5b3Ugd2FudCB0byBsb29rIGZvciBudW1iZXJzIGFuZCBsZXR0ZXJzLCB1c2UgWzAtOWEtekEtWl0uIFJlYWQgdGhpcyBhcw0KImV2ZXJ5IGNoYXJhY3RlciBiZXR3ZWVuIDAgYW5kIDksIGJldHdlZW4gYSBhbmQgeiwgb3IgYmV0d2VlbiBBIGFuZCBaIi4NCiogQXMgaW4gdGhlIGVhcmxpZXIgZXhhbXBsZXMsIHdlIGNhbiBwdXQgc2V2ZXJhbCBtYXRjaGVycyBuZXh0IHRvIGVhY2gNCm90aGVyLiBhbmFseVtzel1lIHdpbGwgbWF0Y2ggYm90aCBBbWVyaWNhbiAoYW5hbHl6ZSkgYW5kIEJyaXRpc2gNCihhbmFseXNlKSBzcGVsbGluZ3MuDQoqIFNpbWlsYXJseSwgdGhlIGV4cHJlc3Npb24gWzAtOV1bYS16XSB3aWxsIGZpbmQgbnVtYmVycyBkaXJlY3RseSBmb2xsb3dlZA0KYnkgYXQgbGVhc3Qgb25lIGxldHRlci4gVGhlIGV4cHJlc3Npb24gW2Etel1bMC05XVswLTldWzAtOV0gZmluZHMgbGV0dGVycw0KZGlyZWN0bHkgZm9sbG93ZWQgYnkgYXQgbGVhc3QgdGhyZWUgbnVtYmVycy4NCiogSWYgeW91IHdhbnQgdG8gZmluZCBtZWFzdXJlbWVudHMgc3VjaCBhcyAxIGNtIG9yIDI1IGluLCB5b3Ugd2lsbCBub3QNCmZpbmQgdGhlbSB3aXRoIHRoZSBwcmVjZWRpbmcgZXhwcmVzc2lvbnMgYmVjYXVzZSBvZiB0aGUgc3BhY2UgaW4gYmV0d2Vlbi4NCkx1Y2tpbHksIGEgc3BhY2UgaXMgYWxzbyBhIHN5bWJvbCwgc28gdGhlIGV4cHJlc3Npb24gWzAtOV0gW2Etel0gd2lsbCBmaW5kDQp0aGVtLiBOb3RlIHRoZSBzcGFjZSBpbiBiZXR3ZWVuIHRoZSBicmFja2V0IHBhaXJzLCBhbmQgbm90ZSB0aGUgZmFjdCB0aGF0DQp0aGlzIHdpbGwgZXZlbiBmaW5kIGxvbmdlciBtZWFzdXJlbWVudHMgc3VjaCBhcyAxMjM0NSBtZXRlcnMuIEluZGVlZCwgdGhlDQpleHByZXNzaW9uIG1hdGNoZXMgYSBudW1iZXIgZm9sbG93ZWQgYnkgYSBzcGFjZSBhbmQgYSBsZXR0ZXIsIHNvIGluIHRoaXMgY2FzZSwNCjUgbS4gSXQgZG9lc24ndCBtYXR0ZXIgd2hldGhlciBvdGhlciBudW1iZXJzIG9yIGxldHRlcnMgYXJlIGFsc28gcHJlc2VudC4NCiogSWYgeW91J3JlIGp1c3QgbG9va2luZyBmb3IgbWVhc3VyZW1lbnRzIGluIGluY2hlcywgdGhlIGV4cHJlc3Npb24gWzAtOV0gaW4NCndpbGwgZG8gdGhlIGpvYi4NCiogSXQgbWlnaHQgYmUgYSBiaXQgY3VtYmVyc29tZSB0byB3cml0ZSBbMC05XSBpbiBmdWxsIGV2ZXJ5IHRpbWUuIFRoaXMgaXMgd2h5DQpzaG9ydGhhbmQgY2hhcmFjdGVyIGNsYXNzZXMgd2VyZSBpbnRyb2R1Y2VkLiBUaGV5IGFyZSBzeW1ib2xzIHRoYXQgc3RhbmQNCmZvciBhIHNldCBvZiBjaGFyYWN0ZXJzLiBGb3IgaW5zdGFuY2UsIHRoZSBzeW1ib2wgXGQgc3RhbmRzIGZvciBhbnkgZGlnaXQgYW5kIGlzDQp0aHVzIGVxdWl2YWxlbnQgdG8gWzAtOV0sIGJ1dCBhIGxvdCBmYXN0ZXIgdG8gd3JpdGUuIFRoZSBvcHBvc2l0ZSBpcyBcRCwgd2hpY2gNCm1lYW5zIGFueXRoaW5nIHRoYXQgaXMgbm90IGEgZGlnaXQgYW5kIGluY2x1ZGVzIGxldHRlcnMgYXMgd2VsbCBhcyBzeW1ib2xzLg0KVW5mb3J0dW5hdGVseSwgdGhlcmUgaXMgbm8gc2hvcnRoYW5kIGZvciBhbnkgbGV0dGVyLCBidXQgdGhlcmUgaXMgYSBzaG9ydGhhbmQNCmZvciBhbnkgbGV0dGVyLCBudW1iZXIsIG9yIHVuZGVyc2NvcmUsIHdoaWNoIGlzIFx3LCB3aGljaCBzdGFuZHMgZm9yIGFueSB3b3JkDQpjaGFyYWN0ZXIuIEFnYWluLCB0aGUgb3Bwb3NpdGUgaXMgXFcsIHdoaWNoIG1hdGNoZXMgZm9yIGFsbCBub24tbGV0dGVycyBhbmQNCm5vbi1udW1iZXJzIHRoYXQgYXJlIG5vdCB1bmRlcnNjb3JlcyBlaXRoZXIuDQoqIFxkIFthLXpdIHdpbGwgYWdhaW4gbWF0Y2ggZm9yIHRleHRzIHdpdGggbWVhc3VyZW1lbnRzOiBhbnkgbnVtYmVyDQpmb2xsb3dlZCBieSBhIHNwYWNlIGFuZCBhIGxldHRlci4NCiogXGRcZFxkIG1hdGNoZXMgdGV4dHMgd2l0aCBudW1iZXJzIHdpdGggYSBsZW5ndGggb2YgYXQgbGVhc3QgdGhyZWUuDQoqIFxEXEQgbWF0Y2hlcyB0ZXh0cyB0aGF0IGhhdmUgYXQgbGVhc3QgdHdvIGNvbnNlY3V0aXZlIG5vbi1udW1iZXJzLiBJZiB5b3UncmUNCnN1cnByaXNlZCB0byBzZWUgdGV4dHMgd2l0aCBudW1iZXJzIGFzIHdlbGwsIHRoaW5rIGFib3V0IGl0OiB0aGUgZXhwcmVzc2lvbiBvbmx5DQpzYXlzIHRoYXQgdGhlIHRleHQgc2hvdWxkIGNvbnRhaW4gYSBub24tbnVtYmVyIGZvbGxvd2VkIGJ5IGEgbm9uLW51bWJlcjsNCml0IGRvZXNuJ3Qgc2F5IHRoYXQgdGhlcmUgc2hvdWxkIGJlIG5vIG51bWJlcnMgYXQgYWxsLiBIb3dldmVyLCBpZiBhIHRleHQgZmllbGQNCm9ubHkgY29udGFpbnMgbnVtYmVycywgaXQgd29uJ3QgYmUgbWF0Y2hlZC4gVG8gcmVwaHJhc2UsIHRoZSBleHByZXNzaW9uDQptZWFucyAiSSdtIGxvb2tpbmcgZm9yIHR3byBub24tbnVtYmVycyBpbiBhIHJvdywgZG8geW91IGhhdmUgdGhlbT8iDQoqIFlvdSBtaWdodCB3b25kZXIgaG93IFxEIHdvcmtzLiBEb2VzIGl0IHRoZW4gdHJhbnNsYXRlIHRvIGEgaHVnZSBzZXQgdGhhdA0KaW5jbHVkZXMgZXZlcnl0aGluZyBidXQgbnVtYmVycz8gVGhlIGFuc3dlciBpcyBtb3JlIHNpbXBsZTogdXNpbmcgYSBjYXJldCBeDQphcyB0aGUgZmlyc3QgY2hhcmFjdGVyIGluIGJyYWNlcyBtZWFucyBub25lIG9mIHRoZSBjaGFyYWN0ZXJzIHNob3VsZCBiZSBwcmVzZW50DQppbiB0aGUgcGF0dGVybi4gVGhlcmVmb3JlLCBcRCBzdGFuZHMgZm9yIFteMC05XS4NCiogVGhlIGV4cHJlc3Npb24gW15hLXpBLVowLTldIGxvb2tzIGZvciB0ZXh0cyB0aGF0IGNvbnRhaW4gc29tZXRoaW5nIHdoaWNoDQppcyBub3QgYSBsZXR0ZXIgb3IgbnVtYmVyLiBNb3N0IHRleHRzIHdpbGwgbWF0Y2gsIGFzIGZvciBpbnN0YW5jZSBzcGFjZXMgYW5kDQpwdW5jdHVhdGlvbiBtYXJrcyBhcmUgc3RpbGwgYWxsb3dlZC4gSG93ZXZlciwgZW1wdHkgZmllbGRzIHdpbGwgbm90IG1hdGNoLA0KYXMgdGhlcmUgbXVzdCBiZSBhdCBsZWFzdCBvbmUgY2hhcmFjdGVyIHdoaWNoIGlzIG5vdCBhIGxldHRlciBvciBudW1iZXIuDQoqIFRoZSBleHByZXNzaW9uIFteYS16QS1aMC05XVxkW15hLXpBLVowLTldIG1lYW5zIGFueSBkaWdpdCBzdXJyb3VuZGVkDQpieSBub24tbGV0dGVycyBvciBub24tbnVtYmVycy4gRm9yIGluc3RhbmNlLCB3ZSBzZWUgdGhhdCBzaW5nbGUgZGlnaXRzIGluDQpwYXJlbnRoZXNlcyBhcmUgbWF0Y2hlZC4gTm90ZSB0aGF0IGl0ZW1zIHN1Y2ggYXMgKDEyMykgd2lsbCBub3QgYmUgbWF0Y2hlZCwNCmJ1dCAoMykgd2lsbCwgYXMgd2UgZXhwbGljaXRseSBzYXkgdGhhdCBpdCBzaG91bGQgYmUgYSBzaW5nbGUgZGlnaXQuDQoqIFRoZSBwYXR0ZXJuIGEuYS5hIG1hdGNoZXMgYW55IHRleHQgd2hlcmUgYW4gYSBpcyBmb2xsb3dlZCBieSBhbnkgY2hhcmFjdGVyLA0KYW5vdGhlciBhLCBhbnkgY2hhcmFjdGVyLCBhbmQgYW5vdGhlciBhLiBGb3IgaW5zdGFuY2UsIHRleHRzIHdpdGggdGhlIHdvcmRzDQpkdWxjYW1hcmEsIGFsYWJhc3RlciwgYW5kIHNhbGFtYW5kZXIgd2lsbCBtYXRjaC4NCiogVGhlIHBhdHRlcm4gMTkuLiAodGhlcmUgaXMgYSBzcGFjZSBiZWZvcmUgYW5kIGFmdGVyKSB3aWxsIG1hdGNoIHllYXJzIGluIHRoZQ0KMjB0aCBjZW50dXJ5Lg0KKiBIb3dldmVyLCB5b3Ugc2hvdWxkIGJlIGNhcmVmdWwgd2l0aCB0aGUgZG90OiB0aGUgbGFzdCBwYXR0ZXJuIGFsc28gbWF0Y2hlcw0KMTl0aCBhbmQgMTlNJCwgYmVjYXVzZSBhIGRvdCByZWFsbHkgbWVhbnMgYW55dGhpbmcuIElmIGEgeWVhciBpcyB3aGF0IHlvdQ0Kd2FudCwgMTlcZFxkIGlzIG1vcmUgYWNjdXJhdGUuDQoqIFRvIGZpbmQgdGV4dHMgdGhhdCBoYXZlIHRocmVlIGNvbnNlY3V0aXZlIGRvdHMgaW4gdGhlbSwgdXNlIFwuXC5cLi4gKFRoaXMgY2FuDQphY3R1YWxseSBiZSBkb25lIGluIGEgbW9yZSBoYW5keSB3YXksIGFzIHdlJ2xsIHNlZSBpbiB0aGUgbmV4dCBzZWN0aW9uLikNCiogVG8gZmluZCB0ZXh0cyB3aXRoIGEgYmFja3NsYXNoLCB1c2UgXFwuIChUaGVyZSBhcmUgbm9uZSBpbiB0aGUgZGF0YXNldC4pDQoqIFRleHRzIHRoYXQgY29udGFpbiBhbiBvcGVuaW5nIG9yIGEgY2xvc2luZyBzcXVhcmUgYnJhY2tldCBhcmUgZm91bmQgd2l0aCBbXA0KW1xdXS4gVGhpcyBsb29rcyBjb21wbGljYXRlZCwgYnV0IGl0IGlzIHF1aXRlIGxvZ2ljYWw6IHRoZSBmaXJzdCBhbmQgbGFzdCBicmFja2V0DQpzYXkgImNob29zZSBhbnkgb2YgdGhlIHRoaW5ncyB3aXRoaW4iLiBBbmQgdGhlIHRoaW5ncyB3aXRoaW4gYXJlIGFjdHVhbA0Kc3F1YXJlIGJyYWNrZXRzLCBidXQgdGhleSBoYXZlIHRvIGJlIGVzY2FwZWQsIHNvIHRoZXkgYmVjb21lIGBcWyBhbmQgXF1gLg0KKiBXaXRoIGBbMl1gLHlvdSBmaW5kIHRleHRzIHRoYXQgY29udGFpbiB0aGUgbnVtYmVyIDIgKCJjaG9vc2UgYW55IG9mIHRoZSB0aGluZ3MNCndpdGhpbiIsIGFuZCB0aGUgb25seSB0aGluZyB3aXRoaW4gaXMgYSAyKS4gV2l0aCBgXFsyXF1gLCB5b3UgZmluZCB0ZXh0cyB3aXRoDQp0aGUgbnVtYmVyIDIgc3Vycm91bmRlZCBpbiBzcXVhcmUgYnJhY2tldHMsIGFzIHRoZSBicmFja2V0cyBhcmUgZXNjYXBlZCB0aGlzDQp0aW1lIGFuZCB0aHVzIGhhdmUgbm8gc3BlY2lhbCBtZWFuaW5nIGFueW1vcmUuDQoNCiMjX1F1YW50aWZpZXJzDQoNClF1YW50aWZpZXJzIGNhbiBleHByZXNzIHJlcGV0aXRpb24uIFRoZXJlIGFyZSB0aHJlZSBzaW1wbGUgcXVhbnRpZmllcnM6IGEgcGx1cyBzaWduICssDQp3aGljaCBtZWFucyBvbmUgb3IgbW9yZSB0aW1lcywgYW4gYXN0ZXJpc2sgKiwgd2hpY2ggbWVhbnMgemVybyBvciBtb3JlIHRpbWVzLCBhbmQNCmEgcXVlc3Rpb24gbWFyayA/LCB3aGljaCBtZWFucyB6ZXJvIG9yIG9uZSB0aW1lLiBUaGV5IG9ubHkgZXhlcnQgYW4gZWZmZWN0IG9uIHRoZQ0Kc3ltYm9sIHRoYXQgaXMgZGlyZWN0bHkgdG8gdGhlIGxlZnQgb2YgdGhlbToNCg0KKiBicmUrZCBtYXRjaGVzIHRleHRzIHRoYXQgY29udGFpbiBicmVkLCBicmVlZCwgb3IgYnJlZWVkIHdpdGggYW55IG51bWJlciBvZg0KZSwgYXMgbG9uZyBhcyBhdCBsZWFzdCBvbmUgZSBpcyBwcmVzZW50Lg0KKiBicmUqZCBtYXRjaGVzIHRleHRzIHRoYXQgY29udGFpbiBicmQsIGJyZWQsIGJyZWVkLCBvciBicmVlZWQgd2l0aCBhbnkNCm51bWJlciBvZiBlLCBldmVuIHdpdGhvdXQuIE5vdGUgaG93IGJyZCBpcyBtYXRjaGVkIHdpdGggdGhlIGFzdGVyaXNrLCBidXQNCm5vdCB3aXRoIHRoZSBwbHVzIHNpZ24uDQoqIGJyZT9kIG1hdGNoZXMgYnJkIGFuZCBicmVkLCBidXQgbm90IGJyZWVkIG9yIGFueSBvdGhlciBudW1iZXIgb2YgZXMuIFB1dA0Kc2ltcGx5LCBpdCBtYWtlcyB0aGUgZSBvcHRpb25hbC4NCiogQ29tYmluYXRpb25zIGFyZSBhbHNvIHBvc3NpYmxlLiBicj9lK2QgbWF0Y2hlcyBiZWQsIGJyZWQsIGJlZWQsIGJyZWVkLA0KYmVlZWQsIGJyZWVlZCwgYW5kIHNvIG9uLg0KKiBJbiBhZGRpdGlvbiwgeW91IGNhbiBiZSBleHBsaWNpdCBhYm91dCB0aGUgbnVtYmVyIG9mIHRpbWVzIHlvdSB3b3VsZCBsaWtlDQphIHN5bWJvbCB0byBvY2N1ciBieSB1c2luZyBjdXJseSBicmFjZXMge21pbixtYXh9LiBZb3UgY2FuIHNwZWNpZnkgdGhlDQptaW5pbXVtIGFuZCBtYXhpbXVtIG51bWJlciBvZiB0aW1lcyBpdCBjYW4gb2NjdXIuIEVpdGhlciBvbmUgY2FuIGJlDQplbXB0eSwgaW4gd2hpY2ggY2FzZSB0aGVyZSBpcyBubyBtaW5pbXVtIG9yIG1heGltdW0uIExlYXZlIHRoZSBjb21tYSBpbg0Kc28gT3BlblJlZmluZSBrbm93cyB3aGV0aGVyIHlvdSBzcGVjaWZpZWQgdGhlIG1pbmltdW0gb3IgdGhlIG1heGltdW0uDQpJZiB5b3UganVzdCBzdXBwbHkgYSBzaW5nbGUgbnVtYmVyIHdpdGhvdXQgYSBjb21tYSwgdGhlIGV4YWN0IG51bWJlciBvZg0KdGltZXMgd2lsbCBiZSBtYXRjaGVkLg0KKiBOXGR7NSw4fSwgbWF0Y2hlcyB0ZXh0cyB0aGF0IGNvbnRhaW4gYSBjb2RlIHRoYXQgc3RhcnRzIHdpdGggTiBmb2xsb3dlZCBieQ0KZml2ZSwgc2l4LCBzZXZlbiwgb3IgZWlnaHQgZGlnaXRzLCBhbmQgdGhlbiBhIGNvbW1hLg0KKiBOXGR7NSx9LCBtYXRjaGVzIHRleHRzIHRoYXQgY29udGFpbiBhIGNvZGUgdGhhdCBzdGFydHMgd2l0aCBOLCBhdCBsZWFzdCBmaXZlDQpkaWdpdHMsIGFuZCB0aGVuIGEgY29tbWEuDQoqIE5cZHssOH0sIG1hdGNoZXMgdGV4dHMgd2hpY2ggY29udGFpbiBhIGNvZGUgdGhhdCBzdGFydHMgd2l0aCBOLCBhdCBtb3N0IGVpZ2h0DQpkaWdpdHMsIGFuZCB0aGVuIGEgY29tbWEuDQoqIE5cZHs1fSwgbWF0Y2hlcyB0ZXh0cyB3aGljaCBjb250YWluIGEgY29kZSB0aGF0IHN0YXJ0cyB3aXRoIE4sIGV4YWN0bHkgZml2ZQ0KZGlnaXRzLCBhbmQgdGhlbiBhIGNvbW1hLiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gTlxkXGRcZFxkXGQgYnV0IG11Y2ggbW9yZQ0KY29tcGFjdCAoZXNwZWNpYWxseSBpZiBudW1iZXJzIGdldCBsYXJnZSkuDQoqIE5lZWRsZXNzIHRvIHNheSwgdGhlIHF1YW50aWZpZXJzIGFuZCBicmFjZXMgYXJlIHNwZWNpYWwgc3ltYm9scywgc28gaWYgeW91DQp3YW50IHRvIG1hdGNoIHRoZW0gbGl0ZXJhbGx5LCB5b3Ugc2hvdWxkIGVzY2FwZSB0aGVtIHdpdGggYSBiYWNrc2xhc2guDQpGb3IgaW5zdGFuY2UsIHF1ZXN0aW9uIG1hcmtzIGNhbiBiZSBtYXRjaGVkIHdpdGggXD8uDQoNCg0KIyNfQW5jaG9ycw0KDQpTb21ldGltZXMsIHlvdSBkb24ndCBvbmx5IHdhbnQgdG8gc2F5IGhvdyBtYW55IGNoYXJhY3RlcnMgdG8gbWF0Y2gsIGJ1dCBhbHNvDQp3aGVyZSB0aGV5IHNob3VsZCBiZSBtYXRjaGVkLiBUaGlzIGlzIHBvc3NpYmxlIHdpdGggYW5jaG9ycy4gQSBjYXJldCBeIGluZGljYXRlcyB0aGF0DQp0aGUgbWF0Y2ggc2hvdWxkIGhhcHBlbiBhdCB0aGUgYmVnaW5uaW5nIG9mIGEgbGluZSwgd2hpbGUgYSBkb2xsYXIgc2lnbiAkIGluZGljYXRlcw0KdGhhdCB0aGUgbWF0Y2ggc2hvdWxkIHN0b3AgYXQgdGhlIGVuZCBvZiBhIGxpbmUuIA0KDQpBZGRpdGlvbmFsbHksIHdlIGNhbiBpbmRpY2F0ZSB0aGF0IHRoZSBtYXRjaCBzaG91bGQgYmVnaW4gb3INCmVuZCBhdCBhIHdvcmQgYm91bmRhcnkgd2l0aCB0aGUgYW5jaG9yIFxiOg0KDQoqIF5cZCBtYXRjaGVzIGFsbCB0ZXh0cyB0aGF0IGJlZ2luIHdpdGggYSBudW1iZXIuDQoqIFxkJCBtYXRjaGVzIGFsbCB0ZXh0cyB0aGF0IGVuZCB3aXRoIGEgbnVtYmVyLg0KKiBeXGQuKlxkJCBtYXRjaGVzIGFsbCB0ZXh0cyB0aGF0IGJlZ2luIGFuZCBlbmQgd2l0aCBhIG51bWJlci4gUmVhZCB0aGlzDQpleHByZXNzaW9uIGFzOiBzdGFydCBvZiB0aGUgdGV4dCwgYSBudW1iZXIsIHplcm8gb3IgbW9yZSB0aW1lcyBhbnkgY2hhcmFjdGVyDQoodGhlIGRvdCksIGEgbnVtYmVyLCBlbmQgb2YgdGhlIHRleHQuIElmIHdlIHdvdWxkIHVzZSBeXGQrJCBpbnN0ZWFkLCB3ZQ0Kd291bGQgaGF2ZSBhbGwgdGV4dHMgdGhhdCBjb250YWluIG9ubHkgYSBudW1iZXIgKG9mIGFueSBsZW5ndGgpLg0KKiBcYlxkezN9XGIgc2VhcmNoZXMgZm9yIHRleHRzIHRoYXQgY29udGFpbiBhdCBsZWFzdCBvbmUgbnVtYmVyIG9mIGV4YWN0bHkNCnRocmVlIGRpZ2l0cywgc2luY2UgdGhlIFxiIGFuY2hvciBtYXRjaGVzIGF0IHdvcmQgYm91bmRhcmllcy4gSWYgdGhlIHRleHQNCmNvbnRhaW5zIGZvdXItZGlnaXQgbnVtYmVycyBidXQgbm8gdGhyZWUtZGlnaXQgbnVtYmVycywgaXQgZG9lcyBub3QgbWF0Y2guDQooSWYgd2Ugd291bGQgcmVtb3ZlIHRoZSBcYiBhbmNob3JzLCBpdCB3b3VsZC4pDQoqIF5cZHszfVxiIGZpbmRzIHRleHRzIHRoYXQgc3RhcnQgd2l0aCBhIHRocmVlLWRpZ2l0IG51bWJlci4NCg0KDQoNCiMjX0Nob2ljZXMNCg0KU3F1YXJlIGJyYWNrZXRzIGdpdmUgcmVndWxhciBleHByZXNzaW9ucyB0aGUgcG9zc2liaWxpdHkgdG8gY2hvb3NlIG9uZSBvZiB0aGUgbWFueSBjaGFyYWN0ZXJzOiBbYS16MTIzXSBzZWFyY2hlcyBmb3IgdGV4dHMgd2l0aCBhdCBsZWFzdCBvbmUgbG93ZXJjYXNlIGxldHRlciBvciBhbnkgb2YgdGhlIGRpZ2l0cyAxLCAyLCBhbmQgMy4gT2Z0ZW4sIHRoZSBjaG9pY2VzIGFyZSBsYXJnZXIsIGFzIHRoZXkgY2FuIGJlIHNldmVyYWwgbGV0dGVycyBvciB3b3JkcyBsb25nLiBGb3IgdGhpcywgdGhlIG9yIG9wZXJhdG9yIHwgd2FzIGludHJvZHVjZWQuIEl0IHdvcmtzIGFzIGFuIE9SIG9wZXJhdG9yIGJldHdlZW4gc2V2ZXJhbCBhbHRlcm5hdGl2ZXM6DQoNCiogZ2xhc3N8d29vZHxzdGVlbCB3aWxsIG1hdGNoIHRleHRzIHRoYXQgY29udGFpbiBnbGFzcywgd29vZCwgb3Igc3RlZWwuDQoqIFxkK3xtYW55fGZldyBtYXRjaGVzIGVpdGhlciBhIG51bWJlciwgbWFueSBvciBmZXcuDQoqIE5cZHs1fSx8Tlxkezh9LCBtYXRjaGVzIGVpdGhlciBmaXZlLWRpZ2l0IG9yIGVpZ2h0LWRpZ2l0IG51bWJlcnMgdGhhdCBzdGFydA0Kd2l0aCBhbiBOIGFuZCBlbmQgd2l0aCBhIGNvbW1hLCBidXQgbm90aGluZyBpbiBiZXR3ZWVuIChzbyBubyBzaXgtZGlnaXQNCm51bWJlcnMgZm9yIGluc3RhbmNlKS4NCg0KIyNfR3JvdXBzDQoNCklmIHlvdSB3YW50IHRvIHVzZSBxdWFudGlmaWVycw0Kb24gYSBncm91cCBvZiBjaGFyYWN0ZXJzIGluc3RlYWQgb2Ygb24gYSBzaW5nbGUgY2hhcmFjdGVyLCB5b3UgaGF2ZSB0byBlbmNsb3NlIHRoZW0NCmluIHBhcmVudGhlc2VzICgpOg0KDQoqIFdoaWxlIGxhKyBtYXRjaGVzIHRleHRzIHRoYXQgY29udGFpbiBsYSwgbGFhLCBsYWFhLCBhbmQgc28gb24sIHRoZSBleHByZXNzaW9uDQoobGEpKyBmaW5kcyB0ZXh0cyB0aGF0IGNvbnRhaW4gbGEsIGxhbGEsIGxhbGFsYSwgYW5kIHNvIG9uLg0KKiBUaGUgZXhwcmVzc2lvbiBhbmFseXp8c2Ugd291bGQgbWF0Y2ggdGV4dHMgdGhhdCBjb250YWluIGFuYWx5eiBhbmQgdGV4dHMNCnRoYXQgY29udGFpbiBzZS4gVGhpcyBpcyBwcm9iYWJseSBub3QgdGhhdCB1c2VmdWwuIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUNCmV4cHJlc3Npb24gYW5hbHkoenxzKWUgbWF0Y2hlcyBib3RoIGFuYWx5emUgYW5kIGFuYWx5c2UuIE5vdGUgdGhhdA0KaW4gdGhpcyBjYXNlLCB0aGlzIGlzIGVxdWl2YWxlbnQgdG8gYW5hbHlbenNdZSBiZWNhdXNlIHRoZSBjaG9pY2UgY29uc2lzdHMgb2YNCmEgc2luZ2xlIGxldHRlci4gSG93ZXZlciwgdGhpcyB3b3VsZCBub3QgYmUgdGhlIGNhc2Ugd2l0aCBhbmFseXooZXxpbmcpLA0Kd2hpY2ggd291bGQgbWF0Y2ggYW5hbHl6ZSBhbmQgYW5hbHl6aW5nLg0KDQojI19PdmVydmlldw0KDQohW10oNTAuUE5HKQ0KDQohW10oNTEuUE5HKQ0KDQpgYGB7cn0NCg0KI0xpbms6aHR0cDovL2ZpbGUuYWxsaXRlYm9va3MuY29tLzIwMTUxMDEyL1VzaW5nJTIwT3BlblJlZmluZS5wZGYNCg0KYGBgDQoNCg0KPEJyPg0KDQoNCiM2LiBHZW5lcmFsIFJlZmluZSBFeHByZXNzaW9uIExhbmd1YWdlIChHUkVMKQ0KDQojI19UcmFuc2Zvcm1pbmcgZGF0YQ0KDQpZb3UgY2FuIGVpdGhlciBjaGFuZ2UgY2VsbHMgaW4tcGxhY2UgKGJ5IG5hdmlnYXRpbmcgdG8gdGhlIHJlc3BlY3RpdmUgY29sdW1uIGRyb3Bkb3duIGFuZCB0aGVuIHRvIEVkaXQgY2VsbHMgfCBUcmFuc2Zvcm0uKSBvciBtYWtlIGEgbmV3IGNvbHVtbiB3aXRoIHRoZSB0cmFuc2Zvcm1lZCB2YWx1ZXMgKGJ5IG5hdmlnYXRpbmcgdG8gdGhlIHJlc3BlY3RpdmUgY29sdW1uIGRyb3Bkb3duIGFuZCB0aGVuIHRvIEVkaXQgY29sdW1uIHwgQWRkIGNvbHVtbiBiYXNlZCBvbiB0aGlzIGNvbHVtbi4pDQoNCiogYCJUSVRMRTogIiArIHZhbHVlICsgIi4iYC4gQWRkcyB0aGUgdGV4dCBUSVRMRTogYmVmb3JlIHRoZSB2YWx1ZSBhbmQNCmFwcGVuZHMgYSBkb3QgdG8gdGhlIGVuZC4NCiogYHZhbHVlLnJlcGxhY2UoInN0b25lIiwgInN0b25lcyIpYC4gVG8gcmVwbGFjZSB0aGUgc3RyaW5nIHN0b25lIGJ5IHN0b25lcyBpbiBlYWNoIGNlbGwNCiogYHZhbHVlLnNwbGl0KCJ8IikubGVuZ3RoKClgLiBUbyBzcGxpdCB0aGUgdmFsdWUgd2hlbmV2ZXIgaXQgZW5jb3VudGVycyBhIHZlcnRpY2FsIGJhciwgYW5kIHRoZW4gdXNlcyB0aGUgbGVuZ3RoIGZ1bmN0aW9uIHRvIGNvdW50IHRoZSBudW1iZXIgb2YgcmVzdWx0aW5nIHZhbHVlcy4NCiogYHZhbHVlLnNwbGl0KCJ8IikudW5pcXVlcygpLmpvaW4oInwiKWAuIFJlbW92ZXMgZHVwbGljYXRlIHZhbHVlcyBmcm9tIHRoZSBmaWVsZC4NCg0KDQojI19DcmVhdGluZyBjdXN0b20gZmFjZXRzDQoNCkxldCdzIGNyZWF0ZSBhIHNpbXBsZSBmYWNldCBieSBjbGlja2luZyBvbiB0aGUgT2JqZWN0IFRpdGxlIGRyb3Bkb3duIGFuZCBuYXZpZ2F0aW5nDQp0byBGYWNldCB8IEN1c3RvbWl6ZWQgRmFjZXRzIHwgRmFjZXQgYnkgYmxhbmsuICANCg0KIVtdKDUyLlBORykNCg0KYGBge3J9DQoNCiNMaW5rOmh0dHA6Ly9maWxlLmFsbGl0ZWJvb2tzLmNvbS8yMDE1MTAxMi9Vc2luZyUyME9wZW5SZWZpbmUucGRmDQoNCmBgYA0KDQpXZSBzZWUgdGhhdCB0aGUgZXhwcmVzc2lvbiBmb3JtIHRvIGZpbGwgd2l0aCBHUkVMIA0KDQojI19Tb2x2aW5nIHByb2JsZW1zIHdpdGggR1JFTA0KDQpBbHNvLCB5b3UnbGwgZ2FpbiBtb3JlIGFuZCBtb3JlIGV4cGVyaWVuY2Ugd2l0aCByZWd1bGFyIGV4cHJlc3Npb25zIGFuZCBHUkVMIGFzIHlvdSBncmFkdWFsbHkgYmVnaW4gdG8gbWFzdGVyIHRoZSBiYXNpY3MuIEZyb20gdGhhdCBwb2ludCBvbndhcmRzLCBpdCBpcyBhIHNtYWxsIHN0ZXAgdG8gdGhlIHRoaW5ncyB0aGF0IGFyZSBpbmNyZWFzaW5nbHkgY29tcGxleC4gDQoNCkZvciBtb3JlIGluZm9ybWF0aW9uOiBodHRwczovL2dpdGh1Yi5jb20vT3BlblJlZmluZS9PcGVuUmVmaW5lL3dpa2kvVW5kZXJzdGFuZGluZy1FeHByZXNzaW9ucw0KDQo8QnI+DQoNCg0KI0NoYW5nZSBsb2cgdXBkYXRlDQoNClRoaXMgTm90ZWJvb2sgdXNpbmcgaXRlcmF0aXZlIGRldmVsb3BtZW50LiBNb3JlIHByZWZlcmVuY2VzIGFuZCByZXZpc2lvbiB3aWxsIGJlIGFkZGVkIGluIHRoZSBuZXh0IHN0ZXBzLiBCZWxvdyBhcmUgdGhlIHRpbWVsaW5lIGNoYW5nZToNCg0KKiAwNy4wNS4yMDE2DQoqIDI3LjEyLjIwMTgNCiogMDIuMDEuMjAxOQ0KKiAwOC4wMS4yMDE5DQoqIDIzLjAxLjIwMTkNCg0KPEJyPg0KDQojUHJlZmVyZW5jZXMNCg0KKiBbT3BlblJlZmluZSBPZmZpY2lhbF0oaHR0cDovL29wZW5yZWZpbmUub3JnLykNCg0KKiBbSUJNIGNvZ25pdGl2ZSBjbGFzcyBEUDAxMDFFTl0oaHR0cHM6Ly9jb2duaXRpdmVjbGFzcy5haS9jb3Vyc2VzL2ludHJvZHVjdGlvbi10by1vcGVucmVmaW5lLykNCg0KKiBbRG9jdW1lbnRhdGlvbiBGb3IgVXNlcnNdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuUmVmaW5lL09wZW5SZWZpbmUvd2lraS9Eb2N1bWVudGF0aW9uLUZvci1Vc2VycykNCg0KKiBbVHV0b3JpYWw6IE9wZW5SZWZpbmUgVW5pdmVyc2l0eSBvZiBNYXJ5bGFuZF0oaHR0cHM6Ly9jYXNjaS51bWQuZWR1L3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDEzLzEyL09wZW5SZWZpbmUtdHV0b3JpYWwtdjEuNS5wZGYpDQoNCiogW1dpa2lwZWRpYV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3BlblJlZmluZSkNCg0KKiBbUmVmaW5lUHJvIEluYy5dKGh0dHA6Ly9yZWZpbmVwcm8uY29tLykNCg0KKiBbQ2xlYW5pbmcgRGF0YSB3aXRoIE9wZW5SZWZpbmUsIEpvaG4gTGl0dGxlXShodHRwczovL2xpYmpvaG4uZ2l0aHViLmlvL29wZW5yZWZpbmUvKQ0KDQoqIFtHZXR0aW5nIFN0YXJ0ZWQgd2l0aCBPcGVuUmVmaW5lLCBUaG9tYXMgUGFkaWxsYV0oaHR0cDovL3Rob21hc3BhZGlsbGEub3JnL2RhdGFwcmVwLykNCg0KKiBbT3BlblJlZmluZSwgUXVlZW5gcyBVbml2ZXJzaXR5XShodHRwczovL2FjY29sZWRzLmZpbGVzLndvcmRwcmVzcy5jb20vMjAxNS8xMi9hY2NvbGVkczIwMTUtb3Blbl9yZWZpbmUucGRmKQ0KDQoqIFtVc2luZyBPcGVuUmVmaW5lLCBNYXggRGUgV2lsZGVdKGh0dHBzOi8vd3d3LmFtYXpvbi5jb20vVXNpbmctT3BlblJlZmluZS1SdWJlbi1WZXJib3JnaC9kcC8xNzgzMjg5MDgyKQ0KDQoNCiNMaWNlbnNlDQoNCltNSVRdKGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUKQ0KDQoNCg==