Objectives

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

  • define a trigger in SQLite
  • remove a trigger from a table

Overview

SQLite, like most relational database management systems, supports triggers. Triggers in SQLite are essentially database “callbacks”, which means they are automatically executed (“fired” or “triggered”) by the SQLite SQL execution engine in response to certain events on a particular table or view. These events generally are modification events and include INSERT, UPDATE, and DELETE operations. Triggers can be defined to execute before or after the specified event, providing a useful mechanism for enforcing data integrity, maintaining audit trails, and implementing complex business logic directly within the database. The benefit is that business logic is centralized. However, triggers are written in a proprietary programming language unique to each database and thus can be difficult to maintain and reduce database mobility.

Key Features of Triggers in SQLite

  • Automatic Execution: Triggers run automatically in response to specified data modification events, without the need for explicit invocation.
  • Event Types: Triggers can be set to fire before or after INSERT, UPDATE, and DELETE operations.
  • Row-Level and Statement-Level Triggers: SQLite supports row-level triggers, which execute once for each row affected by the triggering event. Statement-level triggers, as seen in some other RDBMS systems, execute once per SQL statement, are not directly supported but can be simulated using control structures within the trigger.
  • Support for WHEN Clause: Triggers in SQLite can include a WHEN clause to specify a condition for the trigger’s execution, allowing for more precise control over when the trigger fires.
  • Nested Triggers: SQLite allows triggers to fire other triggers (nested execution), which can be controlled by the PRAGMA recursive_triggers setting.

Common Uses of Triggers in SQLite

  • Data Validation: To enforce complex data validation rules that cannot be defined through standard SQLite constraints.
  • Integrity Constraints: To implement complex integrity constraints or to enforce referential actions (like cascading deletes or updates) that go beyond SQLite’s foreign key constraints.
  • Auditing: To automatically record changes to data, such as logging modifications to certain tables for auditing purposes.
  • Automatic Modification: To automatically update or transform data in response to database operations, such as updating a “last modified” timestamp column whenever a row is updated.

Example of a Trigger in SQLite

Here’s a simple example of a trigger in SQLite that automatically updates a “last_modified” timestamp column in a table called “my_table” whenever a row is updated:

CREATE TRIGGER UpdateLastModifiedTime
AFTER UPDATE ON my_table
BEGIN
    UPDATE my_table SET last_modified = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid;
END;

This trigger is defined to fire after an update operation on “my_table”. It sets the “last_modified” column to the current timestamp for the row that was updated.

Considerations on Use

  • Performance Impact: Triggers can impact database performance, especially if they perform complex operations or if many triggers fire in response to frequent data modification events.
  • Debugging Complexity: Debugging can become more challenging with triggers, as the logic is executed implicitly, which may lead to unexpected behavior if not carefully managed.

Tutorial

In the short video tutorial below, Khoury Boston’s Prof. Schedlbauer shows how to define and test triggers in a SQLite database. Note that while SQLite supports triggers it does not support stored procedures. Triggers are commonly used in SQLite to maintain user defined integrity constraints, keep derived attributes updated, and ensure that values are in defined ranges.

Every database has its own syntax for defining triggers and imposes its own restrictions on what can be done in a trigger and what cannot: SQLite is no different.

Slide Deck: 70.901 - Triggers in SQLite

Step-by-Step Guide

Building a trigger in SQLite involves specifying the timing, event, and action you want the trigger to perform in response to changes in the database. Here’s a step-by-step guide on how to create a trigger in SQLite:

1. Determine the Trigger’s Purpose

First, decide what you want the trigger to do. For example, you might want to log changes to a table, enforce complex constraints, or automatically update related data.

2. Choose the Trigger Event and Timing

Decide on the event (INSERT, UPDATE, DELETE) that will fire the trigger and whether it should happen BEFORE, AFTER, or INSTEAD OF the event.

Basic Syntax

The basic syntax for creating a trigger in SQLite is:

CREATE TRIGGER [IF NOT EXISTS] trigger_name
[BEFORE|AFTER|INSTEAD OF] event_name
ON table_name
[FOR EACH ROW]
[WHEN condition]
BEGIN
    -- Trigger logic here
END;
  • [IF NOT EXISTS]: Optional. Specifies that the trigger should only be created if no other trigger of the same name already exists.
  • trigger_name: The name of the trigger.
  • [BEFORE|AFTER|INSTEAD OF]: Specifies when the trigger should be fired relative to the event.
  • event_name: The type of operation that activates the trigger (INSERT, UPDATE, DELETE).
  • table_name: The name of the table on which the trigger operates.
  • [FOR EACH ROW]: Specifies that the trigger should be fired once for each row affected by the event. Omitting this means the trigger is considered a “statement-level trigger.”
  • [WHEN condition]: An optional condition for the trigger to fire. If the condition is not met, the trigger does not execute.
  • – Trigger logic here: The SQL statements to be executed when the trigger fires.

3. Define the Trigger Action

Write the SQL statements that should be executed when the trigger fires. These can include operations like INSERT, UPDATE, DELETE, or even calling other functions.

Example: Logging Updates to a Table

Suppose you have a table employees and you want to log every update made to an employee’s salary in a salary_changes log table. You could create an AFTER UPDATE trigger like this:

CREATE TRIGGER log_salary_change
AFTER UPDATE OF salary ON employees
FOR EACH ROW
WHEN OLD.salary != NEW.salary
BEGIN
    INSERT INTO salary_changes(employee_id, old_salary, new_salary, change_date)
    VALUES (NEW.employee_id, OLD.salary, NEW.salary, CURRENT_TIMESTAMP);
