Introduction

R programs can connect to virtually any relational (and many non-relational) databases as well as tabular data in files. This tutorial provides an overview of the different approaches to working with data in databases.

Connect to Database

The first step is to connect to the database. This requires a package for the database to which you connect. In this tutorial we will connect to SQLite so we need the corresponding package: RSQLite. Naturally, as with all packages in R, you must install the package first and then load it with library.

With SQLite, if you attempt to open a database that does not exist, it will be created as a new and empty database. This is not true for other databases: any creation must be done through admin tools. In the code below, we connect to an existing database. If you are working in an R Project, the database file will be created in the project’s root folder, otherwise it will be created in the current working directory (which could be anywhere, so best to work in a project).

library(RSQLite)

dbfile = "CoffeeDB.sqlitedb"
conn <- dbConnect(RSQLite::SQLite(), dbfile)

The RSQLite package has a small set of database meta functions that allow us to enquire about the database itself. For example, the function dbListTables lists all tables in the database. The parameter conn is the database connection object returned from dbConnect().

dbListTables(conn)
## [1] "arx_coffees" "coffees"     "customers"   "order_items" "orders"     
## [6] "salespeople"

To get the list of columns of a specific table, you can use dbListFields().

dbListFields(conn, "coffees")
## [1] "id"          "coffee_name" "price"

Setting Default Connection

If only one SQLite (or other) database connection is used for SQL code chunks, then a default connection can bet configured which means that the connections string connection=dbcon can be omitted. The R code fragment must be included after you made a connection to the database. Naturally, replace the connection variable dbcon below with the variable from your own code, i.e., the variable to which you assigned the return value from dbConnect().

library(DBI)
dbcon <- dbConnect(RSQLite::SQLite(), dbname = "sql.sqlite")
knitr::opts_chunk$set(connection = "dbcon")

Execute SQL Query

There are two common ways to run a SQL query against a database. The approaches are the same for all databases and are not exclusive to SQLite.

  1. Embed the SQL statement in a {sql} chunk.
  2. Send the query via an R function (dbGetQuery() and dbSendQuery()).

Any embedded SQL code in a {sql} chunk is translated to a dbSendStatement() call during knitting. So, there’s no performance difference and which to use is a matter of preference. Using a {sql} chunk makes database code more explicit and conforms to the principles of literate programming.

dbGetQuery() and dbSendQuery() are used to send SELECT statements, while dbSendStatement() is used for INSERT, UPDATE, DELETE, CREATE TABLE, and any other SQl statement.

If you need to write an R script (rather than an R Notebook) then you must use the R functions and cannot use {sql} chunks.

Simple Embedded Query: {sql} Code Chunks

The {sql} chunk requires specifying the connection to the database to which the SQL query should be send in the connection parameter. This is the return value from dbConnect().

The generic structure of a {sql} chunk is defined below. A SQL statement can be a SELECT, INSERT, UPDATE, DELETE, ALTER, CREATE, or any other valid SQL statement.

The result of the above SQL query is shown below.

select coffee_name as coffee, price
  from coffees
 where price > 8;
Table 1: 8 records
coffee price
French_Roast 8.99
Espresso 9.99
Colombian_Decaf 8.99
French_Roast_Decaf 9.99
French_Roast 8.99
Espresso 9.99
Colombian_Decaf 8.99
French_Roast_Decaf 9.99

You can only place one SQL statement into a {sql} chunk and thus the semi-colon at the end of statement is optional.

SQL Chunk Parameters

The list below are the most common parameters for a {sql} chunk, although the list is not exhaustive and there are others.

  • connection – a connection object to the database to which the SQL statement will be sent for execution; generally the return value from dbConnect()

  • eval – if TRUE, then the SQL code is executed; if FALSE, then the code is not executed

  • echo – if set to TRUE, then the SQL code is included in any knitted file; if FALSE then the code in the chunk is not in the knitted output

  • output.var – the name of a data frame variable in which the output result will be stored and can be used is subsequent R code chunks; the variable must be in quotes

Capture Query Result

Every SQL SELECT query returns a table. In R, the returned table is transformed to a data frame. This data frame can be assigned to a variable for further processing. For a {sql} chunk you specify the data frame to which the result set is saved using the output.var parameter:

{sql simpleSQLwithResult, connection = conn, output.var = ‘rs’}.

Note that the output data frame must be in quotes.

We can now use the result in R. So, in the example below we calculate the average price of coffee.

mean.Coffee.Price <- mean(rs$price)

print(paste0("Average price of coffee: $", round(mean.Coffee.Price, 2)))
## [1] "Average price of coffee: $9.49"

Embedded Queries with Parameters

Often, we need to execute a SQL query but use a parameter from R. The code below demonstrates how to “pass a variable” to a {sql} chunk and how to use the parameter in the chunk.

First, here is an R code chunk that defines a variable called thePrice and sets it to the value 8.

thePrice <- 8

In the SQL code chunk below, we refer to the value of that variable using the syntax ?RVariable. So, the ?thePrice is substituted with the value of the R variable thePrice.

select * from coffees where price > ?thePrice 

So, the actual SQL query that is sent to the database is: select * from coffees where price > 8.

To verify, here is the result of the query (we used the output.var=“expCoffees” parameter in the SQL code chunk):

head(expCoffees,4)
##   id        coffee_name price
## 1  2       French_Roast  8.99
## 2  3           Espresso  9.99
## 3  4    Colombian_Decaf  8.99
## 4  5 French_Roast_Decaf  9.99

As an alternative, we could have executed the query fully in an R code chunk using the function dbGetQuery() which returns the result as a data frame. In this example, the parameter is passed to the SQL query through string concatenation.

p <- 8
sql <- paste0("select * from coffees where price > ", p)
df <- dbGetQuery(conn, sql)

Querying via R Code

Rather than embedding the SQL query in a {sql} chunk, it often more convenient, simpler, or necessary to execute the query within an R code block. There is no performance difference.

There are two R functions you can choose from: dbGetQuery() and dbSendQuery().

To execute a query within R code, you need to connect to the database, define the SQL query as a string, run the query, and then inspect the result set. The result set is a data frame. Of course, you only need to connect to the database once and not every time before a query. In the example below, we use the same database connection from above.

sql <- "select coffee_name as coffee, price
        from coffees
        where price > 8;"

rs <- dbGetQuery(conn, sql)

print(rs)
##               coffee price
## 1       French_Roast  8.99
## 2           Espresso  9.99
## 3    Colombian_Decaf  8.99
## 4 French_Roast_Decaf  9.99
## 5       French_Roast  8.99
## 6           Espresso  9.99
## 7    Colombian_Decaf  8.99
## 8 French_Roast_Decaf  9.99

Note that the semi-colon at the end of the query is optional as you can only send a single query. The syntax of the query depends on the database – it is not interpreted by R but rather by the database. For example, MySQL recognizes CREATE SCHEMA as a SQL statement, but SQLite does not.

If you needed to add a parameter, then you can use paste0() to generate the SQL query string.

p <- 9

sql <- "select coffee_name as coffee, price
        from coffees
        where price > "
sql <- paste0(sql, p)

rs <- dbGetQuery(conn, sql)

print(rs)
##               coffee price
## 1           Espresso  9.99
## 2 French_Roast_Decaf  9.99
## 3           Espresso  9.99
## 4 French_Roast_Decaf  9.99

Alternatively, you can use dbSendQuery(), which allows you to add parameters to the query. Note that dbSendQuery() executes the query but does not return a result. For that you will need to explicitly call dbFetch()

p <- 9

sql <- "select coffee_name as coffee, price
        from coffees
        where price > "
sql <- paste0(sql, p)

rs <- dbSendQuery(conn, sql)

dbFetch(rs)
##               coffee price
## 1           Espresso  9.99
## 2 French_Roast_Decaf  9.99
## 3           Espresso  9.99
## 4 French_Roast_Decaf  9.99
print(rs)
## <SQLiteResult>
##   SQL  select coffee_name as coffee, price
##         from coffees
##         where price > 9
##   ROWS Fetched: 4 [complete]
##        Changed: 0

Rather than manipulating the query string, you can add parameters to the query. The parameters are marked with ? in the SQL query string and are then bound to actual values (in order) with a list passed to the parameter params.

minP <- 8
maxP <- 12

sql <- "select coffee_name as coffee, price
        from coffees
        where price between ? and ?"

rs <- dbSendQuery(conn, sql, params = list(minP, maxP))
## Warning: Closing open result set, pending rows
dbFetch(rs)
##               coffee price
## 1       French_Roast  8.99
## 2           Espresso  9.99
## 3    Colombian_Decaf  8.99
## 4 French_Roast_Decaf  9.99
## 5       French_Roast  8.99
## 6           Espresso  9.99
## 7    Colombian_Decaf  8.99
## 8 French_Roast_Decaf  9.99
print(rs)
## <SQLiteResult>
##   SQL  select coffee_name as coffee, price
##         from coffees
##         where price between ? and ?
##   ROWS Fetched: 8 [complete]
##        Changed: 0

Reading Entire Tables

The convenience function dbReadTable reads an entire table into a data frame. It is equivalent to the query SELECT * FROM table.

rs <- dbReadTable(conn, "coffees")
## Warning: Closing open result set, pending rows
head(rs, 3)
##   id  coffee_name price
## 1  1    Colombian  7.99
## 2  2 French_Roast  8.99
## 3  3     Espresso  9.99

Writing Entire Data Frames

The convenience function dbWriteTable writes an entire data frame to a table. There are two important parameters for the function: overwrite and append. By default, both are FALSE which means that dbWriteTable can only be used to write a data frame to a new table (i.e., one that does not exist in the database). To add rows to an existing table requires append = T.

rs <- dbReadTable(conn, "coffees")

# let's write all of the data to an archive table, but let's delete the old
# table first
dbRemoveTable(conn, "arx_coffees", fail_if_missing = F)
dbWriteTable(conn, "arx_coffees", rs, append = T)

# and read it back to see if it worked
rs <- dbReadTable(conn, "arx_coffees")

tail(rs, 3)
##    id        coffee_name price
## 8  13           Espresso  9.99
## 9  14    Colombian_Decaf  8.99
## 10 15 French_Roast_Decaf  9.99

Complete Example

The code below shows the complete sequence of connect to, creating, inserting, and querying a SQLite database from an R program (download script):

# Load necessary library
library(RSQLite)

# Create a new SQLite database
db <- dbConnect(SQLite(), dbname = "sample.db")

