Introduction
Relational databases serve as the foundation for structured data storage, ensuring that data is consistently organized and efficiently accessible. In SQLite, as in other relational database systems, the creation, modification, and deletion of tables are fundamental operations that define the structure of the database schema.
In this lesson, you will learn about how to create, modify (alter), and remove (drop or delete) tables in SQLite, although the SQL syntax applies to all relational databases in general. Note that SQL is not case sensitive, but it is common practice to capitalize SQL keywords.
SQLite Databases
SQLite is a server-less database that stores its data in files or in an in-memory database. It is commonly used for mobile app and web development, as well as for research and proof-of-concept prototyping. It is not a multi-user database and thus is not recommended for business environments. In those situations, MySQL, Oracle, SQL Server, or a similar database is recommended. However, the standard nature of SQL means that the statements explained in this lesson are universally applicable to all relational databases.
Executing SQL in R
SQLite databases can be managed directly within R using the DBI
and RSQLite
packages. These tools allow users to execute SQL statements from R scripts or R Notebooks. R Notebooks, which are part of R Markdown, also support SQL code chunks, allowing users to write and execute SQL directly within a document.
SQL in R
R provides a programmatic way to execute SQL statements using the DBI
package, which acts as a common interface for database connections, and RSQLite
, which provides an implementation for SQLite.
Step 1: Install and Load Necessary Packages
If the required packages are not installed, they must be installed first. To install packages in R automatically but only if they are not already installed, you can check whether a package is available using the installed.packages()
function. If the package is not installed, you can install it using install.packages()
.
The following R code ensures that required packages are installed before loading them:
# Define a vector of required packages
required_packages <- c("DBI", "RSQLite")
# Check if each package is installed, and install it if necessary
for (pkg in required_packages) {
if (!pkg %in% installed.packages()[, "Package"]) {
install.packages(pkg, repos = "https://cloud.r-project.org/")
}
}
Once we are assured that the packages are installed in our local R environment, we need to load the packages into our R session using either the library()
or the require()
functions.
library(DBI)
library(RSQLite)
Step 2. Connect to Database
Creating a new database in SQLite is simple: just “connect” to a non-existing database. If the database file does not exist, it will create a new database file in your file system.
In R, the RSQLite package is required for connecting and working with SQLite databases. The dbConnect()
function connects to a database; or creates it if it doesn’t exist. The R code fragment below creates a new database.
# load the necessary package
library(RSQLite)
# change this code to connect to your specific database
conn <- dbConnect(RSQLite::SQLite(), "healthcare.db")
As an aside, the special database “file name” “:memory:” will create a database in memory. An in-memory database is great for exploration, learning, proof-of-concept work, or quick experiments but it is not persistent – when the computer or applications shuts down, the data will disappear. When you need persistent data, use a file on disk.
Step 3: Execute a SQL Statement
Once you are connected to the database, you can execute SQL statements for queries or to create or modify tables and data using the dbExecute()
function. For example, the code below illustrates how to create a Patients
table using an R function. This approach will work for both R Scripts (programs) and in R Notebooks within an R code chunk:
status <- dbExecute(conn, "
CREATE TABLE IF NOT EXISTS Patients (
PatientID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL,
DateOfBirth DATE NOT NULL,
Gender TEXT CHECK(Gender IN ('Male', 'Female', 'Other')),
ContactNumber TEXT UNIQUE,
Email TEXT UNIQUE,
Address TEXT,
EmergencyContact TEXT,
InsuranceNumber TEXT UNIQUE,
RegistrationDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
")
This SQL statement embedded with an R function call creates the Patients
table with constraints to ensure data integrity – we will explain the various parts of this table creation statement later in this lesson. Note the first argument to dbExecute()
is the database connection object that was returned from the call to dbConnect()
.
Step 4: Verify Table Creation
It is good practice, to “test” the creation code by listing all tables in the database. This will confirm that the table was created. The DBI function dbListTables()
will list the names of all tables present in the database referenced by conn
.
If successful, the output will include “Patients”.
Step 5: Close Connection
Always disconnect from the database when done executing queries in order to free resources:
SQL Code Chunks
R Notebooks (a feature of R Markdown) allow embedding SQL queries directly using SQL chunks. These SQL chunks execute queries against a connected database without requiring explicit function calls in R. In fact, during knitting of the markdown, the SQL code chunks are translated to R function calls, so there is no disadvantage to using SQL code chunks.
Step 1: Creating an R Notebook with SQL Support
In RStudio, create an R Notebook (.Rmd
file). Inside the notebook, add a setup chunk to establish a connection:

Step 2: Writing SQL Code in SQL Code Chunks
Within the R Notebook, create an SQL chunk to execute SQL statements. The chunk is specified using:

Note the code chunk parameter connection must be set to the database connection object returned from dbConnect()
.
A SQL code chunk can only contain one SQL statement, so to create multiple tables, you need multiple code chunks, one per SQL statement.
The semi-colon at the end of the SQL statement is customary, but neither required nor necessary as we cannot have multiple SQL statements. Hence, no statement separator is needed.
Step 3: Querying the Database in SQL Chunks
To retrieve data from the Patients
table in an R Notebook, add another SQL chunk:

By default, the result of any query from a SQL code chunk is rendered as a table in the knitted document. However, it is possible to capture the query result set in a dataframe rather than having it displayed.
If you want to use code chunks rather than calling an R function such as dbGetQuery()
to retrieve data, you can store the result of an SQL query into an R dataframe using the output.var
option in a {sql}
code chunk.

The output.var="patients_df"
option stores the result of the SQL query into an R dataframe named patients_df
.
Once executed, the dataframe patients_df
will be available in the R environment and can be used like any other R dataframe:
# Display the first few rows
head(patients_df)
Of course, if you prefer working with standard R code chunks ({r}
) instead of {sql}
or you are building R Scripts rather than R Notebooks, you can capture SQL query results using the dbGetQuery()
function from the DBI
package.
# Retrieve data from Patients table
patients_df <- dbGetQuery(conn, "SELECT * FROM Patients")
# View the first few rows
head(patients_df)
SQL Chunks vs R Functions
Using R Functions (dbExecute() ) |
Full programmatic control, can use dynamically generated SQL |
Requires writing SQL within R functions |
Using SQL Code Chunks in R Notebooks |
Cleaner SQL syntax, good for documentation, inline execution |
Limited to predefined queries, less dynamic, only in R Notebooks |
Creating Tables
The process of defining a database schema begins with the CREATE TABLE
statement. This statement creates a table with specified attributes, each with a designated data type and, optionally, constraints such as primary keys, foreign keys, and uniqueness constraints.
Consider a database designed to manage patient records in a hospital setting.
To create a table to store patient information, the following SQL statement can be executed (assuming that the table does not yet exist, otherwise drop it first):
CREATE TABLE Patients (
PatientID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL,
DateOfBirth DATE NOT NULL,
Gender TEXT CHECK(Gender IN ('Male', 'Female', 'Other')),
ContactNumber TEXT UNIQUE,
Email TEXT UNIQUE,
Address TEXT,
EmergencyContact TEXT,
InsuranceNumber TEXT UNIQUE,
RegistrationDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
This Patients
table defines multiple attributes to store essential patient information. They are the “columns” in the table.
The PatientID
serves as the primary key and is automatically incremented with each new record. Primary key values must be unique and the database will not allow any insertion of duplicate primary key values. Of course, rather than having the database provide a primary key value, you can provide your own value – just ommit the AUTOINCREMENT.
The constraints enforce data integrity by ensuring that critical fields such as FirstName
, LastName
, and DateOfBirth
are non-null, i.e. cannot be left blank.
The Gender
field is restricted to predefined values using the CHECK
constraint mechanism, and contact details, including phone number, email, and insurance number, are unique to prevent duplicate records – these act as so-called alternate keys.
Additionally, the RegistrationDate
column is set to store the current timestamp by default when a new record is inserted.
To store medical records associated with patients, another table can be created to maintain diagnosis details:
CREATE TABLE MedicalRecords (
RecordID INTEGER PRIMARY KEY AUTOINCREMENT,
PatientID INTEGER NOT NULL,
Diagnosis TEXT NOT NULL,
Treatment TEXT,
PrescribedMedications TEXT,
DateOfVisit TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (PatientID) REFERENCES Patients(PatientID) ON DELETE CASCADE
);
The MedicalRecords
table establishes a foreign key relationship with the Patients
table using the PatientID
field. This ensures referential integrity by linking each medical record to a valid patient.
The ON DELETE CASCADE
clause ensures that when a patient is deleted, their corresponding medical records are also removed from the database, preventing orphaned records.
Foreign Key Constraint Enforcement
Unlike other relational database management systems (RDBMS) such as MySQL, PostgreSQL, and SQL Server, SQLite does not enforce foreign key constraints by default. This design choice was originally made to maintain backward compatibility with earlier versions of SQLite, which did not support foreign key constraints at all. Additionally, not checking foreign key constraints improves data insertion and deletion performance. Enforcing foreign key constraints requires additional processing overhead, which can slightly impact performance, especially in embedded systems or lightweight applications where SQLite is commonly used.
Since SQLite aims to be fast, lightweight, and highly portable, foreign key enforcement was disabled by default to avoid breaking compatibility with older applications that were designed without expecting constraint enforcement.
For applications that require strict referential integrity, foreign key enforcement must be explicitly enabled using the PRAGMA foreign_keys = ON;
statement.
Enabling FK Constraints in SQLite
To enforce foreign key constraints in SQLite, you must enable foreign key enforcement each time a database connection is opened. This is done using the PRAGMA foreign_keys = ON;
statement.
When using SQLite from the command line or an SQL script, you can enable foreign key checking by running:
PRAGMA foreign_keys = ON;
After executing this statement, SQLite will enforce foreign key constraints for the duration of the session. This means that any attempt to insert, update, or delete a record that violates a foreign key constraint will result in an error.
For example, consider the following schema:
CREATE TABLE Patients (
PatientID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL
);
CREATE TABLE MedicalRecords (
RecordID INTEGER PRIMARY KEY AUTOINCREMENT,
PatientID INTEGER NOT NULL,
Diagnosis TEXT NOT NULL,
FOREIGN KEY (PatientID) REFERENCES Patients(PatientID)
);
If PRAGMA foreign_keys = ON;
is not set, you can insert a record into MedicalRecords
referencing a non-existent PatientID, and SQLite will allow it:
INSERT INTO MedicalRecords (PatientID, Diagnosis) VALUES (999, 'Hypertension');
However, if foreign key enforcement is enabled, SQLite will reject the insert statement with an error:
Error: FOREIGN KEY constraint failed
Enabling Foreign Key Constraints in R
If you are working with SQLite in R using the DBI
and RSQLite
packages, you must explicitly enable foreign key support each time a connection is established.
# Load necessary libraries
library(DBI)
library(RSQLite)
# Establish a connection to the SQLite database
conn <- dbConnect(SQLite(), "bedDB.db")
# Enable foreign key constraint enforcement
dbExecute(conn, "PRAGMA foreign_keys = ON;")
## [1] 0
# Now execute SQL statements with foreign key constraints enforced
# When done with the database close the connection
dbDisconnect(conn)
Without setting PRAGMA foreign_keys = ON;
, foreign key constraints will not be enforced in the R session, and invalid references to foreign keys will be allowed.
Enabling Foreign Key Constraints in a Persistent Way
SQLite does not allow foreign key enforcement to be set persistently across all sessions (unlike some database systems where foreign key constraints are always enforced once configured). The enforcement setting must be enabled every time a database connection is established.
However, in applications that repeatedly open and close database connections (e.g., web applications), a best practice is to execute PRAGMA foreign_keys = ON;
immediately after opening a connection.
Verifying Whether Foreign Key Constraints Are Enabled
To check if foreign key enforcement is enabled in the current SQLite session, run:
If enforcement is enabled, SQLite will return:
1
If foreign key enforcement is disabled, it will return:
0
In short, SQLite does not enforce foreign key constraints by default to maintain backward compatibility and improve performance. However, if referential integrity is required, you must explicitly enable enforcement using PRAGMA foreign_keys = ON;
every time a database connection is opened. In applications using SQLite, such as R and Python programs, ensuring that this PRAGMA
statement is executed after establishing a connection is essential for maintaining database consistency.
Note that most other databases, such as MySQL, enforce referential integrity constraints by default unless you explicitly disable checking when necessary during bulk loading of data when checking would cause significant performance issues.
Existing Tables
If you attempt to create a table in that already exists, the database engine will return an error, preventing duplication. However, SQL provides a safeguard to handle such situations with the IF NOT EXISTS
clause in the CREATE TABLE
statement. This clause ensures that the table is only created if it does not already exist.
Consider the following example, where a hospital database is being designed to store patient records:
CREATE TABLE IF NOT EXISTS Patients (
PatientID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL,
DateOfBirth DATE NOT NULL,
Gender TEXT CHECK(Gender IN ('Male', 'Female', 'Other')),
ContactNumber TEXT UNIQUE,
Email TEXT UNIQUE,
Address TEXT,
EmergencyContact TEXT,
InsuranceNumber TEXT UNIQUE,
RegistrationDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
In this case, if the Patients
table already exists, SQLite will not create a new one, preventing an error from occurring. Instead, the database will simply ignore the command.
If the IF NOT EXISTS
clause is omitted and the table already exists, attempting to execute the following statement:
CREATE TABLE Patients (
PatientID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL,
DateOfBirth DATE NOT NULL,
Gender TEXT CHECK(Gender IN ('Male', 'Female', 'Other')),
ContactNumber TEXT UNIQUE,
Email TEXT UNIQUE,
Address TEXT,
EmergencyContact TEXT,
InsuranceNumber TEXT UNIQUE,
RegistrationDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
will result in an error similar to:
Error: table Patients already exists
This can be problematic in scenarios where automated processes attempt to create tables without prior knowledge of their existence.
Checking Table Existence
If greater control over the existence check is required, an alternative approach involves querying the SQLite sqlite_master
system table. The sqlite_master
table contains metadata about all database objects, including tables. To check for the existence of a specific table, the following SQL query can be used:
SELECT name FROM sqlite_master WHERE type='table' AND name='Patients';
If this query returns a result, it indicates that the Patients
table already exists. This method can be incorporated into application logic or database scripts to determine whether a table should be created dynamically.
We recommend that when creating tables to use CREATE TABLE IF NOT EXISTS
to prevent errors when defining tables that may already exist. For cases where more detailed checking is needed, querying sqlite_master
can provide insight into the database schema. These strategies help maintain robustness in database design, especially in dynamic or automated environments such as healthcare information systems where schema definitions may be executed multiple times.
Altering Tables
Modifying an existing table is a frequent requirement as database schemas evolve. SQL provides the ALTER TABLE
statement to facilitate such modifications.
Unlike more feature-rich database management systems such as PostgreSQL or MySQL, SQLite’s ALTER TABLE
capabilities are limited to adding new columns, renaming existing columns, and renaming tables.
Suppose the hospital administration decides to track patients’ blood types and allergies. To accommodate this change, the schema can be updated using the following SQL statements:
ALTER TABLE Patients ADD COLUMN BloodType TEXT CHECK(BloodType IN ('A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-'));
ALTER TABLE Patients ADD COLUMN Allergies TEXT;
These statements add the BloodType
column with a CHECK
constraint to restrict values to medically valid blood types and an Allergies
column to store any known allergies.
Additionally, if there is a need to rename the MedicalRecords
table to PatientMedicalRecords
for clarity, this can be achieved with:
ALTER TABLE MedicalRecords RENAME TO PatientMedicalRecords;
Note that SQLite does not support directly dropping or modifying columns. If a column needs to be removed, the recommended approach is to create a new table with the desired schema, migrate existing data, and then rename the new table to match the original table’s name.
Deleting Tables
If a table is no longer needed, it can be permanently removed using the DROP TABLE
statement. Suppose the hospital decides to discontinue maintaining certain old records, such as medical records that are no longer required for archival purposes. To remove the PatientMedicalRecords
table entirely, the following SQL command can be executed:
DROP TABLE PatientMedicalRecords;
Executing this command irreversibly deletes the table and all its stored data. If the table has dependencies, such as foreign keys in other tables, the deletion may fail unless cascading constraints were predefined.
For cases where data needs to be removed while retaining the table structure, using the DELETE FROM
statement without a WHERE
clause is a preferable alternative:
This command removes all records from the Patients
table while keeping its structure intact for future data insertion.
Database Scripts
In practice, database scripts are used to automate the process of defining a database schema, ensuring that tables, constraints, and relationships are established consistently. These scripts are typically written in SQL and executed as part of an application’s setup process or during database migrations.
A SQL script is simply a text file containing SQL commands separated by semi-colons.
For SQLite, database scripts are commonly stored in .sql
text files and executed using the SQLite command-line interface (sqlite3
), programmatically through a database connection in a language like Python, or within a database management tool.
Below is a sample SQL script (healthcare_schema.sql
) designed to create a database schema for a hospital management system. It includes tables for storing patient information, medical records, and doctor details. The – is a comment that is ignored.
Contents of File healthcare_schema.sql
-- Enable foreign key constraints (important for SQLite)
PRAGMA foreign_keys = ON;
-- Create Patients table
CREATE TABLE IF NOT EXISTS Patients (
PatientID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL,
DateOfBirth DATE NOT NULL,
Gender TEXT CHECK(Gender IN ('Male', 'Female', 'Other')),
ContactNumber TEXT UNIQUE,
Email TEXT UNIQUE,
Address TEXT,
EmergencyContact TEXT,
InsuranceNumber TEXT UNIQUE,
RegistrationDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create Doctors table
CREATE TABLE IF NOT EXISTS Doctors (
DoctorID INTEGER PRIMARY KEY AUTOINCREMENT,
FirstName TEXT NOT NULL,
LastName TEXT NOT NULL,
Specialization TEXT NOT NULL,
ContactNumber TEXT UNIQUE,
Email TEXT UNIQUE
);
-- Create MedicalRecords table
CREATE TABLE IF NOT EXISTS MedicalRecords (
RecordID INTEGER PRIMARY KEY AUTOINCREMENT,
PatientID INTEGER NOT NULL,
DoctorID INTEGER NOT NULL,
Diagnosis TEXT NOT NULL,
Treatment TEXT,
PrescribedMedications TEXT,
DateOfVisit TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (PatientID) REFERENCES Patients(PatientID) ON DELETE CASCADE,
FOREIGN KEY (DoctorID) REFERENCES Doctors(DoctorID) ON DELETE SET NULL
);
This script ensures that tables are created only if they do not already exist. It also establishes referential integrity using foreign key constraints, ensuring that medical records reference valid patients and doctors.
There are multiple ways to execute this SQL script in SQLite. The most common methods include using the SQLite command-line tool or executing the script programmatically in Python or R.
Method 1: Running the Script Using the SQLite Command-Line Interface
Ensure SQLite is installed: If SQLite is not installed, download it from SQLite’s official website.
Open a terminal or command prompt.
Navigate to the script’s directory using the cd
command.
Run the script with SQLite by executing:
sqlite3 healthcare.db < healthcare_schema.sql
This command will create a new SQLite database file (healthcare.db
) and execute all the SQL statements within healthcare_schema.sql
. If the database already exists, the script will ensure that the tables are created if they do not exist.
Verify the database schema by opening the SQLite shell and listing the tables:
Then, within the SQLite shell, execute:
This should display Doctors
, Patients
, and MedicalRecords
as the available tables.
Method 2: Executing the Script Programmatically
In many applications, database scripts are executed programmatically to initialize the database. The following Python script demonstrates how to execute healthcare_schema.sql
using SQLite’s sqlite3
module.
import sqlite3
# Connect to SQLite database (creates file if it does not exist)
conn = sqlite3.connect("healthcare.db")
cursor = conn.cursor()
# Read and execute the SQL script
with open("healthcare_schema.sql", "r") as file:
script = file.read()
cursor.executescript(script)
# Commit and close connection
conn.commit()
conn.close()
print("Database schema created successfully.")
Running this Python script will execute all SQL statements within healthcare_schema.sql
, setting up the database schema. This approach is commonly used in web applications, data pipelines, and system deployments where databases need to be initialized programmatically.
Here is an equivalent R script (not an R Notebook) to execute an SQLite database schema from a file, similar to the Python script provided earlier. In this example, we use the RSQLite
package to connect to an SQLite database, read the SQL script, and execute it.
Before running the script, ensure that the DBI
and RSQLite
packages are installed, as shown earlier in this lesson.
# Load necessary libraries
library(DBI)
library(RSQLite)
# Define database file name
db_file <- "healthcare.db"
# Establish a connection to the SQLite database (creates file if not exists)
conn <- dbConnect(SQLite(), db_file)
# Read the SQL script file
sql_script <- readLines("healthcare_schema.sql")
# Collapse the script into a single string
# (SQLite requires commands to be executed as complete statements)
sql_script_combined <- paste(sql_script, collapse = "\n")
# Execute the SQL script
dbExecute(conn, sql_script_combined)
# Close the database connection
dbDisconnect(conn)
# Confirm execution
cat("Database schema created successfully.\n")
Rather than executing an R Script from with R Studio (Posit), it can also be executed from the command line like a program. This allows database administration to be automated in shell scripts and jobs that are executed at specific times.
After running the script, you can check the created tables by executing the following commands in R:
# Reconnect to the database
conn <- dbConnect(SQLite(), "healthcare.db")
# List all tables in the database
dbListTables(conn)
# Disconnect
dbDisconnect(conn)
If successful, the output should display:
[1] "Doctors" "Patients" "MedicalRecords"
Deleting a SQLite Database
To delete the entire database, all of its tables, and all data, simply delete the file using your operating system’s file system manager. Alternatively, you can delete a database in R using the unlink()
function.
# delete database in file patientDB.db
unlink("patientDB.db")
Summary
Understanding the fundamental operations of creating, altering, and deleting tables is crucial for structuring and maintaining relational databases effectively. SQLite provides essential mechanisms for defining tables, modifying schemas, and removing unnecessary structures while ensuring data integrity through constraints and foreign key relationships. By applying these principles to a healthcare database, it becomes possible to manage patient records, medical histories, and related information efficiently. As database requirements evolve, careful planning is necessary to ensure seamless modifications while preserving data consistency.
Executing SQL statements within R can be done using DBI
functions or SQL code chunks in R Notebooks. Using dbExecute()
within R scripts allows programmatic control, whereas SQL chunks in R Notebooks provide a more structured way to document and execute queries inline. Both methods support efficient interaction with SQLite databases, making them valuable tools for managing healthcare data or any other structured information.
Database scripts provide a structured and repeatable way to define and manage a relational database schema. In SQLite, scripts can be executed through the command-line interface or programmatically via database connectors in languages such as Python. Using scripts ensures that database schemas remain consistent across environments and deployments, particularly in applications such as healthcare management systems where data integrity is crucial.
LS0tCnRpdGxlOiAiQ3JlYXRpbmcsIE1vZGlmeWluZywgYW5kIERlbGV0aW5nIFRhYmxlcyBpbiBTUUxpdGUiCnBhcmFtczoKICBjYXRlZ29yeTogNzAKICBudW1iZXI6IDgwNgogIHRpbWU6IDMwCiAgbGV2ZWw6IGJlZ2lubmVyCiAgdGFnczogInNxbGl0ZSxjcmVhdGUgdGFibGUsYXV0byBpbmNyZW1lbnQiCiAgZGVzY3JpcHRpb246ICJFeHBsYWlucyBob3cgdG8gY3JlYXRlLCBhbHRlciwgYW5kIHJlbW92ZSB0YWJsZXMgaW4gU1FMaXRlLiIKZGF0ZTogIjxzbWFsbD5gciBTeXMuRGF0ZSgpYDwvc21hbGw+IgphdXRob3I6ICI8c21hbGw+TWFydGluIFNjaGVkbGJhdWVyPC9zbWFsbD4iCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1IgphZmZpbGl0YXRpb246ICJOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKLS0tCnRpdGxlOiAiPHNtYWxsPmByIHBhcmFtcyRjYXRlZ29yeWAuYHIgcGFyYW1zJG51bWJlcmA8L3NtYWxsPjxici8+PHNwYW4gc3R5bGU9J2NvbG9yOiAjMkU0MDUzOyBmb250LXNpemU6IDAuOWVtJz5gciBybWFya2Rvd246Om1ldGFkYXRhJHRpdGxlYDwvc3Bhbj4iCi0tLQoKYGBge3IgY29kZT14ZnVuOjpyZWFkX3V0ZjgocGFzdGUwKGhlcmU6OmhlcmUoKSwnL1IvX2luc2VydDJEQi5SJykpLCBpbmNsdWRlID0gRkFMU0V9CmBgYAoKIyMgSW50cm9kdWN0aW9uCgpSZWxhdGlvbmFsIGRhdGFiYXNlcyBzZXJ2ZSBhcyB0aGUgZm91bmRhdGlvbiBmb3Igc3RydWN0dXJlZCBkYXRhIHN0b3JhZ2UsIGVuc3VyaW5nIHRoYXQgZGF0YSBpcyBjb25zaXN0ZW50bHkgb3JnYW5pemVkIGFuZCBlZmZpY2llbnRseSBhY2Nlc3NpYmxlLiBJbiBTUUxpdGUsIGFzIGluIG90aGVyIHJlbGF0aW9uYWwgZGF0YWJhc2Ugc3lzdGVtcywgdGhlIGNyZWF0aW9uLCBtb2RpZmljYXRpb24sIGFuZCBkZWxldGlvbiBvZiB0YWJsZXMgYXJlIGZ1bmRhbWVudGFsIG9wZXJhdGlvbnMgdGhhdCBkZWZpbmUgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YWJhc2Ugc2NoZW1hLgoKSW4gdGhpcyBsZXNzb24sIHlvdSB3aWxsIGxlYXJuIGFib3V0IGhvdyB0byBjcmVhdGUsIG1vZGlmeSAoYWx0ZXIpLCBhbmQgcmVtb3ZlIChkcm9wIG9yIGRlbGV0ZSkgdGFibGVzIGluIFNRTGl0ZSwgYWx0aG91Z2ggdGhlIFNRTCBzeW50YXggYXBwbGllcyB0byBhbGwgcmVsYXRpb25hbCBkYXRhYmFzZXMgaW4gZ2VuZXJhbC4gTm90ZSB0aGF0IFNRTCBpcyBub3QgY2FzZSBzZW5zaXRpdmUsIGJ1dCBpdCBpcyBjb21tb24gcHJhY3RpY2UgdG8gY2FwaXRhbGl6ZSBTUUwga2V5d29yZHMuCgojIyBTUUxpdGUgRGF0YWJhc2VzCgpTUUxpdGUgaXMgYSBzZXJ2ZXItbGVzcyBkYXRhYmFzZSB0aGF0IHN0b3JlcyBpdHMgZGF0YSBpbiBmaWxlcyBvciBpbiBhbiBpbi1tZW1vcnkgZGF0YWJhc2UuIEl0IGlzIGNvbW1vbmx5IHVzZWQgZm9yIG1vYmlsZSBhcHAgYW5kIHdlYiBkZXZlbG9wbWVudCwgYXMgd2VsbCBhcyBmb3IgcmVzZWFyY2ggYW5kIHByb29mLW9mLWNvbmNlcHQgcHJvdG90eXBpbmcuIEl0IGlzIG5vdCBhIG11bHRpLXVzZXIgZGF0YWJhc2UgYW5kIHRodXMgaXMgbm90IHJlY29tbWVuZGVkIGZvciBidXNpbmVzcyBlbnZpcm9ubWVudHMuIEluIHRob3NlIHNpdHVhdGlvbnMsIE15U1FMLCBPcmFjbGUsIFNRTCBTZXJ2ZXIsIG9yIGEgc2ltaWxhciBkYXRhYmFzZSBpcyByZWNvbW1lbmRlZC4gSG93ZXZlciwgdGhlIHN0YW5kYXJkIG5hdHVyZSBvZiBTUUwgbWVhbnMgdGhhdCB0aGUgc3RhdGVtZW50cyBleHBsYWluZWQgaW4gdGhpcyBsZXNzb24gYXJlIHVuaXZlcnNhbGx5IGFwcGxpY2FibGUgdG8gYWxsIHJlbGF0aW9uYWwgZGF0YWJhc2VzLgoKIyMgRXhlY3V0aW5nIFNRTCBpbiBSCgpTUUxpdGUgZGF0YWJhc2VzIGNhbiBiZSBtYW5hZ2VkIGRpcmVjdGx5IHdpdGhpbiBSIHVzaW5nIHRoZSBgREJJYCBhbmQgYFJTUUxpdGVgIHBhY2thZ2VzLiBUaGVzZSB0b29scyBhbGxvdyB1c2VycyB0byBleGVjdXRlIFNRTCBzdGF0ZW1lbnRzIGZyb20gUiBzY3JpcHRzIG9yIFIgTm90ZWJvb2tzLiBSIE5vdGVib29rcywgd2hpY2ggYXJlIHBhcnQgb2YgUiBNYXJrZG93biwgYWxzbyBzdXBwb3J0IFNRTCBjb2RlIGNodW5rcywgYWxsb3dpbmcgdXNlcnMgdG8gd3JpdGUgYW5kIGV4ZWN1dGUgU1FMIGRpcmVjdGx5IHdpdGhpbiBhIGRvY3VtZW50LgoKIyMjIFNRTCBpbiBSCgpSIHByb3ZpZGVzIGEgcHJvZ3JhbW1hdGljIHdheSB0byBleGVjdXRlIFNRTCBzdGF0ZW1lbnRzIHVzaW5nIHRoZSBgREJJYCBwYWNrYWdlLCB3aGljaCBhY3RzIGFzIGEgY29tbW9uIGludGVyZmFjZSBmb3IgZGF0YWJhc2UgY29ubmVjdGlvbnMsIGFuZCBgUlNRTGl0ZWAsIHdoaWNoIHByb3ZpZGVzIGFuIGltcGxlbWVudGF0aW9uIGZvciBTUUxpdGUuCgoqKlN0ZXAgMTogSW5zdGFsbCBhbmQgTG9hZCBOZWNlc3NhcnkgUGFja2FnZXMqKgoKSWYgdGhlIHJlcXVpcmVkIHBhY2thZ2VzIGFyZSBub3QgaW5zdGFsbGVkLCB0aGV5IG11c3QgYmUgaW5zdGFsbGVkIGZpcnN0LiBUbyBpbnN0YWxsIHBhY2thZ2VzIGluIFIgYXV0b21hdGljYWxseSBidXQgb25seSBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBpbnN0YWxsZWQsIHlvdSBjYW4gY2hlY2sgd2hldGhlciBhIHBhY2thZ2UgaXMgYXZhaWxhYmxlIHVzaW5nIHRoZSBgaW5zdGFsbGVkLnBhY2thZ2VzKClgIGZ1bmN0aW9uLiBJZiB0aGUgcGFja2FnZSBpcyBub3QgaW5zdGFsbGVkLCB5b3UgY2FuIGluc3RhbGwgaXQgdXNpbmcgYGluc3RhbGwucGFja2FnZXMoKWAuCgpUaGUgZm9sbG93aW5nIFIgY29kZSBlbnN1cmVzIHRoYXQgcmVxdWlyZWQgcGFja2FnZXMgYXJlIGluc3RhbGxlZCBiZWZvcmUgbG9hZGluZyB0aGVtOgoKYGBge3IsIGV2YWwgPSBGfQojIERlZmluZSBhIHZlY3RvciBvZiByZXF1aXJlZCBwYWNrYWdlcwpyZXF1aXJlZF9wYWNrYWdlcyA8LSBjKCJEQkkiLCAiUlNRTGl0ZSIpCgojIENoZWNrIGlmIGVhY2ggcGFja2FnZSBpcyBpbnN0YWxsZWQsIGFuZCBpbnN0YWxsIGl0IGlmIG5lY2Vzc2FyeQpmb3IgKHBrZyBpbiByZXF1aXJlZF9wYWNrYWdlcykgewogIGlmICghcGtnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCAiUGFja2FnZSJdKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHBrZywgcmVwb3MgPSAiaHR0cHM6Ly9jbG91ZC5yLXByb2plY3Qub3JnLyIpCiAgfQp9CmBgYAoKT25jZSB3ZSBhcmUgYXNzdXJlZCB0aGF0IHRoZSBwYWNrYWdlcyBhcmUgaW5zdGFsbGVkIGluIG91ciBsb2NhbCBSIGVudmlyb25tZW50LCB3ZSBuZWVkIHRvIGxvYWQgdGhlIHBhY2thZ2VzIGludG8gb3VyIFIgc2Vzc2lvbiB1c2luZyBlaXRoZXIgdGhlIGBsaWJyYXJ5KClgIG9yIHRoZSBgcmVxdWlyZSgpYCBmdW5jdGlvbnMuCgpgYGB7cn0KbGlicmFyeShEQkkpCmxpYnJhcnkoUlNRTGl0ZSkKYGBgCgoqKlN0ZXAgMi4gQ29ubmVjdCB0byBEYXRhYmFzZSoqCgpDcmVhdGluZyBhIG5ldyBkYXRhYmFzZSBpbiBTUUxpdGUgaXMgc2ltcGxlOiBqdXN0ICJjb25uZWN0IiB0byBhIG5vbi1leGlzdGluZyBkYXRhYmFzZS4gSWYgdGhlIGRhdGFiYXNlIGZpbGUgZG9lcyBub3QgZXhpc3QsIGl0IHdpbGwgY3JlYXRlIGEgbmV3IGRhdGFiYXNlIGZpbGUgaW4geW91ciBmaWxlIHN5c3RlbS4KCkluIFIsIHRoZSBSU1FMaXRlIHBhY2thZ2UgaXMgcmVxdWlyZWQgZm9yIGNvbm5lY3RpbmcgYW5kIHdvcmtpbmcgd2l0aCBTUUxpdGUgZGF0YWJhc2VzLiBUaGUgYGRiQ29ubmVjdCgpYCBmdW5jdGlvbiBjb25uZWN0cyB0byBhIGRhdGFiYXNlOyBvciBjcmVhdGVzIGl0IGlmIGl0IGRvZXNuJ3QgZXhpc3QuIFRoZSBSIGNvZGUgZnJhZ21lbnQgYmVsb3cgY3JlYXRlcyBhIG5ldyBkYXRhYmFzZS4KCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KIyBkZWxldGUgZGF0YWJhc2UgaW4gZmlsZSBwYXRpZW50REIuZGIKdW5saW5rKCJwYXRpZW50REIuZGIiKQp1bmxpbmsoImhlYWx0aGNhcmUuZGIiKQpgYGAKCmBgYHtyIGNyZWF0ZURCLCBlY2hvPVQsIGV2YWw9VH0KIyBsb2FkIHRoZSBuZWNlc3NhcnkgcGFja2FnZQpsaWJyYXJ5KFJTUUxpdGUpCgojIGNoYW5nZSB0aGlzIGNvZGUgdG8gY29ubmVjdCB0byB5b3VyIHNwZWNpZmljIGRhdGFiYXNlCmNvbm4gPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCAiaGVhbHRoY2FyZS5kYiIpCmBgYAoKQXMgYW4gYXNpZGUsIHRoZSBzcGVjaWFsIGRhdGFiYXNlICJmaWxlIG5hbWUiICoiOm1lbW9yeToiKiB3aWxsIGNyZWF0ZSBhIGRhdGFiYXNlIGluIG1lbW9yeS4gQW4gaW4tbWVtb3J5IGRhdGFiYXNlIGlzIGdyZWF0IGZvciBleHBsb3JhdGlvbiwgbGVhcm5pbmcsIHByb29mLW9mLWNvbmNlcHQgd29yaywgb3IgcXVpY2sgZXhwZXJpbWVudHMgYnV0IGl0IGlzIG5vdCBwZXJzaXN0ZW50IC0tIHdoZW4gdGhlIGNvbXB1dGVyIG9yIGFwcGxpY2F0aW9ucyBzaHV0cyBkb3duLCB0aGUgZGF0YSB3aWxsIGRpc2FwcGVhci4gV2hlbiB5b3UgbmVlZCBwZXJzaXN0ZW50IGRhdGEsIHVzZSBhIGZpbGUgb24gZGlzay4KCioqU3RlcCAzOiBFeGVjdXRlIGEgU1FMIFN0YXRlbWVudCoqCgpPbmNlIHlvdSBhcmUgY29ubmVjdGVkIHRvIHRoZSBkYXRhYmFzZSwgeW91IGNhbiBleGVjdXRlIFNRTCBzdGF0ZW1lbnRzIGZvciBxdWVyaWVzIG9yIHRvIGNyZWF0ZSBvciBtb2RpZnkgdGFibGVzIGFuZCBkYXRhIHVzaW5nIHRoZSBgZGJFeGVjdXRlKClgIGZ1bmN0aW9uLiBGb3IgZXhhbXBsZSwgdGhlIGNvZGUgYmVsb3cgaWxsdXN0cmF0ZXMgaG93IHRvIGNyZWF0ZSBhIGBQYXRpZW50c2AgdGFibGUgdXNpbmcgYW4gUiBmdW5jdGlvbi4gVGhpcyBhcHByb2FjaCB3aWxsIHdvcmsgZm9yIGJvdGggUiBTY3JpcHRzIChwcm9ncmFtcykgYW5kIGluIFIgTm90ZWJvb2tzIHdpdGhpbiBhbiBSIGNvZGUgY2h1bms6CgpgYGB7cn0Kc3RhdHVzIDwtIGRiRXhlY3V0ZShjb25uLCAiCiAgICBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBQYXRpZW50cyAoCiAgICAgICAgUGF0aWVudElEIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgICAgICBGaXJzdE5hbWUgVEVYVCBOT1QgTlVMTCwKICAgICAgICBMYXN0TmFtZSBURVhUIE5PVCBOVUxMLAogICAgICAgIERhdGVPZkJpcnRoIERBVEUgTk9UIE5VTEwsCiAgICAgICAgR2VuZGVyIFRFWFQgQ0hFQ0soR2VuZGVyIElOICgnTWFsZScsICdGZW1hbGUnLCAnT3RoZXInKSksCiAgICAgICAgQ29udGFjdE51bWJlciBURVhUIFVOSVFVRSwKICAgICAgICBFbWFpbCBURVhUIFVOSVFVRSwKICAgICAgICBBZGRyZXNzIFRFWFQsCiAgICAgICAgRW1lcmdlbmN5Q29udGFjdCBURVhULAogICAgICAgIEluc3VyYW5jZU51bWJlciBURVhUIFVOSVFVRSwKICAgICAgICBSZWdpc3RyYXRpb25EYXRlIFRJTUVTVEFNUCBERUZBVUxUIENVUlJFTlRfVElNRVNUQU1QCiAgICApOwoiKQpgYGAKClRoaXMgU1FMIHN0YXRlbWVudCBlbWJlZGRlZCB3aXRoIGFuIFIgZnVuY3Rpb24gY2FsbCBjcmVhdGVzIHRoZSBgUGF0aWVudHNgIHRhYmxlIHdpdGggY29uc3RyYWludHMgdG8gZW5zdXJlIGRhdGEgaW50ZWdyaXR5IC0tIHdlIHdpbGwgZXhwbGFpbiB0aGUgdmFyaW91cyBwYXJ0cyBvZiB0aGlzIHRhYmxlIGNyZWF0aW9uIHN0YXRlbWVudCBsYXRlciBpbiB0aGlzIGxlc3Nvbi4gTm90ZSB0aGUgZmlyc3QgYXJndW1lbnQgdG8gYGRiRXhlY3V0ZSgpYCBpcyB0aGUgZGF0YWJhc2UgY29ubmVjdGlvbiBvYmplY3QgdGhhdCB3YXMgcmV0dXJuZWQgZnJvbSB0aGUgY2FsbCB0byBgZGJDb25uZWN0KClgLgoKKipTdGVwIDQ6IFZlcmlmeSBUYWJsZSBDcmVhdGlvbioqCgpJdCBpcyBnb29kIHByYWN0aWNlLCB0byAidGVzdCIgdGhlIGNyZWF0aW9uIGNvZGUgYnkgbGlzdGluZyBhbGwgdGFibGVzIGluIHRoZSBkYXRhYmFzZS4gVGhpcyB3aWxsIGNvbmZpcm0gdGhhdCB0aGUgdGFibGUgd2FzIGNyZWF0ZWQuIFRoZSBEQkkgZnVuY3Rpb24gYGRiTGlzdFRhYmxlcygpYCB3aWxsIGxpc3QgdGhlIG5hbWVzIG9mIGFsbCB0YWJsZXMgcHJlc2VudCBpbiB0aGUgZGF0YWJhc2UgcmVmZXJlbmNlZCBieSBgY29ubmAuCgpgYGB7ciBldmFsID0gRn0KZGJMaXN0VGFibGVzKGNvbm4pCmBgYAoKSWYgc3VjY2Vzc2Z1bCwgdGhlIG91dHB1dCB3aWxsIGluY2x1ZGUgKiJQYXRpZW50cyIqLgoKKipTdGVwIDU6IENsb3NlIENvbm5lY3Rpb24qKgoKQWx3YXlzIGRpc2Nvbm5lY3QgZnJvbSB0aGUgZGF0YWJhc2Ugd2hlbiBkb25lIGV4ZWN1dGluZyBxdWVyaWVzIGluIG9yZGVyIHRvIGZyZWUgcmVzb3VyY2VzOgoKYGBge3J9CmRiRGlzY29ubmVjdChjb25uKQpgYGAKCiMjIyBTUUwgQ29kZSBDaHVua3MKClIgTm90ZWJvb2tzIChhIGZlYXR1cmUgb2YgUiBNYXJrZG93bikgYWxsb3cgZW1iZWRkaW5nIFNRTCBxdWVyaWVzIGRpcmVjdGx5IHVzaW5nIFNRTCBjaHVua3MuIFRoZXNlIFNRTCBjaHVua3MgZXhlY3V0ZSBxdWVyaWVzIGFnYWluc3QgYSBjb25uZWN0ZWQgZGF0YWJhc2Ugd2l0aG91dCByZXF1aXJpbmcgZXhwbGljaXQgZnVuY3Rpb24gY2FsbHMgaW4gUi4gSW4gZmFjdCwgZHVyaW5nIGtuaXR0aW5nIG9mIHRoZSBtYXJrZG93biwgdGhlIFNRTCBjb2RlIGNodW5rcyBhcmUgdHJhbnNsYXRlZCB0byBSIGZ1bmN0aW9uIGNhbGxzLCBzbyB0aGVyZSBpcyBubyBkaXNhZHZhbnRhZ2UgdG8gdXNpbmcgU1FMIGNvZGUgY2h1bmtzLgoKKipTdGVwIDE6IENyZWF0aW5nIGFuIFIgTm90ZWJvb2sgd2l0aCBTUUwgU3VwcG9ydCoqCgpJbiBSU3R1ZGlvLCBjcmVhdGUgYW4gKipSIE5vdGVib29rKiogKGAuUm1kYCBmaWxlKS4gSW5zaWRlIHRoZSBub3RlYm9vaywgYWRkIGEgc2V0dXAgY2h1bmsgdG8gZXN0YWJsaXNoIGEgY29ubmVjdGlvbjoKCiFbXShpbWFnZXMvci1jb2RlLWNodW5rLWNyZWF0ZS1kYi5wbmcpe3dpZHRoPSI1MCUifQoKYGBge3Igc2V0dXAsIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9CmxpYnJhcnkoREJJKQpsaWJyYXJ5KFJTUUxpdGUpCgojIENyZWF0ZSBhIGNvbm5lY3Rpb24gdG8gU1FMaXRlCmNvbm4gPC0gZGJDb25uZWN0KFNRTGl0ZSgpLCAicGF0aWVudERCLmRiIikKYGBgCgoqKlN0ZXAgMjogV3JpdGluZyBTUUwgQ29kZSBpbiBTUUwgQ29kZSBDaHVua3MqKgoKV2l0aGluIHRoZSBSIE5vdGVib29rLCBjcmVhdGUgYW4gU1FMIGNodW5rIHRvIGV4ZWN1dGUgU1FMIHN0YXRlbWVudHMuIFRoZSBjaHVuayBpcyBzcGVjaWZpZWQgdXNpbmc6CgohW10oaW1hZ2VzL3ItY29kZS1jaHVuay1leGVjLXNxbC5wbmcpe3dpZHRoPSI2MCUifQoKYGBge3NxbCBjcmVhdGVUYWJsZVBhdGllbnRzLCBjb25uZWN0aW9uID0gY29ubiwgZXZhbCA9IFQsIGVjaG8gPSBGfQpDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBQYXRpZW50cyAoCiAgICBQYXRpZW50SUQgSU5URUdFUiBQUklNQVJZIEtFWSBBVVRPSU5DUkVNRU5ULAogICAgRmlyc3ROYW1lIFRFWFQgTk9UIE5VTEwsCiAgICBMYXN0TmFtZSBURVhUIE5PVCBOVUxMLAogICAgRGF0ZU9mQmlydGggREFURSBOT1QgTlVMTCwKICAgIEdlbmRlciBURVhUIENIRUNLKEdlbmRlciBJTiAoJ01hbGUnLCAnRmVtYWxlJywgJ090aGVyJykpLAogICAgQ29udGFjdE51bWJlciBURVhUIFVOSVFVRSwKICAgIEVtYWlsIFRFWFQgVU5JUVVFLAogICAgQWRkcmVzcyBURVhULAogICAgRW1lcmdlbmN5Q29udGFjdCBURVhULAogICAgSW5zdXJhbmNlTnVtYmVyIFRFWFQgVU5JUVVFLAogICAgUmVnaXN0cmF0aW9uRGF0ZSBUSU1FU1RBTVAgREVGQVVMVCBDVVJSRU5UX1RJTUVTVEFNUAopOwpgYGAKCk5vdGUgdGhlIGNvZGUgY2h1bmsgcGFyYW1ldGVyICpjb25uZWN0aW9uKiBtdXN0IGJlIHNldCB0byB0aGUgZGF0YWJhc2UgY29ubmVjdGlvbiBvYmplY3QgcmV0dXJuZWQgZnJvbSBgZGJDb25uZWN0KClgLgoKQSBTUUwgY29kZSBjaHVuayBjYW4gb25seSBjb250YWluICoqb25lKiogU1FMIHN0YXRlbWVudCwgc28gdG8gY3JlYXRlIG11bHRpcGxlIHRhYmxlcywgeW91IG5lZWQgbXVsdGlwbGUgY29kZSBjaHVua3MsIG9uZSBwZXIgU1FMIHN0YXRlbWVudC4KClRoZSBzZW1pLWNvbG9uIGF0IHRoZSBlbmQgb2YgdGhlIFNRTCBzdGF0ZW1lbnQgaXMgY3VzdG9tYXJ5LCBidXQgbmVpdGhlciByZXF1aXJlZCBub3IgbmVjZXNzYXJ5IGFzIHdlIGNhbm5vdCBoYXZlIG11bHRpcGxlIFNRTCBzdGF0ZW1lbnRzLiBIZW5jZSwgbm8gc3RhdGVtZW50IHNlcGFyYXRvciBpcyBuZWVkZWQuCgoqKlN0ZXAgMzogUXVlcnlpbmcgdGhlIERhdGFiYXNlIGluIFNRTCBDaHVua3MqKgoKVG8gcmV0cmlldmUgZGF0YSBmcm9tIHRoZSBgUGF0aWVudHNgIHRhYmxlIGluIGFuIFIgTm90ZWJvb2ssIGFkZCBhbm90aGVyIFNRTCBjaHVuazoKCiFbXShpbWFnZXMvci1jb2RlLWNodW5rLWV4ZWMtc3FsLXF1ZXJ5LnBuZyl7d2lkdGg9IjUwJSJ9CgpgYGB7c3FsIGNvbm5lY3Rpb249Y29ubiwgZWNobyA9IEYsIGV2YWwgPSBUfQpTRUxFQ1QgKiBGUk9NIFBhdGllbnRzOwpgYGAKCkJ5IGRlZmF1bHQsIHRoZSByZXN1bHQgb2YgYW55IHF1ZXJ5IGZyb20gYSBTUUwgY29kZSBjaHVuayBpcyByZW5kZXJlZCBhcyBhIHRhYmxlIGluIHRoZSBrbml0dGVkIGRvY3VtZW50LiBIb3dldmVyLCBpdCBpcyBwb3NzaWJsZSB0byBjYXB0dXJlIHRoZSBxdWVyeSByZXN1bHQgc2V0IGluIGEgZGF0YWZyYW1lIHJhdGhlciB0aGFuIGhhdmluZyBpdCBkaXNwbGF5ZWQuCgpJZiB5b3Ugd2FudCB0byB1c2UgY29kZSBjaHVua3MgcmF0aGVyIHRoYW4gY2FsbGluZyBhbiBSIGZ1bmN0aW9uIHN1Y2ggYXMgYGRiR2V0UXVlcnkoKWAgdG8gcmV0cmlldmUgZGF0YSwgeW91IGNhbiBzdG9yZSB0aGUgcmVzdWx0IG9mIGFuIFNRTCBxdWVyeSBpbnRvIGFuIFIgZGF0YWZyYW1lIHVzaW5nIHRoZSBgb3V0cHV0LnZhcmAgb3B0aW9uIGluIGEgYHtzcWx9YCBjb2RlIGNodW5rLgoKIVtdKGltYWdlcy9yLWNvZGUtY2h1bmstY2FwdHVyZS1zcWwucG5nKXt3aWR0aD0iNzAlIn0KCmBgYHtzcWwgY29ubmVjdGlvbj1jb25uLCBvdXRwdXQudmFyPSJwYXRpZW50c19kZiIsIGV2YWw9RiwgZWNobz1GfQpTRUxFQ1QgKiBGUk9NIFBhdGllbnRzOwpgYGAKClRoZSBgb3V0cHV0LnZhcj0icGF0aWVudHNfZGYiYCBvcHRpb24gc3RvcmVzIHRoZSByZXN1bHQgb2YgdGhlIFNRTCBxdWVyeSBpbnRvIGFuIFIgZGF0YWZyYW1lIG5hbWVkIGBwYXRpZW50c19kZmAuCgpPbmNlIGV4ZWN1dGVkLCB0aGUgZGF0YWZyYW1lIGBwYXRpZW50c19kZmAgd2lsbCBiZSBhdmFpbGFibGUgaW4gdGhlIFIgZW52aXJvbm1lbnQgYW5kIGNhbiBiZSB1c2VkIGxpa2UgYW55IG90aGVyIFIgZGF0YWZyYW1lOgoKYGBge3IsIGV2YWw9RiwgZWNobz1UfQojIERpc3BsYXkgdGhlIGZpcnN0IGZldyByb3dzCmhlYWQocGF0aWVudHNfZGYpCmBgYAoKT2YgY291cnNlLCBpZiB5b3UgcHJlZmVyIHdvcmtpbmcgd2l0aCBzdGFuZGFyZCBSIGNvZGUgY2h1bmtzIChge3J9YCkgaW5zdGVhZCBvZiBge3NxbH1gIG9yIHlvdSBhcmUgYnVpbGRpbmcgUiBTY3JpcHRzIHJhdGhlciB0aGFuIFIgTm90ZWJvb2tzLCB5b3UgY2FuIGNhcHR1cmUgU1FMIHF1ZXJ5IHJlc3VsdHMgdXNpbmcgdGhlIGBkYkdldFF1ZXJ5KClgIGZ1bmN0aW9uIGZyb20gdGhlIGBEQklgIHBhY2thZ2UuCgpgYGB7ciBldmFsPUZ9CiMgUmV0cmlldmUgZGF0YSBmcm9tIFBhdGllbnRzIHRhYmxlCnBhdGllbnRzX2RmIDwtIGRiR2V0UXVlcnkoY29ubiwgIlNFTEVDVCAqIEZST00gUGF0aWVudHMiKQoKIyBWaWV3IHRoZSBmaXJzdCBmZXcgcm93cwpoZWFkKHBhdGllbnRzX2RmKQpgYGAKCiMjIyBTUUwgQ2h1bmtzIHZzIFIgRnVuY3Rpb25zCgp8ICoqTWV0aG9kKiogfCAqKlByb3MqKiB8ICoqQ29ucyoqIHwKfC0tLS18LS0tLXwtLS0tfAp8ICoqVXNpbmcgUiBGdW5jdGlvbnMgKGBkYkV4ZWN1dGUoKWApKiogfCBGdWxsIHByb2dyYW1tYXRpYyBjb250cm9sLCBjYW4gdXNlIGR5bmFtaWNhbGx5IGdlbmVyYXRlZCBTUUwgfCBSZXF1aXJlcyB3cml0aW5nIFNRTCB3aXRoaW4gUiBmdW5jdGlvbnMgfAp8ICoqVXNpbmcgU1FMIENvZGUgQ2h1bmtzIGluIFIgTm90ZWJvb2tzKiogfCBDbGVhbmVyIFNRTCBzeW50YXgsIGdvb2QgZm9yIGRvY3VtZW50YXRpb24sIGlubGluZSBleGVjdXRpb24gfCBMaW1pdGVkIHRvIHByZWRlZmluZWQgcXVlcmllcywgbGVzcyBkeW5hbWljLCBvbmx5IGluIFIgTm90ZWJvb2tzIHwKCiMjIENyZWF0aW5nIFRhYmxlcwoKVGhlIHByb2Nlc3Mgb2YgZGVmaW5pbmcgYSBkYXRhYmFzZSBzY2hlbWEgYmVnaW5zIHdpdGggdGhlIGBDUkVBVEUgVEFCTEVgIHN0YXRlbWVudC4gVGhpcyBzdGF0ZW1lbnQgY3JlYXRlcyBhIHRhYmxlIHdpdGggc3BlY2lmaWVkIGF0dHJpYnV0ZXMsIGVhY2ggd2l0aCBhIGRlc2lnbmF0ZWQgZGF0YSB0eXBlIGFuZCwgb3B0aW9uYWxseSwgY29uc3RyYWludHMgc3VjaCBhcyBwcmltYXJ5IGtleXMsIGZvcmVpZ24ga2V5cywgYW5kIHVuaXF1ZW5lc3MgY29uc3RyYWludHMuCgpDb25zaWRlciBhIGRhdGFiYXNlIGRlc2lnbmVkIHRvIG1hbmFnZSBwYXRpZW50IHJlY29yZHMgaW4gYSBob3NwaXRhbCBzZXR0aW5nLgoKVG8gY3JlYXRlIGEgdGFibGUgdG8gc3RvcmUgcGF0aWVudCBpbmZvcm1hdGlvbiwgdGhlIGZvbGxvd2luZyBTUUwgc3RhdGVtZW50IGNhbiBiZSBleGVjdXRlZCAoYXNzdW1pbmcgdGhhdCB0aGUgdGFibGUgZG9lcyBub3QgeWV0IGV4aXN0LCBvdGhlcndpc2UgZHJvcCBpdCBmaXJzdCk6CgpgYGB7c3FsIGNvbm5lY3Rpb249Y29ubiwgZWNobyA9IEZ9CkRST1AgVEFCTEUgSUYgRVhJU1RTIFBhdGllbnRzOwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1jb25ufQpDUkVBVEUgVEFCTEUgUGF0aWVudHMgKAogICAgUGF0aWVudElEIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgIEZpcnN0TmFtZSBURVhUIE5PVCBOVUxMLAogICAgTGFzdE5hbWUgVEVYVCBOT1QgTlVMTCwKICAgIERhdGVPZkJpcnRoIERBVEUgTk9UIE5VTEwsCiAgICBHZW5kZXIgVEVYVCBDSEVDSyhHZW5kZXIgSU4gKCdNYWxlJywgJ0ZlbWFsZScsICdPdGhlcicpKSwKICAgIENvbnRhY3ROdW1iZXIgVEVYVCBVTklRVUUsCiAgICBFbWFpbCBURVhUIFVOSVFVRSwKICAgIEFkZHJlc3MgVEVYVCwKICAgIEVtZXJnZW5jeUNvbnRhY3QgVEVYVCwKICAgIEluc3VyYW5jZU51bWJlciBURVhUIFVOSVFVRSwKICAgIFJlZ2lzdHJhdGlvbkRhdGUgVElNRVNUQU1QIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAKKTsKYGBgCgpUaGlzIGBQYXRpZW50c2AgdGFibGUgZGVmaW5lcyBtdWx0aXBsZSBhdHRyaWJ1dGVzIHRvIHN0b3JlIGVzc2VudGlhbCBwYXRpZW50IGluZm9ybWF0aW9uLiBUaGV5IGFyZSB0aGUgImNvbHVtbnMiIGluIHRoZSB0YWJsZS4KClRoZSBgUGF0aWVudElEYCBzZXJ2ZXMgYXMgdGhlIHByaW1hcnkga2V5IGFuZCBpcyBhdXRvbWF0aWNhbGx5IGluY3JlbWVudGVkIHdpdGggZWFjaCBuZXcgcmVjb3JkLiBQcmltYXJ5IGtleSB2YWx1ZXMgbXVzdCBiZSB1bmlxdWUgYW5kIHRoZSBkYXRhYmFzZSB3aWxsIG5vdCBhbGxvdyBhbnkgaW5zZXJ0aW9uIG9mIGR1cGxpY2F0ZSBwcmltYXJ5IGtleSB2YWx1ZXMuIE9mIGNvdXJzZSwgcmF0aGVyIHRoYW4gaGF2aW5nIHRoZSBkYXRhYmFzZSBwcm92aWRlIGEgcHJpbWFyeSBrZXkgdmFsdWUsIHlvdSBjYW4gcHJvdmlkZSB5b3VyIG93biB2YWx1ZSAtLSBqdXN0IG9tbWl0IHRoZSAqQVVUT0lOQ1JFTUVOVCouCgpUaGUgY29uc3RyYWludHMgZW5mb3JjZSBkYXRhIGludGVncml0eSBieSBlbnN1cmluZyB0aGF0IGNyaXRpY2FsIGZpZWxkcyBzdWNoIGFzIGBGaXJzdE5hbWVgLCBgTGFzdE5hbWVgLCBhbmQgYERhdGVPZkJpcnRoYCBhcmUgbm9uLW51bGwsICppLmUuKiBjYW5ub3QgYmUgbGVmdCBibGFuay4KClRoZSBgR2VuZGVyYCBmaWVsZCBpcyByZXN0cmljdGVkIHRvIHByZWRlZmluZWQgdmFsdWVzIHVzaW5nIHRoZSBgQ0hFQ0tgIGNvbnN0cmFpbnQgbWVjaGFuaXNtLCBhbmQgY29udGFjdCBkZXRhaWxzLCBpbmNsdWRpbmcgcGhvbmUgbnVtYmVyLCBlbWFpbCwgYW5kIGluc3VyYW5jZSBudW1iZXIsIGFyZSB1bmlxdWUgdG8gcHJldmVudCBkdXBsaWNhdGUgcmVjb3JkcyAtLSB0aGVzZSBhY3QgYXMgc28tY2FsbGVkICphbHRlcm5hdGUga2V5cyouCgpBZGRpdGlvbmFsbHksIHRoZSBgUmVnaXN0cmF0aW9uRGF0ZWAgY29sdW1uIGlzIHNldCB0byBzdG9yZSB0aGUgY3VycmVudCB0aW1lc3RhbXAgYnkgZGVmYXVsdCB3aGVuIGEgbmV3IHJlY29yZCBpcyBpbnNlcnRlZC4KClRvIHN0b3JlIG1lZGljYWwgcmVjb3JkcyBhc3NvY2lhdGVkIHdpdGggcGF0aWVudHMsIGFub3RoZXIgdGFibGUgY2FuIGJlIGNyZWF0ZWQgdG8gbWFpbnRhaW4gZGlhZ25vc2lzIGRldGFpbHM6CgpgYGB7c3FsIGNvbm5lY3Rpb249Y29ubn0KQ1JFQVRFIFRBQkxFIE1lZGljYWxSZWNvcmRzICgKICAgIFJlY29yZElEIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgIFBhdGllbnRJRCBJTlRFR0VSIE5PVCBOVUxMLAogICAgRGlhZ25vc2lzIFRFWFQgTk9UIE5VTEwsCiAgICBUcmVhdG1lbnQgVEVYVCwKICAgIFByZXNjcmliZWRNZWRpY2F0aW9ucyBURVhULAogICAgRGF0ZU9mVmlzaXQgVElNRVNUQU1QIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAsCiAgICBGT1JFSUdOIEtFWSAoUGF0aWVudElEKSBSRUZFUkVOQ0VTIFBhdGllbnRzKFBhdGllbnRJRCkgT04gREVMRVRFIENBU0NBREUKKTsKYGBgCgpUaGUgYE1lZGljYWxSZWNvcmRzYCB0YWJsZSBlc3RhYmxpc2hlcyBhIGZvcmVpZ24ga2V5IHJlbGF0aW9uc2hpcCB3aXRoIHRoZSBgUGF0aWVudHNgIHRhYmxlIHVzaW5nIHRoZSBgUGF0aWVudElEYCBmaWVsZC4gVGhpcyBlbnN1cmVzIHJlZmVyZW50aWFsIGludGVncml0eSBieSBsaW5raW5nIGVhY2ggbWVkaWNhbCByZWNvcmQgdG8gYSB2YWxpZCBwYXRpZW50LgoKVGhlIGBPTiBERUxFVEUgQ0FTQ0FERWAgY2xhdXNlIGVuc3VyZXMgdGhhdCB3aGVuIGEgcGF0aWVudCBpcyBkZWxldGVkLCB0aGVpciBjb3JyZXNwb25kaW5nIG1lZGljYWwgcmVjb3JkcyBhcmUgYWxzbyByZW1vdmVkIGZyb20gdGhlIGRhdGFiYXNlLCBwcmV2ZW50aW5nIG9ycGhhbmVkIHJlY29yZHMuCgojIyBGb3JlaWduIEtleSBDb25zdHJhaW50IEVuZm9yY2VtZW50CgpVbmxpa2Ugb3RoZXIgcmVsYXRpb25hbCBkYXRhYmFzZSBtYW5hZ2VtZW50IHN5c3RlbXMgKFJEQk1TKSBzdWNoIGFzIE15U1FMLCBQb3N0Z3JlU1FMLCBhbmQgU1FMIFNlcnZlciwgKipTUUxpdGUgZG9lcyBub3QgZW5mb3JjZSBmb3JlaWduIGtleSBjb25zdHJhaW50cyBieSBkZWZhdWx0KiouIFRoaXMgZGVzaWduIGNob2ljZSB3YXMgb3JpZ2luYWxseSBtYWRlIHRvIG1haW50YWluIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgd2l0aCBlYXJsaWVyIHZlcnNpb25zIG9mIFNRTGl0ZSwgd2hpY2ggZGlkIG5vdCBzdXBwb3J0IGZvcmVpZ24ga2V5IGNvbnN0cmFpbnRzIGF0IGFsbC4gQWRkaXRpb25hbGx5LCBub3QgY2hlY2tpbmcgZm9yZWlnbiBrZXkgY29uc3RyYWludHMgaW1wcm92ZXMgZGF0YSBpbnNlcnRpb24gYW5kIGRlbGV0aW9uIHBlcmZvcm1hbmNlLiBFbmZvcmNpbmcgZm9yZWlnbiBrZXkgY29uc3RyYWludHMgcmVxdWlyZXMgYWRkaXRpb25hbCBwcm9jZXNzaW5nIG92ZXJoZWFkLCB3aGljaCBjYW4gc2xpZ2h0bHkgaW1wYWN0IHBlcmZvcm1hbmNlLCBlc3BlY2lhbGx5IGluIGVtYmVkZGVkIHN5c3RlbXMgb3IgbGlnaHR3ZWlnaHQgYXBwbGljYXRpb25zIHdoZXJlIFNRTGl0ZSBpcyBjb21tb25seSB1c2VkLgoKU2luY2UgU1FMaXRlIGFpbXMgdG8gYmUgZmFzdCwgbGlnaHR3ZWlnaHQsIGFuZCBoaWdobHkgcG9ydGFibGUsIGZvcmVpZ24ga2V5IGVuZm9yY2VtZW50IHdhcyBkaXNhYmxlZCBieSBkZWZhdWx0IHRvIGF2b2lkIGJyZWFraW5nIGNvbXBhdGliaWxpdHkgd2l0aCBvbGRlciBhcHBsaWNhdGlvbnMgdGhhdCB3ZXJlIGRlc2lnbmVkIHdpdGhvdXQgZXhwZWN0aW5nIGNvbnN0cmFpbnQgZW5mb3JjZW1lbnQuCgo+IEZvciBhcHBsaWNhdGlvbnMgdGhhdCByZXF1aXJlIHN0cmljdCByZWZlcmVudGlhbCBpbnRlZ3JpdHksIGZvcmVpZ24ga2V5IGVuZm9yY2VtZW50ICoqbXVzdCBiZSBleHBsaWNpdGx5IGVuYWJsZWQqKiB1c2luZyB0aGUgYFBSQUdNQSBmb3JlaWduX2tleXMgPSBPTjtgIHN0YXRlbWVudC4KCiMjIyBFbmFibGluZyBGSyBDb25zdHJhaW50cyBpbiBTUUxpdGUKClRvIGVuZm9yY2UgZm9yZWlnbiBrZXkgY29uc3RyYWludHMgaW4gU1FMaXRlLCB5b3UgbXVzdCBlbmFibGUgZm9yZWlnbiBrZXkgZW5mb3JjZW1lbnQgKiplYWNoIHRpbWUgYSBkYXRhYmFzZSBjb25uZWN0aW9uIGlzIG9wZW5lZCoqLiBUaGlzIGlzIGRvbmUgdXNpbmcgdGhlIGBQUkFHTUEgZm9yZWlnbl9rZXlzID0gT047YCBzdGF0ZW1lbnQuCgpXaGVuIHVzaW5nIFNRTGl0ZSBmcm9tIHRoZSBjb21tYW5kIGxpbmUgb3IgYW4gU1FMIHNjcmlwdCwgeW91IGNhbiBlbmFibGUgZm9yZWlnbiBrZXkgY2hlY2tpbmcgYnkgcnVubmluZzoKCmBgYCBzcWwKUFJBR01BIGZvcmVpZ25fa2V5cyA9IE9OOwpgYGAKCkFmdGVyIGV4ZWN1dGluZyB0aGlzIHN0YXRlbWVudCwgU1FMaXRlIHdpbGwgZW5mb3JjZSBmb3JlaWduIGtleSBjb25zdHJhaW50cyBmb3IgdGhlIGR1cmF0aW9uIG9mIHRoZSBzZXNzaW9uLiBUaGlzIG1lYW5zIHRoYXQgYW55IGF0dGVtcHQgdG8gaW5zZXJ0LCB1cGRhdGUsIG9yIGRlbGV0ZSBhIHJlY29yZCB0aGF0IHZpb2xhdGVzIGEgZm9yZWlnbiBrZXkgY29uc3RyYWludCB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvci4KCkZvciBleGFtcGxlLCBjb25zaWRlciB0aGUgZm9sbG93aW5nIHNjaGVtYToKCmBgYCBzcWwKQ1JFQVRFIFRBQkxFIFBhdGllbnRzICgKICAgIFBhdGllbnRJRCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICBGaXJzdE5hbWUgVEVYVCBOT1QgTlVMTCwKICAgIExhc3ROYW1lIFRFWFQgTk9UIE5VTEwKKTsKCkNSRUFURSBUQUJMRSBNZWRpY2FsUmVjb3JkcyAoCiAgICBSZWNvcmRJRCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICBQYXRpZW50SUQgSU5URUdFUiBOT1QgTlVMTCwKICAgIERpYWdub3NpcyBURVhUIE5PVCBOVUxMLAogICAgRk9SRUlHTiBLRVkgKFBhdGllbnRJRCkgUkVGRVJFTkNFUyBQYXRpZW50cyhQYXRpZW50SUQpCik7CmBgYAoKSWYgYFBSQUdNQSBmb3JlaWduX2tleXMgPSBPTjtgIGlzIG5vdCBzZXQsIHlvdSBjYW4gaW5zZXJ0IGEgcmVjb3JkIGludG8gYE1lZGljYWxSZWNvcmRzYCByZWZlcmVuY2luZyBhIG5vbi1leGlzdGVudCAqUGF0aWVudElEKiwgYW5kIFNRTGl0ZSB3aWxsIGFsbG93IGl0OgoKYGBgIHNxbApJTlNFUlQgSU5UTyBNZWRpY2FsUmVjb3JkcyAoUGF0aWVudElELCBEaWFnbm9zaXMpIFZBTFVFUyAoOTk5LCAnSHlwZXJ0ZW5zaW9uJyk7CmBgYAoKSG93ZXZlciwgaWYgZm9yZWlnbiBrZXkgZW5mb3JjZW1lbnQgaXMgZW5hYmxlZCwgU1FMaXRlIHdpbGwgcmVqZWN0IHRoZSBpbnNlcnQgc3RhdGVtZW50IHdpdGggYW4gZXJyb3I6CgpgYGAgICAgICAgICAKRXJyb3I6IEZPUkVJR04gS0VZIGNvbnN0cmFpbnQgZmFpbGVkCmBgYAoKIyMjIyBFbmFibGluZyBGb3JlaWduIEtleSBDb25zdHJhaW50cyBpbiBSCgpJZiB5b3UgYXJlIHdvcmtpbmcgd2l0aCBTUUxpdGUgaW4gUiB1c2luZyB0aGUgYERCSWAgYW5kIGBSU1FMaXRlYCBwYWNrYWdlcywgeW91IG11c3QgZXhwbGljaXRseSBlbmFibGUgZm9yZWlnbiBrZXkgc3VwcG9ydCBlYWNoIHRpbWUgYSBjb25uZWN0aW9uIGlzIGVzdGFibGlzaGVkLgoKYGBge3J9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoREJJKQpsaWJyYXJ5KFJTUUxpdGUpCgojIEVzdGFibGlzaCBhIGNvbm5lY3Rpb24gdG8gdGhlIFNRTGl0ZSBkYXRhYmFzZQpjb25uIDwtIGRiQ29ubmVjdChTUUxpdGUoKSwgImJlZERCLmRiIikKCiMgRW5hYmxlIGZvcmVpZ24ga2V5IGNvbnN0cmFpbnQgZW5mb3JjZW1lbnQKZGJFeGVjdXRlKGNvbm4sICJQUkFHTUEgZm9yZWlnbl9rZXlzID0gT047IikKCiMgTm93IGV4ZWN1dGUgU1FMIHN0YXRlbWVudHMgd2l0aCBmb3JlaWduIGtleSBjb25zdHJhaW50cyBlbmZvcmNlZAoKIyBXaGVuIGRvbmUgd2l0aCB0aGUgZGF0YWJhc2UgY2xvc2UgdGhlIGNvbm5lY3Rpb24KZGJEaXNjb25uZWN0KGNvbm4pCmBgYAoKV2l0aG91dCBzZXR0aW5nIGBQUkFHTUEgZm9yZWlnbl9rZXlzID0gT047YCwgZm9yZWlnbiBrZXkgY29uc3RyYWludHMgd2lsbCAqKm5vdCoqIGJlIGVuZm9yY2VkIGluIHRoZSBSIHNlc3Npb24sIGFuZCBpbnZhbGlkIHJlZmVyZW5jZXMgdG8gZm9yZWlnbiBrZXlzIHdpbGwgYmUgYWxsb3dlZC4KCiMjIyMgRW5hYmxpbmcgRm9yZWlnbiBLZXkgQ29uc3RyYWludHMgaW4gYSBQZXJzaXN0ZW50IFdheQoKU1FMaXRlIGRvZXMgKipub3QqKiBhbGxvdyBmb3JlaWduIGtleSBlbmZvcmNlbWVudCB0byBiZSBzZXQgcGVyc2lzdGVudGx5IGFjcm9zcyBhbGwgc2Vzc2lvbnMgKHVubGlrZSBzb21lIGRhdGFiYXNlIHN5c3RlbXMgd2hlcmUgZm9yZWlnbiBrZXkgY29uc3RyYWludHMgYXJlIGFsd2F5cyBlbmZvcmNlZCBvbmNlIGNvbmZpZ3VyZWQpLiBUaGUgZW5mb3JjZW1lbnQgc2V0dGluZyBtdXN0IGJlIGVuYWJsZWQgZXZlcnkgdGltZSBhIGRhdGFiYXNlIGNvbm5lY3Rpb24gaXMgZXN0YWJsaXNoZWQuCgpIb3dldmVyLCBpbiBhcHBsaWNhdGlvbnMgdGhhdCByZXBlYXRlZGx5IG9wZW4gYW5kIGNsb3NlIGRhdGFiYXNlIGNvbm5lY3Rpb25zICgqZS5nLiosIHdlYiBhcHBsaWNhdGlvbnMpLCBhIGJlc3QgcHJhY3RpY2UgaXMgdG8gZXhlY3V0ZSBgUFJBR01BIGZvcmVpZ25fa2V5cyA9IE9OO2AgaW1tZWRpYXRlbHkgYWZ0ZXIgb3BlbmluZyBhIGNvbm5lY3Rpb24uCgojIyMjIFZlcmlmeWluZyBXaGV0aGVyIEZvcmVpZ24gS2V5IENvbnN0cmFpbnRzIEFyZSBFbmFibGVkCgpUbyBjaGVjayBpZiBmb3JlaWduIGtleSBlbmZvcmNlbWVudCBpcyBlbmFibGVkIGluIHRoZSBjdXJyZW50IFNRTGl0ZSBzZXNzaW9uLCBydW46CgpgYGAgc3FsClBSQUdNQSBmb3JlaWduX2tleXM7CmBgYAoKSWYgZW5mb3JjZW1lbnQgaXMgZW5hYmxlZCwgU1FMaXRlIHdpbGwgcmV0dXJuOgoKYGBgICAgICAgICAgCjEKYGBgCgpJZiBmb3JlaWduIGtleSBlbmZvcmNlbWVudCBpcyBkaXNhYmxlZCwgaXQgd2lsbCByZXR1cm46CgpgYGAgICAgICAgICAKMApgYGAKCkluIHNob3J0LCBTUUxpdGUgZG9lcyBub3QgZW5mb3JjZSBmb3JlaWduIGtleSBjb25zdHJhaW50cyBieSBkZWZhdWx0IHRvIG1haW50YWluIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgYW5kIGltcHJvdmUgcGVyZm9ybWFuY2UuIEhvd2V2ZXIsIGlmIHJlZmVyZW50aWFsIGludGVncml0eSBpcyByZXF1aXJlZCwgeW91IG11c3QgZXhwbGljaXRseSBlbmFibGUgZW5mb3JjZW1lbnQgdXNpbmcgYFBSQUdNQSBmb3JlaWduX2tleXMgPSBPTjtgIGV2ZXJ5IHRpbWUgYSBkYXRhYmFzZSBjb25uZWN0aW9uIGlzIG9wZW5lZC4gSW4gYXBwbGljYXRpb25zIHVzaW5nIFNRTGl0ZSwgc3VjaCBhcyBSIGFuZCBQeXRob24gcHJvZ3JhbXMsIGVuc3VyaW5nIHRoYXQgdGhpcyBgUFJBR01BYCBzdGF0ZW1lbnQgaXMgZXhlY3V0ZWQgYWZ0ZXIgZXN0YWJsaXNoaW5nIGEgY29ubmVjdGlvbiBpcyBlc3NlbnRpYWwgZm9yIG1haW50YWluaW5nIGRhdGFiYXNlIGNvbnNpc3RlbmN5LgoKTm90ZSB0aGF0IG1vc3Qgb3RoZXIgZGF0YWJhc2VzLCBzdWNoIGFzIE15U1FMLCBlbmZvcmNlIHJlZmVyZW50aWFsIGludGVncml0eSBjb25zdHJhaW50cyBieSBkZWZhdWx0IHVubGVzcyB5b3UgZXhwbGljaXRseSBkaXNhYmxlIGNoZWNraW5nIHdoZW4gbmVjZXNzYXJ5IGR1cmluZyBidWxrIGxvYWRpbmcgb2YgZGF0YSB3aGVuIGNoZWNraW5nIHdvdWxkIGNhdXNlIHNpZ25pZmljYW50IHBlcmZvcm1hbmNlIGlzc3Vlcy4KCiMjIEV4aXN0aW5nIFRhYmxlcwoKSWYgeW91IGF0dGVtcHQgdG8gY3JlYXRlIGEgdGFibGUgaW4gdGhhdCBhbHJlYWR5IGV4aXN0cywgdGhlIGRhdGFiYXNlIGVuZ2luZSB3aWxsIHJldHVybiBhbiBlcnJvciwgcHJldmVudGluZyBkdXBsaWNhdGlvbi4gSG93ZXZlciwgU1FMIHByb3ZpZGVzIGEgc2FmZWd1YXJkIHRvIGhhbmRsZSBzdWNoIHNpdHVhdGlvbnMgd2l0aCB0aGUgYElGIE5PVCBFWElTVFNgIGNsYXVzZSBpbiB0aGUgYENSRUFURSBUQUJMRWAgc3RhdGVtZW50LiBUaGlzIGNsYXVzZSBlbnN1cmVzIHRoYXQgdGhlIHRhYmxlIGlzIG9ubHkgY3JlYXRlZCBpZiBpdCBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0LgoKQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBleGFtcGxlLCB3aGVyZSBhIGhvc3BpdGFsIGRhdGFiYXNlIGlzIGJlaW5nIGRlc2lnbmVkIHRvIHN0b3JlIHBhdGllbnQgcmVjb3JkczoKCmBgYCBzcWwKQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgUGF0aWVudHMgKAogICAgUGF0aWVudElEIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgIEZpcnN0TmFtZSBURVhUIE5PVCBOVUxMLAogICAgTGFzdE5hbWUgVEVYVCBOT1QgTlVMTCwKICAgIERhdGVPZkJpcnRoIERBVEUgTk9UIE5VTEwsCiAgICBHZW5kZXIgVEVYVCBDSEVDSyhHZW5kZXIgSU4gKCdNYWxlJywgJ0ZlbWFsZScsICdPdGhlcicpKSwKICAgIENvbnRhY3ROdW1iZXIgVEVYVCBVTklRVUUsCiAgICBFbWFpbCBURVhUIFVOSVFVRSwKICAgIEFkZHJlc3MgVEVYVCwKICAgIEVtZXJnZW5jeUNvbnRhY3QgVEVYVCwKICAgIEluc3VyYW5jZU51bWJlciBURVhUIFVOSVFVRSwKICAgIFJlZ2lzdHJhdGlvbkRhdGUgVElNRVNUQU1QIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAKKTsKYGBgCgpJbiB0aGlzIGNhc2UsIGlmIHRoZSBgUGF0aWVudHNgIHRhYmxlIGFscmVhZHkgZXhpc3RzLCBTUUxpdGUgd2lsbCBub3QgY3JlYXRlIGEgbmV3IG9uZSwgcHJldmVudGluZyBhbiBlcnJvciBmcm9tIG9jY3VycmluZy4gSW5zdGVhZCwgdGhlIGRhdGFiYXNlIHdpbGwgc2ltcGx5IGlnbm9yZSB0aGUgY29tbWFuZC4KCklmIHRoZSBgSUYgTk9UIEVYSVNUU2AgY2xhdXNlIGlzIG9taXR0ZWQgYW5kIHRoZSB0YWJsZSBhbHJlYWR5IGV4aXN0cywgYXR0ZW1wdGluZyB0byBleGVjdXRlIHRoZSBmb2xsb3dpbmcgc3RhdGVtZW50OgoKYGBgIHNxbApDUkVBVEUgVEFCTEUgUGF0aWVudHMgKAogICAgUGF0aWVudElEIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgIEZpcnN0TmFtZSBURVhUIE5PVCBOVUxMLAogICAgTGFzdE5hbWUgVEVYVCBOT1QgTlVMTCwKICAgIERhdGVPZkJpcnRoIERBVEUgTk9UIE5VTEwsCiAgICBHZW5kZXIgVEVYVCBDSEVDSyhHZW5kZXIgSU4gKCdNYWxlJywgJ0ZlbWFsZScsICdPdGhlcicpKSwKICAgIENvbnRhY3ROdW1iZXIgVEVYVCBVTklRVUUsCiAgICBFbWFpbCBURVhUIFVOSVFVRSwKICAgIEFkZHJlc3MgVEVYVCwKICAgIEVtZXJnZW5jeUNvbnRhY3QgVEVYVCwKICAgIEluc3VyYW5jZU51bWJlciBURVhUIFVOSVFVRSwKICAgIFJlZ2lzdHJhdGlvbkRhdGUgVElNRVNUQU1QIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAKKTsKYGBgCgp3aWxsIHJlc3VsdCBpbiBhbiBlcnJvciBzaW1pbGFyIHRvOgoKYGBgIHRleHQKRXJyb3I6IHRhYmxlIFBhdGllbnRzIGFscmVhZHkgZXhpc3RzCmBgYAoKVGhpcyBjYW4gYmUgcHJvYmxlbWF0aWMgaW4gc2NlbmFyaW9zIHdoZXJlIGF1dG9tYXRlZCBwcm9jZXNzZXMgYXR0ZW1wdCB0byBjcmVhdGUgdGFibGVzIHdpdGhvdXQgcHJpb3Iga25vd2xlZGdlIG9mIHRoZWlyIGV4aXN0ZW5jZS4KCiMjIyBDaGVja2luZyBUYWJsZSBFeGlzdGVuY2UKCklmIGdyZWF0ZXIgY29udHJvbCBvdmVyIHRoZSBleGlzdGVuY2UgY2hlY2sgaXMgcmVxdWlyZWQsIGFuIGFsdGVybmF0aXZlIGFwcHJvYWNoIGludm9sdmVzIHF1ZXJ5aW5nIHRoZSBTUUxpdGUgYHNxbGl0ZV9tYXN0ZXJgIHN5c3RlbSB0YWJsZS4gVGhlIGBzcWxpdGVfbWFzdGVyYCB0YWJsZSBjb250YWlucyBtZXRhZGF0YSBhYm91dCBhbGwgZGF0YWJhc2Ugb2JqZWN0cywgaW5jbHVkaW5nIHRhYmxlcy4gVG8gY2hlY2sgZm9yIHRoZSBleGlzdGVuY2Ugb2YgYSBzcGVjaWZpYyB0YWJsZSwgdGhlIGZvbGxvd2luZyBTUUwgcXVlcnkgY2FuIGJlIHVzZWQ6CgpgYGAgc3FsClNFTEVDVCBuYW1lIEZST00gc3FsaXRlX21hc3RlciBXSEVSRSB0eXBlPSd0YWJsZScgQU5EIG5hbWU9J1BhdGllbnRzJzsKYGBgCgpJZiB0aGlzIHF1ZXJ5IHJldHVybnMgYSByZXN1bHQsIGl0IGluZGljYXRlcyB0aGF0IHRoZSBgUGF0aWVudHNgIHRhYmxlIGFscmVhZHkgZXhpc3RzLiBUaGlzIG1ldGhvZCBjYW4gYmUgaW5jb3Jwb3JhdGVkIGludG8gYXBwbGljYXRpb24gbG9naWMgb3IgZGF0YWJhc2Ugc2NyaXB0cyB0byBkZXRlcm1pbmUgd2hldGhlciBhIHRhYmxlIHNob3VsZCBiZSBjcmVhdGVkIGR5bmFtaWNhbGx5LgoKV2UgcmVjb21tZW5kIHRoYXQgd2hlbiBjcmVhdGluZyB0YWJsZXMgdG8gdXNlIGBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUU2AgdG8gcHJldmVudCBlcnJvcnMgd2hlbiBkZWZpbmluZyB0YWJsZXMgdGhhdCBtYXkgYWxyZWFkeSBleGlzdC4gRm9yIGNhc2VzIHdoZXJlIG1vcmUgZGV0YWlsZWQgY2hlY2tpbmcgaXMgbmVlZGVkLCBxdWVyeWluZyBgc3FsaXRlX21hc3RlcmAgY2FuIHByb3ZpZGUgaW5zaWdodCBpbnRvIHRoZSBkYXRhYmFzZSBzY2hlbWEuIFRoZXNlIHN0cmF0ZWdpZXMgaGVscCBtYWludGFpbiByb2J1c3RuZXNzIGluIGRhdGFiYXNlIGRlc2lnbiwgZXNwZWNpYWxseSBpbiBkeW5hbWljIG9yIGF1dG9tYXRlZCBlbnZpcm9ubWVudHMgc3VjaCBhcyBoZWFsdGhjYXJlIGluZm9ybWF0aW9uIHN5c3RlbXMgd2hlcmUgc2NoZW1hIGRlZmluaXRpb25zIG1heSBiZSBleGVjdXRlZCBtdWx0aXBsZSB0aW1lcy4KCiMjIEFsdGVyaW5nIFRhYmxlcwoKTW9kaWZ5aW5nIGFuIGV4aXN0aW5nIHRhYmxlIGlzIGEgZnJlcXVlbnQgcmVxdWlyZW1lbnQgYXMgZGF0YWJhc2Ugc2NoZW1hcyBldm9sdmUuIFNRTCBwcm92aWRlcyB0aGUgYEFMVEVSIFRBQkxFYCBzdGF0ZW1lbnQgdG8gZmFjaWxpdGF0ZSBzdWNoIG1vZGlmaWNhdGlvbnMuCgpVbmxpa2UgbW9yZSBmZWF0dXJlLXJpY2ggZGF0YWJhc2UgbWFuYWdlbWVudCBzeXN0ZW1zIHN1Y2ggYXMgUG9zdGdyZVNRTCBvciBNeVNRTCwgU1FMaXRl4oCZcyBgQUxURVIgVEFCTEVgIGNhcGFiaWxpdGllcyBhcmUgbGltaXRlZCB0byBhZGRpbmcgbmV3IGNvbHVtbnMsIHJlbmFtaW5nIGV4aXN0aW5nIGNvbHVtbnMsIGFuZCByZW5hbWluZyB0YWJsZXMuCgpTdXBwb3NlIHRoZSBob3NwaXRhbCBhZG1pbmlzdHJhdGlvbiBkZWNpZGVzIHRvIHRyYWNrIHBhdGllbnRz4oCZIGJsb29kIHR5cGVzIGFuZCBhbGxlcmdpZXMuIFRvIGFjY29tbW9kYXRlIHRoaXMgY2hhbmdlLCB0aGUgc2NoZW1hIGNhbiBiZSB1cGRhdGVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgU1FMIHN0YXRlbWVudHM6CgpgYGAgc3FsCkFMVEVSIFRBQkxFIFBhdGllbnRzIEFERCBDT0xVTU4gQmxvb2RUeXBlIFRFWFQgQ0hFQ0soQmxvb2RUeXBlIElOICgnQSsnLCAnQS0nLCAnQisnLCAnQi0nLCAnQUIrJywgJ0FCLScsICdPKycsICdPLScpKTsKQUxURVIgVEFCTEUgUGF0aWVudHMgQUREIENPTFVNTiBBbGxlcmdpZXMgVEVYVDsKYGBgCgpUaGVzZSBzdGF0ZW1lbnRzIGFkZCB0aGUgYEJsb29kVHlwZWAgY29sdW1uIHdpdGggYSBgQ0hFQ0tgIGNvbnN0cmFpbnQgdG8gcmVzdHJpY3QgdmFsdWVzIHRvIG1lZGljYWxseSB2YWxpZCBibG9vZCB0eXBlcyBhbmQgYW4gYEFsbGVyZ2llc2AgY29sdW1uIHRvIHN0b3JlIGFueSBrbm93biBhbGxlcmdpZXMuCgpBZGRpdGlvbmFsbHksIGlmIHRoZXJlIGlzIGEgbmVlZCB0byByZW5hbWUgdGhlIGBNZWRpY2FsUmVjb3Jkc2AgdGFibGUgdG8gYFBhdGllbnRNZWRpY2FsUmVjb3Jkc2AgZm9yIGNsYXJpdHksIHRoaXMgY2FuIGJlIGFjaGlldmVkIHdpdGg6CgpgYGAgc3FsCkFMVEVSIFRBQkxFIE1lZGljYWxSZWNvcmRzIFJFTkFNRSBUTyBQYXRpZW50TWVkaWNhbFJlY29yZHM7CmBgYAoKTm90ZSB0aGF0IFNRTGl0ZSBkb2VzIG5vdCBzdXBwb3J0IGRpcmVjdGx5IGRyb3BwaW5nIG9yIG1vZGlmeWluZyBjb2x1bW5zLiBJZiBhIGNvbHVtbiBuZWVkcyB0byBiZSByZW1vdmVkLCB0aGUgcmVjb21tZW5kZWQgYXBwcm9hY2ggaXMgdG8gY3JlYXRlIGEgbmV3IHRhYmxlIHdpdGggdGhlIGRlc2lyZWQgc2NoZW1hLCBtaWdyYXRlIGV4aXN0aW5nIGRhdGEsIGFuZCB0aGVuIHJlbmFtZSB0aGUgbmV3IHRhYmxlIHRvIG1hdGNoIHRoZSBvcmlnaW5hbCB0YWJsZeKAmXMgbmFtZS4KCiMjIERlbGV0aW5nIFRhYmxlcwoKSWYgYSB0YWJsZSBpcyBubyBsb25nZXIgbmVlZGVkLCBpdCBjYW4gYmUgcGVybWFuZW50bHkgcmVtb3ZlZCB1c2luZyB0aGUgYERST1AgVEFCTEVgIHN0YXRlbWVudC4gU3VwcG9zZSB0aGUgaG9zcGl0YWwgZGVjaWRlcyB0byBkaXNjb250aW51ZSBtYWludGFpbmluZyBjZXJ0YWluIG9sZCByZWNvcmRzLCBzdWNoIGFzIG1lZGljYWwgcmVjb3JkcyB0aGF0IGFyZSBubyBsb25nZXIgcmVxdWlyZWQgZm9yIGFyY2hpdmFsIHB1cnBvc2VzLiBUbyByZW1vdmUgdGhlIGBQYXRpZW50TWVkaWNhbFJlY29yZHNgIHRhYmxlIGVudGlyZWx5LCB0aGUgZm9sbG93aW5nIFNRTCBjb21tYW5kIGNhbiBiZSBleGVjdXRlZDoKCmBgYCBzcWwKRFJPUCBUQUJMRSBQYXRpZW50TWVkaWNhbFJlY29yZHM7CmBgYAoKRXhlY3V0aW5nIHRoaXMgY29tbWFuZCBpcnJldmVyc2libHkgZGVsZXRlcyB0aGUgdGFibGUgYW5kIGFsbCBpdHMgc3RvcmVkIGRhdGEuIElmIHRoZSB0YWJsZSBoYXMgZGVwZW5kZW5jaWVzLCBzdWNoIGFzIGZvcmVpZ24ga2V5cyBpbiBvdGhlciB0YWJsZXMsIHRoZSBkZWxldGlvbiBtYXkgZmFpbCB1bmxlc3MgY2FzY2FkaW5nIGNvbnN0cmFpbnRzIHdlcmUgcHJlZGVmaW5lZC4KCkZvciBjYXNlcyB3aGVyZSBkYXRhIG5lZWRzIHRvIGJlIHJlbW92ZWQgd2hpbGUgcmV0YWluaW5nIHRoZSB0YWJsZSBzdHJ1Y3R1cmUsIHVzaW5nIHRoZSBgREVMRVRFIEZST01gIHN0YXRlbWVudCB3aXRob3V0IGEgYFdIRVJFYCBjbGF1c2UgaXMgYSBwcmVmZXJhYmxlIGFsdGVybmF0aXZlOgoKYGBgIHNxbApERUxFVEUgRlJPTSBQYXRpZW50czsKYGBgCgpUaGlzIGNvbW1hbmQgcmVtb3ZlcyBhbGwgcmVjb3JkcyBmcm9tIHRoZSBgUGF0aWVudHNgIHRhYmxlIHdoaWxlIGtlZXBpbmcgaXRzIHN0cnVjdHVyZSBpbnRhY3QgZm9yIGZ1dHVyZSBkYXRhIGluc2VydGlvbi4KCiMjIERhdGFiYXNlIFNjcmlwdHMKCkluIHByYWN0aWNlLCBkYXRhYmFzZSBzY3JpcHRzIGFyZSB1c2VkIHRvIGF1dG9tYXRlIHRoZSBwcm9jZXNzIG9mIGRlZmluaW5nIGEgZGF0YWJhc2Ugc2NoZW1hLCBlbnN1cmluZyB0aGF0IHRhYmxlcywgY29uc3RyYWludHMsIGFuZCByZWxhdGlvbnNoaXBzIGFyZSBlc3RhYmxpc2hlZCBjb25zaXN0ZW50bHkuIFRoZXNlIHNjcmlwdHMgYXJlIHR5cGljYWxseSB3cml0dGVuIGluIFNRTCBhbmQgZXhlY3V0ZWQgYXMgcGFydCBvZiBhbiBhcHBsaWNhdGlvbuKAmXMgc2V0dXAgcHJvY2VzcyBvciBkdXJpbmcgZGF0YWJhc2UgbWlncmF0aW9ucy4KCkEgU1FMIHNjcmlwdCBpcyBzaW1wbHkgYSB0ZXh0IGZpbGUgY29udGFpbmluZyBTUUwgY29tbWFuZHMgc2VwYXJhdGVkIGJ5IHNlbWktY29sb25zLgoKRm9yIFNRTGl0ZSwgZGF0YWJhc2Ugc2NyaXB0cyBhcmUgY29tbW9ubHkgc3RvcmVkIGluIGAuc3FsYCB0ZXh0IGZpbGVzIGFuZCBleGVjdXRlZCB1c2luZyB0aGUgU1FMaXRlIGNvbW1hbmQtbGluZSBpbnRlcmZhY2UgKGBzcWxpdGUzYCksIHByb2dyYW1tYXRpY2FsbHkgdGhyb3VnaCBhIGRhdGFiYXNlIGNvbm5lY3Rpb24gaW4gYSBsYW5ndWFnZSBsaWtlIFB5dGhvbiwgb3Igd2l0aGluIGEgZGF0YWJhc2UgbWFuYWdlbWVudCB0b29sLgoKQmVsb3cgaXMgYSBzYW1wbGUgU1FMIHNjcmlwdCAoYGhlYWx0aGNhcmVfc2NoZW1hLnNxbGApIGRlc2lnbmVkIHRvIGNyZWF0ZSBhIGRhdGFiYXNlIHNjaGVtYSBmb3IgYSBob3NwaXRhbCBtYW5hZ2VtZW50IHN5c3RlbS4gSXQgaW5jbHVkZXMgdGFibGVzIGZvciBzdG9yaW5nIHBhdGllbnQgaW5mb3JtYXRpb24sIG1lZGljYWwgcmVjb3JkcywgYW5kIGRvY3RvciBkZXRhaWxzLiBUaGUgLS0gaXMgYSBjb21tZW50IHRoYXQgaXMgaWdub3JlZC4KCioqQ29udGVudHMgb2YgRmlsZSBgaGVhbHRoY2FyZV9zY2hlbWEuc3FsYCoqCgpgYGAgc3FsCi0tIEVuYWJsZSBmb3JlaWduIGtleSBjb25zdHJhaW50cyAoaW1wb3J0YW50IGZvciBTUUxpdGUpClBSQUdNQSBmb3JlaWduX2tleXMgPSBPTjsKCi0tIENyZWF0ZSBQYXRpZW50cyB0YWJsZQpDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBQYXRpZW50cyAoCiAgICBQYXRpZW50SUQgSU5URUdFUiBQUklNQVJZIEtFWSBBVVRPSU5DUkVNRU5ULAogICAgRmlyc3ROYW1lIFRFWFQgTk9UIE5VTEwsCiAgICBMYXN0TmFtZSBURVhUIE5PVCBOVUxMLAogICAgRGF0ZU9mQmlydGggREFURSBOT1QgTlVMTCwKICAgIEdlbmRlciBURVhUIENIRUNLKEdlbmRlciBJTiAoJ01hbGUnLCAnRmVtYWxlJywgJ090aGVyJykpLAogICAgQ29udGFjdE51bWJlciBURVhUIFVOSVFVRSwKICAgIEVtYWlsIFRFWFQgVU5JUVVFLAogICAgQWRkcmVzcyBURVhULAogICAgRW1lcmdlbmN5Q29udGFjdCBURVhULAogICAgSW5zdXJhbmNlTnVtYmVyIFRFWFQgVU5JUVVFLAogICAgUmVnaXN0cmF0aW9uRGF0ZSBUSU1FU1RBTVAgREVGQVVMVCBDVVJSRU5UX1RJTUVTVEFNUAopOwoKLS0gQ3JlYXRlIERvY3RvcnMgdGFibGUKQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgRG9jdG9ycyAoCiAgICBEb2N0b3JJRCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICBGaXJzdE5hbWUgVEVYVCBOT1QgTlVMTCwKICAgIExhc3ROYW1lIFRFWFQgTk9UIE5VTEwsCiAgICBTcGVjaWFsaXphdGlvbiBURVhUIE5PVCBOVUxMLAogICAgQ29udGFjdE51bWJlciBURVhUIFVOSVFVRSwKICAgIEVtYWlsIFRFWFQgVU5JUVVFCik7CgotLSBDcmVhdGUgTWVkaWNhbFJlY29yZHMgdGFibGUKQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgTWVkaWNhbFJlY29yZHMgKAogICAgUmVjb3JkSUQgSU5URUdFUiBQUklNQVJZIEtFWSBBVVRPSU5DUkVNRU5ULAogICAgUGF0aWVudElEIElOVEVHRVIgTk9UIE5VTEwsCiAgICBEb2N0b3JJRCBJTlRFR0VSIE5PVCBOVUxMLAogICAgRGlhZ25vc2lzIFRFWFQgTk9UIE5VTEwsCiAgICBUcmVhdG1lbnQgVEVYVCwKICAgIFByZXNjcmliZWRNZWRpY2F0aW9ucyBURVhULAogICAgRGF0ZU9mVmlzaXQgVElNRVNUQU1QIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAsCiAgICBGT1JFSUdOIEtFWSAoUGF0aWVudElEKSBSRUZFUkVOQ0VTIFBhdGllbnRzKFBhdGllbnRJRCkgT04gREVMRVRFIENBU0NBREUsCiAgICBGT1JFSUdOIEtFWSAoRG9jdG9ySUQpIFJFRkVSRU5DRVMgRG9jdG9ycyhEb2N0b3JJRCkgT04gREVMRVRFIFNFVCBOVUxMCik7CmBgYAoKVGhpcyBzY3JpcHQgZW5zdXJlcyB0aGF0IHRhYmxlcyBhcmUgY3JlYXRlZCBvbmx5IGlmIHRoZXkgZG8gbm90IGFscmVhZHkgZXhpc3QuIEl0IGFsc28gZXN0YWJsaXNoZXMgcmVmZXJlbnRpYWwgaW50ZWdyaXR5IHVzaW5nIGZvcmVpZ24ga2V5IGNvbnN0cmFpbnRzLCBlbnN1cmluZyB0aGF0IG1lZGljYWwgcmVjb3JkcyByZWZlcmVuY2UgdmFsaWQgcGF0aWVudHMgYW5kIGRvY3RvcnMuCgpUaGVyZSBhcmUgbXVsdGlwbGUgd2F5cyB0byBleGVjdXRlIHRoaXMgU1FMIHNjcmlwdCBpbiBTUUxpdGUuIFRoZSBtb3N0IGNvbW1vbiBtZXRob2RzIGluY2x1ZGUgdXNpbmcgdGhlIFNRTGl0ZSBjb21tYW5kLWxpbmUgdG9vbCBvciBleGVjdXRpbmcgdGhlIHNjcmlwdCBwcm9ncmFtbWF0aWNhbGx5IGluIFB5dGhvbiBvciBSLgoKKipNZXRob2QgMTogUnVubmluZyB0aGUgU2NyaXB0IFVzaW5nIHRoZSBTUUxpdGUgQ29tbWFuZC1MaW5lIEludGVyZmFjZSoqCgoxLiAgKipFbnN1cmUgU1FMaXRlIGlzIGluc3RhbGxlZCoqOiBJZiBTUUxpdGUgaXMgbm90IGluc3RhbGxlZCwgZG93bmxvYWQgaXQgZnJvbSBbU1FMaXRlJ3Mgb2ZmaWNpYWwgd2Vic2l0ZV0oaHR0cHM6Ly93d3cuc3FsaXRlLm9yZy9kb3dubG9hZC5odG1sKS4KCjIuICAqKk9wZW4gYSB0ZXJtaW5hbCBvciBjb21tYW5kIHByb21wdCoqLgoKMy4gICoqTmF2aWdhdGUgdG8gdGhlIHNjcmlwdCdzIGRpcmVjdG9yeSoqIHVzaW5nIHRoZSBgY2RgIGNvbW1hbmQuCgo0LiAgKipSdW4gdGhlIHNjcmlwdCB3aXRoIFNRTGl0ZSoqIGJ5IGV4ZWN1dGluZzoKCiAgICBgYGAgc2gKICAgIHNxbGl0ZTMgaGVhbHRoY2FyZS5kYiA8IGhlYWx0aGNhcmVfc2NoZW1hLnNxbAogICAgYGBgCgogICAgVGhpcyBjb21tYW5kIHdpbGwgY3JlYXRlIGEgbmV3IFNRTGl0ZSBkYXRhYmFzZSBmaWxlIChgaGVhbHRoY2FyZS5kYmApIGFuZCBleGVjdXRlIGFsbCB0aGUgU1FMIHN0YXRlbWVudHMgd2l0aGluIGBoZWFsdGhjYXJlX3NjaGVtYS5zcWxgLiBJZiB0aGUgZGF0YWJhc2UgYWxyZWFkeSBleGlzdHMsIHRoZSBzY3JpcHQgd2lsbCBlbnN1cmUgdGhhdCB0aGUgdGFibGVzIGFyZSBjcmVhdGVkIGlmIHRoZXkgZG8gbm90IGV4aXN0LgoKNS4gICoqVmVyaWZ5IHRoZSBkYXRhYmFzZSBzY2hlbWEqKiBieSBvcGVuaW5nIHRoZSBTUUxpdGUgc2hlbGwgYW5kIGxpc3RpbmcgdGhlIHRhYmxlczoKCiAgICBgYGAgc2gKICAgIHNxbGl0ZTMgaGVhbHRoY2FyZS5kYgogICAgYGBgCgogICAgVGhlbiwgd2l0aGluIHRoZSBTUUxpdGUgc2hlbGwsIGV4ZWN1dGU6CgogICAgYGBgIHNxbAogICAgLnRhYmxlcwogICAgYGBgCgogICAgVGhpcyBzaG91bGQgZGlzcGxheSBgRG9jdG9yc2AsIGBQYXRpZW50c2AsIGFuZCBgTWVkaWNhbFJlY29yZHNgIGFzIHRoZSBhdmFpbGFibGUgdGFibGVzLgoKKipNZXRob2QgMjogRXhlY3V0aW5nIHRoZSBTY3JpcHQgUHJvZ3JhbW1hdGljYWxseSoqCgpJbiBtYW55IGFwcGxpY2F0aW9ucywgZGF0YWJhc2Ugc2NyaXB0cyBhcmUgZXhlY3V0ZWQgcHJvZ3JhbW1hdGljYWxseSB0byBpbml0aWFsaXplIHRoZSBkYXRhYmFzZS4gVGhlIGZvbGxvd2luZyBQeXRob24gc2NyaXB0IGRlbW9uc3RyYXRlcyBob3cgdG8gZXhlY3V0ZSBgaGVhbHRoY2FyZV9zY2hlbWEuc3FsYCB1c2luZyBTUUxpdGXigJlzIGBzcWxpdGUzYCBtb2R1bGUuCgpgYGAgcHl0aG9uCmltcG9ydCBzcWxpdGUzCgojIENvbm5lY3QgdG8gU1FMaXRlIGRhdGFiYXNlIChjcmVhdGVzIGZpbGUgaWYgaXQgZG9lcyBub3QgZXhpc3QpCmNvbm4gPSBzcWxpdGUzLmNvbm5lY3QoImhlYWx0aGNhcmUuZGIiKQpjdXJzb3IgPSBjb25uLmN1cnNvcigpCgojIFJlYWQgYW5kIGV4ZWN1dGUgdGhlIFNRTCBzY3JpcHQKd2l0aCBvcGVuKCJoZWFsdGhjYXJlX3NjaGVtYS5zcWwiLCAiciIpIGFzIGZpbGU6CiAgICBzY3JpcHQgPSBmaWxlLnJlYWQoKQogICAgY3Vyc29yLmV4ZWN1dGVzY3JpcHQoc2NyaXB0KQoKIyBDb21taXQgYW5kIGNsb3NlIGNvbm5lY3Rpb24KY29ubi5jb21taXQoKQpjb25uLmNsb3NlKCkKCnByaW50KCJEYXRhYmFzZSBzY2hlbWEgY3JlYXRlZCBzdWNjZXNzZnVsbHkuIikKYGBgCgpSdW5uaW5nIHRoaXMgUHl0aG9uIHNjcmlwdCB3aWxsIGV4ZWN1dGUgYWxsIFNRTCBzdGF0ZW1lbnRzIHdpdGhpbiBgaGVhbHRoY2FyZV9zY2hlbWEuc3FsYCwgc2V0dGluZyB1cCB0aGUgZGF0YWJhc2Ugc2NoZW1hLiBUaGlzIGFwcHJvYWNoIGlzIGNvbW1vbmx5IHVzZWQgaW4gd2ViIGFwcGxpY2F0aW9ucywgZGF0YSBwaXBlbGluZXMsIGFuZCBzeXN0ZW0gZGVwbG95bWVudHMgd2hlcmUgZGF0YWJhc2VzIG5lZWQgdG8gYmUgaW5pdGlhbGl6ZWQgcHJvZ3JhbW1hdGljYWxseS4KCkhlcmUgaXMgYW4gZXF1aXZhbGVudCAqKlIgc2NyaXB0KiogKG5vdCBhbiBSIE5vdGVib29rKSB0byBleGVjdXRlIGFuIFNRTGl0ZSBkYXRhYmFzZSBzY2hlbWEgZnJvbSBhIGZpbGUsIHNpbWlsYXIgdG8gdGhlIFB5dGhvbiBzY3JpcHQgcHJvdmlkZWQgZWFybGllci4gSW4gdGhpcyBleGFtcGxlLCB3ZSB1c2UgdGhlIGBSU1FMaXRlYCBwYWNrYWdlIHRvIGNvbm5lY3QgdG8gYW4gU1FMaXRlIGRhdGFiYXNlLCByZWFkIHRoZSBTUUwgc2NyaXB0LCBhbmQgZXhlY3V0ZSBpdC4KCkJlZm9yZSBydW5uaW5nIHRoZSBzY3JpcHQsIGVuc3VyZSB0aGF0IHRoZSBgREJJYCBhbmQgYFJTUUxpdGVgIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQsIGFzIHNob3duIGVhcmxpZXIgaW4gdGhpcyBsZXNzb24uCgpgYGAgcgojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KERCSSkKbGlicmFyeShSU1FMaXRlKQoKIyBEZWZpbmUgZGF0YWJhc2UgZmlsZSBuYW1lCmRiX2ZpbGUgPC0gImhlYWx0aGNhcmUuZGIiCgojIEVzdGFibGlzaCBhIGNvbm5lY3Rpb24gdG8gdGhlIFNRTGl0ZSBkYXRhYmFzZSAoY3JlYXRlcyBmaWxlIGlmIG5vdCBleGlzdHMpCmNvbm4gPC0gZGJDb25uZWN0KFNRTGl0ZSgpLCBkYl9maWxlKQoKIyBSZWFkIHRoZSBTUUwgc2NyaXB0IGZpbGUKc3FsX3NjcmlwdCA8LSByZWFkTGluZXMoImhlYWx0aGNhcmVfc2NoZW1hLnNxbCIpCgojIENvbGxhcHNlIHRoZSBzY3JpcHQgaW50byBhIHNpbmdsZSBzdHJpbmcgCiMgKFNRTGl0ZSByZXF1aXJlcyBjb21tYW5kcyB0byBiZSBleGVjdXRlZCBhcyBjb21wbGV0ZSBzdGF0ZW1lbnRzKQpzcWxfc2NyaXB0X2NvbWJpbmVkIDwtIHBhc3RlKHNxbF9zY3JpcHQsIGNvbGxhcHNlID0gIlxuIikKCiMgRXhlY3V0ZSB0aGUgU1FMIHNjcmlwdApkYkV4ZWN1dGUoY29ubiwgc3FsX3NjcmlwdF9jb21iaW5lZCkKCiMgQ2xvc2UgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb24KZGJEaXNjb25uZWN0KGNvbm4pCgojIENvbmZpcm0gZXhlY3V0aW9uCmNhdCgiRGF0YWJhc2Ugc2NoZW1hIGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5LlxuIikKYGBgCgpSYXRoZXIgdGhhbiBleGVjdXRpbmcgYW4gUiBTY3JpcHQgZnJvbSB3aXRoIFIgU3R1ZGlvIChQb3NpdCksIGl0IGNhbiBhbHNvIGJlIGV4ZWN1dGVkIGZyb20gdGhlIGNvbW1hbmQgbGluZSBsaWtlIGEgcHJvZ3JhbS4gVGhpcyBhbGxvd3MgZGF0YWJhc2UgYWRtaW5pc3RyYXRpb24gdG8gYmUgYXV0b21hdGVkIGluIHNoZWxsIHNjcmlwdHMgYW5kIGpvYnMgdGhhdCBhcmUgZXhlY3V0ZWQgYXQgc3BlY2lmaWMgdGltZXMuCgpBZnRlciBydW5uaW5nIHRoZSBzY3JpcHQsIHlvdSBjYW4gY2hlY2sgdGhlIGNyZWF0ZWQgdGFibGVzIGJ5IGV4ZWN1dGluZyB0aGUgZm9sbG93aW5nIGNvbW1hbmRzIGluIFI6CgpgYGAgcgojIFJlY29ubmVjdCB0byB0aGUgZGF0YWJhc2UKY29ubiA8LSBkYkNvbm5lY3QoU1FMaXRlKCksICJoZWFsdGhjYXJlLmRiIikKCiMgTGlzdCBhbGwgdGFibGVzIGluIHRoZSBkYXRhYmFzZQpkYkxpc3RUYWJsZXMoY29ubikKCiMgRGlzY29ubmVjdApkYkRpc2Nvbm5lY3QoY29ubikKYGBgCgpJZiBzdWNjZXNzZnVsLCB0aGUgb3V0cHV0IHNob3VsZCBkaXNwbGF5OgoKYGBgICAgICAgICAgClsxXSAiRG9jdG9ycyIgIlBhdGllbnRzIiAiTWVkaWNhbFJlY29yZHMiCmBgYAoKIyMgRGVsZXRpbmcgYSBTUUxpdGUgRGF0YWJhc2UKClRvIGRlbGV0ZSB0aGUgZW50aXJlIGRhdGFiYXNlLCBhbGwgb2YgaXRzIHRhYmxlcywgYW5kIGFsbCBkYXRhLCBzaW1wbHkgZGVsZXRlIHRoZSBmaWxlIHVzaW5nIHlvdXIgb3BlcmF0aW5nIHN5c3RlbSdzIGZpbGUgc3lzdGVtIG1hbmFnZXIuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gZGVsZXRlIGEgZGF0YWJhc2UgaW4gUiB1c2luZyB0aGUgYHVubGluaygpYCBmdW5jdGlvbi4KCmBgYHtyfQojIGRlbGV0ZSBkYXRhYmFzZSBpbiBmaWxlIHBhdGllbnREQi5kYgp1bmxpbmsoInBhdGllbnREQi5kYiIpCmBgYAoKIyMgU3VtbWFyeQoKVW5kZXJzdGFuZGluZyB0aGUgZnVuZGFtZW50YWwgb3BlcmF0aW9ucyBvZiBjcmVhdGluZywgYWx0ZXJpbmcsIGFuZCBkZWxldGluZyB0YWJsZXMgaXMgY3J1Y2lhbCBmb3Igc3RydWN0dXJpbmcgYW5kIG1haW50YWluaW5nIHJlbGF0aW9uYWwgZGF0YWJhc2VzIGVmZmVjdGl2ZWx5LiBTUUxpdGUgcHJvdmlkZXMgZXNzZW50aWFsIG1lY2hhbmlzbXMgZm9yIGRlZmluaW5nIHRhYmxlcywgbW9kaWZ5aW5nIHNjaGVtYXMsIGFuZCByZW1vdmluZyB1bm5lY2Vzc2FyeSBzdHJ1Y3R1cmVzIHdoaWxlIGVuc3VyaW5nIGRhdGEgaW50ZWdyaXR5IHRocm91Z2ggY29uc3RyYWludHMgYW5kIGZvcmVpZ24ga2V5IHJlbGF0aW9uc2hpcHMuIEJ5IGFwcGx5aW5nIHRoZXNlIHByaW5jaXBsZXMgdG8gYSBoZWFsdGhjYXJlIGRhdGFiYXNlLCBpdCBiZWNvbWVzIHBvc3NpYmxlIHRvIG1hbmFnZSBwYXRpZW50IHJlY29yZHMsIG1lZGljYWwgaGlzdG9yaWVzLCBhbmQgcmVsYXRlZCBpbmZvcm1hdGlvbiBlZmZpY2llbnRseS4gQXMgZGF0YWJhc2UgcmVxdWlyZW1lbnRzIGV2b2x2ZSwgY2FyZWZ1bCBwbGFubmluZyBpcyBuZWNlc3NhcnkgdG8gZW5zdXJlIHNlYW1sZXNzIG1vZGlmaWNhdGlvbnMgd2hpbGUgcHJlc2VydmluZyBkYXRhIGNvbnNpc3RlbmN5LgoKRXhlY3V0aW5nIFNRTCBzdGF0ZW1lbnRzIHdpdGhpbiBSIGNhbiBiZSBkb25lIHVzaW5nIGBEQklgIGZ1bmN0aW9ucyBvciBTUUwgY29kZSBjaHVua3MgaW4gUiBOb3RlYm9va3MuIFVzaW5nIGBkYkV4ZWN1dGUoKWAgd2l0aGluIFIgc2NyaXB0cyBhbGxvd3MgcHJvZ3JhbW1hdGljIGNvbnRyb2wsIHdoZXJlYXMgU1FMIGNodW5rcyBpbiBSIE5vdGVib29rcyBwcm92aWRlIGEgbW9yZSBzdHJ1Y3R1cmVkIHdheSB0byBkb2N1bWVudCBhbmQgZXhlY3V0ZSBxdWVyaWVzIGlubGluZS4gQm90aCBtZXRob2RzIHN1cHBvcnQgZWZmaWNpZW50IGludGVyYWN0aW9uIHdpdGggU1FMaXRlIGRhdGFiYXNlcywgbWFraW5nIHRoZW0gdmFsdWFibGUgdG9vbHMgZm9yIG1hbmFnaW5nIGhlYWx0aGNhcmUgZGF0YSBvciBhbnkgb3RoZXIgc3RydWN0dXJlZCBpbmZvcm1hdGlvbi4KCkRhdGFiYXNlIHNjcmlwdHMgcHJvdmlkZSBhIHN0cnVjdHVyZWQgYW5kIHJlcGVhdGFibGUgd2F5IHRvIGRlZmluZSBhbmQgbWFuYWdlIGEgcmVsYXRpb25hbCBkYXRhYmFzZSBzY2hlbWEuIEluIFNRTGl0ZSwgc2NyaXB0cyBjYW4gYmUgZXhlY3V0ZWQgdGhyb3VnaCB0aGUgY29tbWFuZC1saW5lIGludGVyZmFjZSBvciBwcm9ncmFtbWF0aWNhbGx5IHZpYSBkYXRhYmFzZSBjb25uZWN0b3JzIGluIGxhbmd1YWdlcyBzdWNoIGFzIFB5dGhvbi4gVXNpbmcgc2NyaXB0cyBlbnN1cmVzIHRoYXQgZGF0YWJhc2Ugc2NoZW1hcyByZW1haW4gY29uc2lzdGVudCBhY3Jvc3MgZW52aXJvbm1lbnRzIGFuZCBkZXBsb3ltZW50cywgcGFydGljdWxhcmx5IGluIGFwcGxpY2F0aW9ucyBzdWNoIGFzIGhlYWx0aGNhcmUgbWFuYWdlbWVudCBzeXN0ZW1zIHdoZXJlIGRhdGEgaW50ZWdyaXR5IGlzIGNydWNpYWwuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIEZpbGVzICYgUmVzb3VyY2VzCgpgYGB7ciB6aXBGaWxlcywgZWNobz1GQUxTRX0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIAogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwKICAgICAgICAgICAgICAgICBwYXJhbXMkbnVtYmVyKQoKdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCAKICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LCIuIixwYXJhbXMkbnVtYmVyKQoKIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SCmtuaXRyOjpyYXdfaHRtbChkb3dubG9hZEZpbGVzTGluaygiLiIsIHppcE5hbWUsIHRleHRBTGluaykpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBSZWZlcmVuY2VzCgpbU1FMaXRlIEFVVE9JTkNSRU1FTlQuIFNRTGl0ZSBUdXRvcmlhbC5dKGh0dHBzOi8vd3d3LnNxbGl0ZXR1dG9yaWFsLm5ldC9zcWxpdGUtYXV0b2luY3JlbWVudC8pCgpbU1FMaXRlIEFVVE9JTkNSRU1FTlQuIFNRTGl0ZSBEb2N1bWVudGF0aW9uLl0oaHR0cHM6Ly93d3cuc3FsaXRlLm9yZy9hdXRvaW5jLmh0bWwpCgojIyBFcnJhdGEKCltMZXQgdXMga25vd10oaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLzIxMjE4NzA3Mjc4NDE1Nyl7dGFyZ2V0PSJfYmxhbmsifS4K