END;

This trigger fires after the salary column of an employee is updated, but only if the new salary is different from the old salary. It then logs the change in the salary_changes table.

4. Execute the CREATE TRIGGER Statement

Run the CREATE TRIGGER statement in your SQLite environment to create the trigger. You can do this through an SQLite client or through a scripting interface that interacts with SQLite.

5. Test the Trigger

After creating the trigger, perform operations on the target table to ensure the trigger behaves as expected. Check the outcomes based on the logic you’ve defined.

Best Practices

  • Ensure the logic within your triggers is efficient and does not lead to unintended side effects.
  • Keep the trigger logic simple to avoid complex interdependencies that can make debugging difficult.
  • Consider the performance implications of triggers, as complex or numerous triggers can impact the database performance.

Creating triggers in SQLite can greatly enhance the functionality and integrity of your database by automating tasks and enforcing rules directly within the database.

Order of Execution of Multiple Triggers

In SQLite, when multiple triggers are defined for the same event on a single database object, such as a table, and they are of the same time (i.e., BEFORE, AFTER, or INSTEAD OF), the triggers are executed in the order they were created. This means that the trigger that was defined first will be executed first, followed by the next trigger defined, and so on. This order of execution is consistent as long as the triggers remain defined in the database. Other databases may execute the triggers in a different order or perhaps even non-deterministic, so relying on a specific order of execution is dangerous and can lead to unintended behavior and should be avoided.

However, SQLite does not provide built-in functionality to explicitly specify the order of trigger execution beyond this. If a specific execution order is required, the developer must manage the creation order carefully or design the triggers in such a way that their execution order does not impact the application logic or data integrity.

It’s important to design triggers and their logic with consideration of this execution order, especially when triggers might have dependencies on the effects of one another. Proper testing and validation are essential to ensure that the combined effect of multiple triggers on the same event does not lead to unintended consequences or violate data integrity constraints.

Summary

Triggers in SQLite offer a flexible mechanism for implementing automatic responses to database events, making them a valuable feature for developers looking to enforce data integrity, automate database logic, and manage complex relationships within their SQLite databases.


Files & Resources

All Files for Lesson 70.901

Errata

None collected yet. Let us know.

Let us know.

