From 683fef7e9c687e18addaa24d7098a0d6492591c3 Mon Sep 17 00:00:00 2001 From: jason Date: Mon, 9 Mar 2026 22:00:40 -0500 Subject: [PATCH] feat: add is_champion column to dogs table and settings table --- server/db/init.js | 176 +--------------------------------------------- 1 file changed, 1 insertion(+), 175 deletions(-) diff --git a/server/db/init.js b/server/db/init.js index 7b74afc..0228cd4 100644 --- a/server/db/init.js +++ b/server/db/init.js @@ -1,175 +1 @@ -const Database = require('better-sqlite3'); -const path = require('path'); -const fs = require('fs'); - -function initDatabase(dbPath) { - // Ensure data directory exists - const dir = path.dirname(dbPath); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - - const db = new Database(dbPath); - - // Enable foreign keys - db.pragma('foreign_keys = ON'); - - console.log('Initializing database schema...'); - - // Dogs table - NO sire/dam columns, only litter_id - db.exec(` - CREATE TABLE IF NOT EXISTS dogs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - registration_number TEXT UNIQUE, - breed TEXT NOT NULL, - sex TEXT NOT NULL CHECK(sex IN ('male', 'female')), - birth_date DATE, - color TEXT, - microchip TEXT, - photo_urls TEXT, -- JSON array of photo URLs - notes TEXT, - litter_id INTEGER, - is_active INTEGER DEFAULT 1, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (litter_id) REFERENCES litters(id) ON DELETE SET NULL - ) - `); - - // Create unique index for microchip that allows NULL values - db.exec(` - CREATE UNIQUE INDEX IF NOT EXISTS idx_dogs_microchip - ON dogs(microchip) - WHERE microchip IS NOT NULL - `); - - // Parents table - Stores sire/dam relationships - db.exec(` - CREATE TABLE IF NOT EXISTS parents ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - dog_id INTEGER NOT NULL, - parent_id INTEGER NOT NULL, - parent_type TEXT NOT NULL CHECK(parent_type IN ('sire', 'dam')), - FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE, - FOREIGN KEY (parent_id) REFERENCES dogs(id) ON DELETE CASCADE, - UNIQUE(dog_id, parent_type) - ) - `); - - // Litters table - Breeding records - db.exec(` - CREATE TABLE IF NOT EXISTS litters ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - sire_id INTEGER NOT NULL, - dam_id INTEGER NOT NULL, - breeding_date DATE NOT NULL, - whelping_date DATE, - puppy_count INTEGER DEFAULT 0, - notes TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (sire_id) REFERENCES dogs(id) ON DELETE CASCADE, - FOREIGN KEY (dam_id) REFERENCES dogs(id) ON DELETE CASCADE - ) - `); - - // Health records table - db.exec(` - CREATE TABLE IF NOT EXISTS health_records ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - dog_id INTEGER NOT NULL, - record_type TEXT NOT NULL CHECK(record_type IN ('test', 'vaccination', 'exam', 'treatment', 'certification')), - test_name TEXT, - test_date DATE NOT NULL, - result TEXT, - document_url TEXT, - notes TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE - ) - `); - - // Heat cycles table - db.exec(` - CREATE TABLE IF NOT EXISTS heat_cycles ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - dog_id INTEGER NOT NULL, - start_date DATE NOT NULL, - end_date DATE, - progesterone_peak_date DATE, - breeding_date DATE, - breeding_successful INTEGER DEFAULT 0, - notes TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE - ) - `); - - // Traits table - Genetic trait tracking - db.exec(` - CREATE TABLE IF NOT EXISTS traits ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - dog_id INTEGER NOT NULL, - trait_category TEXT NOT NULL, - trait_name TEXT NOT NULL, - trait_value TEXT NOT NULL, - inherited_from INTEGER, - notes TEXT, - FOREIGN KEY (dog_id) REFERENCES dogs(id) ON DELETE CASCADE, - FOREIGN KEY (inherited_from) REFERENCES dogs(id) ON DELETE SET NULL - ) - `); - - // Create indexes for performance - db.exec(` - CREATE INDEX IF NOT EXISTS idx_dogs_name ON dogs(name); - CREATE INDEX IF NOT EXISTS idx_dogs_registration ON dogs(registration_number); - CREATE INDEX IF NOT EXISTS idx_dogs_litter ON dogs(litter_id); - CREATE INDEX IF NOT EXISTS idx_parents_dog ON parents(dog_id); - CREATE INDEX IF NOT EXISTS idx_parents_parent ON parents(parent_id); - CREATE INDEX IF NOT EXISTS idx_litters_sire ON litters(sire_id); - CREATE INDEX IF NOT EXISTS idx_litters_dam ON litters(dam_id); - CREATE INDEX IF NOT EXISTS idx_health_dog ON health_records(dog_id); - CREATE INDEX IF NOT EXISTS idx_heat_dog ON heat_cycles(dog_id); - CREATE INDEX IF NOT EXISTS idx_traits_dog ON traits(dog_id); - `); - - // Create trigger for updated_at - db.exec(` - CREATE TRIGGER IF NOT EXISTS update_dogs_timestamp - AFTER UPDATE ON dogs - FOR EACH ROW - BEGIN - UPDATE dogs SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id; - END; - `); - - console.log('✓ Database schema initialized successfully!'); - console.log('✓ Dogs table: NO sire/dam columns, uses parents table'); - console.log('✓ Parents table: Stores sire/dam relationships'); - console.log('✓ Litters table: Links puppies via litter_id'); - - db.close(); - return true; -} - -function getDatabase() { - const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/breedr.db'); - const db = new Database(dbPath); - db.pragma('foreign_keys = ON'); - return db; -} - -module.exports = { initDatabase, getDatabase }; - -// Run initialization if called directly -if (require.main === module) { - const dbPath = process.env.DB_PATH || path.join(__dirname, '../../data/breedr.db'); - console.log('\n=========================================='); - console.log('BREEDR Database Initialization'); - console.log('=========================================='); - console.log(`Database: ${dbPath}`); - console.log('==========================================\n'); - initDatabase(dbPath); - console.log('\n✓ Database ready!\n'); -} +Y29uc3QgRGF0YWJhc2UgPSByZXF1aXJlKCdiZXR0ZXItc3FsaXRlMycpOwpjb25zdCBwYXRoID0gcmVxdWlyZSgncGF0aCcpOwpjb25zdCBmcyA9IHJlcXVpcmUoJ2ZzJyk7CgpmdW5jdGlvbiBpbml0RGF0YWJhc2UoZGJQYXRoKSB7CiAgY29uc3QgZGlyID0gcGF0aC5kaXJuYW1lKGRiUGF0aCk7CiAgaWYgKCFmcy5leGlzdHNTeW5jKGRpcikpIHsKICAgIGZzLm1rZGlyU3luYyhkaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pOwogIH0KCiAgY29uc3QgZGIgPSBuZXcgRGF0YWJhc2UoZGJQYXRoKTsKICBkYi5wcmFnbWEoJ2ZvcmVpZ25fa2V5cyA9IE9OJyk7CiAgY29uc29sZS5sb2coJ0luaXRpYWxpemluZyBkYXRhYmFzZSBzY2hlbWEuLi4nKTsKCiAgLy8gRG9ncyB0YWJsZSAtIGluY2x1ZGVzIGlzX2NoYW1waW9uIGZsYWcKICBkYi5leGVjKGAKICAgIENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIGRvZ3MgKAogICAgICBpZCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICAgIG5hbWUgVEVYVCBOT1QgTlVMTCwKICAgICAgcmVnaXN0cmF0aW9uX251bWJlciBURVhUIFVOSVFVRSwKICAgICAgYnJlZWQgVEVYVCBOT1QgTlVMTCwKICAgICAgc2V4IFRFWFQgTk9UIE5VTEwgQ0hFQ0soc2V4IElOICgnbWFsZScsICdmZW1hbGUnKSksCiAgICAgIGJpcnRoX2RhdGUgREFURSwKICAgICAgY29sb3IgVEVYVCwKICAgICAgbWljcm9jaGlwIFRFWFQsCiAgICAgIHBob3RvX3VybHMgVEVYVCwKICAgICAgbm90ZXMgVEVYVCwKICAgICAgbGl0dGVyX2lkIElOVEVHRVIsCiAgICAgIGlzX2FjdGl2ZSBJTlRFR0VSIERFRkFVTFQgMSwKICAgICAgaXNfY2hhbXBpb24gSU5URUdFUiBERUZBVUxUIDAsCiAgICAgIGNyZWF0ZWRfYXQgREFURVRJTUUgREVGQVVMVCBDVVJSRU5UX1RJTUVTVEFNUCwKICAgICAgdXBkYXRlZF9hdCBEQVRFVElNRSBERUZBVUxUIENVUlJFTlRfVElNRVNUQU1QLAogICAgICBGT1JFSUdOIEtFWSAobGl0dGVyX2lkKSBSRUZFUkVOQ0VTIGxpdHRlcnMoaWQpIE9OIERFTEVURSBTRVQgTlVMTAogICAgKQogIGApOwoKICAvLyBTZXR0aW5ncyB0YWJsZSAtIGtlbm5lbCBuYW1lICsgaW5mbwogIGRiLmV4ZWMoYAogICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgc2V0dGluZ3MgKAogICAgICBrZXkgVEVYVCBQUklNQVJZIEtFWSwKICAgICAgdmFsdWUgVEVYVAogICAgKQogIGApOwoKICAvLyBJbnNlcnQgZGVmYXVsdHMgaWYgbm90IHByZXNlbnQKICBkYi5wcmVwYXJlKGBJTlNFUlQgT1IgSUdOT1JFIElOVE8gc2V0dGluZ3MgKGtleSwgdmFsdWUpIFZBTFVFUyAoPywgPylgKS5ydW4oJ2tlbm5lbF9uYW1lJywgJ015IEtlbm5lbCcpOwogIGRiLnByZXBhcmUoYElOU0VSVCBPUiBJR05PUkUgSU5UTyBzZXR0aW5ncyAoa2V5LCB2YWx1ZSkgVkFMVUVTICg/LCA/KWApLnJ1bignS2VubmVsX3Bob25lJywgJycpOwogIGRiLnByZXBhcmUoYElOU0VSVCBPUiBJR05PUkUgSU5UTyBzZXR0aW5ncyAoa2V5LCB2YWx1ZSkgVkFMVUVTICg/LCA/KWApLnJ1bignS2VubmVsX2VtYWlsJywgJycpOwogIGRiLnByZXBhcmUoYElOU0VSVCBPUiBJR05PUkUgSU5UTyBzZXR0aW5ncyAoa2V5LCB2YWx1ZSkgVkFMVUVTICg/LCA/KWApLnJ1bignS2VubmVsX2xvY2F0aW9uJywgJycpOwogIGRiLnByZXBhcmUoYElOU0VSVCBPUiBJR05PUkUgSU5UTyBzZXR0aW5ncyAoa2V5LCB2YWx1ZSkgVkFMVUVTICg/LCA/KWApLnJ1bignS2VubmVsX25vdGVzJywgJycpOwoKICAvLyBNaWdyYXRpb246IGFkZCBpc19jaGFtcGlvbiBpZiBtaXNzaW5nIG9uIGV4aXN0aW5nIERCcwogIHRyeSB7CiAgICBkYi5leGVjKCdBTFRFUiBUQUJMRSBkb2dzIEFERCBDT0xVTU4gaXNfY2hhbXBpb24gSU5URUdFUiBERUZBVUxUIDAeKTsKICB9IGNhdGNoIChlKSB7CiAgICAvLyBDb2x1bW4gYWxyZWFkeSBleGlzdHMgLSBpZ25vcmUKICB9CgogIGRiLmV4ZWMoYAogICAgQ1JFQVRFIFVOSVFVRSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9kb2dzX21pY3JvY2hpcAogICAgT04gZG9ncyhtaWNyb2NoaXApCiAgICBXSEVSRSBtaWNyb2NoaXAgSVMgTk9UIE5VTEwKICBgKTsKCiAgZGIuZXhlYyhgCiAgICBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBwYXJlbnRzICgKICAgICAgaWQgSU5URUdFUiBQUklNQVJZIEtFWSBBVVRPSU5DUkVNRU5ULAogICAgICBkb2dfaWQgSU5URUdFUiBOT1QgTlVMTCwKICAgICAgcGFyZW50X2lkIElOVEVHRVIgTk9UIE5VTEwsCiAgICAgIHBhcmVudF90eXBlIFRFWFQgTk9UIE5VTEwgQ0hFQ0socGFyZW50X3R5cGUgSU4gKCdzaXJlJywgJ2RhbScpKSwKICAgICAgRk9SRUlHTiBLRVkgKGRvZ19pZCkgUkVGRVJFTkNFUyBkb2dzKGlkKSBPTiBERUxFVEUgQ0FTQ0FERSwKICAgICAgRk9SRUlHTiBLRVkgKHBhcmVudF9pZCkgUkVGRVJFTkNFUyBkb2dzKGlkKSBPTiBERUxFVEUgQ0FTQ0FERSwKICAgICAgVU5JUVVFKGRvZ19pZCwgcGFyZW50X3R5cGUpCiAgICApCiAgYCk7CgogIGRiLmV4ZWMoYAogICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgbGl0dGVycyAoCiAgICAgIGlkIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgICAgc2lyZV9pZCBJTlRFR0VSIE5PVCBOVUxMLAogICAgICBkYW1faWQgSU5URUdFUiBOT1QgTlVMTCwKICAgICAgYnJlZWRpbmdfZGF0ZSBEQVRFIE5PVCBOVUxMLAogICAgICB3aGVscGluZ19kYXRlIERBVEUsCiAgICAgIHB1cHB5X2NvdW50IElOVEVHRVIgREVGQVVMVCAwLAogICAgICBub3RlcyBURVhULAogICAgICBjcmVhdGVkX2F0IERBVEVUSU1FIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAsCiAgICAgIEZPUkVJR04gS0VZIChzaXJlX2lkKSBSRUZFUkVOQ0VTIGRvZ3MoaWQpIE9OIERFTEVURSBDQVNDQURFLAogICAgICBGT1JFSUdOIEtFWSAoZGFtX2lkKSBSRUZFUkVOQ0VTIGRvZ3MoaWQpIE9OIERFTEVURSBDQVNDQURFCiAgICApCiAgYCk7CgogIGRiLmV4ZWMoYAogICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgaGVhbHRoX3JlY29yZHMgKAogICAgICBpZCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICAgIGRvZ19pZCBJTlRFR0VSIE5PVCBOVUxMLAogICAgICByZWNvcmRfdHlwZSBURVhUIE5PVCBOVUxMIENIRUNLKHJlY29yZF90eXBlIElOICgndGVzdCcsICd2YWNjaW5hdGlvbicsICdleGFtJywgJ3RyZWF0bWVudCcsICdjZXJ0aWZpY2F0aW9uJykpLAogICAgICB0ZXN0X25hbWUgVEVYVCwKICAgICAgdGVzdF9kYXRlIERBVEUgTk9UIE5VTEwsCiAgICAgIHJlc3VsdCBURVhULAogICAgICBkb2N1bWVudF91cmwgVEVYVCwKICAgICAgbm90ZXMgVEVYVCwKICAgICAgY3JlYXRlZF9hdCBEQVRFVElNRSBERUZBVUxUIENVUlJFTlRfVElNRVNUQU1QLAogICAgICBGT1JFSUdOIEtFWSAoZG9nX2lkKSBSRUZFUkVOQ0VTIGRvZ3MoaWQpIE9OIERFTEVURSBDQVNDQURFCiAgICApCiAgYCk7CgogIGRiLmV4ZWMoYAogICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgaGVhdF9jeWNsZXMgKAogICAgICBpZCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICAgIGRvZ19pZCBJTlRFR0VSIE5PVCBOVUxMLAogICAgICBzdGFydF9kYXRlIERBVEUgTk9UIE5VTEwsCiAgICAgIGVuZF9kYXRlIERBVEUsCiAgICAgIHByb2dlc3Rlcm9uZV9wZWFrX2RhdGUgREFURSwKICAgICAgYnJlZWRpbmdfZGF0ZSBEQVRFLAogICAgICBicmVlZGluZ19zdWNjZXNzZnVsIElOVEVHRVIgREVGQVVMVCAwLAogICAgICBub3RlcyBURVhULAogICAgICBjcmVhdGVkX2F0IERBVEVUSU1FIERFRkFVTFQgQ1VSUkVOVF9USU1FU1RBTVAsCiAgICAgIEZPUkVJR04gS0VZIChkb2dfaWQpIFJFRkVSRU5DRVMgZG9ncyhpZCkgT04gREVMRVRFIENBU0NBREUKICAgICkKICBgKTsKCiAgZGIuZXhlYyhgCiAgICBDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyB0cmFpdHMgKAogICAgICBpZCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsCiAgICAgIGRvZ19pZCBJTlRFR0VSIE5PVCBOVUxMLAogICAgICB0cmFpdF9jYXRlZ29yeSBURVhUIE5PVCBOVUxMLAogICAgICB0cmFpdF9uYW1lIFRFWFQgTk9UIE5VTEwsCiAgICAgIHRyYWl0X3ZhbHVlIFRFWFQgTk9UIE5VTEwsCiAgICAgIGluaGVyaXRlZF9mcm9tIElOVEVHRVIsCiAgICAgIG5vdGVzIFRFWFQsCiAgICAgIEZPUkVJR04gS0VZIChkb2dfaWQpIFJFRkVSRU5DRVMgZG9ncyhpZCkgT04gREVMRVRFIENBU0NBREUsCiAgICAgIEZPUkVJR04gS0VZIChpbmhlcml0ZWRfZnJvbSkgUkVGRVJFTkNFUyBkb2dzKGlkKSBPTiBERUxFVEUgU0VUIE5VTEwKICAgICkKICBgKTsKCiAgZGIuZXhlYyhgCiAgICBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfZG9nc19uYW1lIE9OIGRvZ3MobmFtZSk7CiAgICBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfZG9nc19yZWdpc3RyYXRpb24gT04gZG9ncyhyZWdpc3RyYXRpb25fbnVtYmVyKTsKICAgIENSRUFURSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9kb2dzX2xpdHRlciBPTiBkb2dzKGxpdHRlcl9pZCk7CiAgICBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfcGFyZW50c19kb2cgT04gcGFyZW50cyhkb2dfaWQpOwogICAgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X3BhcmVudHNfcGFyZW50IE9OIHBhcmVudHMocGFyZW50X2lkKTsKICAgIENSRUFURSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9saXR0ZXJzX3NpcmUgT04gbGl0dGVycyhzaXJlX2lkKTsKICAgIENSRUFURSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9saXR0ZXJzX2RhbSBPTiBsaXR0ZXJzKGRhbV9pZCk7CiAgICBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfaGVhbHRoX2RvZyBPTiBoZWFsdGhfcmVjb3Jkcyhkb2dfaWQpOwogICAgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X2hlYXRfZG9nIE9OIGhlYXRfY3ljbGVzKGRvZ19pZCk7CiAgICBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfdHJhaXRzX2RvZyBPTiB0cmFpdHMoZG9nX2lkKTsKICBgKTsKCiAgZGIuZXhlYyhgCiAgICBDUkVBVEUgVFJJR0dFUiBJRiBOT1QgRVhJU1RTIHVwZGF0ZV9kb2dzX3RpbWVzdGFtcAogICAgQUZURVIgVVBEQVRFIE9OIGRvZ3MKICAgIEZPUiBFQUNIIFJPVwogICAgQkVHSU4KICAgICAgVVBEQVRFIGRvZ3MgU0VUIHVwZGF0ZWRfYXQgPSBDVVJSRU5UX1RJTUVTVEFNUCBXSEVSRSBpZCA9IE5FVy5pZDsKICAgIEVORDsKICBgKTsKCiAgY29uc29sZS5sb2coJ+KckyBEYXRhYmFzZSBzY2hlbWEgaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5IScpOwogIGNvbnNvbGUubG9nKCfinJMgRG9ncyB0YWJsZTogaXNfY2hhbXBpb24gY29sdW1uIGluY2x1ZGVkJyk7CiAgY29uc29sZS5sb2coJ+KckSBTZXR0aW5ncyB0YWJsZTogS2VubmVsIG5hbWUgYW5kIGluZm8gc3VwcG9ydGVkJyk7CgogIGRiLmNsb3NlKCk7CiAgcmV0dXJuIHRydWU7Cn0KCmZ1bmN0aW9uIGdldERhdGFiYXNlKCkgewogIGNvbnN0IGRiUGF0aCA9IHByb2Nlc3MuZW52LkRCX1BBVEggfHwgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uLy4uL2RhdGEvYnJlZWRyLmRiJyk7CiAgY29uc3QgZGIgPSBuZXcgRGF0YWJhc2UoZGJQYXRoKTsKICBkYi5wcmFnbWEoJ2ZvcmVpZ25fa2V5cyA9IE9OJyk7CiAgcmV0dXJuIGRiOwp9Cgptb2R1bGUuZXhwb3J0cyA9IHsgaW5pdERhdGFiYXNlLCBnZXREYXRhYmFzZSB9OwoKaWYgKHJlcXVpcmUubWFpbiA9PT0gbW9kdWxlKSB7CiAgY29uc3QgZGJQYXRoID0gcHJvY2Vzcy5lbnYuREJfUEFUSCB8fCBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vZGF0YS9icmVlZHIuZGInKTsKICBjb25zb2xlLmxvZygnXG49PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PScpOwogIGNvbnNvbGUubG9nKCdCUkVFRFIgRGF0YWJhc2UgSW5pdGlhbGl6YXRpb24nKTsKICBjb25zb2xlLmxvZygnPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Jyk7CiAgY29uc29sZS5sb2coYERhdGFiYXNlOiAke2RiUGF0aH1gKTsKICBjb25zb2xlLmxvZygnPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4nKTsKICBpbml0RGF0YWJhc2UoZGJQYXRoKTsKICBjb25zb2xlLmxvZygnXG7inJMgRGF0YWJhc2UgcmVhZHkhXG4nKTsKfQo= \ No newline at end of file