Objectives

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

  • create transactions in SQLite
  • explain when to use transactions

Introduction

In this lesson, you will learn about how to specify transactions and define data integrity under concurrent access in SQLite.

A transaction is a sequence of database modifications and queries that occur as a single sequence. The database meets all integrity constraints before and after the transaction.

A transaction must be explicitly started and, if all operations were successful, committed. If an operation within a transaction is not successful, then the transaction must be aborted or rolled back. A rollback restores the database to the state prior to the start of the transaction and all updates are reversed.

For more information on transactions and concurrency, see Lesson 60.701 Transaction Processing in Relational Databases.

To follow along, go to Files & Resources and download the R Notebook and copy (or better yet, type) the R and SQL code chunks into an R Notebook of your own – and experiment along the way.

SQLite and ACID

SQLite is a transactional database; it ensures that all modifications (i.e., inserts, updates, and deletes) and queries exhibit the ACID properties, i.e., they are atomic, consistent, isolated, and durable.

Adhering to the ACID properties implies that in SQLite all modifications leave the database in a consistent state even if a transaction is interrupted by a program crash, operation system dump, or power failure to the computer.

ACID Properties

Atomic: A transaction must be atomic, i.e., a sequence of modification operations cannot be broken down into smaller ones. When a a transaction is committed, either all modifications are applied or none are applied, i.e., no partial updates.

Consistent: a transaction must ensure to change the database from one valid state to another. When a transaction starts and executes a statement to modify data, the database becomes inconsistent. However, when the transaction is committed or rolled back, it is important that the transaction must keep the database consistent.

Isolated: a pending transaction performed by a session must be isolated from other sessions. When a session starts a transaction and executes the INSERT or UPDATE statement to change the data, these changes are only visible to the current session, not others. On the other hand, the changes committed by other sessions after the transaction started should not be visible to the current session.

Durable: if a transaction is successfully committed, the changes must be permanent in the database regardless of the condition such as power failure or program crash. On the contrary, if the program crashes before the transaction is committed, the change should not persist.

Transactions in SQLite

Begin Transaction

By default, SQLite operates in auto-commit mode. This means that for each command that modifies the database (i.e., INSERT, UPDATE, DELETE), SQLite starts a transaction, processes the command, and commits the transaction automatically.

To start a transaction explicitly, issue the BEGIN TRANSACTION command. As SQLite does not support nested transactions, a new transaction cannot be started until the current transaction is committed or rolled back.

begin transaction;

After starting a transaction, the transaction is active until it is explicitly committed or rolled back. Any changes made to the database are only visible to the application that initiated the transaction and are not visible to anyone else. Any other client connected to the database will see that data in the state prior to the start of the transaction (the atomic property). Any SELECT queries by other clients will no see any updates done within the transaction until the transaction is committed.

Commit Transaction

To commit a transaction, i.e., to make permanent any changes done after the start of the transaction, requires an explicit COMMIT or COMMIT TRANSACTION statement.

commit transaction;

Rollback Transaction

If an error occurred during the transaction or, for some reason, the changes should not be made permanent, then all changes can undone using a ROLLBACK or ROLLBACK TRANSACTION statement. If a rollback is perform rather than a commit, then the state of the database is returned to the state just prior to the start of the transaction.

rollback transaction;

Nested Transactions

Nested transactions are a concept in database management systems (DBMS) where a transaction contains one or more sub-transactions. These sub-transactions are referred to as “nested transactions”. The main transaction, also known as the outer or parent transaction, is responsible for managing the nested transactions. This hierarchy allows for better control and isolation of operations, as each nested transaction can be individually committed or rolled back without affecting the other transactions.

In a nested transaction model, if a nested transaction commits successfully, its changes are not immediately made permanent in the database. Instead, the changes are only visible to its parent transaction and are considered temporary. The parent transaction must also commit successfully for the changes made by its nested transactions to become permanent. If any nested transaction or the parent transaction fails, the whole transaction hierarchy can be rolled back, undoing all changes.

Nested transactions are useful in situations where a complex operation requires multiple, related sub-operations that depend on each other, and you want to ensure data consistency and integrity. If one of the sub-operations fails, you may need to undo the changes made by the other sub-operations, which can be achieved by rolling back the nested transaction.

There are read and there are write transactions. In a read transaction you read a consistent state of the database if when others are manipulating the data you are reading – as your application will see the state of the database at the start of the transaction. This can be critical for analytics or calculations where the underlying data must be consistent. So, you could use a nested read transactions within an outer transaction that might make modifications to the database.

You do that because you don’t have to look everything – remember that transactions requires shadow tables or non-concurrency which reduces database server performance.

It can help with making transactions more granular which can increase concurrency and performance of the database server. Always remember that your application is often not the only one accessing the database… think of an airline reservation system where thousands or hundreds of thousands of flight bookings occur every minute and so you have lots of concurrent transactions. Nesting can help isolate smaller parts of the database and increase overall concurrency.

A rollback or commit implicitly closes the transaction and a new transaction can be started. As mentioned before, SQLite does not support nested transactions, i.e., transactions within a transaction. Nested transactions can be useful when some change within a transaction should be made permanent while others should not be, all while not allowing other clients to see any partial updates. Databases like Oracle and Microsoft SQL Server do support nested transactions.

Read Transactions

While it is not common to place SELECT statements within a transaction, it can sometimes be useful when we want to guarantee that we read all tables from a defined state – this can be especially useful when generating reports.

Classic Example

The classic example to motivate transactions is a transfer of money from one account to another in a banking system. One account is debited and then another account is credited. No other client should see one account being debited before the other is credited as that would lead to inconsistency. Furthermore, most banking application have an accounting transactions log called the General Journal where all debits and credits are recorded. Let’s look at the code for doing this, starting with a definition of the tables. We will need a table for accounts and a table for the journal.

CREATE TABLE IF NOT EXISTS accounts ( 
    account_no INTEGER NOT NULL, 
    balance DECIMAL NOT NULL DEFAULT 0,
    PRIMARY KEY(account_no),
  CHECK(balance >= 0)
);
CREATE TABLE IF NOT EXISTS journal (
    change_no INTEGER PRIMARY KEY AUTOINCREMENT,
    account_no INTEGER NOT NULL, 
    flag TEXT NOT NULL, 
    amount DECIMAL NOT NULL, 
    change_date DATE NOT NULL,
    FOREIGN KEY (account_no) 
     REFERENCES accounts(account_no)
);

Next, we will insert sample data into the accounts table that we can use for a “transfer”. After this the database will contain two accounts, one with a balance of \(1100\) and another with a balance of \(2200\), each having an account number.

INSERT INTO accounts 
     (account_no, balance)
     VALUES (117860, 1100),
            (299871, 2200);

Now, the “transfer”: a transfer of \(100\) from account 117860 to account 299871 with an entry in the journal. This requires four data changes to the database: an update of the balance in the two accounts and insertions of two new rows into the journal. This must be done within a transaction because in a concurrent access scenario, our client might update the first balance, then the database might process a read from the database for another client that is also connected to the database. That client would now see that the balance is less but the other account is not yet updated: an inconsistency.

BEGIN TRANSACTION;
UPDATE accounts
   SET balance = balance - 100
 WHERE account_no = 117860;
UPDATE accounts
   SET balance = balance + 100
 WHERE account_no = 299871;
INSERT INTO journal 
     (account_no,flag,amount,change_date) 
     VALUES (117860, 'D', 100, date('now'));
INSERT INTO journal
     (account_no,flag,amount,change_date) 
     VALUES (299871, 'C', 100, date('now'));
COMMIT;

If any part of the update cannot be done, then we would issue a ROLLBACK rather than a COMMIT.

Let’s see what the tables contain after the transfer transaction.

NA
Table 1: 2 records
account_no balance
117860 1000
299871 2300
NA
Table 2: 2 records
change_no account_no flag amount change_date
1 117860 D 100 2024-02-14
2 299871 C 100 2024-02-14

Experiment with this code and set up a concurrent situation and then run the code with an without the transaction logic.

Transactions in Applications

Of course, in an application, we would need to use conditional statements to determine when and whether to commit or rollback. In R, the above transaction code would be best placed within a function, perhaps as shown below. The function doTransfer takes source and a destination account numbers plus an amount to transfer and then executes the SQL statements within a transaction and commits if successful or rolls back if any of them failed. The function also takes the database connection object as a parameter.