LS0tCnRpdGxlOiAiRGVmaW5pbmcgVHJpZ2dlcnMgaW4gU1FMaXRlIgpwYXJhbXM6CiAgY2F0ZWdvcnk6IDcwCiAgbnVtYmVyOiA5MDEKICB0aW1lOiA2MAogIGxldmVsOiBpbnRlcm1lZGlhdGUKICB0YWdzOiAidHJpZ2dlcnMsc3FsaXRlLGJ1c2luZXNzIGxvZ2ljIgogIGRlc2NyaXB0aW9uOiAiVGhpcyBsZXNzb24gZXhwbGFpbnMgaG93IHRvIGRlZmluZSB0cmlnZ2VycyBvbiB0YWJsZXMgaW4gU1FMaXRlLiAKICAgICAgICAgICAgICAgIERlbW9uc3RyYXRlcyB0aGUgc3ludGF4IG9mIHRoZSB0cmlnZ2VycwogICAgICAgICAgICAgICAgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgZm9yIFNRTGl0ZS4gRXhwbGFpbnMgd2hlbiB0byB1c2UgdHJpZ2dlcnMKICAgICAgICAgICAgICAgIGZvciBlbmZvcmNpbmcgYnVzaW5lc3MgZG9tYWluIGNvbnN0cmFpbnRzIGFuZCBydWxlcy4iCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiIKYXV0aG9yOiAiPHNtYWxsPk1hcnRpbiBTY2hlZGxiYXVlcjwvc21hbGw+IgplbWFpbDogIm0uc2NoZWRsYmF1ZXJAbmV1LmVkdSIKYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19pbnNlcnQyREIuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgT2JqZWN0aXZlcwoKVXBvbiBjb21wbGV0aW9uIG9mIHRoaXMgbGVzc29uLCB5b3Ugd2lsbCBiZSBhYmxlIHRvOgoKLSAgIGRlZmluZSBhIHRyaWdnZXIgaW4gU1FMaXRlCi0gICByZW1vdmUgYSB0cmlnZ2VyIGZyb20gYSB0YWJsZQoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBPdmVydmlldwoKU1FMaXRlLCBsaWtlIG1vc3QgcmVsYXRpb25hbCBkYXRhYmFzZSBtYW5hZ2VtZW50IHN5c3RlbXMsIHN1cHBvcnRzIHRyaWdnZXJzLiBUcmlnZ2VycyBpbiBTUUxpdGUgYXJlIGVzc2VudGlhbGx5IGRhdGFiYXNlICJjYWxsYmFja3MiLCB3aGljaCBtZWFucyB0aGV5IGFyZSBhdXRvbWF0aWNhbGx5IGV4ZWN1dGVkICgiZmlyZWQiIG9yICJ0cmlnZ2VyZWQiKSBieSB0aGUgU1FMaXRlIFNRTCBleGVjdXRpb24gZW5naW5lIGluIHJlc3BvbnNlIHRvIGNlcnRhaW4gZXZlbnRzIG9uIGEgcGFydGljdWxhciB0YWJsZSBvciB2aWV3LiBUaGVzZSBldmVudHMgZ2VuZXJhbGx5IGFyZSBtb2RpZmljYXRpb24gZXZlbnRzIGFuZCBpbmNsdWRlIElOU0VSVCwgVVBEQVRFLCBhbmQgREVMRVRFIG9wZXJhdGlvbnMuIFRyaWdnZXJzIGNhbiBiZSBkZWZpbmVkIHRvIGV4ZWN1dGUgYmVmb3JlIG9yIGFmdGVyIHRoZSBzcGVjaWZpZWQgZXZlbnQsIHByb3ZpZGluZyBhIHVzZWZ1bCBtZWNoYW5pc20gZm9yIGVuZm9yY2luZyBkYXRhIGludGVncml0eSwgbWFpbnRhaW5pbmcgYXVkaXQgdHJhaWxzLCBhbmQgaW1wbGVtZW50aW5nIGNvbXBsZXggYnVzaW5lc3MgbG9naWMgZGlyZWN0bHkgd2l0aGluIHRoZSBkYXRhYmFzZS4gVGhlIGJlbmVmaXQgaXMgdGhhdCBidXNpbmVzcyBsb2dpYyBpcyBjZW50cmFsaXplZC4gSG93ZXZlciwgdHJpZ2dlcnMgYXJlIHdyaXR0ZW4gaW4gYSBwcm9wcmlldGFyeSBwcm9ncmFtbWluZyBsYW5ndWFnZSB1bmlxdWUgdG8gZWFjaCBkYXRhYmFzZSBhbmQgdGh1cyBjYW4gYmUgZGlmZmljdWx0IHRvIG1haW50YWluIGFuZCByZWR1Y2UgZGF0YWJhc2UgbW9iaWxpdHkuCgojIyBLZXkgRmVhdHVyZXMgb2YgVHJpZ2dlcnMgaW4gU1FMaXRlCgotICAgKipBdXRvbWF0aWMgRXhlY3V0aW9uKio6IFRyaWdnZXJzIHJ1biBhdXRvbWF0aWNhbGx5IGluIHJlc3BvbnNlIHRvIHNwZWNpZmllZCBkYXRhIG1vZGlmaWNhdGlvbiBldmVudHMsIHdpdGhvdXQgdGhlIG5lZWQgZm9yIGV4cGxpY2l0IGludm9jYXRpb24uCi0gICAqKkV2ZW50IFR5cGVzKio6IFRyaWdnZXJzIGNhbiBiZSBzZXQgdG8gZmlyZSBiZWZvcmUgb3IgYWZ0ZXIgSU5TRVJULCBVUERBVEUsIGFuZCBERUxFVEUgb3BlcmF0aW9ucy4KLSAgICoqUm93LUxldmVsIGFuZCBTdGF0ZW1lbnQtTGV2ZWwgVHJpZ2dlcnMqKjogU1FMaXRlIHN1cHBvcnRzIHJvdy1sZXZlbCB0cmlnZ2Vycywgd2hpY2ggZXhlY3V0ZSBvbmNlIGZvciBlYWNoIHJvdyBhZmZlY3RlZCBieSB0aGUgdHJpZ2dlcmluZyBldmVudC4gU3RhdGVtZW50LWxldmVsIHRyaWdnZXJzLCBhcyBzZWVuIGluIHNvbWUgb3RoZXIgUkRCTVMgc3lzdGVtcywgZXhlY3V0ZSBvbmNlIHBlciBTUUwgc3RhdGVtZW50LCBhcmUgbm90IGRpcmVjdGx5IHN1cHBvcnRlZCBidXQgY2FuIGJlIHNpbXVsYXRlZCB1c2luZyBjb250cm9sIHN0cnVjdHVyZXMgd2l0aGluIHRoZSB0cmlnZ2VyLgotICAgKipTdXBwb3J0IGZvciBXSEVOIENsYXVzZSoqOiBUcmlnZ2VycyBpbiBTUUxpdGUgY2FuIGluY2x1ZGUgYSBXSEVOIGNsYXVzZSB0byBzcGVjaWZ5IGEgY29uZGl0aW9uIGZvciB0aGUgdHJpZ2dlcidzIGV4ZWN1dGlvbiwgYWxsb3dpbmcgZm9yIG1vcmUgcHJlY2lzZSBjb250cm9sIG92ZXIgd2hlbiB0aGUgdHJpZ2dlciBmaXJlcy4KLSAgICoqTmVzdGVkIFRyaWdnZXJzKio6IFNRTGl0ZSBhbGxvd3MgdHJpZ2dlcnMgdG8gZmlyZSBvdGhlciB0cmlnZ2VycyAobmVzdGVkIGV4ZWN1dGlvbiksIHdoaWNoIGNhbiBiZSBjb250cm9sbGVkIGJ5IHRoZSBgUFJBR01BIHJlY3Vyc2l2ZV90cmlnZ2Vyc2Agc2V0dGluZy4KCiMjIENvbW1vbiBVc2VzIG9mIFRyaWdnZXJzIGluIFNRTGl0ZQoKLSAgICoqRGF0YSBWYWxpZGF0aW9uKio6IFRvIGVuZm9yY2UgY29tcGxleCBkYXRhIHZhbGlkYXRpb24gcnVsZXMgdGhhdCBjYW5ub3QgYmUgZGVmaW5lZCB0aHJvdWdoIHN0YW5kYXJkIFNRTGl0ZSBjb25zdHJhaW50cy4KLSAgICoqSW50ZWdyaXR5IENvbnN0cmFpbnRzKio6IFRvIGltcGxlbWVudCBjb21wbGV4IGludGVncml0eSBjb25zdHJhaW50cyBvciB0byBlbmZvcmNlIHJlZmVyZW50aWFsIGFjdGlvbnMgKGxpa2UgY2FzY2FkaW5nIGRlbGV0ZXMgb3IgdXBkYXRlcykgdGhhdCBnbyBiZXlvbmQgU1FMaXRlJ3MgZm9yZWlnbiBrZXkgY29uc3RyYWludHMuCi0gICAqKkF1ZGl0aW5nKio6IFRvIGF1dG9tYXRpY2FsbHkgcmVjb3JkIGNoYW5nZXMgdG8gZGF0YSwgc3VjaCBhcyBsb2dnaW5nIG1vZGlmaWNhdGlvbnMgdG8gY2VydGFpbiB0YWJsZXMgZm9yIGF1ZGl0aW5nIHB1cnBvc2VzLgotICAgKipBdXRvbWF0aWMgTW9kaWZpY2F0aW9uKio6IFRvIGF1dG9tYXRpY2FsbHkgdXBkYXRlIG9yIHRyYW5zZm9ybSBkYXRhIGluIHJlc3BvbnNlIHRvIGRhdGFiYXNlIG9wZXJhdGlvbnMsIHN1Y2ggYXMgdXBkYXRpbmcgYSAibGFzdCBtb2RpZmllZCIgdGltZXN0YW1wIGNvbHVtbiB3aGVuZXZlciBhIHJvdyBpcyB1cGRhdGVkLgoKIyMgRXhhbXBsZSBvZiBhIFRyaWdnZXIgaW4gU1FMaXRlCgpIZXJlJ3MgYSBzaW1wbGUgZXhhbXBsZSBvZiBhIHRyaWdnZXIgaW4gU1FMaXRlIHRoYXQgYXV0b21hdGljYWxseSB1cGRhdGVzIGEgImxhc3RfbW9kaWZpZWQiIHRpbWVzdGFtcCBjb2x1bW4gaW4gYSB0YWJsZSBjYWxsZWQgIm15X3RhYmxlIiB3aGVuZXZlciBhIHJvdyBpcyB1cGRhdGVkOgoKYGBgIHNxbApDUkVBVEUgVFJJR0dFUiBVcGRhdGVMYXN0TW9kaWZpZWRUaW1lCkFGVEVSIFVQREFURSBPTiBteV90YWJsZQpCRUdJTgogICAgVVBEQVRFIG15X3RhYmxlIFNFVCBsYXN0X21vZGlmaWVkID0gQ1VSUkVOVF9USU1FU1RBTVAgV0hFUkUgcm93aWQgPSBORVcucm93aWQ7CkVORDsKYGBgCgpUaGlzIHRyaWdnZXIgaXMgZGVmaW5lZCB0byBmaXJlIGFmdGVyIGFuIHVwZGF0ZSBvcGVyYXRpb24gb24gIm15X3RhYmxlIi4gSXQgc2V0cyB0aGUgImxhc3RfbW9kaWZpZWQiIGNvbHVtbiB0byB0aGUgY3VycmVudCB0aW1lc3RhbXAgZm9yIHRoZSByb3cgdGhhdCB3YXMgdXBkYXRlZC4KCiMjIENvbnNpZGVyYXRpb25zIG9uIFVzZQoKLSAgICoqUGVyZm9ybWFuY2UgSW1wYWN0Kio6IFRyaWdnZXJzIGNhbiBpbXBhY3QgZGF0YWJhc2UgcGVyZm9ybWFuY2UsIGVzcGVjaWFsbHkgaWYgdGhleSBwZXJmb3JtIGNvbXBsZXggb3BlcmF0aW9ucyBvciBpZiBtYW55IHRyaWdnZXJzIGZpcmUgaW4gcmVzcG9uc2UgdG8gZnJlcXVlbnQgZGF0YSBtb2RpZmljYXRpb24gZXZlbnRzLgotICAgKipEZWJ1Z2dpbmcgQ29tcGxleGl0eSoqOiBEZWJ1Z2dpbmcgY2FuIGJlY29tZSBtb3JlIGNoYWxsZW5naW5nIHdpdGggdHJpZ2dlcnMsIGFzIHRoZSBsb2dpYyBpcyBleGVjdXRlZCBpbXBsaWNpdGx5LCB3aGljaCBtYXkgbGVhZCB0byB1bmV4cGVjdGVkIGJlaGF2aW9yIGlmIG5vdCBjYXJlZnVsbHkgbWFuYWdlZC4KCiMjIFR1dG9yaWFsCgpJbiB0aGUgc2hvcnQgdmlkZW8gdHV0b3JpYWwgYmVsb3csIEtob3VyeSBCb3N0b24ncyBQcm9mLiBTY2hlZGxiYXVlciBzaG93cyBob3cgdG8gZGVmaW5lIGFuZCB0ZXN0IHRyaWdnZXJzIGluIGEgU1FMaXRlIGRhdGFiYXNlLiBOb3RlIHRoYXQgd2hpbGUgU1FMaXRlIHN1cHBvcnRzIHRyaWdnZXJzIGl0IGRvZXMgbm90IHN1cHBvcnQgc3RvcmVkIHByb2NlZHVyZXMuIFRyaWdnZXJzIGFyZSBjb21tb25seSB1c2VkIGluIFNRTGl0ZSB0byBtYWludGFpbiB1c2VyIGRlZmluZWQgaW50ZWdyaXR5IGNvbnN0cmFpbnRzLCBrZWVwIGRlcml2ZWQgYXR0cmlidXRlcyB1cGRhdGVkLCBhbmQgZW5zdXJlIHRoYXQgdmFsdWVzIGFyZSBpbiBkZWZpbmVkIHJhbmdlcy4KCkV2ZXJ5IGRhdGFiYXNlIGhhcyBpdHMgb3duIHN5bnRheCBmb3IgZGVmaW5pbmcgdHJpZ2dlcnMgYW5kIGltcG9zZXMgaXRzIG93biByZXN0cmljdGlvbnMgb24gd2hhdCBjYW4gYmUgZG9uZSBpbiBhIHRyaWdnZXIgYW5kIHdoYXQgY2Fubm90OiBTUUxpdGUgaXMgbm8gZGlmZmVyZW50LgoKPGlmcmFtZSBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgIzQ2NDY0NjsiIHNyYz0iaHR0cHM6Ly9ub3J0aGVhc3Rlcm4uaG9zdGVkLnBhbm9wdG8uY29tL1Bhbm9wdG8vUGFnZXMvRW1iZWQuYXNweD9pZD1kNWE5MTRlNy1kMDM0LTQyMzktYTZjNy1hYzU1MDE1MDhmZDYmYW1wO2F1dG9wbGF5PWZhbHNlJmFtcDtvZmZlcnZpZXdlcj10cnVlJmFtcDtzaG93dGl0bGU9ZmFsc2UmYW1wO3Nob3dicmFuZD1mYWxzZSZhbXA7c3RhcnQ9MCZhbXA7aW50ZXJhY3Rpdml0eT1hbGwiIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBhbGxvd2Z1bGxzY3JlZW49ImFsbG93ZnVsbHNjcmVlbiIgYWxsb3c9ImF1dG9wbGF5IiBkYXRhLWV4dGVybmFsPSIxIj4KCjwvaWZyYW1lPgoKKipTbGlkZSBEZWNrKio6IFs3MC45MDEgLSBUcmlnZ2VycyBpbiBTUUxpdGVdKHMtNzAtOTAxLXRyaWdnZXJzLXNxbGl0ZS5wcHR4KQoKIyMgU3RlcC1ieS1TdGVwIEd1aWRlCgpCdWlsZGluZyBhIHRyaWdnZXIgaW4gU1FMaXRlIGludm9sdmVzIHNwZWNpZnlpbmcgdGhlIHRpbWluZywgZXZlbnQsIGFuZCBhY3Rpb24geW91IHdhbnQgdGhlIHRyaWdnZXIgdG8gcGVyZm9ybSBpbiByZXNwb25zZSB0byBjaGFuZ2VzIGluIHRoZSBkYXRhYmFzZS4gSGVyZSdzIGEgc3RlcC1ieS1zdGVwIGd1aWRlIG9uIGhvdyB0byBjcmVhdGUgYSB0cmlnZ2VyIGluIFNRTGl0ZToKCiMjIyAxLiBEZXRlcm1pbmUgdGhlIFRyaWdnZXIncyBQdXJwb3NlCgpGaXJzdCwgZGVjaWRlIHdoYXQgeW91IHdhbnQgdGhlIHRyaWdnZXIgdG8gZG8uIEZvciBleGFtcGxlLCB5b3UgbWlnaHQgd2FudCB0byBsb2cgY2hhbmdlcyB0byBhIHRhYmxlLCBlbmZvcmNlIGNvbXBsZXggY29uc3RyYWludHMsIG9yIGF1dG9tYXRpY2FsbHkgdXBkYXRlIHJlbGF0ZWQgZGF0YS4KCiMjIyAyLiBDaG9vc2UgdGhlIFRyaWdnZXIgRXZlbnQgYW5kIFRpbWluZwoKRGVjaWRlIG9uIHRoZSBldmVudCAoSU5TRVJULCBVUERBVEUsIERFTEVURSkgdGhhdCB3aWxsIGZpcmUgdGhlIHRyaWdnZXIgYW5kIHdoZXRoZXIgaXQgc2hvdWxkIGhhcHBlbiBCRUZPUkUsIEFGVEVSLCBvciBJTlNURUFEIE9GIHRoZSBldmVudC4KCiMjIyBCYXNpYyBTeW50YXgKClRoZSBiYXNpYyBzeW50YXggZm9yIGNyZWF0aW5nIGEgdHJpZ2dlciBpbiBTUUxpdGUgaXM6CgpgYGAgc3FsCkNSRUFURSBUUklHR0VSIFtJRiBOT1QgRVhJU1RTXSB0cmlnZ2VyX25hbWUKW0JFRk9SRXxBRlRFUnxJTlNURUFEIE9GXSBldmVudF9uYW1lCk9OIHRhYmxlX25hbWUKW0ZPUiBFQUNIIFJPV10KW1dIRU4gY29uZGl0aW9uXQpCRUdJTgogICAgLS0gVHJpZ2dlciBsb2dpYyBoZXJlCkVORDsKYGBgCgotICAgKipbSUYgTk9UIEVYSVNUU10qKjogT3B0aW9uYWwuIFNwZWNpZmllcyB0aGF0IHRoZSB0cmlnZ2VyIHNob3VsZCBvbmx5IGJlIGNyZWF0ZWQgaWYgbm8gb3RoZXIgdHJpZ2dlciBvZiB0aGUgc2FtZSBuYW1lIGFscmVhZHkgZXhpc3RzLgotICAgKip0cmlnZ2VyX25hbWUqKjogVGhlIG5hbWUgb2YgdGhlIHRyaWdnZXIuCi0gICAqKltCRUZPUkVcfEFGVEVSXHxJTlNURUFEIE9GXSoqOiBTcGVjaWZpZXMgd2hlbiB0aGUgdHJpZ2dlciBzaG91bGQgYmUgZmlyZWQgcmVsYXRpdmUgdG8gdGhlIGV2ZW50LgotICAgKipldmVudF9uYW1lKio6IFRoZSB0eXBlIG9mIG9wZXJhdGlvbiB0aGF0IGFjdGl2YXRlcyB0aGUgdHJpZ2dlciAoSU5TRVJULCBVUERBVEUsIERFTEVURSkuCi0gICAqKnRhYmxlX25hbWUqKjogVGhlIG5hbWUgb2YgdGhlIHRhYmxlIG9uIHdoaWNoIHRoZSB0cmlnZ2VyIG9wZXJhdGVzLgotICAgKipbRk9SIEVBQ0ggUk9XXSoqOiBTcGVjaWZpZXMgdGhhdCB0aGUgdHJpZ2dlciBzaG91bGQgYmUgZmlyZWQgb25jZSBmb3IgZWFjaCByb3cgYWZmZWN0ZWQgYnkgdGhlIGV2ZW50LiBPbWl0dGluZyB0aGlzIG1lYW5zIHRoZSB0cmlnZ2VyIGlzIGNvbnNpZGVyZWQgYSAic3RhdGVtZW50LWxldmVsIHRyaWdnZXIuIgotICAgKipbV0hFTiBjb25kaXRpb25dKio6IEFuIG9wdGlvbmFsIGNvbmRpdGlvbiBmb3IgdGhlIHRyaWdnZXIgdG8gZmlyZS4gSWYgdGhlIGNvbmRpdGlvbiBpcyBub3QgbWV0LCB0aGUgdHJpZ2dlciBkb2VzIG5vdCBleGVjdXRlLgotICAgKiotLSBUcmlnZ2VyIGxvZ2ljIGhlcmUqKjogVGhlIFNRTCBzdGF0ZW1lbnRzIHRvIGJlIGV4ZWN1dGVkIHdoZW4gdGhlIHRyaWdnZXIgZmlyZXMuCgojIyMgMy4gRGVmaW5lIHRoZSBUcmlnZ2VyIEFjdGlvbgoKV3JpdGUgdGhlIFNRTCBzdGF0ZW1lbnRzIHRoYXQgc2hvdWxkIGJlIGV4ZWN1dGVkIHdoZW4gdGhlIHRyaWdnZXIgZmlyZXMuIFRoZXNlIGNhbiBpbmNsdWRlIG9wZXJhdGlvbnMgbGlrZSBJTlNFUlQsIFVQREFURSwgREVMRVRFLCBvciBldmVuIGNhbGxpbmcgb3RoZXIgZnVuY3Rpb25zLgoKIyMjIEV4YW1wbGU6IExvZ2dpbmcgVXBkYXRlcyB0byBhIFRhYmxlCgpTdXBwb3NlIHlvdSBoYXZlIGEgdGFibGUgYGVtcGxveWVlc2AgYW5kIHlvdSB3YW50IHRvIGxvZyBldmVyeSB1cGRhdGUgbWFkZSB0byBhbiBlbXBsb3llZSdzIHNhbGFyeSBpbiBhIGBzYWxhcnlfY2hhbmdlc2AgbG9nIHRhYmxlLiBZb3UgY291bGQgY3JlYXRlIGFuIEFGVEVSIFVQREFURSB0cmlnZ2VyIGxpa2UgdGhpczoKCmBgYCBzcWwKQ1JFQVRFIFRSSUdHRVIgbG9nX3NhbGFyeV9jaGFuZ2UKQUZURVIgVVBEQVRFIE9GIHNhbGFyeSBPTiBlbXBsb3llZXMKRk9SIEVBQ0ggUk9XCldIRU4gT0xELnNhbGFyeSAhPSBORVcuc2FsYXJ5CkJFR0lOCiAgICBJTlNFUlQgSU5UTyBzYWxhcnlfY2hhbmdlcyhlbXBsb3llZV9pZCwgb2xkX3NhbGFyeSwgbmV3X3NhbGFyeSwgY2hhbmdlX2RhdGUpCiAgICBWQUxVRVMgKE5FVy5lbXBsb3llZV9pZCwgT0xELnNhbGFyeSwgTkVXLnNhbGFyeSwgQ1VSUkVOVF9USU1FU1RBTVApOwpFTkQ7CmBgYAoKVGhpcyB0cmlnZ2VyIGZpcmVzIGFmdGVyIHRoZSBzYWxhcnkgY29sdW1uIG9mIGFuIGVtcGxveWVlIGlzIHVwZGF0ZWQsIGJ1dCBvbmx5IGlmIHRoZSBuZXcgc2FsYXJ5IGlzIGRpZmZlcmVudCBmcm9tIHRoZSBvbGQgc2FsYXJ5LiBJdCB0aGVuIGxvZ3MgdGhlIGNoYW5nZSBpbiB0aGUgYHNhbGFyeV9jaGFuZ2VzYCB0YWJsZS4KCiMjIyA0LiBFeGVjdXRlIHRoZSBDUkVBVEUgVFJJR0dFUiBTdGF0ZW1lbnQKClJ1biB0aGUgYENSRUFURSBUUklHR0VSYCBzdGF0ZW1lbnQgaW4geW91ciBTUUxpdGUgZW52aXJvbm1lbnQgdG8gY3JlYXRlIHRoZSB0cmlnZ2VyLiBZb3UgY2FuIGRvIHRoaXMgdGhyb3VnaCBhbiBTUUxpdGUgY2xpZW50IG9yIHRocm91Z2ggYSBzY3JpcHRpbmcgaW50ZXJmYWNlIHRoYXQgaW50ZXJhY3RzIHdpdGggU1FMaXRlLgoKIyMjIDUuIFRlc3QgdGhlIFRyaWdnZXIKCkFmdGVyIGNyZWF0aW5nIHRoZSB0cmlnZ2VyLCBwZXJmb3JtIG9wZXJhdGlvbnMgb24gdGhlIHRhcmdldCB0YWJsZSB0byBlbnN1cmUgdGhlIHRyaWdnZXIgYmVoYXZlcyBhcyBleHBlY3RlZC4gQ2hlY2sgdGhlIG91dGNvbWVzIGJhc2VkIG9uIHRoZSBsb2dpYyB5b3UndmUgZGVmaW5lZC4KCiMjIyBCZXN0IFByYWN0aWNlcwoKLSAgIEVuc3VyZSB0aGUgbG9naWMgd2l0aGluIHlvdXIgdHJpZ2dlcnMgaXMgZWZmaWNpZW50IGFuZCBkb2VzIG5vdCBsZWFkIHRvIHVuaW50ZW5kZWQgc2lkZSBlZmZlY3RzLgotICAgS2VlcCB0aGUgdHJpZ2dlciBsb2dpYyBzaW1wbGUgdG8gYXZvaWQgY29tcGxleCBpbnRlcmRlcGVuZGVuY2llcyB0aGF0IGNhbiBtYWtlIGRlYnVnZ2luZyBkaWZmaWN1bHQuCi0gICBDb25zaWRlciB0aGUgcGVyZm9ybWFuY2UgaW1wbGljYXRpb25zIG9mIHRyaWdnZXJzLCBhcyBjb21wbGV4IG9yIG51bWVyb3VzIHRyaWdnZXJzIGNhbiBpbXBhY3QgdGhlIGRhdGFiYXNlIHBlcmZvcm1hbmNlLgoKQ3JlYXRpbmcgdHJpZ2dlcnMgaW4gU1FMaXRlIGNhbiBncmVhdGx5IGVuaGFuY2UgdGhlIGZ1bmN0aW9uYWxpdHkgYW5kIGludGVncml0eSBvZiB5b3VyIGRhdGFiYXNlIGJ5IGF1dG9tYXRpbmcgdGFza3MgYW5kIGVuZm9yY2luZyBydWxlcyBkaXJlY3RseSB3aXRoaW4gdGhlIGRhdGFiYXNlLgoKIyMgT3JkZXIgb2YgRXhlY3V0aW9uIG9mIE11bHRpcGxlIFRyaWdnZXJzCgpJbiBTUUxpdGUsIHdoZW4gbXVsdGlwbGUgdHJpZ2dlcnMgYXJlIGRlZmluZWQgZm9yIHRoZSBzYW1lIGV2ZW50IG9uIGEgc2luZ2xlIGRhdGFiYXNlIG9iamVjdCwgc3VjaCBhcyBhIHRhYmxlLCBhbmQgdGhleSBhcmUgb2YgdGhlIHNhbWUgdGltZSAoKmkuZS4qLCBCRUZPUkUsIEFGVEVSLCBvciBJTlNURUFEIE9GKSwgdGhlIHRyaWdnZXJzIGFyZSBleGVjdXRlZCBpbiB0aGUgb3JkZXIgdGhleSB3ZXJlIGNyZWF0ZWQuIFRoaXMgbWVhbnMgdGhhdCB0aGUgdHJpZ2dlciB0aGF0IHdhcyBkZWZpbmVkIGZpcnN0IHdpbGwgYmUgZXhlY3V0ZWQgZmlyc3QsIGZvbGxvd2VkIGJ5IHRoZSBuZXh0IHRyaWdnZXIgZGVmaW5lZCwgYW5kIHNvIG9uLiBUaGlzIG9yZGVyIG9mIGV4ZWN1dGlvbiBpcyBjb25zaXN0ZW50IGFzIGxvbmcgYXMgdGhlIHRyaWdnZXJzIHJlbWFpbiBkZWZpbmVkIGluIHRoZSBkYXRhYmFzZS4gT3RoZXIgZGF0YWJhc2VzIG1heSBleGVjdXRlIHRoZSB0cmlnZ2VycyBpbiBhIGRpZmZlcmVudCBvcmRlciBvciBwZXJoYXBzIGV2ZW4gbm9uLWRldGVybWluaXN0aWMsIHNvIHJlbHlpbmcgb24gYSBzcGVjaWZpYyBvcmRlciBvZiBleGVjdXRpb24gaXMgZGFuZ2Vyb3VzIGFuZCBjYW4gbGVhZCB0byB1bmludGVuZGVkIGJlaGF2aW9yIGFuZCBzaG91bGQgYmUgYXZvaWRlZC4KCkhvd2V2ZXIsIFNRTGl0ZSBkb2VzIG5vdCBwcm92aWRlIGJ1aWx0LWluIGZ1bmN0aW9uYWxpdHkgdG8gZXhwbGljaXRseSBzcGVjaWZ5IHRoZSBvcmRlciBvZiB0cmlnZ2VyIGV4ZWN1dGlvbiBiZXlvbmQgdGhpcy4gSWYgYSBzcGVjaWZpYyBleGVjdXRpb24gb3JkZXIgaXMgcmVxdWlyZWQsIHRoZSBkZXZlbG9wZXIgbXVzdCBtYW5hZ2UgdGhlIGNyZWF0aW9uIG9yZGVyIGNhcmVmdWxseSBvciBkZXNpZ24gdGhlIHRyaWdnZXJzIGluIHN1Y2ggYSB3YXkgdGhhdCB0aGVpciBleGVjdXRpb24gb3JkZXIgZG9lcyBub3QgaW1wYWN0IHRoZSBhcHBsaWNhdGlvbiBsb2dpYyBvciBkYXRhIGludGVncml0eS4KCkl0J3MgaW1wb3J0YW50IHRvIGRlc2lnbiB0cmlnZ2VycyBhbmQgdGhlaXIgbG9naWMgd2l0aCBjb25zaWRlcmF0aW9uIG9mIHRoaXMgZXhlY3V0aW9uIG9yZGVyLCBlc3BlY2lhbGx5IHdoZW4gdHJpZ2dlcnMgbWlnaHQgaGF2ZSBkZXBlbmRlbmNpZXMgb24gdGhlIGVmZmVjdHMgb2Ygb25lIGFub3RoZXIuIFByb3BlciB0ZXN0aW5nIGFuZCB2YWxpZGF0aW9uIGFyZSBlc3NlbnRpYWwgdG8gZW5zdXJlIHRoYXQgdGhlIGNvbWJpbmVkIGVmZmVjdCBvZiBtdWx0aXBsZSB0cmlnZ2VycyBvbiB0aGUgc2FtZSBldmVudCBkb2VzIG5vdCBsZWFkIHRvIHVuaW50ZW5kZWQgY29uc2VxdWVuY2VzIG9yIHZpb2xhdGUgZGF0YSBpbnRlZ3JpdHkgY29uc3RyYWludHMuCgojIyBTdW1tYXJ5CgpUcmlnZ2VycyBpbiBTUUxpdGUgb2ZmZXIgYSBmbGV4aWJsZSBtZWNoYW5pc20gZm9yIGltcGxlbWVudGluZyBhdXRvbWF0aWMgcmVzcG9uc2VzIHRvIGRhdGFiYXNlIGV2ZW50cywgbWFraW5nIHRoZW0gYSB2YWx1YWJsZSBmZWF0dXJlIGZvciBkZXZlbG9wZXJzIGxvb2tpbmcgdG8gZW5mb3JjZSBkYXRhIGludGVncml0eSwgYXV0b21hdGUgZGF0YWJhc2UgbG9naWMsIGFuZCBtYW5hZ2UgY29tcGxleCByZWxhdGlvbnNoaXBzIHdpdGhpbiB0aGVpciBTUUxpdGUgZGF0YWJhc2VzLgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBGaWxlcyAmIFJlc291cmNlcyB7I2ZpbGVzLXJlc291cmNlc30KCmBgYHtyIHppcEZpbGVzLCBlY2hvPUZBTFNFfQp6aXBOYW1lID0gc3ByaW50ZigiTGVzc29uRmlsZXMtJXMtJXMuemlwIiwgCiAgICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LAogICAgICAgICAgICAgICAgIHBhcmFtcyRudW1iZXIpCgp0ZXh0QUxpbmsgPSBwYXN0ZTAoIkFsbCBGaWxlcyBmb3IgTGVzc29uICIsIAogICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksIi4iLHBhcmFtcyRudW1iZXIpCgojIGRvd25sb2FkRmlsZXNMaW5rKCkgaXMgaW5jbHVkZWQgZnJvbSBfaW5zZXJ0MkRCLlIKa25pdHI6OnJhd19odG1sKGRvd25sb2FkRmlsZXNMaW5rKCIuIiwgemlwTmFtZSwgdGV4dEFMaW5rKSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFJlZmVyZW5jZXMKCi0gICBbU1FMaXRlIFRyaWdnZXJzXShodHRwczovL3d3dy5zcWxpdGV0dXRvcmlhbC5uZXQvc3FsaXRlLXRyaWdnZXIvIzp+OnRleHQ9QW4lMjBTUUxpdGUlMjB0cmlnZ2VyJTIwaXMlMjBhLGlzc3VlZCUyMGFnYWluc3QlMjB0aGUlMjBhc3NvY2lhdGVkJTIwdGFibGUuKQotICAgW1NRTGl0ZSBJTlNURUFEIE9GIFRyaWdnZXJzXShodHRwczovL3d3dy5zcWxpdGV0dXRvcmlhbC5uZXQvc3FsaXRlLWluc3RlYWQtb2YtdHJpZ2dlcnMvKQoKIyMgRXJyYXRhCgpOb25lIGNvbGxlY3RlZCB5ZXQuIExldCB1cyBrbm93LgoKW0xldCB1cyBrbm93XShodHRwczovL2Zvcm0uam90Zm9ybS5jb20vMjEyMTg3MDcyNzg0MTU3KXt0YXJnZXQ9Il9ibGFuayJ9Lgo=