{ "version": 3, "sources": ["../../page/wallet.js"], "sourcesContent": ["\"use strict\"\n\nimport * as App from '../app/app~fv=cw_byBD8.min.js'\nimport * as Coze from '../pkg/coze_all~fv=-7uCIHNa.min.js'\nimport '../pkg/qrgen~fv=t0jhkAEE.min.js' // Namespaced as 'qrgen'.\nimport '../pkg/urlform~fv=VhWyOSvq.min.js' // Namespaced as 'URLForm'.\nimport QrScanner from '../pkg/qr-scanner.min.js'\n\n/**\n@typedef {import('../app/login.js').Profile} Profile\n@typedef {import('../pkg/cozejs/key.js').CozeKey} CozeKey\n@typedef {import('../../../pkg/cozejs/typedef.js').Coze} Coze\n@typedef {import('../../../pkg/cozejs/typedef.js').B64} B64\n@typedef {import('../pkg/urlformjs/urlform.js').FormParameters} FormParameters\n */\n\n/**\nKey is the application object for holding a Coze Key, and meta data.\n\n- first_seen: First time key was seen by Cyphr.me.\n- fvm: First verified message seen by Cyphr.me server.\n- fvm_time: First verified message time.\n- key: Cryptographic components of the key (Coze Key). Contains 'id'. 'id' is\n not standard in a Coze Key, but used in the app. 'id' and 'tmb' should match.\n- time: Time the key was added to Cyphr.me.\n- uad: Owner of the key.\n- updated: The last time the key was updated.\n- utk: Index for key.\n@typedef {object} Key\n@property {string} first_seen\n@property {string} fvm\n@property {string} fvm_time\n@property {CozeKey} key\n@property {string} time\n@property {string} uad\n@property {string} updated\n@property {string} utk\n */\n\n/**\nKeys is an array of `Key` objects.\n@typedef {Key[]} Keys\n */\n\nvar SelectedAlg // Alg that the gui is using. Used for new key generation\n\nvar Wallets = {} // Wallets are 1:1 to \"accounts.\"\nvar selectedWalletID // ID of the wallet currently selected in the GUI.\nvar AutoGenOnEmpty = true\n\n// Page Modals\nvar scanQRModal\nvar revokeKeyModal // Modal for revoking key from system.\nvar revokeKeyObject // The key being revoked.\nvar revokeOnlyKeyModal // Modal for warning user they are revoking their only key.\nvar systemKeyModal // Modal for deleting key from system.\nvar systemKeyDeleteTmb // Tmb Used for system key modal delete btn.\nvar localKeyModal // Modal for deleting key locally.\nvar localLoggedInKeyModal // Modal for deleting currently logged in key.\nvar localKeyDeleteTmb // Tmb Used for local key modal delete btn.\nvar localTmbModal // Modal for adding thumbprint to local wallet.\nvar localTmb // Tmb used for adding to wallet. Coze Key object that is a thumb only key.\nvar localWalletModal // Modal for deleting a wallet.\nvar localLoggedInWalletModal // Modal for deleting logged in wallet.\n// var pageLimit = 5 // Number used for limiting the amount of keys in the wallet, per page.\n\n// Since information is lost when we change the account id to display as the\n// display name, we must make a map of the display name, and which account/id it\n// relates to.\nvar displayNameMap = {}\n\n// Holds state for currently expanded wallets to preserve state when refreshing\n// wallets. Object of the wallet's ids. Values are empty strings. We only care\n// about whether or not the ID is present, and object solves many of the\n// problems that arrays have (i.e. delete).\nvar expandedWallets = {}\n\n// Page Icons\nconst greenCheckmarkIcon = ``\nconst redExIcon = ``\nconst starIcon = ` `\nconst revokedIcon = ''\n\n/**\nPageFormParameters are not in an 'HTMLFormElement' on the page, and are\nindependent of each other, thus calling 'GetForm', 'Serialize', and 'Clear'\nin 'URLFormJS' does not work. This page only uses the package for sticky\noptions to be set on the page via the URL.\n\nhttps://localhost:8081/wallet?import_key=Bob&advanced\nhttps://localhost:8081/wallet#?power&advanced&import&import_key={\"alg\":\"ES256\",\"iat\":1658879472,\"kid\":\"Bob\",\"tmb\":\"wja13v-cUfLHrwosRYO45NskMq0Ajt9Kec6LTHto_dg\",\"x\":\"UQw1VLdBpKd81WuQP5NScFiRiozvLZlpTN9nXbtbssgCnn5aEi73HrpCE-Uu7gzvh7__ZAWTJRAxgvVnhWZTSA\",\"d\":\"lEemeFvivgh-62J2Kdtu8wF594PPAApWg7f9FFA9uB8\"}\nhttps://localhost:8081/wallet#?power=true\n{\"alg\":\"ES256\",\"x\":\"pzJ51F8pQfbqalpjNy-7x4OfvhEKpP92JEeIsIaAmaPfeqeh2pAdgP2pVnkAGx9lZ11qYtw9Le-Zr5uxVezjpw\",\"d\":\"RZ0ltt0GF4PQn0EdCxPvd451clBJU_ZXpGB1UWULRwY\",\"tmb\":\"PhhFSK9S1SkYsLHhWDkxcsLI254qnbzLiCb9Ixi-LE8\",\"iat\":1664379297,\"kid\":\"My Cyphr.me Key.\"}\n\n\n\n/**@type {FormOptions} */\nconst FormOptions = {\n\t\"FormParameters\": [{\n\t\t\t\"name\": \"import_key\",\n\t\t\t\"id\": \"KeyImportArea\",\n\t\t},\n\t\t{\n\t\t\t\"name\": \"import\",\n\t\t\t\"type\": \"bool\",\n\t\t\t\"funcTrue\": importPrivateKey,\n\t\t\t\"nonFormValue\": true,\n\t\t},\n\t\t{\n\t\t\t\"name\": \"advanced\",\n\t\t\t\"type\": \"bool\",\n\t\t\t\"funcTrue\": () => ToggleVisible(\"Advanced\"),\n\t\t\t\"nonFormValue\": true,\n\t\t},\n\t\t{\n\t\t\t\"name\": \"power\",\n\t\t\t\"id\": \"power\",\n\t\t\t\"type\": \"bool\",\n\t\t\t\"saveSetting\": true,\n\t\t\t\"funcTrue\": () => powerMode(true),\n\t\t},\n\t\t// {\n\t\t// \t\"name\": \"power\", // alias for powerMode\n\t\t// \t\"type\": \"bool\",\n\t\t// \t\"funcTrue\": () => powerMode(true),\n\t\t// },\n\t\t{\n\t\t\t\"name\": \"noAutoGen\", // Don't automatically generate key on empty wallet. \n\t\t\t\"type\": \"bool\",\n\t\t\t\"funcTrue\": () => {\n\t\t\t\tconsole.log(\"AutoGenFalse\")\n\t\t\t\tAutoGenOnEmpty = false\n\t\t\t},\n\t\t\t\"nonFormValue\": true,\n\t\t},\n\t\t// https://localhost:8081/wallet?power&noAutoGen\n\t]\n}\n\nApp.AddOnload(WalletOnload)\n\nasync function WalletOnload() {\n\tSelectedAlg = document.querySelector(\"#SelectedAlg\").value\n\n\t// Modals\n\tlet modalOpts = {\n\t\tkeyboard: true\n\t}\n\n\tscanQRModal = new bootstrap.Modal(document.getElementById('scanQRModal'), modalOpts)\n\tlocalKeyModal = new bootstrap.Modal(document.getElementById('deleteLocalKeyModal'), modalOpts)\n\tlocalLoggedInKeyModal = new bootstrap.Modal(document.getElementById('deleteCurrentLoggedInLocalKeyModal'), modalOpts)\n\tsystemKeyModal = new bootstrap.Modal(document.getElementById('deleteSystemKeyModal'), modalOpts)\n\trevokeKeyModal = new bootstrap.Modal(document.getElementById('revokeKeyModal'), modalOpts)\n\trevokeOnlyKeyModal = new bootstrap.Modal(document.getElementById('revokeOnlyKeyModal'), modalOpts)\n\tlocalTmbModal = new bootstrap.Modal(document.getElementById('addThumbprintToWalletModal'), modalOpts)\n\tlocalWalletModal = new bootstrap.Modal(document.getElementById('deleteWalletModal'), modalOpts)\n\tlocalLoggedInWalletModal = new bootstrap.Modal(document.getElementById('deleteLoggedInWalletModal'), modalOpts)\n\n\t// Set power mode toggle\n\tdocument.querySelector(\"#power\").addEventListener(\"click\", powerMode)\n\n\t// Generate new key buttons\n\tdocument.querySelectorAll('.newKeyBtn').forEach((item) => item.addEventListener(\"click\", () => genNewKey()))\n\t// Generates and sets as selected new key\n\tdocument.querySelectorAll('.NewPrimaryKeyBtn').forEach((item) => item.addEventListener(\"click\", () => genNewKey(true)))\n\n\t// Download all keys within local storage.\n\tdocument.querySelectorAll('.downloadAllWallets').forEach((item) => item.addEventListener(\"click\", () => App.DownloadWallet(App.Keys)))\n\n\t// Import Private Key Button\n\tdocument.querySelector(\"#ImportPrivateKeyButton\").addEventListener(\"click\", () => importPrivateKey(document.querySelector(\"#KeyImportArea\").value))\n\n\t// Sets event listener for the local delete key modal on page.\n\tdocument.querySelector('.modal_local_delete_key').addEventListener('click', () => deleteLocalKey(localKeyDeleteTmb))\n\n\t// Deletes the current logged in key.\n\tdocument.querySelector('.modal_delete_local_logged_in_key').addEventListener('click', () => deleteKey(localKeyDeleteTmb))\n\n\t// Sets event listener for the system delete key modal on page.\n\tdocument.querySelector('.modal_system_delete_key').addEventListener('click', () => deleteKeyFromSystem(systemKeyDeleteTmb))\n\n\t// Sets event listener for the revoke key modal on page.\n\tdocument.querySelector('.modal_revoke_key').addEventListener('click', () => revokeKey(revokeKeyObject))\n\n\t// Show advanced options for page (Generate new key, etc.).\n\tdocument.querySelector('#ShowAdvancedBtn').addEventListener('click', () => ToggleVisible(\"Advanced\"))\n\n\t// Delete selected wallet and all keys within the wallet, unless key is the current logged in key.\n\tdocument.querySelector('#deleteLocalWalletBtn').addEventListener('click', deleteLocalWallet)\n\n\t// Delete logged in wallet and all keys within the wallet.\n\tdocument.querySelector('.modal_local_delete_logged_in_wallet').addEventListener('click', deleteWallet)\n\n\t// Sync all Keys\n\tdocument.querySelector('#syncAllKeys').addEventListener('click', () => syncAllKeys(Object.values(App.Keys)))\n\n\t// Set selected alg for generation of new key.\n\tdocument.querySelector(\"#SelectedAlg\").addEventListener('change', function () {\n\t\tSelectedAlg = document.querySelector(\"#SelectedAlg\").value\n\t})\n\n\n\t// Modal button for adding thumbprint only keys to the selected account.\n\tdocument.querySelector('#addTmbToWalletBtn').addEventListener('click', async () => {\n\t\tApp.UpsertGlobalKey(localTmb)\n\t\tinitWallets()\n\t\tApp.Notification(\"Successfully added thumbprint to wallet.\", \"success\")\n\t})\n\n\tURLForm.Populate(URLForm.Init(FormOptions))\n\n\t// Initializes the User's wallets\n\tinitWallets()\n}\n\n/**\nClear application and GUI state for wallets. Helpful for having the wallet state\nclearing in one place, as well as knowing we can call await to let if complete\nbefore continuing.\n@returns {void}\n */\nasync function clearWalletsState() {\n\tWallets = {}\n\tdisplayNameMap = {}\n\tdocument.querySelector(\"#wallets\").innerHTML = \"\"\n}\n\n/**\nInitializes the User's key wallet. Grabs keys from local storage, parses the\nobject that holds them, and then ranges through the User's Keys and adds them to\nthe key wallet. Displays all of a user's keys in local storage to the page.\n@throws {SyntaxError} JSON parse exception.\n@returns {void} Calls createKeyDiv with each private key.\n */\nasync function initWallets() {\n\tconsole.log(\"initWallets\")\n\tawait clearWalletsState()\n\n\t// Initialize application global Keys and Accounts variables.\n\tawait App.InitKeys() // Make sure keys are inited.\n\tawait App.InitAccounts() // Make sure accounts are inited.\n\n\t// Public CozeKey, and CozeKey Extra must be set, for users that are not\n\t// logged in, do not have a key set, or have cleared setting, but have keys in\n\t// local storage. If no key is set, the first key in 'App.Keys' is set as the\n\t// selected key, and loaded in simple mode.\n\tif (isEmpty(App.CozeKeyPublic) && App.Keys.length > 0) {\n\t\tawait App.SetSelectedKey(Object.values(App.Keys)[0])\n\t}\n\n\t// Simple mode copy button\n\t// Perform this in 'initWallets' instead of typical onload location, to ensure\n\t// CozeKeyExtra is set.\n\tdocument.querySelector('#simpleMode .copyBtn').addEventListener('click', () => {\n\t\tClipboardS(App.CozeKeyExtra.SerializedTmb)\n\t\tApp.Notification(\"Copied: \" + App.CozeKeyExtra.SerializedTmb)\n\t})\n\n\t// Create a key accordion for each key in Keys. This also creates the wallets\n\t// for the given keys, as necessary.\n\tfor (const property in App.Keys) {\n\t\t// console.log(`${property}: ${keys[property]}`)\n\t\tlet jpk = App.Keys[property]\n\t\tif (typeof jpk != 'object') { // Convert to object if not object.\n\t\t\tjpk = JSON.parse(jpk)\n\t\t}\n\t\t// Would be more ideal to let this run synchronously, but there are variables\n\t\t// that get set here, so race conditions can break without this await.\n\t\tawait createKeyDiv(jpk)\n\t}\n\n\n\t// No keys yet. Show \"New Key\" Button on top.\n\tif (Object.keys(App.Keys).length == 0) {\n\t\tif (!isEmpty(AutoGenOnEmpty)) {\n\t\t\tconsole.log(\"Wallet is empty. Autogenerating new key.\")\n\t\t\tgenNewKey(true)\n\t\t} else {\n\t\t\tShow(\"emptyWallet\")\n\t\t\t// Hide(\"walletModSelect\")\n\t\t\t// Hide(\"simpleMode\")\n\t\t\tShow(\"powerMode\")\n\t\t}\n\t} else {\n\t\tHide(\"emptyWallet\")\n\t\t// Get wallet IDs and remove 'wallet_' prefix.\n\t\tlet walletIDs = Object.keys(Wallets)\n\t\tfor (let w in walletIDs) {\n\t\t\twalletIDs[w] = walletIDs[w].replace('wallet_', '')\n\t\t}\n\n\t\t// Load local accounts from storage that do not have a wallet/key on the page.\n\t\tfor (let a in App.Accounts) {\n\t\t\tif (!walletIDs.includes(a)) {\n\t\t\t\t// await necessary to load all wallets before appending no account.\n\t\t\t\tawait CreateWalletGUI(a)\n\t\t\t}\n\t\t}\n\n\t\t// Set No account wallet as the last wallet on the page.\n\t\tvar noAccountElem = document.getElementById(\"wallet_no_account\") // No account wallet element.\n\t\tdocument.querySelector(\"#wallets\").append(noAccountElem)\n\n\t\t// Populates key display names.\n\t\tfor (let account in Wallets) { // Each wallet\n\t\t\t// Show how many active keys are in each wallet. Use innerHTML and not\n\t\t\t// textContent to avoid modifying any icons, styling, etc.\n\t\t\tlet count = 0\n\t\t\tfor (let key of Wallets[account]) { // Each key in wallet\n\t\t\t\tif (isEmpty(key.display_name)) {\n\t\t\t\t\tif (!isEmpty(App.Accounts[key.uad]) && !isEmpty(App.Accounts[key.uad].display_name)) {\n\t\t\t\t\t\tkey.display_name = App.Accounts[key.uad].display_name\n\t\t\t\t\t\tApp.UpsertGlobalKey(key)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (key.rvk > 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tcount++\n\t\t\t}\n\t\t\tdocument.getElementById(account).querySelector('.walletCount ').innerHTML += \" (\" + count + \")\"\n\t\t}\n\t}\n\n\t// Show expanded wallets\n\tfor (let id in expandedWallets) {\n\t\tShow(document.querySelector(\"#\" + id + ' .card-hide'))\n\t}\n\n\t// Set select account options\n\tsetNewKeyAccountGUI()\n\n\t// Hide No account wallet when empty\n\tif (document.querySelectorAll('#wallet_no_account .accordion-item').length <= 0) {\n\t\tHide(noAccountElem)\n\t}\n\n\tconsole.debug(\"App is using public key: \", App.CozeKeyPublic)\n\tconsole.debug(\"Keys in wallet: \" + Object.keys(App.Keys).length)\n\tApp.Log.Trace(\"Done init wallet\")\n}\n\n\n/**\ncreateKeyDiv creates a card for individual keys on the page. Shows what keys\nare valid/imported on the server.\nTODO Implement sanity check/isEmpty on data and server response for which keys are valid.\n\nReturns CozeKey with potential fields added, if they are not already present,\nsuch as 'uad', and 'kid'.\n\nThis function was built from the simplest construction, to the most complex.\nE.g. Starting with the most generic logic that applies to all key variations,\nand adding to GUI/CK as needed, depending on the typ. Keep this in mind if\nmodifying this function, that the order was constructed carefully.\n@param {object} ck Local key object (A Coze Key with extra fields) to add to key accordion.\n@returns {CozeKey}\n */\nasync function createKeyDiv(ck) {\n\tif (isEmpty(ck)) {\n\t\tconsole.error('ck passed in empty')\n\t\treturn null\n\t}\n\n\tvar keyDiv = await document.querySelector('#KeyRowTempl').content.cloneNode(true)\n\tlet verifiedElem = keyDiv.querySelector('.verified')\n\n\tlet collapseKey = \"collapseKey\" + ck.tmb\n\t//accordion-header\n\tlet headerID = \"header\" + collapseKey\n\tkeyDiv.querySelector('.accordion-item').setAttribute(\"id\", headerID)\n\tlet ab = keyDiv.querySelector('.accordion-button')\n\tab.setAttribute(\"data-bs-target\", \"#\" + collapseKey)\n\tab.setAttribute(\"aria-controls\", collapseKey)\n\tkeyDiv.querySelector('.accordion-collapse').setAttribute(\"id\", collapseKey)\n\tkeyDiv.querySelector('.accordion-collapse').setAttribute(\"aria-labelledby\", headerID)\n\n\tlet tmbSub = ck.tmb.substring(0, 6) + '...'\n\tif (isEmpty(ck.kid)) {\n\t\tck.kid = \"[\" + tmbSub + \"]\"\n\t}\n\tkeyDiv.querySelector('.tmb').textContent = tmbSub\n\n\tif ('time' in ck && ck.time > 0) {\n\t\tverifiedElem.title = \"Key verified by Cyphr.me\"\n\t\tverifiedElem.innerHTML = greenCheckmarkIcon\n\t\tkeyDiv.querySelector('.cyphrme_added').textContent = await App.UnixToHR(ck.time)\n\t} else {\n\t\tverifiedElem.title = \"Key not verified by Cyphr.me\"\n\t\tverifiedElem.innerHTML = redExIcon\n\t\tHide(keyDiv.querySelector('.cyphrme_added').parentElement)\n\t}\n\n\t// Selected and Simple mode.\n\tif (!isEmpty(App.CozeKeyPublic)) {\n\t\tif (ck.tmb == App.CozeKeyPublic.tmb) {\n\t\t\tlet selected = keyDiv.querySelector('.starSelectedKey')\n\t\t\tselected.innerHTML = starIcon\n\t\t\tselected.title = \"Current selected key\"\n\n\t\t\t// Simple Mode\n\t\t\tdocument.querySelector('#simpleMode .kid').textContent = ck.kid\n\t\t\tdocument.querySelector('#simpleMode .tmb').textContent = tmbSub\n\n\t\t\tif (isEmpty(App.UAD)) { // Not logged in\n\t\t\t\tSetQR(location.origin + \"/wallet?import=\" + App.CozeKeyExtra.SerializedTmb, document.querySelector('#simpleMode .simpleQrcode'))\n\t\t\t\tif (isEmpty(App.CozeKey.UAD)) {\n\t\t\t\t\tconsole.log(\"No Account Yet. \")\n\t\t\t\t\tlet cas = document.querySelectorAll('.createAccountBtn')\n\t\t\t\t\tcas.forEach((ca) => {\n\t\t\t\t\t\tShow(ca)\n\t\t\t\t\t\tca.addEventListener('click', () => {\n\t\t\t\t\t\t\tconsole.log(\"Create Account\")\n\t\t\t\t\t\t\tlet preInviteModal = new bootstrap.Modal(document.querySelector('#preinviteModal'))\n\t\t\t\t\t\t\tpreInviteModal.show()\n\t\t\t\t\t\t\tApp.CreatePreInviteEmailForm()\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\t// Login Button\n\t\t\t\t\tlet lb = document.querySelector('#simpleMode .key_login')\n\t\t\t\t\tShow(lb)\n\t\t\t\t\tlb.addEventListener('click', () => {\n\t\t\t\t\t\tApp.Login(ck, initWallets)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tkeyDiv.querySelectorAll('.kid').forEach((item) => item.textContent = ck.kid.substring(0, 100))\n\n\tlet addKeyBtn = keyDiv.querySelector('.key_add')\n\tlet deleteKeyBtn = keyDiv.querySelector('.key_delete')\n\tlet revokeKeyBtn = keyDiv.querySelector('.key_revoke')\n\n\tif (!isEmpty(ck.uad)) {\n\t\taddKeyBtn.addEventListener('click', async () => {\n\t\t\t//// AddKeyToSystem\n\t\t\tlet callback = async (parsd) => {\n\t\t\t\tawait setKeysState([parsd.obj])\n\t\t\t\tawait initWallets()\n\t\t\t\tApp.Notification('Key has been added to Cyphr.me', 'success')\n\t\t\t}\n\t\t\tApp.UpsertKey(ck, callback)\n\t\t})\n\t} else {\n\t\tHide(addKeyBtn)\n\t\tHide(deleteKeyBtn)\n\t\tHide(revokeKeyBtn)\n\t}\n\n\t// Local Delete\n\tkeyDiv.querySelector('.key_local_delete').addEventListener('click', () => {\n\t\tlocalKeyDeleteTmb = ck.tmb\n\t\tlocalKeyModal.toggle()\n\t})\n\n\n\tvar tmbElem = keyDiv.querySelector('.keyThumb')\n\ttmbElem.value = ck.alg + \":\" + ck.tmb\n\n\tvar kidElem = keyDiv.querySelector('.accordion-body .kid')\n\tkeyDiv.querySelector('.kidEditBtn').addEventListener('click', () => EditKid(kidElem)) // Edit kid button\n\tkeyDiv.querySelector('.kidSaveBtn').addEventListener('click', () => SaveKid(kidElem, ck.tmb)) // Save kid button\n\t// Save on enter on kid edit\n\tkeyDiv.querySelector('.kidEditInput').addEventListener('keyup', (e) => {\n\t\tif (e.keyCode === 13) {\n\t\t\tSaveKid(kidElem, ck.tmb)\n\t\t}\n\t})\n\n\t// Copy tmb button\n\tkeyDiv.querySelector('.tmbCopy').addEventListener('click', () => {\n\t\tClipboardS(tmbElem.value)\n\t\tApp.Notification(\"Copied: \" + tmbElem.value)\n\t})\n\n\tSetQR(tmbElem.value, keyDiv.querySelector('.publicQrcode'))\n\n\t// Check if Coze Key is a thumbprint only key.\n\tif (isEmpty(ck.x) && isEmpty(ck.d)) {\n\t\tkeyDiv.querySelector('.accordion-item').classList.add('cyphr-bg-warning')\n\t\tkeyDiv.querySelector('.accordion-button').classList.add('cyphr-bg-warning')\n\t\tkeyDiv.querySelector('.iat').textContent = \"n/a\"\n\t\tHide(keyDiv.querySelector('.cyphrme_added').parentElement)\n\t\tHide(keyDiv.querySelector('.ShowPrivateKeyBtn'))\n\t\tkeyDiv.querySelector('.pub_key_btns').append(revokeKeyBtn)\n\t\tShow(revokeKeyBtn)\n\t} else {\n\t\tkeyDiv.querySelector('.iat').textContent = await App.UnixToHR(ck.iat)\n\n\t\t////////////////////////////////////////////\n\t\t// Private\n\t\tvar priv_cks = JSON.stringify(ck)\n\t\tvar prkElem = keyDiv.querySelector('.privateKeyText')\n\t\tprkElem.textContent = priv_cks\n\t\tSetQR(priv_cks, keyDiv.querySelector('.privateKeyQR'))\n\n\t\tvar showPKBtn = keyDiv.querySelector('.ShowPrivateKeyBtn')\n\n\t\t// Key buttons\n\t\tlet selectKeyBtn = keyDiv.querySelector('.key_select')\n\t\tlet loginBtns = keyDiv.querySelectorAll('.key_login')\n\t\tlet item = keyDiv.querySelector('.accordion-item')\n\n\t\t// Flag for no login button, for revoke and not in wallet. \n\t\tvar NoLoginBtn = true\n\n\t\tif (!isEmpty(ck.rvk)) {\n\t\t\t// Key is revoked\n\t\t\tShow(keyDiv.querySelector('.revokedKeyTitle'))\n\t\t\titem.title = 'This key is revoked and is unusable.'\n\t\t\titem.classList.add('cyphr-bg-grey')\n\t\t\tkeyDiv.querySelector('.accordion-button').classList.add('cyphr-bg-grey')\n\n\t\t\tkeyDiv.querySelector('.rvk').textContent = await App.UnixToHR(ck.rvk_time)\n\t\t\tShow(keyDiv.querySelector('.rvk').parentElement)\n\t\t\tverifiedElem.innerHTML = revokedIcon\n\n\t\t\tHide(selectKeyBtn)\n\t\t\tHide(deleteKeyBtn)\n\t\t\tHide(revokeKeyBtn)\n\t\t\tHide(addKeyBtn)\n\t\t} else {\n\t\t\t// Key is not revoked\n\t\t\t// Check if key is passed in, but not in wallet.\n\t\t\tif (!isEmpty(ck.niw) && ck.niw === true || (isEmpty(ck.d))) {\n\t\t\t\tShow(keyDiv.querySelector('.niwKeyTitle'))\n\n\t\t\t\titem.title = 'This key is in your account, but not your local wallet.'\n\t\t\t\titem.classList.add('cyphr-bg-warning')\n\t\t\t\tlet accordBtn = keyDiv.querySelector('.accordion-button')\n\t\t\t\taccordBtn.classList.add('cyphr-bg-warning')\n\n\t\t\t\tHide(selectKeyBtn)\n\t\t\t\tHide(showPKBtn)\n\t\t\t\tkeyDiv.querySelector('.pub_key_btns').append(revokeKeyBtn)\n\t\t\t} else {\n\t\t\t\t// In wallet \n\t\t\t\tNoLoginBtn = false\n\n\t\t\t\t// Select key for Signing Button\n\t\t\t\tselectKeyBtn.addEventListener('click', () => setSelectedKey(ck))\n\t\t\t\t// Revoke key from the system\n\t\t\t}\n\n\t\t\trevokeKeyBtn.addEventListener('click', () => {\n\t\t\t\trevokeKeyObject = ck\n\t\t\t\t// Show warning modal if user is revoking only key.\n\t\t\t\tif (Object.keys(App.Keys).length == 1) {\n\t\t\t\t\tdocument.querySelector('.revokeOnlyKeyContinueBtn').addEventListener('click', () => revokeKeyModal.toggle())\n\t\t\t\t\trevokeOnlyKeyModal.toggle()\n\t\t\t\t} else {\n\t\t\t\t\trevokeKeyModal.toggle()\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Delete key from the system\n\t\t\tdeleteKeyBtn.addEventListener('click', () => {\n\t\t\t\tsystemKeyDeleteTmb = ck.tmb\n\t\t\t\tsystemKeyModal.toggle()\n\t\t\t})\n\n\t\t} // End of non revoked key check\n\n\t\tif (!NoLoginBtn) {\n\t\t\t// Login with key button(s)\n\t\t\tloginBtns.forEach((item) => {\n\t\t\t\titem.addEventListener('click', () => {\n\t\t\t\t\t// Use this new key, on success, for GUI and Login internals. \n\t\t\t\t\tApp.Login(ck, initWallets)\n\t\t\t\t})\n\t\t\t\tShow(item)\n\t\t\t})\n\t\t}\n\n\t\t// Copy prk (full text of private key) button\n\t\tkeyDiv.querySelector('.prkCopy').addEventListener('click', () => ClipboardE(prkElem))\n\n\t\t// Toggle private key div\n\t\tlet pkd = keyDiv.querySelector('.privateKeyDiv')\n\t\tshowPKBtn.addEventListener(\"click\", () => {\n\t\t\tToggleVisible(pkd)\n\t\t})\n\n\t\t// Set the mailto to the private key\n\t\tkeyDiv.querySelector('.prikEmail').href = \"mailto:?subject=My%20Cyphr.me%20Private%20Key%20-%20Key%20ID%3A\" + ck.kid + \"&body=Hello%20from%20Cyphr.me%2C%0A%0ABelow%20is%20your%20private%20key.%20%20Be%20sure%20to%20keep%20it%20safe.%20%20Anyone%20with%20your%20key%20can%20pretend%20to%20be%20you.%20%20%0A%0A%0A%0A\" + priv_cks\n\n\t} // End of not a thumbprint only Coze Key section.\n\n\n\t/////////////////\n\t// Wallet\n\t////////////////\n\tlet walletID = await CreateWalletGUI(ck.uad)\n\tWallets[walletID].push(ck) // Add key to app wallet state.\n\tdocument.querySelector(\"#\" + walletID + \" .card-body\").append(keyDiv)\n\n\treturn ck\n}\n\n\n/**\nCreateWalletGUI Creates a wallet on the page. If the wallet has already been\ngenerated this function does nothing.\n\nIf a the id passed in is empty, the wallet is assumed to be a wallet that\ncontains only local keys, and has the HTML Element id: cardno_account_wallet\n\nEmpty wallet is legitimate.\n\nReturns the HTML ID for the wallet, which should also be the same key/id for the\nno account wallet in local storage. The HTML ID is the wallet ID prepended with\n'wallet_'.\n@param {B64} id B64 ID of the wallet.\n@returns {string}\n */\nasync function CreateWalletGUI(id) {\n\tlet walletName = \"\"\n\tlet selected = \"\"\n\n\tlet isNoWallet = false // Whether current wallet is the no account wallet.\n\tlet noWalletOnly = false // Whether page only has the no account wallet.\n\tlet walletLoggedIn = false // Whether wallet is the currently logged in wallet.\n\n\t// No account\n\tif (isEmpty(id) || id === \"wallet_no_account\") {\n\t\tisNoWallet = true\n\t\twalletName = \"No account\"\n\t\tid = \"wallet_no_account\" // id/key used for GUI as well as local storage\n\t} else {\n\t\t// Populate wallet name with account display name is present.\n\t\twalletName = id.substring(0, 6) + '...'\n\t\tif (!isEmpty(App.Accounts[id]) && !isEmpty(App.Accounts[id].display_name)) {\n\t\t\twalletName = App.Accounts[id].display_name\n\t\t}\n\t\t// Add a star if in use.\n\t\tif (App.UAD == id) {\n\t\t\twalletLoggedIn = true\n\t\t\tselected = starIcon\n\t\t}\n\t}\n\n\tlet htmlID = id // Make copy to not modify original.\n\tif (htmlID.substring(0, 7) !== \"wallet_\") {\n\t\thtmlID = 'wallet_' + htmlID\n\t}\n\n\t// Expand No Account wallet if the user is not logged in or if only 1 key\n\t// exists locally.\n\tif (isEmpty(App.UAD) || Object.keys(App.Keys).length <= 1) {\n\t\t// console.log(\"UAD Is Empty BOB\")\n\t\tShow(document.querySelector('#wallet_no_account .card-hide'))\n\t\tnoWalletOnly = true\n\t}\n\n\t// Check if wallet already exists.\n\tif (htmlID in Wallets) {\n\t\treturn htmlID\n\t}\n\tvar walletDiv = await document.querySelector('#WalletRow').content.cloneNode(true)\n\n\t// Set Wallet address in Advanced.\n\twalletDiv.querySelector('.inputWalletAddress').value = id\n\twalletDiv.querySelector('.copyWalletAddress').addEventListener('click', (e) => {\n\t\te.preventDefault()\n\t\tClipboardS(id)\n\t\tApp.Notification(\"Copied account \" + id + \" to clipboard.\", 'success')\n\t})\n\tlet displayNameInput = walletDiv.querySelector('.inputDisplayName')\n\tdisplayNameInput.value = walletName\n\twalletDiv.querySelector('.updateDisplayName').addEventListener('click', async (e) => {\n\t\te.preventDefault()\n\t\tif (isEmpty(displayNameInput.value)) {\n\t\t\tApp.Error(\"Display name cannot be empty.\")\n\t\t}\n\t\t/** @type {Profile} */\n\t\tlet profile = App.GetProfile()\n\t\tprofile.display_name = displayNameInput.value\n\n\t\tlet formData = new FormData()\n\t\tformData.append('coze', JSON.stringify(await App.ProfileUpdate(profile)))\n\t\tlet parsd = await App.FetchPost(App.API.Post.Profile, formData)\n\t\tif (isEmpty(parsd)) {\n\t\t\treturn\n\t\t}\n\n\t\t// ZAMI review:\n\t\t//\n\t\t// This was the existing function/way to accomplish the update, but this\n\t\t// updates the entire account in AccountDetails and Account instead of\n\t\t// just the display name: await App.SetLocalAccount(parsd.ob)\n\t\t//\n\t\t// Created UpdateLocalAccountDisplayName which only updates the display\n\t\t// name. If this is unnecessary, we can just delete this and call\n\t\t// SetLocalAccount().\n\t\tApp.UpdateLocalAccountDisplayName(parsd.obj)\n\t\tinitWallets()\n\t\tApp.Notification('Successfully updated display name', 'success')\n\t})\n\n\tdisplayNameMap[walletName] = id\n\twalletName = selected + walletName\n\tWallets[htmlID] = [] // init wallet as array.\n\n\twalletDiv.querySelector(\".card\").id = htmlID\n\tlet walletNameElem = walletDiv.querySelector(\".walletName\")\n\twalletNameElem.innerHTML = walletName\n\tif (walletName === \"No account\") {\n\t\twalletNameElem.classList.add(\"text-warning\")\n\t}\n\n\t// Don't expand any wallets that are not logged in. No Account wallet is the\n\t// exception, for users that only have that wallet, or are not logged in.\n\tif (!walletLoggedIn && !noWalletOnly) {\n\t\tHide(walletDiv.querySelector(\".card-hide\"))\n\t}\n\n\t// Callback for Collapse().\n\tlet callback = () => {\n\t\tif (!document.querySelector(\"#\" + htmlID + \" .card-hide\").hidden) {\n\t\t\texpandedWallets[htmlID] = ''\n\t\t} else {\n\t\t\tdelete expandedWallets[htmlID]\n\t\t}\n\t}\n\tApp.Collapse(walletDiv.querySelector(\".card-header\"), walletDiv.querySelector(\".card-hide\"), callback)\n\n\t// Keep this as a variable. JavaScript was buggy when putting this directly into ToggleVisible().\n\tlet optsDiv = walletDiv.querySelector('.walletAdvancedOpts')\n\twalletDiv.querySelector('.walAdvOptsBtn').addEventListener('click', () => ToggleVisible(optsDiv))\n\twalletDiv.querySelector('.deleteWalletBtn').addEventListener('click', (item) => {\n\t\tselectedWalletID = id\n\t\tlocalWalletModal.toggle()\n\t})\n\n\t// Append account to links\n\tlet userActiveKeysElem = walletDiv.querySelector(\".user_active_keys\")\n\tlet userRevokedKeysElem = walletDiv.querySelector(\".user_revoked_keys\")\n\tlet syncAcctBtn = walletDiv.querySelector('.syncAccountBtn')\n\tif (!isNoWallet) {\n\t\tuserActiveKeysElem.href = userActiveKeysElem.href + \"/\" + id\n\t\tuserRevokedKeysElem.href = userRevokedKeysElem.href + \"/\" + id\n\t\t// Sends request to the server to sync the user's account state.\n\t\tsyncAcctBtn.addEventListener('click', () => SyncAccount(id))\n\t} else {\n\t\tHide(userActiveKeysElem)\n\t\tHide(userRevokedKeysElem)\n\t\tHide(walletDiv.querySelector('.account_id'))\n\t\tHide(walletDiv.querySelector('.edit_display_name'))\n\t\tHide(syncAcctBtn)\n\t\tShow(walletDiv.querySelector(\".syncKeysBtn\"))\n\n\t\t// Set Sync Keys button for wallet.\n\t\twalletDiv.querySelector('.syncKeysBtn').addEventListener('click', () => syncAllKeys(Wallets[htmlID]))\n\t}\n\n\twalletDiv.querySelector(\".importKeyBtn\").addEventListener(\"click\", (item) => {\n\t\t// Set Selected Account to be the current wallet.\n\t\tdocument.getElementById(\"AccountSelect\").value = id\n\t\timportPrivateKey(item.target.parentElement.querySelector('.importKeyInput').value)\n\t})\n\n\t// QR scanning modal.\n\tconst importKeyInput = walletDiv.querySelector(\".importKeyInput\")\n\twalletDiv.querySelector(\".scanQRBtn\").addEventListener(\"click\", (item) => {\n\t\tconsole.log(\"Start scan QR\")\n\t\tscanQRModal.toggle()\n\t\tlet videoElem = document.getElementById(\"scanQRVideo\")\n\n\t\tconst qrScanner = new QrScanner(\n\t\t\tvideoElem,\n\t\t\tresult => scanQRCallback(result), {\n\t\t\t\thighlightScanRegion: true,\n\t\t\t},\n\t\t)\n\n\t\tfunction scanQRCallback(result) {\n\t\t\tconsole.log('decoded qr code:', result)\n\t\t\tscanQRModal.toggle()\n\t\t\timportKeyInput.value = result.data\n\t\t}\n\n\t\t// Stop scanning when the modal is closed. (The bootstrap modal object is\n\t\t// not the html element, so select it by ID. )\n\t\tdocument.getElementById('scanQRModal').addEventListener('hidden.bs.modal', event => {\n\t\t\tqrScanner.stop()\n\t\t})\n\n\t\tqrScanner.start()\n\t})\n\n\t// Button for exporting the User's wallet to a json file.\n\twalletDiv.querySelector('.exportWalletBtn').addEventListener('click', () => App.DownloadWallet(Wallets[htmlID], id))\n\n\t// Add logged in wallet as first child.\n\tif (walletLoggedIn) {\n\t\tlet s = walletDiv.querySelector(\".bi-plus-square\")\n\t\t// Set correct icons for expanded wallet and add to beginning of GUI wallets.\n\t\ts.classList.remove(\"bi-plus-square\")\n\t\ts.classList.add(\"bi-dash-square\")\n\t\tdocument.querySelector(\"#wallets\").prepend(walletDiv)\n\t\texpandedWallets[htmlID] = ''\n\t} else {\n\t\tdocument.querySelector(\"#wallets\").append(walletDiv)\n\t}\n\n\treturn htmlID\n}\n\n/**\nsetPublicKeyQrCode sets the QR code for the public key being used by the\napplication.\n@param {string} payload Payload being applied to the QR code.\n@param {Element} element HTML Element on the page.\n@returns {void}\n */\nasync function SetQR(payload, element) {\n\tlet QRC = qrgen.QrCode\n\tlet qr0 = QRC.encodeText(payload, QRC.Ecc.LOW)\n\tlet qrElem = document.createElement('div')\n\tqrElem.setAttribute('value', payload)\n\n\t// Second parameter is boarder. \n\t// Values 0-4\n\tlet svg = qr0.toSvgString(2)\n\tqrElem.innerHTML = svg\n\n\tlet containerElem = document.createElement('div')\n\tcontainerElem.append(qrElem)\n\telement.innerHTML = ''\n\telement.append(containerElem)\n}\n\n/**\nEditKid makes the text area for the key's kid editable.\n@param {Element} element HTML text area\n@returns {void}\n */\nfunction EditKid(element) {\n\tlet g = element.parentElement.parentElement\n\tToggleVisible(g.querySelector(\".kidEdit\"))\n\tg.querySelector(\".kidEditInput\").value = element.innerText\n}\n\n/**\nSaveKid saves the text in the text area for the key's kid.\n@param {Element} e HTML text area.\n@param {B64} tmb Thumbprint of the key being edited.\n@returns {void}\n */\nasync function SaveKid(e, tmb) {\n\tawait App.UpdateKid(tmb, e.parentElement.parentElement.querySelector(\".kidEditInput\").value)\n\tinitWallets()\n}\n\n/**\nsetSelectedKey is used to select a given Coze key from a User's wallet, which is\nthen used as the selected key for the application. It is what's used for\n'actions' on the application.\n@param {CozeKey} ck\n@returns {void}\n@throws {error}\n */\nasync function setSelectedKey(ck) {\n\tlet set = await App.SetSelectedKey(ck)\n\tif (!set) {\n\t\tApp.Error(\"Could not set key.\")\n\t\treturn\n\t}\n\tsetSelectGui(ck.tmb)\n}\n\n/**\nsetSelectGui sets a star next to the currently selected key.\n@param {Tmb} tmb Thumbprint of current selected key.\n@returns {void}\n@throws {error}\n */\nfunction setSelectGui(tmb) {\n\t// console.debug(tmb)\n\tdocument.querySelectorAll('.selected').forEach((item) => {\n\t\titem.innerHTML = \"\"\n\t})\n\tlet h = document.getElementById('headercollapseKey' + tmb)\n\tif (h === null) {\n\t\tthrow new Error(\"Key header not found\")\n\t}\n\tselected.innerHTML = starIcon\n\tselected.title = \"Selected key\"\n}\n\n\n/**\nsyncAllKeys syncs all keys (up to 50) from Cyphr.me (if they exist) for the\ngiven keys, and returns an array of the current keys' public state.\n@param {CozeKey[]} keys Coze Keys being synced.\n@returns {void}\n */\nasync function syncAllKeys(keys) {\n\tlet tmbs = []\n\tfor (let key of keys) {\n\t\tif (isEmpty(key.tmb)) {\n\t\t\tthrow new Error(\"tmb in key is empty\")\n\t\t}\n\t\ttmbs.push(key.tmb)\n\t}\n\n\tif (isEmpty(tmbs)) {\n\t\tApp.Notification(\"No thumbprints given for syncing key(s).\", 'error')\n\t\treturn\n\t}\n\n\tlet formData = new(FormData)\n\tformData.append('tmbs', tmbs)\n\tlet response = await App.FetchPost(App.API.Post.KeyUploaded, formData)\n\tconsole.debug(response)\n\t// Successful requests, but no keys exist in system.\n\tif (!isEmpty(response.obj) && !isEmpty(response.obj.keys)) {\n\t\t// console.debug(response.obj)\n\n\t\t// kills only wallet styling and not actual keys fields\n\t\tawait clearWalletStyling()\n\n\t\t// Sets all local keys' `uad` to null.\n\t\tawait clearAppKeysUAD()\n\t\tawait setKeysState(response.obj.keys)\n\t\tawait App.UpdateAccountDisplayNames(response.obj.accounts)\n\t}\n\tinitWallets()\n\tApp.Notification('Successfully synced keys', 'success')\n\n}\n\n\n/**\nSyncAccount downloads all active keys from Cyphr.me related to the account into\nthe wallet. If there are local keys in the wallet that are not returned by the\nserver, those keys are moved to the \"No Account\" wallet.\n@param {B64} uad UAD of the account being synced.\n@returns {void}\n */\nasync function SyncAccount(uad) {\n\tconsole.log(\"SyncAccount\", uad)\n\tif (isEmpty(uad)) {\n\t\tif (isEmpty(App.UAD)) {\n\t\t\tApp.Notification(\"Must be logged in to sync account.\", 'error')\n\t\t\treturn\n\t\t}\n\t\tuad = App.UAD\n\t}\n\n\tconsole.log(App.API.Get.DisplayName + \"/\" + uad)\n\t// Get display name for account then get keys. Encapsulating request inside\n\t// the first avoids possible race for display name map. // TODO use fetch. \n\tlet response = await App.Fetch(App.API.Get.DisplayName + \"/\" + uad)\n\t// console.debug(response)\n\tfor (let key in response) {\n\t\tlet k = key.substring(0, 6) + '...'\n\t\tdisplayNameMap[k] = response[key]\n\t}\n\n\tlet keyResponse = await App.Fetch(App.API.Get.UserKeys + \"/\" + uad)\n\t// console.debug(keyResponse)\n\tApp.UpdateAccountDisplayNames(response)\n\tawait setKeysState(keyResponse.rec)\n\tfor (let lk of Wallets['wallet_' + uad]) {\n\t\tlet found = false\n\t\tfor (let sk of keyResponse.rec) {\n\t\t\tif (lk.tmb == sk.id) {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\t// Move key to no account if not found and not revoked. User active key and\n\t\t// revoked keys are separate endpoints, and the non revoked endpoint is\n\t\t// being used, so revoked keys are not returned by the server on sync\n\t\t// account.\n\t\tif (!found && (isEmpty(lk.rvk) || lk.rvk <= 0)) {\n\t\t\tlk.uad = null\n\t\t\tApp.UpsertGlobalKey(lk)\n\t\t}\n\t}\n\tinitWallets()\n\tApp.Notification('Successfully synced account', 'success')\n}\n\n\n/**\ndeleteLocalKey accepts a key thumbprint as a string, and removes it from\nlocal storage. If the key being removed is the current active key, a second\nwarning modal is triggered.\n@param {Tmb} tmb Key thumbprint being removed from localstorage.\n@returns {void}\n */\nasync function deleteLocalKey(tmb) {\n\tif (isEmpty(tmb)) {\n\t\tconsole.debug('id passed in empty')\n\t\treturn\n\t}\n\n\t// If attempting to delete key that is user is logged in with, trigger a\n\t// secondary warning modal to ensure the user meant to perform the action.\n\tif (!isEmpty(App.CozeKey) && App.CozeKey.tmb == tmb) {\n\t\tlocalLoggedInKeyModal.toggle()\n\t\treturn\n\t}\n\tdeleteKey(tmb)\n}\n\n/**\ndeleteKey deletes a key from local storage and from the GUI, then displays a\nsuccess message.\n@param {Tmb} tmb Key thumbprint being deleted.\n@returns {void}\n */\nasync function deleteKey(tmb) {\n\ttry {\n\t\tawait App.DeleteKey(tmb)\n\t\tdocument.getElementById(\"headercollapseKey\" + tmb).remove()\n\t\tApp.Notification(\"Successfully removed key from local storage.\")\n\t} catch (error) {\n\t\tApp.Error(error)\n\t}\n}\n\n/**\ndeleteKeyFromSystem accepts a key thumbprint as a string, and removes it from\nCyphr.me. Sends key to be deleted, along with the action of the notary deleting\nthe key.\n\nCallback takes server response and shows a notification on the page if the\nserver sends back an error. Otherwise, takes the key tmb that was deleted, and\nremove that accordion/key from the page.\n@param {Tmb} tmb Thumbprint of the key being removed from the system.\n@returns {void}\n */\nasync function deleteKeyFromSystem(tmb) {\n\tif (isEmpty(App.UAD)) {\n\t\tApp.Error(App.Err.AccountIDNotSet)\n\t}\n\tlet formData = new(FormData)\n\tformData.append(\"coze\", JSON.stringify(await App.KeyDelete(tmb)))\n\tlet parsd = await App.FetchPost(App.API.Post.DeleteKey, formData)\n\t// console.debug(parsd)\n\tlet verifiedElem = document.getElementById('headercollapseKey' + parsd.obj).querySelector('.verified')\n\tverifiedElem.innerHTML = redExIcon\n\tverifiedElem.title = \"Key not verified by Cyphr.me\"\n\tApp.Keys[parsd.obj].time = 0\n\tawait App.UpsertGlobalKey(App.Keys[parsd.obj])\n\tApp.Notification(\"Key has been removed from Cyphr.me, but still exists locally in your browser. Click the delete locally button for complete removal.\", 'success')\n}\n\n/**\ndeleteLocalWallet deletes the currently selected Wallet and all of the keys\nwithin the wallet. If the wallet is the current logged in wallet, a warning\nmodal is triggered.\n@returns {void}\n */\nfunction deleteLocalWallet() {\n\t// If wallet is currently logged in, display warning modal.\n\tif (selectedWalletID === App.UAD) {\n\t\tlocalLoggedInWalletModal.toggle()\n\t\treturn\n\t}\n\tdeleteWallet()\n}\n\n/**\ndeleteWallet deletes the currently selected Wallet and all of the keys within\nthe wallet. Removes the Wallet/Keys from the GUI, and the application's local\nstorage.\n@returns {void}\n */\nasync function deleteWallet() {\n\ttry {\n\t\tfor (let key of Wallets['wallet_' + selectedWalletID]) {\n\t\t\tawait deleteKey(key.tmb) // Does not catch thrown error without await.\n\t\t}\n\t} catch (error) {\n\t\tApp.Error(error)\n\t}\n\n\tawait App.DeleteLocalAccount(selectedWalletID)\n\tinitWallets()\n\tApp.Notification(\"Successfully removed wallet and keys from local storage.\", \"success\")\n}\n\n/**\nrevokeKey signs a revoke message for the given key, and send the request to the\nserver to be processed. The success/fail from the response is handled in the\nrevokeKeyCallback.\n\nOther revoke: for when a key signs a revoke message for another key. This should\nonly be performed if a self revoke is not possible, or the key has been leaked,\nand another person is revoking the key. Calling this function uses the key that\nis currently selected for signing. The key used for signing must still be owned\nby the person who owns the key being revoked.\n\nSelf revoke: Signs a revoke message for the given key, to revoke itself.\n\ncallback Handles the server response for revoking a key.\n@param {CozeKey} cozeKey Key being revoked from the system.\n@param {string} [msg] Optional reason for revoking the key.\n@returns {void}\n */\nasync function revokeKey(cozeKey, msg) {\n\tif (isEmpty(App.UAD)) {\n\t\tApp.Error(App.Err.AccountIDNotSet)\n\t}\n\ttry {\n\t\tlet coze\n\t\tlet uri = \"\"\n\n\t\t// Other revoke\n\t\tif (cozeKey.tmb !== App.CozeKey.tmb || (!isEmpty(cozeKey.niw) && (cozeKey.niw === 'true' || cozeKey.niw === true))) {\n\t\t\tcoze = await App.KeyOtherRevoke(cozeKey.tmb, msg)\n\t\t\turi = App.API.Post.RevokeKeyOther\n\t\t} else {\n\t\t\t// Self revoke\n\t\t\turi = App.API.Post.RevokeKey\n\t\t\tcoze = await App.KeyRevoke(cozeKey, msg)\n\t\t}\n\t\tlet formData = new(FormData)\n\t\tformData.append(\"coze\", JSON.stringify(coze))\n\t\tlet parsd = await App.FetchPost(uri, formData)\n\t\tlet item = document.getElementById('headercollapseKey' + parsd.obj.tmb)\n\t\titem.title = 'This key is revoked and is unusable.'\n\t\titem.classList.add('cyphr-bg-danger')\n\n\t\tApp.Keys[parsd.obj.tmb].rvk = parsd.obj.rvk\n\t\tawait App.UpsertGlobalKey(App.Keys[parsd.obj.tmb])\n\t\tApp.Notification(\"Key has successfully been revoked.\", 'success')\n\t} catch (e) {\n\t\tconsole.error(e)\n\t\tApp.Error(\"Could not revoke the key. Make sure you are the owner.\")\n\t}\n}\n\n/**\nGenerates a new key, with the selected alg and account. Adds the key to the\nglobal application state, local storage, and GUI. This sets the key twice, first\nwhen calling GlobalNewKey(), and then again to set the uad on the key (if\napplicable).\n@param {boolean} [select]\n@returns {void}\n */\nasync function genNewKey(select) {\n\tlet ck = await App.GlobalNewKey(SelectedAlg)\n\tif (select == true) {\n\t\tconsole.log(\"Setting as selected: \", ck)\n\t\tlet set = await App.SetSelectedKey(ck)\n\t\tif (!set) {\n\t\t\tApp.Error(\"Could not set key.\")\n\t\t\treturn\n\t\t}\n\t}\n\tlet selectedAccount = document.getElementById(\"AccountSelect\").value\n\t// Set UAD if selected option is not `No Account`.\n\tif (selectedAccount !== \"wallet_no_account\") {\n\t\tck.uad = displayNameMap[selectedAccount]\n\t}\n\tcreateKeyDiv(ck)\n\tApp.UpsertGlobalKey(ck)\n\tlet accountCopy = App.AccountDetails\n\taccountCopy.backup = false\n\tawait App.SetLocalAccount(accountCopy)\n\tlet st = ck.alg + \":\" + ck.tmb\n\tClipboardS(st)\n\tApp.Notification(st + \" copied to clipboard.\", \"success\")\n\tHide(\"emptyWallet\")\n}\n\n/**\nimportPrivateKey imports a private key to be set for the application. This\nreplaces the current key, if one is already set, unless the key trying\nto be added is a thumbprint only key.\n *\nValid supported formats include:\n\n- Array of objects (keys)\n- Object of named objects (keys)\n- Object (single key)\n- Serialized format (single key). See more on serialized formats below.\n\nSerialized formats:\nCoze key serialized:\nalg:d:x:tmb\n- (ES256:bNstg4_H3m3SlROufwRSEgibLrBuRq9114OvdapcpVA:2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g:cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk)\n\nCan be shorted to public:\n\nalg:x:tmb\n- (ES256:2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g:cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk)\n\nWhich can be shortened to just thumbprint:\nalg:tmb\n- (ES256:cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk)\n\nWith x and no tmb\nalg:x:\n- (ES256:2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g:)\n\nWith just d:\nalg:d::\n- (ES256:bNstg4_H3m3SlROufwRSEgibLrBuRq9114OvdapcpVA::)\n\nAlthough a serialized format is only supported as a single key, multiple\nkeys can be imported in a serialized format, delimitted by lines.\nE.g. :\n- (ES256:cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk)\n- (ES256:cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk)\n@throws {SyntaxError} JSON parse exception.\n@returns {void} Imports a new private key and sets it for the application.\n */\nasync function importPrivateKey(inKey) {\n\tconsole.log(\"Importing key:\", inKey)\n\ttry {\n\t\tif (isEmpty(inKey)) {\n\t\t\tApp.Error(\"Import key area is blank. Doing nothing.\", 'error')\n\t\t}\n\n\t\t// Array of CozeKeys that are used as the processing format that all\n\t\t// supported formats should conform to.\n\t\tvar czs = []\n\n\t\t// Normalize different supported JSON formats into a valid JSON array.\n\t\t// Check if in Thumbprint Serialized form.\n\t\tif (isSerializedForm(inKey)) {\n\t\t\tczs = getCozeKeysFromSerializedForm(inKey)\n\t\t\tif (isEmpty(czs)) {\n\t\t\t\tApp.Error(\"CozeKey from serialized format returned nil.\", 'error')\n\t\t\t}\n\t\t} else {\n\t\t\tlet parsd = JSON.parse(inKey)\n\t\t\t// Restringify import area to remove possible JSON formatting/prettifying \n\t\t\t// to ensure we can access first character.\n\t\t\tlet parsds = JSON.stringify(parsd)\n\t\t\t// Check if in Array\n\t\t\tif (parsds.charAt(0) === \"[\") {\n\t\t\t\tvar czs = JSON.parse(inKey)\n\t\t\t\t// Check if in object\n\t\t\t} else if (parsds.charAt(0) === \"{\") {\n\t\t\t\t// Check for named objects.\n\t\t\t\tlet namedObj = false\n\t\t\t\tfor (let key of Object.keys(parsd)) {\n\t\t\t\t\tif (App.IsCyphrmeDigest(key)) {\n\t\t\t\t\t\tnamedObj = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (namedObj) {\n\t\t\t\t\tczs = Object.values(parsd)\n\t\t\t\t} else {\n\t\t\t\t\t// Object. Assume one key. \n\t\t\t\t\tczs.push(parsd)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet uad = displayNameMap[document.getElementById(\"AccountSelect\").value] // Selected account\n\t\tif (isEmpty(uad)) {\n\t\t\tuad = \"wallet_no_account\"\n\t\t\tconsole.log('\"No account\" selected')\n\t\t}\n\n\t\tfor (var key of czs) {\n\t\t\t// Set account on key\n\t\t\tconsole.log(\"Adding key to account: \", uad)\n\t\t\tkey.uad = uad\n\n\t\t\t// Thumbprint only Coze Keys.\n\t\t\tif (isEmpty(key.x) && isEmpty(key.d)) {\n\t\t\t\tif (!App.IsCyphrmeDigest(key.tmb)) {\n\t\t\t\t\tthrow new Error(\"tmb is not a recognized digest.\")\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tvar parsd = await App.Fetch(App.API.Get.CozeKey + \"/\" + key.tmb)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(error)\n\t\t\t\t}\n\t\t\t\tif (isEmpty(parsd)) { // Key is not in the system.\n\t\t\t\t\tlocalTmb = key\n\t\t\t\t\tlocalTmbModal.toggle()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Keys already in the system\n\t\t\t\tif (parsd.uad != uad) {\n\t\t\t\t\tconsole.log(\"Import uad is different from system UAD. Using import UAD.\")\n\t\t\t\t\tparsd.uad = uad\n\t\t\t\t}\n\t\t\t\tApp.UpsertGlobalKey(parsd)\n\t\t\t\tinitWallets() // Must be called for single key imports\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlet valid = await Coze.Correct(key)\n\t\t\tif (!valid) {\n\t\t\t\tApp.Notification(\"Key '\" + key.tmb + \"' is not a valid Coze Key\", 'error')\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Recalculate Thumbprint.\n\t\t\tkey.tmb = await Coze.Thumbprint(key)\n\t\t\tawait App.UpsertGlobalKey(key)\n\t\t}\n\t} catch (e) {\n\t\tApp.Error(e)\n\t\treturn\n\t}\n\tinitWallets()\n}\n\n/**\nclearWalletStyling clears all styling in the wallet, and set all of the keys to\nthe default style. The default style is with a white background, the key not\nverified icon, and tooltips indicating these styles. A function calling this\nmethod is expected to then set the styles after clearing styling and setting to\ndefault.\n@returns {void}\n */\nasync function clearWalletStyling() {\n\tlet classStyles = [\"cyphr-bg-danger\", \"cyphr-bg-grey\"]\n\tdocument.querySelectorAll('.accordion-item').forEach((item) => {\n\t\tlet verifiedElem = item.querySelector('button').querySelector('.verified')\n\t\tverifiedElem.innerHTML = redExIcon\n\t\tverifiedElem.title = \"Key not verified by Cyphr.me\"\n\t\titem.classList.remove(...classStyles)\n\t})\n}\n\n/**\nClears the `uad` field on all of the locally stored CozeKeys in the application.\n@returns {void}\n */\nasync function clearAppKeysUAD() {\n\tfor (let k in App.Keys) {\n\t\tApp.Keys[k].uad = null\n\t}\n\tApp.UpsertGlobalKeys()\n}\n\n/**\nsetKeyState sets the stateful fields on a key. If the key state has a private\ncomponent, the private components are preserved. Also sets the GUI state for the\nkey.\n@param {Keys} keys\n@returns {void}\n */\nasync function setKeysState(keys) {\n\tfor (let key of keys) {\n\t\tlet tmb = key.id\n\t\tif (isEmpty(tmb)) {\n\t\t\ttmb = key.tmb\n\t\t\tif (isEmpty(tmb)) {\n\t\t\t\tconsole.error(\"cannot resolve key's tmb/id: \", key)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Preserves private component, if present. \n\t\t// Also checks keys for account that are not in local wallet.\n\t\tif (!isEmpty(App.Keys[tmb]) && !isEmpty(App.Keys[tmb].d)) {\n\t\t\tkey.d = App.Keys[tmb].d // preserve private component when updating state\n\t\t} else {\n\t\t\tkey.niw = true // Not in wallet, or don't have private key\n\t\t}\n\t\t//// Sets global key state for application\n\t\tkey.tmb = tmb\n\t\tApp.Keys[tmb] = key\n\t}\n\tApp.UpsertGlobalKeys()\n}\n\n/**\nGrabs each account from the Wallets object and sets the account as an option for\nwhere to place newly generated keys.\n\nIf there are keys in the No Account wallet, this shows the move to account\noptions for each key in the wallet.\n@returns {void}\n */\nfunction setNewKeyAccountGUI() {\n\tlet noAccountSelect = document.getElementById('noAccountSelectOption') // must be set before clear.\n\tlet selectedAccountElem = document.getElementById(\"AccountSelect\")\n\tselectedAccountElem.innerHTML = \"\" // Clear out any existing options before setting.\n\n\t// Set main account select in advanced options\n\tfor (let account in Wallets) {\n\t\tlet id = account.replace('wallet_', '')\n\t\tif (!isEmpty(App.Accounts[id]) && !isEmpty(App.Accounts[id].display_name)) {\n\t\t\taccount = App.Accounts[id].display_name\n\t\t} else {\n\t\t\tif (account === \"wallet_no_account\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\taccount = id.substring(0, 6) + \"...\"\n\t\t}\n\t\tlet optElem = document.createElement(\"option\")\n\t\toptElem.textContent = account\n\t\toptElem.classList.add(\"account\" + id) // Prepend with `account`. Class cannot start with a number.\n\n\t\t// Set the selected account as the currently selected option and move as the\n\t\t// first select option.\n\t\tif (!isEmpty(account) && !isEmpty(App.AccountDetails) && !isEmpty(App.AccountDetails.display_name) && App.AccountDetails.display_name == account) {\n\t\t\tselectedAccountElem.prepend(optElem)\n\t\t\tselectedAccountElem.value = account\n\t\t\toptElem.selected = true\n\t\t\tcontinue\n\t\t}\n\t\tselectedAccountElem.append(optElem)\n\t}\n\n\t// Append No Account as last option and denote special with yellow text\n\tShow(noAccountSelect)\n\tselectedAccountElem.append(noAccountSelect)\n\n\t// Helper for reusing logic.\n\tlet appendToKey = (item, id, elem) => {\n\t\tlet accountFormElem = item.querySelector('.formAccount')\n\t\t// console.debug(accountFormElem)\n\t\tShow(accountFormElem)\n\n\t\taccountFormElem.querySelector('label').setAttribute(\"for\", elem.id)\n\n\t\t// Button for moving key to a selected account.\n\t\tlet moveKeyBtn = accountFormElem.querySelector('button')\n\t\tmoveKeyBtn.dataset.keyID = id\n\t\tmoveKeyBtn.addEventListener('click', (e) => {\n\t\t\tlet uad = displayNameMap[elem.value]\n\t\t\tif (isEmpty(uad) || !App.IsCyphrmeDigest(uad)) {\n\t\t\t\tApp.Error(\"Could not resolve the selected account.\", \"error\")\n\t\t\t}\n\t\t\tApp.Keys[e.target.dataset.keyID].uad = uad\n\t\t\tApp.UpsertGlobalKeys()\n\t\t\tinitWallets()\n\t\t})\n\t\taccountFormElem.prepend(elem)\n\t}\n\n\t// Avoid pulling/comparing each time in for loop below.\n\tlet isNoAccountWalletNull = document.getElementById('wallet_no_account') === null\n\n\t// Set account select option in applicable keys.\n\tfor (let k in App.Keys) {\n\t\tlet key = App.Keys[k]\n\t\tlet keyElem = document.querySelector('#headercollapseKey' + key.tmb)\n\t\t// Keys in no account wallet.\n\t\tif (isEmpty(key.uad) || key.uad === \"wallet_no_account\") {\n\t\t\tif (isNoAccountWalletNull) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlet clone = selectedAccountElem.cloneNode(true)\n\t\t\tclone.id = key.tmb.substring(0, 6)\n\t\t\tclone.querySelector('#noAccountSelectOption').remove()\n\t\t\tappendToKey(keyElem, key.tmb, clone)\n\t\t\tcontinue\n\t\t}\n\t\t// Keys in wallet other than no account wallet that are not yet added to the\n\t\t// system.\n\t\tif (isEmpty(key.time)) {\n\t\t\tlet clone = selectedAccountElem.cloneNode(true)\n\t\t\tclone.id = key.tmb.substring(0, 6)\n\t\t\tclone.querySelector('.account' + key.uad).remove()\n\t\t\tappendToKey(keyElem, key.tmb, clone)\n\t\t}\n\t}\n}\n\n/**\nReturns whether or not the given string is a valid, serialized CozeKey format.\nReturns false when given serialization is not a string\n@param {string} s\n@returns {boolean}\n */\nfunction isSerializedForm(s) {\n\tif (typeof s !== \"string\") {\n\t\treturn false\n\t}\n\n\t// Do processing line by line, as we support line delimitted serializations.\n\tfor (let line of s.split(\"\\n\")) {\n\t\tlet splits = line.split(\":\")\n\t\tif (splits.length > 4 || splits.length === 0) {\n\t\t\treturn false\n\t\t}\n\t\tlet fam\n\t\ttry {\n\t\t\tfam = Coze.Family(splits[0]) // throws\n\t\t} catch (error) {\n\t\t\t// do nothing\n\t\t}\n\t\tif (fam !== \"EC\") {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n/**\nReturns an Array of CozeKey objects from the given serialized format.\nSee importPrivateKey() for more on serialization formats.\nReturns nil on failure.\n\nCalling isSerializedForm() before ensures the input is proplery formatted.\n@param {string} s CozeKey in a stringed, serialized form.\n@returns {CozeKey[]}\n */\nfunction getCozeKeysFromSerializedForm(s) {\n\tlet czs = []\n\tfor (let line of s.split(\"\\n\")) {\n\t\tlet splits = line.split(\":\")\n\n\t\tlet ck = {\n\t\t\talg: splits[0]\n\t\t}\n\n\t\tswitch (splits.length) {\n\t\t\tcase 2: // Only alg:tmb have 1 delimiter (2 sides to delim).\n\t\t\t\tck.tmb = splits[1]\n\t\t\t\tbreak\n\t\t\tcase 3: // alg:x:tmb & alg:x: have 2 delimiters.\n\t\t\t\tck.x = splits[1]\n\t\t\t\tif (!isEmpty(splits[2])) {\n\t\t\t\t\tck.tmb = splits[2]\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tcase 4: // alg:d:x:tmb & alg:d:: have 3 delimiters.\n\t\t\t\tck.d = splits[1]\n\t\t\t\tif (!isEmpty(splits(2))) {\n\t\t\t\t\tck.x = splits[2]\n\t\t\t\t}\n\t\t\t\tif (!isEmpty(splits(3))) {\n\t\t\t\t\tck.tmb = splits[3]\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t}\n\t\tczs.push(ck)\n\t}\n\treturn czs\n}\n\n/**\npowerMode toggles simpleMode vs powerMode If bool is nil, powerMode toggles.\n@param {boolean} [bool]\n */\nfunction powerMode(bool) {\n\tlet pm = document.querySelector(\"#power\")\n\n\tif (bool === true) {\n\t\tpm.checked = true\n\t}\n\tif (bool === false) {\n\t\tpm.checked = false\n\t}\n\n\tif (pm.checked) {\n\t\tShow(\"powerMode\")\n\t\tHide(\"simpleMode\")\n\t} else {\n\t\tHide(\"powerMode\")\n\t\tShow(\"simpleMode\")\n\t}\n}"], "mappings": "AAEA,UAAYA,MAAS,gCACrB,UAAYC,MAAU,qCACtB,MAAO,kCACP,MAAO,oCACP,OAAOC,OAAe,2BAsCtB,IAAIC,EAEAC,EAAU,CAAC,EACXC,EACAC,EAAiB,GAGjBC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAMAC,EAAiB,CAAC,EAMlBC,EAAkB,CAAC,EAGvB,MAAMC,GAAqB,8CACrBC,EAAY,iDACZC,EAAW,gDACXC,GAAc,6DAgBdC,GAAc,CACnB,eAAkB,CAAC,CACjB,KAAQ,aACR,GAAM,eACP,EACA,CACC,KAAQ,SACR,KAAQ,OACR,SAAYC,EACZ,aAAgB,EACjB,EACA,CACC,KAAQ,WACR,KAAQ,OACR,SAAY,IAAM,cAAc,UAAU,EAC1C,aAAgB,EACjB,EACA,CACC,KAAQ,QACR,GAAM,QACN,KAAQ,OACR,YAAe,GACf,SAAY,IAAMC,GAAU,EAAI,CACjC,EAMA,CACC,KAAQ,YACR,KAAQ,OACR,SAAY,IAAM,CACjB,QAAQ,IAAI,cAAc,EAC1BtB,EAAiB,EAClB,EACA,aAAgB,EACjB,CAED,CACD,EAEAN,EAAI,UAAU6B,EAAY,EAE1B,eAAeA,IAAe,CAC7B1B,EAAc,SAAS,cAAc,cAAc,EAAE,MAGrD,IAAI2B,EAAY,CACf,SAAU,EACX,EAEAvB,EAAc,IAAI,UAAU,MAAM,SAAS,eAAe,aAAa,EAAGuB,CAAS,EACnFjB,EAAgB,IAAI,UAAU,MAAM,SAAS,eAAe,qBAAqB,EAAGiB,CAAS,EAC7FhB,EAAwB,IAAI,UAAU,MAAM,SAAS,eAAe,oCAAoC,EAAGgB,CAAS,EACpHnB,EAAiB,IAAI,UAAU,MAAM,SAAS,eAAe,sBAAsB,EAAGmB,CAAS,EAC/FtB,EAAiB,IAAI,UAAU,MAAM,SAAS,eAAe,gBAAgB,EAAGsB,CAAS,EACzFpB,EAAqB,IAAI,UAAU,MAAM,SAAS,eAAe,oBAAoB,EAAGoB,CAAS,EACjGd,EAAgB,IAAI,UAAU,MAAM,SAAS,eAAe,4BAA4B,EAAGc,CAAS,EACpGZ,EAAmB,IAAI,UAAU,MAAM,SAAS,eAAe,mBAAmB,EAAGY,CAAS,EAC9FX,EAA2B,IAAI,UAAU,MAAM,SAAS,eAAe,2BAA2B,EAAGW,CAAS,EAG9G,SAAS,cAAc,QAAQ,EAAE,iBAAiB,QAASF,EAAS,EAGpE,SAAS,iBAAiB,YAAY,EAAE,QAASG,GAASA,EAAK,iBAAiB,QAAS,IAAMC,EAAU,CAAC,CAAC,EAE3G,SAAS,iBAAiB,mBAAmB,EAAE,QAASD,GAASA,EAAK,iBAAiB,QAAS,IAAMC,EAAU,EAAI,CAAC,CAAC,EAGtH,SAAS,iBAAiB,qBAAqB,EAAE,QAASD,GAASA,EAAK,iBAAiB,QAAS,IAAM/B,EAAI,eAAeA,EAAI,IAAI,CAAC,CAAC,EAGrI,SAAS,cAAc,yBAAyB,EAAE,iBAAiB,QAAS,IAAM2B,EAAiB,SAAS,cAAc,gBAAgB,EAAE,KAAK,CAAC,EAGlJ,SAAS,cAAc,yBAAyB,EAAE,iBAAiB,QAAS,IAAMM,GAAelB,CAAiB,CAAC,EAGnH,SAAS,cAAc,mCAAmC,EAAE,iBAAiB,QAAS,IAAMmB,EAAUnB,CAAiB,CAAC,EAGxH,SAAS,cAAc,0BAA0B,EAAE,iBAAiB,QAAS,IAAMoB,GAAoBvB,CAAkB,CAAC,EAG1H,SAAS,cAAc,mBAAmB,EAAE,iBAAiB,QAAS,IAAMwB,GAAU3B,CAAe,CAAC,EAGtG,SAAS,cAAc,kBAAkB,EAAE,iBAAiB,QAAS,IAAM,cAAc,UAAU,CAAC,EAGpG,SAAS,cAAc,uBAAuB,EAAE,iBAAiB,QAAS4B,EAAiB,EAG3F,SAAS,cAAc,sCAAsC,EAAE,iBAAiB,QAASC,EAAY,EAGrG,SAAS,cAAc,cAAc,EAAE,iBAAiB,QAAS,IAAMC,GAAY,OAAO,OAAOvC,EAAI,IAAI,CAAC,CAAC,EAG3G,SAAS,cAAc,cAAc,EAAE,iBAAiB,SAAU,UAAY,CAC7EG,EAAc,SAAS,cAAc,cAAc,EAAE,KACtD,CAAC,EAID,SAAS,cAAc,oBAAoB,EAAE,iBAAiB,QAAS,SAAY,CAClFH,EAAI,gBAAgBiB,CAAQ,EAC5BuB,EAAY,EACZxC,EAAI,aAAa,2CAA4C,SAAS,CACvE,CAAC,EAED,QAAQ,SAAS,QAAQ,KAAK0B,EAAW,CAAC,EAG1Cc,EAAY,CACb,CAQA,eAAeC,IAAoB,CAClCrC,EAAU,CAAC,EACXgB,EAAiB,CAAC,EAClB,SAAS,cAAc,UAAU,EAAE,UAAY,EAChD,CASA,eAAeoB,GAAc,CAC5B,QAAQ,IAAI,aAAa,EACzB,MAAMC,GAAkB,EAGxB,MAAMzC,EAAI,SAAS,EACnB,MAAMA,EAAI,aAAa,EAMnB,QAAQA,EAAI,aAAa,GAAKA,EAAI,KAAK,OAAS,GACnD,MAAMA,EAAI,eAAe,OAAO,OAAOA,EAAI,IAAI,EAAE,EAAE,EAMpD,SAAS,cAAc,sBAAsB,EAAE,iBAAiB,QAAS,IAAM,CAC9E,WAAWA,EAAI,aAAa,aAAa,EACzCA,EAAI,aAAa,WAAaA,EAAI,aAAa,aAAa,CAC7D,CAAC,EAID,UAAW0C,KAAY1C,EAAI,KAAM,CAEhC,IAAI2C,EAAM3C,EAAI,KAAK0C,GACf,OAAOC,GAAO,WACjBA,EAAM,KAAK,MAAMA,CAAG,GAIrB,MAAMC,EAAaD,CAAG,CACvB,CAIA,GAAI,OAAO,KAAK3C,EAAI,IAAI,EAAE,QAAU,EAC9B,QAAQM,CAAc,GAI1B,KAAK,aAAa,EAGlB,KAAK,WAAW,IANhB,QAAQ,IAAI,2CAA2C,EACvD0B,EAAU,EAAI,OAOT,CACN,KAAK,aAAa,EAElB,IAAIa,EAAY,OAAO,KAAKzC,CAAO,EACnC,QAAS0C,KAAKD,EACbA,EAAUC,GAAKD,EAAUC,GAAG,QAAQ,UAAW,EAAE,EAIlD,QAASC,KAAK/C,EAAI,SACZ6C,EAAU,SAASE,CAAC,GAExB,MAAMC,EAAgBD,CAAC,EAKzB,IAAIE,EAAgB,SAAS,eAAe,mBAAmB,EAC/D,SAAS,cAAc,UAAU,EAAE,OAAOA,CAAa,EAGvD,QAASC,KAAW9C,EAAS,CAG5B,IAAI+C,EAAQ,EACZ,QAASC,KAAOhD,EAAQ8C,GACnB,QAAQE,EAAI,YAAY,GACvB,CAAC,QAAQpD,EAAI,SAASoD,EAAI,IAAI,GAAK,CAAC,QAAQpD,EAAI,SAASoD,EAAI,KAAK,YAAY,IACjFA,EAAI,aAAepD,EAAI,SAASoD,EAAI,KAAK,aACzCpD,EAAI,gBAAgBoD,CAAG,GAGrB,EAAAA,EAAI,IAAM,IAGdD,IAED,SAAS,eAAeD,CAAO,EAAE,cAAc,eAAe,EAAE,WAAa,KAAOC,EAAQ,GAC7F,CACD,CAGA,QAASE,KAAMhC,EACd,KAAK,SAAS,cAAc,IAAMgC,EAAK,aAAa,CAAC,EAItDC,GAAoB,EAGhB,SAAS,iBAAiB,oCAAoC,EAAE,QAAU,GAC7E,KAAKL,CAAa,EAGnB,QAAQ,MAAM,4BAA6BjD,EAAI,aAAa,EAC5D,QAAQ,MAAM,mBAAqB,OAAO,KAAKA,EAAI,IAAI,EAAE,MAAM,EAC/DA,EAAI,IAAI,MAAM,kBAAkB,CACjC,CAkBA,eAAe4C,EAAaW,EAAI,CAC/B,GAAI,QAAQA,CAAE,EACb,eAAQ,MAAM,oBAAoB,EAC3B,KAGR,IAAIC,EAAS,MAAM,SAAS,cAAc,cAAc,EAAE,QAAQ,UAAU,EAAI,EAChF,IAAIC,EAAeD,EAAO,cAAc,WAAW,EAE/CE,EAAc,cAAgBH,EAAG,IAEjCI,EAAW,SAAWD,EAC1BF,EAAO,cAAc,iBAAiB,EAAE,aAAa,KAAMG,CAAQ,EACnE,IAAIC,EAAKJ,EAAO,cAAc,mBAAmB,EACjDI,EAAG,aAAa,iBAAkB,IAAMF,CAAW,EACnDE,EAAG,aAAa,gBAAiBF,CAAW,EAC5CF,EAAO,cAAc,qBAAqB,EAAE,aAAa,KAAME,CAAW,EAC1EF,EAAO,cAAc,qBAAqB,EAAE,aAAa,kBAAmBG,CAAQ,EAEpF,IAAIE,EAASN,EAAG,IAAI,UAAU,EAAG,CAAC,EAAI,MAiBtC,GAhBI,QAAQA,EAAG,GAAG,IACjBA,EAAG,IAAM,IAAMM,EAAS,KAEzBL,EAAO,cAAc,MAAM,EAAE,YAAcK,EAEvC,SAAUN,GAAMA,EAAG,KAAO,GAC7BE,EAAa,MAAQ,2BACrBA,EAAa,UAAYnC,GACzBkC,EAAO,cAAc,gBAAgB,EAAE,YAAc,MAAMxD,EAAI,SAASuD,EAAG,IAAI,IAE/EE,EAAa,MAAQ,+BACrBA,EAAa,UAAYlC,EACzB,KAAKiC,EAAO,cAAc,gBAAgB,EAAE,aAAa,GAItD,CAAC,QAAQxD,EAAI,aAAa,GACzBuD,EAAG,KAAOvD,EAAI,cAAc,IAAK,CACpC,IAAI8D,EAAWN,EAAO,cAAc,kBAAkB,EAQtD,GAPAM,EAAS,UAAYtC,EACrBsC,EAAS,MAAQ,uBAGjB,SAAS,cAAc,kBAAkB,EAAE,YAAcP,EAAG,IAC5D,SAAS,cAAc,kBAAkB,EAAE,YAAcM,EAErD,QAAQ7D,EAAI,GAAG,EAElB,GADA+D,EAAM,SAAS,OAAS,kBAAoB/D,EAAI,aAAa,cAAe,SAAS,cAAc,2BAA2B,CAAC,EAC3H,QAAQA,EAAI,QAAQ,GAAG,EAC1B,QAAQ,IAAI,kBAAkB,EACpB,SAAS,iBAAiB,mBAAmB,EACnD,QAASgE,GAAO,CACnB,KAAKA,CAAE,EACPA,EAAG,iBAAiB,QAAS,IAAM,CAClC,QAAQ,IAAI,gBAAgB,EACP,IAAI,UAAU,MAAM,SAAS,cAAc,iBAAiB,CAAC,EACnE,KAAK,EACpBhE,EAAI,yBAAyB,CAC9B,CAAC,CACF,CAAC,MACK,CAEN,IAAIiE,EAAK,SAAS,cAAc,wBAAwB,EACxD,KAAKA,CAAE,EACPA,EAAG,iBAAiB,QAAS,IAAM,CAClCjE,EAAI,MAAMuD,EAAIf,CAAW,CAC1B,CAAC,CACF,CAEF,CAGDgB,EAAO,iBAAiB,MAAM,EAAE,QAASzB,GAASA,EAAK,YAAcwB,EAAG,IAAI,UAAU,EAAG,GAAG,CAAC,EAE7F,IAAIW,EAAYV,EAAO,cAAc,UAAU,EAC3CW,EAAeX,EAAO,cAAc,aAAa,EACjDY,EAAeZ,EAAO,cAAc,aAAa,EAEhD,QAAQD,EAAG,GAAG,GAWlB,KAAKW,CAAS,EACd,KAAKC,CAAY,EACjB,KAAKC,CAAY,GAZjBF,EAAU,iBAAiB,QAAS,SAAY,CAE/C,IAAIG,EAAW,MAAOC,GAAU,CAC/B,MAAMC,EAAa,CAACD,EAAM,GAAG,CAAC,EAC9B,MAAM9B,EAAY,EAClBxC,EAAI,aAAa,iCAAkC,SAAS,CAC7D,EACAA,EAAI,UAAUuD,EAAIc,CAAQ,CAC3B,CAAC,EAQFb,EAAO,cAAc,mBAAmB,EAAE,iBAAiB,QAAS,IAAM,CACzEzC,EAAoBwC,EAAG,IACvB1C,EAAc,OAAO,CACtB,CAAC,EAGD,IAAI2D,EAAUhB,EAAO,cAAc,WAAW,EAC9CgB,EAAQ,MAAQjB,EAAG,IAAM,IAAMA,EAAG,IAElC,IAAIkB,EAAUjB,EAAO,cAAc,sBAAsB,EAmBzD,GAlBAA,EAAO,cAAc,aAAa,EAAE,iBAAiB,QAAS,IAAMkB,GAAQD,CAAO,CAAC,EACpFjB,EAAO,cAAc,aAAa,EAAE,iBAAiB,QAAS,IAAMmB,EAAQF,EAASlB,EAAG,GAAG,CAAC,EAE5FC,EAAO,cAAc,eAAe,EAAE,iBAAiB,QAAUoB,GAAM,CAClEA,EAAE,UAAY,IACjBD,EAAQF,EAASlB,EAAG,GAAG,CAEzB,CAAC,EAGDC,EAAO,cAAc,UAAU,EAAE,iBAAiB,QAAS,IAAM,CAChE,WAAWgB,EAAQ,KAAK,EACxBxE,EAAI,aAAa,WAAawE,EAAQ,KAAK,CAC5C,CAAC,EAEDT,EAAMS,EAAQ,MAAOhB,EAAO,cAAc,eAAe,CAAC,EAGtD,QAAQD,EAAG,CAAC,GAAK,QAAQA,EAAG,CAAC,EAChCC,EAAO,cAAc,iBAAiB,EAAE,UAAU,IAAI,kBAAkB,EACxEA,EAAO,cAAc,mBAAmB,EAAE,UAAU,IAAI,kBAAkB,EAC1EA,EAAO,cAAc,MAAM,EAAE,YAAc,MAC3C,KAAKA,EAAO,cAAc,gBAAgB,EAAE,aAAa,EACzD,KAAKA,EAAO,cAAc,oBAAoB,CAAC,EAC/CA,EAAO,cAAc,eAAe,EAAE,OAAOY,CAAY,EACzD,KAAKA,CAAY,MACX,CACNZ,EAAO,cAAc,MAAM,EAAE,YAAc,MAAMxD,EAAI,SAASuD,EAAG,GAAG,EAIpE,IAAIsB,EAAW,KAAK,UAAUtB,CAAE,EAC5BuB,EAAUtB,EAAO,cAAc,iBAAiB,EACpDsB,EAAQ,YAAcD,EACtBd,EAAMc,EAAUrB,EAAO,cAAc,eAAe,CAAC,EAErD,IAAIuB,EAAYvB,EAAO,cAAc,oBAAoB,EAGzD,IAAIwB,EAAexB,EAAO,cAAc,aAAa,EACjDyB,EAAYzB,EAAO,iBAAiB,YAAY,EAChDzB,EAAOyB,EAAO,cAAc,iBAAiB,EAGjD,IAAI0B,EAAa,GAEZ,QAAQ3B,EAAG,GAAG,GAkBd,CAAC,QAAQA,EAAG,GAAG,GAAKA,EAAG,MAAQ,IAAS,QAAQA,EAAG,CAAC,GACvD,KAAKC,EAAO,cAAc,cAAc,CAAC,EAEzCzB,EAAK,MAAQ,0DACbA,EAAK,UAAU,IAAI,kBAAkB,EACrByB,EAAO,cAAc,mBAAmB,EAC9C,UAAU,IAAI,kBAAkB,EAE1C,KAAKwB,CAAY,EACjB,KAAKD,CAAS,EACdvB,EAAO,cAAc,eAAe,EAAE,OAAOY,CAAY,IAGzDc,EAAa,GAGbF,EAAa,iBAAiB,QAAS,IAAMG,GAAe5B,CAAE,CAAC,GAIhEa,EAAa,iBAAiB,QAAS,IAAM,CAC5C3D,EAAkB8C,EAEd,OAAO,KAAKvD,EAAI,IAAI,EAAE,QAAU,GACnC,SAAS,cAAc,2BAA2B,EAAE,iBAAiB,QAAS,IAAMQ,EAAe,OAAO,CAAC,EAC3GE,EAAmB,OAAO,GAE1BF,EAAe,OAAO,CAExB,CAAC,EAGD2D,EAAa,iBAAiB,QAAS,IAAM,CAC5CvD,EAAqB2C,EAAG,IACxB5C,EAAe,OAAO,CACvB,CAAC,IAnDD,KAAK6C,EAAO,cAAc,kBAAkB,CAAC,EAC7CzB,EAAK,MAAQ,uCACbA,EAAK,UAAU,IAAI,eAAe,EAClCyB,EAAO,cAAc,mBAAmB,EAAE,UAAU,IAAI,eAAe,EAEvEA,EAAO,cAAc,MAAM,EAAE,YAAc,MAAMxD,EAAI,SAASuD,EAAG,QAAQ,EACzE,KAAKC,EAAO,cAAc,MAAM,EAAE,aAAa,EAC/CC,EAAa,UAAYhC,GAEzB,KAAKuD,CAAY,EACjB,KAAKb,CAAY,EACjB,KAAKC,CAAY,EACjB,KAAKF,CAAS,GA2CVgB,GAEJD,EAAU,QAASlD,GAAS,CAC3BA,EAAK,iBAAiB,QAAS,IAAM,CAEpC/B,EAAI,MAAMuD,EAAIf,CAAW,CAC1B,CAAC,EACD,KAAKT,CAAI,CACV,CAAC,EAIFyB,EAAO,cAAc,UAAU,EAAE,iBAAiB,QAAS,IAAM,WAAWsB,CAAO,CAAC,EAGpF,IAAIM,EAAM5B,EAAO,cAAc,gBAAgB,EAC/CuB,EAAU,iBAAiB,QAAS,IAAM,CACzC,cAAcK,CAAG,CAClB,CAAC,EAGD5B,EAAO,cAAc,YAAY,EAAE,KAAO,kEAAoED,EAAG,IAAM,sMAAwMsB,CAEhU,CAMA,IAAIQ,EAAW,MAAMrC,EAAgBO,EAAG,GAAG,EAC3C,OAAAnD,EAAQiF,GAAU,KAAK9B,CAAE,EACzB,SAAS,cAAc,IAAM8B,EAAW,aAAa,EAAE,OAAO7B,CAAM,EAE7DD,CACR,CAkBA,eAAeP,EAAgBK,EAAI,CAClC,IAAIiC,EAAa,GACbxB,EAAW,GAEXyB,EAAa,GACbC,EAAe,GACfC,EAAiB,GAGjB,QAAQpC,CAAE,GAAKA,IAAO,qBACzBkC,EAAa,GACbD,EAAa,aACbjC,EAAK,sBAGLiC,EAAajC,EAAG,UAAU,EAAG,CAAC,EAAI,MAC9B,CAAC,QAAQrD,EAAI,SAASqD,EAAG,GAAK,CAAC,QAAQrD,EAAI,SAASqD,GAAI,YAAY,IACvEiC,EAAatF,EAAI,SAASqD,GAAI,cAG3BrD,EAAI,KAAOqD,IACdoC,EAAiB,GACjB3B,EAAWtC,IAIb,IAAIkE,EAASrC,EAcb,GAbIqC,EAAO,UAAU,EAAG,CAAC,IAAM,YAC9BA,EAAS,UAAYA,IAKlB,QAAQ1F,EAAI,GAAG,GAAK,OAAO,KAAKA,EAAI,IAAI,EAAE,QAAU,KAEvD,KAAK,SAAS,cAAc,+BAA+B,CAAC,EAC5DwF,EAAe,IAIZE,KAAUtF,EACb,OAAOsF,EAER,IAAIC,EAAY,MAAM,SAAS,cAAc,YAAY,EAAE,QAAQ,UAAU,EAAI,EAGjFA,EAAU,cAAc,qBAAqB,EAAE,MAAQtC,EACvDsC,EAAU,cAAc,oBAAoB,EAAE,iBAAiB,QAAUf,GAAM,CAC9EA,EAAE,eAAe,EACjB,WAAWvB,CAAE,EACbrD,EAAI,aAAa,kBAAoBqD,EAAK,iBAAkB,SAAS,CACtE,CAAC,EACD,IAAIuC,EAAmBD,EAAU,cAAc,mBAAmB,EAClEC,EAAiB,MAAQN,EACzBK,EAAU,cAAc,oBAAoB,EAAE,iBAAiB,QAAS,MAAOf,GAAM,CACpFA,EAAE,eAAe,EACb,QAAQgB,EAAiB,KAAK,GACjC5F,EAAI,MAAM,+BAA+B,EAG1C,IAAI6F,EAAU7F,EAAI,WAAW,EAC7B6F,EAAQ,aAAeD,EAAiB,MAExC,IAAIE,EAAW,IAAI,SACnBA,EAAS,OAAO,OAAQ,KAAK,UAAU,MAAM9F,EAAI,cAAc6F,CAAO,CAAC,CAAC,EACxE,IAAIvB,EAAQ,MAAMtE,EAAI,UAAUA,EAAI,IAAI,KAAK,QAAS8F,CAAQ,EAC1D,QAAQxB,CAAK,IAajBtE,EAAI,8BAA8BsE,EAAM,GAAG,EAC3C9B,EAAY,EACZxC,EAAI,aAAa,oCAAqC,SAAS,EAChE,CAAC,EAEDoB,EAAekE,GAAcjC,EAC7BiC,EAAaxB,EAAWwB,EACxBlF,EAAQsF,GAAU,CAAC,EAEnBC,EAAU,cAAc,OAAO,EAAE,GAAKD,EACtC,IAAIK,EAAiBJ,EAAU,cAAc,aAAa,EAC1DI,EAAe,UAAYT,EACvBA,IAAe,cAClBS,EAAe,UAAU,IAAI,cAAc,EAKxC,CAACN,GAAkB,CAACD,GACvB,KAAKG,EAAU,cAAc,YAAY,CAAC,EAI3C,IAAItB,EAAW,IAAM,CACf,SAAS,cAAc,IAAMqB,EAAS,aAAa,EAAE,OAGzD,OAAOrE,EAAgBqE,GAFvBrE,EAAgBqE,GAAU,EAI5B,EACA1F,EAAI,SAAS2F,EAAU,cAAc,cAAc,EAAGA,EAAU,cAAc,YAAY,EAAGtB,CAAQ,EAGrG,IAAI2B,EAAUL,EAAU,cAAc,qBAAqB,EAC3DA,EAAU,cAAc,gBAAgB,EAAE,iBAAiB,QAAS,IAAM,cAAcK,CAAO,CAAC,EAChGL,EAAU,cAAc,kBAAkB,EAAE,iBAAiB,QAAU5D,GAAS,CAC/E1B,EAAmBgD,EACnBnC,EAAiB,OAAO,CACzB,CAAC,EAGD,IAAI+E,EAAqBN,EAAU,cAAc,mBAAmB,EAChEO,EAAsBP,EAAU,cAAc,oBAAoB,EAClEQ,EAAcR,EAAU,cAAc,iBAAiB,EACtDJ,GAMJ,KAAKU,CAAkB,EACvB,KAAKC,CAAmB,EACxB,KAAKP,EAAU,cAAc,aAAa,CAAC,EAC3C,KAAKA,EAAU,cAAc,oBAAoB,CAAC,EAClD,KAAKQ,CAAW,EAChB,KAAKR,EAAU,cAAc,cAAc,CAAC,EAG5CA,EAAU,cAAc,cAAc,EAAE,iBAAiB,QAAS,IAAMpD,GAAYnC,EAAQsF,EAAO,CAAC,IAbpGO,EAAmB,KAAOA,EAAmB,KAAO,IAAM5C,EAC1D6C,EAAoB,KAAOA,EAAoB,KAAO,IAAM7C,EAE5D8C,EAAY,iBAAiB,QAAS,IAAMC,GAAY/C,CAAE,CAAC,GAa5DsC,EAAU,cAAc,eAAe,EAAE,iBAAiB,QAAU5D,GAAS,CAE5E,SAAS,eAAe,eAAe,EAAE,MAAQsB,EACjD1B,EAAiBI,EAAK,OAAO,cAAc,cAAc,iBAAiB,EAAE,KAAK,CAClF,CAAC,EAGD,MAAMsE,EAAiBV,EAAU,cAAc,iBAAiB,EAgChE,GA/BAA,EAAU,cAAc,YAAY,EAAE,iBAAiB,QAAU5D,GAAS,CACzE,QAAQ,IAAI,eAAe,EAC3BxB,EAAY,OAAO,EACnB,IAAI+F,EAAY,SAAS,eAAe,aAAa,EAErD,MAAMC,EAAY,IAAIrG,GACrBoG,EACAE,GAAUC,EAAeD,CAAM,EAAG,CACjC,oBAAqB,EACtB,CACD,EAEA,SAASC,EAAeD,EAAQ,CAC/B,QAAQ,IAAI,mBAAoBA,CAAM,EACtCjG,EAAY,OAAO,EACnB8F,EAAe,MAAQG,EAAO,IAC/B,CAIA,SAAS,eAAe,aAAa,EAAE,iBAAiB,kBAAmBE,GAAS,CACnFH,EAAU,KAAK,CAChB,CAAC,EAEDA,EAAU,MAAM,CACjB,CAAC,EAGDZ,EAAU,cAAc,kBAAkB,EAAE,iBAAiB,QAAS,IAAM3F,EAAI,eAAeI,EAAQsF,GAASrC,CAAE,CAAC,EAG/GoC,EAAgB,CACnB,IAAIkB,EAAIhB,EAAU,cAAc,iBAAiB,EAEjDgB,EAAE,UAAU,OAAO,gBAAgB,EACnCA,EAAE,UAAU,IAAI,gBAAgB,EAChC,SAAS,cAAc,UAAU,EAAE,QAAQhB,CAAS,EACpDtE,EAAgBqE,GAAU,EAC3B,MACC,SAAS,cAAc,UAAU,EAAE,OAAOC,CAAS,EAGpD,OAAOD,CACR,CASA,eAAe3B,EAAM6C,EAASC,EAAS,CACtC,IAAIC,EAAM,MAAM,OACZC,EAAMD,EAAI,WAAWF,EAASE,EAAI,IAAI,GAAG,EACzCE,EAAS,SAAS,cAAc,KAAK,EACzCA,EAAO,aAAa,QAASJ,CAAO,EAIpC,IAAIK,EAAMF,EAAI,YAAY,CAAC,EAC3BC,EAAO,UAAYC,EAEnB,IAAIC,EAAgB,SAAS,cAAc,KAAK,EAChDA,EAAc,OAAOF,CAAM,EAC3BH,EAAQ,UAAY,GACpBA,EAAQ,OAAOK,CAAa,CAC7B,CAOA,SAASxC,GAAQmC,EAAS,CACzB,IAAIM,EAAIN,EAAQ,cAAc,cAC9B,cAAcM,EAAE,cAAc,UAAU,CAAC,EACzCA,EAAE,cAAc,eAAe,EAAE,MAAQN,EAAQ,SAClD,CAQA,eAAelC,EAAQC,EAAGwC,EAAK,CAC9B,MAAMpH,EAAI,UAAUoH,EAAKxC,EAAE,cAAc,cAAc,cAAc,eAAe,EAAE,KAAK,EAC3FpC,EAAY,CACb,CAUA,eAAe2C,GAAe5B,EAAI,CAEjC,GAAI,CADM,MAAMvD,EAAI,eAAeuD,CAAE,EAC3B,CACTvD,EAAI,MAAM,oBAAoB,EAC9B,MACD,CACAqH,GAAa9D,EAAG,GAAG,CACpB,CAQA,SAAS8D,GAAaD,EAAK,CAM1B,GAJA,SAAS,iBAAiB,WAAW,EAAE,QAASrF,GAAS,CACxDA,EAAK,UAAY,EAClB,CAAC,EACO,SAAS,eAAe,oBAAsBqF,CAAG,IAC/C,KACT,MAAM,IAAI,MAAM,sBAAsB,EAEvC,SAAS,UAAY5F,EACrB,SAAS,MAAQ,cAClB,CASA,eAAee,GAAY+E,EAAM,CAChC,IAAIC,EAAO,CAAC,EACZ,QAASnE,KAAOkE,EAAM,CACrB,GAAI,QAAQlE,EAAI,GAAG,EAClB,MAAM,IAAI,MAAM,qBAAqB,EAEtCmE,EAAK,KAAKnE,EAAI,GAAG,CAClB,CAEA,GAAI,QAAQmE,CAAI,EAAG,CAClBvH,EAAI,aAAa,2CAA4C,OAAO,EACpE,MACD,CAEA,IAAI8F,EAAW,IAAI,SACnBA,EAAS,OAAO,OAAQyB,CAAI,EAC5B,IAAIC,EAAW,MAAMxH,EAAI,UAAUA,EAAI,IAAI,KAAK,YAAa8F,CAAQ,EACrE,QAAQ,MAAM0B,CAAQ,EAElB,CAAC,QAAQA,EAAS,GAAG,GAAK,CAAC,QAAQA,EAAS,IAAI,IAAI,IAIvD,MAAMC,GAAmB,EAGzB,MAAMC,GAAgB,EACtB,MAAMnD,EAAaiD,EAAS,IAAI,IAAI,EACpC,MAAMxH,EAAI,0BAA0BwH,EAAS,IAAI,QAAQ,GAE1DhF,EAAY,EACZxC,EAAI,aAAa,2BAA4B,SAAS,CAEvD,CAUA,eAAeoG,GAAYuB,EAAK,CAE/B,GADA,QAAQ,IAAI,cAAeA,CAAG,EAC1B,QAAQA,CAAG,EAAG,CACjB,GAAI,QAAQ3H,EAAI,GAAG,EAAG,CACrBA,EAAI,aAAa,qCAAsC,OAAO,EAC9D,MACD,CACA2H,EAAM3H,EAAI,GACX,CAEA,QAAQ,IAAIA,EAAI,IAAI,IAAI,YAAc,IAAM2H,CAAG,EAG/C,IAAIH,EAAW,MAAMxH,EAAI,MAAMA,EAAI,IAAI,IAAI,YAAc,IAAM2H,CAAG,EAElE,QAASvE,KAAOoE,EAAU,CACzB,IAAII,EAAIxE,EAAI,UAAU,EAAG,CAAC,EAAI,MAC9BhC,EAAewG,GAAKJ,EAASpE,EAC9B,CAEA,IAAIyE,EAAc,MAAM7H,EAAI,MAAMA,EAAI,IAAI,IAAI,SAAW,IAAM2H,CAAG,EAElE3H,EAAI,0BAA0BwH,CAAQ,EACtC,MAAMjD,EAAasD,EAAY,GAAG,EAClC,QAASC,KAAM1H,EAAQ,UAAYuH,GAAM,CACxC,IAAII,EAAQ,GACZ,QAASC,KAAMH,EAAY,IAC1B,GAAIC,EAAG,KAAOE,EAAG,GAAI,CACpBD,EAAQ,GACR,KACD,CAMG,CAACA,IAAU,QAAQD,EAAG,GAAG,GAAKA,EAAG,KAAO,KAC3CA,EAAG,IAAM,KACT9H,EAAI,gBAAgB8H,CAAE,EAExB,CACAtF,EAAY,EACZxC,EAAI,aAAa,8BAA+B,SAAS,CAC1D,CAUA,eAAeiC,GAAemF,EAAK,CAClC,GAAI,QAAQA,CAAG,EAAG,CACjB,QAAQ,MAAM,oBAAoB,EAClC,MACD,CAIA,GAAI,CAAC,QAAQpH,EAAI,OAAO,GAAKA,EAAI,QAAQ,KAAOoH,EAAK,CACpDtG,EAAsB,OAAO,EAC7B,MACD,CACAoB,EAAUkF,CAAG,CACd,CAQA,eAAelF,EAAUkF,EAAK,CAC7B,GAAI,CACH,MAAMpH,EAAI,UAAUoH,CAAG,EACvB,SAAS,eAAe,oBAAsBA,CAAG,EAAE,OAAO,EAC1DpH,EAAI,aAAa,8CAA8C,CAChE,OAASiI,EAAP,CACDjI,EAAI,MAAMiI,CAAK,CAChB,CACD,CAaA,eAAe9F,GAAoBiF,EAAK,CACnC,QAAQpH,EAAI,GAAG,GAClBA,EAAI,MAAMA,EAAI,IAAI,eAAe,EAElC,IAAI8F,EAAW,IAAI,SACnBA,EAAS,OAAO,OAAQ,KAAK,UAAU,MAAM9F,EAAI,UAAUoH,CAAG,CAAC,CAAC,EAChE,IAAI9C,EAAQ,MAAMtE,EAAI,UAAUA,EAAI,IAAI,KAAK,UAAW8F,CAAQ,EAE5DrC,EAAe,SAAS,eAAe,oBAAsBa,EAAM,GAAG,EAAE,cAAc,WAAW,EACrGb,EAAa,UAAYlC,EACzBkC,EAAa,MAAQ,+BACrBzD,EAAI,KAAKsE,EAAM,KAAK,KAAO,EAC3B,MAAMtE,EAAI,gBAAgBA,EAAI,KAAKsE,EAAM,IAAI,EAC7CtE,EAAI,aAAa,sIAAuI,SAAS,CAClK,CAQA,SAASqC,IAAoB,CAE5B,GAAIhC,IAAqBL,EAAI,IAAK,CACjCmB,EAAyB,OAAO,EAChC,MACD,CACAmB,GAAa,CACd,CAQA,eAAeA,IAAe,CAC7B,GAAI,CACH,QAASc,KAAOhD,EAAQ,UAAYC,GACnC,MAAM6B,EAAUkB,EAAI,GAAG,CAEzB,OAAS6E,EAAP,CACDjI,EAAI,MAAMiI,CAAK,CAChB,CAEA,MAAMjI,EAAI,mBAAmBK,CAAgB,EAC7CmC,EAAY,EACZxC,EAAI,aAAa,2DAA4D,SAAS,CACvF,CAoBA,eAAeoC,GAAU8F,EAASC,EAAK,CAClC,QAAQnI,EAAI,GAAG,GAClBA,EAAI,MAAMA,EAAI,IAAI,eAAe,EAElC,GAAI,CACH,IAAIoI,EACAC,EAAM,GAGNH,EAAQ,MAAQlI,EAAI,QAAQ,KAAQ,CAAC,QAAQkI,EAAQ,GAAG,IAAMA,EAAQ,MAAQ,QAAUA,EAAQ,MAAQ,KAC3GE,EAAO,MAAMpI,EAAI,eAAekI,EAAQ,IAAKC,CAAG,EAChDE,EAAMrI,EAAI,IAAI,KAAK,iBAGnBqI,EAAMrI,EAAI,IAAI,KAAK,UACnBoI,EAAO,MAAMpI,EAAI,UAAUkI,EAASC,CAAG,GAExC,IAAIrC,EAAW,IAAI,SACnBA,EAAS,OAAO,OAAQ,KAAK,UAAUsC,CAAI,CAAC,EAC5C,IAAI9D,EAAQ,MAAMtE,EAAI,UAAUqI,EAAKvC,CAAQ,EACzC/D,EAAO,SAAS,eAAe,oBAAsBuC,EAAM,IAAI,GAAG,EACtEvC,EAAK,MAAQ,uCACbA,EAAK,UAAU,IAAI,iBAAiB,EAEpC/B,EAAI,KAAKsE,EAAM,IAAI,KAAK,IAAMA,EAAM,IAAI,IACxC,MAAMtE,EAAI,gBAAgBA,EAAI,KAAKsE,EAAM,IAAI,IAAI,EACjDtE,EAAI,aAAa,qCAAsC,SAAS,CACjE,OAAS4E,EAAP,CACD,QAAQ,MAAMA,CAAC,EACf5E,EAAI,MAAM,wDAAwD,CACnE,CACD,CAUA,eAAegC,EAAUsG,EAAQ,CAChC,IAAI/E,EAAK,MAAMvD,EAAI,aAAaG,CAAW,EAC3C,GAAImI,GAAU,KACb,QAAQ,IAAI,wBAAyB/E,CAAE,EAEnC,CADM,MAAMvD,EAAI,eAAeuD,CAAE,GAC3B,CACTvD,EAAI,MAAM,oBAAoB,EAC9B,MACD,CAED,IAAIuI,EAAkB,SAAS,eAAe,eAAe,EAAE,MAE3DA,IAAoB,sBACvBhF,EAAG,IAAMnC,EAAemH,IAEzB3F,EAAaW,CAAE,EACfvD,EAAI,gBAAgBuD,CAAE,EACtB,IAAIiF,EAAcxI,EAAI,eACtBwI,EAAY,OAAS,GACrB,MAAMxI,EAAI,gBAAgBwI,CAAW,EACrC,IAAIC,EAAKlF,EAAG,IAAM,IAAMA,EAAG,IAC3B,WAAWkF,CAAE,EACbzI,EAAI,aAAayI,EAAK,wBAAyB,SAAS,EACxD,KAAK,aAAa,CACnB,CA4CA,eAAe9G,EAAiB+G,EAAO,CACtC,QAAQ,IAAI,iBAAkBA,CAAK,EACnC,GAAI,CACC,QAAQA,CAAK,GAChB1I,EAAI,MAAM,2CAA4C,OAAO,EAK9D,IAAI2I,EAAM,CAAC,EAIX,GAAIC,GAAiBF,CAAK,EACzBC,EAAME,GAA8BH,CAAK,EACrC,QAAQC,CAAG,GACd3I,EAAI,MAAM,+CAAgD,OAAO,MAE5D,CACN,IAAIsE,EAAQ,KAAK,MAAMoE,CAAK,EAGxBI,EAAS,KAAK,UAAUxE,CAAK,EAEjC,GAAIwE,EAAO,OAAO,CAAC,IAAM,IACxB,IAAIH,EAAM,KAAK,MAAMD,CAAK,UAEhBI,EAAO,OAAO,CAAC,IAAM,IAAK,CAEpC,IAAIC,EAAW,GACf,QAAS3F,KAAO,OAAO,KAAKkB,CAAK,EAC5BtE,EAAI,gBAAgBoD,CAAG,IAC1B2F,EAAW,IAGTA,EACHJ,EAAM,OAAO,OAAOrE,CAAK,EAGzBqE,EAAI,KAAKrE,CAAK,CAEhB,CACD,CAEA,IAAIqD,EAAMvG,EAAe,SAAS,eAAe,eAAe,EAAE,OAC9D,QAAQuG,CAAG,IACdA,EAAM,oBACN,QAAQ,IAAI,uBAAuB,GAGpC,QAASvE,KAAOuF,EAAK,CAMpB,GAJA,QAAQ,IAAI,0BAA2BhB,CAAG,EAC1CvE,EAAI,IAAMuE,EAGN,QAAQvE,EAAI,CAAC,GAAK,QAAQA,EAAI,CAAC,EAAG,CACrC,GAAI,CAACpD,EAAI,gBAAgBoD,EAAI,GAAG,EAC/B,MAAM,IAAI,MAAM,kCAAkC,EAEnD,GAAI,CACH,IAAIkB,EAAQ,MAAMtE,EAAI,MAAMA,EAAI,IAAI,IAAI,QAAU,IAAMoD,EAAI,GAAG,CAChE,OAAS6E,EAAP,CACD,QAAQ,MAAMA,CAAK,CACpB,CACA,GAAI,QAAQ3D,CAAK,EAAG,CACnBrD,EAAWmC,EACXpC,EAAc,OAAO,EACrB,MACD,CAEIsD,EAAM,KAAOqD,IAChB,QAAQ,IAAI,6DAA6D,EACzErD,EAAM,IAAMqD,GAEb3H,EAAI,gBAAgBsE,CAAK,EACzB9B,EAAY,EACZ,MACD,CAGA,GAAI,CADQ,MAAMvC,EAAK,QAAQmD,CAAG,EACtB,CACXpD,EAAI,aAAa,QAAUoD,EAAI,IAAM,4BAA6B,OAAO,EACzE,MACD,CAEAA,EAAI,IAAM,MAAMnD,EAAK,WAAWmD,CAAG,EACnC,MAAMpD,EAAI,gBAAgBoD,CAAG,CAC9B,CACD,OAASwB,EAAP,CACD5E,EAAI,MAAM4E,CAAC,EACX,MACD,CACApC,EAAY,CACb,CAUA,eAAeiF,IAAqB,CACnC,IAAIuB,EAAc,CAAC,kBAAmB,eAAe,EACrD,SAAS,iBAAiB,iBAAiB,EAAE,QAASjH,GAAS,CAC9D,IAAI0B,EAAe1B,EAAK,cAAc,QAAQ,EAAE,cAAc,WAAW,EACzE0B,EAAa,UAAYlC,EACzBkC,EAAa,MAAQ,+BACrB1B,EAAK,UAAU,OAAO,GAAGiH,CAAW,CACrC,CAAC,CACF,CAMA,eAAetB,IAAkB,CAChC,QAASE,KAAK5H,EAAI,KACjBA,EAAI,KAAK4H,GAAG,IAAM,KAEnB5H,EAAI,iBAAiB,CACtB,CASA,eAAeuE,EAAa+C,EAAM,CACjC,QAASlE,KAAOkE,EAAM,CACrB,IAAIF,EAAMhE,EAAI,GACd,GAAI,QAAQgE,CAAG,IACdA,EAAMhE,EAAI,IACN,QAAQgE,CAAG,GAAG,CACjB,QAAQ,MAAM,gCAAiChE,CAAG,EAClD,QACD,CAKG,CAAC,QAAQpD,EAAI,KAAKoH,EAAI,GAAK,CAAC,QAAQpH,EAAI,KAAKoH,GAAK,CAAC,EACtDhE,EAAI,EAAIpD,EAAI,KAAKoH,GAAK,EAEtBhE,EAAI,IAAM,GAGXA,EAAI,IAAMgE,EACVpH,EAAI,KAAKoH,GAAOhE,CACjB,CACApD,EAAI,iBAAiB,CACtB,CAUA,SAASsD,IAAsB,CAC9B,IAAI2F,EAAkB,SAAS,eAAe,uBAAuB,EACjEC,EAAsB,SAAS,eAAe,eAAe,EACjEA,EAAoB,UAAY,GAGhC,QAAShG,KAAW9C,EAAS,CAC5B,IAAIiD,EAAKH,EAAQ,QAAQ,UAAW,EAAE,EACtC,GAAI,CAAC,QAAQlD,EAAI,SAASqD,EAAG,GAAK,CAAC,QAAQrD,EAAI,SAASqD,GAAI,YAAY,EACvEH,EAAUlD,EAAI,SAASqD,GAAI,iBACrB,CACN,GAAIH,IAAY,oBACf,SAEDA,EAAUG,EAAG,UAAU,EAAG,CAAC,EAAI,KAChC,CACA,IAAI8F,EAAU,SAAS,cAAc,QAAQ,EAM7C,GALAA,EAAQ,YAAcjG,EACtBiG,EAAQ,UAAU,IAAI,UAAY9F,CAAE,EAIhC,CAAC,QAAQH,CAAO,GAAK,CAAC,QAAQlD,EAAI,cAAc,GAAK,CAAC,QAAQA,EAAI,eAAe,YAAY,GAAKA,EAAI,eAAe,cAAgBkD,EAAS,CACjJgG,EAAoB,QAAQC,CAAO,EACnCD,EAAoB,MAAQhG,EAC5BiG,EAAQ,SAAW,GACnB,QACD,CACAD,EAAoB,OAAOC,CAAO,CACnC,CAGA,KAAKF,CAAe,EACpBC,EAAoB,OAAOD,CAAe,EAG1C,IAAIG,EAAc,CAACrH,EAAMsB,EAAIgG,IAAS,CACrC,IAAIC,EAAkBvH,EAAK,cAAc,cAAc,EAEvD,KAAKuH,CAAe,EAEpBA,EAAgB,cAAc,OAAO,EAAE,aAAa,MAAOD,EAAK,EAAE,EAGlE,IAAIE,EAAaD,EAAgB,cAAc,QAAQ,EACvDC,EAAW,QAAQ,MAAQlG,EAC3BkG,EAAW,iBAAiB,QAAU3E,GAAM,CAC3C,IAAI+C,EAAMvG,EAAeiI,EAAK,QAC1B,QAAQ1B,CAAG,GAAK,CAAC3H,EAAI,gBAAgB2H,CAAG,IAC3C3H,EAAI,MAAM,0CAA2C,OAAO,EAE7DA,EAAI,KAAK4E,EAAE,OAAO,QAAQ,OAAO,IAAM+C,EACvC3H,EAAI,iBAAiB,EACrBwC,EAAY,CACb,CAAC,EACD8G,EAAgB,QAAQD,CAAI,CAC7B,EAGIG,EAAwB,SAAS,eAAe,mBAAmB,IAAM,KAG7E,QAAS5B,KAAK5H,EAAI,KAAM,CACvB,IAAIoD,EAAMpD,EAAI,KAAK4H,GACf6B,EAAU,SAAS,cAAc,qBAAuBrG,EAAI,GAAG,EAEnE,GAAI,QAAQA,EAAI,GAAG,GAAKA,EAAI,MAAQ,oBAAqB,CACxD,GAAIoG,EACH,SAED,IAAIE,EAAQR,EAAoB,UAAU,EAAI,EAC9CQ,EAAM,GAAKtG,EAAI,IAAI,UAAU,EAAG,CAAC,EACjCsG,EAAM,cAAc,wBAAwB,EAAE,OAAO,EACrDN,EAAYK,EAASrG,EAAI,IAAKsG,CAAK,EACnC,QACD,CAGA,GAAI,QAAQtG,EAAI,IAAI,EAAG,CACtB,IAAIsG,EAAQR,EAAoB,UAAU,EAAI,EAC9CQ,EAAM,GAAKtG,EAAI,IAAI,UAAU,EAAG,CAAC,EACjCsG,EAAM,cAAc,WAAatG,EAAI,GAAG,EAAE,OAAO,EACjDgG,EAAYK,EAASrG,EAAI,IAAKsG,CAAK,CACpC,CACD,CACD,CAQA,SAASd,GAAiBjC,EAAG,CAC5B,GAAI,OAAOA,GAAM,SAChB,MAAO,GAIR,QAASgD,KAAQhD,EAAE,MAAM;AAAA,CAAI,EAAG,CAC/B,IAAIiD,EAASD,EAAK,MAAM,GAAG,EAC3B,GAAIC,EAAO,OAAS,GAAKA,EAAO,SAAW,EAC1C,MAAO,GAER,IAAIC,EACJ,GAAI,CACHA,EAAM5J,EAAK,OAAO2J,EAAO,EAAE,CAC5B,MAAE,CAEF,CACA,GAAIC,IAAQ,KACX,MAAO,EAET,CACA,MAAO,EACR,CAWA,SAAShB,GAA8BlC,EAAG,CACzC,IAAIgC,EAAM,CAAC,EACX,QAASgB,KAAQhD,EAAE,MAAM;AAAA,CAAI,EAAG,CAC/B,IAAIiD,EAASD,EAAK,MAAM,GAAG,EAEvBpG,EAAK,CACR,IAAKqG,EAAO,EACb,EAEA,OAAQA,EAAO,OAAQ,CACtB,IAAK,GACJrG,EAAG,IAAMqG,EAAO,GAChB,MACD,IAAK,GACJrG,EAAG,EAAIqG,EAAO,GACT,QAAQA,EAAO,EAAE,IACrBrG,EAAG,IAAMqG,EAAO,IAEjB,MACD,IAAK,GACJrG,EAAG,EAAIqG,EAAO,GACT,QAAQA,EAAO,CAAC,CAAC,IACrBrG,EAAG,EAAIqG,EAAO,IAEV,QAAQA,EAAO,CAAC,CAAC,IACrBrG,EAAG,IAAMqG,EAAO,IAEjB,MACD,QACC,OAAO,GACT,CACAjB,EAAI,KAAKpF,CAAE,CACZ,CACA,OAAOoF,CACR,CAMA,SAAS/G,GAAUkI,EAAM,CACxB,IAAIC,EAAK,SAAS,cAAc,QAAQ,EAEpCD,IAAS,KACZC,EAAG,QAAU,IAEVD,IAAS,KACZC,EAAG,QAAU,IAGVA,EAAG,SACN,KAAK,WAAW,EAChB,KAAK,YAAY,IAEjB,KAAK,WAAW,EAChB,KAAK,YAAY,EAEnB", "names": ["App", "Coze", "QrScanner", "SelectedAlg", "Wallets", "selectedWalletID", "AutoGenOnEmpty", "scanQRModal", "revokeKeyModal", "revokeKeyObject", "revokeOnlyKeyModal", "systemKeyModal", "systemKeyDeleteTmb", "localKeyModal", "localLoggedInKeyModal", "localKeyDeleteTmb", "localTmbModal", "localTmb", "localWalletModal", "localLoggedInWalletModal", "displayNameMap", "expandedWallets", "greenCheckmarkIcon", "redExIcon", "starIcon", "revokedIcon", "FormOptions", "importPrivateKey", "powerMode", "WalletOnload", "modalOpts", "item", "genNewKey", "deleteLocalKey", "deleteKey", "deleteKeyFromSystem", "revokeKey", "deleteLocalWallet", "deleteWallet", "syncAllKeys", "initWallets", "clearWalletsState", "property", "jpk", "createKeyDiv", "walletIDs", "w", "a", "CreateWalletGUI", "noAccountElem", "account", "count", "key", "id", "setNewKeyAccountGUI", "ck", "keyDiv", "verifiedElem", "collapseKey", "headerID", "ab", "tmbSub", "selected", "SetQR", "ca", "lb", "addKeyBtn", "deleteKeyBtn", "revokeKeyBtn", "callback", "parsd", "setKeysState", "tmbElem", "kidElem", "EditKid", "SaveKid", "e", "priv_cks", "prkElem", "showPKBtn", "selectKeyBtn", "loginBtns", "NoLoginBtn", "setSelectedKey", "pkd", "walletID", "walletName", "isNoWallet", "noWalletOnly", "walletLoggedIn", "htmlID", "walletDiv", "displayNameInput", "profile", "formData", "walletNameElem", "optsDiv", "userActiveKeysElem", "userRevokedKeysElem", "syncAcctBtn", "SyncAccount", "importKeyInput", "videoElem", "qrScanner", "result", "scanQRCallback", "event", "s", "payload", "element", "QRC", "qr0", "qrElem", "svg", "containerElem", "g", "tmb", "setSelectGui", "keys", "tmbs", "response", "clearWalletStyling", "clearAppKeysUAD", "uad", "k", "keyResponse", "lk", "found", "sk", "error", "cozeKey", "msg", "coze", "uri", "select", "selectedAccount", "accountCopy", "st", "inKey", "czs", "isSerializedForm", "getCozeKeysFromSerializedForm", "parsds", "namedObj", "classStyles", "noAccountSelect", "selectedAccountElem", "optElem", "appendToKey", "elem", "accountFormElem", "moveKeyBtn", "isNoAccountWalletNull", "keyElem", "clone", "line", "splits", "fam", "bool", "pm"] }