The function dbSendStatement() is used to send update, delete, and insert statements plus other database commands such as for dropping tables, creating tables or indexes, and, of course, transaction logic. It is a synchronous method that returns once the command has been executed. As an alternative, we can call dbExecute() which calls dbSendStatement() and returns the number of rows affected; if that number is less than one then the command was not successful.

doTransfer <- function (dbcon, acctNoSrc, acctNoDest, amount)
{
  txnFailed = FALSE
  
  if (acctNoSrc == acctNoDest)
  {
    # can't transfer to same account
    return (FALSE)
  }
  
  dbExecute(dbcon, "BEGIN TRANSACTION")

  # debit source account
  sql <- "UPDATE accounts
             SET balance = balance - ?
           WHERE account_no = ?"
  ps <- dbSendStatement(dbcon, sql,
                        params = list(amount, acctNoSrc))
  if (dbGetRowsAffected(ps) < 1)
    txnFailed = TRUE
  dbClearResult(ps)

  # credit destination account
  sql <- "UPDATE accounts
             SET balance = balance + ?
           WHERE account_no = ?"
  ps <- dbSendStatement(dbcon, sql,
                        params = list(amount, acctNoDest))
  if (dbGetRowsAffected(ps) < 1)
    txnFailed = TRUE
  dbClearResult(ps)
  
  # add accounting transaction to journal
  sql <- "INSERT INTO journal 
           (account_no,flag,amount,change_date) 
          VALUES (?, 'D', ?, date('now'))"
  ps <- dbSendStatement(dbcon, sql,
                        params = list(acctNoSrc, amount))
  if (dbGetRowsAffected(ps) < 1)
    txnFailed = TRUE
  dbClearResult(ps)
  
  sql <- "INSERT INTO journal
           (account_no,flag,amount,change_date) 
          VALUES (?, 'C', ?, date('now'))"
  ps <- dbSendStatement(dbcon, sql,
                        params = list(acctNoDest, amount))
  if (dbGetRowsAffected(ps) < 1)
    txnFailed = TRUE
  dbClearResult(ps)


  # commit transaction if no failure, otherwise rollback
  if (txnFailed == TRUE)
    dbExecute(dbcon, "ROLLBACK TRANSACTION")
  else
    dbExecute(dbcon, "COMMIT TRANSACTION")

  # return status; TRUE if successful; FALSE if failed
  return (!txnFailed)
}

To test the function, we will call it with two account numbers and an amount.

srcAccount <- '117860'
destAccount <- '299871'
amount <- 99

status <- doTransfer(dbcon, srcAccount, destAccount, amount)

if (status == TRUE) {
  cat('Transfer successful')
} else {
  cat('Transfer failed')
}
Transfer successful

To verify that the database was correctly updated, we should inspect all the tables that were affected, but for brevity we will only look at the table containing the journal entries.

Table 3: 4 records
change_no account_no flag amount change_date
1 117860 D 100 2024-02-14
2 299871 C 100 2024-02-14
3 117860 D 99 2024-02-14
4 299871 C 99 2024-02-14

Now that we know that it commits correctly, let’s transfer to an account that does not exist; then the transaction should fail and no log entry should have been created.

srcAccount <- '117860'
destAccount <- '999999'
amount <- 200

status <- doTransfer(dbcon, srcAccount, destAccount, amount)

if (status == TRUE) {
  cat('Transfer successful')
} else {
  cat('Transfer failed')
}
Transfer failed

And, indeed, the journal doesn’t contain the entry.

Table 4: 4 records
change_no account_no flag amount change_date
1 117860 D 100 2024-02-14
2 299871 C 100 2024-02-14
3 117860 D 99 2024-02-14
4 299871 C 99 2024-02-14

Conclusion

Transactions are necessary to ensure data integrity when a database is modified concurrently by multiple users or applications. This lesson explained how to create transactions in SQLite and perform commit and rollback functions.

When databases can be accessed concurrently, all updates that consist of more than one modification must be done as a transaction, otherwise data integrity issues will arise.


Files & Resources

All Files for Lesson 70.821

References

SQLite Transactions

Errata

None collected yet. Let us know.