# Create a table named 'customers'
dbExecute(db, "
  CREATE TABLE customers (
    cid INTEGER PRIMARY KEY,
    name TEXT,
    email TEXT
  )
")
## [1] 0
# Insert 3 rows of synthetic data into the 'customers' table
s <- dbExecute(db, "INSERT INTO customers (cid, name, email) VALUES (1, 'Alice', 'alice@example.com')")
s <- dbExecute(db, "INSERT INTO customers (cid, name, email) VALUES (2, 'Bob', 'bob@example.com')")
s <- dbExecute(db, "INSERT INTO customers (cid, name, email) VALUES (3, 'Charlie', 'charlie@example.com')")

# Retrieve all rows in the 'customers' table and display them
customers <- dbGetQuery(db, "SELECT * FROM customers")
print(customers)
##   cid    name               email
## 1   1   Alice   alice@example.com
## 2   2     Bob     bob@example.com
## 3   3 Charlie charlie@example.com
# Close the connection to the database
dbDisconnect(db)

The return value of dbExecute() is always the number of rows affected. So, if the return value is 0 it means that the SQL statement failed. Consequently, it is always a good idea to check the return value of dbExecute() and dbSendStatement().

Other Convenience Functions

In addition to the convenience functions mentioned above, you also have the ones below, among others:

  • dbAppendTable()
  • dbCreateTable()
  • dbRemoveTable()

Querying Data Frames with sqldf

sqldf is a package that allows data frames to be queried with SQL as if they were tables in a database. Many queries, while generally doable in Base R or with tidyverse, are often simpler with a SQL query – albeit a bit slower, but that reduction in performance is often not perceptible. However, when the data frame is large, base R functions are much faster as sqldf actually works by copying the data frame to a temporary in-memory SQLite database and runs a SQL query on that table in the database – that can be slow. Use sqldf primarily for grouping and extracting unique values – use which() and any() as well as logical vector operations otherwise.

We will demonstrate the use of sqldf by querying the data in a large CSV file. The file is loaded into a data frame and then treated as if it were a table in a database.

txns <- read.csv("customertxndata.csv", 
               header = F, 
               col.names = c("visits","numtxns","os","gender","total"))

The CSV file contains data on visits to an e-commerce site.

head(txns, 4)
##   visits numtxns      os gender     total
## 1      7       0 Android   Male    0.0000
## 2     20       1     iOS   <NA>  576.8668
## 3     22       1     iOS Female  850.0000
## 4     24       2     iOS Female 1050.0000

Execute sqldf SQL Query

sqldf executes a SQL query against an in-memory data frame and returns the query result as a data frame. The data frame can be captured and then processed further with sqldf or R.

library(sqldf)

sqlq <- "select gender, sum(total) as total from `txns` group by gender"
df <- sqldf(sqlq)

head(df, 3)
##   gender   total
## 1   <NA> 2522332
## 2 Female 2790500
## 3   Male 5059692
library(sqldf)

# imagine you need to ask user for OS, perhaps by choosing from a menu
theOS <- "' and 1=1 or gender <>'"

sqlq <- paste0("select gender, sum(total) as total from `txns` where os='",
                theOS, "' group by gender")
df <- sqldf(sqlq)

head(df, 4)
##   gender   total
## 1 Female 2790500
## 2   Male 5059692

A potential issue with sqldf can occur when you connect to MySQL or a non-SQLite database as sqldf attempts to use your existing database connection as a backing store for its data; this will often not work due to security constraints. So, you need to add the R code options(sqldf.driver = ‘SQLite’) which forces sqldf to use SQLite as its backing store.

Columns containing dot (.): A column containing a dot (period) in its name confuses SQL as the dit is a separator between table name and column name. So, T.x refers to column x in the table T. That is useful when you have queries that involve multiple tables and columns with the same name are in several tables; it allows disambiguation. However, if you have a column in a CSV or data frame named “year.before” then SQL would interpret incorrectly; to “escape” the meaning of the dot, you need to enclose the column in backticks, i.e., `year.before`.

Creating a Database

Let’s create a new (and empty) database.

library(RSQLite)

db.file <- "customerDB.db"

unlink(db.file)
custDB <- dbConnect(RSQLite::SQLite(), db.file)

We can create as well as drop tables in three ways:

  1. embed SQL CREATE TABLE statements in a {sql} chunk
  2. send SQL CREATE TABLE statements with dbExecute()
  3. call the convenience functions dbCreateTable() or dbRemoveTable()

Which to use is preference; there is little difference in performance.

Dropping a Table

sqlCode <- "drop table if exists txns"
dbExecute(custDB, sqlCode)
## [1] 0

Create Tables in {sql}

Create new tables using {sql} chunks:

create table txns (
  id INTEGER PRIMARY KEY,
  visits INTEGER NOT NULL,
  os TEXT
)

Create Table in R

Create new tables using dbExecute():

sqlCode <- "create table if not exists txns (
              id INTEGER PRIMARY KEY,
              visits INTEGER NOT NULL,
              os TEXT
            )"
dbExecute(custDB, sqlCode)
## [1] 0

Adding Data to the Database

Adding new data to the database can be done in several ways. Insert data row by row using SQL INSERT statements or add all rows from a data frame to a table in batch mode using dbWriteTable().

The code below loads a CSV that we will load into the a newly created database.

txns <- read.csv("customertxndata.csv", 
               header = F,
               col.names = c("visits","numtxns","os","gender","total"))

txns$id <- seq(from = 1, to = nrow(txns)) + 100

Bulk Loading

To get data from a data frame into a table in the database, you can either insert the data row by row in a loop or (better) use dbWriteTable() which inserts an entire data frame into a new or an existing table.

dbWriteTable(custDB, "txns", txns[,c(6,1,3)], overwrite=F, append=T)

dbWriteTable() requires that “bulk/batch loading” is enables for the database. This is not the default for MySQL but is for SQLite. For MySQL it must be configured first. Some cloud services for MySQL do not enable batch loading (e.g., db4free.net).

If your table has row names and you end up with an extra column in the database, then specify row.names = F as a parameter.

Prepared Statements

Prepared statements are a special form of a SQL statement that includes parameters. It is preferable to use prepared statements rather than build a SQL string use concatenation. However, some database may not support statements (notably MySQL hosted on db4free.net).

id <- 102
numVisits <- 4
os <- 'iOS'

# sets up prepared statement code
sqlCode <- "insert into txns values (:id, :n, :os)"

# create a prepared statement with parameters
ps <- dbSendStatement(custDB, sqlCode)

# bind parameters
dbBind(ps, params = list(id = id, n = numVisits, os = os))

# run the query
dbClearResult(ps)

Insert Data Row by Row

If bulk loading is not an option because either the database does not support it or the data has to be processed prior to insertion, then adding the data row by row in a loop using a prepared statement is an alternative. However, this process is much slower and should only be used as a last resort.

nrows <- nrow(txns)

for (i in 1:nrows)
{
  id <- txns[i,6]
  numVisits <- txns[i,1]
  os <- txns[i,3]
  
  # sets up prepared statement code
  sqlCode <- "insert into txns values (:id, :n, :os)"
  
  # create a prepared statement with parameters
  ps <- dbSendStatement(custDB, sqlCode)
  
  # bind parameters
  dbBind(ps, params = list(id = id, n = numVisits, os = os))
}

The code below is a performance improvement where the loop generates a single large SQL INSERT statement that inserts multiple rows in a single call to the database. Some database may restrict the number of values that can be included in a single INSERT statement, so this may have to be done in batches.

delete from txns
nrows <- nrow(txns)
sqlCode <- "insert into txns values "

for (i in 1:nrows)
{
  id <- txns[i,6]
  numVisits <- txns[i,1]
  os <- txns[i,3]
  
  # add values to the list of values
  sqlCode <- paste0(sqlCode, "(",id,",", numVisits, ",'", os, "')")
  
  # add comma at the end except for the last row
  if (i < nrows)
    sqlCode <- paste0(sqlCode, ",")
}

print(sqlCode)

# execute the insert statement
r <- dbExecute(custDB, sqlCode)

If the data frame is too large and the subsequent SQL INSERT statement would have too many values and exceed a database limit, then insert the data in stages. For example, read rows in batches from the CSV and inserts them into the database. read.csv has parameters skip and nrows to help do that.

Clearing Result Sets

A common warning message is received (“Warning: Closing open result set, pending rows”) when working with SQLite databases in R using the DBI or RSQLite package. It indicates that a previous query or statement execution was not properly finalized or closed, leaving an open “result set” that hasn’t been fully handled. This typically happens when you:

  1. Execute a query or statement that returns rows (e.g., a SELECT statement) but do not fetch or clear the results.
  2. Forget to explicitly clear or finalize a result set after running dbSendStatement() or dbSendQuery().

Understanding the Problem

The function dbSendStatement() (from the DBI package) executes a SQL statement, such as an INSERT, UPDATE, or DELETE, which does not return a result set. However, the function returns a DBIResult object that must be cleared explicitly using dbClearResult().

If you don’t clear the DBIResult object, it remains open, and when you close the connection or perform another database operation, RSQLite automatically clears the open result, leading to the warning.

Resolving the Warning

To resolve the warning, you should explicitly clear the result set after executing a statement with dbSendStatement(). Here’s an example:

# Load required packages
library(DBI)
library(RSQLite)

# Create a connection to the SQLite database
con <- dbConnect(SQLite(), "example.db")

# Example: Insert data into a table
stmt <- dbSendStatement(con, "INSERT INTO my_table (column1, column2) VALUES (?, ?)")

# Bind values to the statement
dbBind(stmt, list("value1", "value2"))

# Clear the result explicitly to avoid the warning
dbClearResult(stmt)

# Disconnect from the database
dbDisconnect(con)

Key Points to Avoid the Warning

  1. Always Clear the Result: Use dbClearResult() after executing a query or statement with dbSendQuery() or dbSendStatement().

  2. Use dbExecute() for Simpler Cases: If you do not need to bind parameters or fetch rows, prefer using dbExecute(), which handles result clearing automatically:

    dbExecute(con, "INSERT INTO my_table (column1, column2) VALUES ('value1', 'value2')")
  3. Review Your Code for Open Results: Check if you have any dbSendQuery() or dbSendStatement() calls without corresponding dbClearResult().

Explanation of the Warning

SQLite enforces that all result sets must be closed before executing new statements. RSQLite warns you when it detects an open result set because this could lead to resource leaks or undefined behavior.

By adhering to proper resource management (clearing results and closing connections), you can avoid such warnings and ensure robust interaction with your SQLite database.

Disconnect from Database

When a database connection is no longer needed, it must be closed by disconnecting from the database. This frees up database and other resources.

dbDisconnect(custDB)

Files & Resources

All Files for Lesson 6.301

Errata

Let us know.

