Introduction

A Common Table Expression (CTE) in SQL is a named temporary result set that can be referenced within a SELECT, INSERT, UPDATE, or DELETE statement. CTEs can improve code readability, simplify complex queries, and provide a way to modularize query logic. They are defined using the WITH keyword, followed by the CTE name and its definition.

A CTE is basically a temporary view defined within a query’s scope. Unlike database views, which are persistent database object (although generally not materialized until referenced) and reusable across sessions, CTEs are local to the query they are defined in and exist only for the duration of that query. The general syntax of a CTE is:

WITH cte_name (optional_column_names) AS (
    -- CTE definition (usually a SELECT query)
    SELECT ...
)
-- Main query referencing the CTE
SELECT ... FROM cte_name;

Key Benefits of CTEs

CTEs are most commonly used in the following ways:

  1. Improving Query Readability: By breaking a complex query into smaller, more manageable pieces, CTEs make the logic easier to follow.

    Example:

    WITH SalesByRegion AS (
        SELECT Region, SUM(Sales) AS TotalSales
        FROM SalesData
        GROUP BY Region
    )
    SELECT Region, TotalSales
    FROM SalesByRegion
    WHERE TotalSales > 100000;

    Here, the SalesByRegion CTE simplifies the process of filtering regions with high sales.

  2. Recursive Queries: CTEs support recursion, making them essential for hierarchical data, such as organizational structures or tree-like data models.

    Example:

    WITH RECURSIVE OrgHierarchy AS (
        SELECT EmployeeID, ManagerID, EmployeeName, 1 AS Level
        FROM Employees
        WHERE ManagerID IS NULL
        UNION ALL
        SELECT e.EmployeeID, e.ManagerID, e.EmployeeName, oh.Level + 1
        FROM Employees e
        INNER JOIN OrgHierarchy oh ON e.ManagerID = oh.EmployeeID
    )
    SELECT * FROM OrgHierarchy;

    This query builds a hierarchy of employees and their levels in the organization.

  3. Complex Joins and Subqueries: Instead of writing nested subqueries, CTEs allow you to name intermediate steps, improving modularity.

  4. Multiple References: A CTE can be referenced multiple times within the same query, avoiding the need to repeat code and potentially improving performance.

CTEs are particularly useful in the following scenarios:

  • Readability: When a query involves multiple subqueries or intricate logic, using CTEs can make the SQL easier to understand and maintain.
  • Recursion: Recursive CTEs are essential for traversing hierarchical or tree-like data, such as file systems, family trees, or organizational structures.
  • Reusable Logic: If you need to reuse a complex query multiple times within the same SQL statement, a CTE eliminates repetition.
  • Debugging: During query development, defining parts of a query as CTEs makes it easier to test and debug individual components.

Necessity of CTEs

CTEs are not strictly necessary because the same functionality can generally be achieved using subqueries or temporary tables. However, they offer the following advantages:

  1. Clarity and Maintainability: By breaking down complex queries, CTEs make SQL more human-readable.
  2. Ad-Hoc Development: CTEs allow you to create temporary structures without modifying the database schema, which is useful for one-off analysis or rapid prototyping.
  3. Performance Considerations: In some cases, using a CTE instead of a subquery can improve performance, though this depends on the database system and query optimizer.

That said, CTEs may not always be the best choice. For instance, if performance is critical and a query references the same CTE multiple times, the database’s query engine might execute the CTE’s logic repeatedly unless the optimizer materializes it. In such situations, temporary tables might be a better choice when dealing with large intermediate datasets because they are explicitly materialized and stored and thus are not repeatedly materialized.

Nevertheless, CTEs are an essential mechanism in SQL, improving code readability, modularity, and enabling recursion. While not strictly necessary for all queries, they are indispensable for many complex scenarios. The choice between using a CTE, a subquery, or a temporary table depends on the specific requirements of the query, including readability, performance, and maintainability.

CTEs in SQLite

SQLite supports Common Table Expressions (CTEs), including both standard and recursive ones. Below are some examples demonstrating their use in SQLite. We will use the sample database created below:

library(RSQLite)
db <- dbConnect(RSQLite::SQLite(), "sampleDB.db")

1. Simplifying Queries with Standard CTEs

Suppose you have a table named Orders with the following structure:

CREATE TABLE Orders (
    OrderID INTEGER,
    CustomerID INTEGER,
    OrderDate TEXT,
    TotalAmount REAL
);

You want to find the total amount spent by each customer in a specific year (e.g., 2024) and filter those who spent more than $5000.

Using a CTE, this query can be written as:

WITH CustomerTotals AS (
    SELECT CustomerID, SUM(TotalAmount) AS TotalSpent
    FROM Orders
    WHERE strftime('%Y', OrderDate) = '2024'
    GROUP BY CustomerID
)
SELECT CustomerID, TotalSpent
FROM CustomerTotals
WHERE TotalSpent > 5000;
  • Explanation: The CTE CustomerTotals calculates the total amount spent by each customer in 2024. The main query then filters for customers who spent more than $5000.

2. Recursive CTE for Hierarchical Data

Consider an Employees table with the following structure:

CREATE TABLE Employees (
    EmployeeID INTEGER,
    ManagerID INTEGER,
    Name TEXT
);

You want to list all employees in the hierarchy starting from a specific manager (e.g., ManagerID = 1).

Using a recursive CTE:

WITH RECURSIVE EmployeeHierarchy AS (
    SELECT EmployeeID, ManagerID, Name, 1 AS Level
    FROM Employees
    WHERE ManagerID = 1  -- Start from the specified manager
    UNION ALL
    SELECT e.EmployeeID, e.ManagerID, e.Name, eh.Level + 1
    FROM Employees e
    INNER JOIN EmployeeHierarchy eh ON e.ManagerID = eh.EmployeeID
)
SELECT EmployeeID, ManagerID, Name, Level
FROM EmployeeHierarchy;
  • Explanation:
    • The anchor part of the CTE selects employees directly managed by ManagerID = 1.
    • The recursive part retrieves employees managed by those employees, repeating this process to traverse the hierarchy.
    • The Level column indicates the depth of each employee in the hierarchy.

3. Reusing Logic for Multiple References

Suppose you have a table named Products with the following structure:

CREATE TABLE Products (
    ProductID INTEGER,
    CategoryID INTEGER,
    Price REAL
);

You want to calculate the average price of products per category and find products that are above the average price in their category.

Using a CTE:

WITH CategoryAverages AS (
    SELECT CategoryID, AVG(Price) AS AvgPrice
    FROM Products
    GROUP BY CategoryID
)
SELECT p.ProductID, p.CategoryID, p.Price, ca.AvgPrice
FROM Products p
JOIN CategoryAverages ca ON p.CategoryID = ca.CategoryID
WHERE p.Price > ca.AvgPrice;
  • Explanation:
    • The CTE CategoryAverages calculates the average price for each category.
    • The main query joins this CTE with the Products table to filter products priced above their category’s average.

4. Generating Sequential Numbers (Recursive CTE)

SQLite does not have a built-in function to generate sequences, but a recursive CTE can be used to create one.

For example, generate numbers from 1 to 10:

WITH RECURSIVE Numbers AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1
    FROM Numbers
    WHERE n < 10
)
SELECT n
FROM Numbers;
  • Explanation:
    • The anchor part initializes the sequence with 1.
    • The recursive part increments n by 1 until it reaches 10.

5. Combining Multiple CTEs

