Introduction
In this lesson, you will learn about the SQLite AUTOINCREMENT column attribute for specifying primary key values that are assigned by the database and do not have to be specified explicitly. While convenient, they can slow insertion performance. We recommend that you avoid using AUTOINCREMENT. Nevertheless, this tutorial will explain how to use the keyword.
Creating Tables
create table lessons (
lname text not null,
llength integer not null default 0
);
Let’s add a few rows of data to the table so we can see how SQLite assigns a row id.
insert into lessons values
('Intro C++', 90),
('Intro Java', 90),
('SQL Joins', 60)
Row IDs as Implicit Primary Keys
When creating a table, SQLite adds an automatic column called rowid (also accessible by the aliases _rowid_ and oid). Thus, there is no requirement to have an explicitly specified primary key column in SQLite.
Let’s select the “hidden” column rowid. Of course, we should not rely on the fact that the row id starts at 1 and the id’s are in sequence. We can, however, rely on them being unique integers. The row id is a 64-bit integer, so the maximum value is 264−1.
select rowid, lname, llength from lessons;
Table 1: 3 records
1 |
Intro C++ |
90 |
2 |
Intro Java |
90 |
3 |
SQL Joins |
60 |
To create a table without a row id added, you need to add a the WITHOUT ROWID option. If we do that, then we must specify a primary key column explicitly. Of course, there is no need to specify the primary key column as NOT NULL as that is implied.
Note that the WITHOUT ROWID option is only available in SQLite 3.8.2 or later.
create table lessons (
lid integer primary key,
lname text not null,
llength integer not null default 0
) without rowid;
Alternatively, you can specify the primary key column with the primary key constraint. This is necessary of the primary key consists of more than one column.
create table lessons (
lid integer,
lname text not null,
llength integer not null default 0,
primary key (lid)
) without rowid;
When we specify WITHOUT ROWID, then we do not have an implicit primary key through the hidden rowid column and consequently we need to assign unique primary key values when inserting rows. Primary keys are often integers but do not have to be and their values do not have to be sequential. Attempting to insert a duplicate primary key value would naturally result in the error “UNIQUE constraint failed”.
insert into lessons values
(101, 'Intro C++', 90),
(102, 'Intro Java', 90),
(605, 'SQL Joins', 60)
And here is the data:
Table 2: 3 records
101 |
Intro C++ |
90 |
102 |
Intro Java |
90 |
605 |
SQL Joins |
60 |
Automatic Primary Keys with AUTOINCREMENT
Another alternative to synthetic primary keys and row id’s is the AUTOINCREMENT attribute for primary key columns where SQLite generates a unique and increasing value for a primary key. The value is generated and SQLite only guarantees that is is larger than any prior value but does not guarantee sequentially increasing values – particularly in concurrent situations.
The table definition below specifies a primary key with an automatic primary key value.
create table lessons (
lid integer primary key autoincrement,
lname text not null,
llength integer not null default 0
);
When a primary key is auto incremented then we do not have to specify a value when inserting a new row, although we can. Note that you must specify the column names explicitly when using auto incremented primary keys, e.g., the (lname, llength) after insert into lessons and before values is essential – omitting it will result in a column mismatch error.
insert into lessons (lname, llength) values
('Intro C++', 90),
('Intro Java', 90),
('SQL Joins', 60)
Let’s retrieve the data and see the primary key values.
Table 3: 3 records
1 |
Intro C++ |
90 |
2 |
Intro Java |
90 |
3 |
SQL Joins |
60 |
Of course, you can still specify a primary key value explicitly:
insert into lessons (lid, lname, llength) values
(399, 'Intro Python', 90)
But notice the next value of the auto increment after you specified a primary key.
insert into lessons (lname, llength) values
('Intro R', 65)
The value is now incremented from the largest value (to avoid possible duplication).
Table 4: 5 records
1 |
Intro C++ |
90 |
2 |
Intro Java |
90 |
3 |
SQL Joins |
60 |
399 |
Intro Python |
90 |
400 |
Intro R |
65 |
Note that AUTOINCREMENT does not reuse values (such as when a row is deleted) and thus it is possible to eventually exceed the maximum value and get an (erroneous) “disk full” error. On the other hand, ROWID does reuse values and thus is less likely to run out of disk space.
Conclusion
Assigning primary key values using auto increment or using a row id is convenient but can result in slower performance and issues in connecting tables. While often useful, both should generally be avoided in favor of application generated primary keys.
Since row id is potentially slow in generating a new key, tables should be created without a row id and either use an application generated primary key or an auto incremented value.
Errata
None collected yet. Let us know.
LS0tDQp0aXRsZTogIlByaW1hcnkgS2V5cyB3aXRoIEFVVE9JTkNSRU1FTlQgYW5kIFJPV0lEIGluIFNRTGl0ZSINCnBhcmFtczoNCiAgY2F0ZWdvcnk6IDcwDQogIG51bWJlcjogODA5DQogIHRpbWU6IDMwDQogIGxldmVsOiBiZWdpbm5lcg0KICB0YWdzOiAic3FsaXRlLGNyZWF0ZSB0YWJsZSxhdXRvIGluY3JlbWVudCINCiAgZGVzY3JpcHRpb246ICJFeHBsYWlucyB0aGUgdXNlIGFuZCBzcGVjaWZpY2F0aW9uIG9mIGF1dG8gaW5jcmVtZW50ZWQgcHJpbWFyeQ0KICAgICAgICAgICAgICAgIGtleXMgaW4gU1FMaXRlLiINCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiINCmF1dGhvcjogIjxzbWFsbD5NYXJ0aW4gU2NoZWRsYmF1ZXI8L3NtYWxsPiINCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1Ig0KYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiDQpvdXRwdXQ6IA0KICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KLS0tDQoNCi0tLQ0KdGl0bGU6ICI8c21hbGw+YHIgcGFyYW1zJGNhdGVnb3J5YC5gciBwYXJhbXMkbnVtYmVyYDwvc21hbGw+PGJyLz48c3BhbiBzdHlsZT0nY29sb3I6ICMyRTQwNTM7IGZvbnQtc2l6ZTogMC45ZW0nPmByIHJtYXJrZG93bjo6bWV0YWRhdGEkdGl0bGVgPC9zcGFuPiINCi0tLQ0KDQpgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9faW5zZXJ0MkRCLlInKSksIGluY2x1ZGUgPSBGQUxTRX0NCmBgYA0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSB3aWxsIGxlYXJuIGFib3V0IHRoZSBTUUxpdGUgKkFVVE9JTkNSRU1FTlQqIGNvbHVtbiBhdHRyaWJ1dGUgZm9yIHNwZWNpZnlpbmcgcHJpbWFyeSBrZXkgdmFsdWVzIHRoYXQgYXJlIGFzc2lnbmVkIGJ5IHRoZSBkYXRhYmFzZSBhbmQgZG8gbm90IGhhdmUgdG8gYmUgc3BlY2lmaWVkIGV4cGxpY2l0bHkuIFdoaWxlIGNvbnZlbmllbnQsIHRoZXkgY2FuIHNsb3cgaW5zZXJ0aW9uIHBlcmZvcm1hbmNlLiBXZSByZWNvbW1lbmQgdGhhdCB5b3UgYXZvaWQgdXNpbmcgQVVUT0lOQ1JFTUVOVC4gTmV2ZXJ0aGVsZXNzLCB0aGlzIHR1dG9yaWFsIHdpbGwgZXhwbGFpbiBob3cgdG8gdXNlIHRoZSBrZXl3b3JkLg0KDQojIyBDcmVhdGluZyBUYWJsZXMNCg0KYGBge3IgY3JlYXRlREIsIGVjaG89Rn0NCiMgY2hhbmdlIHRoaXMgY29kZSB0byBjb25uZWN0IHRvIHlvdXIgc3BlY2lmaWMgZGF0YWJhc2UNCmxpYnJhcnkoUlNRTGl0ZSkNCmRiY29uIDwtIGRiQ29ubmVjdChSU1FMaXRlOjpTUUxpdGUoKSwgIjptZW1vcnk6IikNCmBgYA0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb24sIGVjaG89Rn0NCmRyb3AgdGFibGUgaWYgZXhpc3RzIGxlc3NvbnM7DQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRiY29ufQ0KY3JlYXRlIHRhYmxlIGxlc3NvbnMgKA0KICBsbmFtZSB0ZXh0IG5vdCBudWxsLA0KICBsbGVuZ3RoIGludGVnZXIgbm90IG51bGwgZGVmYXVsdCAwDQopOw0KYGBgDQoNCkxldCdzIGFkZCBhIGZldyByb3dzIG9mIGRhdGEgdG8gdGhlIHRhYmxlIHNvIHdlIGNhbiBzZWUgaG93IFNRTGl0ZSBhc3NpZ25zIGEgcm93IGlkLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQppbnNlcnQgaW50byBsZXNzb25zIHZhbHVlcw0KICAoJ0ludHJvIEMrKycsIDkwKSwNCiAgKCdJbnRybyBKYXZhJywgOTApLA0KICAoJ1NRTCBKb2lucycsIDYwKQ0KYGBgDQoNCiMjIFJvdyBJRHMgYXMgSW1wbGljaXQgUHJpbWFyeSBLZXlzDQoNCldoZW4gY3JlYXRpbmcgYSB0YWJsZSwgU1FMaXRlIGFkZHMgYW4gYXV0b21hdGljIGNvbHVtbiBjYWxsZWQgKnJvd2lkKiAoYWxzbyBhY2Nlc3NpYmxlIGJ5IHRoZSBhbGlhc2VzICpcX3Jvd2lkXF8qIGFuZCAqb2lkKikuIFRodXMsIHRoZXJlIGlzIG5vIHJlcXVpcmVtZW50IHRvIGhhdmUgYW4gZXhwbGljaXRseSBzcGVjaWZpZWQgcHJpbWFyeSBrZXkgY29sdW1uIGluIFNRTGl0ZS4NCg0KTGV0J3Mgc2VsZWN0IHRoZSAiaGlkZGVuIiBjb2x1bW4gKnJvd2lkKi4gT2YgY291cnNlLCB3ZSBzaG91bGQgbm90IHJlbHkgb24gdGhlIGZhY3QgdGhhdCB0aGUgcm93IGlkIHN0YXJ0cyBhdCAxIGFuZCB0aGUgaWQncyBhcmUgaW4gc2VxdWVuY2UuIFdlIGNhbiwgaG93ZXZlciwgcmVseSBvbiB0aGVtIGJlaW5nIHVuaXF1ZSBpbnRlZ2Vycy4gVGhlIHJvdyBpZCBpcyBhIDY0LWJpdCBpbnRlZ2VyLCBzbyB0aGUgbWF4aW11bSB2YWx1ZSBpcyAkMl57NjR9LTEkLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQpzZWxlY3Qgcm93aWQsIGxuYW1lLCBsbGVuZ3RoIGZyb20gbGVzc29uczsNCmBgYA0KDQpUbyBjcmVhdGUgYSB0YWJsZSB3aXRob3V0IGEgcm93IGlkIGFkZGVkLCB5b3UgbmVlZCB0byBhZGQgYSB0aGUgKldJVEhPVVQgUk9XSUQqIG9wdGlvbi4gSWYgd2UgZG8gdGhhdCwgdGhlbiB3ZSBtdXN0IHNwZWNpZnkgYSBwcmltYXJ5IGtleSBjb2x1bW4gZXhwbGljaXRseS4gT2YgY291cnNlLCB0aGVyZSBpcyBubyBuZWVkIHRvIHNwZWNpZnkgdGhlIHByaW1hcnkga2V5IGNvbHVtbiBhcyAqTk9UIE5VTEwqIGFzIHRoYXQgaXMgaW1wbGllZC4NCg0KTm90ZSB0aGF0IHRoZSAqV0lUSE9VVCBST1dJRCogb3B0aW9uIGlzIG9ubHkgYXZhaWxhYmxlIGluIFNRTGl0ZSAzLjguMiBvciBsYXRlci4NCg0KYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBlY2hvPUZ9DQpkcm9wIHRhYmxlIGlmIGV4aXN0cyBsZXNzb25zOw0KYGBgDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbn0NCmNyZWF0ZSB0YWJsZSBsZXNzb25zICgNCiAgbGlkIGludGVnZXIgcHJpbWFyeSBrZXksDQogIGxuYW1lIHRleHQgbm90IG51bGwsDQogIGxsZW5ndGggaW50ZWdlciBub3QgbnVsbCBkZWZhdWx0IDANCikgd2l0aG91dCByb3dpZDsNCmBgYA0KDQpBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHNwZWNpZnkgdGhlIHByaW1hcnkga2V5IGNvbHVtbiB3aXRoIHRoZSAqcHJpbWFyeSBrZXkqIGNvbnN0cmFpbnQuIFRoaXMgaXMgbmVjZXNzYXJ5IG9mIHRoZSBwcmltYXJ5IGtleSBjb25zaXN0cyBvZiBtb3JlIHRoYW4gb25lIGNvbHVtbi4NCg0KYGBge3NxbCBjb25uZWN0aW9uPWRiY29uLCBldmFsPUZ9DQpjcmVhdGUgdGFibGUgbGVzc29ucyAoDQogIGxpZCBpbnRlZ2VyLA0KICBsbmFtZSB0ZXh0IG5vdCBudWxsLA0KICBsbGVuZ3RoIGludGVnZXIgbm90IG51bGwgZGVmYXVsdCAwLA0KICBwcmltYXJ5IGtleSAobGlkKQ0KKSB3aXRob3V0IHJvd2lkOw0KYGBgDQoNCldoZW4gd2Ugc3BlY2lmeSAqV0lUSE9VVCBST1dJRCosIHRoZW4gd2UgZG8gbm90IGhhdmUgYW4gaW1wbGljaXQgcHJpbWFyeSBrZXkgdGhyb3VnaCB0aGUgaGlkZGVuICpyb3dpZCogY29sdW1uIGFuZCBjb25zZXF1ZW50bHkgd2UgbmVlZCB0byBhc3NpZ24gdW5pcXVlIHByaW1hcnkga2V5IHZhbHVlcyB3aGVuIGluc2VydGluZyByb3dzLiBQcmltYXJ5IGtleXMgYXJlIG9mdGVuIGludGVnZXJzIGJ1dCBkbyBub3QgaGF2ZSB0byBiZSBhbmQgdGhlaXIgdmFsdWVzIGRvIG5vdCBoYXZlIHRvIGJlIHNlcXVlbnRpYWwuIEF0dGVtcHRpbmcgdG8gaW5zZXJ0IGEgZHVwbGljYXRlIHByaW1hcnkga2V5IHZhbHVlIHdvdWxkIG5hdHVyYWxseSByZXN1bHQgaW4gdGhlIGVycm9yICJVTklRVUUgY29uc3RyYWludCBmYWlsZWQiLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQppbnNlcnQgaW50byBsZXNzb25zIHZhbHVlcw0KICAoMTAxLCAnSW50cm8gQysrJywgOTApLA0KICAoMTAyLCAnSW50cm8gSmF2YScsIDkwKSwNCiAgKDYwNSwgJ1NRTCBKb2lucycsIDYwKQ0KYGBgDQoNCkFuZCBoZXJlIGlzIHRoZSBkYXRhOg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQpzZWxlY3QgKiBmcm9tIGxlc3NvbnM7DQpgYGANCg0KIyMgQXV0b21hdGljIFByaW1hcnkgS2V5cyB3aXRoIEFVVE9JTkNSRU1FTlQNCg0KQW5vdGhlciBhbHRlcm5hdGl2ZSB0byBzeW50aGV0aWMgcHJpbWFyeSBrZXlzIGFuZCByb3cgaWQncyBpcyB0aGUgKkFVVE9JTkNSRU1FTlQqIGF0dHJpYnV0ZSBmb3IgcHJpbWFyeSBrZXkgY29sdW1ucyB3aGVyZSBTUUxpdGUgZ2VuZXJhdGVzIGEgdW5pcXVlIGFuZCBpbmNyZWFzaW5nIHZhbHVlIGZvciBhIHByaW1hcnkga2V5LiBUaGUgdmFsdWUgaXMgZ2VuZXJhdGVkIGFuZCBTUUxpdGUgb25seSBndWFyYW50ZWVzIHRoYXQgaXMgaXMgbGFyZ2VyIHRoYW4gYW55IHByaW9yIHZhbHVlIGJ1dCBkb2VzIG5vdCBndWFyYW50ZWUgc2VxdWVudGlhbGx5IGluY3JlYXNpbmcgdmFsdWVzIC0tIHBhcnRpY3VsYXJseSBpbiBjb25jdXJyZW50IHNpdHVhdGlvbnMuDQoNClRoZSB0YWJsZSBkZWZpbml0aW9uIGJlbG93IHNwZWNpZmllcyBhIHByaW1hcnkga2V5IHdpdGggYW4gYXV0b21hdGljIHByaW1hcnkga2V5IHZhbHVlLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb24sIGVjaG89Rn0NCmRyb3AgdGFibGUgaWYgZXhpc3RzIGxlc3NvbnM7DQpgYGANCg0KYGBge3NxbCBjb25uZWN0aW9uPWRiY29ufQ0KY3JlYXRlIHRhYmxlIGxlc3NvbnMgKA0KICBsaWQgaW50ZWdlciBwcmltYXJ5IGtleSBhdXRvaW5jcmVtZW50LA0KICBsbmFtZSB0ZXh0IG5vdCBudWxsLA0KICBsbGVuZ3RoIGludGVnZXIgbm90IG51bGwgZGVmYXVsdCAwDQopOw0KYGBgDQoNCldoZW4gYSBwcmltYXJ5IGtleSBpcyBhdXRvIGluY3JlbWVudGVkIHRoZW4gd2UgZG8gbm90IGhhdmUgdG8gc3BlY2lmeSBhIHZhbHVlIHdoZW4gaW5zZXJ0aW5nIGEgbmV3IHJvdywgYWx0aG91Z2ggd2UgY2FuLiBOb3RlIHRoYXQgeW91IG11c3Qgc3BlY2lmeSB0aGUgY29sdW1uIG5hbWVzIGV4cGxpY2l0bHkgd2hlbiB1c2luZyBhdXRvIGluY3JlbWVudGVkIHByaW1hcnkga2V5cywgZS5nLiwgdGhlICoobG5hbWUsIGxsZW5ndGgpKiBhZnRlciAqaW5zZXJ0IGludG8gbGVzc29ucyogYW5kIGJlZm9yZSAqdmFsdWVzKiBpcyBlc3NlbnRpYWwgLS0gb21pdHRpbmcgaXQgd2lsbCByZXN1bHQgaW4gYSBjb2x1bW4gbWlzbWF0Y2ggZXJyb3IuDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbn0NCmluc2VydCBpbnRvIGxlc3NvbnMgKGxuYW1lLCBsbGVuZ3RoKSB2YWx1ZXMgDQogICgnSW50cm8gQysrJywgOTApLA0KICAoJ0ludHJvIEphdmEnLCA5MCksDQogICgnU1FMIEpvaW5zJywgNjApDQpgYGANCg0KTGV0J3MgcmV0cmlldmUgdGhlIGRhdGEgYW5kIHNlZSB0aGUgcHJpbWFyeSBrZXkgdmFsdWVzLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQpzZWxlY3QgKiBmcm9tIGxlc3NvbnM7DQpgYGANCg0KT2YgY291cnNlLCB5b3UgY2FuIHN0aWxsIHNwZWNpZnkgYSBwcmltYXJ5IGtleSB2YWx1ZSBleHBsaWNpdGx5Og0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQppbnNlcnQgaW50byBsZXNzb25zIChsaWQsIGxuYW1lLCBsbGVuZ3RoKSB2YWx1ZXMgDQogICgzOTksICdJbnRybyBQeXRob24nLCA5MCkNCmBgYA0KDQpCdXQgbm90aWNlIHRoZSBuZXh0IHZhbHVlIG9mIHRoZSBhdXRvIGluY3JlbWVudCBhZnRlciB5b3Ugc3BlY2lmaWVkIGEgcHJpbWFyeSBrZXkuDQoNCmBgYHtzcWwgY29ubmVjdGlvbj1kYmNvbn0NCmluc2VydCBpbnRvIGxlc3NvbnMgKGxuYW1lLCBsbGVuZ3RoKSB2YWx1ZXMgDQogICgnSW50cm8gUicsIDY1KQ0KYGBgDQoNClRoZSB2YWx1ZSBpcyBub3cgaW5jcmVtZW50ZWQgZnJvbSB0aGUgbGFyZ2VzdCB2YWx1ZSAodG8gYXZvaWQgcG9zc2libGUgZHVwbGljYXRpb24pLg0KDQpgYGB7c3FsIGNvbm5lY3Rpb249ZGJjb259DQpzZWxlY3QgKiBmcm9tIGxlc3NvbnM7DQpgYGANCg0KTm90ZSB0aGF0ICpBVVRPSU5DUkVNRU5UKiBkb2VzIG5vdCByZXVzZSB2YWx1ZXMgKHN1Y2ggYXMgd2hlbiBhIHJvdyBpcyBkZWxldGVkKSBhbmQgdGh1cyBpdCBpcyBwb3NzaWJsZSB0byBldmVudHVhbGx5IGV4Y2VlZCB0aGUgbWF4aW11bSB2YWx1ZSBhbmQgZ2V0IGFuIChlcnJvbmVvdXMpICJkaXNrIGZ1bGwiIGVycm9yLiBPbiB0aGUgb3RoZXIgaGFuZCwgKlJPV0lEKiBkb2VzIHJldXNlIHZhbHVlcyBhbmQgdGh1cyBpcyBsZXNzIGxpa2VseSB0byBydW4gb3V0IG9mIGRpc2sgc3BhY2UuDQoNCiMjIENvbmNsdXNpb24NCg0KQXNzaWduaW5nIHByaW1hcnkga2V5IHZhbHVlcyB1c2luZyBhdXRvIGluY3JlbWVudCBvciB1c2luZyBhIHJvdyBpZCBpcyBjb252ZW5pZW50IGJ1dCBjYW4gcmVzdWx0IGluIHNsb3dlciBwZXJmb3JtYW5jZSBhbmQgaXNzdWVzIGluIGNvbm5lY3RpbmcgdGFibGVzLiBXaGlsZSBvZnRlbiB1c2VmdWwsIGJvdGggc2hvdWxkIGdlbmVyYWxseSBiZSBhdm9pZGVkIGluIGZhdm9yIG9mIGFwcGxpY2F0aW9uIGdlbmVyYXRlZCBwcmltYXJ5IGtleXMuDQoNClNpbmNlIHJvdyBpZCBpcyBwb3RlbnRpYWxseSBzbG93IGluIGdlbmVyYXRpbmcgYSBuZXcga2V5LCB0YWJsZXMgc2hvdWxkIGJlIGNyZWF0ZWQgd2l0aG91dCBhIHJvdyBpZCBhbmQgZWl0aGVyIHVzZSBhbiBhcHBsaWNhdGlvbiBnZW5lcmF0ZWQgcHJpbWFyeSBrZXkgb3IgYW4gYXV0byBpbmNyZW1lbnRlZCB2YWx1ZS4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIEZpbGVzICYgUmVzb3VyY2VzDQoNCmBgYHtyIHppcEZpbGVzLCBlY2hvPUZBTFNFfQ0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIA0KICAgICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksDQogICAgICAgICAgICAgICAgIHBhcmFtcyRudW1iZXIpDQoNCnRleHRBTGluayA9IHBhc3RlMCgiQWxsIEZpbGVzIGZvciBMZXNzb24gIiwgDQogICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksIi4iLHBhcmFtcyRudW1iZXIpDQoNCiMgZG93bmxvYWRGaWxlc0xpbmsoKSBpcyBpbmNsdWRlZCBmcm9tIF9pbnNlcnQyREIuUg0Ka25pdHI6OnJhd19odG1sKGRvd25sb2FkRmlsZXNMaW5rKCIuIiwgemlwTmFtZSwgdGV4dEFMaW5rKSkNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgUmVmZXJlbmNlcw0KDQpbU1FMaXRlIEFVVE9JTkNSRU1FTlQuIFNRTGl0ZSBUdXRvcmlhbC5dKGh0dHBzOi8vd3d3LnNxbGl0ZXR1dG9yaWFsLm5ldC9zcWxpdGUtYXV0b2luY3JlbWVudC8pDQoNCltTUUxpdGUgQVVUT0lOQ1JFTUVOVC4gU1FMaXRlIERvY3VtZW50YXRpb24uXShodHRwczovL3d3dy5zcWxpdGUub3JnL2F1dG9pbmMuaHRtbCkNCg0KIyMgRXJyYXRhDQoNCk5vbmUgY29sbGVjdGVkIHlldC4gTGV0IHVzIGtub3cuDQoNCmBgYHs9aHRtbH0NCjxzY3JpcHQgc3JjPSJodHRwczovL2Zvcm0uam90Zm9ybS5jb20vc3RhdGljL2ZlZWRiYWNrMi5qcyIgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4NCiAgbmV3IEpvdGZvcm1GZWVkYmFjayh7DQogICAgZm9ybUlkOiAiMjEyMTg3MDcyNzg0MTU3IiwNCiAgICBidXR0b25UZXh0OiAiRmVlZGJhY2siLA0KICAgIGJhc2U6ICJodHRwczovL2Zvcm0uam90Zm9ybS5jb20vIiwNCiAgICBiYWNrZ3JvdW5kOiAiI0Y1OTIwMiIsDQogICAgZm9udENvbG9yOiAiI0ZGRkZGRiIsDQogICAgYnV0dG9uU2lkZTogImxlZnQiLA0KICAgIGJ1dHRvbkFsaWduOiAiY2VudGVyIiwNCiAgICB0eXBlOiBmYWxzZSwNCiAgICB3aWR0aDogNzAwLA0KICAgIGhlaWdodDogNTAwLA0KICAgIGlzQ2FyZEZvcm06IGZhbHNlDQogIH0pOw0KPC9zY3JpcHQ+DQpgYGANCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19kZXBsb3lLbml0LlInKSksIGluY2x1ZGUgPSBGQUxTRX0NCmBgYA0K