LS0tCnRpdGxlOiAiV29ya2luZyB3aXRoIERhdGFiYXNlcyBpbiBSIgpwYXJhbXM6CiAgY2F0ZWdvcnk6IDYKICBudW1iZXI6IDMwMQogIHRpbWU6IDQ1CiAgbGV2ZWw6IGJlZ2lubmVyCiAgdGFnczogInIsU1FMLHNxbGRmLGRhdGFiYXNlLHNxbGl0ZSIKICBkZXNjcmlwdGlvbjogIkRlbW9uc3RyYXRlcyBob3cgdG8gY29ubmVjdCB0byBkYXRhYmFzZXMgaW4gUiB1c2luZwogICAgICAgICAgICAgICAgU1FMaXRlIGFzIGFuIGV4YW1wbGUuIFNob3dzIGhvdyB0byBjb25uZWN0LCBjcmVhdGUgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdGFibGVzLCBleGVjdXRlIFNRTCBxdWVyaWVzLCBtb2RpZnkgdGhlIGRhdGEsIGFuZCAKICAgICAgICAgICAgICAgIGVucXVpcmUgYWJvdXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YWJhc2UuIAogICAgICAgICAgICAgICAgRXhwbGFpbnMgUiBjb2RlIHZzIHtzcWx9IGNodW5rcyBhbmQgdGhlCiAgICAgICAgICAgICAgICBiZW5lZml0cyBvZiBsaXRlcmF0ZSBwcm9ncmFtbWluZy4gU2hvd3MgaG93IHRvCiAgICAgICAgICAgICAgICBzdW1tYXJpemUgZGF0YSBpbiBkYXRhIGZyYW1lcyB1c2luZyBTUUwgCiAgICAgICAgICAgICAgICB2aWEgc3FsZGYuIgpkYXRlOiAiPHNtYWxsPmByIFN5cy5EYXRlKClgPC9zbWFsbD4iCmF1dGhvcjogIjxzbWFsbD5NYXJ0aW4gU2NoZWRsYmF1ZXI8L3NtYWxsPiIKZW1haWw6ICJtLnNjaGVkbGJhdWVyQG5ldS5lZHUiCmFmZmlsaXRhdGlvbjogIk5vcnRoZWFzdGVybiBVbml2ZXJzaXR5IgpvdXRwdXQ6IAogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogc3BhY2VsYWIKICAgIGhpZ2hsaWdodDogdGFuZ28KLS0tCgotLS0KdGl0bGU6ICI8c21hbGw+YHIgcGFyYW1zJGNhdGVnb3J5YC5gciBwYXJhbXMkbnVtYmVyYDwvc21hbGw+PGJyLz48c3BhbiBzdHlsZT0nY29sb3I6ICMyRTQwNTM7IGZvbnQtc2l6ZTogMC45ZW0nPmByIHJtYXJrZG93bjo6bWV0YWRhdGEkdGl0bGVgPC9zcGFuPiIKLS0tCgpgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9faW5zZXJ0MkRCLlInKSksIGluY2x1ZGUgPSBGQUxTRX0KYGBgCgojIyBJbnRyb2R1Y3Rpb24KClIgcHJvZ3JhbXMgY2FuIGNvbm5lY3QgdG8gdmlydHVhbGx5IGFueSByZWxhdGlvbmFsIChhbmQgbWFueSBub24tcmVsYXRpb25hbCkgZGF0YWJhc2VzIGFzIHdlbGwgYXMgdGFidWxhciBkYXRhIGluIGZpbGVzLiBUaGlzIHR1dG9yaWFsIHByb3ZpZGVzIGFuIG92ZXJ2aWV3IG9mIHRoZSBkaWZmZXJlbnQgYXBwcm9hY2hlcyB0byB3b3JraW5nIHdpdGggZGF0YSBpbiBkYXRhYmFzZXMuCgojIyBDb25uZWN0IHRvIERhdGFiYXNlCgpUaGUgZmlyc3Qgc3RlcCBpcyB0byBjb25uZWN0IHRvIHRoZSBkYXRhYmFzZS4gVGhpcyByZXF1aXJlcyBhIHBhY2thZ2UgZm9yIHRoZSBkYXRhYmFzZSB0byB3aGljaCB5b3UgY29ubmVjdC4gSW4gdGhpcyB0dXRvcmlhbCB3ZSB3aWxsIGNvbm5lY3QgdG8gU1FMaXRlIHNvIHdlIG5lZWQgdGhlIGNvcnJlc3BvbmRpbmcgcGFja2FnZTogKipSU1FMaXRlKiouIE5hdHVyYWxseSwgYXMgd2l0aCBhbGwgcGFja2FnZXMgaW4gUiwgeW91IG11c3QgaW5zdGFsbCB0aGUgcGFja2FnZSBmaXJzdCBhbmQgdGhlbiBsb2FkIGl0IHdpdGggPGNvZGU+bGlicmFyeTwvY29kZT4uCgpXaXRoIFNRTGl0ZSwgaWYgeW91IGF0dGVtcHQgdG8gb3BlbiBhIGRhdGFiYXNlIHRoYXQgZG9lcyBub3QgZXhpc3QsIGl0IHdpbGwgYmUgY3JlYXRlZCBhcyBhIG5ldyBhbmQgZW1wdHkgZGF0YWJhc2UuIFRoaXMgaXMgbm90IHRydWUgZm9yIG90aGVyIGRhdGFiYXNlczogYW55IGNyZWF0aW9uIG11c3QgYmUgZG9uZSB0aHJvdWdoIGFkbWluIHRvb2xzLiBJbiB0aGUgY29kZSBiZWxvdywgd2UgY29ubmVjdCB0byBhbiBleGlzdGluZyBkYXRhYmFzZS4gSWYgeW91IGFyZSB3b3JraW5nIGluIGFuIFIgUHJvamVjdCwgdGhlIGRhdGFiYXNlIGZpbGUgd2lsbCBiZSBjcmVhdGVkIGluIHRoZSBwcm9qZWN0J3Mgcm9vdCBmb2xkZXIsIG90aGVyd2lzZSBpdCB3aWxsIGJlIGNyZWF0ZWQgaW4gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkgKHdoaWNoIGNvdWxkIGJlIGFueXdoZXJlLCBzbyBiZXN0IHRvIHdvcmsgaW4gYSBwcm9qZWN0KS4KCmBgYHtyfQpsaWJyYXJ5KFJTUUxpdGUpCgpkYmZpbGUgPSAiQ29mZmVlREIuc3FsaXRlZGIiCmNvbm4gPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCBkYmZpbGUpCmBgYAoKVGhlICoqUlNRTGl0ZSoqIHBhY2thZ2UgaGFzIGEgc21hbGwgc2V0IG9mIGRhdGFiYXNlIG1ldGEgZnVuY3Rpb25zIHRoYXQgYWxsb3cgdXMgdG8gZW5xdWlyZSBhYm91dCB0aGUgZGF0YWJhc2UgaXRzZWxmLiBGb3IgZXhhbXBsZSwgdGhlIGZ1bmN0aW9uIDxjb2RlPmRiTGlzdFRhYmxlczwvY29kZT4gbGlzdHMgYWxsIHRhYmxlcyBpbiB0aGUgZGF0YWJhc2UuIFRoZSBwYXJhbWV0ZXIgKmNvbm4qIGlzIHRoZSBkYXRhYmFzZSBjb25uZWN0aW9uIG9iamVjdCByZXR1cm5lZCBmcm9tIDxjb2RlPmRiQ29ubmVjdCgpPC9jb2RlPi4KCmBgYHtyIGxpc3RUYWJsZXNpbkRCfQpkYkxpc3RUYWJsZXMoY29ubikKYGBgCgpUbyBnZXQgdGhlIGxpc3Qgb2YgY29sdW1ucyBvZiBhIHNwZWNpZmljIHRhYmxlLCB5b3UgY2FuIHVzZSA8Y29kZT5kYkxpc3RGaWVsZHMoKTwvY29kZT4uCgpgYGB7ciBsaXN0RmllbGRzfQpkYkxpc3RGaWVsZHMoY29ubiwgImNvZmZlZXMiKQpgYGAKCiMjIyBTZXR0aW5nIERlZmF1bHQgQ29ubmVjdGlvbgoKSWYgb25seSBvbmUgU1FMaXRlIChvciBvdGhlcikgZGF0YWJhc2UgY29ubmVjdGlvbiBpcyB1c2VkIGZvciBTUUwgY29kZSBjaHVua3MsIHRoZW4gYSBkZWZhdWx0IGNvbm5lY3Rpb24gY2FuIGJldCBjb25maWd1cmVkIHdoaWNoIG1lYW5zIHRoYXQgdGhlIGNvbm5lY3Rpb25zIHN0cmluZyAqY29ubmVjdGlvbj1kYmNvbiogY2FuIGJlIG9taXR0ZWQuIFRoZSBSIGNvZGUgZnJhZ21lbnQgbXVzdCBiZSBpbmNsdWRlZCBhZnRlciB5b3UgbWFkZSBhIGNvbm5lY3Rpb24gdG8gdGhlIGRhdGFiYXNlLiBOYXR1cmFsbHksIHJlcGxhY2UgdGhlIGNvbm5lY3Rpb24gdmFyaWFibGUgKmRiY29uKiBiZWxvdyB3aXRoIHRoZSB2YXJpYWJsZSBmcm9tIHlvdXIgb3duIGNvZGUsICppLmUuKiwgdGhlIHZhcmlhYmxlIHRvIHdoaWNoIHlvdSBhc3NpZ25lZCB0aGUgcmV0dXJuIHZhbHVlIGZyb20gYGRiQ29ubmVjdCgpYC4KCmBgYHtyIGRlZmF1bHRDb25uU2V0dXAsIGV2YWw9Rn0KbGlicmFyeShEQkkpCmRiY29uIDwtIGRiQ29ubmVjdChSU1FMaXRlOjpTUUxpdGUoKSwgZGJuYW1lID0gInNxbC5zcWxpdGUiKQprbml0cjo6b3B0c19jaHVuayRzZXQoY29ubmVjdGlvbiA9ICJkYmNvbiIpCmBgYAoKIyMgRXhlY3V0ZSBTUUwgUXVlcnkKClRoZXJlIGFyZSB0d28gY29tbW9uIHdheXMgdG8gcnVuIGEgU1FMIHF1ZXJ5IGFnYWluc3QgYSBkYXRhYmFzZS4gVGhlIGFwcHJvYWNoZXMgYXJlIHRoZSBzYW1lIGZvciBhbGwgZGF0YWJhc2VzIGFuZCBhcmUgbm90IGV4Y2x1c2l2ZSB0byBTUUxpdGUuCgoxLiAgRW1iZWQgdGhlIFNRTCBzdGF0ZW1lbnQgaW4gYSA8Y29kZT57c3FsfTwvY29kZT4gY2h1bmsuCjIuICBTZW5kIHRoZSBxdWVyeSB2aWEgYW4gUiBmdW5jdGlvbiAoPGNvZGU+ZGJHZXRRdWVyeSgpPC9jb2RlPiBhbmQgPGNvZGU+ZGJTZW5kUXVlcnkoKTwvY29kZT4pLgoKQW55IGVtYmVkZGVkIFNRTCBjb2RlIGluIGEgPGNvZGU+e3NxbH08L2NvZGU+IGNodW5rIGlzIHRyYW5zbGF0ZWQgdG8gYSA8Y29kZT5kYlNlbmRTdGF0ZW1lbnQoKTwvY29kZT4gY2FsbCBkdXJpbmcga25pdHRpbmcuIFNvLCB0aGVyZSdzIG5vIHBlcmZvcm1hbmNlIGRpZmZlcmVuY2UgYW5kIHdoaWNoIHRvIHVzZSBpcyBhIG1hdHRlciBvZiBwcmVmZXJlbmNlLiBVc2luZyBhIDxjb2RlPntzcWx9PC9jb2RlPiBjaHVuayBtYWtlcyBkYXRhYmFzZSBjb2RlIG1vcmUgZXhwbGljaXQgYW5kIGNvbmZvcm1zIHRvIHRoZSBwcmluY2lwbGVzIG9mIFtsaXRlcmF0ZSBwcm9ncmFtbWluZ10oaHR0cDovL3d3dy5saXRlcmF0ZXByb2dyYW1taW5nLmNvbSkuCgo8Y29kZT5kYkdldFF1ZXJ5KCk8L2NvZGU+IGFuZCA8Y29kZT5kYlNlbmRRdWVyeSgpPC9jb2RlPiBhcmUgdXNlZCB0byBzZW5kIFNFTEVDVCBzdGF0ZW1lbnRzLCB3aGlsZSA8Y29kZT5kYlNlbmRTdGF0ZW1lbnQoKTwvY29kZT4gaXMgdXNlZCBmb3IgSU5TRVJULCBVUERBVEUsIERFTEVURSwgQ1JFQVRFIFRBQkxFLCBhbmQgYW55IG90aGVyIFNRbCBzdGF0ZW1lbnQuCgpJZiB5b3UgbmVlZCB0byB3cml0ZSBhbiBSIHNjcmlwdCAocmF0aGVyIHRoYW4gYW4gUiBOb3RlYm9vaykgdGhlbiB5b3UgbXVzdCB1c2UgdGhlIFIgZnVuY3Rpb25zIGFuZCBjYW5ub3QgdXNlIDxjb2RlPntzcWx9PC9jb2RlPiBjaHVua3MuCgojIyMgU2ltcGxlIEVtYmVkZGVkIFF1ZXJ5OiB7c3FsfSBDb2RlIENodW5rcwoKVGhlIDxjb2RlPntzcWx9PC9jb2RlPiBjaHVuayByZXF1aXJlcyBzcGVjaWZ5aW5nIHRoZSBjb25uZWN0aW9uIHRvIHRoZSBkYXRhYmFzZSB0byB3aGljaCB0aGUgU1FMIHF1ZXJ5IHNob3VsZCBiZSBzZW5kIGluIHRoZSAqY29ubmVjdGlvbiogcGFyYW1ldGVyLiBUaGlzIGlzIHRoZSByZXR1cm4gdmFsdWUgZnJvbSA8Y29kZT5kYkNvbm5lY3QoKTwvY29kZT4uCgpUaGUgZ2VuZXJpYyBzdHJ1Y3R1cmUgb2YgYSA8Y29kZT57c3FsfTwvY29kZT4gY2h1bmsgaXMgZGVmaW5lZCBiZWxvdy4gQSBTUUwgc3RhdGVtZW50IGNhbiBiZSBhIFNFTEVDVCwgSU5TRVJULCBVUERBVEUsIERFTEVURSwgQUxURVIsIENSRUFURSwgb3IgYW55IG90aGVyIHZhbGlkIFNRTCBzdGF0ZW1lbnQuCgohW10oaW1hZ2VzL3NxbC1jaHVuay5qcGcpe3dpZHRoPSI3NSUifQoKVGhlIHJlc3VsdCBvZiB0aGUgYWJvdmUgU1FMIHF1ZXJ5IGlzIHNob3duIGJlbG93LgoKYGBge3NxbCBzaW1wbGVTUUxDaHVuaywgY29ubmVjdGlvbj1jb25ufQpzZWxlY3QgY29mZmVlX25hbWUgYXMgY29mZmVlLCBwcmljZQogIGZyb20gY29mZmVlcwogd2hlcmUgcHJpY2UgPiA4OwpgYGAKCj4gWW91IGNhbiBvbmx5IHBsYWNlIG9uZSBTUUwgc3RhdGVtZW50IGludG8gYSA8Y29kZT57c3FsfTwvY29kZT4gY2h1bmsgYW5kIHRodXMgdGhlIHNlbWktY29sb24gYXQgdGhlIGVuZCBvZiBzdGF0ZW1lbnQgaXMgb3B0aW9uYWwuCgojIyMjIFNRTCBDaHVuayBQYXJhbWV0ZXJzCgpUaGUgbGlzdCBiZWxvdyBhcmUgdGhlIG1vc3QgY29tbW9uIHBhcmFtZXRlcnMgZm9yIGEgPGNvZGU+e3NxbH08L2NvZGU+IGNodW5rLCBhbHRob3VnaCB0aGUgbGlzdCBpcyBub3QgZXhoYXVzdGl2ZSBhbmQgdGhlcmUgYXJlIG90aGVycy4KCi0gICAqKmNvbm5lY3Rpb24qKiAtLSBhIGNvbm5lY3Rpb24gb2JqZWN0IHRvIHRoZSBkYXRhYmFzZSB0byB3aGljaCB0aGUgU1FMIHN0YXRlbWVudCB3aWxsIGJlIHNlbnQgZm9yIGV4ZWN1dGlvbjsgZ2VuZXJhbGx5IHRoZSByZXR1cm4gdmFsdWUgZnJvbSA8Y29kZT5kYkNvbm5lY3QoKTwvY29kZT4KCi0gICAqKmV2YWwqKiAtLSBpZiAqVFJVRSosIHRoZW4gdGhlIFNRTCBjb2RlIGlzIGV4ZWN1dGVkOyBpZiAqRkFMU0UqLCB0aGVuIHRoZSBjb2RlIGlzIG5vdCBleGVjdXRlZAoKLSAgICoqZWNobyoqIC0tIGlmIHNldCB0byAqVFJVRSosIHRoZW4gdGhlIFNRTCBjb2RlIGlzIGluY2x1ZGVkIGluIGFueSBrbml0dGVkIGZpbGU7IGlmICpGQUxTRSogdGhlbiB0aGUgY29kZSBpbiB0aGUgY2h1bmsgaXMgbm90IGluIHRoZSBrbml0dGVkIG91dHB1dAoKLSAgICoqb3V0cHV0LnZhcioqIC0tIHRoZSBuYW1lIG9mIGEgZGF0YSBmcmFtZSB2YXJpYWJsZSBpbiB3aGljaCB0aGUgb3V0cHV0IHJlc3VsdCB3aWxsIGJlIHN0b3JlZCBhbmQgY2FuIGJlIHVzZWQgaXMgc3Vic2VxdWVudCBSIGNvZGUgY2h1bmtzOyB0aGUgdmFyaWFibGUgbXVzdCBiZSBpbiBxdW90ZXMKCiMjIyBDYXB0dXJlIFF1ZXJ5IFJlc3VsdAoKRXZlcnkgU1FMIFNFTEVDVCBxdWVyeSByZXR1cm5zIGEgdGFibGUuIEluIFIsIHRoZSByZXR1cm5lZCB0YWJsZSBpcyB0cmFuc2Zvcm1lZCB0byBhIGRhdGEgZnJhbWUuIFRoaXMgZGF0YSBmcmFtZSBjYW4gYmUgYXNzaWduZWQgdG8gYSB2YXJpYWJsZSBmb3IgZnVydGhlciBwcm9jZXNzaW5nLiBGb3IgYSA8Y29kZT57c3FsfTwvY29kZT4gY2h1bmsgeW91IHNwZWNpZnkgdGhlIGRhdGEgZnJhbWUgdG8gd2hpY2ggdGhlIHJlc3VsdCBzZXQgaXMgc2F2ZWQgdXNpbmcgdGhlICpvdXRwdXQudmFyKiBwYXJhbWV0ZXI6Cgo8Y29kZT57c3FsIHNpbXBsZVNRTHdpdGhSZXN1bHQsIGNvbm5lY3Rpb24gPSBjb25uLCBvdXRwdXQudmFyID0gJ3JzJ308L2NvZGU+LgoKTm90ZSB0aGF0IHRoZSBvdXRwdXQgZGF0YSBmcmFtZSBtdXN0IGJlIGluIHF1b3Rlcy4KCiFbXShpbWFnZXMvc3FsLWNodW5rLTIuanBnKXt3aWR0aD0iNzUlIn0KCmBgYHtzcWwgc2ltcGxlU1FMd2l0aFJlc3VsdCwgY29ubmVjdGlvbiA9IGNvbm4sIG91dHB1dC52YXIgPSAicnMiLCBpbmNsdWRlPUZ9CnNlbGVjdCBjb2ZmZWVfbmFtZSBhcyBjb2ZmZWUsIHByaWNlCiAgZnJvbSBjb2ZmZWVzCiB3aGVyZSBwcmljZSA+IDg7CmBgYAoKV2UgY2FuIG5vdyB1c2UgdGhlIHJlc3VsdCBpbiBSLiBTbywgaW4gdGhlIGV4YW1wbGUgYmVsb3cgd2UgY2FsY3VsYXRlIHRoZSBhdmVyYWdlIHByaWNlIG9mIGNvZmZlZS4KCmBgYHtyIHVzZVJlc3VsdH0KbWVhbi5Db2ZmZWUuUHJpY2UgPC0gbWVhbihycyRwcmljZSkKCnByaW50KHBhc3RlMCgiQXZlcmFnZSBwcmljZSBvZiBjb2ZmZWU6ICQiLCByb3VuZChtZWFuLkNvZmZlZS5QcmljZSwgMikpKQpgYGAKCiMjIyBFbWJlZGRlZCBRdWVyaWVzIHdpdGggUGFyYW1ldGVycwoKT2Z0ZW4sIHdlIG5lZWQgdG8gZXhlY3V0ZSBhIFNRTCBxdWVyeSBidXQgdXNlIGEgcGFyYW1ldGVyIGZyb20gUi4gVGhlIGNvZGUgYmVsb3cgZGVtb25zdHJhdGVzIGhvdyB0byAicGFzcyBhIHZhcmlhYmxlIiB0byBhIDxjb2RlPntzcWx9PC9jb2RlPiBjaHVuayBhbmQgaG93IHRvIHVzZSB0aGUgcGFyYW1ldGVyIGluIHRoZSBjaHVuay4KCkZpcnN0LCBoZXJlIGlzIGFuIFIgY29kZSBjaHVuayB0aGF0IGRlZmluZXMgYSB2YXJpYWJsZSBjYWxsZWQgKnRoZVByaWNlKiBhbmQgc2V0cyBpdCB0byB0aGUgdmFsdWUgKjgqLgoKYGBge3J9CnRoZVByaWNlIDwtIDgKYGBgCgpJbiB0aGUgU1FMIGNvZGUgY2h1bmsgYmVsb3csIHdlIHJlZmVyIHRvIHRoZSB2YWx1ZSBvZiB0aGF0IHZhcmlhYmxlIHVzaW5nIHRoZSBzeW50YXggKj9SVmFyaWFibGUqLiBTbywgdGhlICo/dGhlUHJpY2UqIGlzIHN1YnN0aXR1dGVkIHdpdGggdGhlIHZhbHVlIG9mIHRoZSBSIHZhcmlhYmxlICp0aGVQcmljZSouCgpgYGB7c3FsIGNodW5rV2l0aFBhcmFtLCBjb25uZWN0aW9uPWNvbm4sIG91dHB1dC52YXI9ImV4cENvZmZlZXMifQpzZWxlY3QgKiBmcm9tIGNvZmZlZXMgd2hlcmUgcHJpY2UgPiA/dGhlUHJpY2UgCmBgYAoKU28sIHRoZSBhY3R1YWwgU1FMIHF1ZXJ5IHRoYXQgaXMgc2VudCB0byB0aGUgZGF0YWJhc2UgaXM6IGBzZWxlY3QgKiBmcm9tIGNvZmZlZXMgd2hlcmUgcHJpY2UgPiA4YC4KClRvIHZlcmlmeSwgaGVyZSBpcyB0aGUgcmVzdWx0IG9mIHRoZSBxdWVyeSAod2UgdXNlZCB0aGUgKm91dHB1dC52YXI9ImV4cENvZmZlZXMiKiBwYXJhbWV0ZXIgaW4gdGhlIFNRTCBjb2RlIGNodW5rKToKCmBgYHtyfQpoZWFkKGV4cENvZmZlZXMsNCkKYGBgCgpBcyBhbiBhbHRlcm5hdGl2ZSwgd2UgY291bGQgaGF2ZSBleGVjdXRlZCB0aGUgcXVlcnkgZnVsbHkgaW4gYW4gUiBjb2RlIGNodW5rIHVzaW5nIHRoZSBmdW5jdGlvbiAqZGJHZXRRdWVyeSgpKiB3aGljaCByZXR1cm5zIHRoZSByZXN1bHQgYXMgYSBkYXRhIGZyYW1lLiBJbiB0aGlzIGV4YW1wbGUsIHRoZSBwYXJhbWV0ZXIgaXMgcGFzc2VkIHRvIHRoZSBTUUwgcXVlcnkgdGhyb3VnaCBzdHJpbmcgY29uY2F0ZW5hdGlvbi4KCmBgYHtyfQpwIDwtIDgKc3FsIDwtIHBhc3RlMCgic2VsZWN0ICogZnJvbSBjb2ZmZWVzIHdoZXJlIHByaWNlID4gIiwgcCkKZGYgPC0gZGJHZXRRdWVyeShjb25uLCBzcWwpCmBgYAoKIyMjIFF1ZXJ5aW5nIHZpYSBSIENvZGUKClJhdGhlciB0aGFuIGVtYmVkZGluZyB0aGUgU1FMIHF1ZXJ5IGluIGEgPGNvZGU+e3NxbH08L2NvZGU+IGNodW5rLCBpdCBvZnRlbiBtb3JlIGNvbnZlbmllbnQsIHNpbXBsZXIsIG9yIG5lY2Vzc2FyeSB0byBleGVjdXRlIHRoZSBxdWVyeSB3aXRoaW4gYW4gUiBjb2RlIGJsb2NrLiBUaGVyZSBpcyBubyBwZXJmb3JtYW5jZSBkaWZmZXJlbmNlLgoKVGhlcmUgYXJlIHR3byBSIGZ1bmN0aW9ucyB5b3UgY2FuIGNob29zZSBmcm9tOiA8Y29kZT5kYkdldFF1ZXJ5KCk8L2NvZGU+IGFuZCA8Y29kZT5kYlNlbmRRdWVyeSgpPC9jb2RlPi4KClRvIGV4ZWN1dGUgYSBxdWVyeSB3aXRoaW4gUiBjb2RlLCB5b3UgbmVlZCB0byBjb25uZWN0IHRvIHRoZSBkYXRhYmFzZSwgZGVmaW5lIHRoZSBTUUwgcXVlcnkgYXMgYSBzdHJpbmcsIHJ1biB0aGUgcXVlcnksIGFuZCB0aGVuIGluc3BlY3QgdGhlIHJlc3VsdCBzZXQuIFRoZSByZXN1bHQgc2V0IGlzIGEgZGF0YSBmcmFtZS4gT2YgY291cnNlLCB5b3Ugb25seSBuZWVkIHRvIGNvbm5lY3QgdG8gdGhlIGRhdGFiYXNlIG9uY2UgYW5kIG5vdCBldmVyeSB0aW1lIGJlZm9yZSBhIHF1ZXJ5LiBJbiB0aGUgZXhhbXBsZSBiZWxvdywgd2UgdXNlIHRoZSBzYW1lIGRhdGFiYXNlIGNvbm5lY3Rpb24gZnJvbSBhYm92ZS4KCmBgYHtyIGV4ZWNTUUxRdWVyeX0Kc3FsIDwtICJzZWxlY3QgY29mZmVlX25hbWUgYXMgY29mZmVlLCBwcmljZQogICAgICAgIGZyb20gY29mZmVlcwogICAgICAgIHdoZXJlIHByaWNlID4gODsiCgpycyA8LSBkYkdldFF1ZXJ5KGNvbm4sIHNxbCkKCnByaW50KHJzKQpgYGAKCk5vdGUgdGhhdCB0aGUgc2VtaS1jb2xvbiBhdCB0aGUgZW5kIG9mIHRoZSBxdWVyeSBpcyBvcHRpb25hbCBhcyB5b3UgY2FuIG9ubHkgc2VuZCBhIHNpbmdsZSBxdWVyeS4gVGhlIHN5bnRheCBvZiB0aGUgcXVlcnkgZGVwZW5kcyBvbiB0aGUgZGF0YWJhc2UgLS0gaXQgaXMgbm90IGludGVycHJldGVkIGJ5IFIgYnV0IHJhdGhlciBieSB0aGUgZGF0YWJhc2UuIEZvciBleGFtcGxlLCBNeVNRTCByZWNvZ25pemVzIENSRUFURSBTQ0hFTUEgYXMgYSBTUUwgc3RhdGVtZW50LCBidXQgU1FMaXRlIGRvZXMgbm90LgoKSWYgeW91IG5lZWRlZCB0byBhZGQgYSBwYXJhbWV0ZXIsIHRoZW4geW91IGNhbiB1c2UgPGNvZGU+cGFzdGUwKCk8L2NvZGU+IHRvIGdlbmVyYXRlIHRoZSBTUUwgcXVlcnkgc3RyaW5nLgoKYGBge3IgZXhlY1NRTFF1ZXJ5V2l0aFBhcmFtfQpwIDwtIDkKCnNxbCA8LSAic2VsZWN0IGNvZmZlZV9uYW1lIGFzIGNvZmZlZSwgcHJpY2UKICAgICAgICBmcm9tIGNvZmZlZXMKICAgICAgICB3aGVyZSBwcmljZSA+ICIKc3FsIDwtIHBhc3RlMChzcWwsIHApCgpycyA8LSBkYkdldFF1ZXJ5KGNvbm4sIHNxbCkKCnByaW50KHJzKQpgYGAKCkFsdGVybmF0aXZlbHksIHlvdSBjYW4gdXNlIDxjb2RlPmRiU2VuZFF1ZXJ5KCk8L2NvZGU+LCB3aGljaCBhbGxvd3MgeW91IHRvIGFkZCBwYXJhbWV0ZXJzIHRvIHRoZSBxdWVyeS4gTm90ZSB0aGF0IDxjb2RlPmRiU2VuZFF1ZXJ5KCk8L2NvZGU+IGV4ZWN1dGVzIHRoZSBxdWVyeSBidXQgZG9lcyBub3QgcmV0dXJuIGEgcmVzdWx0LiBGb3IgdGhhdCB5b3Ugd2lsbCBuZWVkIHRvIGV4cGxpY2l0bHkgY2FsbCA8Y29kZT5kYkZldGNoKCk8L2NvZGU+CgpgYGB7ciBleGVjU1FMUXVlcnkyfQpwIDwtIDkKCnNxbCA8LSAic2VsZWN0IGNvZmZlZV9uYW1lIGFzIGNvZmZlZSwgcHJpY2UKICAgICAgICBmcm9tIGNvZmZlZXMKICAgICAgICB3aGVyZSBwcmljZSA+ICIKc3FsIDwtIHBhc3RlMChzcWwsIHApCgpycyA8LSBkYlNlbmRRdWVyeShjb25uLCBzcWwpCgpkYkZldGNoKHJzKQoKcHJpbnQocnMpCmBgYAoKUmF0aGVyIHRoYW4gbWFuaXB1bGF0aW5nIHRoZSBxdWVyeSBzdHJpbmcsIHlvdSBjYW4gYWRkIHBhcmFtZXRlcnMgdG8gdGhlIHF1ZXJ5LiBUaGUgcGFyYW1ldGVycyBhcmUgbWFya2VkIHdpdGggPyBpbiB0aGUgU1FMIHF1ZXJ5IHN0cmluZyBhbmQgYXJlIHRoZW4gYm91bmQgdG8gYWN0dWFsIHZhbHVlcyAoaW4gb3JkZXIpIHdpdGggYSBsaXN0IHBhc3NlZCB0byB0aGUgcGFyYW1ldGVyICpwYXJhbXMqLgoKYGBge3IgZXhlY1NRTFF1ZXJ5V2l0aFBhcmFtc30KbWluUCA8LSA4Cm1heFAgPC0gMTIKCnNxbCA8LSAic2VsZWN0IGNvZmZlZV9uYW1lIGFzIGNvZmZlZSwgcHJpY2UKICAgICAgICBmcm9tIGNvZmZlZXMKICAgICAgICB3aGVyZSBwcmljZSBiZXR3ZWVuID8gYW5kID8iCgpycyA8LSBkYlNlbmRRdWVyeShjb25uLCBzcWwsIHBhcmFtcyA9IGxpc3QobWluUCwgbWF4UCkpCgpkYkZldGNoKHJzKQoKcHJpbnQocnMpCmBgYAoKIyMjIFJlYWRpbmcgRW50aXJlIFRhYmxlcwoKVGhlIGNvbnZlbmllbmNlIGZ1bmN0aW9uIDxjb2RlPmRiUmVhZFRhYmxlPC9jb2RlPiByZWFkcyBhbiBlbnRpcmUgdGFibGUgaW50byBhIGRhdGEgZnJhbWUuIEl0IGlzIGVxdWl2YWxlbnQgdG8gdGhlIHF1ZXJ5ICpTRUxFQ1QgXCogRlJPTSB0YWJsZSouCgpgYGB7ciByZWFkRnVsbFRhYmxlfQpycyA8LSBkYlJlYWRUYWJsZShjb25uLCAiY29mZmVlcyIpCgpoZWFkKHJzLCAzKQpgYGAKCiMjIyBXcml0aW5nIEVudGlyZSBEYXRhIEZyYW1lcwoKVGhlIGNvbnZlbmllbmNlIGZ1bmN0aW9uIDxjb2RlPmRiV3JpdGVUYWJsZTwvY29kZT4gd3JpdGVzIGFuIGVudGlyZSBkYXRhIGZyYW1lIHRvIGEgdGFibGUuIFRoZXJlIGFyZSB0d28gaW1wb3J0YW50IHBhcmFtZXRlcnMgZm9yIHRoZSBmdW5jdGlvbjogKm92ZXJ3cml0ZSogYW5kICphcHBlbmQqLiBCeSBkZWZhdWx0LCBib3RoIGFyZSAqRkFMU0UqIHdoaWNoIG1lYW5zIHRoYXQgPGNvZGU+ZGJXcml0ZVRhYmxlPC9jb2RlPiBjYW4gb25seSBiZSB1c2VkIHRvIHdyaXRlIGEgZGF0YSBmcmFtZSB0byBhIG5ldyB0YWJsZSAoKmkuZS4qLCBvbmUgdGhhdCBkb2VzIG5vdCBleGlzdCBpbiB0aGUgZGF0YWJhc2UpLiBUbyBhZGQgcm93cyB0byBhbiBleGlzdGluZyB0YWJsZSByZXF1aXJlcyAqYXBwZW5kID0gVCouCgpgYGB7ciB3cml0ZUZ1bGxUYWJsZX0KcnMgPC0gZGJSZWFkVGFibGUoY29ubiwgImNvZmZlZXMiKQoKIyBsZXQncyB3cml0ZSBhbGwgb2YgdGhlIGRhdGEgdG8gYW4gYXJjaGl2ZSB0YWJsZSwgYnV0IGxldCdzIGRlbGV0ZSB0aGUgb2xkCiMgdGFibGUgZmlyc3QKZGJSZW1vdmVUYWJsZShjb25uLCAiYXJ4X2NvZmZlZXMiLCBmYWlsX2lmX21pc3NpbmcgPSBGKQpkYldyaXRlVGFibGUoY29ubiwgImFyeF9jb2ZmZWVzIiwgcnMsIGFwcGVuZCA9IFQpCgojIGFuZCByZWFkIGl0IGJhY2sgdG8gc2VlIGlmIGl0IHdvcmtlZApycyA8LSBkYlJlYWRUYWJsZShjb25uLCAiYXJ4X2NvZmZlZXMiKQoKdGFpbChycywgMykKYGBgCgojIyMgQ29tcGxldGUgRXhhbXBsZQoKVGhlIGNvZGUgYmVsb3cgc2hvd3MgdGhlIGNvbXBsZXRlIHNlcXVlbmNlIG9mIGNvbm5lY3QgdG8sIGNyZWF0aW5nLCBpbnNlcnRpbmcsIGFuZCBxdWVyeWluZyBhIFNRTGl0ZSBkYXRhYmFzZSBmcm9tIGFuIFIgcHJvZ3JhbSAoW2Rvd25sb2FkIHNjcmlwdF0oY3JlYXRlU1FMaXRlREJmcm9tUi5SKSk6CgpgYGB7ciByZW1EQiwgZWNobz1GfQp1bmxpbmsoInNhbXBsZS5kYiIpCmBgYAoKYGBge3IgY29tcGxldGVFeGFtcGxlLCBlY2hvPVQsIG1lc3NhZ2U9Rn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJ5CmxpYnJhcnkoUlNRTGl0ZSkKCiMgQ3JlYXRlIGEgbmV3IFNRTGl0ZSBkYXRhYmFzZQpkYiA8LSBkYkNvbm5lY3QoU1FMaXRlKCksIGRibmFtZSA9ICJzYW1wbGUuZGIiKQoKIyBDcmVhdGUgYSB0YWJsZSBuYW1lZCAnY3VzdG9tZXJzJwpkYkV4ZWN1dGUoZGIsICIKICBDUkVBVEUgVEFCTEUgY3VzdG9tZXJzICgKICAgIGNpZCBJTlRFR0VSIFBSSU1BUlkgS0VZLAogICAgbmFtZSBURVhULAogICAgZW1haWwgVEVYVAogICkKIikKCiMgSW5zZXJ0IDMgcm93cyBvZiBzeW50aGV0aWMgZGF0YSBpbnRvIHRoZSAnY3VzdG9tZXJzJyB0YWJsZQpzIDwtIGRiRXhlY3V0ZShkYiwgIklOU0VSVCBJTlRPIGN1c3RvbWVycyAoY2lkLCBuYW1lLCBlbWFpbCkgVkFMVUVTICgxLCAnQWxpY2UnLCAnYWxpY2VAZXhhbXBsZS5jb20nKSIpCnMgPC0gZGJFeGVjdXRlKGRiLCAiSU5TRVJUIElOVE8gY3VzdG9tZXJzIChjaWQsIG5hbWUsIGVtYWlsKSBWQUxVRVMgKDIsICdCb2InLCAnYm9iQGV4YW1wbGUuY29tJykiKQpzIDwtIGRiRXhlY3V0ZShkYiwgIklOU0VSVCBJTlRPIGN1c3RvbWVycyAoY2lkLCBuYW1lLCBlbWFpbCkgVkFMVUVTICgzLCAnQ2hhcmxpZScsICdjaGFybGllQGV4YW1wbGUuY29tJykiKQoKIyBSZXRyaWV2ZSBhbGwgcm93cyBpbiB0aGUgJ2N1c3RvbWVycycgdGFibGUgYW5kIGRpc3BsYXkgdGhlbQpjdXN0b21lcnMgPC0gZGJHZXRRdWVyeShkYiwgIlNFTEVDVCAqIEZST00gY3VzdG9tZXJzIikKcHJpbnQoY3VzdG9tZXJzKQoKIyBDbG9zZSB0aGUgY29ubmVjdGlvbiB0byB0aGUgZGF0YWJhc2UKZGJEaXNjb25uZWN0KGRiKQoKYGBgCgpUaGUgcmV0dXJuIHZhbHVlIG9mIGBkYkV4ZWN1dGUoKWAgaXMgYWx3YXlzIHRoZSBudW1iZXIgb2Ygcm93cyBhZmZlY3RlZC4gU28sIGlmIHRoZSByZXR1cm4gdmFsdWUgaXMgMCBpdCBtZWFucyB0aGF0IHRoZSBTUUwgc3RhdGVtZW50IGZhaWxlZC4gQ29uc2VxdWVudGx5LCBpdCBpcyBhbHdheXMgYSBnb29kIGlkZWEgdG8gY2hlY2sgdGhlIHJldHVybiB2YWx1ZSBvZiBgZGJFeGVjdXRlKClgIGFuZCBgZGJTZW5kU3RhdGVtZW50KClgLgoKIyMjIE90aGVyIENvbnZlbmllbmNlIEZ1bmN0aW9ucwoKSW4gYWRkaXRpb24gdG8gdGhlIGNvbnZlbmllbmNlIGZ1bmN0aW9ucyBtZW50aW9uZWQgYWJvdmUsIHlvdSBhbHNvIGhhdmUgdGhlIG9uZXMgYmVsb3csIGFtb25nIG90aGVyczoKCi0gICA8Y29kZT5kYkFwcGVuZFRhYmxlKCk8L2NvZGU+Ci0gICA8Y29kZT5kYkNyZWF0ZVRhYmxlKCk8L2NvZGU+Ci0gICA8Y29kZT5kYlJlbW92ZVRhYmxlKCk8L2NvZGU+CgojIyBRdWVyeWluZyBEYXRhIEZyYW1lcyB3aXRoICoqc3FsZGYqKgoKKipzcWxkZioqIGlzIGEgcGFja2FnZSB0aGF0IGFsbG93cyBkYXRhIGZyYW1lcyB0byBiZSBxdWVyaWVkIHdpdGggU1FMIGFzIGlmIHRoZXkgd2VyZSB0YWJsZXMgaW4gYSBkYXRhYmFzZS4gTWFueSBxdWVyaWVzLCB3aGlsZSBnZW5lcmFsbHkgZG9hYmxlIGluIEJhc2UgUiBvciB3aXRoICoqdGlkeXZlcnNlKiosIGFyZSBvZnRlbiBzaW1wbGVyIHdpdGggYSBTUUwgcXVlcnkgLS0gYWxiZWl0IGEgYml0IHNsb3dlciwgYnV0IHRoYXQgcmVkdWN0aW9uIGluIHBlcmZvcm1hbmNlIGlzIG9mdGVuIG5vdCBwZXJjZXB0aWJsZS4gSG93ZXZlciwgd2hlbiB0aGUgZGF0YSBmcmFtZSBpcyBsYXJnZSwgYmFzZSBSIGZ1bmN0aW9ucyBhcmUgbXVjaCBmYXN0ZXIgYXMgKipzcWxkZioqIGFjdHVhbGx5IHdvcmtzIGJ5IGNvcHlpbmcgdGhlIGRhdGEgZnJhbWUgdG8gYSB0ZW1wb3JhcnkgaW4tbWVtb3J5IFNRTGl0ZSBkYXRhYmFzZSBhbmQgcnVucyBhIFNRTCBxdWVyeSBvbiB0aGF0IHRhYmxlIGluIHRoZSBkYXRhYmFzZSAtLSB0aGF0IGNhbiBiZSBzbG93LiBVc2UgKipzcWxkZioqIHByaW1hcmlseSBmb3IgZ3JvdXBpbmcgYW5kIGV4dHJhY3RpbmcgdW5pcXVlIHZhbHVlcyAtLSB1c2UgYHdoaWNoKClgIGFuZCBgYW55KClgIGFzIHdlbGwgYXMgbG9naWNhbCB2ZWN0b3Igb3BlcmF0aW9ucyBvdGhlcndpc2UuCgpXZSB3aWxsIGRlbW9uc3RyYXRlIHRoZSB1c2Ugb2YgKipzcWxkZioqIGJ5IHF1ZXJ5aW5nIHRoZSBkYXRhIGluIGEgbGFyZ2UgQ1NWIGZpbGUuIFRoZSBmaWxlIGlzIGxvYWRlZCBpbnRvIGEgZGF0YSBmcmFtZSBhbmQgdGhlbiB0cmVhdGVkIGFzIGlmIGl0IHdlcmUgYSB0YWJsZSBpbiBhIGRhdGFiYXNlLgoKYGBge3IgbG9hZENTVn0KdHhucyA8LSByZWFkLmNzdigiY3VzdG9tZXJ0eG5kYXRhLmNzdiIsIAogICAgICAgICAgICAgICBoZWFkZXIgPSBGLCAKICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygidmlzaXRzIiwibnVtdHhucyIsIm9zIiwiZ2VuZGVyIiwidG90YWwiKSkKYGBgCgpUaGUgQ1NWIGZpbGUgY29udGFpbnMgZGF0YSBvbiB2aXNpdHMgdG8gYW4gZS1jb21tZXJjZSBzaXRlLgoKYGBge3IsIGV2YWw9VH0KaGVhZCh0eG5zLCA0KQpgYGAKCiMjIyBFeGVjdXRlICoqc3FsZGYqKiBTUUwgUXVlcnkKCioqc3FsZGYqKiBleGVjdXRlcyBhIFNRTCBxdWVyeSBhZ2FpbnN0IGFuIGluLW1lbW9yeSBkYXRhIGZyYW1lIGFuZCByZXR1cm5zIHRoZSBxdWVyeSByZXN1bHQgYXMgYSBkYXRhIGZyYW1lLiBUaGUgZGF0YSBmcmFtZSBjYW4gYmUgY2FwdHVyZWQgYW5kIHRoZW4gcHJvY2Vzc2VkIGZ1cnRoZXIgd2l0aCAqKnNxbGRmKiogb3IgUi4KCmBgYHtyIGluc3RhbGxzcWxkZiwgZWNobz1GLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KI2luc3RhbGwucGFja2FnZXMoInNxbGRmIikKYGBgCgpgYGB7ciB3YXJuaW5nPUYsbWVzc2FnZT1GfQpsaWJyYXJ5KHNxbGRmKQoKc3FscSA8LSAic2VsZWN0IGdlbmRlciwgc3VtKHRvdGFsKSBhcyB0b3RhbCBmcm9tIGB0eG5zYCBncm91cCBieSBnZW5kZXIiCmRmIDwtIHNxbGRmKHNxbHEpCgpoZWFkKGRmLCAzKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHNxbGRmKQoKIyBpbWFnaW5lIHlvdSBuZWVkIHRvIGFzayB1c2VyIGZvciBPUywgcGVyaGFwcyBieSBjaG9vc2luZyBmcm9tIGEgbWVudQp0aGVPUyA8LSAiJyBhbmQgMT0xIG9yIGdlbmRlciA8PiciCgpzcWxxIDwtIHBhc3RlMCgic2VsZWN0IGdlbmRlciwgc3VtKHRvdGFsKSBhcyB0b3RhbCBmcm9tIGB0eG5zYCB3aGVyZSBvcz0nIiwKICAgICAgICAgICAgICAgIHRoZU9TLCAiJyBncm91cCBieSBnZW5kZXIiKQpkZiA8LSBzcWxkZihzcWxxKQoKaGVhZChkZiwgNCkKYGBgCgo+IEEgcG90ZW50aWFsIGlzc3VlIHdpdGggKipzcWxkZioqIGNhbiBvY2N1ciB3aGVuIHlvdSBjb25uZWN0IHRvIE15U1FMIG9yIGEgbm9uLVNRTGl0ZSBkYXRhYmFzZSBhcyAqKnNxbGRmKiogYXR0ZW1wdHMgdG8gdXNlIHlvdXIgZXhpc3RpbmcgZGF0YWJhc2UgY29ubmVjdGlvbiBhcyBhIGJhY2tpbmcgc3RvcmUgZm9yIGl0cyBkYXRhOyB0aGlzIHdpbGwgb2Z0ZW4gbm90IHdvcmsgZHVlIHRvIHNlY3VyaXR5IGNvbnN0cmFpbnRzLiBTbywgeW91IG5lZWQgdG8gYWRkIHRoZSBSIGNvZGUgPGNvZGU+b3B0aW9ucyhzcWxkZi5kcml2ZXIgPSAnU1FMaXRlJyk8L2NvZGU+IHdoaWNoIGZvcmNlcyAqKnNxbGRmKiogdG8gdXNlIFNRTGl0ZSBhcyBpdHMgYmFja2luZyBzdG9yZS4KCioqQ29sdW1ucyBjb250YWluaW5nIGRvdCAoLikqKjogQSBjb2x1bW4gY29udGFpbmluZyBhIGRvdCAocGVyaW9kKSBpbiBpdHMgbmFtZSBjb25mdXNlcyBTUUwgYXMgdGhlIGRpdCBpcyBhIHNlcGFyYXRvciBiZXR3ZWVuIHRhYmxlIG5hbWUgYW5kIGNvbHVtbiBuYW1lLiBTbywgKlQueCogcmVmZXJzIHRvIGNvbHVtbiAqeCogaW4gdGhlIHRhYmxlICpUKi4gVGhhdCBpcyB1c2VmdWwgd2hlbiB5b3UgaGF2ZSBxdWVyaWVzIHRoYXQgaW52b2x2ZSBtdWx0aXBsZSB0YWJsZXMgYW5kIGNvbHVtbnMgd2l0aCB0aGUgc2FtZSBuYW1lIGFyZSBpbiBzZXZlcmFsIHRhYmxlczsgaXQgYWxsb3dzIGRpc2FtYmlndWF0aW9uLiBIb3dldmVyLCBpZiB5b3UgaGF2ZSBhIGNvbHVtbiBpbiBhIENTViBvciBkYXRhIGZyYW1lIG5hbWVkICoieWVhci5iZWZvcmUiKiB0aGVuIFNRTCB3b3VsZCBpbnRlcnByZXQgaW5jb3JyZWN0bHk7IHRvICJlc2NhcGUiIHRoZSBtZWFuaW5nIG9mIHRoZSBkb3QsIHlvdSBuZWVkIHRvIGVuY2xvc2UgdGhlIGNvbHVtbiBpbiBiYWNrdGlja3MsICppLmUuKiwgXGB5ZWFyLmJlZm9yZVxgLgoKIyMgQ3JlYXRpbmcgYSBEYXRhYmFzZQoKTGV0J3MgY3JlYXRlIGEgbmV3IChhbmQgZW1wdHkpIGRhdGFiYXNlLgoKYGBge3IgY29ubmVjdDJEQn0KbGlicmFyeShSU1FMaXRlKQoKZGIuZmlsZSA8LSAiY3VzdG9tZXJEQi5kYiIKCnVubGluayhkYi5maWxlKQpjdXN0REIgPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCBkYi5maWxlKQpgYGAKCldlIGNhbiBjcmVhdGUgYXMgd2VsbCBhcyBkcm9wIHRhYmxlcyBpbiB0aHJlZSB3YXlzOgoKMS4gIGVtYmVkIFNRTCAqQ1JFQVRFIFRBQkxFKiBzdGF0ZW1lbnRzIGluIGEge3NxbH0gY2h1bmsKMi4gIHNlbmQgU1FMICpDUkVBVEUgVEFCTEUqIHN0YXRlbWVudHMgd2l0aCA8Y29kZT5kYkV4ZWN1dGUoKTwvY29kZT4KMy4gIGNhbGwgdGhlIGNvbnZlbmllbmNlIGZ1bmN0aW9ucyA8Y29kZT5kYkNyZWF0ZVRhYmxlKCk8L2NvZGU+IG9yIDxjb2RlPmRiUmVtb3ZlVGFibGUoKTwvY29kZT4KCldoaWNoIHRvIHVzZSBpcyBwcmVmZXJlbmNlOyB0aGVyZSBpcyBsaXR0bGUgZGlmZmVyZW5jZSBpbiBwZXJmb3JtYW5jZS4KCiMjIyBEcm9wcGluZyBhIFRhYmxlCgpgYGB7ciBkcm9wVGFibGVDb2RlLCBldmFsPVQsIGVjaG89VH0Kc3FsQ29kZSA8LSAiZHJvcCB0YWJsZSBpZiBleGlzdHMgdHhucyIKZGJFeGVjdXRlKGN1c3REQiwgc3FsQ29kZSkKYGBgCgojIyMgQ3JlYXRlIFRhYmxlcyBpbiB7c3FsfQoKQ3JlYXRlIG5ldyB0YWJsZXMgdXNpbmcge3NxbH0gY2h1bmtzOgoKYGBge3NxbCBjcmVhdGVUYWJsZUVtYmVkZGVkLCBjb25uZWN0aW9uPWN1c3REQn0KY3JlYXRlIHRhYmxlIHR4bnMgKAogIGlkIElOVEVHRVIgUFJJTUFSWSBLRVksCiAgdmlzaXRzIElOVEVHRVIgTk9UIE5VTEwsCiAgb3MgVEVYVAopCmBgYAoKIyMjIENyZWF0ZSBUYWJsZSBpbiBSCgpDcmVhdGUgbmV3IHRhYmxlcyB1c2luZyA8Y29kZT5kYkV4ZWN1dGUoKTwvY29kZT46CgpgYGB7ciBjcmVhdGVUYWJsZUNvZGUsIGV2YWw9VCwgZWNobz1UfQpzcWxDb2RlIDwtICJjcmVhdGUgdGFibGUgaWYgbm90IGV4aXN0cyB0eG5zICgKICAgICAgICAgICAgICBpZCBJTlRFR0VSIFBSSU1BUlkgS0VZLAogICAgICAgICAgICAgIHZpc2l0cyBJTlRFR0VSIE5PVCBOVUxMLAogICAgICAgICAgICAgIG9zIFRFWFQKICAgICAgICAgICAgKSIKZGJFeGVjdXRlKGN1c3REQiwgc3FsQ29kZSkKYGBgCgojIyBBZGRpbmcgRGF0YSB0byB0aGUgRGF0YWJhc2UKCkFkZGluZyBuZXcgZGF0YSB0byB0aGUgZGF0YWJhc2UgY2FuIGJlIGRvbmUgaW4gc2V2ZXJhbCB3YXlzLiBJbnNlcnQgZGF0YSByb3cgYnkgcm93IHVzaW5nIFNRTCBJTlNFUlQgc3RhdGVtZW50cyBvciBhZGQgYWxsIHJvd3MgZnJvbSBhIGRhdGEgZnJhbWUgdG8gYSB0YWJsZSBpbiBiYXRjaCBtb2RlIHVzaW5nIDxjb2RlPmRiV3JpdGVUYWJsZSgpPC9jb2RlPi4KClRoZSBjb2RlIGJlbG93IGxvYWRzIGEgQ1NWIHRoYXQgd2Ugd2lsbCBsb2FkIGludG8gdGhlIGEgbmV3bHkgY3JlYXRlZCBkYXRhYmFzZS4KCmBgYHtyIHJlbG9hZENTVn0KdHhucyA8LSByZWFkLmNzdigiY3VzdG9tZXJ0eG5kYXRhLmNzdiIsIAogICAgICAgICAgICAgICBoZWFkZXIgPSBGLAogICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJ2aXNpdHMiLCJudW10eG5zIiwib3MiLCJnZW5kZXIiLCJ0b3RhbCIpKQoKdHhucyRpZCA8LSBzZXEoZnJvbSA9IDEsIHRvID0gbnJvdyh0eG5zKSkgKyAxMDAKYGBgCgojIyMgQnVsayBMb2FkaW5nCgpUbyBnZXQgZGF0YSBmcm9tIGEgZGF0YSBmcmFtZSBpbnRvIGEgdGFibGUgaW4gdGhlIGRhdGFiYXNlLCB5b3UgY2FuIGVpdGhlciBpbnNlcnQgdGhlIGRhdGEgcm93IGJ5IHJvdyBpbiBhIGxvb3Agb3IgKGJldHRlcikgdXNlIDxjb2RlPmRiV3JpdGVUYWJsZSgpPC9jb2RlPiB3aGljaCBpbnNlcnRzIGFuIGVudGlyZSBkYXRhIGZyYW1lIGludG8gYSBuZXcgb3IgYW4gZXhpc3RpbmcgdGFibGUuCgpgYGB7cn0KZGJXcml0ZVRhYmxlKGN1c3REQiwgInR4bnMiLCB0eG5zWyxjKDYsMSwzKV0sIG92ZXJ3cml0ZT1GLCBhcHBlbmQ9VCkKYGBgCgo+IDxjb2RlPmRiV3JpdGVUYWJsZSgpPC9jb2RlPiByZXF1aXJlcyB0aGF0ICJidWxrL2JhdGNoIGxvYWRpbmciIGlzIGVuYWJsZXMgZm9yIHRoZSBkYXRhYmFzZS4gVGhpcyBpcyAqbm90KiB0aGUgZGVmYXVsdCBmb3IgTXlTUUwgYnV0IGlzIGZvciBTUUxpdGUuIEZvciBNeVNRTCBpdCBtdXN0IGJlIGNvbmZpZ3VyZWQgZmlyc3QuIFNvbWUgY2xvdWQgc2VydmljZXMgZm9yIE15U1FMIGRvIG5vdCBlbmFibGUgYmF0Y2ggbG9hZGluZyAoKmUuZy4qLCBbZGI0ZnJlZS5uZXRdKGh0dHBzOi8vZGI0ZnJlZS5uZXQpKS4KCj4gSWYgeW91ciB0YWJsZSBoYXMgcm93IG5hbWVzIGFuZCB5b3UgZW5kIHVwIHdpdGggYW4gZXh0cmEgY29sdW1uIGluIHRoZSBkYXRhYmFzZSwgdGhlbiBzcGVjaWZ5ICpyb3cubmFtZXMgPSBGKiBhcyBhIHBhcmFtZXRlci4KCiMjIyBQcmVwYXJlZCBTdGF0ZW1lbnRzCgpQcmVwYXJlZCBzdGF0ZW1lbnRzIGFyZSBhIHNwZWNpYWwgZm9ybSBvZiBhIFNRTCBzdGF0ZW1lbnQgdGhhdCBpbmNsdWRlcyBwYXJhbWV0ZXJzLiBJdCBpcyBwcmVmZXJhYmxlIHRvIHVzZSBwcmVwYXJlZCBzdGF0ZW1lbnRzIHJhdGhlciB0aGFuIGJ1aWxkIGEgU1FMIHN0cmluZyB1c2UgY29uY2F0ZW5hdGlvbi4gSG93ZXZlciwgc29tZSBkYXRhYmFzZSBtYXkgbm90IHN1cHBvcnQgc3RhdGVtZW50cyAobm90YWJseSBNeVNRTCBob3N0ZWQgb24gKmRiNGZyZWUubmV0KikuCgpgYGB7c3FsIGRlbGV0ZURhdGFJblRhYmxlLCBjb25uZWN0aW9uPWN1c3REQiwgZWNobyA9IEZ9CmRlbGV0ZSBmcm9tIHR4bnMKYGBgCgpgYGB7ciBwcmVwYXJlZFN0YXRlbWVudH0KaWQgPC0gMTAyCm51bVZpc2l0cyA8LSA0Cm9zIDwtICdpT1MnCgojIHNldHMgdXAgcHJlcGFyZWQgc3RhdGVtZW50IGNvZGUKc3FsQ29kZSA8LSAiaW5zZXJ0IGludG8gdHhucyB2YWx1ZXMgKDppZCwgOm4sIDpvcykiCgojIGNyZWF0ZSBhIHByZXBhcmVkIHN0YXRlbWVudCB3aXRoIHBhcmFtZXRlcnMKcHMgPC0gZGJTZW5kU3RhdGVtZW50KGN1c3REQiwgc3FsQ29kZSkKCiMgYmluZCBwYXJhbWV0ZXJzCmRiQmluZChwcywgcGFyYW1zID0gbGlzdChpZCA9IGlkLCBuID0gbnVtVmlzaXRzLCBvcyA9IG9zKSkKCiMgcnVuIHRoZSBxdWVyeQpkYkNsZWFyUmVzdWx0KHBzKQpgYGAKCiMjIyBJbnNlcnQgRGF0YSBSb3cgYnkgUm93CgpJZiBidWxrIGxvYWRpbmcgaXMgbm90IGFuIG9wdGlvbiBiZWNhdXNlIGVpdGhlciB0aGUgZGF0YWJhc2UgZG9lcyBub3Qgc3VwcG9ydCBpdCBvciB0aGUgZGF0YSBoYXMgdG8gYmUgcHJvY2Vzc2VkIHByaW9yIHRvIGluc2VydGlvbiwgdGhlbiBhZGRpbmcgdGhlIGRhdGEgcm93IGJ5IHJvdyBpbiBhIGxvb3AgdXNpbmcgYSBwcmVwYXJlZCBzdGF0ZW1lbnQgaXMgYW4gYWx0ZXJuYXRpdmUuIEhvd2V2ZXIsIHRoaXMgcHJvY2VzcyBpcyBtdWNoIHNsb3dlciBhbmQgc2hvdWxkIG9ubHkgYmUgdXNlZCBhcyBhIGxhc3QgcmVzb3J0LgoKYGBge3NxbCBkZWxldGVEYXRhSW5UYWJsZTIsIGNvbm5lY3Rpb249Y3VzdERCLCBlY2hvID0gRn0KZGVsZXRlIGZyb20gdHhucwpgYGAKCmBgYHtyIGluc2VydFJvd0J5Um93LCBldmFsPUYsIHdhcm5pbmc9Rn0KbnJvd3MgPC0gbnJvdyh0eG5zKQoKZm9yIChpIGluIDE6bnJvd3MpCnsKICBpZCA8LSB0eG5zW2ksNl0KICBudW1WaXNpdHMgPC0gdHhuc1tpLDFdCiAgb3MgPC0gdHhuc1tpLDNdCiAgCiAgIyBzZXRzIHVwIHByZXBhcmVkIHN0YXRlbWVudCBjb2RlCiAgc3FsQ29kZSA8LSAiaW5zZXJ0IGludG8gdHhucyB2YWx1ZXMgKDppZCwgOm4sIDpvcykiCiAgCiAgIyBjcmVhdGUgYSBwcmVwYXJlZCBzdGF0ZW1lbnQgd2l0aCBwYXJhbWV0ZXJzCiAgcHMgPC0gZGJTZW5kU3RhdGVtZW50KGN1c3REQiwgc3FsQ29kZSkKICAKICAjIGJpbmQgcGFyYW1ldGVycwogIGRiQmluZChwcywgcGFyYW1zID0gbGlzdChpZCA9IGlkLCBuID0gbnVtVmlzaXRzLCBvcyA9IG9zKSkKfQoKYGBgCgpUaGUgY29kZSBiZWxvdyBpcyBhIHBlcmZvcm1hbmNlIGltcHJvdmVtZW50IHdoZXJlIHRoZSBsb29wIGdlbmVyYXRlcyBhIHNpbmdsZSBsYXJnZSBTUUwgSU5TRVJUIHN0YXRlbWVudCB0aGF0IGluc2VydHMgbXVsdGlwbGUgcm93cyBpbiBhIHNpbmdsZSBjYWxsIHRvIHRoZSBkYXRhYmFzZS4gU29tZSBkYXRhYmFzZSBtYXkgcmVzdHJpY3QgdGhlIG51bWJlciBvZiB2YWx1ZXMgdGhhdCBjYW4gYmUgaW5jbHVkZWQgaW4gYSBzaW5nbGUgSU5TRVJUIHN0YXRlbWVudCwgc28gdGhpcyBtYXkgaGF2ZSB0byBiZSBkb25lIGluIGJhdGNoZXMuCgpgYGB7c3FsIGRlbGV0ZURhdGFJblRhYmxlMywgY29ubmVjdGlvbj1jdXN0REJ9CmRlbGV0ZSBmcm9tIHR4bnMKYGBgCgpgYGB7ciBpbXByb3ZlZFJvd0J5Um93LCBldmFsPUZ9Cm5yb3dzIDwtIG5yb3codHhucykKc3FsQ29kZSA8LSAiaW5zZXJ0IGludG8gdHhucyB2YWx1ZXMgIgoKZm9yIChpIGluIDE6bnJvd3MpCnsKICBpZCA8LSB0eG5zW2ksNl0KICBudW1WaXNpdHMgPC0gdHhuc1tpLDFdCiAgb3MgPC0gdHhuc1tpLDNdCiAgCiAgIyBhZGQgdmFsdWVzIHRvIHRoZSBsaXN0IG9mIHZhbHVlcwogIHNxbENvZGUgPC0gcGFzdGUwKHNxbENvZGUsICIoIixpZCwiLCIsIG51bVZpc2l0cywgIiwnIiwgb3MsICInKSIpCiAgCiAgIyBhZGQgY29tbWEgYXQgdGhlIGVuZCBleGNlcHQgZm9yIHRoZSBsYXN0IHJvdwogIGlmIChpIDwgbnJvd3MpCiAgICBzcWxDb2RlIDwtIHBhc3RlMChzcWxDb2RlLCAiLCIpCn0KCnByaW50KHNxbENvZGUpCgojIGV4ZWN1dGUgdGhlIGluc2VydCBzdGF0ZW1lbnQKciA8LSBkYkV4ZWN1dGUoY3VzdERCLCBzcWxDb2RlKQpgYGAKCklmIHRoZSBkYXRhIGZyYW1lIGlzIHRvbyBsYXJnZSBhbmQgdGhlIHN1YnNlcXVlbnQgU1FMIElOU0VSVCBzdGF0ZW1lbnQgd291bGQgaGF2ZSB0b28gbWFueSB2YWx1ZXMgYW5kIGV4Y2VlZCBhIGRhdGFiYXNlIGxpbWl0LCB0aGVuIGluc2VydCB0aGUgZGF0YSBpbiBzdGFnZXMuIEZvciBleGFtcGxlLCByZWFkIHJvd3MgaW4gYmF0Y2hlcyBmcm9tIHRoZSBDU1YgYW5kIGluc2VydHMgdGhlbSBpbnRvIHRoZSBkYXRhYmFzZS4gPGNvZGU+cmVhZC5jc3Y8L2NvZGU+IGhhcyBwYXJhbWV0ZXJzICpza2lwKiBhbmQgKm5yb3dzKiB0byBoZWxwIGRvIHRoYXQuCgojIyBDbGVhcmluZyBSZXN1bHQgU2V0cwoKQSBjb21tb24gd2FybmluZyBtZXNzYWdlIGlzIHJlY2VpdmVkICgiV2FybmluZzogQ2xvc2luZyBvcGVuIHJlc3VsdCBzZXQsIHBlbmRpbmcgcm93cyIpIHdoZW4gd29ya2luZyB3aXRoIFNRTGl0ZSBkYXRhYmFzZXMgaW4gUiB1c2luZyB0aGUgYERCSWAgb3IgYFJTUUxpdGVgIHBhY2thZ2UuIEl0IGluZGljYXRlcyB0aGF0IGEgcHJldmlvdXMgcXVlcnkgb3Igc3RhdGVtZW50IGV4ZWN1dGlvbiB3YXMgbm90IHByb3Blcmx5IGZpbmFsaXplZCBvciBjbG9zZWQsIGxlYXZpbmcgYW4gb3BlbiAicmVzdWx0IHNldCIgdGhhdCBoYXNuJ3QgYmVlbiBmdWxseSBoYW5kbGVkLiBUaGlzIHR5cGljYWxseSBoYXBwZW5zIHdoZW4geW91OgoKMS4gIEV4ZWN1dGUgYSBxdWVyeSBvciBzdGF0ZW1lbnQgdGhhdCByZXR1cm5zIHJvd3MgKCplLmcuKiwgYSBgU0VMRUNUYCBzdGF0ZW1lbnQpIGJ1dCBkbyBub3QgZmV0Y2ggb3IgY2xlYXIgdGhlIHJlc3VsdHMuCjIuICBGb3JnZXQgdG8gZXhwbGljaXRseSBjbGVhciBvciBmaW5hbGl6ZSBhIHJlc3VsdCBzZXQgYWZ0ZXIgcnVubmluZyBgZGJTZW5kU3RhdGVtZW50KClgIG9yIGBkYlNlbmRRdWVyeSgpYC4KCiMjIyBVbmRlcnN0YW5kaW5nIHRoZSBQcm9ibGVtCgpUaGUgZnVuY3Rpb24gYGRiU2VuZFN0YXRlbWVudCgpYCAoZnJvbSB0aGUgYERCSWAgcGFja2FnZSkgZXhlY3V0ZXMgYSBTUUwgc3RhdGVtZW50LCBzdWNoIGFzIGFuIGBJTlNFUlRgLCBgVVBEQVRFYCwgb3IgYERFTEVURWAsIHdoaWNoIGRvZXMgbm90IHJldHVybiBhIHJlc3VsdCBzZXQuIEhvd2V2ZXIsIHRoZSBmdW5jdGlvbiByZXR1cm5zIGEgYERCSVJlc3VsdGAgb2JqZWN0IHRoYXQgbXVzdCBiZSBjbGVhcmVkIGV4cGxpY2l0bHkgdXNpbmcgYGRiQ2xlYXJSZXN1bHQoKWAuCgpJZiB5b3UgZG9uJ3QgY2xlYXIgdGhlIGBEQklSZXN1bHRgIG9iamVjdCwgaXQgcmVtYWlucyBvcGVuLCBhbmQgd2hlbiB5b3UgY2xvc2UgdGhlIGNvbm5lY3Rpb24gb3IgcGVyZm9ybSBhbm90aGVyIGRhdGFiYXNlIG9wZXJhdGlvbiwgUlNRTGl0ZSBhdXRvbWF0aWNhbGx5IGNsZWFycyB0aGUgb3BlbiByZXN1bHQsIGxlYWRpbmcgdG8gdGhlIHdhcm5pbmcuCgojIyMgUmVzb2x2aW5nIHRoZSBXYXJuaW5nCgpUbyByZXNvbHZlIHRoZSB3YXJuaW5nLCB5b3Ugc2hvdWxkIGV4cGxpY2l0bHkgY2xlYXIgdGhlIHJlc3VsdCBzZXQgYWZ0ZXIgZXhlY3V0aW5nIGEgc3RhdGVtZW50IHdpdGggYGRiU2VuZFN0YXRlbWVudCgpYC4gSGVyZSdzIGFuIGV4YW1wbGU6CgpgYGAgcgojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMKbGlicmFyeShEQkkpCmxpYnJhcnkoUlNRTGl0ZSkKCiMgQ3JlYXRlIGEgY29ubmVjdGlvbiB0byB0aGUgU1FMaXRlIGRhdGFiYXNlCmNvbiA8LSBkYkNvbm5lY3QoU1FMaXRlKCksICJleGFtcGxlLmRiIikKCiMgRXhhbXBsZTogSW5zZXJ0IGRhdGEgaW50byBhIHRhYmxlCnN0bXQgPC0gZGJTZW5kU3RhdGVtZW50KGNvbiwgIklOU0VSVCBJTlRPIG15X3RhYmxlIChjb2x1bW4xLCBjb2x1bW4yKSBWQUxVRVMgKD8sID8pIikKCiMgQmluZCB2YWx1ZXMgdG8gdGhlIHN0YXRlbWVudApkYkJpbmQoc3RtdCwgbGlzdCgidmFsdWUxIiwgInZhbHVlMiIpKQoKIyBDbGVhciB0aGUgcmVzdWx0IGV4cGxpY2l0bHkgdG8gYXZvaWQgdGhlIHdhcm5pbmcKZGJDbGVhclJlc3VsdChzdG10KQoKIyBEaXNjb25uZWN0IGZyb20gdGhlIGRhdGFiYXNlCmRiRGlzY29ubmVjdChjb24pCmBgYAoKIyMjIEtleSBQb2ludHMgdG8gQXZvaWQgdGhlIFdhcm5pbmcKCjEuICAqKkFsd2F5cyBDbGVhciB0aGUgUmVzdWx0Kio6IFVzZSBgZGJDbGVhclJlc3VsdCgpYCBhZnRlciBleGVjdXRpbmcgYSBxdWVyeSBvciBzdGF0ZW1lbnQgd2l0aCBgZGJTZW5kUXVlcnkoKWAgb3IgYGRiU2VuZFN0YXRlbWVudCgpYC4KCjIuICAqKlVzZSBgZGJFeGVjdXRlKClgIGZvciBTaW1wbGVyIENhc2VzKio6IElmIHlvdSBkbyBub3QgbmVlZCB0byBiaW5kIHBhcmFtZXRlcnMgb3IgZmV0Y2ggcm93cywgcHJlZmVyIHVzaW5nIGBkYkV4ZWN1dGUoKWAsIHdoaWNoIGhhbmRsZXMgcmVzdWx0IGNsZWFyaW5nIGF1dG9tYXRpY2FsbHk6CgogICAgYGBgIHIKICAgIGRiRXhlY3V0ZShjb24sICJJTlNFUlQgSU5UTyBteV90YWJsZSAoY29sdW1uMSwgY29sdW1uMikgVkFMVUVTICgndmFsdWUxJywgJ3ZhbHVlMicpIikKICAgIGBgYAoKMy4gICoqUmV2aWV3IFlvdXIgQ29kZSBmb3IgT3BlbiBSZXN1bHRzKio6IENoZWNrIGlmIHlvdSBoYXZlIGFueSBgZGJTZW5kUXVlcnkoKWAgb3IgYGRiU2VuZFN0YXRlbWVudCgpYCBjYWxscyB3aXRob3V0IGNvcnJlc3BvbmRpbmcgYGRiQ2xlYXJSZXN1bHQoKWAuCgojIyMgRXhwbGFuYXRpb24gb2YgdGhlIFdhcm5pbmcKClNRTGl0ZSBlbmZvcmNlcyB0aGF0IGFsbCByZXN1bHQgc2V0cyBtdXN0IGJlIGNsb3NlZCBiZWZvcmUgZXhlY3V0aW5nIG5ldyBzdGF0ZW1lbnRzLiBSU1FMaXRlIHdhcm5zIHlvdSB3aGVuIGl0IGRldGVjdHMgYW4gb3BlbiByZXN1bHQgc2V0IGJlY2F1c2UgdGhpcyBjb3VsZCBsZWFkIHRvIHJlc291cmNlIGxlYWtzIG9yIHVuZGVmaW5lZCBiZWhhdmlvci4KCkJ5IGFkaGVyaW5nIHRvIHByb3BlciByZXNvdXJjZSBtYW5hZ2VtZW50IChjbGVhcmluZyByZXN1bHRzIGFuZCBjbG9zaW5nIGNvbm5lY3Rpb25zKSwgeW91IGNhbiBhdm9pZCBzdWNoIHdhcm5pbmdzIGFuZCBlbnN1cmUgcm9idXN0IGludGVyYWN0aW9uIHdpdGggeW91ciBTUUxpdGUgZGF0YWJhc2UuCgojIyBEaXNjb25uZWN0IGZyb20gRGF0YWJhc2UKCldoZW4gYSBkYXRhYmFzZSBjb25uZWN0aW9uIGlzIG5vIGxvbmdlciBuZWVkZWQsIGl0IG11c3QgYmUgY2xvc2VkIGJ5IGRpc2Nvbm5lY3RpbmcgZnJvbSB0aGUgZGF0YWJhc2UuIFRoaXMgZnJlZXMgdXAgZGF0YWJhc2UgYW5kIG90aGVyIHJlc291cmNlcy4KCmBgYHtyIGRpc2Nvbm5lY3REQn0KZGJEaXNjb25uZWN0KGN1c3REQikKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIEZpbGVzICYgUmVzb3VyY2VzCgpgYGB7ciB6aXBGaWxlcywgZWNobz1GQUxTRX0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIAogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwKICAgICAgICAgICAgICAgICBwYXJhbXMkbnVtYmVyKQoKdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCAKICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LCIuIixwYXJhbXMkbnVtYmVyKQoKIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SCmtuaXRyOjpyYXdfaHRtbChkb3dubG9hZEZpbGVzTGluaygiLiIsIHppcE5hbWUsIHRleHRBTGluaykpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBSZWZlcmVuY2VzCgotICAgW1RoZSBzcWxkZiBQYWNrYWdlLiBSIERvY3VtZW50YXRpb24uXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvc3FsZGYvdmVyc2lvbnMvMC40LTExKQotICAgW0NvcHkgRGF0YSBGcmFtZSB0byBUYWJsZXM6IGRiV3JpdGVUYWJsZV0oaHR0cHM6Ly9kYmkuci1kYmkub3JnL3JlZmVyZW5jZS9kYndyaXRldGFibGUpCgojIyBFcnJhdGEKCltMZXQgdXMga25vd10oaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLzIxMjE4NzA3Mjc4NDE1Nyl7dGFyZ2V0PSJfYmxhbmsifS4KCg==