Objectives
Upon completion of this lesson, you will be able to:
- explain the need for cursors
- know when to use cursors
- use cursors in MySQL stored procedures
Overview
In relational databases, a cursor is a programming construct that allows a developer to traverse and manipulate the result set returned by a SQL SELECT query. It is typically used in stored procedures or other database programming scenarios where the developer needs to work with individual rows of a result set one at a time.
Cursors can be useful in situations where the data needs to be processed row-by-row and where it is not practical or efficient to load the entire result set into memory at once. For example, if a stored procedure needs to perform some calculations on each row of a large result set, using a cursor can help to conserve memory and reduce the amount of processing required at any given time.
However, it is important to note that cursors can also be a source of performance problems if not used carefully, since they can require additional overhead and may lead to locking and blocking issues in concurrent database access situations if not properly managed. Therefore, it is generally recommended to use cursors only when necessary and to consider alternative approaches, such as in-memory traversal, whenever possible.
Cursors in MySQL
To create and use a cursor in MySQL, follow these steps:
- Declare the cursor: To declare a cursor, you can use the DECLARE statement followed by a unique name for the cursor and the SELECT statement that defines the result set. For example:
DECLARE my_cursor CURSOR FOR SELECT * FROM my_table;
- Open the cursor: To open the cursor, you can use the OPEN statement followed by the cursor name. For example:
- Fetch the rows: To fetch the rows one by one, you can use the FETCH statement followed by the cursor name and the variable names that will hold the values of the columns in each row. For example:
FETCH my_cursor INTO var1, var2, var3;
You can use a loop to fetch all the rows one by one until there are no more rows to fetch.
- Close the cursor: When you are done fetching the rows, you should close the cursor using the CLOSE statement followed by the cursor name. For example:
The cursors provided by MySQL are embedded cursors and are subject to some restrictions and have certain characteristics. Specifically, they are:
READ ONLY, i.e., is not possible to update any table through a cursor
Non-Scrollable, i.e., with cursors you can only retrieve records from a table in one direction
Asensitive, i.e., cursors are insensitive to the changes that are made in the table and any modifications made in the table are not reflected in the cursor; that implies that a cursor moving over all the records in a table would not see any changes made to the table after the cursor is created
Sample Database
The SQL statement below creates the customers and export tables used in the examples.
Using Cursors from Stored Procedures
Cursors are most commonly employed within stored procedures. The example below defines a simple stored procedure that uses a cursor:
CREATE PROCEDURE ExportDataProc()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE custID INTEGER;
DECLARE custProf, custOrigin VARCHAR(64);
DECLARE aCursor CURSOR FOR SELECT cid, profession, country FROM customers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN aCursor;
label: LOOP
FETCH aCursor INTO custID, custProf, custOrigin;
INSERT INTO export VALUES(custID, custProf, custOrigin);
IF done = 1 THEN LEAVE label;
END IF;
END LOOP;
CLOSE aCursor;
END
To demonstrate the the cursor and stored procedure work, we will call the procedure from R:
status <- dbExecute(conn = con,
"CALL ExportDataProc();")
Summary
Cursors in relational databases allow a developer to linearly traverse the result set returned by a SQL SELECT query. They are useful when data needs to be processed row-by-row, and loading the entire result set into memory at once is not appropriate.
MySQL cursors are read-only, non-scrollable, and insensitive to changes made to the table while the cursor is active.
Developers should use cursors only when necessary and consider alternative approaches such as in-memory traversal.
Errata
None collected yet. Let us know.
LS0tCnRpdGxlOiAiRWZmaWNpZW50IERhdGEgUmV0cmlldmFsIHdpdGggQ3Vyc29ycyIKcGFyYW1zOgogIGNhdGVnb3J5OiA3MAogIG51bWJlcjogNjA1CiAgdGltZTogMzAKICBsZXZlbDogYmVnaW5uZXIKICB0YWdzOiAiTXlTUUwsY3Vyc29ycyxTUUwiCiAgZGVzY3JpcHRpb246ICJUaGlzIGxlc3NvbiBleHBsYWlucyBob3cgdG8gbGV2ZXJhZ2UgY3Vyc29ycyBmb3IKICAgICAgICAgICAgICAgIGVmZmljaWVudCByZXRyaWV2YWwgb2YgbGFyZ2UgcmVzdWx0IHNldHMuIFVzZXMKICAgICAgICAgICAgICAgIHByb2dyYW1taW5nIGV4YW1wbGVzIGluIE15U1FMLiIKZGF0ZTogIjxzbWFsbD5gciBTeXMuRGF0ZSgpYDwvc21hbGw+IgphdXRob3I6ICI8c21hbGw+TWFydGluIFNjaGVkbGJhdWVyPC9zbWFsbD4iCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1IgphZmZpbGl0YXRpb246ICJOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKLS0tCnRpdGxlOiAiPHNtYWxsPmByIHBhcmFtcyRjYXRlZ29yeWAuYHIgcGFyYW1zJG51bWJlcmA8L3NtYWxsPjxici8+PHNwYW4gc3R5bGU9J2NvbG9yOiAjMkU0MDUzOyBmb250LXNpemU6IDAuOWVtJz5gciBybWFya2Rvd246Om1ldGFkYXRhJHRpdGxlYDwvc3Bhbj4iCi0tLQoKYGBge3IgY29kZT14ZnVuOjpyZWFkX3V0ZjgocGFzdGUwKGhlcmU6OmhlcmUoKSwnL1IvX2luc2VydDJEQi5SJykpLCBpbmNsdWRlID0gRkFMU0V9CmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBPYmplY3RpdmVzCgpVcG9uIGNvbXBsZXRpb24gb2YgdGhpcyBsZXNzb24sIHlvdSB3aWxsIGJlIGFibGUgdG86CgotICAgZXhwbGFpbiB0aGUgbmVlZCBmb3IgY3Vyc29ycwotICAga25vdyB3aGVuIHRvIHVzZSBjdXJzb3JzCi0gICB1c2UgY3Vyc29ycyBpbiBNeVNRTCBzdG9yZWQgcHJvY2VkdXJlcwoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBPdmVydmlldwoKSW4gcmVsYXRpb25hbCBkYXRhYmFzZXMsIGEgKmN1cnNvciogaXMgYSBwcm9ncmFtbWluZyBjb25zdHJ1Y3QgdGhhdCBhbGxvd3MgYSBkZXZlbG9wZXIgdG8gdHJhdmVyc2UgYW5kIG1hbmlwdWxhdGUgdGhlIHJlc3VsdCBzZXQgcmV0dXJuZWQgYnkgYSBTUUwgU0VMRUNUIHF1ZXJ5LiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBzdG9yZWQgcHJvY2VkdXJlcyBvciBvdGhlciBkYXRhYmFzZSBwcm9ncmFtbWluZyBzY2VuYXJpb3Mgd2hlcmUgdGhlIGRldmVsb3BlciBuZWVkcyB0byB3b3JrIHdpdGggaW5kaXZpZHVhbCByb3dzIG9mIGEgcmVzdWx0IHNldCBvbmUgYXQgYSB0aW1lLgoKQ3Vyc29ycyBjYW4gYmUgdXNlZnVsIGluIHNpdHVhdGlvbnMgd2hlcmUgdGhlIGRhdGEgbmVlZHMgdG8gYmUgcHJvY2Vzc2VkIHJvdy1ieS1yb3cgYW5kIHdoZXJlIGl0IGlzIG5vdCBwcmFjdGljYWwgb3IgZWZmaWNpZW50IHRvIGxvYWQgdGhlIGVudGlyZSByZXN1bHQgc2V0IGludG8gbWVtb3J5IGF0IG9uY2UuIEZvciBleGFtcGxlLCBpZiBhIHN0b3JlZCBwcm9jZWR1cmUgbmVlZHMgdG8gcGVyZm9ybSBzb21lIGNhbGN1bGF0aW9ucyBvbiBlYWNoIHJvdyBvZiBhIGxhcmdlIHJlc3VsdCBzZXQsIHVzaW5nIGEgY3Vyc29yIGNhbiBoZWxwIHRvIGNvbnNlcnZlIG1lbW9yeSBhbmQgcmVkdWNlIHRoZSBhbW91bnQgb2YgcHJvY2Vzc2luZyByZXF1aXJlZCBhdCBhbnkgZ2l2ZW4gdGltZS4KCkhvd2V2ZXIsIGl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgY3Vyc29ycyBjYW4gYWxzbyBiZSBhIHNvdXJjZSBvZiBwZXJmb3JtYW5jZSBwcm9ibGVtcyBpZiBub3QgdXNlZCBjYXJlZnVsbHksIHNpbmNlIHRoZXkgY2FuIHJlcXVpcmUgYWRkaXRpb25hbCBvdmVyaGVhZCBhbmQgbWF5IGxlYWQgdG8gbG9ja2luZyBhbmQgYmxvY2tpbmcgaXNzdWVzIGluIGNvbmN1cnJlbnQgZGF0YWJhc2UgYWNjZXNzIHNpdHVhdGlvbnMgaWYgbm90IHByb3Blcmx5IG1hbmFnZWQuIFRoZXJlZm9yZSwgaXQgaXMgZ2VuZXJhbGx5IHJlY29tbWVuZGVkIHRvIHVzZSBjdXJzb3JzIG9ubHkgd2hlbiBuZWNlc3NhcnkgYW5kIHRvIGNvbnNpZGVyIGFsdGVybmF0aXZlIGFwcHJvYWNoZXMsIHN1Y2ggYXMgaW4tbWVtb3J5IHRyYXZlcnNhbCwgd2hlbmV2ZXIgcG9zc2libGUuCgojIyBDdXJzb3JzIGluIE15U1FMCgpUbyBjcmVhdGUgYW5kIHVzZSBhIGN1cnNvciBpbiBNeVNRTCwgZm9sbG93IHRoZXNlIHN0ZXBzOgoKMS4gICoqRGVjbGFyZSB0aGUgY3Vyc29yKio6IFRvIGRlY2xhcmUgYSBjdXJzb3IsIHlvdSBjYW4gdXNlIHRoZSAqREVDTEFSRSogc3RhdGVtZW50IGZvbGxvd2VkIGJ5IGEgdW5pcXVlIG5hbWUgZm9yIHRoZSBjdXJzb3IgYW5kIHRoZSAqU0VMRUNUKiBzdGF0ZW1lbnQgdGhhdCBkZWZpbmVzIHRoZSByZXN1bHQgc2V0LiBGb3IgZXhhbXBsZToKCmBgYCBzcWwKREVDTEFSRSBteV9jdXJzb3IgQ1VSU09SIEZPUiBTRUxFQ1QgKiBGUk9NIG15X3RhYmxlOwpgYGAKCjIuICAqKk9wZW4gdGhlIGN1cnNvcioqOiBUbyBvcGVuIHRoZSBjdXJzb3IsIHlvdSBjYW4gdXNlIHRoZSAqT1BFTiogc3RhdGVtZW50IGZvbGxvd2VkIGJ5IHRoZSBjdXJzb3IgbmFtZS4gRm9yIGV4YW1wbGU6CgpgYGAgc3FsCk9QRU4gbXlfY3Vyc29yOwpgYGAKCjMuICAqKkZldGNoIHRoZSByb3dzKio6IFRvIGZldGNoIHRoZSByb3dzIG9uZSBieSBvbmUsIHlvdSBjYW4gdXNlIHRoZSAqRkVUQ0gqIHN0YXRlbWVudCBmb2xsb3dlZCBieSB0aGUgY3Vyc29yIG5hbWUgYW5kIHRoZSB2YXJpYWJsZSBuYW1lcyB0aGF0IHdpbGwgaG9sZCB0aGUgdmFsdWVzIG9mIHRoZSBjb2x1bW5zIGluIGVhY2ggcm93LiBGb3IgZXhhbXBsZToKCmBgYCBzcWwKRkVUQ0ggbXlfY3Vyc29yIElOVE8gdmFyMSwgdmFyMiwgdmFyMzsKYGBgCgpZb3UgY2FuIHVzZSBhIGxvb3AgdG8gZmV0Y2ggYWxsIHRoZSByb3dzIG9uZSBieSBvbmUgdW50aWwgdGhlcmUgYXJlIG5vIG1vcmUgcm93cyB0byBmZXRjaC4KCjQuICAqKkNsb3NlIHRoZSBjdXJzb3IqKjogV2hlbiB5b3UgYXJlIGRvbmUgZmV0Y2hpbmcgdGhlIHJvd3MsIHlvdSBzaG91bGQgY2xvc2UgdGhlIGN1cnNvciB1c2luZyB0aGUgKkNMT1NFKiBzdGF0ZW1lbnQgZm9sbG93ZWQgYnkgdGhlIGN1cnNvciBuYW1lLiBGb3IgZXhhbXBsZToKCmBgYCBzcWwKQ0xPU0UgbXlfY3Vyc29yOwpgYGAKClRoZSBjdXJzb3JzIHByb3ZpZGVkIGJ5IE15U1FMIGFyZSBlbWJlZGRlZCBjdXJzb3JzIGFuZCBhcmUgc3ViamVjdCB0byBzb21lIHJlc3RyaWN0aW9ucyBhbmQgaGF2ZSBjZXJ0YWluIGNoYXJhY3RlcmlzdGljcy4gU3BlY2lmaWNhbGx5LCB0aGV5IGFyZToKCioqUkVBRCBPTkxZKiosICppLmUuKiwgaXMgbm90IHBvc3NpYmxlIHRvIHVwZGF0ZSBhbnkgdGFibGUgdGhyb3VnaCBhIGN1cnNvcgoKKipOb24tU2Nyb2xsYWJsZSoqLCAqaS5lLiosIHdpdGggY3Vyc29ycyB5b3UgY2FuIG9ubHkgcmV0cmlldmUgcmVjb3JkcyBmcm9tIGEgdGFibGUgaW4gb25lIGRpcmVjdGlvbgoKKipBc2Vuc2l0aXZlKiosICppLmUuKiwgY3Vyc29ycyBhcmUgaW5zZW5zaXRpdmUgdG8gdGhlIGNoYW5nZXMgdGhhdCBhcmUgbWFkZSBpbiB0aGUgdGFibGUgYW5kIGFueSBtb2RpZmljYXRpb25zIG1hZGUgaW4gdGhlIHRhYmxlIGFyZSBub3QgcmVmbGVjdGVkIGluIHRoZSBjdXJzb3I7IHRoYXQgaW1wbGllcyB0aGF0IGEgY3Vyc29yIG1vdmluZyBvdmVyIGFsbCB0aGUgcmVjb3JkcyBpbiBhIHRhYmxlIHdvdWxkIG5vdCBzZWUgYW55IGNoYW5nZXMgbWFkZSB0byB0aGUgdGFibGUgYWZ0ZXIgdGhlIGN1cnNvciBpcyBjcmVhdGVkCgojIyMgU2FtcGxlIERhdGFiYXNlCgpgYGB7ciBjb25uZWN0MmRiNGZyZWUsIGV2YWw9VCwgZWNobz1GLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KbGlicmFyeShSTXlTUUwpCgojIE15U1FMIERhdGFiYXNlIENvbm5lY3Rpb24gU2V0dGluZ3MKZGJfdXNlciA8LSAnY3M1MjAwJyAKZGJfcGFzc3dvcmQgPC0gJ2tob3VyIzIwMjEnCmRiX25hbWUgPC0gJ2NzNTIwMGRiMScKZGJfdGFibGUgPC0gJ2NvdXJzZXMnCmRiX2hvc3QgPC0gJ2RiNGZyZWUubmV0JyAjIEhvc3QgODUuMTAuMjA1LjE3MwpkYl9wb3J0IDwtIDMzMDYKCiMgQ29ubmVjdCB0byBNeVNRTCBEYXRhYmFzZQpjb24gPC0gIGRiQ29ubmVjdChNeVNRTCgpLCB1c2VyID0gZGJfdXNlciwgcGFzc3dvcmQgPSBkYl9wYXNzd29yZCwKICAgICAgICAgICAgICAgICAgZGJuYW1lID0gZGJfbmFtZSwgaG9zdCA9IGRiX2hvc3QsIHBvcnQgPSBkYl9wb3J0KQoKYGBgCgpUaGUgU1FMIHN0YXRlbWVudCBiZWxvdyBjcmVhdGVzIHRoZSAqY3VzdG9tZXJzKiBhbmQgKmV4cG9ydCogdGFibGVzIHVzZWQgaW4gdGhlIGV4YW1wbGVzLgoKYGBge3NxbCBkcm9wQ3VzdG9tZXJzVGFibGUsIGNvbm5lY3Rpb249Y29uLCBpbmNsdWRlPUYsIGVjaG89RiwgZXZhbD1GfQpEUk9QIFRBQkxFIElGIEVYSVNUUyBjdXN0b21lcnM7CmBgYAoKYGBge3NxbCBkcm9wRXhwb3J0VGFibGUsIGNvbm5lY3Rpb249Y29uLCBpbmNsdWRlPUYsIGVjaG89RiwgZXZhbD1GfQpEUk9QIFRBQkxFIElGIEVYSVNUUyBleHBvcnQ7CmBgYAoKYGBge3NxbCBjcmVhdGVUYWJsZSwgY29ubmVjdGlvbj1jb24sIGluY2x1ZGU9RiwgZWNobz1ULCBldmFsPUZ9CkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIGN1c3RvbWVycyAKKAogIGNpZCBJTlRFR0VSIFBSSU1BUlkgS0VZLAogIG5hbWUgVEVYVCBOT1QgTlVMTCwKICBhZ2UgSU5URUdFUiBOT1QgTlVMTCwKICBjb3VudHJ5IFRFWFQgTk9UIE5VTEwsCiAgcHJvZmVzc2lvbiBURVhUIE5PVCBOVUxMCikKYGBgCgpgYGB7c3FsIGNyZWF0ZVRhYmxlMiwgY29ubmVjdGlvbj1jb24sIGluY2x1ZGU9RiwgZWNobz1ULCBldmFsPUZ9CkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIGV4cG9ydCAKKAogIG5hbWUgVEVYVCBOT1QgTlVMTCwKICBqb2IgVEVYVCBOT1QgTlVMTCwKICByZWdpb24gVEVYVCBOT1QgTlVMTAopCmBgYAoKYGBge3IgYWRkQ1NWMkRCLCBldmFsPUYsIGVjaG89Rn0KZGJXcml0ZVRhYmxlKGNvbiwgCiAgICAgICAgICAgICBuYW1lPSJjdXN0b21lcnMiLCAKICAgICAgICAgICAgIHZhbHVlPSJjdXN0b21lcnMuY3N2IiwgCiAgICAgICAgICAgICByb3cubmFtZXM9RkFMU0UsIAogICAgICAgICAgICAgaGVhZGVyPVRSVUUsIAogICAgICAgICAgICAgc2VwID0gIiwiLCAKICAgICAgICAgICAgIG92ZXJ3cml0ZSA9IFRSVUUpCmBgYAoKYGBge3IgbG9hZERCLCBlY2hvPUYsIGV2YWw9Rn0KZGYgPC0gcmVhZC5jc3YoZmlsZSA9ICJjdXN0b21lcnMuY3N2IiwKICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgpmb3IgKGkgaW4gMToxMDAwKSB7CiAgciA8LSBkZltpLF0KICAKICBzcWwgPC0gcGFzdGUwKCJJTlNFUlQgSU5UTyBjdXN0b21lcnMgVkFMVUVTICgiLAogICAgICAgICAgICAgICAgICAgciRjaWQsICIsIiwKICAgICAgICAgICAgICAgICAgICInIiwgciRuYW1lLCAiJywiLAogICAgICAgICAgICAgICAgICAgciRhZ2UsICIsIiwKICAgICAgICAgICAgICAgICAgICInIiwgciRjb3VudHJ5LCAiJywiLAogICAgICAgICAgICAgICAgICAgIiciLCByJHByb2Zlc3Npb24sICInKSIpCiAgZGJTZW5kU3RhdGVtZW50KGNvbm4gPSBjb24sIAogICAgICAgICAgICAgICAgICBzdGF0ZW1lbnQgPSBzcWwpCn0KYGBgCgpgYGB7c3FsIGNvbm5lY3Rpb249Y29uLCBpbmNsdWRlPUYsIGVjaG89RiwgZXZhbD1GfQpzZWxlY3QgKiBmcm9tIGN1c3RvbWVycyBsaW1pdCA2OwpgYGAKCmBgYHtzcWwgY29ubmVjdGlvbj1jb24sIGluY2x1ZGU9RiwgZWNobz1GLCBldmFsPUZ9CnNlbGVjdCBjb3VudCgqKSBmcm9tIGN1c3RvbWVyczsKYGBgCgpgYGB7c3FsIGNvbm5lY3Rpb249Y29uLCBpbmNsdWRlPUYsIGVjaG89RiwgZXZhbD1GfQpzZWxlY3QgKiBmcm9tIGV4cG9ydCBsaW1pdCA2OwpgYGAKCiMjIyBVc2luZyBDdXJzb3JzIGZyb20gU3RvcmVkIFByb2NlZHVyZXMKCkN1cnNvcnMgYXJlIG1vc3QgY29tbW9ubHkgZW1wbG95ZWQgd2l0aGluIHN0b3JlZCBwcm9jZWR1cmVzLiBUaGUgZXhhbXBsZSBiZWxvdyBkZWZpbmVzIGEgc2ltcGxlIHN0b3JlZCBwcm9jZWR1cmUgdGhhdCB1c2VzIGEgY3Vyc29yOgoKYGBge3NxbCBkZWZTUCwgY29ubmVjdGlvbj1jb24sZXZhbD1GfQpDUkVBVEUgUFJPQ0VEVVJFIEV4cG9ydERhdGFQcm9jKCkKICAgQkVHSU4KICAgICAgREVDTEFSRSBkb25lIElOVCBERUZBVUxUIDA7CiAgICAgIERFQ0xBUkUgY3VzdElEIElOVEVHRVI7CiAgICAgIERFQ0xBUkUgY3VzdFByb2YsIGN1c3RPcmlnaW4gVkFSQ0hBUig2NCk7CiAgICAgIERFQ0xBUkUgYUN1cnNvciBDVVJTT1IgRk9SIFNFTEVDVCBjaWQsIHByb2Zlc3Npb24sIGNvdW50cnkgRlJPTSBjdXN0b21lcnM7CiAgICAgIERFQ0xBUkUgQ09OVElOVUUgSEFORExFUiBGT1IgTk9UIEZPVU5EIFNFVCBkb25lID0gMTsKICAgICAgT1BFTiBhQ3Vyc29yOwogICAgICBsYWJlbDogTE9PUAogICAgICBGRVRDSCBhQ3Vyc29yIElOVE8gY3VzdElELCBjdXN0UHJvZiwgY3VzdE9yaWdpbjsKICAgICAgSU5TRVJUIElOVE8gZXhwb3J0IFZBTFVFUyhjdXN0SUQsIGN1c3RQcm9mLCBjdXN0T3JpZ2luKTsKICAgICAgSUYgZG9uZSA9IDEgVEhFTiBMRUFWRSBsYWJlbDsKICAgICAgRU5EIElGOwogICAgICBFTkQgTE9PUDsKICAgICAgQ0xPU0UgYUN1cnNvcjsKICAgRU5ECmBgYAoKVG8gZGVtb25zdHJhdGUgdGhlIHRoZSBjdXJzb3IgYW5kIHN0b3JlZCBwcm9jZWR1cmUgd29yaywgd2Ugd2lsbCBjYWxsIHRoZSBwcm9jZWR1cmUgZnJvbSBSOgoKYGBge3IgY2FsbFNQLCBlY2hvPVQsIGV2YWw9Rn0Kc3RhdHVzIDwtIGRiRXhlY3V0ZShjb25uID0gY29uLAogICAgICAgICAgICAgICAgICAgICJDQUxMIEV4cG9ydERhdGFQcm9jKCk7IikKYGBgCgpgYGB7ciBkaXNjZnJvbURCLCBlY2hvPUYsIGV2YWw9Rn0KZGJEaXNjb25uZWN0KGNvbikKYGBgCgojIyBTdW1tYXJ5CgpDdXJzb3JzIGluIHJlbGF0aW9uYWwgZGF0YWJhc2VzIGFsbG93IGEgZGV2ZWxvcGVyIHRvIGxpbmVhcmx5IHRyYXZlcnNlIHRoZSByZXN1bHQgc2V0IHJldHVybmVkIGJ5IGEgU1FMIFNFTEVDVCBxdWVyeS4gVGhleSBhcmUgdXNlZnVsIHdoZW4gZGF0YSBuZWVkcyB0byBiZSBwcm9jZXNzZWQgcm93LWJ5LXJvdywgYW5kIGxvYWRpbmcgdGhlIGVudGlyZSByZXN1bHQgc2V0IGludG8gbWVtb3J5IGF0IG9uY2UgaXMgbm90IGFwcHJvcHJpYXRlLgoKTXlTUUwgY3Vyc29ycyBhcmUgcmVhZC1vbmx5LCBub24tc2Nyb2xsYWJsZSwgYW5kIGluc2Vuc2l0aXZlIHRvIGNoYW5nZXMgbWFkZSB0byB0aGUgdGFibGUgd2hpbGUgdGhlIGN1cnNvciBpcyBhY3RpdmUuCgpEZXZlbG9wZXJzIHNob3VsZCB1c2UgY3Vyc29ycyBvbmx5IHdoZW4gbmVjZXNzYXJ5IGFuZCBjb25zaWRlciBhbHRlcm5hdGl2ZSBhcHByb2FjaGVzIHN1Y2ggYXMgaW4tbWVtb3J5IHRyYXZlcnNhbC4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgRmlsZXMgJiBSZXNvdXJjZXMgeyNmaWxlcy1yZXNvdXJjZXN9CgpgYGB7ciB6aXBGaWxlcywgZWNobz1GQUxTRX0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIAogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwKICAgICAgICAgICAgICAgICBwYXJhbXMkbnVtYmVyKQoKdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCAKICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LCIuIixwYXJhbXMkbnVtYmVyKQoKIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SCmtuaXRyOjpyYXdfaHRtbChkb3dubG9hZEZpbGVzTGluaygiLiIsIHppcE5hbWUsIHRleHRBTGluaykpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBTZWUgQWxzbwoKLSAgIFs3MC45MDcgLS0gU3RvcmVkIFByb2NlZHVyZXMgaW4gTXlTUUxdKGh0dHA6Ly9hcnRpZmljaXVtLnVzL2xlc3NvbnMvNzAuc3FsL2wtNzAtOTA3LXN0b3JlZC1wcm9jcy1teXNxbC9sLTcwLTkwNy5odG1sKQoKIyMgUmVmZXJlbmNlcwoKW1R1dG9yaWFsc1BvaW50OiBNeVNRTCBDdXJzb3IgREVDTEFSRSBTdGF0ZW1lbnRdKGh0dHBzOi8vd3d3LnR1dG9yaWFsc3BvaW50LmNvbS9teXNxbC9teXNxbF9jdXJzb3JfZGVjbGFyZV9zdGF0ZW1lbnQuaHRtKQoKIyMgRXJyYXRhCgpOb25lIGNvbGxlY3RlZCB5ZXQuIExldCB1cyBrbm93LgoKYGBgez1odG1sfQo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tL3N0YXRpYy9mZWVkYmFjazIuanMiIHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgbmV3IEpvdGZvcm1GZWVkYmFjayh7CiAgICBmb3JtSWQ6ICIyMTIxODcwNzI3ODQxNTciLAogICAgYnV0dG9uVGV4dDogIkZlZWRiYWNrIiwKICAgIGJhc2U6ICJodHRwczovL2Zvcm0uam90Zm9ybS5jb20vIiwKICAgIGJhY2tncm91bmQ6ICIjRjU5MjAyIiwKICAgIGZvbnRDb2xvcjogIiNGRkZGRkYiLAogICAgYnV0dG9uU2lkZTogImxlZnQiLAogICAgYnV0dG9uQWxpZ246ICJjZW50ZXIiLAogICAgdHlwZTogZmFsc2UsCiAgICB3aWR0aDogNzAwLAogICAgaGVpZ2h0OiA1MDAsCiAgICBpc0NhcmRGb3JtOiBmYWxzZQogIH0pOwo8L3NjcmlwdD4KYGBgCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19kZXBsb3lLbml0LlInKSksIGluY2x1ZGUgPSBGQUxTRX0KYGBgCg==