Introduction

SQLite is a popular software library that provides a relational database management system (RDBMS) that is designed to be embedded into software applications. It is a self-contained, serverless, zero-configuration, transactional SQL database engine. SQLite is a file-based database system, which means that the entire database is stored in a single file on the file system of the host computer.

SQLite supports most of the standard SQL syntax and provides a lightweight and fast alternative to larger, more complex database systems. It is a widely used database technology in embedded systems, mobile applications, desktop software, and web applications. SQLite is often used for small to medium-sized applications or as a local data store for larger applications that use a more powerful database server for remote data storage and retrieval.

Serverless Architecture

When we say that SQLite is “serverless”, it means that it doesn’t require a separate server process to be running in order to access and manipulate the data in the database. Instead, SQLite is designed to be embedded directly into the application that uses it. This means that the database operations are performed directly by the application, without the need for a separate server process to be running in the background.

Additionally, SQLite is a “file-based” database system, which means that the entire database is stored in a single file on the file system of the host computer. This makes it easy to move the database between different machines or to back it up, since it’s just a matter of copying the file. The file-based approach also makes it easy to set up and use SQLite, since there is no need to install or configure a separate database server or create a separate database instance.

SQLite being serverless and file-based makes it a lightweight, self-contained, and easy-to-use database system that can be embedded into a wide range of applications, without the need for a separate database server or complex setup.

Installing SQLite Command Line Tools

The tools below do not need to be installed when accessing a SQLite database from an application written in Java, C++, R, Python, and most other languages. These language include a package or library that contains all the code necessary to access a SQLite database.

However, to run scripts, you must install the command line tools. Of course, you can access the same database from an application, R programs, R Notebooks, and the command line. This is often useful to inspect a database that’s created by an application.

The process of installing SQLite can vary depending on your operating system and how you plan to use it. Here are some general steps to follow:

Installing SQLite on Windows

  • Go to the SQLite download page: https://www.sqlite.org/download.html
  • Under the “Precompiled Binaries for Windows” section, download the appropriate version of SQLite for your Windows operating system (32-bit or 64-bit).
  • Unzip the downloaded file and extract the contents to a directory on your computer.
  • Add the directory where you extracted SQLite to the system’s PATH environment variable.

Installing SQLite on Mac

  • Install Homebrew, if you don’t have it already, by following the instructions on the Homebrew website: https://brew.sh/
  • Open a terminal window and run the following command: brew install sqlite
  • Wait for Homebrew to download and install SQLite.

Installing SQLite on Linux

  • Open a terminal window and run the following command to update the package list:

    sudo apt-get update

  • Run the following command to install SQLite:

    sudo apt-get install sqlite3

  • Wait for the installation to complete.

After installation, you can start using SQLite by running the sqlite3 command in your terminal or command prompt. This will launch the SQLite shell, where you can create, open, and manipulate SQLite databases.

Cloud SQLite

As an alternative to installing SQLite locally, you can upload SQLite database files to sqliteonline.com, or, use sqliteonline.com to create databases, run scripts, and download database files.

Creating a New Database

Creating a new database is SQLite is simple: open a database file that does not exist and SQLite will create a new database with that file name.

% sqlite3 customerDB.sqlitedb

SQLite database files can have any extension, but .sqlitedb and .db are most common.

Worked Example

In the worked example below, we create a new database using a creation script through the management console os SQLite. The script is generic and standard SQL, so it will work just as well on any other relational database, including MySQL, Oracle, and SQL Server. After creation of the database, sample data is added to the database via the script, although this could have also been done via imports of CSV files. Finally, we execute a set of queries against the sample data in the database.

Create Database

Download the organization database creation script: create-orgdb.sql. A script is a plain text file containing SQL statements.

Using either the command line tools sqlite3 or the cloud version of SQLite, source (run) the script to execute all of the SQL statements in the script. This will create the database with sample data.

Inspect the tables in the database either by studying the SQL creation code or listing the tables. It is a useful practice to visualize the database structure by drawing an Entity-Relationship or UML diagram.

The tutorial below will show you how to create the database, connect to it, and inspect the tables. Watch it only after you attempted to do this yourself. It assumes that you have the SQLite tools installed locally on your computer.

Build Queries

Once you are familiar with the database, use the interactive command line tool to build SQL queries for the following questions:

Query 1

Find the distinct number of workers who work in the HR department and who earn more than ₹225,000.

select distinct count(*) as 'NumWorkers'
  from Worker as w
 where w.department = 'HR'
   and w.salary > 250000;
    

Query 2

Find the last name and title of all workers and the department they work in who earn less than the average salary.

select last_name, worker_title
  from Worker AS w JOIN Title AS t ON (w.WORKER_ID = t.WORKER_REF_ID)
   and w.salary < (select avg(salary) from Worker);
    

Query 3

What is the average salary paid for all workers in each department? List the department, the average salary for the department, and the number of workers in each department. Name the average column ‘AvgSal’ and the number of workers column to ‘Num’.

select department, AVG(salary) as 'AvgSalary', count(*) as 'NumWorkers'
  from Worker
 group by department;
    

Query 4

What is the total compensation for each worker (salary and bonus) on a per monthly basis? List the name of the worker, their title, and the their monthly compensation (annual compensation divided by 12). Change the header for compensation to ‘MonthlyComp’ and round it to the nearest whole number.

select last_name, ((salary + bonus_amount) / 12) as 'MonthlyComp'
  from Worker as w join Bonus as b on (w.WORKER_ID = b.WORKER_REF_ID)
    

Query 5

List the full names of all workers in all capital letters who did not get a bonus.

select upper(last_name || ", " || first_name) as 'FullName'
  from Worker
 where worker_id not in (select worker_ref_id from Bonus)
 order by last_name;
    

Query 6

What are the full names of all workers who have ‘Manager’ in their title. Do not “hard code” the titles; use string searching.

select upper(last_name || ", " || first_name) as 'FullName', t.WORKER_TITLE
  from Worker w, Title t 
 WHERE w.WORKER_ID = t.WORKER_REF_ID
   and t.WORKER_TITLE LIKE '%Manager%';
    

Tutorial

Conclusion

Management consoles, available for every database, are an essential tool for database development and administration. Some are command-line oriented and some have graphical user interfaces. Some even allow database design through integrated diagramming tools.