SQLite allows defining multiple CTEs in a query. For example, consider the Orders table again, and you want to calculate: 1. The total revenue for 2024. 2. The total number of orders for each customer in 2024.

WITH TotalRevenue AS (
    SELECT SUM(TotalAmount) AS Revenue2024
    FROM Orders
    WHERE strftime('%Y', OrderDate) = '2024'
),
CustomerOrders AS (
    SELECT CustomerID, COUNT(OrderID) AS OrderCount
    FROM Orders
    WHERE strftime('%Y', OrderDate) = '2024'
    GROUP BY CustomerID
)
SELECT co.CustomerID, co.OrderCount, tr.Revenue2024
FROM CustomerOrders co
CROSS JOIN TotalRevenue tr;
  • Explanation:
    • The TotalRevenue CTE calculates the overall revenue for 2024.
    • The CustomerOrders CTE calculates the number of orders for each customer in 2024.
    • The main query combines these results, showing the number of orders per customer along with the total revenue.

Why Use CTEs in SQLite?

CTEs in SQLite: - Enhance readability by breaking down complex queries. - Enable recursion for hierarchical data or sequence generation. - Allow reusable query components, avoiding duplication.

While not always necessary, CTEs can simplify logic and make queries easier to maintain. However, for very large datasets or performance-critical applications, testing the impact of CTEs versus subqueries or temporary tables is important since SQLite handles CTEs as inline query fragments rather than materialized views.

Example CTE Queries

Given the table definition and the inserted data:

CREATE TABLE T (a INT, b INT);

INSERT INTO T VALUES (11, 20), (10, 20), (10, 20), (10, 20), (88, 77);

The table T now contains the following data:

a b
11 20
10 20
10 20
10 20
88 77

1. Query: Selecting All Data

To view all rows in the table:

SELECT * FROM T;

Result: | a | b | |—-|—-| | 11 | 20 | | 10 | 20 | | 10 | 20 | | 10 | 20 | | 88 | 77 |


2. Query: Using a Common Table Expression (CTE) to Remove Duplicates

You might want to eliminate duplicate rows, which SQLite can achieve with the DISTINCT keyword. Using a CTE:

WITH DistinctRows AS (
    SELECT DISTINCT a, b
    FROM T
)
SELECT * 
FROM DistinctRows;

Result: | a | b | |—-|—-| | 11 | 20 | | 10 | 20 | | 88 | 77 |


3. Query: Count Occurrences of Each Row

To count how many times each pair (a, b) appears in the table:

WITH RowCounts AS (
    SELECT a, b, COUNT(*) AS Count
    FROM T
    GROUP BY a, b
)
SELECT *
FROM RowCounts;

Result: | a | b | Count | |—-|—-|——-| | 11 | 20 | 1 | | 10 | 20 | 3 | | 88 | 77 | 1 |


4. Query: Find the Row with the Maximum Count

To identify the (a, b) pair that appears most frequently:

WITH RowCounts AS (
    SELECT a, b, COUNT(*) AS Count
    FROM T
    GROUP BY a, b
)
SELECT a, b, Count
FROM RowCounts
WHERE Count = (SELECT MAX(Count) FROM RowCounts);

Result: | a | b | Count | |—-|—-|——-| | 10 | 20 | 3 |


5. Query: Filter Rows Based on Conditions

For example, selecting rows where a > 10 and b < 30:

WITH FilteredRows AS (
    SELECT *
    FROM T
    WHERE a > 10 AND b < 30
)
SELECT *
FROM FilteredRows;

Result: | a | b | |—-|—-| | 11 | 20 |


6. Query: Summing Values in a CTE

You may want to calculate the sum of a and b for the entire table:

WITH TotalSums AS (
    SELECT SUM(a) AS SumA, SUM(b) AS SumB
    FROM T
)
SELECT SumA, SumB
FROM TotalSums;

Result: | SumA | SumB | |——|——| | 129 | 157 |


7. Query: Identify Unique Rows Only

If you want rows that appear exactly once in the table:

WITH RowCounts AS (
    SELECT a, b, COUNT(*) AS Count
    FROM T
    GROUP BY a, b
)
SELECT a, b
FROM RowCounts
WHERE Count = 1;

Result: | a | b | |—-|—-| | 11 | 20 | | 88 | 77 |


8. Query: Recursive CTE Example

If you want to generate a sequence starting from the smallest value in column a (e.g., 10) and increment it up to 15:

WITH RECURSIVE Sequence AS (
    SELECT MIN(a) AS n
    FROM T
    UNION ALL
    SELECT n + 1
    FROM Sequence
    WHERE n < 15
)
SELECT n
FROM Sequence;

Result: | n | |—-| | 10 | | 11 | | 12 | | 13 | | 14 | | 15 |


These examples showcase how CTEs can simplify and modularize SQL queries in SQLite, making them easier to write and read while handling common tasks like deduplication, filtering, aggregation, and recursion.

Summary

Common Table Expressions (CTE) in SQL provides a temporary, named result set defined within the scope of a single query using the WITH keyword. It simplifies complex queries, improves readability, and enables recursion. CTEs are particularly useful for tasks like breaking down intricate logic into modular steps, removing duplicate rows, counting occurrences of specific data, filtering, aggregating, and handling recursive operations such as hierarchical data traversal or generating sequences.

While not mandatory, CTEs make queries more maintainable and expressive, especially for intermediate calculations or when logic needs to be reused within a single SQL statement.


Files & Resources

All Files for Lesson 70.114

References

No references.

Errata

Let us know.