LS0tCnRpdGxlOiAiVHJhbnNhY3Rpb25zIGluIFNRTGl0ZSIKcGFyYW1zOgogIGNhdGVnb3J5OiA3MAogIG51bWJlcjogODIxCiAgdGltZTogMzAKICBsZXZlbDogYmVnaW5uZXIKICB0YWdzOiAic3FsaXRlLHRyYW5zYWN0aW9ucyxhY2lkLGNvbmN1cnJlbmN5IgogIGRlc2NyaXB0aW9uOiAiVGhpcyBsZXNzb24gZXhwbGFpbnMgaG93IHRyYW5zYWN0aW9ucyBhcmUgc3BlY2lmaWVkCiAgICAgICAgICAgICAgICBpbiBTUUxpdGUgdG8gYWNoaWV2ZSBkYXRhIGludGVncml0eSB1bmRlciBjb25jdXJyZW50CiAgICAgICAgICAgICAgICBkYXRhYmFzZSBhY2Nlc3MuIgpkYXRlOiAiPHNtYWxsPmByIFN5cy5EYXRlKClgPC9zbWFsbD4iCmF1dGhvcjogIjxzbWFsbD5NYXJ0aW4gU2NoZWRsYmF1ZXI8L3NtYWxsPiIKZW1haWw6ICJtLnNjaGVkbGJhdWVyQG5ldS5lZHUiCmFmZmlsaXRhdGlvbjogIk5vcnRoZWFzdGVybiBVbml2ZXJzaXR5IgpvdXRwdXQ6IAogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogc3BhY2VsYWIKICAgIGhpZ2hsaWdodDogdGFuZ28KLS0tCgotLS0KdGl0bGU6ICI8c21hbGw+YHIgcGFyYW1zJGNhdGVnb3J5YC5gciBwYXJhbXMkbnVtYmVyYDwvc21hbGw+PGJyLz48c3BhbiBzdHlsZT0nY29sb3I6ICMyRTQwNTM7IGZvbnQtc2l6ZTogMC45ZW0nPmByIHJtYXJrZG93bjo6bWV0YWRhdGEkdGl0bGVgPC9zcGFuPiIKLS0tCgpgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9faW5zZXJ0MkRCLlInKSksIGluY2x1ZGUgPSBGQUxTRX0KYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIE9iamVjdGl2ZXMKClVwb24gY29tcGxldGlvbiBvZiB0aGlzIGxlc3NvbiwgeW91IHdpbGwgYmUgYWJsZSB0bzoKCi0gICBjcmVhdGUgdHJhbnNhY3Rpb25zIGluIFNRTGl0ZQotICAgZXhwbGFpbiB3aGVuIHRvIHVzZSB0cmFuc2FjdGlvbnMKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIGxlc3NvbiwgeW91IHdpbGwgbGVhcm4gYWJvdXQgaG93IHRvIHNwZWNpZnkgdHJhbnNhY3Rpb25zIGFuZCBkZWZpbmUgZGF0YSBpbnRlZ3JpdHkgdW5kZXIgY29uY3VycmVudCBhY2Nlc3MgaW4gU1FMaXRlLgoKQSB0cmFuc2FjdGlvbiBpcyBhIHNlcXVlbmNlIG9mIGRhdGFiYXNlIG1vZGlmaWNhdGlvbnMgYW5kIHF1ZXJpZXMgdGhhdCBvY2N1ciBhcyBhIHNpbmdsZSBzZXF1ZW5jZS4gVGhlIGRhdGFiYXNlIG1lZXRzIGFsbCBpbnRlZ3JpdHkgY29uc3RyYWludHMgYmVmb3JlIGFuZCBhZnRlciB0aGUgdHJhbnNhY3Rpb24uCgpBIHRyYW5zYWN0aW9uIG11c3QgYmUgZXhwbGljaXRseSBzdGFydGVkIGFuZCwgaWYgYWxsIG9wZXJhdGlvbnMgd2VyZSBzdWNjZXNzZnVsLCBjb21taXR0ZWQuIElmIGFuIG9wZXJhdGlvbiB3aXRoaW4gYSB0cmFuc2FjdGlvbiBpcyBub3Qgc3VjY2Vzc2Z1bCwgdGhlbiB0aGUgdHJhbnNhY3Rpb24gbXVzdCBiZSBhYm9ydGVkIG9yIHJvbGxlZCBiYWNrLiBBIHJvbGxiYWNrIHJlc3RvcmVzIHRoZSBkYXRhYmFzZSB0byB0aGUgc3RhdGUgcHJpb3IgdG8gdGhlIHN0YXJ0IG9mIHRoZSB0cmFuc2FjdGlvbiBhbmQgYWxsIHVwZGF0ZXMgYXJlIHJldmVyc2VkLgoKRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdHJhbnNhY3Rpb25zIGFuZCBjb25jdXJyZW5jeSwgc2VlIExlc3NvbiBbNjAuNzAxIFRyYW5zYWN0aW9uIFByb2Nlc3NpbmcgaW4gUmVsYXRpb25hbCBEYXRhYmFzZXNdKGh0dHA6Ly9hcnRpZmljaXVtLnVzL2xlc3NvbnMvNjAuZGJkZXNpZ24vbC02MC03MDEtdHJhbnNhY3Rpb25zL2wtNjAtNzAxLmh0bWwpLgoKVG8gZm9sbG93IGFsb25nLCBnbyB0byBbRmlsZXMgJiBSZXNvdXJjZXNdKCNmaWxlcy1yZXNvdXJjZXMpIGFuZCBkb3dubG9hZCB0aGUgUiBOb3RlYm9vayBhbmQgY29weSAob3IgYmV0dGVyIHlldCwgdHlwZSkgdGhlIFIgYW5kIFNRTCBjb2RlIGNodW5rcyBpbnRvIGFuIFIgTm90ZWJvb2sgb2YgeW91ciBvd24gLS0gYW5kIGV4cGVyaW1lbnQgYWxvbmcgdGhlIHdheS4KCmBgYHtyIGluY2x1ZGU9Rn0KdW5saW5rKCJ0eG5zLWRlbW9EQi5zcWxpdGVkYiIpCmBgYAoKYGBge3IgY3JlYXRlREIsIGVjaG89Rn0KbGlicmFyeShSU1FMaXRlKQpkYmNvbiA8LSBkYkNvbm5lY3QoUlNRTGl0ZTo6U1FMaXRlKCksICJ0eG5zLWRlbW9EQi5zcWxpdGVkYiIpCmBgYAoKIyMgU1FMaXRlIGFuZCBBQ0lECgpTUUxpdGUgaXMgYSB0cmFuc2FjdGlvbmFsIGRhdGFiYXNlOyBpdCBlbnN1cmVzIHRoYXQgYWxsIG1vZGlmaWNhdGlvbnMgKCppLmUuKiwgaW5zZXJ0cywgdXBkYXRlcywgYW5kIGRlbGV0ZXMpIGFuZCBxdWVyaWVzIGV4aGliaXQgdGhlIEFDSUQgcHJvcGVydGllcywgKmkuZS4qLCB0aGV5IGFyZSBhdG9taWMsIGNvbnNpc3RlbnQsIGlzb2xhdGVkLCBhbmQgZHVyYWJsZS4KCkFkaGVyaW5nIHRvIHRoZSBBQ0lEIHByb3BlcnRpZXMgaW1wbGllcyB0aGF0IGluIFNRTGl0ZSBhbGwgbW9kaWZpY2F0aW9ucyBsZWF2ZSB0aGUgZGF0YWJhc2UgaW4gYSBjb25zaXN0ZW50IHN0YXRlIGV2ZW4gaWYgYSB0cmFuc2FjdGlvbiBpcyBpbnRlcnJ1cHRlZCBieSBhIHByb2dyYW0gY3Jhc2gsIG9wZXJhdGlvbiBzeXN0ZW0gZHVtcCwgb3IgcG93ZXIgZmFpbHVyZSB0byB0aGUgY29tcHV0ZXIuCgojIyMgQUNJRCBQcm9wZXJ0aWVzCgoqKkF0b21pYyoqOiBBIHRyYW5zYWN0aW9uIG11c3QgYmUgYXRvbWljLCAqaS5lLiosIGEgc2VxdWVuY2Ugb2YgbW9kaWZpY2F0aW9uIG9wZXJhdGlvbnMgY2Fubm90IGJlIGJyb2tlbiBkb3duIGludG8gc21hbGxlciBvbmVzLiBXaGVuIGEgYSB0cmFuc2FjdGlvbiBpcyBjb21taXR0ZWQsIGVpdGhlciBhbGwgbW9kaWZpY2F0aW9ucyBhcmUgYXBwbGllZCBvciBub25lIGFyZSBhcHBsaWVkLCAqaS5lLiosIG5vIHBhcnRpYWwgdXBkYXRlcy4KCioqQ29uc2lzdGVudCoqOiBhIHRyYW5zYWN0aW9uIG11c3QgZW5zdXJlIHRvIGNoYW5nZSB0aGUgZGF0YWJhc2UgZnJvbSBvbmUgdmFsaWQgc3RhdGUgdG8gYW5vdGhlci4gV2hlbiBhIHRyYW5zYWN0aW9uIHN0YXJ0cyBhbmQgZXhlY3V0ZXMgYSBzdGF0ZW1lbnQgdG8gbW9kaWZ5IGRhdGEsIHRoZSBkYXRhYmFzZSBiZWNvbWVzIGluY29uc2lzdGVudC4gSG93ZXZlciwgd2hlbiB0aGUgdHJhbnNhY3Rpb24gaXMgY29tbWl0dGVkIG9yIHJvbGxlZCBiYWNrLCBpdCBpcyBpbXBvcnRhbnQgdGhhdCB0aGUgdHJhbnNhY3Rpb24gbXVzdCBrZWVwIHRoZSBkYXRhYmFzZSBjb25zaXN0ZW50LgoKKipJc29sYXRlZCoqOiBhIHBlbmRpbmcgdHJhbnNhY3Rpb24gcGVyZm9ybWVkIGJ5IGEgc2Vzc2lvbiBtdXN0IGJlIGlzb2xhdGVkIGZyb20gb3RoZXIgc2Vzc2lvbnMuIFdoZW4gYSBzZXNzaW9uIHN0YXJ0cyBhIHRyYW5zYWN0aW9uIGFuZCBleGVjdXRlcyB0aGUgSU5TRVJUIG9yIFVQREFURSBzdGF0ZW1lbnQgdG8gY2hhbmdlIHRoZSBkYXRhLCB0aGVzZSBjaGFuZ2VzIGFyZSBvbmx5IHZpc2libGUgdG8gdGhlIGN1cnJlbnQgc2Vzc2lvbiwgbm90IG90aGVycy4gT24gdGhlIG90aGVyIGhhbmQsIHRoZSBjaGFuZ2VzIGNvbW1pdHRlZCBieSBvdGhlciBzZXNzaW9ucyBhZnRlciB0aGUgdHJhbnNhY3Rpb24gc3RhcnRlZCBzaG91bGQgbm90IGJlIHZpc2libGUgdG8gdGhlIGN1cnJlbnQgc2Vzc2lvbi4KCioqRHVyYWJsZSoqOiBpZiBhIHRyYW5zYWN0aW9uIGlzIHN1Y2Nlc3NmdWxseSBjb21taXR0ZWQsIHRoZSBjaGFuZ2VzIG11c3QgYmUgcGVybWFuZW50IGluIHRoZSBkYXRhYmFzZSByZWdhcmRsZXNzIG9mIHRoZSBjb25kaXRpb24gc3VjaCBhcyBwb3dlciBmYWlsdXJlIG9yIHByb2dyYW0gY3Jhc2guIE9uIHRoZSBjb250cmFyeSwgaWYgdGhlIHByb2dyYW0gY3Jhc2hlcyBiZWZvcmUgdGhlIHRyYW5zYWN0aW9uIGlzIGNvbW1pdHRlZCwgdGhlIGNoYW5nZSBzaG91bGQgbm90IHBlcnNpc3QuCgojIyBUcmFuc2FjdGlvbnMgaW4gU1FMaXRlCgojIyMgQmVnaW4gVHJhbnNhY3Rpb24KCkJ5IGRlZmF1bHQsIFNRTGl0ZSBvcGVyYXRlcyBpbiBhdXRvLWNvbW1pdCBtb2RlLiBUaGlzIG1lYW5zIHRoYXQgZm9yIGVhY2ggY29tbWFuZCB0aGF0IG1vZGlmaWVzIHRoZSBkYXRhYmFzZSAoKmkuZS4qLCBJTlNFUlQsIFVQREFURSwgREVMRVRFKSwgU1FMaXRlIHN0YXJ0cyBhIHRyYW5zYWN0aW9uLCBwcm9jZXNzZXMgdGhlIGNvbW1hbmQsIGFuZCBjb21taXRzIHRoZSB0cmFuc2FjdGlvbiBhdXRvbWF0aWNhbGx5LgoKVG8gc3RhcnQgYSB0cmFuc2FjdGlvbiBleHBsaWNpdGx5LCBpc3N1ZSB0aGUgKkJFR0lOIFRSQU5TQUNUSU9OKiBjb21tYW5kLiBBcyBTUUxpdGUgZG9lcyBub3Qgc3VwcG9ydCBuZXN0ZWQgdHJhbnNhY3Rpb25zLCBhIG5ldyB0cmFuc2FjdGlvbiBjYW5ub3QgYmUgc3RhcnRlZCB1bnRpbCB0aGUgY3VycmVudCB0cmFuc2FjdGlvbiBpcyBjb21taXR0ZWQgb3Igcm9sbGVkIGJhY2suCgpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb24sIG91dHB1dC52YXI9Im5yIiwgd2FybmluZ3M9Rn0KYmVnaW4gdHJhbnNhY3Rpb247CmBgYAoKQWZ0ZXIgc3RhcnRpbmcgYSB0cmFuc2FjdGlvbiwgdGhlIHRyYW5zYWN0aW9uIGlzIGFjdGl2ZSB1bnRpbCBpdCBpcyBleHBsaWNpdGx5IGNvbW1pdHRlZCBvciByb2xsZWQgYmFjay4gQW55IGNoYW5nZXMgbWFkZSB0byB0aGUgZGF0YWJhc2UgYXJlIG9ubHkgdmlzaWJsZSB0byB0aGUgYXBwbGljYXRpb24gdGhhdCBpbml0aWF0ZWQgdGhlIHRyYW5zYWN0aW9uIGFuZCBhcmUgbm90IHZpc2libGUgdG8gYW55b25lIGVsc2UuIEFueSBvdGhlciBjbGllbnQgY29ubmVjdGVkIHRvIHRoZSBkYXRhYmFzZSB3aWxsIHNlZSB0aGF0IGRhdGEgaW4gdGhlIHN0YXRlIHByaW9yIHRvIHRoZSBzdGFydCBvZiB0aGUgdHJhbnNhY3Rpb24gKHRoZSAqYXRvbWljKiBwcm9wZXJ0eSkuIEFueSAqU0VMRUNUKiBxdWVyaWVzIGJ5IG90aGVyIGNsaWVudHMgd2lsbCBubyBzZWUgYW55IHVwZGF0ZXMgZG9uZSB3aXRoaW4gdGhlIHRyYW5zYWN0aW9uIHVudGlsIHRoZSB0cmFuc2FjdGlvbiBpcyBjb21taXR0ZWQuCgojIyMgQ29tbWl0IFRyYW5zYWN0aW9uCgpUbyBjb21taXQgYSB0cmFuc2FjdGlvbiwgKmkuZS4qLCB0byBtYWtlIHBlcm1hbmVudCBhbnkgY2hhbmdlcyBkb25lIGFmdGVyIHRoZSBzdGFydCBvZiB0aGUgdHJhbnNhY3Rpb24sIHJlcXVpcmVzIGFuIGV4cGxpY2l0ICpDT01NSVQqIG9yICpDT01NSVQgVFJBTlNBQ1RJT04qIHN0YXRlbWVudC4KCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbiwgb3V0cHV0LnZhcj0ibnIiLCB3YXJuaW5ncz1GfQpjb21taXQgdHJhbnNhY3Rpb247CmBgYAoKIyMjIFJvbGxiYWNrIFRyYW5zYWN0aW9uCgpJZiBhbiBlcnJvciBvY2N1cnJlZCBkdXJpbmcgdGhlIHRyYW5zYWN0aW9uIG9yLCBmb3Igc29tZSByZWFzb24sIHRoZSBjaGFuZ2VzIHNob3VsZCBub3QgYmUgbWFkZSBwZXJtYW5lbnQsIHRoZW4gYWxsIGNoYW5nZXMgY2FuIHVuZG9uZSB1c2luZyBhICpST0xMQkFDSyogb3IgKlJPTExCQUNLIFRSQU5TQUNUSU9OKiBzdGF0ZW1lbnQuIElmIGEgcm9sbGJhY2sgaXMgcGVyZm9ybSByYXRoZXIgdGhhbiBhIGNvbW1pdCwgdGhlbiB0aGUgc3RhdGUgb2YgdGhlIGRhdGFiYXNlIGlzIHJldHVybmVkIHRvIHRoZSBzdGF0ZSBqdXN0IHByaW9yIHRvIHRoZSBzdGFydCBvZiB0aGUgdHJhbnNhY3Rpb24uCgpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb24sIG91dHB1dC52YXI9Im5yIiwgd2FybmluZ3M9RiwgZXZhbD1GfQpyb2xsYmFjayB0cmFuc2FjdGlvbjsKYGBgCgojIyBOZXN0ZWQgVHJhbnNhY3Rpb25zCgpOZXN0ZWQgdHJhbnNhY3Rpb25zIGFyZSBhIGNvbmNlcHQgaW4gZGF0YWJhc2UgbWFuYWdlbWVudCBzeXN0ZW1zIChEQk1TKSB3aGVyZSBhIHRyYW5zYWN0aW9uIGNvbnRhaW5zIG9uZSBvciBtb3JlIHN1Yi10cmFuc2FjdGlvbnMuIFRoZXNlIHN1Yi10cmFuc2FjdGlvbnMgYXJlIHJlZmVycmVkIHRvIGFzICJuZXN0ZWQgdHJhbnNhY3Rpb25zIi4gVGhlIG1haW4gdHJhbnNhY3Rpb24sIGFsc28ga25vd24gYXMgdGhlIG91dGVyIG9yIHBhcmVudCB0cmFuc2FjdGlvbiwgaXMgcmVzcG9uc2libGUgZm9yIG1hbmFnaW5nIHRoZSBuZXN0ZWQgdHJhbnNhY3Rpb25zLiBUaGlzIGhpZXJhcmNoeSBhbGxvd3MgZm9yIGJldHRlciBjb250cm9sIGFuZCBpc29sYXRpb24gb2Ygb3BlcmF0aW9ucywgYXMgZWFjaCBuZXN0ZWQgdHJhbnNhY3Rpb24gY2FuIGJlIGluZGl2aWR1YWxseSBjb21taXR0ZWQgb3Igcm9sbGVkIGJhY2sgd2l0aG91dCBhZmZlY3RpbmcgdGhlIG90aGVyIHRyYW5zYWN0aW9ucy4KCkluIGEgbmVzdGVkIHRyYW5zYWN0aW9uIG1vZGVsLCBpZiBhIG5lc3RlZCB0cmFuc2FjdGlvbiBjb21taXRzIHN1Y2Nlc3NmdWxseSwgaXRzIGNoYW5nZXMgYXJlIG5vdCBpbW1lZGlhdGVseSBtYWRlIHBlcm1hbmVudCBpbiB0aGUgZGF0YWJhc2UuIEluc3RlYWQsIHRoZSBjaGFuZ2VzIGFyZSBvbmx5IHZpc2libGUgdG8gaXRzIHBhcmVudCB0cmFuc2FjdGlvbiBhbmQgYXJlIGNvbnNpZGVyZWQgdGVtcG9yYXJ5LiBUaGUgcGFyZW50IHRyYW5zYWN0aW9uIG11c3QgYWxzbyBjb21taXQgc3VjY2Vzc2Z1bGx5IGZvciB0aGUgY2hhbmdlcyBtYWRlIGJ5IGl0cyBuZXN0ZWQgdHJhbnNhY3Rpb25zIHRvIGJlY29tZSBwZXJtYW5lbnQuIElmIGFueSBuZXN0ZWQgdHJhbnNhY3Rpb24gb3IgdGhlIHBhcmVudCB0cmFuc2FjdGlvbiBmYWlscywgdGhlIHdob2xlIHRyYW5zYWN0aW9uIGhpZXJhcmNoeSBjYW4gYmUgcm9sbGVkIGJhY2ssIHVuZG9pbmcgYWxsIGNoYW5nZXMuCgpOZXN0ZWQgdHJhbnNhY3Rpb25zIGFyZSB1c2VmdWwgaW4gc2l0dWF0aW9ucyB3aGVyZSBhIGNvbXBsZXggb3BlcmF0aW9uIHJlcXVpcmVzIG11bHRpcGxlLCByZWxhdGVkIHN1Yi1vcGVyYXRpb25zIHRoYXQgZGVwZW5kIG9uIGVhY2ggb3RoZXIsIGFuZCB5b3Ugd2FudCB0byBlbnN1cmUgZGF0YSBjb25zaXN0ZW5jeSBhbmQgaW50ZWdyaXR5LiBJZiBvbmUgb2YgdGhlIHN1Yi1vcGVyYXRpb25zIGZhaWxzLCB5b3UgbWF5IG5lZWQgdG8gdW5kbyB0aGUgY2hhbmdlcyBtYWRlIGJ5IHRoZSBvdGhlciBzdWItb3BlcmF0aW9ucywgd2hpY2ggY2FuIGJlIGFjaGlldmVkIGJ5IHJvbGxpbmcgYmFjayB0aGUgbmVzdGVkIHRyYW5zYWN0aW9uLgoKVGhlcmUgYXJlIHJlYWQgYW5kIHRoZXJlIGFyZSB3cml0ZSB0cmFuc2FjdGlvbnMuIEluIGEgcmVhZCB0cmFuc2FjdGlvbiB5b3UgcmVhZCBhIGNvbnNpc3RlbnQgc3RhdGUgb2YgdGhlIGRhdGFiYXNlIGlmIHdoZW4gb3RoZXJzIGFyZSBtYW5pcHVsYXRpbmcgdGhlIGRhdGEgeW91IGFyZSByZWFkaW5nIC0tIGFzIHlvdXIgYXBwbGljYXRpb24gd2lsbCBzZWUgdGhlIHN0YXRlIG9mIHRoZSBkYXRhYmFzZSBhdCB0aGUgc3RhcnQgb2YgdGhlIHRyYW5zYWN0aW9uLiBUaGlzIGNhbiBiZSBjcml0aWNhbCBmb3IgYW5hbHl0aWNzIG9yIGNhbGN1bGF0aW9ucyB3aGVyZSB0aGUgdW5kZXJseWluZyBkYXRhIG11c3QgYmUgY29uc2lzdGVudC4gU28sIHlvdSBjb3VsZCB1c2UgYSBuZXN0ZWQgcmVhZCB0cmFuc2FjdGlvbnMgd2l0aGluIGFuIG91dGVyIHRyYW5zYWN0aW9uIHRoYXQgbWlnaHQgbWFrZSBtb2RpZmljYXRpb25zIHRvIHRoZSBkYXRhYmFzZS4KCllvdSBkbyB0aGF0IGJlY2F1c2UgeW91IGRvbid0IGhhdmUgdG8gbG9vayBldmVyeXRoaW5nIC0tIHJlbWVtYmVyIHRoYXQgdHJhbnNhY3Rpb25zIHJlcXVpcmVzIHNoYWRvdyB0YWJsZXMgb3Igbm9uLWNvbmN1cnJlbmN5IHdoaWNoIHJlZHVjZXMgZGF0YWJhc2Ugc2VydmVyIHBlcmZvcm1hbmNlLgoKSXQgY2FuIGhlbHAgd2l0aCBtYWtpbmcgdHJhbnNhY3Rpb25zIG1vcmUgZ3JhbnVsYXIgd2hpY2ggY2FuIGluY3JlYXNlIGNvbmN1cnJlbmN5IGFuZCBwZXJmb3JtYW5jZSBvZiB0aGUgZGF0YWJhc2Ugc2VydmVyLiBBbHdheXMgcmVtZW1iZXIgdGhhdCB5b3VyIGFwcGxpY2F0aW9uIGlzIG9mdGVuIG5vdCB0aGUgb25seSBvbmUgYWNjZXNzaW5nIHRoZSBkYXRhYmFzZS4uLiB0aGluayBvZiBhbiBhaXJsaW5lIHJlc2VydmF0aW9uIHN5c3RlbSB3aGVyZSB0aG91c2FuZHMgb3IgaHVuZHJlZHMgb2YgdGhvdXNhbmRzIG9mIGZsaWdodCBib29raW5ncyBvY2N1ciBldmVyeSBtaW51dGUgYW5kIHNvIHlvdSBoYXZlIGxvdHMgb2YgY29uY3VycmVudCB0cmFuc2FjdGlvbnMuIE5lc3RpbmcgY2FuIGhlbHAgaXNvbGF0ZSBzbWFsbGVyIHBhcnRzIG9mIHRoZSBkYXRhYmFzZSBhbmQgaW5jcmVhc2Ugb3ZlcmFsbCBjb25jdXJyZW5jeS4KCkEgcm9sbGJhY2sgb3IgY29tbWl0IGltcGxpY2l0bHkgY2xvc2VzIHRoZSB0cmFuc2FjdGlvbiBhbmQgYSBuZXcgdHJhbnNhY3Rpb24gY2FuIGJlIHN0YXJ0ZWQuIEFzIG1lbnRpb25lZCBiZWZvcmUsIFNRTGl0ZSBkb2VzIG5vdCBzdXBwb3J0IG5lc3RlZCB0cmFuc2FjdGlvbnMsICppLmUuKiwgdHJhbnNhY3Rpb25zIHdpdGhpbiBhIHRyYW5zYWN0aW9uLiBOZXN0ZWQgdHJhbnNhY3Rpb25zIGNhbiBiZSB1c2VmdWwgd2hlbiBzb21lIGNoYW5nZSB3aXRoaW4gYSB0cmFuc2FjdGlvbiBzaG91bGQgYmUgbWFkZSBwZXJtYW5lbnQgd2hpbGUgb3RoZXJzIHNob3VsZCBub3QgYmUsIGFsbCB3aGlsZSBub3QgYWxsb3dpbmcgb3RoZXIgY2xpZW50cyB0byBzZWUgYW55IHBhcnRpYWwgdXBkYXRlcy4gRGF0YWJhc2VzIGxpa2UgT3JhY2xlIGFuZCBNaWNyb3NvZnQgU1FMIFNlcnZlciBkbyBzdXBwb3J0IG5lc3RlZCB0cmFuc2FjdGlvbnMuCgojIyBSZWFkIFRyYW5zYWN0aW9ucwoKV2hpbGUgaXQgaXMgbm90IGNvbW1vbiB0byBwbGFjZSAqU0VMRUNUKiBzdGF0ZW1lbnRzIHdpdGhpbiBhIHRyYW5zYWN0aW9uLCBpdCBjYW4gc29tZXRpbWVzIGJlIHVzZWZ1bCB3aGVuIHdlIHdhbnQgdG8gZ3VhcmFudGVlIHRoYXQgd2UgcmVhZCBhbGwgdGFibGVzIGZyb20gYSBkZWZpbmVkIHN0YXRlIC0tIHRoaXMgY2FuIGJlIGVzcGVjaWFsbHkgdXNlZnVsIHdoZW4gZ2VuZXJhdGluZyByZXBvcnRzLgoKIyMgQ2xhc3NpYyBFeGFtcGxlCgpUaGUgY2xhc3NpYyBleGFtcGxlIHRvIG1vdGl2YXRlIHRyYW5zYWN0aW9ucyBpcyBhIHRyYW5zZmVyIG9mIG1vbmV5IGZyb20gb25lIGFjY291bnQgdG8gYW5vdGhlciBpbiBhIGJhbmtpbmcgc3lzdGVtLiBPbmUgYWNjb3VudCBpcyBkZWJpdGVkIGFuZCB0aGVuIGFub3RoZXIgYWNjb3VudCBpcyBjcmVkaXRlZC4gTm8gb3RoZXIgY2xpZW50IHNob3VsZCBzZWUgb25lIGFjY291bnQgYmVpbmcgZGViaXRlZCBiZWZvcmUgdGhlIG90aGVyIGlzIGNyZWRpdGVkIGFzIHRoYXQgd291bGQgbGVhZCB0byBpbmNvbnNpc3RlbmN5LiBGdXJ0aGVybW9yZSwgbW9zdCBiYW5raW5nIGFwcGxpY2F0aW9uIGhhdmUgYW4gYWNjb3VudGluZyB0cmFuc2FjdGlvbnMgbG9nIGNhbGxlZCB0aGUgR2VuZXJhbCBKb3VybmFsIHdoZXJlIGFsbCBkZWJpdHMgYW5kIGNyZWRpdHMgYXJlIHJlY29yZGVkLiBMZXQncyBsb29rIGF0IHRoZSBjb2RlIGZvciBkb2luZyB0aGlzLCBzdGFydGluZyB3aXRoIGEgZGVmaW5pdGlvbiBvZiB0aGUgdGFibGVzLiBXZSB3aWxsIG5lZWQgYSB0YWJsZSBmb3IgYWNjb3VudHMgYW5kIGEgdGFibGUgZm9yIHRoZSBqb3VybmFsLgoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBvdXRwdXQudmFyPSJuciIsIGVjaG89Rn0KZHJvcCB0YWJsZSBpZiBleGlzdHMgYWNjb3VudHM7CmBgYAoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBvdXRwdXQudmFyPSJuciIsIGVjaG89Rn0KZHJvcCB0YWJsZSBpZiBleGlzdHMgdHhuX2xvZzsKYGBgCgpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb24sIG91dHB1dC52YXI9Im5yIn0KQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgYWNjb3VudHMgKCAKCWFjY291bnRfbm8gSU5URUdFUiBOT1QgTlVMTCwgCgliYWxhbmNlIERFQ0lNQUwgTk9UIE5VTEwgREVGQVVMVCAwLAoJUFJJTUFSWSBLRVkoYWNjb3VudF9ubyksCiAgQ0hFQ0soYmFsYW5jZSA+PSAwKQopOwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbiwgb3V0cHV0LnZhcj0ibnIifQpDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBqb3VybmFsICgKCWNoYW5nZV9ubyBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCglhY2NvdW50X25vIElOVEVHRVIgTk9UIE5VTEwsIAoJZmxhZyBURVhUIE5PVCBOVUxMLCAKCWFtb3VudCBERUNJTUFMIE5PVCBOVUxMLCAKCWNoYW5nZV9kYXRlIERBVEUgTk9UIE5VTEwsCglGT1JFSUdOIEtFWSAoYWNjb3VudF9ubykgCgkgUkVGRVJFTkNFUyBhY2NvdW50cyhhY2NvdW50X25vKQopOwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbiwgaW5jbHVkZT1GLCBldmFsPUZ9CnNlbGVjdCAqIGZyb20gam91cm5hbApgYGAKCk5leHQsIHdlIHdpbGwgaW5zZXJ0IHNhbXBsZSBkYXRhIGludG8gdGhlICphY2NvdW50cyogdGFibGUgdGhhdCB3ZSBjYW4gdXNlIGZvciBhICJ0cmFuc2ZlciIuIEFmdGVyIHRoaXMgdGhlIGRhdGFiYXNlIHdpbGwgY29udGFpbiB0d28gYWNjb3VudHMsIG9uZSB3aXRoIGEgYmFsYW5jZSBvZiAkMTEwMCQgYW5kIGFub3RoZXIgd2l0aCBhIGJhbGFuY2Ugb2YgJDIyMDAkLCBlYWNoIGhhdmluZyBhbiBhY2NvdW50IG51bWJlci4KCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbn0KSU5TRVJUIElOVE8gYWNjb3VudHMgCiAgICAgKGFjY291bnRfbm8sIGJhbGFuY2UpCiAgICAgVkFMVUVTICgxMTc4NjAsIDExMDApLAogICAgICAgICAgICAoMjk5ODcxLCAyMjAwKTsKYGBgCgpOb3csIHRoZSAidHJhbnNmZXIiOiBhIHRyYW5zZmVyIG9mICQxMDAkIGZyb20gYWNjb3VudCAqMTE3ODYwKiB0byBhY2NvdW50ICoyOTk4NzEqIHdpdGggYW4gZW50cnkgaW4gdGhlIGpvdXJuYWwuIFRoaXMgcmVxdWlyZXMgZm91ciBkYXRhIGNoYW5nZXMgdG8gdGhlIGRhdGFiYXNlOiBhbiB1cGRhdGUgb2YgdGhlIGJhbGFuY2UgaW4gdGhlIHR3byBhY2NvdW50cyBhbmQgaW5zZXJ0aW9ucyBvZiB0d28gbmV3IHJvd3MgaW50byB0aGUgam91cm5hbC4gVGhpcyBtdXN0IGJlIGRvbmUgd2l0aGluIGEgdHJhbnNhY3Rpb24gYmVjYXVzZSBpbiBhIGNvbmN1cnJlbnQgYWNjZXNzIHNjZW5hcmlvLCBvdXIgY2xpZW50IG1pZ2h0IHVwZGF0ZSB0aGUgZmlyc3QgYmFsYW5jZSwgdGhlbiB0aGUgZGF0YWJhc2UgbWlnaHQgcHJvY2VzcyBhIHJlYWQgZnJvbSB0aGUgZGF0YWJhc2UgZm9yIGFub3RoZXIgY2xpZW50IHRoYXQgaXMgYWxzbyBjb25uZWN0ZWQgdG8gdGhlIGRhdGFiYXNlLiBUaGF0IGNsaWVudCB3b3VsZCBub3cgc2VlIHRoYXQgdGhlIGJhbGFuY2UgaXMgbGVzcyBidXQgdGhlIG90aGVyIGFjY291bnQgaXMgbm90IHlldCB1cGRhdGVkOiBhbiBpbmNvbnNpc3RlbmN5LgoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29ufQpCRUdJTiBUUkFOU0FDVElPTjsKYGBgCgpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259ClVQREFURSBhY2NvdW50cwogICBTRVQgYmFsYW5jZSA9IGJhbGFuY2UgLSAxMDAKIFdIRVJFIGFjY291bnRfbm8gPSAxMTc4NjA7CmBgYAoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29ufQpVUERBVEUgYWNjb3VudHMKICAgU0VUIGJhbGFuY2UgPSBiYWxhbmNlICsgMTAwCiBXSEVSRSBhY2NvdW50X25vID0gMjk5ODcxOwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbn0KSU5TRVJUIElOVE8gam91cm5hbCAKICAgICAoYWNjb3VudF9ubyxmbGFnLGFtb3VudCxjaGFuZ2VfZGF0ZSkgCiAgICAgVkFMVUVTICgxMTc4NjAsICdEJywgMTAwLCBkYXRlKCdub3cnKSk7CmBgYAoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29ufQpJTlNFUlQgSU5UTyBqb3VybmFsCiAgICAgKGFjY291bnRfbm8sZmxhZyxhbW91bnQsY2hhbmdlX2RhdGUpIAogICAgIFZBTFVFUyAoMjk5ODcxLCAnQycsIDEwMCwgZGF0ZSgnbm93JykpOwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbn0KQ09NTUlUOwpgYGAKCklmIGFueSBwYXJ0IG9mIHRoZSB1cGRhdGUgY2Fubm90IGJlIGRvbmUsIHRoZW4gd2Ugd291bGQgaXNzdWUgYSAqUk9MTEJBQ0sqIHJhdGhlciB0aGFuIGEgKkNPTU1JVCouCgpMZXQncyBzZWUgd2hhdCB0aGUgdGFibGVzIGNvbnRhaW4gYWZ0ZXIgdGhlIHRyYW5zZmVyIHRyYW5zYWN0aW9uLgoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBlY2hvPVR9ClNFTEVDVCAqIEZST00gYWNjb3VudHM7CmBgYAoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBlY2hvPVR9ClNFTEVDVCAqIEZST00gam91cm5hbDsKYGBgCgpFeHBlcmltZW50IHdpdGggdGhpcyBjb2RlIGFuZCBzZXQgdXAgYSBjb25jdXJyZW50IHNpdHVhdGlvbiBhbmQgdGhlbiBydW4gdGhlIGNvZGUgd2l0aCBhbiB3aXRob3V0IHRoZSB0cmFuc2FjdGlvbiBsb2dpYy4KCiMjIyBUcmFuc2FjdGlvbnMgaW4gQXBwbGljYXRpb25zCgpPZiBjb3Vyc2UsIGluIGFuIGFwcGxpY2F0aW9uLCB3ZSB3b3VsZCBuZWVkIHRvIHVzZSBjb25kaXRpb25hbCBzdGF0ZW1lbnRzIHRvIGRldGVybWluZSB3aGVuIGFuZCB3aGV0aGVyIHRvIGNvbW1pdCBvciByb2xsYmFjay4gSW4gUiwgdGhlIGFib3ZlIHRyYW5zYWN0aW9uIGNvZGUgd291bGQgYmUgYmVzdCBwbGFjZWQgd2l0aGluIGEgZnVuY3Rpb24sIHBlcmhhcHMgYXMgc2hvd24gYmVsb3cuIFRoZSBmdW5jdGlvbiAqZG9UcmFuc2ZlciogdGFrZXMgc291cmNlIGFuZCBhIGRlc3RpbmF0aW9uIGFjY291bnQgbnVtYmVycyBwbHVzIGFuIGFtb3VudCB0byB0cmFuc2ZlciBhbmQgdGhlbiBleGVjdXRlcyB0aGUgU1FMIHN0YXRlbWVudHMgd2l0aGluIGEgdHJhbnNhY3Rpb24gYW5kIGNvbW1pdHMgaWYgc3VjY2Vzc2Z1bCBvciByb2xscyBiYWNrIGlmIGFueSBvZiB0aGVtIGZhaWxlZC4gVGhlIGZ1bmN0aW9uIGFsc28gdGFrZXMgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb24gb2JqZWN0IGFzIGEgcGFyYW1ldGVyLgoKVGhlIGZ1bmN0aW9uIDxjb2RlPmRiU2VuZFN0YXRlbWVudCgpPC9jb2RlPiBpcyB1c2VkIHRvIHNlbmQgdXBkYXRlLCBkZWxldGUsIGFuZCBpbnNlcnQgc3RhdGVtZW50cyBwbHVzIG90aGVyIGRhdGFiYXNlIGNvbW1hbmRzIHN1Y2ggYXMgZm9yIGRyb3BwaW5nIHRhYmxlcywgY3JlYXRpbmcgdGFibGVzIG9yIGluZGV4ZXMsIGFuZCwgb2YgY291cnNlLCB0cmFuc2FjdGlvbiBsb2dpYy4gSXQgaXMgYSBzeW5jaHJvbm91cyBtZXRob2QgdGhhdCByZXR1cm5zIG9uY2UgdGhlIGNvbW1hbmQgaGFzIGJlZW4gZXhlY3V0ZWQuIEFzIGFuIGFsdGVybmF0aXZlLCB3ZSBjYW4gY2FsbCA8Y29kZT5kYkV4ZWN1dGUoKTwvY29kZT4gd2hpY2ggY2FsbHMgPGNvZGU+ZGJTZW5kU3RhdGVtZW50KCk8L2NvZGU+IGFuZCByZXR1cm5zIHRoZSBudW1iZXIgb2Ygcm93cyBhZmZlY3RlZDsgaWYgdGhhdCBudW1iZXIgaXMgbGVzcyB0aGFuIG9uZSB0aGVuIHRoZSBjb21tYW5kIHdhcyBub3Qgc3VjY2Vzc2Z1bC4KCmBgYHtyIGRvVHJhbnNhY3Rpb259CmRvVHJhbnNmZXIgPC0gZnVuY3Rpb24gKGRiY29uLCBhY2N0Tm9TcmMsIGFjY3ROb0Rlc3QsIGFtb3VudCkKewogIHR4bkZhaWxlZCA9IEZBTFNFCiAgCiAgaWYgKGFjY3ROb1NyYyA9PSBhY2N0Tm9EZXN0KQogIHsKICAgICMgY2FuJ3QgdHJhbnNmZXIgdG8gc2FtZSBhY2NvdW50CiAgICByZXR1cm4gKEZBTFNFKQogIH0KICAKICBkYkV4ZWN1dGUoZGJjb24sICJCRUdJTiBUUkFOU0FDVElPTiIpCgogICMgZGViaXQgc291cmNlIGFjY291bnQKICBzcWwgPC0gIlVQREFURSBhY2NvdW50cwogICAgICAgICAgICAgU0VUIGJhbGFuY2UgPSBiYWxhbmNlIC0gPwogICAgICAgICAgIFdIRVJFIGFjY291bnRfbm8gPSA/IgogIHBzIDwtIGRiU2VuZFN0YXRlbWVudChkYmNvbiwgc3FsLAogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMgPSBsaXN0KGFtb3VudCwgYWNjdE5vU3JjKSkKICBpZiAoZGJHZXRSb3dzQWZmZWN0ZWQocHMpIDwgMSkKICAgIHR4bkZhaWxlZCA9IFRSVUUKICBkYkNsZWFyUmVzdWx0KHBzKQoKICAjIGNyZWRpdCBkZXN0aW5hdGlvbiBhY2NvdW50CiAgc3FsIDwtICJVUERBVEUgYWNjb3VudHMKICAgICAgICAgICAgIFNFVCBiYWxhbmNlID0gYmFsYW5jZSArID8KICAgICAgICAgICBXSEVSRSBhY2NvdW50X25vID0gPyIKICBwcyA8LSBkYlNlbmRTdGF0ZW1lbnQoZGJjb24sIHNxbCwKICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zID0gbGlzdChhbW91bnQsIGFjY3ROb0Rlc3QpKQogIGlmIChkYkdldFJvd3NBZmZlY3RlZChwcykgPCAxKQogICAgdHhuRmFpbGVkID0gVFJVRQogIGRiQ2xlYXJSZXN1bHQocHMpCiAgCiAgIyBhZGQgYWNjb3VudGluZyB0cmFuc2FjdGlvbiB0byBqb3VybmFsCiAgc3FsIDwtICJJTlNFUlQgSU5UTyBqb3VybmFsIAogICAgICAgICAgIChhY2NvdW50X25vLGZsYWcsYW1vdW50LGNoYW5nZV9kYXRlKSAKICAgICAgICAgIFZBTFVFUyAoPywgJ0QnLCA/LCBkYXRlKCdub3cnKSkiCiAgcHMgPC0gZGJTZW5kU3RhdGVtZW50KGRiY29uLCBzcWwsCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcyA9IGxpc3QoYWNjdE5vU3JjLCBhbW91bnQpKQogIGlmIChkYkdldFJvd3NBZmZlY3RlZChwcykgPCAxKQogICAgdHhuRmFpbGVkID0gVFJVRQogIGRiQ2xlYXJSZXN1bHQocHMpCiAgCiAgc3FsIDwtICJJTlNFUlQgSU5UTyBqb3VybmFsCiAgICAgICAgICAgKGFjY291bnRfbm8sZmxhZyxhbW91bnQsY2hhbmdlX2RhdGUpIAogICAgICAgICAgVkFMVUVTICg/LCAnQycsID8sIGRhdGUoJ25vdycpKSIKICBwcyA8LSBkYlNlbmRTdGF0ZW1lbnQoZGJjb24sIHNxbCwKICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zID0gbGlzdChhY2N0Tm9EZXN0LCBhbW91bnQpKQogIGlmIChkYkdldFJvd3NBZmZlY3RlZChwcykgPCAxKQogICAgdHhuRmFpbGVkID0gVFJVRQogIGRiQ2xlYXJSZXN1bHQocHMpCgoKICAjIGNvbW1pdCB0cmFuc2FjdGlvbiBpZiBubyBmYWlsdXJlLCBvdGhlcndpc2Ugcm9sbGJhY2sKICBpZiAodHhuRmFpbGVkID09IFRSVUUpCiAgICBkYkV4ZWN1dGUoZGJjb24sICJST0xMQkFDSyBUUkFOU0FDVElPTiIpCiAgZWxzZQogICAgZGJFeGVjdXRlKGRiY29uLCAiQ09NTUlUIFRSQU5TQUNUSU9OIikKCiAgIyByZXR1cm4gc3RhdHVzOyBUUlVFIGlmIHN1Y2Nlc3NmdWw7IEZBTFNFIGlmIGZhaWxlZAogIHJldHVybiAoIXR4bkZhaWxlZCkKfQpgYGAKClRvIHRlc3QgdGhlIGZ1bmN0aW9uLCB3ZSB3aWxsIGNhbGwgaXQgd2l0aCB0d28gYWNjb3VudCBudW1iZXJzIGFuZCBhbiBhbW91bnQuCgpgYGB7ciBjb21tZW50PSIifQpzcmNBY2NvdW50IDwtICcxMTc4NjAnCmRlc3RBY2NvdW50IDwtICcyOTk4NzEnCmFtb3VudCA8LSA5OQoKc3RhdHVzIDwtIGRvVHJhbnNmZXIoZGJjb24sIHNyY0FjY291bnQsIGRlc3RBY2NvdW50LCBhbW91bnQpCgppZiAoc3RhdHVzID09IFRSVUUpIHsKICBjYXQoJ1RyYW5zZmVyIHN1Y2Nlc3NmdWwnKQp9IGVsc2UgewogIGNhdCgnVHJhbnNmZXIgZmFpbGVkJykKfQpgYGAKClRvIHZlcmlmeSB0aGF0IHRoZSBkYXRhYmFzZSB3YXMgY29ycmVjdGx5IHVwZGF0ZWQsIHdlIHNob3VsZCBpbnNwZWN0IGFsbCB0aGUgdGFibGVzIHRoYXQgd2VyZSBhZmZlY3RlZCwgYnV0IGZvciBicmV2aXR5IHdlIHdpbGwgb25seSBsb29rIGF0IHRoZSB0YWJsZSBjb250YWluaW5nIHRoZSBqb3VybmFsIGVudHJpZXMuCgpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb24sIGVjaG89Rn0KU0VMRUNUICogRlJPTSBqb3VybmFsOwpgYGAKCk5vdyB0aGF0IHdlIGtub3cgdGhhdCBpdCBjb21taXRzIGNvcnJlY3RseSwgbGV0J3MgdHJhbnNmZXIgdG8gYW4gYWNjb3VudCB0aGF0IGRvZXMgbm90IGV4aXN0OyB0aGVuIHRoZSB0cmFuc2FjdGlvbiBzaG91bGQgZmFpbCBhbmQgbm8gbG9nIGVudHJ5IHNob3VsZCBoYXZlIGJlZW4gY3JlYXRlZC4KCmBgYHtyIGNvbW1lbnQ9IiJ9CnNyY0FjY291bnQgPC0gJzExNzg2MCcKZGVzdEFjY291bnQgPC0gJzk5OTk5OScKYW1vdW50IDwtIDIwMAoKc3RhdHVzIDwtIGRvVHJhbnNmZXIoZGJjb24sIHNyY0FjY291bnQsIGRlc3RBY2NvdW50LCBhbW91bnQpCgppZiAoc3RhdHVzID09IFRSVUUpIHsKICBjYXQoJ1RyYW5zZmVyIHN1Y2Nlc3NmdWwnKQp9IGVsc2UgewogIGNhdCgnVHJhbnNmZXIgZmFpbGVkJykKfQpgYGAKCkFuZCwgaW5kZWVkLCB0aGUgam91cm5hbCBkb2Vzbid0IGNvbnRhaW4gdGhlIGVudHJ5LgoKYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBlY2hvPUZ9ClNFTEVDVCAqIEZST00gam91cm5hbDsKYGBgCgojIyBDb25jbHVzaW9uCgpUcmFuc2FjdGlvbnMgYXJlIG5lY2Vzc2FyeSB0byBlbnN1cmUgZGF0YSBpbnRlZ3JpdHkgd2hlbiBhIGRhdGFiYXNlIGlzIG1vZGlmaWVkIGNvbmN1cnJlbnRseSBieSBtdWx0aXBsZSB1c2VycyBvciBhcHBsaWNhdGlvbnMuIFRoaXMgbGVzc29uIGV4cGxhaW5lZCBob3cgdG8gY3JlYXRlIHRyYW5zYWN0aW9ucyBpbiBTUUxpdGUgYW5kIHBlcmZvcm0gY29tbWl0IGFuZCByb2xsYmFjayBmdW5jdGlvbnMuCgo+IFdoZW4gZGF0YWJhc2VzIGNhbiBiZSBhY2Nlc3NlZCBjb25jdXJyZW50bHksIGFsbCB1cGRhdGVzIHRoYXQgY29uc2lzdCBvZiBtb3JlIHRoYW4gb25lIG1vZGlmaWNhdGlvbiBtdXN0IGJlIGRvbmUgYXMgYSB0cmFuc2FjdGlvbiwgb3RoZXJ3aXNlIGRhdGEgaW50ZWdyaXR5IGlzc3VlcyB3aWxsIGFyaXNlLgoKYGBge3IgaW5jbHVkZT1GfQpkYkRpc2Nvbm5lY3QoZGJjb24pCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBGaWxlcyAmIFJlc291cmNlcyB7I2ZpbGVzLXJlc291cmNlc30KCmBgYHtyIHppcEZpbGVzLCBlY2hvPUZBTFNFfQp6aXBOYW1lID0gc3ByaW50ZigiTGVzc29uRmlsZXMtJXMtJXMuemlwIiwgCiAgICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LAogICAgICAgICAgICAgICAgIHBhcmFtcyRudW1iZXIpCgp0ZXh0QUxpbmsgPSBwYXN0ZTAoIkFsbCBGaWxlcyBmb3IgTGVzc29uICIsIAogICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksIi4iLHBhcmFtcyRudW1iZXIpCgojIGRvd25sb2FkRmlsZXNMaW5rKCkgaXMgaW5jbHVkZWQgZnJvbSBfaW5zZXJ0MkRCLlIKa25pdHI6OnJhd19odG1sKGRvd25sb2FkRmlsZXNMaW5rKCIuIiwgemlwTmFtZSwgdGV4dEFMaW5rKSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFNlZSBBbHNvCgotICAgWzYwLjcwMSBUcmFuc2FjdGlvbiBQcm9jZXNzaW5nIGluIFJlbGF0aW9uYWwgRGF0YWJhc2VzXShodHRwOi8vYXJ0aWZpY2l1bS51cy9sZXNzb25zLzYwLmRiZGVzaWduL2wtNjAtNzAxLXRyYW5zYWN0aW9ucy9sLTYwLTcwMS5odG1sKQoKLSAgIFs2MC43MDYgQ29uY3VycmVuY3kgQ29udHJvbCBpbiBSZWxhdGlvbmFsIERhdGFiYXNlc10oaHR0cDovL2FydGlmaWNpdW0udXMvbGVzc29ucy82MC5kYmRlc2lnbi9sLTYwLTcwNi1jb25jdXJyZW5jeS9sLTYwLTcwNi5odG1sKQoKIyMgUmVmZXJlbmNlcwoKW1NRTGl0ZSBUcmFuc2FjdGlvbnNdKGh0dHBzOi8vd3d3LnNxbGl0ZXR1dG9yaWFsLm5ldC9zcWxpdGUtdHJhbnNhY3Rpb24vKQoKIyMgRXJyYXRhCgpOb25lIGNvbGxlY3RlZCB5ZXQuIExldCB1cyBrbm93LgoKYGBgez1odG1sfQo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tL3N0YXRpYy9mZWVkYmFjazIuanMiIHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgbmV3IEpvdGZvcm1GZWVkYmFjayh7CiAgICBmb3JtSWQ6ICIyMTIxODcwNzI3ODQxNTciLAogICAgYnV0dG9uVGV4dDogIkZlZWRiYWNrIiwKICAgIGJhc2U6ICJodHRwczovL2Zvcm0uam90Zm9ybS5jb20vIiwKICAgIGJhY2tncm91bmQ6ICIjRjU5MjAyIiwKICAgIGZvbnRDb2xvcjogIiNGRkZGRkYiLAogICAgYnV0dG9uU2lkZTogImxlZnQiLAogICAgYnV0dG9uQWxpZ246ICJjZW50ZXIiLAogICAgdHlwZTogZmFsc2UsCiAgICB3aWR0aDogNzAwLAogICAgaGVpZ2h0OiA1MDAsCiAgICBpc0NhcmRGb3JtOiBmYWxzZQogIH0pOwo8L3NjcmlwdD4KYGBgCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19kZXBsb3lLbml0LlInKSksIGluY2x1ZGUgPSBGQUxTRX0KYGBgCg==