Aside from allowing us to create databases and perform ad hoc queries, the provide a number of additional benefits.

  • Centralized control: A management console provides a centralized interface for managing and monitoring a database, allowing administrators to configure and monitor the database more easily and efficiently.

  • Efficient performance monitoring: A management console provides real-time monitoring of the database’s performance, enabling administrators to quickly identify and troubleshoot performance issues. This can help improve the overall performance of the database, reducing downtime and improving the end user experience.

  • Enhanced security: A management console can help to enhance the security of a database by providing tools to manage users and permissions, set up auditing, and monitor the database for suspicious activity. This can help prevent unauthorized access to the database and protect sensitive data.

  • Automated backup and recovery: Many management consoles include tools for automated backup and recovery of the database, helping to ensure data is protected in the event of a disaster or other unforeseen circumstances.

  • Simplified administration: A management console can simplify database administration by providing a graphical user interface that simplifies complex database tasks. This can help reduce the need for specialized skills or knowledge, making it easier for a wider range of staff to manage and maintain the database.

Overall, a management console for a database can help streamline database management, facilitate ad hoc querying, improve performance and security, and simplify administration, making it an essential tool for database development.

This lesson showed how to install and use the management console for SQLite.


Files & Resources

All Files for Lesson 70.803

Errata

None collected yet. Let us know.