LS0tCnRpdGxlOiAiU2ltcGxpZnlpbmcgUXVlcmllcyB3aXRoIENvbW1vbiBUYWJsZSBFeHByZXNzaW9ucyAoQ1RFKSIKcGFyYW1zOgogIGNhdGVnb3J5OiA3MAogIG51bWJlcjogMTE0CiAgdGltZTogNDUKICBsZXZlbDogYmVnaW5uZXIKICB0YWdzOiAic3FsLGN0ZSxyY3RlLGpvaW5zIgogIGRlc2NyaXB0aW9uOiAiRXhwbGFpbnMgaG93IENvbW1vbiBUYWJsZSBFeHByZXNzaW9ucyAoQ1RFKSBhbmQgUmVjdXJzaXZlIENvbW1vbgogICAgICAgICAgICAgICAgVGFibGUgRXhwcmVzc2lvbnMgKFJDVEUpIGNhbiBiZSB1c2VkIHRvIHNpbXBsaWZ5IFNRTCBxdWVyaWVzIGFuZCAKICAgICAgICAgICAgICAgIG1ha2UgY29tcGxleCBxdWVyaWVzIG1vcmUgcmVhc2FibGUuIgpkYXRlOiAiPHNtYWxsPmByIFN5cy5EYXRlKClgPC9zbWFsbD4iCmF1dGhvcjogIjxzbWFsbD5NYXJ0aW4gU2NoZWRsYmF1ZXI8L3NtYWxsPiIKZW1haWw6ICJtLnNjaGVkbGJhdWVyQG5ldS5lZHUiCmFmZmlsaXRhdGlvbjogIk5vcnRoZWFzdGVybiBVbml2ZXJzaXR5IgpvdXRwdXQ6IAogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGVjaG89Rn0KIyBQYWNrYWdlIG5hbWVzCnBhY2thZ2VzIDwtIGMoImhlcmUiLCAiUlNRTGl0ZSIpCgojIEluc3RhbGwgcGFja2FnZXMgbm90IHlldCBpbnN0YWxsZWQKaW5zdGFsbGVkX3BhY2thZ2VzIDwtIHBhY2thZ2VzICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpCmlmIChhbnkoaW5zdGFsbGVkX3BhY2thZ2VzID09IEZBTFNFKSkgewogIGluc3RhbGwucGFja2FnZXMocGFja2FnZXNbIWluc3RhbGxlZF9wYWNrYWdlc10sIHJlcG9zID0gImh0dHBzOi8vY2xvdWQuci1wcm9qZWN0Lm9yZyIpCn0KCiMgUGFja2FnZXMgbG9hZGluZwpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoaW52aXNpYmxlKGxhcHBseShwYWNrYWdlcywgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkpCmBgYAoKYGBge3IgY29kZT14ZnVuOjpyZWFkX3V0ZjgocGFzdGUwKGhlcmU6OmhlcmUoKSwnL1IvX2luc2VydDJEQi5SJykpLCBpbmNsdWRlID0gRkFMU0V9CmBgYAoKIyMgSW50cm9kdWN0aW9uCgpBICpDb21tb24gVGFibGUgRXhwcmVzc2lvbiAoQ1RFKSogaW4gU1FMIGlzIGEgbmFtZWQgdGVtcG9yYXJ5IHJlc3VsdCBzZXQgdGhhdCBjYW4gYmUgcmVmZXJlbmNlZCB3aXRoaW4gYSAqU0VMRUNUKiwgKklOU0VSVCosICpVUERBVEUqLCBvciAqREVMRVRFKiBzdGF0ZW1lbnQuIENURXMgY2FuIGltcHJvdmUgY29kZSByZWFkYWJpbGl0eSwgc2ltcGxpZnkgY29tcGxleCBxdWVyaWVzLCBhbmQgcHJvdmlkZSBhIHdheSB0byBtb2R1bGFyaXplIHF1ZXJ5IGxvZ2ljLiBUaGV5IGFyZSBkZWZpbmVkIHVzaW5nIHRoZSAqV0lUSCoga2V5d29yZCwgZm9sbG93ZWQgYnkgdGhlIENURSBuYW1lIGFuZCBpdHMgZGVmaW5pdGlvbi4KCkEgQ1RFIGlzIGJhc2ljYWxseSBhIHRlbXBvcmFyeSB2aWV3IGRlZmluZWQgd2l0aGluIGEgcXVlcnkncyBzY29wZS4gVW5saWtlIGRhdGFiYXNlIHZpZXdzLCB3aGljaCBhcmUgcGVyc2lzdGVudCBkYXRhYmFzZSBvYmplY3QgKGFsdGhvdWdoIGdlbmVyYWxseSBub3QgbWF0ZXJpYWxpemVkIHVudGlsIHJlZmVyZW5jZWQpIGFuZCByZXVzYWJsZSBhY3Jvc3Mgc2Vzc2lvbnMsIENURXMgYXJlIGxvY2FsIHRvIHRoZSBxdWVyeSB0aGV5IGFyZSBkZWZpbmVkIGluIGFuZCBleGlzdCBvbmx5IGZvciB0aGUgZHVyYXRpb24gb2YgdGhhdCBxdWVyeS4gVGhlIGdlbmVyYWwgc3ludGF4IG9mIGEgQ1RFIGlzOgoKYGBgIHNxbApXSVRIIGN0ZV9uYW1lIChvcHRpb25hbF9jb2x1bW5fbmFtZXMpIEFTICgKICAgIC0tIENURSBkZWZpbml0aW9uICh1c3VhbGx5IGEgU0VMRUNUIHF1ZXJ5KQogICAgU0VMRUNUIC4uLgopCi0tIE1haW4gcXVlcnkgcmVmZXJlbmNpbmcgdGhlIENURQpTRUxFQ1QgLi4uIEZST00gY3RlX25hbWU7CmBgYAoKIyMgS2V5IEJlbmVmaXRzIG9mIENURXMKCkNURXMgYXJlIG1vc3QgY29tbW9ubHkgdXNlZCBpbiB0aGUgZm9sbG93aW5nIHdheXM6CgoxLiAgKipJbXByb3ZpbmcgUXVlcnkgUmVhZGFiaWxpdHkqKjogQnkgYnJlYWtpbmcgYSBjb21wbGV4IHF1ZXJ5IGludG8gc21hbGxlciwgbW9yZSBtYW5hZ2VhYmxlIHBpZWNlcywgQ1RFcyBtYWtlIHRoZSBsb2dpYyBlYXNpZXIgdG8gZm9sbG93LgoKICAgIEV4YW1wbGU6CgogICAgYGBgIHNxbAogICAgV0lUSCBTYWxlc0J5UmVnaW9uIEFTICgKICAgICAgICBTRUxFQ1QgUmVnaW9uLCBTVU0oU2FsZXMpIEFTIFRvdGFsU2FsZXMKICAgICAgICBGUk9NIFNhbGVzRGF0YQogICAgICAgIEdST1VQIEJZIFJlZ2lvbgogICAgKQogICAgU0VMRUNUIFJlZ2lvbiwgVG90YWxTYWxlcwogICAgRlJPTSBTYWxlc0J5UmVnaW9uCiAgICBXSEVSRSBUb3RhbFNhbGVzID4gMTAwMDAwOwogICAgYGBgCgogICAgSGVyZSwgdGhlIGBTYWxlc0J5UmVnaW9uYCBDVEUgc2ltcGxpZmllcyB0aGUgcHJvY2VzcyBvZiBmaWx0ZXJpbmcgcmVnaW9ucyB3aXRoIGhpZ2ggc2FsZXMuCgoyLiAgKipSZWN1cnNpdmUgUXVlcmllcyoqOiBDVEVzIHN1cHBvcnQgcmVjdXJzaW9uLCBtYWtpbmcgdGhlbSBlc3NlbnRpYWwgZm9yIGhpZXJhcmNoaWNhbCBkYXRhLCBzdWNoIGFzIG9yZ2FuaXphdGlvbmFsIHN0cnVjdHVyZXMgb3IgdHJlZS1saWtlIGRhdGEgbW9kZWxzLgoKICAgIEV4YW1wbGU6CgogICAgYGBgIHNxbAogICAgV0lUSCBSRUNVUlNJVkUgT3JnSGllcmFyY2h5IEFTICgKICAgICAgICBTRUxFQ1QgRW1wbG95ZWVJRCwgTWFuYWdlcklELCBFbXBsb3llZU5hbWUsIDEgQVMgTGV2ZWwKICAgICAgICBGUk9NIEVtcGxveWVlcwogICAgICAgIFdIRVJFIE1hbmFnZXJJRCBJUyBOVUxMCiAgICAgICAgVU5JT04gQUxMCiAgICAgICAgU0VMRUNUIGUuRW1wbG95ZWVJRCwgZS5NYW5hZ2VySUQsIGUuRW1wbG95ZWVOYW1lLCBvaC5MZXZlbCArIDEKICAgICAgICBGUk9NIEVtcGxveWVlcyBlCiAgICAgICAgSU5ORVIgSk9JTiBPcmdIaWVyYXJjaHkgb2ggT04gZS5NYW5hZ2VySUQgPSBvaC5FbXBsb3llZUlECiAgICApCiAgICBTRUxFQ1QgKiBGUk9NIE9yZ0hpZXJhcmNoeTsKICAgIGBgYAoKICAgIFRoaXMgcXVlcnkgYnVpbGRzIGEgaGllcmFyY2h5IG9mIGVtcGxveWVlcyBhbmQgdGhlaXIgbGV2ZWxzIGluIHRoZSBvcmdhbml6YXRpb24uCgozLiAgKipDb21wbGV4IEpvaW5zIGFuZCBTdWJxdWVyaWVzKio6IEluc3RlYWQgb2Ygd3JpdGluZyBuZXN0ZWQgc3VicXVlcmllcywgQ1RFcyBhbGxvdyB5b3UgdG8gbmFtZSBpbnRlcm1lZGlhdGUgc3RlcHMsIGltcHJvdmluZyBtb2R1bGFyaXR5LgoKNC4gICoqTXVsdGlwbGUgUmVmZXJlbmNlcyoqOiBBIENURSBjYW4gYmUgcmVmZXJlbmNlZCBtdWx0aXBsZSB0aW1lcyB3aXRoaW4gdGhlIHNhbWUgcXVlcnksIGF2b2lkaW5nIHRoZSBuZWVkIHRvIHJlcGVhdCBjb2RlIGFuZCBwb3RlbnRpYWxseSBpbXByb3ZpbmcgcGVyZm9ybWFuY2UuCgpDVEVzIGFyZSBwYXJ0aWN1bGFybHkgdXNlZnVsIGluIHRoZSBmb2xsb3dpbmcgc2NlbmFyaW9zOgoKLSAgICoqUmVhZGFiaWxpdHkqKjogV2hlbiBhIHF1ZXJ5IGludm9sdmVzIG11bHRpcGxlIHN1YnF1ZXJpZXMgb3IgaW50cmljYXRlIGxvZ2ljLCB1c2luZyBDVEVzIGNhbiBtYWtlIHRoZSBTUUwgZWFzaWVyIHRvIHVuZGVyc3RhbmQgYW5kIG1haW50YWluLgotICAgKipSZWN1cnNpb24qKjogUmVjdXJzaXZlIENURXMgYXJlIGVzc2VudGlhbCBmb3IgdHJhdmVyc2luZyBoaWVyYXJjaGljYWwgb3IgdHJlZS1saWtlIGRhdGEsIHN1Y2ggYXMgZmlsZSBzeXN0ZW1zLCBmYW1pbHkgdHJlZXMsIG9yIG9yZ2FuaXphdGlvbmFsIHN0cnVjdHVyZXMuCi0gICAqKlJldXNhYmxlIExvZ2ljKio6IElmIHlvdSBuZWVkIHRvIHJldXNlIGEgY29tcGxleCBxdWVyeSBtdWx0aXBsZSB0aW1lcyB3aXRoaW4gdGhlIHNhbWUgU1FMIHN0YXRlbWVudCwgYSBDVEUgZWxpbWluYXRlcyByZXBldGl0aW9uLgotICAgKipEZWJ1Z2dpbmcqKjogRHVyaW5nIHF1ZXJ5IGRldmVsb3BtZW50LCBkZWZpbmluZyBwYXJ0cyBvZiBhIHF1ZXJ5IGFzIENURXMgbWFrZXMgaXQgZWFzaWVyIHRvIHRlc3QgYW5kIGRlYnVnIGluZGl2aWR1YWwgY29tcG9uZW50cy4KCiMjIE5lY2Vzc2l0eSBvZiBDVEVzCgpDVEVzIGFyZSBub3Qgc3RyaWN0bHkgbmVjZXNzYXJ5IGJlY2F1c2UgdGhlIHNhbWUgZnVuY3Rpb25hbGl0eSBjYW4gZ2VuZXJhbGx5IGJlIGFjaGlldmVkIHVzaW5nIHN1YnF1ZXJpZXMgb3IgdGVtcG9yYXJ5IHRhYmxlcy4gSG93ZXZlciwgdGhleSBvZmZlciB0aGUgZm9sbG93aW5nIGFkdmFudGFnZXM6CgoxLiAgKipDbGFyaXR5IGFuZCBNYWludGFpbmFiaWxpdHkqKjogQnkgYnJlYWtpbmcgZG93biBjb21wbGV4IHF1ZXJpZXMsIENURXMgbWFrZSBTUUwgbW9yZSBodW1hbi1yZWFkYWJsZS4KMi4gICoqQWQtSG9jIERldmVsb3BtZW50Kio6IENURXMgYWxsb3cgeW91IHRvIGNyZWF0ZSB0ZW1wb3Jhcnkgc3RydWN0dXJlcyB3aXRob3V0IG1vZGlmeWluZyB0aGUgZGF0YWJhc2Ugc2NoZW1hLCB3aGljaCBpcyB1c2VmdWwgZm9yIG9uZS1vZmYgYW5hbHlzaXMgb3IgcmFwaWQgcHJvdG90eXBpbmcuCjMuICAqKlBlcmZvcm1hbmNlIENvbnNpZGVyYXRpb25zKio6IEluIHNvbWUgY2FzZXMsIHVzaW5nIGEgQ1RFIGluc3RlYWQgb2YgYSBzdWJxdWVyeSBjYW4gaW1wcm92ZSBwZXJmb3JtYW5jZSwgdGhvdWdoIHRoaXMgZGVwZW5kcyBvbiB0aGUgZGF0YWJhc2Ugc3lzdGVtIGFuZCBxdWVyeSBvcHRpbWl6ZXIuCgpUaGF0IHNhaWQsIENURXMgbWF5IG5vdCBhbHdheXMgYmUgdGhlIGJlc3QgY2hvaWNlLiBGb3IgaW5zdGFuY2UsIGlmIHBlcmZvcm1hbmNlIGlzIGNyaXRpY2FsIGFuZCBhIHF1ZXJ5IHJlZmVyZW5jZXMgdGhlIHNhbWUgQ1RFIG11bHRpcGxlIHRpbWVzLCB0aGUgZGF0YWJhc2UncyBxdWVyeSBlbmdpbmUgbWlnaHQgZXhlY3V0ZSB0aGUgQ1RFJ3MgbG9naWMgcmVwZWF0ZWRseSB1bmxlc3MgdGhlIG9wdGltaXplciBtYXRlcmlhbGl6ZXMgaXQuIEluIHN1Y2ggc2l0dWF0aW9ucywgdGVtcG9yYXJ5IHRhYmxlcyBtaWdodCBiZSBhIGJldHRlciBjaG9pY2Ugd2hlbiBkZWFsaW5nIHdpdGggbGFyZ2UgaW50ZXJtZWRpYXRlIGRhdGFzZXRzIGJlY2F1c2UgdGhleSBhcmUgZXhwbGljaXRseSBtYXRlcmlhbGl6ZWQgYW5kIHN0b3JlZCBhbmQgdGh1cyBhcmUgbm90IHJlcGVhdGVkbHkgbWF0ZXJpYWxpemVkLgoKTmV2ZXJ0aGVsZXNzLCBDVEVzIGFyZSBhbiBlc3NlbnRpYWwgbWVjaGFuaXNtIGluIFNRTCwgaW1wcm92aW5nIGNvZGUgcmVhZGFiaWxpdHksIG1vZHVsYXJpdHksIGFuZCBlbmFibGluZyByZWN1cnNpb24uIFdoaWxlIG5vdCBzdHJpY3RseSBuZWNlc3NhcnkgZm9yIGFsbCBxdWVyaWVzLCB0aGV5IGFyZSBpbmRpc3BlbnNhYmxlIGZvciBtYW55IGNvbXBsZXggc2NlbmFyaW9zLiBUaGUgY2hvaWNlIGJldHdlZW4gdXNpbmcgYSBDVEUsIGEgc3VicXVlcnksIG9yIGEgdGVtcG9yYXJ5IHRhYmxlIGRlcGVuZHMgb24gdGhlIHNwZWNpZmljIHJlcXVpcmVtZW50cyBvZiB0aGUgcXVlcnksIGluY2x1ZGluZyByZWFkYWJpbGl0eSwgcGVyZm9ybWFuY2UsIGFuZCBtYWludGFpbmFiaWxpdHkuCgojIyBDVEVzIGluIFNRTGl0ZQoKU1FMaXRlIHN1cHBvcnRzICpDb21tb24gVGFibGUgRXhwcmVzc2lvbnMgKENURXMpKiwgaW5jbHVkaW5nIGJvdGggc3RhbmRhcmQgYW5kIHJlY3Vyc2l2ZSBvbmVzLiBCZWxvdyBhcmUgc29tZSBleGFtcGxlcyBkZW1vbnN0cmF0aW5nIHRoZWlyIHVzZSBpbiBTUUxpdGUuIFdlIHdpbGwgdXNlIHRoZSBzYW1wbGUgZGF0YWJhc2UgY3JlYXRlZCBiZWxvdzoKCmBgYHtyIGVjaG89Rn0KdW5saW5rKCJzYW1wbGVEQi5kYiIpCmBgYAoKYGBge3J9CmxpYnJhcnkoUlNRTGl0ZSkKZGIgPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCAic2FtcGxlREIuZGIiKQpgYGAKCiMjIyAxLiBTaW1wbGlmeWluZyBRdWVyaWVzIHdpdGggU3RhbmRhcmQgQ1RFcwoKU3VwcG9zZSB5b3UgaGF2ZSBhIHRhYmxlIG5hbWVkIGBPcmRlcnNgIHdpdGggdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmU6CgpgYGB7c3FsLCBjb25uZWN0aW9uPWRifQpDUkVBVEUgVEFCTEUgT3JkZXJzICgKICAgIE9yZGVySUQgSU5URUdFUiwKICAgIEN1c3RvbWVySUQgSU5URUdFUiwKICAgIE9yZGVyRGF0ZSBURVhULAogICAgVG90YWxBbW91bnQgUkVBTAopOwpgYGAKCllvdSB3YW50IHRvIGZpbmQgdGhlIHRvdGFsIGFtb3VudCBzcGVudCBieSBlYWNoIGN1c3RvbWVyIGluIGEgc3BlY2lmaWMgeWVhciAoZS5nLiwgMjAyNCkgYW5kIGZpbHRlciB0aG9zZSB3aG8gc3BlbnQgbW9yZSB0aGFuIFwkNTAwMC4KClVzaW5nIGEgQ1RFLCB0aGlzIHF1ZXJ5IGNhbiBiZSB3cml0dGVuIGFzOgoKYGBgIHNxbApXSVRIIEN1c3RvbWVyVG90YWxzIEFTICgKICAgIFNFTEVDVCBDdXN0b21lcklELCBTVU0oVG90YWxBbW91bnQpIEFTIFRvdGFsU3BlbnQKICAgIEZST00gT3JkZXJzCiAgICBXSEVSRSBzdHJmdGltZSgnJVknLCBPcmRlckRhdGUpID0gJzIwMjQnCiAgICBHUk9VUCBCWSBDdXN0b21lcklECikKU0VMRUNUIEN1c3RvbWVySUQsIFRvdGFsU3BlbnQKRlJPTSBDdXN0b21lclRvdGFscwpXSEVSRSBUb3RhbFNwZW50ID4gNTAwMDsKYGBgCgotICAgKipFeHBsYW5hdGlvbioqOiBUaGUgQ1RFIGBDdXN0b21lclRvdGFsc2AgY2FsY3VsYXRlcyB0aGUgdG90YWwgYW1vdW50IHNwZW50IGJ5IGVhY2ggY3VzdG9tZXIgaW4gMjAyNC4gVGhlIG1haW4gcXVlcnkgdGhlbiBmaWx0ZXJzIGZvciBjdXN0b21lcnMgd2hvIHNwZW50IG1vcmUgdGhhbiBcJDUwMDAuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAqKjIuIFJlY3Vyc2l2ZSBDVEUgZm9yIEhpZXJhcmNoaWNhbCBEYXRhKioKCkNvbnNpZGVyIGFuIGBFbXBsb3llZXNgIHRhYmxlIHdpdGggdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmU6CgpgYGAgc3FsCkNSRUFURSBUQUJMRSBFbXBsb3llZXMgKAogICAgRW1wbG95ZWVJRCBJTlRFR0VSLAogICAgTWFuYWdlcklEIElOVEVHRVIsCiAgICBOYW1lIFRFWFQKKTsKYGBgCgpZb3Ugd2FudCB0byBsaXN0IGFsbCBlbXBsb3llZXMgaW4gdGhlIGhpZXJhcmNoeSBzdGFydGluZyBmcm9tIGEgc3BlY2lmaWMgbWFuYWdlciAoZS5nLiwgYE1hbmFnZXJJRCA9IDFgKS4KClVzaW5nIGEgcmVjdXJzaXZlIENURToKCmBgYCBzcWwKV0lUSCBSRUNVUlNJVkUgRW1wbG95ZWVIaWVyYXJjaHkgQVMgKAogICAgU0VMRUNUIEVtcGxveWVlSUQsIE1hbmFnZXJJRCwgTmFtZSwgMSBBUyBMZXZlbAogICAgRlJPTSBFbXBsb3llZXMKICAgIFdIRVJFIE1hbmFnZXJJRCA9IDEgIC0tIFN0YXJ0IGZyb20gdGhlIHNwZWNpZmllZCBtYW5hZ2VyCiAgICBVTklPTiBBTEwKICAgIFNFTEVDVCBlLkVtcGxveWVlSUQsIGUuTWFuYWdlcklELCBlLk5hbWUsIGVoLkxldmVsICsgMQogICAgRlJPTSBFbXBsb3llZXMgZQogICAgSU5ORVIgSk9JTiBFbXBsb3llZUhpZXJhcmNoeSBlaCBPTiBlLk1hbmFnZXJJRCA9IGVoLkVtcGxveWVlSUQKKQpTRUxFQ1QgRW1wbG95ZWVJRCwgTWFuYWdlcklELCBOYW1lLCBMZXZlbApGUk9NIEVtcGxveWVlSGllcmFyY2h5OwpgYGAKCi0gICAqKkV4cGxhbmF0aW9uKio6CiAgICAtICAgVGhlIGFuY2hvciBwYXJ0IG9mIHRoZSBDVEUgc2VsZWN0cyBlbXBsb3llZXMgZGlyZWN0bHkgbWFuYWdlZCBieSBgTWFuYWdlcklEID0gMWAuCiAgICAtICAgVGhlIHJlY3Vyc2l2ZSBwYXJ0IHJldHJpZXZlcyBlbXBsb3llZXMgbWFuYWdlZCBieSB0aG9zZSBlbXBsb3llZXMsIHJlcGVhdGluZyB0aGlzIHByb2Nlc3MgdG8gdHJhdmVyc2UgdGhlIGhpZXJhcmNoeS4KICAgIC0gICBUaGUgYExldmVsYCBjb2x1bW4gaW5kaWNhdGVzIHRoZSBkZXB0aCBvZiBlYWNoIGVtcGxveWVlIGluIHRoZSBoaWVyYXJjaHkuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAqKjMuIFJldXNpbmcgTG9naWMgZm9yIE11bHRpcGxlIFJlZmVyZW5jZXMqKgoKU3VwcG9zZSB5b3UgaGF2ZSBhIHRhYmxlIG5hbWVkIGBQcm9kdWN0c2Agd2l0aCB0aGUgZm9sbG93aW5nIHN0cnVjdHVyZToKCmBgYCBzcWwKQ1JFQVRFIFRBQkxFIFByb2R1Y3RzICgKICAgIFByb2R1Y3RJRCBJTlRFR0VSLAogICAgQ2F0ZWdvcnlJRCBJTlRFR0VSLAogICAgUHJpY2UgUkVBTAopOwpgYGAKCllvdSB3YW50IHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBwcmljZSBvZiBwcm9kdWN0cyBwZXIgY2F0ZWdvcnkgYW5kIGZpbmQgcHJvZHVjdHMgdGhhdCBhcmUgYWJvdmUgdGhlIGF2ZXJhZ2UgcHJpY2UgaW4gdGhlaXIgY2F0ZWdvcnkuCgpVc2luZyBhIENURToKCmBgYCBzcWwKV0lUSCBDYXRlZ29yeUF2ZXJhZ2VzIEFTICgKICAgIFNFTEVDVCBDYXRlZ29yeUlELCBBVkcoUHJpY2UpIEFTIEF2Z1ByaWNlCiAgICBGUk9NIFByb2R1Y3RzCiAgICBHUk9VUCBCWSBDYXRlZ29yeUlECikKU0VMRUNUIHAuUHJvZHVjdElELCBwLkNhdGVnb3J5SUQsIHAuUHJpY2UsIGNhLkF2Z1ByaWNlCkZST00gUHJvZHVjdHMgcApKT0lOIENhdGVnb3J5QXZlcmFnZXMgY2EgT04gcC5DYXRlZ29yeUlEID0gY2EuQ2F0ZWdvcnlJRApXSEVSRSBwLlByaWNlID4gY2EuQXZnUHJpY2U7CmBgYAoKLSAgICoqRXhwbGFuYXRpb24qKjoKICAgIC0gICBUaGUgQ1RFIGBDYXRlZ29yeUF2ZXJhZ2VzYCBjYWxjdWxhdGVzIHRoZSBhdmVyYWdlIHByaWNlIGZvciBlYWNoIGNhdGVnb3J5LgogICAgLSAgIFRoZSBtYWluIHF1ZXJ5IGpvaW5zIHRoaXMgQ1RFIHdpdGggdGhlIGBQcm9kdWN0c2AgdGFibGUgdG8gZmlsdGVyIHByb2R1Y3RzIHByaWNlZCBhYm92ZSB0aGVpciBjYXRlZ29yeSdzIGF2ZXJhZ2UuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAqKjQuIEdlbmVyYXRpbmcgU2VxdWVudGlhbCBOdW1iZXJzIChSZWN1cnNpdmUgQ1RFKSoqCgpTUUxpdGUgZG9lcyBub3QgaGF2ZSBhIGJ1aWx0LWluIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIHNlcXVlbmNlcywgYnV0IGEgcmVjdXJzaXZlIENURSBjYW4gYmUgdXNlZCB0byBjcmVhdGUgb25lLgoKRm9yIGV4YW1wbGUsIGdlbmVyYXRlIG51bWJlcnMgZnJvbSAxIHRvIDEwOgoKYGBgIHNxbApXSVRIIFJFQ1VSU0lWRSBOdW1iZXJzIEFTICgKICAgIFNFTEVDVCAxIEFTIG4KICAgIFVOSU9OIEFMTAogICAgU0VMRUNUIG4gKyAxCiAgICBGUk9NIE51bWJlcnMKICAgIFdIRVJFIG4gPCAxMAopClNFTEVDVCBuCkZST00gTnVtYmVyczsKYGBgCgotICAgKipFeHBsYW5hdGlvbioqOgogICAgLSAgIFRoZSBhbmNob3IgcGFydCBpbml0aWFsaXplcyB0aGUgc2VxdWVuY2Ugd2l0aCBgMWAuCiAgICAtICAgVGhlIHJlY3Vyc2l2ZSBwYXJ0IGluY3JlbWVudHMgYG5gIGJ5IDEgdW50aWwgaXQgcmVhY2hlcyAxMC4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjICoqNS4gQ29tYmluaW5nIE11bHRpcGxlIENURXMqKgoKU1FMaXRlIGFsbG93cyBkZWZpbmluZyBtdWx0aXBsZSBDVEVzIGluIGEgcXVlcnkuIEZvciBleGFtcGxlLCBjb25zaWRlciB0aGUgYE9yZGVyc2AgdGFibGUgYWdhaW4sIGFuZCB5b3Ugd2FudCB0byBjYWxjdWxhdGU6IDEuIFRoZSB0b3RhbCByZXZlbnVlIGZvciAyMDI0LiAyLiBUaGUgdG90YWwgbnVtYmVyIG9mIG9yZGVycyBmb3IgZWFjaCBjdXN0b21lciBpbiAyMDI0LgoKYGBgIHNxbApXSVRIIFRvdGFsUmV2ZW51ZSBBUyAoCiAgICBTRUxFQ1QgU1VNKFRvdGFsQW1vdW50KSBBUyBSZXZlbnVlMjAyNAogICAgRlJPTSBPcmRlcnMKICAgIFdIRVJFIHN0cmZ0aW1lKCclWScsIE9yZGVyRGF0ZSkgPSAnMjAyNCcKKSwKQ3VzdG9tZXJPcmRlcnMgQVMgKAogICAgU0VMRUNUIEN1c3RvbWVySUQsIENPVU5UKE9yZGVySUQpIEFTIE9yZGVyQ291bnQKICAgIEZST00gT3JkZXJzCiAgICBXSEVSRSBzdHJmdGltZSgnJVknLCBPcmRlckRhdGUpID0gJzIwMjQnCiAgICBHUk9VUCBCWSBDdXN0b21lcklECikKU0VMRUNUIGNvLkN1c3RvbWVySUQsIGNvLk9yZGVyQ291bnQsIHRyLlJldmVudWUyMDI0CkZST00gQ3VzdG9tZXJPcmRlcnMgY28KQ1JPU1MgSk9JTiBUb3RhbFJldmVudWUgdHI7CmBgYAoKLSAgICoqRXhwbGFuYXRpb24qKjoKICAgIC0gICBUaGUgYFRvdGFsUmV2ZW51ZWAgQ1RFIGNhbGN1bGF0ZXMgdGhlIG92ZXJhbGwgcmV2ZW51ZSBmb3IgMjAyNC4KICAgIC0gICBUaGUgYEN1c3RvbWVyT3JkZXJzYCBDVEUgY2FsY3VsYXRlcyB0aGUgbnVtYmVyIG9mIG9yZGVycyBmb3IgZWFjaCBjdXN0b21lciBpbiAyMDI0LgogICAgLSAgIFRoZSBtYWluIHF1ZXJ5IGNvbWJpbmVzIHRoZXNlIHJlc3VsdHMsIHNob3dpbmcgdGhlIG51bWJlciBvZiBvcmRlcnMgcGVyIGN1c3RvbWVyIGFsb25nIHdpdGggdGhlIHRvdGFsIHJldmVudWUuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAqKldoeSBVc2UgQ1RFcyBpbiBTUUxpdGU/KioKCkNURXMgaW4gU1FMaXRlOiAtIEVuaGFuY2UgcmVhZGFiaWxpdHkgYnkgYnJlYWtpbmcgZG93biBjb21wbGV4IHF1ZXJpZXMuIC0gRW5hYmxlIHJlY3Vyc2lvbiBmb3IgaGllcmFyY2hpY2FsIGRhdGEgb3Igc2VxdWVuY2UgZ2VuZXJhdGlvbi4gLSBBbGxvdyByZXVzYWJsZSBxdWVyeSBjb21wb25lbnRzLCBhdm9pZGluZyBkdXBsaWNhdGlvbi4KCldoaWxlIG5vdCBhbHdheXMgbmVjZXNzYXJ5LCBDVEVzIGNhbiBzaW1wbGlmeSBsb2dpYyBhbmQgbWFrZSBxdWVyaWVzIGVhc2llciB0byBtYWludGFpbi4gSG93ZXZlciwgZm9yIHZlcnkgbGFyZ2UgZGF0YXNldHMgb3IgcGVyZm9ybWFuY2UtY3JpdGljYWwgYXBwbGljYXRpb25zLCB0ZXN0aW5nIHRoZSBpbXBhY3Qgb2YgQ1RFcyB2ZXJzdXMgc3VicXVlcmllcyBvciB0ZW1wb3JhcnkgdGFibGVzIGlzIGltcG9ydGFudCBzaW5jZSBTUUxpdGUgaGFuZGxlcyBDVEVzIGFzIGlubGluZSBxdWVyeSBmcmFnbWVudHMgcmF0aGVyIHRoYW4gbWF0ZXJpYWxpemVkIHZpZXdzLgoKIyMgRXhhbXBsZSBDVEUgUXVlcmllcwoKR2l2ZW4gdGhlIHRhYmxlIGRlZmluaXRpb24gYW5kIHRoZSBpbnNlcnRlZCBkYXRhOgoKYGBgIHNxbApDUkVBVEUgVEFCTEUgVCAoYSBJTlQsIGIgSU5UKTsKCklOU0VSVCBJTlRPIFQgVkFMVUVTICgxMSwgMjApLCAoMTAsIDIwKSwgKDEwLCAyMCksICgxMCwgMjApLCAoODgsIDc3KTsKYGBgCgpUaGUgdGFibGUgYFRgIG5vdyBjb250YWlucyB0aGUgZm9sbG93aW5nIGRhdGE6Cgp8IGEgICB8IGIgICB8CnwtLS0tLXwtLS0tLXwKfCAxMSAgfCAyMCAgfAp8IDEwICB8IDIwICB8CnwgMTAgIHwgMjAgIHwKfCAxMCAgfCAyMCAgfAp8IDg4ICB8IDc3ICB8CgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAqKjEuIFF1ZXJ5OiBTZWxlY3RpbmcgQWxsIERhdGEqKgoKVG8gdmlldyBhbGwgcm93cyBpbiB0aGUgdGFibGU6CgpgYGAgc3FsClNFTEVDVCAqIEZST00gVDsKYGBgCgoqKlJlc3VsdDoqKiBcfCBhIFx8IGIgXHwgXHwtLS0tXHwtLS0tXHwgXHwgMTEgXHwgMjAgXHwgXHwgMTAgXHwgMjAgXHwgXHwgMTAgXHwgMjAgXHwgXHwgMTAgXHwgMjAgXHwgXHwgODggXHwgNzcgXHwKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjICoqMi4gUXVlcnk6IFVzaW5nIGEgQ29tbW9uIFRhYmxlIEV4cHJlc3Npb24gKENURSkgdG8gUmVtb3ZlIER1cGxpY2F0ZXMqKgoKWW91IG1pZ2h0IHdhbnQgdG8gZWxpbWluYXRlIGR1cGxpY2F0ZSByb3dzLCB3aGljaCBTUUxpdGUgY2FuIGFjaGlldmUgd2l0aCB0aGUgYERJU1RJTkNUYCBrZXl3b3JkLiBVc2luZyBhIENURToKCmBgYCBzcWwKV0lUSCBEaXN0aW5jdFJvd3MgQVMgKAogICAgU0VMRUNUIERJU1RJTkNUIGEsIGIKICAgIEZST00gVAopClNFTEVDVCAqIApGUk9NIERpc3RpbmN0Um93czsKYGBgCgoqKlJlc3VsdDoqKiBcfCBhIFx8IGIgXHwgXHwtLS0tXHwtLS0tXHwgXHwgMTEgXHwgMjAgXHwgXHwgMTAgXHwgMjAgXHwgXHwgODggXHwgNzcgXHwKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjICoqMy4gUXVlcnk6IENvdW50IE9jY3VycmVuY2VzIG9mIEVhY2ggUm93KioKClRvIGNvdW50IGhvdyBtYW55IHRpbWVzIGVhY2ggcGFpciBgKGEsIGIpYCBhcHBlYXJzIGluIHRoZSB0YWJsZToKCmBgYCBzcWwKV0lUSCBSb3dDb3VudHMgQVMgKAogICAgU0VMRUNUIGEsIGIsIENPVU5UKCopIEFTIENvdW50CiAgICBGUk9NIFQKICAgIEdST1VQIEJZIGEsIGIKKQpTRUxFQ1QgKgpGUk9NIFJvd0NvdW50czsKYGBgCgoqKlJlc3VsdDoqKiBcfCBhIFx8IGIgXHwgQ291bnQgXHwgXHwtLS0tXHwtLS0tXHwtLS0tLS0tXHwgXHwgMTEgXHwgMjAgXHwgMSBcfCBcfCAxMCBcfCAyMCBcfCAzIFx8IFx8IDg4IFx8IDc3IFx8IDEgXHwKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjICoqNC4gUXVlcnk6IEZpbmQgdGhlIFJvdyB3aXRoIHRoZSBNYXhpbXVtIENvdW50KioKClRvIGlkZW50aWZ5IHRoZSBgKGEsIGIpYCBwYWlyIHRoYXQgYXBwZWFycyBtb3N0IGZyZXF1ZW50bHk6CgpgYGAgc3FsCldJVEggUm93Q291bnRzIEFTICgKICAgIFNFTEVDVCBhLCBiLCBDT1VOVCgqKSBBUyBDb3VudAogICAgRlJPTSBUCiAgICBHUk9VUCBCWSBhLCBiCikKU0VMRUNUIGEsIGIsIENvdW50CkZST00gUm93Q291bnRzCldIRVJFIENvdW50ID0gKFNFTEVDVCBNQVgoQ291bnQpIEZST00gUm93Q291bnRzKTsKYGBgCgoqKlJlc3VsdDoqKiBcfCBhIFx8IGIgXHwgQ291bnQgXHwgXHwtLS0tXHwtLS0tXHwtLS0tLS0tXHwgXHwgMTAgXHwgMjAgXHwgMyBcfAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgKio1LiBRdWVyeTogRmlsdGVyIFJvd3MgQmFzZWQgb24gQ29uZGl0aW9ucyoqCgpGb3IgZXhhbXBsZSwgc2VsZWN0aW5nIHJvd3Mgd2hlcmUgYGEgPiAxMGAgYW5kIGBiIDwgMzBgOgoKYGBgIHNxbApXSVRIIEZpbHRlcmVkUm93cyBBUyAoCiAgICBTRUxFQ1QgKgogICAgRlJPTSBUCiAgICBXSEVSRSBhID4gMTAgQU5EIGIgPCAzMAopClNFTEVDVCAqCkZST00gRmlsdGVyZWRSb3dzOwpgYGAKCioqUmVzdWx0OioqIFx8IGEgXHwgYiBcfCBcfC0tLS1cfC0tLS1cfCBcfCAxMSBcfCAyMCBcfAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgKio2LiBRdWVyeTogU3VtbWluZyBWYWx1ZXMgaW4gYSBDVEUqKgoKWW91IG1heSB3YW50IHRvIGNhbGN1bGF0ZSB0aGUgc3VtIG9mIGBhYCBhbmQgYGJgIGZvciB0aGUgZW50aXJlIHRhYmxlOgoKYGBgIHNxbApXSVRIIFRvdGFsU3VtcyBBUyAoCiAgICBTRUxFQ1QgU1VNKGEpIEFTIFN1bUEsIFNVTShiKSBBUyBTdW1CCiAgICBGUk9NIFQKKQpTRUxFQ1QgU3VtQSwgU3VtQgpGUk9NIFRvdGFsU3VtczsKYGBgCgoqKlJlc3VsdDoqKiBcfCBTdW1BIFx8IFN1bUIgXHwgXHwtLS0tLS1cfC0tLS0tLVx8IFx8IDEyOSBcfCAxNTcgXHwKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjICoqNy4gUXVlcnk6IElkZW50aWZ5IFVuaXF1ZSBSb3dzIE9ubHkqKgoKSWYgeW91IHdhbnQgcm93cyB0aGF0IGFwcGVhciBleGFjdGx5IG9uY2UgaW4gdGhlIHRhYmxlOgoKYGBgIHNxbApXSVRIIFJvd0NvdW50cyBBUyAoCiAgICBTRUxFQ1QgYSwgYiwgQ09VTlQoKikgQVMgQ291bnQKICAgIEZST00gVAogICAgR1JPVVAgQlkgYSwgYgopClNFTEVDVCBhLCBiCkZST00gUm93Q291bnRzCldIRVJFIENvdW50ID0gMTsKYGBgCgoqKlJlc3VsdDoqKiBcfCBhIFx8IGIgXHwgXHwtLS0tXHwtLS0tXHwgXHwgMTEgXHwgMjAgXHwgXHwgODggXHwgNzcgXHwKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjICoqOC4gUXVlcnk6IFJlY3Vyc2l2ZSBDVEUgRXhhbXBsZSoqCgpJZiB5b3Ugd2FudCB0byBnZW5lcmF0ZSBhIHNlcXVlbmNlIHN0YXJ0aW5nIGZyb20gdGhlIHNtYWxsZXN0IHZhbHVlIGluIGNvbHVtbiBgYWAgKGUuZy4sIGAxMGApIGFuZCBpbmNyZW1lbnQgaXQgdXAgdG8gYDE1YDoKCmBgYCBzcWwKV0lUSCBSRUNVUlNJVkUgU2VxdWVuY2UgQVMgKAogICAgU0VMRUNUIE1JTihhKSBBUyBuCiAgICBGUk9NIFQKICAgIFVOSU9OIEFMTAogICAgU0VMRUNUIG4gKyAxCiAgICBGUk9NIFNlcXVlbmNlCiAgICBXSEVSRSBuIDwgMTUKKQpTRUxFQ1QgbgpGUk9NIFNlcXVlbmNlOwpgYGAKCioqUmVzdWx0OioqIFx8IG4gXHwgXHwtLS0tXHwgXHwgMTAgXHwgXHwgMTEgXHwgXHwgMTIgXHwgXHwgMTMgXHwgXHwgMTQgXHwgXHwgMTUgXHwKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKVGhlc2UgZXhhbXBsZXMgc2hvd2Nhc2UgaG93IENURXMgY2FuIHNpbXBsaWZ5IGFuZCBtb2R1bGFyaXplIFNRTCBxdWVyaWVzIGluIFNRTGl0ZSwgbWFraW5nIHRoZW0gZWFzaWVyIHRvIHdyaXRlIGFuZCByZWFkIHdoaWxlIGhhbmRsaW5nIGNvbW1vbiB0YXNrcyBsaWtlIGRlZHVwbGljYXRpb24sIGZpbHRlcmluZywgYWdncmVnYXRpb24sIGFuZCByZWN1cnNpb24uCgojIyBTdW1tYXJ5CgpDb21tb24gVGFibGUgRXhwcmVzc2lvbnMgKENURSkgaW4gU1FMIHByb3ZpZGVzIGEgdGVtcG9yYXJ5LCBuYW1lZCByZXN1bHQgc2V0IGRlZmluZWQgd2l0aGluIHRoZSBzY29wZSBvZiBhIHNpbmdsZSBxdWVyeSB1c2luZyB0aGUgYFdJVEhgIGtleXdvcmQuIEl0IHNpbXBsaWZpZXMgY29tcGxleCBxdWVyaWVzLCBpbXByb3ZlcyByZWFkYWJpbGl0eSwgYW5kIGVuYWJsZXMgcmVjdXJzaW9uLiBDVEVzIGFyZSBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciB0YXNrcyBsaWtlIGJyZWFraW5nIGRvd24gaW50cmljYXRlIGxvZ2ljIGludG8gbW9kdWxhciBzdGVwcywgcmVtb3ZpbmcgZHVwbGljYXRlIHJvd3MsIGNvdW50aW5nIG9jY3VycmVuY2VzIG9mIHNwZWNpZmljIGRhdGEsIGZpbHRlcmluZywgYWdncmVnYXRpbmcsIGFuZCBoYW5kbGluZyByZWN1cnNpdmUgb3BlcmF0aW9ucyBzdWNoIGFzIGhpZXJhcmNoaWNhbCBkYXRhIHRyYXZlcnNhbCBvciBnZW5lcmF0aW5nIHNlcXVlbmNlcy4KCldoaWxlIG5vdCBtYW5kYXRvcnksIENURXMgbWFrZSBxdWVyaWVzIG1vcmUgbWFpbnRhaW5hYmxlIGFuZCBleHByZXNzaXZlLCBlc3BlY2lhbGx5IGZvciBpbnRlcm1lZGlhdGUgY2FsY3VsYXRpb25zIG9yIHdoZW4gbG9naWMgbmVlZHMgdG8gYmUgcmV1c2VkIHdpdGhpbiBhIHNpbmdsZSBTUUwgc3RhdGVtZW50LgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBGaWxlcyAmIFJlc291cmNlcwoKYGBge3IgemlwRmlsZXMsIGVjaG89RkFMU0V9CnppcE5hbWUgPSBzcHJpbnRmKCJMZXNzb25GaWxlcy0lcy0lcy56aXAiLCAKICAgICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksCiAgICAgICAgICAgICAgICAgcGFyYW1zJG51bWJlcikKCnRleHRBTGluayA9IHBhc3RlMCgiQWxsIEZpbGVzIGZvciBMZXNzb24gIiwgCiAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwiLiIscGFyYW1zJG51bWJlcikKCiMgZG93bmxvYWRGaWxlc0xpbmsoKSBpcyBpbmNsdWRlZCBmcm9tIF9pbnNlcnQyREIuUgprbml0cjo6cmF3X2h0bWwoZG93bmxvYWRGaWxlc0xpbmsoIi4iLCB6aXBOYW1lLCB0ZXh0QUxpbmspKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgUmVmZXJlbmNlcwoKTm8gcmVmZXJlbmNlcy4KCiMjIEVycmF0YQoKW0xldCB1cyBrbm93XShodHRwczovL2Zvcm0uam90Zm9ybS5jb20vMjEyMTg3MDcyNzg0MTU3KXt0YXJnZXQ9Il9ibGFuayJ9Lgo=