LS0tCnRpdGxlOiAiSW50ZXJhY3Rpbmcgd2l0aCBTUUxpdGUgdGhyb3VnaCBDb25zb2xlIGFuZCBTY3JpcHRzIgpwYXJhbXM6CiAgY2F0ZWdvcnk6IDcwCiAgbnVtYmVyOiA4MDMKICB0aW1lOiA2MAogIGxldmVsOiBpbnRlcm1lZGlhdGUKICB0YWdzOiAic3FsaXRlLHNjcmlwdHMiCiAgZGVzY3JpcHRpb246ICJFeHBsYWlucyBob3cgdG8gY3JlYXRlIGRhdGFiYXNlcyB0aHJvdWdoIFNRTGl0ZSBTUUwgc2NyaXB0cy4gU2hvd3MKICAgICAgICAgICAgICAgIGhvdyB0byBpbnN0YWxsIGFuZCB1c2UgbWFuYWdlbWVudCBjb25zb2xlIHRocm91Z2ggdGVybWluIHNoZWxsLiIKZGF0ZTogIjxzbWFsbD5gciBTeXMuRGF0ZSgpYDwvc21hbGw+IgphdXRob3I6ICI8c21hbGw+TWFydGluIFNjaGVkbGJhdWVyPC9zbWFsbD4iCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1IgphZmZpbGl0YXRpb246ICJOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogc3BhY2VsYWIKICAgIGhpZ2hsaWdodDogdGFuZ28KLS0tCgotLS0KdGl0bGU6ICI8c21hbGw+YHIgcGFyYW1zJGNhdGVnb3J5YC5gciBwYXJhbXMkbnVtYmVyYDwvc21hbGw+PGJyLz48c3BhbiBzdHlsZT0nY29sb3I6ICMyRTQwNTM7IGZvbnQtc2l6ZTogMC45ZW0nPmByIHJtYXJrZG93bjo6bWV0YWRhdGEkdGl0bGVgPC9zcGFuPiIKLS0tCgpgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9faW5zZXJ0MkRCLlInKSksIGluY2x1ZGUgPSBGQUxTRSwgY2FjaGU9VFJVRX0KYGBgCgojIyBJbnRyb2R1Y3Rpb24KClNRTGl0ZSBpcyBhIHBvcHVsYXIgc29mdHdhcmUgbGlicmFyeSB0aGF0IHByb3ZpZGVzIGEgcmVsYXRpb25hbCBkYXRhYmFzZSBtYW5hZ2VtZW50IHN5c3RlbSAoUkRCTVMpIHRoYXQgaXMgZGVzaWduZWQgdG8gYmUgZW1iZWRkZWQgaW50byBzb2Z0d2FyZSBhcHBsaWNhdGlvbnMuIEl0IGlzIGEgc2VsZi1jb250YWluZWQsIHNlcnZlcmxlc3MsIHplcm8tY29uZmlndXJhdGlvbiwgdHJhbnNhY3Rpb25hbCBTUUwgZGF0YWJhc2UgZW5naW5lLiBTUUxpdGUgaXMgYSBmaWxlLWJhc2VkIGRhdGFiYXNlIHN5c3RlbSwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgZW50aXJlIGRhdGFiYXNlIGlzIHN0b3JlZCBpbiBhIHNpbmdsZSBmaWxlIG9uIHRoZSBmaWxlIHN5c3RlbSBvZiB0aGUgaG9zdCBjb21wdXRlci4KClNRTGl0ZSBzdXBwb3J0cyBtb3N0IG9mIHRoZSBzdGFuZGFyZCBTUUwgc3ludGF4IGFuZCBwcm92aWRlcyBhIGxpZ2h0d2VpZ2h0IGFuZCBmYXN0IGFsdGVybmF0aXZlIHRvIGxhcmdlciwgbW9yZSBjb21wbGV4IGRhdGFiYXNlIHN5c3RlbXMuIEl0IGlzIGEgd2lkZWx5IHVzZWQgZGF0YWJhc2UgdGVjaG5vbG9neSBpbiBlbWJlZGRlZCBzeXN0ZW1zLCBtb2JpbGUgYXBwbGljYXRpb25zLCBkZXNrdG9wIHNvZnR3YXJlLCBhbmQgd2ViIGFwcGxpY2F0aW9ucy4gU1FMaXRlIGlzIG9mdGVuIHVzZWQgZm9yIHNtYWxsIHRvIG1lZGl1bS1zaXplZCBhcHBsaWNhdGlvbnMgb3IgYXMgYSBsb2NhbCBkYXRhIHN0b3JlIGZvciBsYXJnZXIgYXBwbGljYXRpb25zIHRoYXQgdXNlIGEgbW9yZSBwb3dlcmZ1bCBkYXRhYmFzZSBzZXJ2ZXIgZm9yIHJlbW90ZSBkYXRhIHN0b3JhZ2UgYW5kIHJldHJpZXZhbC4KCiMjIFNlcnZlcmxlc3MgQXJjaGl0ZWN0dXJlCgpXaGVuIHdlIHNheSB0aGF0IFNRTGl0ZSBpcyAic2VydmVybGVzcyIsIGl0IG1lYW5zIHRoYXQgaXQgZG9lc24ndCByZXF1aXJlIGEgc2VwYXJhdGUgc2VydmVyIHByb2Nlc3MgdG8gYmUgcnVubmluZyBpbiBvcmRlciB0byBhY2Nlc3MgYW5kIG1hbmlwdWxhdGUgdGhlIGRhdGEgaW4gdGhlIGRhdGFiYXNlLiBJbnN0ZWFkLCBTUUxpdGUgaXMgZGVzaWduZWQgdG8gYmUgZW1iZWRkZWQgZGlyZWN0bHkgaW50byB0aGUgYXBwbGljYXRpb24gdGhhdCB1c2VzIGl0LiBUaGlzIG1lYW5zIHRoYXQgdGhlIGRhdGFiYXNlIG9wZXJhdGlvbnMgYXJlIHBlcmZvcm1lZCBkaXJlY3RseSBieSB0aGUgYXBwbGljYXRpb24sIHdpdGhvdXQgdGhlIG5lZWQgZm9yIGEgc2VwYXJhdGUgc2VydmVyIHByb2Nlc3MgdG8gYmUgcnVubmluZyBpbiB0aGUgYmFja2dyb3VuZC4KCkFkZGl0aW9uYWxseSwgU1FMaXRlIGlzIGEgImZpbGUtYmFzZWQiIGRhdGFiYXNlIHN5c3RlbSwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgZW50aXJlIGRhdGFiYXNlIGlzIHN0b3JlZCBpbiBhIHNpbmdsZSBmaWxlIG9uIHRoZSBmaWxlIHN5c3RlbSBvZiB0aGUgaG9zdCBjb21wdXRlci4gVGhpcyBtYWtlcyBpdCBlYXN5IHRvIG1vdmUgdGhlIGRhdGFiYXNlIGJldHdlZW4gZGlmZmVyZW50IG1hY2hpbmVzIG9yIHRvIGJhY2sgaXQgdXAsIHNpbmNlIGl0J3MganVzdCBhIG1hdHRlciBvZiBjb3B5aW5nIHRoZSBmaWxlLiBUaGUgZmlsZS1iYXNlZCBhcHByb2FjaCBhbHNvIG1ha2VzIGl0IGVhc3kgdG8gc2V0IHVwIGFuZCB1c2UgU1FMaXRlLCBzaW5jZSB0aGVyZSBpcyBubyBuZWVkIHRvIGluc3RhbGwgb3IgY29uZmlndXJlIGEgc2VwYXJhdGUgZGF0YWJhc2Ugc2VydmVyIG9yIGNyZWF0ZSBhIHNlcGFyYXRlIGRhdGFiYXNlIGluc3RhbmNlLgoKU1FMaXRlIGJlaW5nIHNlcnZlcmxlc3MgYW5kIGZpbGUtYmFzZWQgbWFrZXMgaXQgYSBsaWdodHdlaWdodCwgc2VsZi1jb250YWluZWQsIGFuZCBlYXN5LXRvLXVzZSBkYXRhYmFzZSBzeXN0ZW0gdGhhdCBjYW4gYmUgZW1iZWRkZWQgaW50byBhIHdpZGUgcmFuZ2Ugb2YgYXBwbGljYXRpb25zLCB3aXRob3V0IHRoZSBuZWVkIGZvciBhIHNlcGFyYXRlIGRhdGFiYXNlIHNlcnZlciBvciBjb21wbGV4IHNldHVwLgoKIyMgSW5zdGFsbGluZyBTUUxpdGUgQ29tbWFuZCBMaW5lIFRvb2xzCgpUaGUgdG9vbHMgYmVsb3cgZG8gbm90IG5lZWQgdG8gYmUgaW5zdGFsbGVkIHdoZW4gYWNjZXNzaW5nIGEgU1FMaXRlIGRhdGFiYXNlIGZyb20gYW4gYXBwbGljYXRpb24gd3JpdHRlbiBpbiBKYXZhLCBDKyssIFIsIFB5dGhvbiwgYW5kIG1vc3Qgb3RoZXIgbGFuZ3VhZ2VzLiBUaGVzZSBsYW5ndWFnZSBpbmNsdWRlIGEgcGFja2FnZSBvciBsaWJyYXJ5IHRoYXQgY29udGFpbnMgYWxsIHRoZSBjb2RlIG5lY2Vzc2FyeSB0byBhY2Nlc3MgYSBTUUxpdGUgZGF0YWJhc2UuCgpIb3dldmVyLCB0byBydW4gc2NyaXB0cywgeW91IG11c3QgaW5zdGFsbCB0aGUgY29tbWFuZCBsaW5lIHRvb2xzLiBPZiBjb3Vyc2UsIHlvdSBjYW4gYWNjZXNzIHRoZSBzYW1lIGRhdGFiYXNlIGZyb20gYW4gYXBwbGljYXRpb24sIFIgcHJvZ3JhbXMsIFIgTm90ZWJvb2tzLCBhbmQgdGhlIGNvbW1hbmQgbGluZS4gVGhpcyBpcyBvZnRlbiB1c2VmdWwgdG8gaW5zcGVjdCBhIGRhdGFiYXNlIHRoYXQncyBjcmVhdGVkIGJ5IGFuIGFwcGxpY2F0aW9uLgoKVGhlIHByb2Nlc3Mgb2YgaW5zdGFsbGluZyBTUUxpdGUgY2FuIHZhcnkgZGVwZW5kaW5nIG9uIHlvdXIgb3BlcmF0aW5nIHN5c3RlbSBhbmQgaG93IHlvdSBwbGFuIHRvIHVzZSBpdC4gSGVyZSBhcmUgc29tZSBnZW5lcmFsIHN0ZXBzIHRvIGZvbGxvdzoKCiMjIyBJbnN0YWxsaW5nIFNRTGl0ZSBvbiBXaW5kb3dzCgotICAgR28gdG8gdGhlIFNRTGl0ZSBkb3dubG9hZCBwYWdlOiA8aHR0cHM6Ly93d3cuc3FsaXRlLm9yZy9kb3dubG9hZC5odG1sPgotICAgVW5kZXIgdGhlICJQcmVjb21waWxlZCBCaW5hcmllcyBmb3IgV2luZG93cyIgc2VjdGlvbiwgZG93bmxvYWQgdGhlIGFwcHJvcHJpYXRlIHZlcnNpb24gb2YgU1FMaXRlIGZvciB5b3VyIFdpbmRvd3Mgb3BlcmF0aW5nIHN5c3RlbSAoMzItYml0IG9yIDY0LWJpdCkuCi0gICBVbnppcCB0aGUgZG93bmxvYWRlZCBmaWxlIGFuZCBleHRyYWN0IHRoZSBjb250ZW50cyB0byBhIGRpcmVjdG9yeSBvbiB5b3VyIGNvbXB1dGVyLgotICAgQWRkIHRoZSBkaXJlY3Rvcnkgd2hlcmUgeW91IGV4dHJhY3RlZCBTUUxpdGUgdG8gdGhlIHN5c3RlbSdzIFBBVEggZW52aXJvbm1lbnQgdmFyaWFibGUuCgojIyMgSW5zdGFsbGluZyBTUUxpdGUgb24gTWFjCgotICAgSW5zdGFsbCBIb21lYnJldywgaWYgeW91IGRvbid0IGhhdmUgaXQgYWxyZWFkeSwgYnkgZm9sbG93aW5nIHRoZSBpbnN0cnVjdGlvbnMgb24gdGhlIEhvbWVicmV3IHdlYnNpdGU6IDxodHRwczovL2JyZXcuc2gvPgotICAgT3BlbiBhIHRlcm1pbmFsIHdpbmRvdyBhbmQgcnVuIHRoZSBmb2xsb3dpbmcgY29tbWFuZDogYnJldyBpbnN0YWxsIHNxbGl0ZQotICAgV2FpdCBmb3IgSG9tZWJyZXcgdG8gZG93bmxvYWQgYW5kIGluc3RhbGwgU1FMaXRlLgoKIyMjIEluc3RhbGxpbmcgU1FMaXRlIG9uIExpbnV4CgotICAgT3BlbiBhIHRlcm1pbmFsIHdpbmRvdyBhbmQgcnVuIHRoZSBmb2xsb3dpbmcgY29tbWFuZCB0byB1cGRhdGUgdGhlIHBhY2thZ2UgbGlzdDoKCiAgICBbc3VkbyBhcHQtZ2V0IHVwZGF0ZV17c3R5bGU9ImZvbnQtZmFtaWx5OkNvdXJpZXIifQoKLSAgIFJ1biB0aGUgZm9sbG93aW5nIGNvbW1hbmQgdG8gaW5zdGFsbCBTUUxpdGU6CgogICAgW3N1ZG8gYXB0LWdldCBpbnN0YWxsIHNxbGl0ZTNde3N0eWxlPSJmb250LWZhbWlseTpDb3VyaWVyIn0KCi0gICBXYWl0IGZvciB0aGUgaW5zdGFsbGF0aW9uIHRvIGNvbXBsZXRlLgoKQWZ0ZXIgaW5zdGFsbGF0aW9uLCB5b3UgY2FuIHN0YXJ0IHVzaW5nIFNRTGl0ZSBieSBydW5uaW5nIHRoZSBbc3FsaXRlM117c3R5bGU9ImZvbnQtZmFtaWx5OkNvdXJpZXIifSBjb21tYW5kIGluIHlvdXIgdGVybWluYWwgb3IgY29tbWFuZCBwcm9tcHQuIFRoaXMgd2lsbCBsYXVuY2ggdGhlIFNRTGl0ZSBzaGVsbCwgd2hlcmUgeW91IGNhbiBjcmVhdGUsIG9wZW4sIGFuZCBtYW5pcHVsYXRlIFNRTGl0ZSBkYXRhYmFzZXMuCgojIyMgQ2xvdWQgU1FMaXRlCgpBcyBhbiBhbHRlcm5hdGl2ZSB0byBpbnN0YWxsaW5nIFNRTGl0ZSBsb2NhbGx5LCB5b3UgY2FuIHVwbG9hZCBTUUxpdGUgZGF0YWJhc2UgZmlsZXMgdG8gW3NxbGl0ZW9ubGluZS5jb21dKGh0dHA6Ly9zcWxpdGVvbmxpbmUuY29tKSwgb3IsIHVzZSBbc3FsaXRlb25saW5lLmNvbV0oaHR0cDovL3NxbGl0ZW9ubGluZS5jb20pIHRvIGNyZWF0ZSBkYXRhYmFzZXMsIHJ1biBzY3JpcHRzLCBhbmQgZG93bmxvYWQgZGF0YWJhc2UgZmlsZXMuCgojIyBDcmVhdGluZyBhIE5ldyBEYXRhYmFzZQoKQ3JlYXRpbmcgYSBuZXcgZGF0YWJhc2UgaXMgU1FMaXRlIGlzIHNpbXBsZTogb3BlbiBhIGRhdGFiYXNlIGZpbGUgdGhhdCBkb2VzIG5vdCBleGlzdCBhbmQgU1FMaXRlIHdpbGwgY3JlYXRlIGEgbmV3IGRhdGFiYXNlIHdpdGggdGhhdCBmaWxlIG5hbWUuCgpbJSBzcWxpdGUzIGN1c3RvbWVyREIuc3FsaXRlZGJde3N0eWxlPSJmb250LWZhbWlseTpDb3VyaWVyIn0KClNRTGl0ZSBkYXRhYmFzZSBmaWxlcyBjYW4gaGF2ZSBhbnkgZXh0ZW5zaW9uLCBidXQgKi5zcWxpdGVkYiogYW5kICouZGIqIGFyZSBtb3N0IGNvbW1vbi4KCiMjIFdvcmtlZCBFeGFtcGxlCgpJbiB0aGUgd29ya2VkIGV4YW1wbGUgYmVsb3csIHdlIGNyZWF0ZSBhIG5ldyBkYXRhYmFzZSB1c2luZyBhIGNyZWF0aW9uIHNjcmlwdCB0aHJvdWdoIHRoZSBtYW5hZ2VtZW50IGNvbnNvbGUgb3MgU1FMaXRlLiBUaGUgc2NyaXB0IGlzIGdlbmVyaWMgYW5kIHN0YW5kYXJkIFNRTCwgc28gaXQgd2lsbCB3b3JrIGp1c3QgYXMgd2VsbCBvbiBhbnkgb3RoZXIgcmVsYXRpb25hbCBkYXRhYmFzZSwgaW5jbHVkaW5nIE15U1FMLCBPcmFjbGUsIGFuZCBTUUwgU2VydmVyLiBBZnRlciBjcmVhdGlvbiBvZiB0aGUgZGF0YWJhc2UsIHNhbXBsZSBkYXRhIGlzIGFkZGVkIHRvIHRoZSBkYXRhYmFzZSB2aWEgdGhlIHNjcmlwdCwgYWx0aG91Z2ggdGhpcyBjb3VsZCBoYXZlIGFsc28gYmVlbiBkb25lIHZpYSBpbXBvcnRzIG9mIENTViBmaWxlcy4gRmluYWxseSwgd2UgZXhlY3V0ZSBhIHNldCBvZiBxdWVyaWVzIGFnYWluc3QgdGhlIHNhbXBsZSBkYXRhIGluIHRoZSBkYXRhYmFzZS4KCiMjIyBDcmVhdGUgRGF0YWJhc2UKCkRvd25sb2FkIHRoZSBvcmdhbml6YXRpb24gZGF0YWJhc2UgY3JlYXRpb24gc2NyaXB0OiBbY3JlYXRlLW9yZ2RiLnNxbF0oY3JlYXRlLW9yZ2RiLnNxbCkuIEEgc2NyaXB0IGlzIGEgcGxhaW4gdGV4dCBmaWxlIGNvbnRhaW5pbmcgU1FMIHN0YXRlbWVudHMuCgpVc2luZyBlaXRoZXIgdGhlIGNvbW1hbmQgbGluZSB0b29scyAqc3FsaXRlMyogb3IgdGhlIFtjbG91ZCB2ZXJzaW9uIG9mIFNRTGl0ZV0oaHR0cDovL3NxbGl0ZW9ubGluZS5jb20pLCBzb3VyY2UgKHJ1bikgdGhlIHNjcmlwdCB0byBleGVjdXRlIGFsbCBvZiB0aGUgU1FMIHN0YXRlbWVudHMgaW4gdGhlIHNjcmlwdC4gVGhpcyB3aWxsIGNyZWF0ZSB0aGUgZGF0YWJhc2Ugd2l0aCBzYW1wbGUgZGF0YS4KCkluc3BlY3QgdGhlIHRhYmxlcyBpbiB0aGUgZGF0YWJhc2UgZWl0aGVyIGJ5IHN0dWR5aW5nIHRoZSBTUUwgY3JlYXRpb24gY29kZSBvciBsaXN0aW5nIHRoZSB0YWJsZXMuIEl0IGlzIGEgdXNlZnVsIHByYWN0aWNlIHRvIHZpc3VhbGl6ZSB0aGUgZGF0YWJhc2Ugc3RydWN0dXJlIGJ5IGRyYXdpbmcgYW4gRW50aXR5LVJlbGF0aW9uc2hpcCBvciBVTUwgZGlhZ3JhbS4KClRoZSB0dXRvcmlhbCBiZWxvdyB3aWxsIHNob3cgeW91IGhvdyB0byBjcmVhdGUgdGhlIGRhdGFiYXNlLCBjb25uZWN0IHRvIGl0LCBhbmQgaW5zcGVjdCB0aGUgdGFibGVzLiBXYXRjaCBpdCBvbmx5IGFmdGVyIHlvdSBhdHRlbXB0ZWQgdG8gZG8gdGhpcyB5b3Vyc2VsZi4gSXQgYXNzdW1lcyB0aGF0IHlvdSBoYXZlIHRoZSBTUUxpdGUgdG9vbHMgaW5zdGFsbGVkIGxvY2FsbHkgb24geW91ciBjb21wdXRlci4KCjxpZnJhbWUgc3JjPSJodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vNzk5OTg5OTU5P2g9MDYzNTdjODA1ZiZhbXA7dGl0bGU9MCZhbXA7YnlsaW5lPTAmYW1wO3BvcnRyYWl0PTAmYW1wO3NwZWVkPTAmYW1wO2JhZGdlPTAmYW1wO2F1dG9wYXVzZT0wJmFtcDtwbGF5ZXJfaWQ9MCZhbXA7YXBwX2lkPTU4NDc5IiB3aWR0aD0iNDgwIiBoZWlnaHQ9IjMxOCIgZnJhbWVib3JkZXI9IjEiIGFsbG93PSJhdXRvcGxheTsgZnVsbHNjcmVlbjsgcGljdHVyZS1pbi1waWN0dXJlIiBhbGxvd2Z1bGxzY3JlZW4gdGl0bGU9Ildvcmtpbmcgd2l0aCBTUUxpdGUgTWFuYWdlbWVudCBDb25zb2xlIiBkYXRhLWV4dGVybmFsPSIxIj4KCjwvaWZyYW1lPgoKIyMjIEJ1aWxkIFF1ZXJpZXMKCk9uY2UgeW91IGFyZSBmYW1pbGlhciB3aXRoIHRoZSBkYXRhYmFzZSwgdXNlIHRoZSBpbnRlcmFjdGl2ZSBjb21tYW5kIGxpbmUgdG9vbCB0byBidWlsZCBTUUwgcXVlcmllcyBmb3IgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CgojIyMjIFF1ZXJ5IDEKCipGaW5kIHRoZSBkaXN0aW5jdCBudW1iZXIgb2Ygd29ya2VycyB3aG8gd29yayBpbiB0aGUgSFIgZGVwYXJ0bWVudCBhbmQgd2hvIGVhcm4gbW9yZSB0aGFuIOKCuTIyNSwwMDAuKgoKYGBgez1odG1sfQo8cD4KICA8YSBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGhyZWY9IiNjb2xsYXBzZS1saWQtNzAtODAzLVExIiByb2xlPSJidXR0b24iIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJjb2xsYXBzZUV4YW1wbGUiPgogICAgQ2xpY2sgZm9yIFNvbHV0aW9uCiAgPC9hPgo8L3A+CjxkaXYgY2xhc3M9ImNvbGxhcHNlIiBpZD0iY29sbGFwc2UtbGlkLTcwLTgwMy1RMSI+CiAgPGRpdiBjbGFzcz0iY2FyZCBjYXJkLWJvZHkiPgogICAgPHByZT4Kc2VsZWN0IGRpc3RpbmN0IGNvdW50KCopIGFzICdOdW1Xb3JrZXJzJwogIGZyb20gV29ya2VyIGFzIHcKIHdoZXJlIHcuZGVwYXJ0bWVudCA9ICdIUicKICAgYW5kIHcuc2FsYXJ5ID4gMjUwMDAwOwogICAgPC9wcmU+CiAgPC9kaXY+CjwvZGl2PgpgYGAKIyMjIyBRdWVyeSAyCgoqRmluZCB0aGUgbGFzdCBuYW1lIGFuZCB0aXRsZSBvZiBhbGwgd29ya2VycyBhbmQgdGhlIGRlcGFydG1lbnQgdGhleSB3b3JrIGluIHdobyBlYXJuIGxlc3MgdGhhbiB0aGUgYXZlcmFnZSBzYWxhcnkuKgoKYGBgez1odG1sfQo8cD4KICA8YSBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGhyZWY9IiNjb2xsYXBzZS1saWQtNzAtODAzLVEyIiByb2xlPSJidXR0b24iIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJjb2xsYXBzZUV4YW1wbGUiPgogICAgQ2xpY2sgZm9yIFNvbHV0aW9uCiAgPC9hPgo8L3A+CjxkaXYgY2xhc3M9ImNvbGxhcHNlIiBpZD0iY29sbGFwc2UtbGlkLTcwLTgwMy1RMiI+CiAgPGRpdiBjbGFzcz0iY2FyZCBjYXJkLWJvZHkiPgogICAgPHByZT4Kc2VsZWN0IGxhc3RfbmFtZSwgd29ya2VyX3RpdGxlCiAgZnJvbSBXb3JrZXIgQVMgdyBKT0lOIFRpdGxlIEFTIHQgT04gKHcuV09SS0VSX0lEID0gdC5XT1JLRVJfUkVGX0lEKQogICBhbmQgdy5zYWxhcnkgPCAoc2VsZWN0IGF2ZyhzYWxhcnkpIGZyb20gV29ya2VyKTsKICAgIDwvcHJlPgogIDwvZGl2Pgo8L2Rpdj4KYGBgCiMjIyMgUXVlcnkgMwoKKldoYXQgaXMgdGhlIGF2ZXJhZ2Ugc2FsYXJ5IHBhaWQgZm9yIGFsbCB3b3JrZXJzIGluIGVhY2ggZGVwYXJ0bWVudD8gTGlzdCB0aGUgZGVwYXJ0bWVudCwgdGhlIGF2ZXJhZ2Ugc2FsYXJ5IGZvciB0aGUgZGVwYXJ0bWVudCwgYW5kIHRoZSBudW1iZXIgb2Ygd29ya2VycyBpbiBlYWNoIGRlcGFydG1lbnQuIE5hbWUgdGhlIGF2ZXJhZ2UgY29sdW1uICdBdmdTYWwnIGFuZCB0aGUgbnVtYmVyIG9mIHdvcmtlcnMgY29sdW1uIHRvICdOdW0nLioKCmBgYHs9aHRtbH0KPHA+CiAgPGEgY2xhc3M9ImJ0biBidG4tcHJpbWFyeSIgZGF0YS10b2dnbGU9ImNvbGxhcHNlIiBocmVmPSIjY29sbGFwc2UtbGlkLTcwLTgwMy1RMyIgcm9sZT0iYnV0dG9uIiBhcmlhLWV4cGFuZGVkPSJmYWxzZSIgYXJpYS1jb250cm9scz0iY29sbGFwc2VFeGFtcGxlIj4KICAgIENsaWNrIGZvciBTb2x1dGlvbgogIDwvYT4KPC9wPgo8ZGl2IGNsYXNzPSJjb2xsYXBzZSIgaWQ9ImNvbGxhcHNlLWxpZC03MC04MDMtUTMiPgogIDxkaXYgY2xhc3M9ImNhcmQgY2FyZC1ib2R5Ij4KICAgIDxwcmU+CnNlbGVjdCBkZXBhcnRtZW50LCBBVkcoc2FsYXJ5KSBhcyAnQXZnU2FsYXJ5JywgY291bnQoKikgYXMgJ051bVdvcmtlcnMnCiAgZnJvbSBXb3JrZXIKIGdyb3VwIGJ5IGRlcGFydG1lbnQ7CiAgICA8L3ByZT4KICA8L2Rpdj4KPC9kaXY+CmBgYAojIyMjIFF1ZXJ5IDQKCipXaGF0IGlzIHRoZSB0b3RhbCBjb21wZW5zYXRpb24gZm9yIGVhY2ggd29ya2VyIChzYWxhcnkgYW5kIGJvbnVzKSBvbiBhIHBlciBtb250aGx5IGJhc2lzPyBMaXN0IHRoZSBuYW1lIG9mIHRoZSB3b3JrZXIsIHRoZWlyIHRpdGxlLCBhbmQgdGhlIHRoZWlyIG1vbnRobHkgY29tcGVuc2F0aW9uIChhbm51YWwgY29tcGVuc2F0aW9uIGRpdmlkZWQgYnkgMTIpLiBDaGFuZ2UgdGhlIGhlYWRlciBmb3IgY29tcGVuc2F0aW9uIHRvICdNb250aGx5Q29tcCcgYW5kIHJvdW5kIGl0IHRvIHRoZSBuZWFyZXN0IHdob2xlIG51bWJlci4qCgpgYGB7PWh0bWx9CjxwPgogIDxhIGNsYXNzPSJidG4gYnRuLXByaW1hcnkiIGRhdGEtdG9nZ2xlPSJjb2xsYXBzZSIgaHJlZj0iI2NvbGxhcHNlLWxpZC03MC04MDMtUTQiIHJvbGU9ImJ1dHRvbiIgYXJpYS1leHBhbmRlZD0iZmFsc2UiIGFyaWEtY29udHJvbHM9ImNvbGxhcHNlRXhhbXBsZSI+CiAgICBDbGljayBmb3IgU29sdXRpb24KICA8L2E+CjwvcD4KPGRpdiBjbGFzcz0iY29sbGFwc2UiIGlkPSJjb2xsYXBzZS1saWQtNzAtODAzLVE0Ij4KICA8ZGl2IGNsYXNzPSJjYXJkIGNhcmQtYm9keSI+CiAgICA8cHJlPgpzZWxlY3QgbGFzdF9uYW1lLCAoKHNhbGFyeSArIGJvbnVzX2Ftb3VudCkgLyAxMikgYXMgJ01vbnRobHlDb21wJwogIGZyb20gV29ya2VyIGFzIHcgam9pbiBCb251cyBhcyBiIG9uICh3LldPUktFUl9JRCA9IGIuV09SS0VSX1JFRl9JRCkKICAgIDwvcHJlPgogIDwvZGl2Pgo8L2Rpdj4KYGBgCiMjIyMgUXVlcnkgNQoKKkxpc3QgdGhlIGZ1bGwgbmFtZXMgb2YgYWxsIHdvcmtlcnMgaW4gYWxsIGNhcGl0YWwgbGV0dGVycyB3aG8gZGlkIG5vdCBnZXQgYSBib251cy4qCgpgYGB7PWh0bWx9CjxwPgogIDxhIGNsYXNzPSJidG4gYnRuLXByaW1hcnkiIGRhdGEtdG9nZ2xlPSJjb2xsYXBzZSIgaHJlZj0iI2NvbGxhcHNlLWxpZC03MC04MDMtUTUiIHJvbGU9ImJ1dHRvbiIgYXJpYS1leHBhbmRlZD0iZmFsc2UiIGFyaWEtY29udHJvbHM9ImNvbGxhcHNlRXhhbXBsZSI+CiAgICBDbGljayBmb3IgU29sdXRpb24KICA8L2E+CjwvcD4KPGRpdiBjbGFzcz0iY29sbGFwc2UiIGlkPSJjb2xsYXBzZS1saWQtNzAtODAzLVE1Ij4KICA8ZGl2IGNsYXNzPSJjYXJkIGNhcmQtYm9keSI+CiAgICA8cHJlPgpzZWxlY3QgdXBwZXIobGFzdF9uYW1lIHx8ICIsICIgfHwgZmlyc3RfbmFtZSkgYXMgJ0Z1bGxOYW1lJwogIGZyb20gV29ya2VyCiB3aGVyZSB3b3JrZXJfaWQgbm90IGluIChzZWxlY3Qgd29ya2VyX3JlZl9pZCBmcm9tIEJvbnVzKQogb3JkZXIgYnkgbGFzdF9uYW1lOwogICAgPC9wcmU+CiAgPC9kaXY+CjwvZGl2PgpgYGAKIyMjIyBRdWVyeSA2CgoqV2hhdCBhcmUgdGhlIGZ1bGwgbmFtZXMgb2YgYWxsIHdvcmtlcnMgd2hvIGhhdmUgJ01hbmFnZXInIGluIHRoZWlyIHRpdGxlLiBEbyBub3QgImhhcmQgY29kZSIgdGhlIHRpdGxlczsgdXNlIHN0cmluZyBzZWFyY2hpbmcuKgoKYGBgez1odG1sfQo8cD4KICA8YSBjbGFzcz0iYnRuIGJ0bi1wcmltYXJ5IiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGhyZWY9IiNjb2xsYXBzZS1saWQtNzAtODAzLVE2IiByb2xlPSJidXR0b24iIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJjb2xsYXBzZUV4YW1wbGUiPgogICAgQ2xpY2sgZm9yIFNvbHV0aW9uCiAgPC9hPgo8L3A+CjxkaXYgY2xhc3M9ImNvbGxhcHNlIiBpZD0iY29sbGFwc2UtbGlkLTcwLTgwMy1RNiI+CiAgPGRpdiBjbGFzcz0iY2FyZCBjYXJkLWJvZHkiPgogICAgPHByZT4Kc2VsZWN0IHVwcGVyKGxhc3RfbmFtZSB8fCAiLCAiIHx8IGZpcnN0X25hbWUpIGFzICdGdWxsTmFtZScsIHQuV09SS0VSX1RJVExFCiAgZnJvbSBXb3JrZXIgdywgVGl0bGUgdCAKIFdIRVJFIHcuV09SS0VSX0lEID0gdC5XT1JLRVJfUkVGX0lECiAgIGFuZCB0LldPUktFUl9USVRMRSBMSUtFICclTWFuYWdlciUnOwogICAgPC9wcmU+CiAgPC9kaXY+CjwvZGl2PgpgYGAKIyMjIFR1dG9yaWFsCgo8aWZyYW1lIHNyYz0iaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tL3ZpZGVvLzgwMDUyODE1Nz9oPWUzNTk4ODUwMWYmYW1wO3RpdGxlPTAmYW1wO2J5bGluZT0wJmFtcDtwb3J0cmFpdD0wJmFtcDtzcGVlZD0wJmFtcDtiYWRnZT0wJmFtcDthdXRvcGF1c2U9MCZhbXA7cGxheWVyX2lkPTAmYW1wO2FwcF9pZD01ODQ3OSIgd2lkdGg9IjQ4MCIgaGVpZ2h0PSIzMDUiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYXV0b3BsYXk7IGZ1bGxzY3JlZW47IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuIHRpdGxlPSJTUUwgUXVlcmllczogRXhhbXBsZXMiIGRhdGEtZXh0ZXJuYWw9IjEiPgoKPC9pZnJhbWU+CgojIyBDb25jbHVzaW9uCgpNYW5hZ2VtZW50IGNvbnNvbGVzLCBhdmFpbGFibGUgZm9yIGV2ZXJ5IGRhdGFiYXNlLCBhcmUgYW4gZXNzZW50aWFsIHRvb2wgZm9yIGRhdGFiYXNlIGRldmVsb3BtZW50IGFuZCBhZG1pbmlzdHJhdGlvbi4gU29tZSBhcmUgY29tbWFuZC1saW5lIG9yaWVudGVkIGFuZCBzb21lIGhhdmUgZ3JhcGhpY2FsIHVzZXIgaW50ZXJmYWNlcy4gU29tZSBldmVuIGFsbG93IGRhdGFiYXNlIGRlc2lnbiB0aHJvdWdoIGludGVncmF0ZWQgZGlhZ3JhbW1pbmcgdG9vbHMuCgpBc2lkZSBmcm9tIGFsbG93aW5nIHVzIHRvIGNyZWF0ZSBkYXRhYmFzZXMgYW5kIHBlcmZvcm0gKmFkIGhvYyogcXVlcmllcywgdGhlIHByb3ZpZGUgYSBudW1iZXIgb2YgYWRkaXRpb25hbCBiZW5lZml0cy4KCi0gICAqKkNlbnRyYWxpemVkIGNvbnRyb2wqKjogQSBtYW5hZ2VtZW50IGNvbnNvbGUgcHJvdmlkZXMgYSBjZW50cmFsaXplZCBpbnRlcmZhY2UgZm9yIG1hbmFnaW5nIGFuZCBtb25pdG9yaW5nIGEgZGF0YWJhc2UsIGFsbG93aW5nIGFkbWluaXN0cmF0b3JzIHRvIGNvbmZpZ3VyZSBhbmQgbW9uaXRvciB0aGUgZGF0YWJhc2UgbW9yZSBlYXNpbHkgYW5kIGVmZmljaWVudGx5LgoKLSAgICoqRWZmaWNpZW50IHBlcmZvcm1hbmNlIG1vbml0b3JpbmcqKjogQSBtYW5hZ2VtZW50IGNvbnNvbGUgcHJvdmlkZXMgcmVhbC10aW1lIG1vbml0b3Jpbmcgb2YgdGhlIGRhdGFiYXNlJ3MgcGVyZm9ybWFuY2UsIGVuYWJsaW5nIGFkbWluaXN0cmF0b3JzIHRvIHF1aWNrbHkgaWRlbnRpZnkgYW5kIHRyb3VibGVzaG9vdCBwZXJmb3JtYW5jZSBpc3N1ZXMuIFRoaXMgY2FuIGhlbHAgaW1wcm92ZSB0aGUgb3ZlcmFsbCBwZXJmb3JtYW5jZSBvZiB0aGUgZGF0YWJhc2UsIHJlZHVjaW5nIGRvd250aW1lIGFuZCBpbXByb3ZpbmcgdGhlIGVuZCB1c2VyIGV4cGVyaWVuY2UuCgotICAgKipFbmhhbmNlZCBzZWN1cml0eSoqOiBBIG1hbmFnZW1lbnQgY29uc29sZSBjYW4gaGVscCB0byBlbmhhbmNlIHRoZSBzZWN1cml0eSBvZiBhIGRhdGFiYXNlIGJ5IHByb3ZpZGluZyB0b29scyB0byBtYW5hZ2UgdXNlcnMgYW5kIHBlcm1pc3Npb25zLCBzZXQgdXAgYXVkaXRpbmcsIGFuZCBtb25pdG9yIHRoZSBkYXRhYmFzZSBmb3Igc3VzcGljaW91cyBhY3Rpdml0eS4gVGhpcyBjYW4gaGVscCBwcmV2ZW50IHVuYXV0aG9yaXplZCBhY2Nlc3MgdG8gdGhlIGRhdGFiYXNlIGFuZCBwcm90ZWN0IHNlbnNpdGl2ZSBkYXRhLgoKLSAgICoqQXV0b21hdGVkIGJhY2t1cCBhbmQgcmVjb3ZlcnkqKjogTWFueSBtYW5hZ2VtZW50IGNvbnNvbGVzIGluY2x1ZGUgdG9vbHMgZm9yIGF1dG9tYXRlZCBiYWNrdXAgYW5kIHJlY292ZXJ5IG9mIHRoZSBkYXRhYmFzZSwgaGVscGluZyB0byBlbnN1cmUgZGF0YSBpcyBwcm90ZWN0ZWQgaW4gdGhlIGV2ZW50IG9mIGEgZGlzYXN0ZXIgb3Igb3RoZXIgdW5mb3Jlc2VlbiBjaXJjdW1zdGFuY2VzLgoKLSAgICoqU2ltcGxpZmllZCBhZG1pbmlzdHJhdGlvbioqOiBBIG1hbmFnZW1lbnQgY29uc29sZSBjYW4gc2ltcGxpZnkgZGF0YWJhc2UgYWRtaW5pc3RyYXRpb24gYnkgcHJvdmlkaW5nIGEgZ3JhcGhpY2FsIHVzZXIgaW50ZXJmYWNlIHRoYXQgc2ltcGxpZmllcyBjb21wbGV4IGRhdGFiYXNlIHRhc2tzLiBUaGlzIGNhbiBoZWxwIHJlZHVjZSB0aGUgbmVlZCBmb3Igc3BlY2lhbGl6ZWQgc2tpbGxzIG9yIGtub3dsZWRnZSwgbWFraW5nIGl0IGVhc2llciBmb3IgYSB3aWRlciByYW5nZSBvZiBzdGFmZiB0byBtYW5hZ2UgYW5kIG1haW50YWluIHRoZSBkYXRhYmFzZS4KCk92ZXJhbGwsIGEgbWFuYWdlbWVudCBjb25zb2xlIGZvciBhIGRhdGFiYXNlIGNhbiBoZWxwIHN0cmVhbWxpbmUgZGF0YWJhc2UgbWFuYWdlbWVudCwgZmFjaWxpdGF0ZSAqYWQgaG9jKiBxdWVyeWluZywgaW1wcm92ZSBwZXJmb3JtYW5jZSBhbmQgc2VjdXJpdHksIGFuZCBzaW1wbGlmeSBhZG1pbmlzdHJhdGlvbiwgbWFraW5nIGl0IGFuIGVzc2VudGlhbCB0b29sIGZvciBkYXRhYmFzZSBkZXZlbG9wbWVudC4KClRoaXMgbGVzc29uIHNob3dlZCBob3cgdG8gaW5zdGFsbCBhbmQgdXNlIHRoZSBtYW5hZ2VtZW50IGNvbnNvbGUgZm9yIFNRTGl0ZS4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgRmlsZXMgJiBSZXNvdXJjZXMKCmBgYHtyIHppcEZpbGVzLCBlY2hvPUZBTFNFfQp6aXBOYW1lID0gc3ByaW50ZigiTGVzc29uRmlsZXMtJXMtJXMuemlwIiwgCiAgICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LAogICAgICAgICAgICAgICAgIHBhcmFtcyRudW1iZXIpCgp0ZXh0QUxpbmsgPSBwYXN0ZTAoIkFsbCBGaWxlcyBmb3IgTGVzc29uICIsIAogICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksIi4iLHBhcmFtcyRudW1iZXIpCgojIGRvd25sb2FkRmlsZXNMaW5rKCkgaXMgaW5jbHVkZWQgZnJvbSBfaW5zZXJ0MkRCLlIKa25pdHI6OnJhd19odG1sKGRvd25sb2FkRmlsZXNMaW5rKCIuIiwgemlwTmFtZSwgdGV4dEFMaW5rKSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFJlZmVyZW5jZXMKCltDb21tYW5kIExpbmUgU2hlbGwgRm9yIFNRTGl0ZV0oaHR0cHM6Ly93d3cuc3FsaXRlLm9yZy9jbGkuaHRtbCkKCiMjIEVycmF0YQoKTm9uZSBjb2xsZWN0ZWQgeWV0LiBMZXQgdXMga25vdy4KCmBgYHs9aHRtbH0KPHNjcmlwdCBzcmM9Imh0dHBzOi8vZm9ybS5qb3Rmb3JtLmNvbS9zdGF0aWMvZmVlZGJhY2syLmpzIiB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgogIG5ldyBKb3Rmb3JtRmVlZGJhY2soewogICAgZm9ybUlkOiAiMjEyMTg3MDcyNzg0MTU3IiwKICAgIGJ1dHRvblRleHQ6ICJGZWVkYmFjayIsCiAgICBiYXNlOiAiaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLyIsCiAgICBiYWNrZ3JvdW5kOiAiI0Y1OTIwMiIsCiAgICBmb250Q29sb3I6ICIjRkZGRkZGIiwKICAgIGJ1dHRvblNpZGU6ICJsZWZ0IiwKICAgIGJ1dHRvbkFsaWduOiAiY2VudGVyIiwKICAgIHR5cGU6IGZhbHNlLAogICAgd2lkdGg6IDcwMCwKICAgIGhlaWdodDogNTAwLAogICAgaXNDYXJkRm9ybTogZmFsc2UKICB9KTsKPC9zY3JpcHQ+CmBgYApgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9fZGVwbG95S25pdC5SJykpLCBpbmNsdWRlID0gRkFMU0V9CmBgYAo=