tx · znGN8gwYHAETvUrwxQYeexRGdNuMt5n5A2DF7kUGCXZ

3PB2v4Mi2TzFuHyvBkUtFJqNv2J6piYnRwS:  -0.08000000 Waves

2023.02.22 20:47 [3526681] smart account 3PB2v4Mi2TzFuHyvBkUtFJqNv2J6piYnRwS > SELF 0.00000000 Waves

{ "type": 13, "id": "znGN8gwYHAETvUrwxQYeexRGdNuMt5n5A2DF7kUGCXZ", "fee": 8000000, "feeAssetId": null, "timestamp": 1677088030861, "version": 2, "chainId": 87, "sender": "3PB2v4Mi2TzFuHyvBkUtFJqNv2J6piYnRwS", "senderPublicKey": "FzTYu19myxy8hf86jZcmzXYmn3Y4ro7o14prubcULNqu", "proofs": [ "57jAdjYdujT739hEeUFenk51uJ29GY4fXh11ads694xx4fM6psfjwkdGkV75fd7fBNUiEvqEq9U3SferLwVjma4w" ], "script": "base64:BgJyCAISABIAEgASABIDCgEBEgMKAQESDwoNAQEBAQEBAQEBAQEBARIUChIBAQEBAQEBCAgIAQEBAQEBAQESBgoEAQEBCBIAEgMKAQESBQoDAQEEEgMKAQgSABIAEgASAwoBCBIDCgEBEgASABIAEgQKAggIvAEADGtfYmFzZU9yYWNsZQIMa19iYXNlT3JhY2xlAA1rX3F1b3RlT3JhY2xlAg1rX3F1b3RlT3JhY2xlAAlrX2JhbGFuY2UCCWtfYmFsYW5jZQAKa19zZXF1ZW5jZQIKa19zZXF1ZW5jZQAOa19wb3NpdGlvblNpemUCDmtfcG9zaXRpb25TaXplABBrX3Bvc2l0aW9uTWFyZ2luAhBrX3Bvc2l0aW9uTWFyZ2luABZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsAhZrX3Bvc2l0aW9uT3Blbk5vdGlvbmFsAC5rX3Bvc2l0aW9uTGFzdFVwZGF0ZWRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAhJrX3Bvc2l0aW9uRnJhY3Rpb24AEmtfcG9zaXRpb25TZXF1ZW5jZQISa19wb3NpdGlvblNlcXVlbmNlAA9rX3Bvc2l0aW9uQXNzZXQCD2tfcG9zaXRpb25Bc3NldAANa19wb3NpdGlvbkZlZQINa19wb3NpdGlvbkZlZQAea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wAhNrX3Bvc2l0aW9uVGltZXN0YW1wAA1rX2luaXRpYWxpemVkAg1rX2luaXRpYWxpemVkAAhrX3BhdXNlZAIIa19wYXVzZWQAC2tfY2xvc2VPbmx5AgtrX2Nsb3NlT25seQAFa19mZWUCBWtfZmVlAA1rX3JvbGxvdmVyRmVlAg5rX3JvbGxvdmVyX2ZlZQAPa19mdW5kaW5nUGVyaW9kAg9rX2Z1bmRpbmdQZXJpb2QAEWtfaW5pdE1hcmdpblJhdGlvAhFrX2luaXRNYXJnaW5SYXRpbwAYa19tYWludGVuYW5jZU1hcmdpblJhdGlvAgVrX21tcgAVa19saXF1aWRhdGlvbkZlZVJhdGlvAhVrX2xpcXVpZGF0aW9uRmVlUmF0aW8AGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8CFmtfcGFydExpcXVpZGF0aW9uUmF0aW8ADWtfc3ByZWFkTGltaXQCDWtfc3ByZWFkTGltaXQAEGtfbWF4UHJpY2VJbXBhY3QCEGtfbWF4UHJpY2VJbXBhY3QAEGtfbWF4UHJpY2VTcHJlYWQCEGtfbWF4UHJpY2VTcHJlYWQAEWtfbWF4T3Blbk5vdGlvbmFsAhFrX21heE9wZW5Ob3Rpb25hbAAVa19mZWVUb1N0YWtlcnNQZXJjZW50AhVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQAEGtfbWF4T3JhY2xlRGVsYXkCEGtfbWF4T3JhY2xlRGVsYXkADWtfbGFzdERhdGFTdHICDWtfbGFzdERhdGFTdHIADmtfbGFzdE1pbnV0ZUlkAg5rX2xhc3RNaW51dGVJZAAda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UCHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlABNrX3R3YXBEYXRhTGFzdFByaWNlAhNrX3R3YXBEYXRhTGFzdFByaWNlABprX3R3YXBEYXRhUHJldmlvdXNNaW51dGVJZAIaa190d2FwRGF0YVByZXZpb3VzTWludXRlSWQAJWtfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CG2tfbGF0ZXN0TG9uZ1ByZW1pdW1GcmFjdGlvbgAma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24CHGtfbGF0ZXN0U2hvcnRQcmVtaXVtRnJhY3Rpb24AEmtfbmV4dEZ1bmRpbmdCbG9jawIea19uZXh0RnVuZGluZ0Jsb2NrTWluVGltZXN0YW1wABFrX2xvbmdGdW5kaW5nUmF0ZQIRa19sb25nRnVuZGluZ1JhdGUAEmtfc2hvcnRGdW5kaW5nUmF0ZQISa19zaG9ydEZ1bmRpbmdSYXRlABNrX3F1b3RlQXNzZXRSZXNlcnZlAghrX3F0QXN0UgASa19iYXNlQXNzZXRSZXNlcnZlAghrX2JzQXN0UgASa19xdW90ZUFzc2V0V2VpZ2h0AghrX3F0QXN0VwARa19iYXNlQXNzZXRXZWlnaHQCCGtfYnNBc3RXABNrX3RvdGFsUG9zaXRpb25TaXplAhNrX3RvdGFsUG9zaXRpb25TaXplABdrX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQIXa190b3RhbExvbmdQb3NpdGlvblNpemUAGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQIYa190b3RhbFNob3J0UG9zaXRpb25TaXplABZrX29wZW5JbnRlcmVzdE5vdGlvbmFsAhZrX29wZW5JbnRlcmVzdE5vdGlvbmFsABNrX29wZW5JbnRlcmVzdFNob3J0AhNrX29wZW5JbnRlcmVzdFNob3J0ABJrX29wZW5JbnRlcmVzdExvbmcCEmtfb3BlbkludGVyZXN0TG9uZwAIa19sYXN0VHgCCGtfbGFzdFR4ABRrX2Nvb3JkaW5hdG9yQWRkcmVzcwIUa19jb29yZGluYXRvckFkZHJlc3MAD2tfdmF1bHRfYWRkcmVzcwIPa192YXVsdF9hZGRyZXNzAA9rX2FkbWluX2FkZHJlc3MCD2tfYWRtaW5fYWRkcmVzcwANa19xdW90ZV9hc3NldAINa19xdW90ZV9hc3NldAAPa19xdW90ZV9zdGFraW5nAg9rX3F1b3RlX3N0YWtpbmcAEWtfc3Rha2luZ19hZGRyZXNzAhFrX3N0YWtpbmdfYWRkcmVzcwAPa19taW5lcl9hZGRyZXNzAg9rX21pbmVyX2FkZHJlc3MAEGtfb3JkZXJzX2FkZHJlc3MCEGtfb3JkZXJzX2FkZHJlc3MAEmtfcmVmZXJyYWxfYWRkcmVzcwISa19yZWZlcnJhbF9hZGRyZXNzABJrX2V4Y2hhbmdlX2FkZHJlc3MCEmtfZXhjaGFuZ2VfYWRkcmVzcwAVa19uZnRfbWFuYWdlcl9hZGRyZXNzAhVrX25mdF9tYW5hZ2VyX2FkZHJlc3MBDnRvQ29tcG9zaXRlS2V5AgRfa2V5CF9hZGRyZXNzCQCsAgIJAKwCAgUEX2tleQIBXwUIX2FkZHJlc3MBC2Nvb3JkaW5hdG9yAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIFBHRoaXMFFGtfY29vcmRpbmF0b3JBZGRyZXNzAhNDb29yZGluYXRvciBub3Qgc2V0AQxhZG1pbkFkZHJlc3MACQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFD2tfYWRtaW5fYWRkcmVzcwEKcXVvdGVBc3NldAAJANkEAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUNa19xdW90ZV9hc3NldAERcXVvdGVBc3NldFN0YWtpbmcACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUPa19xdW90ZV9zdGFraW5nAhtRdW90ZSBhc3NldCBzdGFraW5nIG5vdCBzZXQBDnN0YWtpbmdBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFEWtfc3Rha2luZ19hZGRyZXNzAg9TdGFraW5nIG5vdCBzZXQBDHZhdWx0QWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX3ZhdWx0X2FkZHJlc3MCDVZhdWx0IG5vdCBzZXQBDG1pbmVyQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABQ9rX21pbmVyX2FkZHJlc3MCDU1pbmVyIG5vdCBzZXQBDW9yZGVyc0FkZHJlc3MACQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQkBEUBleHRyTmF0aXZlKDEwNTMpAgkBC2Nvb3JkaW5hdG9yAAUQa19vcmRlcnNfYWRkcmVzcwIOT3JkZXJzIG5vdCBzZXQBD3JlZmVycmFsQWRkcmVzcwAJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBCQERQGV4dHJOYXRpdmUoMTA1MykCCQELY29vcmRpbmF0b3IABRJrX3JlZmVycmFsX2FkZHJlc3MCEFJlZmVycmFsIG5vdCBzZXQBEW5mdE1hbmFnZXJBZGRyZXNzAAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJARFAZXh0ck5hdGl2ZSgxMDUzKQIJAQtjb29yZGluYXRvcgAFFWtfbmZ0X21hbmFnZXJfYWRkcmVzcwITTkZUIE1hbmFnZXIgbm90IHNldAANa190b2tlbl9wYXJhbQINa190b2tlbl9wYXJhbQAMa190b2tlbl90eXBlAgxrX3Rva2VuX3R5cGUAGEZFRV9SRURVQ1RJT05fVE9LRU5fVFlQRQINZmVlX3JlZHVjdGlvbgAIRElSX0xPTkcAAQAJRElSX1NIT1JUAAIADVRXQVBfSU5URVJWQUwADwAHU0VDT05EUwDoBwAPREVDSU1BTF9OVU1CRVJTAAYADERFQ0lNQUxfVU5JVAkAaAIAAQkAaAIJAGgCCQBoAgkAaAIJAGgCAAoACgAKAAoACgAKAA9NSU5VVEVTX0lOX1lFQVIJAGgCAKCKIAUMREVDSU1BTF9VTklUAAdPTkVfREFZCQBoAgCAowUFDERFQ0lNQUxfVU5JVAAPUE5MX09QVElPTl9TUE9UAAEAEVBOTF9PUFRJT05fT1JBQ0xFAAIBAXMBAl94CQCsAgIJAKQDAQUCX3gCASwBBGRpdmQCAl94Al95CQBuBAUCX3gFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQRtdWxkAgJfeAJfeQkAbgQFAl94BQJfeQUMREVDSU1BTF9VTklUBQhIQUxGRVZFTgEFYmRpdmQCAl94Al95CQC9AgQFAl94CQC2AgEFDERFQ0lNQUxfVU5JVAUCX3kFCEhBTEZFVkVOAQVibXVsZAICX3gCX3kJAL0CBAUCX3gFAl95CQC2AgEFDERFQ0lNQUxfVU5JVAUISEFMRkVWRU4BA2FicwECX3gDCQBmAgUCX3gAAAUCX3gJAQEtAQUCX3gBBHZtYXgCAl94Al95AwkAZwIFAl94BQJfeQUCX3gFAl95AQlsaXN0VG9TdHIBBV9saXN0AwkAAAIJAJADAQUFX2xpc3QAAAIACQC5CQIFBV9saXN0AgEsAQlzdHJUb0xpc3QBBF9zdHIDCQAAAgUEX3N0cgIABQNuaWwJALUJAgUEX3N0cgIBLAELcHVzaFRvUXVldWUDBV9saXN0CF9tYXhTaXplBl92YWx1ZQMJAGYCCQCQAwEFBV9saXN0BQhfbWF4U2l6ZQkAzQgCCQDRCAIFBV9saXN0AAAFBl92YWx1ZQkAzQgCBQVfbGlzdAUGX3ZhbHVlAQNpbnQBAWsJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQR0aGlzBQFrCQCsAgICDW5vIHZhbHVlIGZvciAFAWsBBWludE9yAgFrA2RlZgkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBQFrBQNkZWYBBHN0ckECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBBGludEECCF9hZGRyZXNzBF9rZXkEA3ZhbAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCaCAIFCF9hZGRyZXNzBQRfa2V5CQCsAgICEU5vIHZhbHVlIGZvciBrZXkgBQRfa2V5BQN2YWwBCGNiYWxhbmNlAAkBA2ludAEFCWtfYmFsYW5jZQEDZmVlAAkBA2ludAEFBWtfZmVlAQ9yb2xsb3ZlckZlZVJhdGUACQEDaW50AQUNa19yb2xsb3ZlckZlZQEPaW5pdE1hcmdpblJhdGlvAAkBA2ludAEFEWtfaW5pdE1hcmdpblJhdGlvAQZxdEFzdFIACQEDaW50AQUTa19xdW90ZUFzc2V0UmVzZXJ2ZQEGYnNBc3RSAAkBA2ludAEFEmtfYmFzZUFzc2V0UmVzZXJ2ZQEGcXRBc3RXAAkBBWludE9yAgUSa19xdW90ZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBBmJzQXN0VwAJAQVpbnRPcgIFEWtfYmFzZUFzc2V0V2VpZ2h0BQxERUNJTUFMX1VOSVQBEXRvdGFsUG9zaXRpb25TaXplAAkBA2ludAEFE2tfdG90YWxQb3NpdGlvblNpemUBFG9wZW5JbnRlcmVzdE5vdGlvbmFsAAkBA2ludAEFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwBEW9wZW5JbnRlcmVzdFNob3J0AAkBA2ludAEFE2tfb3BlbkludGVyZXN0U2hvcnQBEG9wZW5JbnRlcmVzdExvbmcACQEDaW50AQUSa19vcGVuSW50ZXJlc3RMb25nARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAkBA2ludAEFEmtfbmV4dEZ1bmRpbmdCbG9jawEQZnVuZGluZ1BlcmlvZFJhdwAJAQNpbnQBBQ9rX2Z1bmRpbmdQZXJpb2QBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAkAaAIJARBmdW5kaW5nUGVyaW9kUmF3AAUMREVDSU1BTF9VTklUARRmdW5kaW5nUGVyaW9kU2Vjb25kcwAJAGgCCQEQZnVuZGluZ1BlcmlvZFJhdwAFB1NFQ09ORFMBFm1haW50ZW5hbmNlTWFyZ2luUmF0aW8ACQEDaW50AQUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkBA2ludAEFFWtfbGlxdWlkYXRpb25GZWVSYXRpbwEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQEDaW50AQUZa19wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwELc3ByZWFkTGltaXQACQEDaW50AQUNa19zcHJlYWRMaW1pdAEObWF4UHJpY2VJbXBhY3QACQEDaW50AQUQa19tYXhQcmljZUltcGFjdAEObWF4UHJpY2VTcHJlYWQACQEDaW50AQUQa19tYXhQcmljZVNwcmVhZAEPbWF4T3Blbk5vdGlvbmFsAAkBA2ludAEFEWtfbWF4T3Blbk5vdGlvbmFsASNsYXRlc3RMb25nQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgAJAQNpbnQBBSVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ACQEDaW50AQUma19sYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQEDaW50AQUYa190b3RhbFNob3J0UG9zaXRpb25TaXplARV0b3RhbExvbmdQb3NpdGlvblNpemUACQEDaW50AQUXa190b3RhbExvbmdQb3NpdGlvblNpemUBDGxhc3RTZXF1ZW5jZQAJAQVpbnRPcgIFCmtfc2VxdWVuY2UAAAETZmVlVG9TdGFrZXJzUGVyY2VudAAJAQNpbnQBBRVrX2ZlZVRvU3Rha2Vyc1BlcmNlbnQBDm1heE9yYWNsZURlbGF5AAkBA2ludAEFEGtfbWF4T3JhY2xlRGVsYXkBDWxhc3RUaW1lc3RhbXAACAUJbGFzdEJsb2NrCXRpbWVzdGFtcAEPZ2V0QWN0dWFsQ2FsbGVyAQFpCQELdmFsdWVPckVsc2UCCQCdCAIJAQ1vcmRlcnNBZGRyZXNzAAIIa19zZW5kZXIJAKUIAQgFAWkGY2FsbGVyARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwxfbWFyZ2luUmF0aW8QX2Jhc2VNYXJnaW5SYXRpbxRfbGFyZ2VyVGhhbk9yRXF1YWxUbwQUcmVtYWluaW5nTWFyZ2luUmF0aW8JAGUCBQxfbWFyZ2luUmF0aW8FEF9iYXNlTWFyZ2luUmF0aW8DAwUUX2xhcmdlclRoYW5PckVxdWFsVG8JAGYCAAAFFHJlbWFpbmluZ01hcmdpblJhdGlvBwkAAgEJAKwCAgkArAICCQCsAgICEEludmFsaWQgbWFyZ2luOiAJAKQDAQUMX21hcmdpblJhdGlvAgMgPCAJAKQDAQUQX2Jhc2VNYXJnaW5SYXRpbwMDCQEBIQEFFF9sYXJnZXJUaGFuT3JFcXVhbFRvCQBnAgUUcmVtYWluaW5nTWFyZ2luUmF0aW8AAAcJAAIBCQCsAgIJAKwCAgkArAICAhBJbnZhbGlkIG1hcmdpbjogCQCkAwEFDF9tYXJnaW5SYXRpbwIDID4gCQCkAwEFEF9iYXNlTWFyZ2luUmF0aW8GAR9sYXRlc3RDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAQ1fcG9zaXRpb25TaXplAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECLFNob3VsZCBub3QgYmUgY2FsbGVkIHdpdGggX3Bvc2l0aW9uU2l6ZSA9PSAwAwkAZgIFDV9wb3NpdGlvblNpemUAAAkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAkBJGxhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgABC2dldFBvc2l0aW9uAQdfdHJhZGVyBA9wb3NpdGlvblNpemVPcHQJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFB190cmFkZXIEByRtYXRjaDAFD3Bvc2l0aW9uU2l6ZU9wdAMJAAECBQckbWF0Y2gwAgNJbnQEDHBvc2l0aW9uU2l6ZQUHJG1hdGNoMAkAlwoFBQxwb3NpdGlvblNpemUJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FB190cmFkZXIJARFAZXh0ck5hdGl2ZSgxMDUwKQIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFHmtfcG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAUHX3RyYWRlcgkAlwoFAAAAAAAAAAAAAAEQZ2V0UG9zaXRpb25Bc3NldAEHX3RyYWRlcgQQcG9zaXRpb25Bc3NldE9wdAkAnQgCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBQ9rX3Bvc2l0aW9uQXNzZXQFB190cmFkZXIEByRtYXRjaDAFEHBvc2l0aW9uQXNzZXRPcHQDCQABAgUHJG1hdGNoMAIGU3RyaW5nBA1wb3NpdGlvbkFzc2V0BQckbWF0Y2gwBQ1wb3NpdGlvbkFzc2V0CQDYBAEJAQpxdW90ZUFzc2V0AAEOZ2V0UG9zaXRpb25GZWUBB190cmFkZXIEDnBvc2l0aW9uRmVlT3B0CQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFB190cmFkZXIEByRtYXRjaDAFDnBvc2l0aW9uRmVlT3B0AwkAAQIFByRtYXRjaDACA0ludAQLcG9zaXRpb25GZWUFByRtYXRjaDAFC3Bvc2l0aW9uRmVlCQEDZmVlAAETcmVxdWlyZU9wZW5Qb3NpdGlvbgEHX3RyYWRlcgMJAAACCAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgJfMQAACQACAQIQTm8gb3BlbiBwb3NpdGlvbgYBDWdldE9yYWNsZURhdGEBA2tleQQNb3JhY2xlRGF0YVN0cgkAnQgCBQR0aGlzBQNrZXkDAwkBCWlzRGVmaW5lZAEFDW9yYWNsZURhdGFTdHIJAQIhPQIJAQV2YWx1ZQEFDW9yYWNsZURhdGFTdHICAAcECm9yYWNsZURhdGEJALUJAgkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgIBLAQNb3JhY2xlQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCmCAEJAJEDAgUKb3JhY2xlRGF0YQAACQCsAgICG0ludmFsaWQgb3JhY2xlIGFkZHJlc3MgaW46IAkBBXZhbHVlAQUNb3JhY2xlRGF0YVN0cgQIcHJpY2VLZXkJAJEDAgUKb3JhY2xlRGF0YQABBAhibG9ja0tleQkAkQMCBQpvcmFjbGVEYXRhAAIEB29wZW5LZXkJAJEDAgUKb3JhY2xlRGF0YQADCQCWCgQFDW9yYWNsZUFkZHJlc3MFCHByaWNlS2V5BQhibG9ja0tleQUHb3BlbktleQUEdW5pdAELaW5pdGlhbGl6ZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFDWtfaW5pdGlhbGl6ZWQHAQZwYXVzZWQACQELdmFsdWVPckVsc2UCCQCbCAIFBHRoaXMFCGtfcGF1c2VkBwEJY2xvc2VPbmx5AAkBC3ZhbHVlT3JFbHNlAgkAmwgCBQR0aGlzBQtrX2Nsb3NlT25seQcBDXVwZGF0ZVJlc2VydmUDBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudBBfYmFzZUFzc2V0QW1vdW50AwUGX2lzQWRkBAduZXdCYXNlCQBlAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQDCQBnAgAABQduZXdCYXNlCQACAQIqVHggbGVhZCB0byBiYXNlIGFzc2V0IHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMJAGQCCQEGcXRBc3RSAAURX3F1b3RlQXNzZXRBbW91bnQFB25ld0Jhc2UJAGQCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50BAhuZXdRdW90ZQkAZQIJAQZxdEFzdFIABRFfcXVvdGVBc3NldEFtb3VudAMJAGcCAAAFCG5ld1F1b3RlCQACAQIqVHggbGVhZCB0byBiYXNlIHF1b3RlIHJlc2VydmUgPD0gMCwgcmV2ZXJ0CQCVCgMFCG5ld1F1b3RlCQBkAgkBBmJzQXN0UgAFEF9iYXNlQXNzZXRBbW91bnQJAGUCCQERdG90YWxQb3NpdGlvblNpemUABRBfYmFzZUFzc2V0QW1vdW50AQ1jYWxjSW52YXJpYW50AgdfcXRBc3RSB19ic0FzdFIEB2JxdEFzdFIJALYCAQUHX3F0QXN0UgQHYmJzQXN0UgkAtgIBBQdfYnNBc3RSCQEFYm11bGQCBQdicXRBc3RSBQdiYnNBc3RSAQlzd2FwSW5wdXQCBl9pc0FkZBFfcXVvdGVBc3NldEFtb3VudAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwAEGHF1b3RlQXNzZXRBbW91bnRBZGp1c3RlZAkBBGRpdmQCBRFfcXVvdGVBc3NldEFtb3VudAUHX3F0QXN0VwQBawkBDWNhbGNJbnZhcmlhbnQCBQdfcXRBc3RSBQdfYnNBc3RSBBZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyAwUGX2lzQWRkCQBkAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkCQBlAgUHX3F0QXN0UgUYcXVvdGVBc3NldEFtb3VudEFkanVzdGVkBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIJAKADAQkBBWJkaXZkAgUBawkAtgIBBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBBhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMJAQNhYnMBCQBlAgUVYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyBQdfYnNBc3RSBBVhbW91bnRCYXNlQXNzZXRCb3VnaHQDBQZfaXNBZGQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwkBAS0BBRhhbW91bnRCYXNlQXNzZXRCb3VnaHRBYnMEDSR0MDE2NzIyMTY4OTIJAQ11cGRhdGVSZXNlcnZlAwUGX2lzQWRkBRhxdW90ZUFzc2V0QW1vdW50QWRqdXN0ZWQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEIBQ0kdDAxNjcyMjE2ODkyAl8xBBZiYXNlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMTY3MjIxNjg5MgJfMgQXdG90YWxQb3NpdGlvblNpemVBZnRlcjEIBQ0kdDAxNjcyMjE2ODkyAl8zBAtwcmljZUJlZm9yZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLbWFya2V0UHJpY2UJAQRkaXZkAgURX3F1b3RlQXNzZXRBbW91bnQFGGFtb3VudEJhc2VBc3NldEJvdWdodEFicwQJcHJpY2VEaWZmCQEDYWJzAQkAZQIFC3ByaWNlQmVmb3JlBQttYXJrZXRQcmljZQQLcHJpY2VJbXBhY3QJAGUCBQxERUNJTUFMX1VOSVQJAQRkaXZkAgULcHJpY2VCZWZvcmUJAGQCBQtwcmljZUJlZm9yZQUJcHJpY2VEaWZmBBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QAAwkAZgIFC3ByaWNlSW1wYWN0BRNtYXhQcmljZUltcGFjdFZhbHVlCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICAg1QcmljZSBpbXBhY3QgCQCkAwEFC3ByaWNlSW1wYWN0AhQgPiBtYXggcHJpY2UgaW1wYWN0IAkApAMBBRNtYXhQcmljZUltcGFjdFZhbHVlAhUgYmVmb3JlIHF1b3RlIGFzc2V0OiAJAKQDAQUHX3F0QXN0UgIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQUHX2JzQXN0UgIhIHF1b3RlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEV9xdW90ZUFzc2V0QW1vdW50Ag8gcHJpY2UgYmVmb3JlOiAJAKQDAQULcHJpY2VCZWZvcmUCDiBtYXJrZXRQcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCWCgQFFWFtb3VudEJhc2VBc3NldEJvdWdodAUXcXVvdGVBc3NldFJlc2VydmVBZnRlcjEFFmJhc2VBc3NldFJlc2VydmVBZnRlcjEFF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxAQ9jYWxjUm9sbG92ZXJGZWUCEl9vbGRQb3NpdGlvbk1hcmdpbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAQPcG9zaXRpb25NaW51dGVzCQBoAgkAaQIJAGkCCQBlAgkBDWxhc3RUaW1lc3RhbXAABSBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcADoBwA8BQxERUNJTUFMX1VOSVQEC3JvbGxvdmVyRmVlCQEEZGl2ZAIJAQRtdWxkAgkBBG11bGQCBRJfb2xkUG9zaXRpb25NYXJnaW4FD3Bvc2l0aW9uTWludXRlcwkBD3JvbGxvdmVyRmVlUmF0ZQAFD01JTlVURVNfSU5fWUVBUgULcm9sbG92ZXJGZWUBMGNhbGNSZW1haW5NYXJnaW5XaXRoRnVuZGluZ1BheW1lbnRBbmRSb2xsb3ZlckZlZQUQX29sZFBvc2l0aW9uU2l6ZRJfb2xkUG9zaXRpb25NYXJnaW4lX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbiBfb2xkUG9zaXRpb25MYXN0VXBkYXRlZFRpbWVzdGFtcAxfbWFyZ2luRGVsdGEEDmZ1bmRpbmdQYXltZW50AwkBAiE9AgUQX29sZFBvc2l0aW9uU2l6ZQAABCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkBH2xhdGVzdEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24BBRBfb2xkUG9zaXRpb25TaXplCQEEbXVsZAIJAGUCBSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUlX29sZFBvc2l0aW9uQ3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgUQX29sZFBvc2l0aW9uU2l6ZQAABAtyb2xsb3ZlckZlZQkBD2NhbGNSb2xsb3ZlckZlZQIFEl9vbGRQb3NpdGlvbk1hcmdpbgUgX29sZFBvc2l0aW9uTGFzdFVwZGF0ZWRUaW1lc3RhbXAEDHNpZ25lZE1hcmdpbgkAZAIJAGUCCQBlAgUMX21hcmdpbkRlbHRhBQtyb2xsb3ZlckZlZQUOZnVuZGluZ1BheW1lbnQFEl9vbGRQb3NpdGlvbk1hcmdpbgQNJHQwMTkxNDcxOTI3NAMJAGYCAAAFDHNpZ25lZE1hcmdpbgkAlAoCAAAJAQNhYnMBBQxzaWduZWRNYXJnaW4JAJQKAgkBA2FicwEFDHNpZ25lZE1hcmdpbgAABAxyZW1haW5NYXJnaW4IBQ0kdDAxOTE0NzE5Mjc0Al8xBAdiYWREZWJ0CAUNJHQwMTkxNDcxOTI3NAJfMgkAlgoEBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFDmZ1bmRpbmdQYXltZW50BQtyb2xsb3ZlckZlZQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QSX3F1b3RlQXNzZXRSZXNlcnZlEV9xdW90ZUFzc2V0V2VpZ2h0EV9iYXNlQXNzZXRSZXNlcnZlEF9iYXNlQXNzZXRXZWlnaHQEC3ByaWNlQmVmb3JlCQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAMJAAACBRBfYmFzZUFzc2V0QW1vdW50AAAJAAIBAhlJbnZhbGlkIGJhc2UgYXNzZXQgYW1vdW50BAFrCQENY2FsY0ludmFyaWFudAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQURX2Jhc2VBc3NldFJlc2VydmUEGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgMFBl9pc0FkZAkAZAIFEV9iYXNlQXNzZXRSZXNlcnZlBRBfYmFzZUFzc2V0QW1vdW50CQBlAgURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRBbW91bnQED3F1b3RlQXNzZXRBZnRlcgkAoAMBCQEFYmRpdmQCBQFrCQC2AgEFGGJhc2VBc3NldFBvb2xBbW91bnRBZnRlcgQPcXVvdGVBc3NldERlbHRhCQEDYWJzAQkAZQIFD3F1b3RlQXNzZXRBZnRlcgUSX3F1b3RlQXNzZXRSZXNlcnZlBA5xdW90ZUFzc2V0U29sZAkBBG11bGQCBQ9xdW90ZUFzc2V0RGVsdGEFEV9xdW90ZUFzc2V0V2VpZ2h0BBNtYXhQcmljZUltcGFjdFZhbHVlCQEObWF4UHJpY2VJbXBhY3QABA0kdDAyMDUzNjIwNjk4CQENdXBkYXRlUmVzZXJ2ZQMJAQEhAQUGX2lzQWRkBQ9xdW90ZUFzc2V0RGVsdGEFEF9iYXNlQXNzZXRBbW91bnQEF3F1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIxCAUNJHQwMjA1MzYyMDY5OAJfMQQWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQgFDSR0MDIwNTM2MjA2OTgCXzIEF3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIxCAUNJHQwMjA1MzYyMDY5OAJfMwQLbWFya2V0UHJpY2UJAQRkaXZkAgUOcXVvdGVBc3NldFNvbGQFEF9iYXNlQXNzZXRBbW91bnQECXByaWNlRGlmZgkBA2FicwEJAGUCBQtwcmljZUJlZm9yZQULbWFya2V0UHJpY2UEC3ByaWNlSW1wYWN0CQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIFC3ByaWNlQmVmb3JlCQBkAgULcHJpY2VCZWZvcmUFCXByaWNlRGlmZgMDCQBmAgULcHJpY2VJbXBhY3QFE21heFByaWNlSW1wYWN0VmFsdWUFFF9jaGVja01heFByaWNlSW1wYWN0BwkAAgEJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgINUHJpY2UgaW1wYWN0IAkApAMBBQtwcmljZUltcGFjdAIUID4gbWF4IHByaWNlIGltcGFjdCAJAKQDAQUTbWF4UHJpY2VJbXBhY3RWYWx1ZQIVIGJlZm9yZSBxdW90ZSBhc3NldDogCQCkAwEFEl9xdW90ZUFzc2V0UmVzZXJ2ZQIUIGJlZm9yZSBiYXNlIGFzc2V0OiAJAKQDAQURX2Jhc2VBc3NldFJlc2VydmUCICBiYXNlIGFzc2V0IGFtb3VudCB0byBleGNoYW5nZTogCQCkAwEFEF9iYXNlQXNzZXRBbW91bnQCDyBwcmljZSBiZWZvcmU6IAkApAMBBQtwcmljZUJlZm9yZQIPIG1hcmtldCBwcmljZTogCQCkAwEFC21hcmtldFByaWNlCQCZCgcFDnF1b3RlQXNzZXRTb2xkBRdxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyMQUWYmFzZUFzc2V0UmVzZXJ2ZUFmdGVyMQUXdG90YWxQb3NpdGlvblNpemVBZnRlcjEJAGUCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMFBl9pc0FkZAkBA2FicwEFEF9iYXNlQXNzZXRBbW91bnQAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUGX2lzQWRkCQEDYWJzAQUQX2Jhc2VBc3NldEFtb3VudAAABQtwcmljZUltcGFjdAEKc3dhcE91dHB1dAMGX2lzQWRkEF9iYXNlQXNzZXRBbW91bnQUX2NoZWNrTWF4UHJpY2VJbXBhY3QJARZzd2FwT3V0cHV0V2l0aFJlc2VydmVzBwUGX2lzQWRkBRBfYmFzZUFzc2V0QW1vdW50BRRfY2hlY2tNYXhQcmljZUltcGFjdAkBBnF0QXN0UgAJAQZxdEFzdFcACQEGYnNBc3RSAAkBBmJzQXN0VwABE2dldE9yYWNsZVByaWNlVmFsdWUDBm9yYWNsZQhwcmljZUtleQhibG9ja0tleQQJbGFzdFZhbHVlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAJoIAgUGb3JhY2xlBQhwcmljZUtleQkArAICCQCsAgIJAKwCAgIiQ2FuIG5vdCBnZXQgb3JhY2xlIHByaWNlLiBPcmFjbGU6IAkApQgBBQZvcmFjbGUCBiBrZXk6IAUIcHJpY2VLZXkDCQECIT0CBQhibG9ja0tleQIABAxjdXJyZW50QmxvY2sIBQlsYXN0QmxvY2sGaGVpZ2h0BA9sYXN0T3JhY2xlQmxvY2sJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmggCBQZvcmFjbGUFCGJsb2NrS2V5CQCsAgIJAKwCAgkArAICAiJDYW4gbm90IGdldCBvcmFjbGUgYmxvY2suIE9yYWNsZTogCQClCAEFBm9yYWNsZQIGIGtleTogBQhibG9ja0tleQMJAGYCCQBlAgUMY3VycmVudEJsb2NrBQ9sYXN0T3JhY2xlQmxvY2sJAQ5tYXhPcmFjbGVEZWxheQAJAAIBCQCsAgIJAKwCAgkArAICAiZPcmFjbGUgc3RhbGUgZGF0YS4gTGFzdCBvcmFjbGUgYmxvY2s6IAkApAMBBQ9sYXN0T3JhY2xlQmxvY2sCECBjdXJyZW50IGJsb2NrOiAJAKQDAQUMY3VycmVudEJsb2NrBQlsYXN0VmFsdWUFCWxhc3RWYWx1ZQEOZ2V0T3JhY2xlUHJpY2UABApiYXNlT3JhY2xlCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAQ1nZXRPcmFjbGVEYXRhAQUMa19iYXNlT3JhY2xlAhlObyBiYXNlIGFzc2V0IG9yYWNsZSBkYXRhBA9iYXNlT3JhY2xlUHJpY2UJARNnZXRPcmFjbGVQcmljZVZhbHVlAwgFCmJhc2VPcmFjbGUCXzEIBQpiYXNlT3JhY2xlAl8yCAUKYmFzZU9yYWNsZQJfMwQLcXVvdGVPcmFjbGUJAQ1nZXRPcmFjbGVEYXRhAQUNa19xdW90ZU9yYWNsZQQQcXVvdGVPcmFjbGVQcmljZQMJAQlpc0RlZmluZWQBBQtxdW90ZU9yYWNsZQQMcXVvdGVPcmFjbGVWCQEFdmFsdWUBBQtxdW90ZU9yYWNsZQkBE2dldE9yYWNsZVByaWNlVmFsdWUDCAUMcXVvdGVPcmFjbGVWAl8xCAUMcXVvdGVPcmFjbGVWAl8yCAUMcXVvdGVPcmFjbGVWAl8zBQxERUNJTUFMX1VOSVQJAQRkaXZkAgUPYmFzZU9yYWNsZVByaWNlBRBxdW90ZU9yYWNsZVByaWNlAQ5pc01hcmtldENsb3NlZAAECmJhc2VPcmFjbGUJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkBDWdldE9yYWNsZURhdGEBBQxrX2Jhc2VPcmFjbGUCGU5vIGJhc2UgYXNzZXQgb3JhY2xlIGRhdGEEBm9yYWNsZQgFCmJhc2VPcmFjbGUCXzEEB29wZW5LZXkIBQpiYXNlT3JhY2xlAl80AwkBAiE9AgUHb3BlbktleQIABAZpc09wZW4JARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAmwgCBQZvcmFjbGUFB29wZW5LZXkJAKwCAgkArAICCQCsAgICK0NhbiBub3QgZ2V0IG9yYWNsZSBpcyBvcGVuL2Nsb3NlZC4gT3JhY2xlOiAJAKUIAQUGb3JhY2xlAgYga2V5OiAFB29wZW5LZXkJAQEhAQUGaXNPcGVuBwEMYWJzUHJpY2VEaWZmBQxfb3JhY2xlUHJpY2USX3F1b3RlQXNzZXRSZXNlcnZlEV9iYXNlQXNzZXRSZXNlcnZlB19xdEFzdFcHX2JzQXN0VwQKcHJpY2VBZnRlcgkBBGRpdmQCCQEEbXVsZAIFEl9xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0VwkBBG11bGQCBRFfYmFzZUFzc2V0UmVzZXJ2ZQUHX2JzQXN0VwQMYXZlcmFnZVByaWNlCQEEZGl2ZAIJAGQCBQxfb3JhY2xlUHJpY2UFCnByaWNlQWZ0ZXIJAGgCAAIFDERFQ0lNQUxfVU5JVAQMYWJzUHJpY2VEaWZmCQEEZGl2ZAIJAQNhYnMBCQBlAgUMX29yYWNsZVByaWNlBQpwcmljZUFmdGVyBQxhdmVyYWdlUHJpY2UFDGFic1ByaWNlRGlmZgEZcmVxdWlyZU5vdE92ZXJTcHJlYWRMaW1pdAISX3F1b3RlQXNzZXRSZXNlcnZlEV9iYXNlQXNzZXRSZXNlcnZlBAtvcmFjbGVQcmljZQkBDmdldE9yYWNsZVByaWNlAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABBJhYnNQcmljZURpZmZCZWZvcmUJAQxhYnNQcmljZURpZmYFBQtvcmFjbGVQcmljZQkBBnF0QXN0UgAJAQZic0FzdFIABQdfcXRBc3RXBQdfYnNBc3RXBBFhYnNQcmljZURpZmZBZnRlcgkBDGFic1ByaWNlRGlmZgUFC29yYWNsZVByaWNlBRJfcXVvdGVBc3NldFJlc2VydmUFEV9iYXNlQXNzZXRSZXNlcnZlBQdfcXRBc3RXBQdfYnNBc3RXAwMJAGYCBRFhYnNQcmljZURpZmZBZnRlcgkBDm1heFByaWNlU3ByZWFkAAkAZgIFEWFic1ByaWNlRGlmZkFmdGVyBRJhYnNQcmljZURpZmZCZWZvcmUHCQACAQkArAICCQCsAgIJAKwCAgINUHJpY2Ugc3ByZWFkIAkApAMBBRFhYnNQcmljZURpZmZBZnRlcgIUID4gbWF4IHByaWNlIHNwcmVhZCAJAKQDAQkBDm1heFByaWNlU3ByZWFkAAYBHXJlcXVpcmVOb3RPdmVyTWF4T3Blbk5vdGlvbmFsAhFfbG9uZ09wZW5Ob3Rpb25hbBJfc2hvcnRPcGVuTm90aW9uYWwEEF9tYXhPcGVuTm90aW9uYWwJAQ9tYXhPcGVuTm90aW9uYWwAAwkAZgIFEV9sb25nT3Blbk5vdGlvbmFsBRBfbWF4T3Blbk5vdGlvbmFsCQACAQkArAICCQCsAgIJAKwCAgITTG9uZyBvcGVuIG5vdGlvbmFsIAkApAMBBRFfbG9uZ09wZW5Ob3Rpb25hbAIVID4gbWF4IG9wZW4gbm90aW9uYWwgCQCkAwEFEF9tYXhPcGVuTm90aW9uYWwDCQBmAgUSX3Nob3J0T3Blbk5vdGlvbmFsBRBfbWF4T3Blbk5vdGlvbmFsCQACAQkArAICCQCsAgIJAKwCAgIUU2hvcnQgb3BlbiBub3Rpb25hbCAJAKQDAQUSX3Nob3J0T3Blbk5vdGlvbmFsAhUgPiBtYXggb3BlbiBub3Rpb25hbCAJAKQDAQUQX21heE9wZW5Ob3Rpb25hbAYBDGdldFNwb3RQcmljZQAEEl9xdW90ZUFzc2V0UmVzZXJ2ZQkBBnF0QXN0UgAEEV9iYXNlQXNzZXRSZXNlcnZlCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcACQEEZGl2ZAIJAQRtdWxkAgUSX3F1b3RlQXNzZXRSZXNlcnZlBQdfcXRBc3RXCQEEbXVsZAIFEV9iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RXARZpc092ZXJGbHVjdHVhdGlvbkxpbWl0AAQLb3JhY2xlUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDGN1cnJlbnRQcmljZQkBDGdldFNwb3RQcmljZQAJAGYCCQEEZGl2ZAIJAQNhYnMBCQBlAgULb3JhY2xlUHJpY2UFDGN1cnJlbnRQcmljZQULb3JhY2xlUHJpY2UJAQtzcHJlYWRMaW1pdAABH2dldFBvc2l0aW9uQWRqdXN0ZWRPcGVuTm90aW9uYWwGDV9wb3NpdGlvblNpemUHX29wdGlvbhJfcXVvdGVBc3NldFJlc2VydmURX3F1b3RlQXNzZXRXZWlnaHQRX2Jhc2VBc3NldFJlc2VydmUQX2Jhc2VBc3NldFdlaWdodAQPcG9zaXRpb25TaXplQWJzCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQQHaXNTaG9ydAkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQQQcG9zaXRpb25Ob3Rpb25hbAMJAAACBQdfb3B0aW9uBQ9QTkxfT1BUSU9OX1NQT1QEE291dFBvc2l0aW9uTm90aW9uYWwICQEWc3dhcE91dHB1dFdpdGhSZXNlcnZlcwcJAQEhAQUHaXNTaG9ydAUPcG9zaXRpb25TaXplQWJzBwUSX3F1b3RlQXNzZXRSZXNlcnZlBRFfcXVvdGVBc3NldFdlaWdodAURX2Jhc2VBc3NldFJlc2VydmUFEF9iYXNlQXNzZXRXZWlnaHQCXzEFE291dFBvc2l0aW9uTm90aW9uYWwJAQRtdWxkAgUPcG9zaXRpb25TaXplQWJzCQEOZ2V0T3JhY2xlUHJpY2UABRBwb3NpdGlvbk5vdGlvbmFsAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBw1fcG9zaXRpb25TaXplFV9wb3NpdGlvbk9wZW5Ob3Rpb25hbBJfcXVvdGVBc3NldFJlc2VydmURX3F1b3RlQXNzZXRXZWlnaHQRX2Jhc2VBc3NldFJlc2VydmUQX2Jhc2VBc3NldFdlaWdodAdfb3B0aW9uAwkAAAIFDV9wb3NpdGlvblNpemUAAAkAAgECFUludmFsaWQgcG9zaXRpb24gc2l6ZQQHaXNTaG9ydAkAZgIAAAUNX3Bvc2l0aW9uU2l6ZQQQcG9zaXRpb25Ob3Rpb25hbAkBH2dldFBvc2l0aW9uQWRqdXN0ZWRPcGVuTm90aW9uYWwGBQ1fcG9zaXRpb25TaXplBQdfb3B0aW9uBRJfcXVvdGVBc3NldFJlc2VydmUFEV9xdW90ZUFzc2V0V2VpZ2h0BRFfYmFzZUFzc2V0UmVzZXJ2ZQUQX2Jhc2VBc3NldFdlaWdodAQNdW5yZWFsaXplZFBubAMFB2lzU2hvcnQJAGUCBRVfcG9zaXRpb25PcGVuTm90aW9uYWwFEHBvc2l0aW9uTm90aW9uYWwJAGUCBRBwb3NpdGlvbk5vdGlvbmFsBRVfcG9zaXRpb25PcGVuTm90aW9uYWwJAJQKAgUQcG9zaXRpb25Ob3Rpb25hbAUNdW5yZWFsaXplZFBubAEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCB190cmFkZXIHX29wdGlvbgQNJHQwMjg1NzYyODcwNAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwMjg1NzYyODcwNAJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyODU3NjI4NzA0Al8yBBRwb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDI4NTc2Mjg3MDQCXzMEEXBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMjg1NzYyODcwNAJfNAkBK2dldFBvc2l0aW9uTm90aW9uYWxBbmRVbnJlYWxpemVkUG5sQnlWYWx1ZXMHBQxwb3NpdGlvblNpemUFFHBvc2l0aW9uT3Blbk5vdGlvbmFsCQEGcXRBc3RSAAkBBnF0QXN0VwAJAQZic0FzdFIACQEGYnNBc3RXAAUHX29wdGlvbgEPY2FsY01hcmdpblJhdGlvAw1fcmVtYWluTWFyZ2luCF9iYWREZWJ0EV9wb3NpdGlvbk5vdGlvbmFsCQEEZGl2ZAIJAGUCBQ1fcmVtYWluTWFyZ2luBQhfYmFkRGVidAURX3Bvc2l0aW9uTm90aW9uYWwBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CB190cmFkZXIHX29wdGlvbgQNJHQwMjkyMTkyOTM2MAkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQMcG9zaXRpb25TaXplCAUNJHQwMjkyMTkyOTM2MAJfMQQOcG9zaXRpb25NYXJnaW4IBQ0kdDAyOTIxOTI5MzYwAl8yBANwb24IBQ0kdDAyOTIxOTI5MzYwAl8zBBZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGCAUNJHQwMjkyMTkyOTM2MAJfNAQRcG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAyOTIxOTI5MzYwAl81BA0kdDAyOTM2NjI5NDU5CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCBQdfdHJhZGVyBQdfb3B0aW9uBBBwb3NpdGlvbk5vdGlvbmFsCAUNJHQwMjkzNjYyOTQ1OQJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDI5MzY2Mjk0NTkCXzIEDSR0MDI5NDY0Mjk2NzYJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQxwb3NpdGlvblNpemUFDnBvc2l0aW9uTWFyZ2luBRZwb3NpdGlvbkxhc3RVcGRhdGVkQ1BGBRFwb3NpdGlvblRpbWVzdGFtcAUNdW5yZWFsaXplZFBubAQMcmVtYWluTWFyZ2luCAUNJHQwMjk0NjQyOTY3NgJfMQQHYmFkRGVidAgFDSR0MDI5NDY0Mjk2NzYCXzIJAQ9jYWxjTWFyZ2luUmF0aW8DBQxyZW1haW5NYXJnaW4FB2JhZERlYnQFEHBvc2l0aW9uTm90aW9uYWwBDmdldE1hcmdpblJhdGlvAQdfdHJhZGVyCQEWZ2V0TWFyZ2luUmF0aW9CeU9wdGlvbgIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAEbZ2V0UGFydGlhbExpcXVpZGF0aW9uQW1vdW50AgdfdHJhZGVyDV9wb3NpdGlvblNpemUEDG1heGltdW1SYXRpbwkBBHZtYXgCCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8ACQBlAgUMREVDSU1BTF9VTklUCQEEZGl2ZAIJAQ5nZXRNYXJnaW5SYXRpbwEFB190cmFkZXIJARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAQYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplBQxtYXhpbXVtUmF0aW8ECnN3YXBSZXN1bHQJAQpzd2FwT3V0cHV0AwkAZgIFDV9wb3NpdGlvblNpemUAAAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplBwQcbWF4RXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAgFCnN3YXBSZXN1bHQCXzEEC3ByaWNlSW1wYWN0CAUKc3dhcFJlc3VsdAJfNwMJAGYCCQEObWF4UHJpY2VJbXBhY3QABQtwcmljZUltcGFjdAUYbWF4RXhjaGFuZ2VkUG9zaXRpb25TaXplCQEEbXVsZAIJAQNhYnMBBQ1fcG9zaXRpb25TaXplCQEXcGFydGlhbExpcXVpZGF0aW9uUmF0aW8AARVpbnRlcm5hbENsb3NlUG9zaXRpb24HB190cmFkZXIFX3NpemUEX2ZlZRRfbWluUXVvdGVBc3NldEFtb3VudAxfYWRkVG9NYXJnaW4UX2NoZWNrTWF4UHJpY2VJbXBhY3QKX2xpcXVpZGF0ZQQNJHQwMzA3NDMzMDg5OQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwMzA3NDMzMDg5OQJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDAzMDc0MzMwODk5Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDMwNzQzMzA4OTkCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwMzA3NDMzMDg5OQJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDAzMDc0MzMwODk5Al81BA5pc0xvbmdQb3NpdGlvbgkAZgIFD29sZFBvc2l0aW9uU2l6ZQAABBJhYnNPbGRQb3NpdGlvblNpemUJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUDAwkAZwIFEmFic09sZFBvc2l0aW9uU2l6ZQUFX3NpemUJAGYCBQVfc2l6ZQAABwQOaXNQYXJ0aWFsQ2xvc2UJAGYCBRJhYnNPbGRQb3NpdGlvblNpemUFBV9zaXplBA0kdDAzMTE5MTMxNjQyCQEKc3dhcE91dHB1dAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAUFX3NpemUFFF9jaGVja01heFByaWNlSW1wYWN0BBlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50CAUNJHQwMzExOTEzMTY0MgJfMQQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDMxMTkxMzE2NDICXzIEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDMxMTkxMzE2NDICXzMEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDAzMTE5MTMxNjQyAl80BBVleGNoYW5nZWRQb3NpdGlvblNpemUDCQBmAgUPb2xkUG9zaXRpb25TaXplAAAJAQEtAQUFX3NpemUFBV9zaXplBA0kdDAzMTg1NzMyMDY0CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEE29sZFBvc2l0aW9uTm90aW9uYWwIBQ0kdDAzMTg1NzMyMDY0Al8xBA11bnJlYWxpemVkUG5sCAUNJHQwMzE4NTczMjA2NAJfMgQNcmVhbGl6ZWRSYXRpbwkBBGRpdmQCCQEDYWJzAQUVZXhjaGFuZ2VkUG9zaXRpb25TaXplBRJhYnNPbGRQb3NpdGlvblNpemUEC3JlYWxpemVkUG5sCQEEbXVsZAIFDXVucmVhbGl6ZWRQbmwFDXJlYWxpemVkUmF0aW8EDSR0MDMyNDA1MzI2NTEJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFDXVucmVhbGl6ZWRQbmwEEnJlbWFpbk1hcmdpbkJlZm9yZQgFDSR0MDMyNDA1MzI2NTECXzEEAngxCAUNJHQwMzI0MDUzMjY1MQJfMgQCeDIIBQ0kdDAzMjQwNTMyNjUxAl8zBAtyb2xsb3ZlckZlZQgFDSR0MDMyNDA1MzI2NTECXzQED3Bvc2l0aW9uQmFkRGVidAgJATBjYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50QW5kUm9sbG92ZXJGZWUFBQ9vbGRQb3NpdGlvblNpemUFEW9sZFBvc2l0aW9uTWFyZ2luBRRvbGRQb3NpdGlvbkxzdFVwZENQRgUUb2xkUG9zaXRpb25UaW1lc3RhbXAFC3JlYWxpemVkUG5sAl8yBBByZWFsaXplZENsb3NlRmVlCQEEbXVsZAIJAQRtdWxkAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUNcmVhbGl6ZWRSYXRpbwUEX2ZlZQQSdW5yZWFsaXplZFBubEFmdGVyCQBlAgUNdW5yZWFsaXplZFBubAULcmVhbGl6ZWRQbmwEEnJlbWFpbk9wZW5Ob3Rpb25hbAMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAGUCBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQBkAgUSdW5yZWFsaXplZFBubEFmdGVyBRNvbGRQb3NpdGlvbk5vdGlvbmFsBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50BA9uZXdQb3NpdGlvblNpemUJAGQCBQ9vbGRQb3NpdGlvblNpemUFFWV4Y2hhbmdlZFBvc2l0aW9uU2l6ZQQNJHQwMzQwNTczNDQ0MwMJAAACBQ9uZXdQb3NpdGlvblNpemUAAAkAlAoCAAAAAAkAlAoCCQEDYWJzAQUScmVtYWluT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQQXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwIBQ0kdDAzNDA1NzM0NDQzAl8xBBRuZXdQb3NpdGlvbkxzdFVwZENQRggFDSR0MDM0MDU3MzQ0NDMCXzIEEW9wZW5Ob3Rpb25hbERlbHRhCQBlAgUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBAttYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBQ9QTkxfT1BUSU9OX1NQT1QEHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwMJAGYCBQ9vbGRQb3NpdGlvblNpemUAAAkAZQIJAQRtdWxkAgkAZAIFF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsBRJ1bnJlYWxpemVkUG5sQWZ0ZXIFC21hcmdpblJhdGlvBRJ1bnJlYWxpemVkUG5sQWZ0ZXIJAGUCCQEEbXVsZAIJAGUCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUSdW5yZWFsaXplZFBubEFmdGVyBQttYXJnaW5SYXRpbwUSdW5yZWFsaXplZFBubEFmdGVyBBFtYXJnaW5Ub1RyYWRlclJhdwkAZQIJAGUCBRJyZW1haW5NYXJnaW5CZWZvcmUJAGQCBR5uZXdQb3NpdGlvbk1hcmdpbldpdGhTYW1lUmF0aW8FEnVucmVhbGl6ZWRQbmxBZnRlcgUQcmVhbGl6ZWRDbG9zZUZlZQQObWFyZ2luVG9UcmFkZXIDCQBmAgAABRFtYXJnaW5Ub1RyYWRlclJhdwMFCl9saXF1aWRhdGUAAAkAAgECN0ludmFsaWQgaW50ZXJuYWxDbG9zZVBvc2l0aW9uIHBhcmFtczogdW5hYmxlIHRvIHBheSBmZWUFEW1hcmdpblRvVHJhZGVyUmF3BBFuZXdQb3NpdGlvbk1hcmdpbgMFDF9hZGRUb01hcmdpbgkAZAIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwUObWFyZ2luVG9UcmFkZXIFHm5ld1Bvc2l0aW9uTWFyZ2luV2l0aFNhbWVSYXRpbwMDCQECIT0CBRRfbWluUXVvdGVBc3NldEFtb3VudAAACQBmAgUUX21pblF1b3RlQXNzZXRBbW91bnQFGWV4Y2hhbmdlZFF1b3RlQXNzZXRBbW91bnQHCQACAQkArAICCQCsAgIJAKwCAgINTGltaXQgZXJyb3I6IAkApAMBBRlleGNoYW5nZWRRdW90ZUFzc2V0QW1vdW50AgMgPCAJAKQDAQUUX21pblF1b3RlQXNzZXRBbW91bnQJAKMKEQUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGBQ9wb3NpdGlvbkJhZERlYnQFC3JlYWxpemVkUG5sAwMFDF9hZGRUb01hcmdpbgUOaXNQYXJ0aWFsQ2xvc2UHAAAFDm1hcmdpblRvVHJhZGVyBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGUCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABRFvcGVuTm90aW9uYWxEZWx0YQkAZQIJARV0b3RhbExvbmdQb3NpdGlvblNpemUAAwUOaXNMb25nUG9zaXRpb24JAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARZ0b3RhbFNob3J0UG9zaXRpb25TaXplAAMJAQEhAQUOaXNMb25nUG9zaXRpb24JAQNhYnMBBRVleGNoYW5nZWRQb3NpdGlvblNpemUAAAkAZQIJARBvcGVuSW50ZXJlc3RMb25nAAMFDmlzTG9uZ1Bvc2l0aW9uBRFvcGVuTm90aW9uYWxEZWx0YQAACQBlAgkBEW9wZW5JbnRlcmVzdFNob3J0AAMJAQEhAQUOaXNMb25nUG9zaXRpb24FEW9wZW5Ob3Rpb25hbERlbHRhAAAJAGQCBRByZWFsaXplZENsb3NlRmVlBQtyb2xsb3ZlckZlZQUZZXhjaGFuZ2VkUXVvdGVBc3NldEFtb3VudAkAAgEJAKwCAgkArAICCQCsAgICPUludmFsaWQgaW50ZXJuYWxDbG9zZVBvc2l0aW9uIHBhcmFtczogaW52YWxpZCBwb3NpdGlvbiBzaXplOiAJAKQDAQUFX3NpemUCBiBtYXg6IAkApAMBBRJhYnNPbGRQb3NpdGlvblNpemUBEGdldFR3YXBTcG90UHJpY2UABAhtaW51dGVJZAkAaQIJAGkCCQENbGFzdFRpbWVzdGFtcAAA6AcAPAQNc3RhcnRNaW51dGVJZAkAZQIFCG1pbnV0ZUlkBQ1UV0FQX0lOVEVSVkFMBAdsaXN0U3RyCQELdmFsdWVPckVsc2UCCQCdCAIFBHRoaXMFDWtfbGFzdERhdGFTdHICAAQEbGlzdAkAtQkCBQdsaXN0U3RyAgEsCgEIZmlsdGVyRm4CC2FjY3VtdWxhdG9yBG5leHQDCQBnAgUNc3RhcnRNaW51dGVJZAkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQC2CQEFBG5leHQJAKwCAgIfZ2V0VHdhcFNwb3RQcmljZTogaW52YWxpZCBpbnQ6IAUHbGlzdFN0cgkAzQgCBQthY2N1bXVsYXRvcgkBDXBhcnNlSW50VmFsdWUBBQRuZXh0BQthY2N1bXVsYXRvcgQFbGlzdEYKAAIkbAUEbGlzdAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEIZmlsdGVyRm4CBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDIwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAQIbWF4SW5kZXgDCQBmAgkAkAMBBQVsaXN0RgAACQCWAwEFBWxpc3RGCQETdmFsdWVPckVycm9yTWVzc2FnZQIJALYJAQkAkQMCBQRsaXN0AAAJAKwCAgIfZ2V0VHdhcFNwb3RQcmljZTogaW52YWxpZCBpbnQ6IAUHbGlzdFN0cgQMbGFzdE1pbnV0ZUlkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFDmtfbGFzdE1pbnV0ZUlkAAAEFmVuZExhc3RDdW11bGF0aXZlUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlAgFfCQCkAwEFDGxhc3RNaW51dGVJZAAABAxlbmRMYXN0UHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFE2tfdHdhcERhdGFMYXN0UHJpY2UCAV8JAKQDAQUMbGFzdE1pbnV0ZUlkAAAEEm5vd0N1bXVsYXRpdmVQcmljZQkAZAIFFmVuZExhc3RDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUIbWludXRlSWQFDGxhc3RNaW51dGVJZAUMZW5kTGFzdFByaWNlBBhzdGFydExhc3RDdW11bGF0aXZlUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlAgFfCQCkAwEFCG1heEluZGV4AAAEDnN0YXJ0TGFzdFByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBRNrX3R3YXBEYXRhTGFzdFByaWNlAgFfCQCkAwEFCG1heEluZGV4AAAEFHN0YXJ0Q3VtdWxhdGl2ZVByaWNlCQBkAgUYc3RhcnRMYXN0Q3VtdWxhdGl2ZVByaWNlCQBoAgkAZQIFDXN0YXJ0TWludXRlSWQFCG1heEluZGV4BQ5zdGFydExhc3RQcmljZQkAaQIJAGUCBRJub3dDdW11bGF0aXZlUHJpY2UFFHN0YXJ0Q3VtdWxhdGl2ZVByaWNlBQ1UV0FQX0lOVEVSVkFMARNnZXRUZXJtaW5hbEFtbVN0YXRlAAQNX3Bvc2l0aW9uU2l6ZQkBEXRvdGFsUG9zaXRpb25TaXplAAMJAAACBQ1fcG9zaXRpb25TaXplAAAJAJQKAgkBBnF0QXN0UgAJAQZic0FzdFIABAlkaXJlY3Rpb24JAGYCBQ1fcG9zaXRpb25TaXplAAAEDSR0MDM5MTgwMzkzNTkJAQpzd2FwT3V0cHV0AwUJZGlyZWN0aW9uCQEDYWJzAQUNX3Bvc2l0aW9uU2l6ZQcEFWN1cnJlbnROZXRNYXJrZXRWYWx1ZQgFDSR0MDM5MTgwMzkzNTkCXzEEGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUIBQ0kdDAzOTE4MDM5MzU5Al8yBBh0ZXJtaW5hbEJhc2VBc3NldFJlc2VydmUIBQ0kdDAzOTE4MDM5MzU5Al8zCQCUCgIFGXRlcm1pbmFsUXVvdGVBc3NldFJlc2VydmUFGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQETZ2V0UXVvdGVBc3NldFdlaWdodAQQYmFzZUFzc2V0UmVzZXJ2ZRF0b3RhbFBvc2l0aW9uU2l6ZRFxdW90ZUFzc2V0UmVzZXJ2ZQt0YXJnZXRQcmljZQQBYgkAtgIBBRBiYXNlQXNzZXRSZXNlcnZlBAJzegkAtgIBBRF0b3RhbFBvc2l0aW9uU2l6ZQQBcQkAtgIBBRFxdW90ZUFzc2V0UmVzZXJ2ZQQBcAkAtgIBBQt0YXJnZXRQcmljZQQBawkBBWJtdWxkAgUBcQUBYgQEbmV3QgkAtwICBQFiBQJzegQEbmV3UQkBBWJkaXZkAgUBawUEbmV3QgQBegkBBWJkaXZkAgUEbmV3UQUEbmV3QgQGcmVzdWx0CQEFYmRpdmQCBQFwBQF6CQCgAwEFBnJlc3VsdAEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDDl90ZXJtaW5hbFByaWNlB19xdEFzdFIHX2JzQXN0UgQNX3Bvc2l0aW9uU2l6ZQkBEXRvdGFsUG9zaXRpb25TaXplAAMJAAACBQ1fcG9zaXRpb25TaXplAAAECW5ld1F0QXN0VwkBBGRpdmQCCQEEbXVsZAIFDl90ZXJtaW5hbFByaWNlBQdfYnNBc3RSBQdfcXRBc3RSCQCVCgMFCW5ld1F0QXN0VwUMREVDSU1BTF9VTklUAAAECWRpcmVjdGlvbgkAZgIFDV9wb3NpdGlvblNpemUAAAQVY3VycmVudE5ldE1hcmtldFZhbHVlCAkBCnN3YXBPdXRwdXQDBQlkaXJlY3Rpb24JAQNhYnMBBQ1fcG9zaXRpb25TaXplBwJfMQQJbmV3UXRBc3RXCQETZ2V0UXVvdGVBc3NldFdlaWdodAQFB19ic0FzdFIFDV9wb3NpdGlvblNpemUFB19xdEFzdFIFDl90ZXJtaW5hbFByaWNlBAluZXdCc0FzdFcFDERFQ0lNQUxfVU5JVAQNbWFyZ2luVG9WYXVsdAgJAStnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubEJ5VmFsdWVzBwUNX3Bvc2l0aW9uU2l6ZQUVY3VycmVudE5ldE1hcmtldFZhbHVlBQdfcXRBc3RSBQluZXdRdEFzdFcFB19ic0FzdFIFCW5ld0JzQXN0VwUPUE5MX09QVElPTl9TUE9UAl8yCQCVCgMFCW5ld1F0QXN0VwUJbmV3QnNBc3RXBQ1tYXJnaW5Ub1ZhdWx0AQpnZXRGdW5kaW5nAAQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABA1zcG90VHdhcFByaWNlCQEQZ2V0VHdhcFNwb3RQcmljZQAEB3ByZW1pdW0JAGUCBQ1zcG90VHdhcFByaWNlBQ91bmRlcmx5aW5nUHJpY2UDAwMJAAACCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAAAAYJAAACCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAAABgkBDmlzTWFya2V0Q2xvc2VkAAkAlAoCAAAAAAMJAGYCAAAFB3ByZW1pdW0EFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQQTbG9uZ1ByZW1pdW1GcmFjdGlvbgkBBGRpdmQCCQEEbXVsZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uCQEWdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQAJARV0b3RhbExvbmdQb3NpdGlvblNpemUACQCUCgIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uBBNsb25nUHJlbWl1bUZyYWN0aW9uCQEEZGl2ZAIJAQRtdWxkAgUHcHJlbWl1bQkBFGZ1bmRpbmdQZXJpb2REZWNpbWFsAAUHT05FX0RBWQQUc2hvcnRQcmVtaXVtRnJhY3Rpb24JAQRkaXZkAgkBBG11bGQCBRNsb25nUHJlbWl1bUZyYWN0aW9uCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUACQCUCgIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBRNsb25nUHJlbWl1bUZyYWN0aW9uAQ5nZXRBZGp1c3RlZEZlZQILX2FydGlmYWN0SWQQX2Jhc2VGZWVEaXNjb3VudAQKYmFzZUZlZVJhdwkBA2ZlZQAEB2Jhc2VGZWUJAQRtdWxkAgUKYmFzZUZlZVJhdwUQX2Jhc2VGZWVEaXNjb3VudAQNJHQwNDIyMjA0MjcxNQMJAQIhPQIFC19hcnRpZmFjdElkAgAEDGFydGlmYWN0S2luZAkBBHN0ckECCQERbmZ0TWFuYWdlckFkZHJlc3MACQEOdG9Db21wb3NpdGVLZXkCBQxrX3Rva2VuX3R5cGUFC19hcnRpZmFjdElkAwkAAAIFDGFydGlmYWN0S2luZAUYRkVFX1JFRFVDVElPTl9UT0tFTl9UWVBFBAlyZWR1Y3Rpb24JAQRpbnRBAgkBEW5mdE1hbmFnZXJBZGRyZXNzAAkBDnRvQ29tcG9zaXRlS2V5AgUNa190b2tlbl9wYXJhbQULX2FydGlmYWN0SWQEC2FkanVzdGVkRmVlCQEEbXVsZAIFB2Jhc2VGZWUFCXJlZHVjdGlvbgkAlAoCBQthZGp1c3RlZEZlZQYJAAIBAhlJbnZhbGlkIGF0dGFjaGVkIGFydGlmYWN0CQCUCgIFB2Jhc2VGZWUHBAthZGp1c3RlZEZlZQgFDSR0MDQyMjIwNDI3MTUCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDQyMjIwNDI3MTUCXzIJAJQKAgULYWRqdXN0ZWRGZWUFDGJ1cm5BcnRpZmFjdAEXaXNTYW1lQXNzZXRPck5vUG9zaXRpb24CB190cmFkZXIIX2Fzc2V0SWQED29sZFBvc2l0aW9uU2l6ZQgJAQtnZXRQb3NpdGlvbgEFB190cmFkZXICXzEDCQAAAgUPb2xkUG9zaXRpb25TaXplAAAGCQAAAgkBEGdldFBvc2l0aW9uQXNzZXQBBQdfdHJhZGVyBQhfYXNzZXRJZAELaXNTYW1lQXNzZXQCB190cmFkZXIIX2Fzc2V0SWQJAAACCQEQZ2V0UG9zaXRpb25Bc3NldAEFB190cmFkZXIFCF9hc3NldElkARhnZXRGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCB190cmFkZXILX2FydGlmYWN0SWQEEGRvR2V0RmVlRGlzY291bnQJAPwHBAkBDG1pbmVyQWRkcmVzcwACEmNvbXB1dGVGZWVEaXNjb3VudAkAzAgCBQdfdHJhZGVyBQNuaWwFA25pbAMJAAACBRBkb0dldEZlZURpc2NvdW50BRBkb0dldEZlZURpc2NvdW50BAtmZWVEaXNjb3VudAQHJG1hdGNoMAUQZG9HZXRGZWVEaXNjb3VudAMJAAECBQckbWF0Y2gwAgNJbnQEAXgFByRtYXRjaDAFAXgJAAIBAiFJbnZhbGlkIGNvbXB1dGVGZWVEaXNjb3VudCByZXN1bHQEDSR0MDQzMzk1NDM0NjkJAQ5nZXRBZGp1c3RlZEZlZQIFC19hcnRpZmFjdElkBQtmZWVEaXNjb3VudAQLYWRqdXN0ZWRGZWUIBQ0kdDA0MzM5NTQzNDY5Al8xBAxidXJuQXJ0aWZhY3QIBQ0kdDA0MzM5NTQzNDY5Al8yCQCUCgIFC2FkanVzdGVkRmVlBQxidXJuQXJ0aWZhY3QJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BDWdldEFydGlmYWN0SWQBAWkECmFydGlmYWN0SWQDCQBmAgkAkAMBCAUBaQhwYXltZW50cwABCQDYBAEJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAggJAJEDAggFAWkIcGF5bWVudHMAAQdhc3NldElkAhJJbnZhbGlkIGFydGlmYWN0SWQCAAUKYXJ0aWZhY3RJZAENZGlzdHJpYnV0ZUZlZQEKX2ZlZUFtb3VudAQMZmVlVG9TdGFrZXJzCQEEbXVsZAIFCl9mZWVBbW91bnQJARNmZWVUb1N0YWtlcnNQZXJjZW50AAQKZmVlVG9WYXVsdAkAZQIFCl9mZWVBbW91bnQFDGZlZVRvU3Rha2VycwkAlAoCBQxmZWVUb1N0YWtlcnMFCmZlZVRvVmF1bHQBDnVwZGF0ZVNldHRpbmdzDRBfaW5pdE1hcmdpblJhdGlvBF9tbXIUX2xpcXVpZGF0aW9uRmVlUmF0aW8OX2Z1bmRpbmdQZXJpb2QEX2ZlZQxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2luaXRNYXJnaW5SYXRpbwUQX2luaXRNYXJnaW5SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUYa19tYWludGVuYW5jZU1hcmdpblJhdGlvBQRfbW1yCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRVrX2xpcXVpZGF0aW9uRmVlUmF0aW8FFF9saXF1aWRhdGlvbkZlZVJhdGlvCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ9rX2Z1bmRpbmdQZXJpb2QFDl9mdW5kaW5nUGVyaW9kCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQVrX2ZlZQUEX2ZlZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUNa19zcHJlYWRMaW1pdAUMX3NwcmVhZExpbWl0CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRBrX21heFByaWNlSW1wYWN0BQ9fbWF4UHJpY2VJbXBhY3QJAMwIAgkBDEludGVnZXJFbnRyeQIFGWtfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8FGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhQcmljZVNwcmVhZAUPX21heFByaWNlU3ByZWFkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX21heE9wZW5Ob3Rpb25hbAUQX21heE9wZW5Ob3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUVa19mZWVUb1N0YWtlcnNQZXJjZW50BRRfZmVlVG9TdGFrZXJzUGVyY2VudAkAzAgCCQEMSW50ZWdlckVudHJ5AgUQa19tYXhPcmFjbGVEZWxheQUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQJAMwIAgkBDEludGVnZXJFbnRyeQIFDWtfcm9sbG92ZXJGZWUFDF9yb2xsb3ZlckZlZQUDbmlsAQ11cGRhdGVGdW5kaW5nBRFfbmV4dEZ1bmRpbmdCbG9jayRfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24lX2xhdGVzdFNob3J0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbhBfbG9uZ0Z1bmRpbmdSYXRlEV9zaG9ydEZ1bmRpbmdSYXRlCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRJrX25leHRGdW5kaW5nQmxvY2sFEV9uZXh0RnVuZGluZ0Jsb2NrCQDMCAIJAQxJbnRlZ2VyRW50cnkCBSVrX2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBSRfbGF0ZXN0TG9uZ0N1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24JAMwIAgkBDEludGVnZXJFbnRyeQIFJmtfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uBSVfbGF0ZXN0U2hvcnRDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2xvbmdGdW5kaW5nUmF0ZQUQX2xvbmdGdW5kaW5nUmF0ZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19zaG9ydEZ1bmRpbmdSYXRlBRFfc2hvcnRGdW5kaW5nUmF0ZQUDbmlsAR9pbmNyZW1lbnRQb3NpdGlvblNlcXVlbmNlTnVtYmVyAg5faXNOZXdQb3NpdGlvbghfYWRkcmVzcwMFDl9pc05ld1Bvc2l0aW9uBA9jdXJyZW50U2VxdWVuY2UJAQxsYXN0U2VxdWVuY2UACQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRJrX3Bvc2l0aW9uU2VxdWVuY2UFCF9hZGRyZXNzCQBkAgUPY3VycmVudFNlcXVlbmNlAAEJAMwIAgkBDEludGVnZXJFbnRyeQIFCmtfc2VxdWVuY2UJAGQCBQ9jdXJyZW50U2VxdWVuY2UAAQUDbmlsBQNuaWwBEXVwZGF0ZVBvc2l0aW9uRmVlAw5faXNOZXdQb3NpdGlvbghfYWRkcmVzcwRfZmVlAwUOX2lzTmV3UG9zaXRpb24JAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFDWtfcG9zaXRpb25GZWUFCF9hZGRyZXNzBQRfZmVlBQNuaWwFA25pbAEOdXBkYXRlUG9zaXRpb24GCF9hZGRyZXNzBV9zaXplB19tYXJnaW4NX29wZW5Ob3Rpb25hbCBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbhBfbGF0ZXN0VGltZXN0YW1wCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBQ5rX3Bvc2l0aW9uU2l6ZQUIX2FkZHJlc3MFBV9zaXplCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRBrX3Bvc2l0aW9uTWFyZ2luBQhfYWRkcmVzcwUHX21hcmdpbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUWa19wb3NpdGlvbk9wZW5Ob3Rpb25hbAUIX2FkZHJlc3MFDV9vcGVuTm90aW9uYWwJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FCF9hZGRyZXNzBSBfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQhfYWRkcmVzcwUQX2xhdGVzdFRpbWVzdGFtcAUDbmlsAQphcHBlbmRUd2FwAQZfcHJpY2UECG1pbnV0ZUlkCQBpAgkAaQIJAQ1sYXN0VGltZXN0YW1wAADoBwA8BBBwcmV2aW91c01pbnV0ZUlkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMFDmtfbGFzdE1pbnV0ZUlkAAADCQBmAgUQcHJldmlvdXNNaW51dGVJZAUIbWludXRlSWQJAAIBAhFUV0FQIG91dC1vZi1vcmRlcgQMbGFzdE1pbnV0ZUlkAwkAAAIFEHByZXZpb3VzTWludXRlSWQAAAUIbWludXRlSWQFEHByZXZpb3VzTWludXRlSWQDCQBmAgUIbWludXRlSWQFEHByZXZpb3VzTWludXRlSWQEE3ByZXZDdW11bGF0aXZlUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkArAICCQCsAgIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlAgFfCQCkAwEFEHByZXZpb3VzTWludXRlSWQAAAQJcHJldlByaWNlCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAKwCAgkArAICBRNrX3R3YXBEYXRhTGFzdFByaWNlAgFfCQCkAwEFEHByZXZpb3VzTWludXRlSWQFBl9wcmljZQQTbGFzdEN1bXVsYXRpdmVQcmljZQkAZAIFE3ByZXZDdW11bGF0aXZlUHJpY2UJAGgCCQBlAgUIbWludXRlSWQFDGxhc3RNaW51dGVJZAUJcHJldlByaWNlBARsaXN0CQELcHVzaFRvUXVldWUDCQEJc3RyVG9MaXN0AQkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQ1rX2xhc3REYXRhU3RyAgAFDVRXQVBfSU5URVJWQUwJAKQDAQUIbWludXRlSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlCQCkAwEFCG1pbnV0ZUlkBRNsYXN0Q3VtdWxhdGl2ZVByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRNrX3R3YXBEYXRhTGFzdFByaWNlCQCkAwEFCG1pbnV0ZUlkBQZfcHJpY2UJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkCQCkAwEFCG1pbnV0ZUlkBRBwcmV2aW91c01pbnV0ZUlkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5rX2xhc3RNaW51dGVJZAUIbWludXRlSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUNa19sYXN0RGF0YVN0cgkBCWxpc3RUb1N0cgEFBGxpc3QFA25pbAQYdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkCQELdmFsdWVPckVsc2UCCQCaCAIFBHRoaXMJAQ50b0NvbXBvc2l0ZUtleQIFGmtfdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkCQCkAwEFCG1pbnV0ZUlkAAAEE3ByZXZDdW11bGF0aXZlUHJpY2UJAQt2YWx1ZU9yRWxzZQIJAJoIAgUEdGhpcwkBDnRvQ29tcG9zaXRlS2V5AgUda190d2FwRGF0YUxhc3RDdW11bGF0aXZlUHJpY2UJAKQDAQUYdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkAAAECXByZXZQcmljZQkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzCQEOdG9Db21wb3NpdGVLZXkCBRNrX3R3YXBEYXRhTGFzdFByaWNlCQCkAwEFGHR3YXBEYXRhUHJldmlvdXNNaW51dGVJZAUGX3ByaWNlBBNsYXN0Q3VtdWxhdGl2ZVByaWNlCQBkAgUTcHJldkN1bXVsYXRpdmVQcmljZQkAaAIJAGUCBQhtaW51dGVJZAUYdHdhcERhdGFQcmV2aW91c01pbnV0ZUlkBQlwcmV2UHJpY2UJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ50b0NvbXBvc2l0ZUtleQIFHWtfdHdhcERhdGFMYXN0Q3VtdWxhdGl2ZVByaWNlCQCkAwEFCG1pbnV0ZUlkBRNsYXN0Q3VtdWxhdGl2ZVByaWNlCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOdG9Db21wb3NpdGVLZXkCBRNrX3R3YXBEYXRhTGFzdFByaWNlCQCkAwEFCG1pbnV0ZUlkBQZfcHJpY2UFA25pbAERdXBkYXRlQW1tUmVzZXJ2ZXMCB19xdEFzdFIHX2JzQXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19xdW90ZUFzc2V0UmVzZXJ2ZQUHX3F0QXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19iYXNlQXNzZXRSZXNlcnZlBQdfYnNBc3RSBQNuaWwBEHVwZGF0ZUFtbVdlaWdodHMCB19xdEFzdFcHX2JzQXN0VwkAzAgCCQEMSW50ZWdlckVudHJ5AgUSa19xdW90ZUFzc2V0V2VpZ2h0BQdfcXRBc3RXCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRFrX2Jhc2VBc3NldFdlaWdodAUHX2JzQXN0VwUDbmlsAQl1cGRhdGVBbW0IB19xdEFzdFIHX2JzQXN0UhdfdG90YWxQb3NpdGlvblNpemVBZnRlchVfb3BlbkludGVyZXN0Tm90aW9uYWwWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZRdfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZRZfdG90YWxMb25nT3Blbk5vdGlvbmFsF190b3RhbFNob3J0T3Blbk5vdGlvbmFsBAdfcXRBc3RXCQEGcXRBc3RXAAQHX2JzQXN0VwkBBmJzQXN0VwADCQECIT0CCQBlAgUWX3RvdGFsTG9uZ1Bvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICGEludmFsaWQgQU1NIHN0YXRlIGRhdGE6IAkApAMBBRZfdG90YWxMb25nUG9zaXRpb25TaXplAgQgKyAgCQCkAwEFF190b3RhbFNob3J0UG9zaXRpb25TaXplAgQgIT0gCQCkAwEFF190b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCQDOCAIJAM4IAgkBEXVwZGF0ZUFtbVJlc2VydmVzAgUHX3F0QXN0UgUHX2JzQXN0UgkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa190b3RhbFBvc2l0aW9uU2l6ZQUXX3RvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAMwIAgkBDEludGVnZXJFbnRyeQIFFmtfb3BlbkludGVyZXN0Tm90aW9uYWwFFV9vcGVuSW50ZXJlc3ROb3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUXa190b3RhbExvbmdQb3NpdGlvblNpemUFFl90b3RhbExvbmdQb3NpdGlvblNpemUJAMwIAgkBDEludGVnZXJFbnRyeQIFGGtfdG90YWxTaG9ydFBvc2l0aW9uU2l6ZQUXX3RvdGFsU2hvcnRQb3NpdGlvblNpemUJAMwIAgkBDEludGVnZXJFbnRyeQIFEmtfb3BlbkludGVyZXN0TG9uZwUWX3RvdGFsTG9uZ09wZW5Ob3Rpb25hbAkAzAgCCQEMSW50ZWdlckVudHJ5AgUTa19vcGVuSW50ZXJlc3RTaG9ydAUXX3RvdGFsU2hvcnRPcGVuTm90aW9uYWwFA25pbAkBCmFwcGVuZFR3YXABCQEEZGl2ZAIJAQRtdWxkAgUHX3F0QXN0UgUHX3F0QXN0VwkBBG11bGQCBQdfYnNBc3RSBQdfYnNBc3RXAQ5kZWxldGVQb3NpdGlvbgEIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUOa19wb3NpdGlvblNpemUFCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFEGtfcG9zaXRpb25NYXJnaW4FCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFFmtfcG9zaXRpb25PcGVuTm90aW9uYWwFCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFLmtfcG9zaXRpb25MYXN0VXBkYXRlZEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24FCF9hZGRyZXNzCQDMCAIJAQtEZWxldGVFbnRyeQEJAQ50b0NvbXBvc2l0ZUtleQIFD2tfcG9zaXRpb25Bc3NldAUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUNa19wb3NpdGlvbkZlZQUIX2FkZHJlc3MJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBDnRvQ29tcG9zaXRlS2V5AgUea19wb3NpdGlvbkxhc3RVcGRhdGVkVGltZXN0YW1wBQhfYWRkcmVzcwUDbmlsAQh3aXRoZHJhdwIIX2FkZHJlc3MHX2Ftb3VudAQHYmFsYW5jZQkA8AcCBQR0aGlzCQEKcXVvdGVBc3NldAADCQBmAgUHX2Ftb3VudAUHYmFsYW5jZQkAAgEJAKwCAgkArAICCQCsAgICE1VuYWJsZSB0byB3aXRoZHJhdyAJAKQDAQUHX2Ftb3VudAIXIGZyb20gY29udHJhY3QgYmFsYW5jZSAJAKQDAQUHYmFsYW5jZQkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQhfYWRkcmVzcwUHX2Ftb3VudAkBCnF1b3RlQXNzZXQABQNuaWwBDXVwZGF0ZUJhbGFuY2UBAWkDCQBmAgAABQFpCQACAQIHQmFsYW5jZQkAzAgCCQEMSW50ZWdlckVudHJ5AgUJa19iYWxhbmNlBQFpBQNuaWwBC3RyYW5zZmVyRmVlAQFpCQDMCAIJAQ5TY3JpcHRUcmFuc2ZlcgMJAQ5zdGFraW5nQWRkcmVzcwAFAWkJAQpxdW90ZUFzc2V0AAUDbmlsAQ5kb0J1cm5BcnRpZmFjdAINX2J1cm5BcnRpZmFjdAFpAwUNX2J1cm5BcnRpZmFjdAkAzAgCCQEEQnVybgIJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAggJAJEDAggFAWkIcGF5bWVudHMAAQdhc3NldElkAhBJbnZhbGlkIGFydGlmYWN0AAEFA25pbAUDbmlsFgFpAQVwYXVzZQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIUSW52YWxpZCBwYXVzZSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCGtfcGF1c2VkBgUDbmlsAWkBB3VucGF1c2UAAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAkAAgECFkludmFsaWQgdW5wYXVzZSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFCGtfcGF1c2VkBwUDbmlsAWkBDHNldENsb3NlT25seQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIbSW52YWxpZCBzZXRDbG9zZU9ubHkgcGFyYW1zCQDMCAIJAQxCb29sZWFuRW50cnkCBQtrX2Nsb3NlT25seQYFA25pbAFpAQ51bnNldENsb3NlT25seQADCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIdSW52YWxpZCB1bnNldENsb3NlT25seSBwYXJhbXMJAMwIAgkBDEJvb2xlYW5FbnRyeQIFC2tfY2xvc2VPbmx5BwUDbmlsAWkBDGFkZExpcXVpZGl0eQERX3F1b3RlQXNzZXRBbW91bnQDAwkBAiE9AggFAWkGY2FsbGVyCQEMYWRtaW5BZGRyZXNzAAYJAGcCAAAFEV9xdW90ZUFzc2V0QW1vdW50CQACAQIbSW52YWxpZCBhZGRMaXF1aWRpdHkgcGFyYW1zBAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEB19xdEFzdFcJAQZxdEFzdFcABAdfYnNBc3RXCQEGYnNBc3RXAAQFcHJpY2UJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBQdfcXRBc3RXCQEEbXVsZAIFB19ic0FzdFIFB19ic0FzdFcEC3F0QXN0UkFmdGVyCQBkAgUHX3F0QXN0UgURX3F1b3RlQXNzZXRBbW91bnQEFGJhc2VBc3NldEFtb3VudFRvQWRkCQBlAgkBBGRpdmQCCQEEbXVsZAIFC3F0QXN0UkFmdGVyBQdfcXRBc3RXBQVwcmljZQUHX2JzQXN0UgQLYnNBc3RSQWZ0ZXIJAGQCBQdfYnNBc3RSBRRiYXNlQXNzZXRBbW91bnRUb0FkZAQNJHQwNTI4NzY1MzAyNwkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwkBDmdldE9yYWNsZVByaWNlAAULcXRBc3RSQWZ0ZXIFC2JzQXN0UkFmdGVyBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwNTI4NzY1MzAyNwJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwNTI4NzY1MzAyNwJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDUyODc2NTMwMjcCXzMEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBQ1tYXJnaW5Ub1ZhdWx0AAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBQ1tYXJnaW5Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgkBEHVwZGF0ZUFtbVdlaWdodHMCBRNuZXdRdW90ZUFzc2V0V2VpZ2h0BRJuZXdCYXNlQXNzZXRXZWlnaHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEPcmVtb3ZlTGlxdWlkaXR5ARFfcXVvdGVBc3NldEFtb3VudAMDCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MABgkAZwIFEV9xdW90ZUFzc2V0QW1vdW50AAAJAAIBAh5JbnZhbGlkIHJlbW92ZUxpcXVpZGl0eSBwYXJhbXMEB19xdEFzdFIJAQZxdEFzdFIABAdfYnNBc3RSCQEGYnNBc3RSAAQHX3F0QXN0VwkBBnF0QXN0VwAEB19ic0FzdFcJAQZic0FzdFcABAVwcmljZQkBBGRpdmQCCQEEbXVsZAIFB19xdEFzdFIFB19xdEFzdFcJAQRtdWxkAgUHX2JzQXN0UgUHX2JzQXN0VwQLcXRBc3RSQWZ0ZXIJAGUCBQdfcXRBc3RSBRFfcXVvdGVBc3NldEFtb3VudAQXYmFzZUFzc2V0QW1vdW50VG9SZW1vdmUJAQNhYnMBCQBlAgkBBGRpdmQCCQEEbXVsZAIFC3F0QXN0UkFmdGVyBQdfcXRBc3RXBQVwcmljZQUHX2JzQXN0UgQLYnNBc3RSQWZ0ZXIJAGUCBQdfYnNBc3RSBRdiYXNlQXNzZXRBbW91bnRUb1JlbW92ZQQNJHQwNTM5NTk1NDExMAkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwkBDmdldE9yYWNsZVByaWNlAAULcXRBc3RSQWZ0ZXIFC2JzQXN0UkFmdGVyBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwNTM5NTk1NDExMAJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwNTM5NTk1NDExMAJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDUzOTU5NTQxMTACXzMEDWRvRXhjaGFuZ2VQbkwDCQECIT0CBQ1tYXJnaW5Ub1ZhdWx0AAAEDWRvRXhjaGFuZ2VQbkwJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCBQ1tYXJnaW5Ub1ZhdWx0BQNuaWwFA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MBQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4FA25pbAMJAAACBQ1kb0V4Y2hhbmdlUG5MBQ1kb0V4Y2hhbmdlUG5MCQDOCAIJARF1cGRhdGVBbW1SZXNlcnZlcwIFC3F0QXN0UkFmdGVyBQtic0FzdFJBZnRlcgkBEHVwZGF0ZUFtbVdlaWdodHMCBRNuZXdRdW90ZUFzc2V0V2VpZ2h0BRJuZXdCYXNlQXNzZXRXZWlnaHQJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEOY2hhbmdlU2V0dGluZ3MNEF9pbml0TWFyZ2luUmF0aW8EX21tchRfbGlxdWlkYXRpb25GZWVSYXRpbw5fZnVuZGluZ1BlcmlvZARfZmVlDF9zcHJlYWRMaW1pdA9fbWF4UHJpY2VJbXBhY3QYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvD19tYXhQcmljZVNwcmVhZBBfbWF4T3Blbk5vdGlvbmFsFF9mZWVUb1N0YWtlcnNQZXJjZW50D19tYXhPcmFjbGVEZWxheQxfcm9sbG92ZXJGZWUDCQECIT0CCAUBaQZjYWxsZXIJAQxhZG1pbkFkZHJlc3MACQACAQIdSW52YWxpZCBjaGFuZ2VTZXR0aW5ncyBwYXJhbXMJAQ51cGRhdGVTZXR0aW5ncw0FEF9pbml0TWFyZ2luUmF0aW8FBF9tbXIFFF9saXF1aWRhdGlvbkZlZVJhdGlvBQ5fZnVuZGluZ1BlcmlvZAUEX2ZlZQUMX3NwcmVhZExpbWl0BQ9fbWF4UHJpY2VJbXBhY3QFGF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwUPX21heFByaWNlU3ByZWFkBRBfbWF4T3Blbk5vdGlvbmFsBRRfZmVlVG9TdGFrZXJzUGVyY2VudAUPX21heE9yYWNsZURlbGF5BQxfcm9sbG92ZXJGZWUBaQEKaW5pdGlhbGl6ZRIHX3F0QXN0UgdfYnNBc3RSDl9mdW5kaW5nUGVyaW9kEF9pbml0TWFyZ2luUmF0aW8EX21tchRfbGlxdWlkYXRpb25GZWVSYXRpbwRfZmVlD19iYXNlT3JhY2xlRGF0YRBfcXVvdGVPcmFjbGVEYXRhDF9jb29yZGluYXRvcgxfc3ByZWFkTGltaXQPX21heFByaWNlSW1wYWN0GF9wYXJ0aWFsTGlxdWlkYXRpb25SYXRpbw9fbWF4UHJpY2VTcHJlYWQQX21heE9wZW5Ob3Rpb25hbBRfZmVlVG9TdGFrZXJzUGVyY2VudA9fbWF4T3JhY2xlRGVsYXkMX3JvbGxvdmVyRmVlAwMDAwMDAwMDAwMDAwMDAwMDCQBnAgAABQdfcXRBc3RSBgkAZwIAAAUHX2JzQXN0UgYJAGcCAAAFDl9mdW5kaW5nUGVyaW9kBgkAZwIAAAUQX2luaXRNYXJnaW5SYXRpbwYJAGcCAAAFBF9tbXIGCQBnAgAABRRfbGlxdWlkYXRpb25GZWVSYXRpbwYJAGcCAAAFBF9mZWUGCQBnAgAABQxfc3ByZWFkTGltaXQGCQBnAgAABQ9fbWF4UHJpY2VJbXBhY3QGCQBnAgAABRhfcGFydGlhbExpcXVpZGF0aW9uUmF0aW8GCQBnAgAABQ9fbWF4UHJpY2VTcHJlYWQGCQBnAgAABRBfbWF4T3Blbk5vdGlvbmFsBgkAZwIAAAUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQGCQBmAgUUX2ZlZVRvU3Rha2Vyc1BlcmNlbnQFDERFQ0lNQUxfVU5JVAYJAGcCAAAFD19tYXhPcmFjbGVEZWxheQYJAGcCAAAFDF9yb2xsb3ZlckZlZQYJAQtpbml0aWFsaXplZAAGCQECIT0CCAUBaQZjYWxsZXIFBHRoaXMJAAIBAh1JbnZhbGlkIGluaXRpYWxpemUgcGFyYW1ldGVycwkAzggCCQDOCAIJAM4IAgkAzggCCQEJdXBkYXRlQW1tCAUHX3F0QXN0UgUHX2JzQXN0UgAAAAAAAAAAAAAAAAkBDnVwZGF0ZVNldHRpbmdzDQUQX2luaXRNYXJnaW5SYXRpbwUEX21tcgUUX2xpcXVpZGF0aW9uRmVlUmF0aW8FDl9mdW5kaW5nUGVyaW9kBQRfZmVlBQxfc3ByZWFkTGltaXQFD19tYXhQcmljZUltcGFjdAUYX3BhcnRpYWxMaXF1aWRhdGlvblJhdGlvBQ9fbWF4UHJpY2VTcHJlYWQFEF9tYXhPcGVuTm90aW9uYWwFFF9mZWVUb1N0YWtlcnNQZXJjZW50BQ9fbWF4T3JhY2xlRGVsYXkFDF9yb2xsb3ZlckZlZQkBDXVwZGF0ZUZ1bmRpbmcFCQBkAgkBDWxhc3RUaW1lc3RhbXAABQ5fZnVuZGluZ1BlcmlvZAAAAAAAAAAACQENdXBkYXRlQmFsYW5jZQEAAAkAzAgCCQEMQm9vbGVhbkVudHJ5AgUNa19pbml0aWFsaXplZAYJAMwIAgkBC1N0cmluZ0VudHJ5AgUMa19iYXNlT3JhY2xlBQ9fYmFzZU9yYWNsZURhdGEJAMwIAgkBC1N0cmluZ0VudHJ5AgUNa19xdW90ZU9yYWNsZQUQX3F1b3RlT3JhY2xlRGF0YQkAzAgCCQELU3RyaW5nRW50cnkCBRRrX2Nvb3JkaW5hdG9yQWRkcmVzcwkApQgBCQERQGV4dHJOYXRpdmUoMTA2MikBBQxfY29vcmRpbmF0b3IFA25pbAFpARBpbmNyZWFzZVBvc2l0aW9uBApfZGlyZWN0aW9uCV9sZXZlcmFnZRNfbWluQmFzZUFzc2V0QW1vdW50CF9yZWZMaW5rBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkBD2dldEFjdHVhbENhbGxlcgEFAWkECl9yYXdBbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMDAwMJAQIhPQIFCl9kaXJlY3Rpb24FCERJUl9MT05HCQECIT0CBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQHBgkAZwIAAAUKX3Jhd0Ftb3VudAYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQEXaXNTYW1lQXNzZXRPck5vUG9zaXRpb24CBQdfdHJhZGVyBQtfYXNzZXRJZFN0cgYJAQEhAQkBFnJlcXVpcmVNb3JlTWFyZ2luUmF0aW8DCQEEZGl2ZAIFDERFQ0lNQUxfVU5JVAUJX2xldmVyYWdlCQEPaW5pdE1hcmdpblJhdGlvAAYGCQEGcGF1c2VkAAYJAQljbG9zZU9ubHkABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECI0ludmFsaWQgaW5jcmVhc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBA0kdDA1Nzg4ODU4MDM3CQEYZ2V0Rm9yVHJhZGVyV2l0aEFydGlmYWN0AgUHX3RyYWRlcgkBDWdldEFydGlmYWN0SWQBBQFpBAthZGp1c3RlZEZlZQgFDSR0MDU3ODg4NTgwMzcCXzEEDGJ1cm5BcnRpZmFjdAgFDSR0MDU3ODg4NTgwMzcCXzIEB19hbW91bnQJAQRkaXZkAgUKX3Jhd0Ftb3VudAkAZAIJAQRtdWxkAgULYWRqdXN0ZWRGZWUFCV9sZXZlcmFnZQUMREVDSU1BTF9VTklUBBNkaXN0cmlidXRlRmVlQW1vdW50CQBlAgUKX3Jhd0Ftb3VudAUHX2Ftb3VudAQOcmVmZXJyZXJGZWVBbnkJAPwHBAkBD3JlZmVycmFsQWRkcmVzcwACFWFjY2VwdFBheW1lbnRXaXRoTGluawkAzAgCBQdfdHJhZGVyCQDMCAIFCF9yZWZMaW5rBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUTZGlzdHJpYnV0ZUZlZUFtb3VudAUDbmlsAwkAAAIFDnJlZmVycmVyRmVlQW55BQ5yZWZlcnJlckZlZUFueQQLcmVmZXJyZXJGZWUEByRtYXRjaDAFDnJlZmVycmVyRmVlQW55AwkAAQIFByRtYXRjaDACA0ludAQBeAUHJG1hdGNoMAUBeAkAAgECE0ludmFsaWQgcmVmZXJyZXJGZWUECWZlZUFtb3VudAkAZQIFE2Rpc3RyaWJ1dGVGZWVBbW91bnQFC3JlZmVycmVyRmVlBA0kdDA1ODUzMzU4NzAxCQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyBA9vbGRQb3NpdGlvblNpemUIBQ0kdDA1ODUzMzU4NzAxAl8xBBFvbGRQb3NpdGlvbk1hcmdpbggFDSR0MDU4NTMzNTg3MDECXzIEF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTg1MzM1ODcwMQJfMwQUb2xkUG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA1ODUzMzU4NzAxAl80BBRvbGRQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDU4NTMzNTg3MDECXzUEDWlzTmV3UG9zaXRpb24JAAACBQ9vbGRQb3NpdGlvblNpemUAAAQPaXNTYW1lRGlyZWN0aW9uAwkAZgIFD29sZFBvc2l0aW9uU2l6ZQAACQAAAgUKX2RpcmVjdGlvbgUIRElSX0xPTkcJAAACBQpfZGlyZWN0aW9uBQlESVJfU0hPUlQEDmV4cGFuZEV4aXN0aW5nAwkBASEBBQ1pc05ld1Bvc2l0aW9uBQ9pc1NhbWVEaXJlY3Rpb24HBAVpc0FkZAkAAAIFCl9kaXJlY3Rpb24FCERJUl9MT05HBA0kdDA1ODk5MDYyMTExAwMFDWlzTmV3UG9zaXRpb24GBQ5leHBhbmRFeGlzdGluZwQMb3Blbk5vdGlvbmFsCQEEbXVsZAIFB19hbW91bnQFCV9sZXZlcmFnZQQNJHQwNTk0OTk1OTY3MgkBCXN3YXBJbnB1dAIFBWlzQWRkBQxvcGVuTm90aW9uYWwEFWFtb3VudEJhc2VBc3NldEJvdWdodAgFDSR0MDU5NDk5NTk2NzICXzEEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1OTQ5OTU5NjcyAl8yBBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1OTQ5OTU5NjcyAl8zBBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTk0OTk1OTY3MgJfNAMDCQECIT0CBRNfbWluQmFzZUFzc2V0QW1vdW50AAAJAGYCBRNfbWluQmFzZUFzc2V0QW1vdW50CQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BwkAAgEJAKwCAgkArAICCQCsAgICDUxpbWl0IGVycm9yOiAJAKQDAQkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAIDIDwgCQCkAwEFE19taW5CYXNlQXNzZXRBbW91bnQED25ld1Bvc2l0aW9uU2l6ZQkAZAIFD29sZFBvc2l0aW9uU2l6ZQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0BBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARBvcGVuSW50ZXJlc3RMb25nAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAUMb3Blbk5vdGlvbmFsAAAEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAZAIJARFvcGVuSW50ZXJlc3RTaG9ydAADCQBmAgAABQ9uZXdQb3NpdGlvblNpemUFDG9wZW5Ob3Rpb25hbAAABA0kdDA2MDIxODYwNDkzCQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wBQdfYW1vdW50BAxyZW1haW5NYXJnaW4IBQ0kdDA2MDIxODYwNDkzAl8xBAJ4MQgFDSR0MDYwMjE4NjA0OTMCXzIEAngyCAUNJHQwNjAyMTg2MDQ5MwJfMwQLcm9sbG92ZXJGZWUIBQ0kdDA2MDIxODYwNDkzAl80AwkBASEBCQEZcmVxdWlyZU5vdE92ZXJTcHJlYWRMaW1pdAIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgkAAgECFU92ZXIgbWF4IHNwcmVhZCBsaW1pdAMJAQEhAQkBHXJlcXVpcmVOb3RPdmVyTWF4T3Blbk5vdGlvbmFsAgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkAAgECFk92ZXIgbWF4IG9wZW4gbm90aW9uYWwJAKAKDgUPbmV3UG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4JAGQCBRdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD25ld1Bvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAABRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIJAGQCCQEUb3BlbkludGVyZXN0Tm90aW9uYWwABQxvcGVuTm90aW9uYWwJAGQCCQEVdG90YWxMb25nUG9zaXRpb25TaXplAAMJAGYCBQ9uZXdQb3NpdGlvblNpemUAAAkBA2FicwEFFWFtb3VudEJhc2VBc3NldEJvdWdodAAACQBkAgkBFnRvdGFsU2hvcnRQb3NpdGlvblNpemUAAwkAZgIAAAUPbmV3UG9zaXRpb25TaXplCQEDYWJzAQUVYW1vdW50QmFzZUFzc2V0Qm91Z2h0AAAFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIFC3JvbGxvdmVyRmVlBAxvcGVuTm90aW9uYWwJAQRtdWxkAgUHX2Ftb3VudAUJX2xldmVyYWdlBA0kdDA2MTgxMTYxOTI3CQEjZ2V0UG9zaXRpb25Ob3Rpb25hbEFuZFVucmVhbGl6ZWRQbmwCCQClCAEIBQFpBmNhbGxlcgUPUE5MX09QVElPTl9TUE9UBBNvbGRQb3NpdGlvbk5vdGlvbmFsCAUNJHQwNjE4MTE2MTkyNwJfMQQNdW5yZWFsaXplZFBubAgFDSR0MDYxODExNjE5MjcCXzIDCQBmAgUTb2xkUG9zaXRpb25Ob3Rpb25hbAUMb3Blbk5vdGlvbmFsCQACAQIuVXNlIGRlY3JlYXNlUG9zaXRpb24gdG8gZGVjcmVhc2UgcG9zaXRpb24gc2l6ZQkAAgECFENsb3NlIHBvc2l0aW9uIGZpcnN0BA9uZXdQb3NpdGlvblNpemUIBQ0kdDA1ODk5MDYyMTExAl8xBBduZXdQb3NpdGlvblJlbWFpbk1hcmdpbggFDSR0MDU4OTkwNjIxMTECXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNTg5OTA2MjExMQJfMwQUbmV3UG9zaXRpb25MYXRlc3RDUEYIBQ0kdDA1ODk5MDYyMTExAl80BBRuZXdQb3NpdGlvblRpbWVzdGFtcAgFDSR0MDU4OTkwNjIxMTECXzUEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDU4OTkwNjIxMTECXzYEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA1ODk5MDYyMTExAl83BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNTg5OTA2MjExMQJfOAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDU4OTkwNjIxMTECXzkEDnRvdGFsTG9uZ0FmdGVyCAUNJHQwNTg5OTA2MjExMQNfMTAED3RvdGFsU2hvcnRBZnRlcggFDSR0MDU4OTkwNjIxMTEDXzExBBp0b3RhbExvbmdPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDU4OTkwNjIxMTEDXzEyBBt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA1ODk5MDYyMTExA18xMwQLcm9sbG92ZXJGZWUIBQ0kdDA1ODk5MDYyMTExA18xNAQNJHQwNjIxMTc2MjE4OAkBDWRpc3RyaWJ1dGVGZWUBCQBkAgUJZmVlQW1vdW50BQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjIxMTc2MjE4OAJfMQQKZmVlVG9WYXVsdAgFDSR0MDYyMTE3NjIxODgCXzIEBXN0YWtlAwkAZwIFB19hbW91bnQFC3JvbGxvdmVyRmVlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAglhZGRMb2NrZWQFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQACQBlAgUHX2Ftb3VudAULcm9sbG92ZXJGZWUFA25pbAkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZQIFC3JvbGxvdmVyRmVlBQdfYW1vdW50BQNuaWwFA25pbAMJAAACBQVzdGFrZQUFc3Rha2UEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgUJZmVlQW1vdW50BQNuaWwFA25pbAMJAAACBQlub3RpZnlGZWUFCW5vdGlmeUZlZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRduZXdQb3NpdGlvblJlbWFpbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTGF0ZXN0Q1BGBRRuZXdQb3NpdGlvblRpbWVzdGFtcAkBH2luY3JlbWVudFBvc2l0aW9uU2VxdWVuY2VOdW1iZXICBQ1pc05ld1Bvc2l0aW9uBQdfdHJhZGVyCQERdXBkYXRlUG9zaXRpb25GZWUDBQ1pc05ld1Bvc2l0aW9uBQdfdHJhZGVyBQthZGp1c3RlZEZlZQkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUJAQ5kb0J1cm5BcnRpZmFjdAIFDGJ1cm5BcnRpZmFjdAUBaQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQlhZGRNYXJnaW4ABARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIEB19hbW91bnQICQCRAwIIBQFpCHBheW1lbnRzAAAGYW1vdW50BAhfYXNzZXRJZAgJAJEDAggFAWkIcGF5bWVudHMAAAdhc3NldElkBAtfYXNzZXRJZFN0cgkA2AQBCQEFdmFsdWUBBQhfYXNzZXRJZAQMaXNRdW90ZUFzc2V0CQAAAgUIX2Fzc2V0SWQJAQpxdW90ZUFzc2V0AAMDAwMDAwMJAQEhAQUMaXNRdW90ZUFzc2V0BgkBASEBCQETcmVxdWlyZU9wZW5Qb3NpdGlvbgEJAKUIAQgFAWkGY2FsbGVyBgkBASEBCQELaXNTYW1lQXNzZXQCBQdfdHJhZGVyBQtfYXNzZXRJZFN0cgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBCWNsb3NlT25seQAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIcSW52YWxpZCBhZGRNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjQyOTk2NDQ2NwkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjQyOTk2NDQ2NwJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2NDI5OTY0NDY3Al8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY0Mjk5NjQ0NjcCXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjQyOTk2NDQ2NwJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2NDI5OTY0NDY3Al81BAVzdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIJYWRkTG9ja2VkBQNuaWwJAMwIAgkBD0F0dGFjaGVkUGF5bWVudAIJAQpxdW90ZUFzc2V0AAUHX2Ftb3VudAUDbmlsAwkAAAIFBXN0YWtlBQVzdGFrZQQLcm9sbG92ZXJGZWUJAQ9jYWxjUm9sbG92ZXJGZWUCBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25UaW1lc3RhbXAEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQNJHQwNjQ3NTI2NDgxMQkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjQ3NTI2NDgxMQJfMQQKZmVlVG9WYXVsdAgFDSR0MDY0NzUyNjQ4MTECXzIEB3Vuc3Rha2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACDndpdGhkcmF3TG9ja2VkCQDMCAIFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAzggCCQDOCAIJAQ51cGRhdGVQb3NpdGlvbgYFB190cmFkZXIFD29sZFBvc2l0aW9uU2l6ZQkAZAIJAGUCBRFvbGRQb3NpdGlvbk1hcmdpbgULcm9sbG92ZXJGZWUFB19hbW91bnQFF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsBRRvbGRQb3NpdGlvbkxzdFVwZENQRgkBDWxhc3RUaW1lc3RhbXAACQENdXBkYXRlQmFsYW5jZQEJAGUCCQBkAgkBCGNiYWxhbmNlAAUHX2Ftb3VudAULcm9sbG92ZXJGZWUFFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEMcmVtb3ZlTWFyZ2luAQdfYW1vdW50BARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEEGVuc3VyZUNhbGxlZE9uY2UJAPwHBAUEdGhpcwIQZW5zdXJlQ2FsbGVkT25jZQUDbmlsBQNuaWwDCQAAAgUQZW5zdXJlQ2FsbGVkT25jZQUQZW5zdXJlQ2FsbGVkT25jZQQHX3RyYWRlcgkApQgBCAUBaQZjYWxsZXIDAwMDAwkAZwIAAAUHX2Ftb3VudAYJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQEOaXNNYXJrZXRDbG9zZWQACQACAQIfSW52YWxpZCByZW1vdmVNYXJnaW4gcGFyYW1ldGVycwQNJHQwNjU5MjM2NjA5MQkBC2dldFBvc2l0aW9uAQUHX3RyYWRlcgQPb2xkUG9zaXRpb25TaXplCAUNJHQwNjU5MjM2NjA5MQJfMQQRb2xkUG9zaXRpb25NYXJnaW4IBQ0kdDA2NTkyMzY2MDkxAl8yBBdvbGRQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY1OTIzNjYwOTECXzMEFG9sZFBvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjU5MjM2NjA5MQJfNAQUb2xkUG9zaXRpb25UaW1lc3RhbXAIBQ0kdDA2NTkyMzY2MDkxAl81BA0kdDA2NjA5NzY2MzQ2CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUPb2xkUG9zaXRpb25TaXplBRFvbGRQb3NpdGlvbk1hcmdpbgUUb2xkUG9zaXRpb25Mc3RVcGRDUEYFFG9sZFBvc2l0aW9uVGltZXN0YW1wCQEBLQEFB19hbW91bnQEDHJlbWFpbk1hcmdpbggFDSR0MDY2MDk3NjYzNDYCXzEEB2JhZERlYnQIBQ0kdDA2NjA5NzY2MzQ2Al8yBA5mdW5kaW5nUGF5bWVudAgFDSR0MDY2MDk3NjYzNDYCXzMEC3JvbGxvdmVyRmVlCAUNJHQwNjYwOTc2NjM0NgJfNAMJAQIhPQIFB2JhZERlYnQAAAkAAgECHUludmFsaWQgcmVtb3ZlZCBtYXJnaW4gYW1vdW50BAttYXJnaW5SYXRpbwkBD2NhbGNNYXJnaW5SYXRpbwMFDHJlbWFpbk1hcmdpbgUHYmFkRGVidAUXb2xkUG9zaXRpb25PcGVuTm90aW9uYWwDCQEBIQEJARZyZXF1aXJlTW9yZU1hcmdpblJhdGlvAwULbWFyZ2luUmF0aW8JAQ9pbml0TWFyZ2luUmF0aW8ABgkAAgEJAKwCAgkArAICCQCsAgICGVRvbyBtdWNoIG1hcmdpbiByZW1vdmVkOiAJAKQDAQULbWFyZ2luUmF0aW8CAyA8IAkApAMBCQEPaW5pdE1hcmdpblJhdGlvAAQNJHQwNjY3MzI2Njc5MQkBDWRpc3RyaWJ1dGVGZWUBBQtyb2xsb3ZlckZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjY3MzI2Njc5MQJfMQQKZmVlVG9WYXVsdAgFDSR0MDY2NzMyNjY3OTECXzIEFmRvVHJhbnNmZXJGZWVUb1N0YWtlcnMDCQBmAgULcm9sbG92ZXJGZWUAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQEBLQEFCmZlZVRvVmF1bHQFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwQHdW5zdGFrZQkA/AcECQEMdmF1bHRBZGRyZXNzAAIOd2l0aGRyYXdMb2NrZWQJAMwIAgkAZAIFB19hbW91bnQFDGZlZVRvU3Rha2VycwUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQkAzggCCQDOCAIJAM4IAgkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBQxyZW1haW5NYXJnaW4FF29sZFBvc2l0aW9uT3Blbk5vdGlvbmFsCQEfbGF0ZXN0Q3VtdWxhdGl2ZVByZW1pdW1GcmFjdGlvbgEFD29sZFBvc2l0aW9uU2l6ZQkBDWxhc3RUaW1lc3RhbXAACQEId2l0aGRyYXcCCAUBaQZjYWxsZXIFB19hbW91bnQJAQ11cGRhdGVCYWxhbmNlAQkAZQIJAGUCCQEIY2JhbGFuY2UABQdfYW1vdW50BQtyb2xsb3ZlckZlZQUWZG9UcmFuc2ZlckZlZVRvU3Rha2VycwkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ1jbG9zZVBvc2l0aW9uAwVfc2l6ZRRfbWluUXVvdGVBc3NldEFtb3VudAxfYWRkVG9NYXJnaW4EBHN5bmMJAPwHBAUEdGhpcwIZc3luY1Rlcm1pbmFsUHJpY2VUb09yYWNsZQUDbmlsBQNuaWwDCQAAAgUEc3luYwUEc3luYwQQZW5zdXJlQ2FsbGVkT25jZQkA/AcEBQR0aGlzAhBlbnN1cmVDYWxsZWRPbmNlBQNuaWwFA25pbAMJAAACBRBlbnN1cmVDYWxsZWRPbmNlBRBlbnN1cmVDYWxsZWRPbmNlBAdfdHJhZGVyCQEPZ2V0QWN0dWFsQ2FsbGVyAQUBaQQOX3RyYWRlckFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkApggBBQdfdHJhZGVyAg5JbnZhbGlkIGNhbGxlcgQLcG9zaXRpb25GZWUJAQ5nZXRQb3NpdGlvbkZlZQEFB190cmFkZXIDAwMDAwMJAQEhAQkBE3JlcXVpcmVPcGVuUG9zaXRpb24BBQdfdHJhZGVyBgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAGCQBnAgAABQVfc2l6ZQYJAGYCAAAFFF9taW5RdW90ZUFzc2V0QW1vdW50BgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECIEludmFsaWQgY2xvc2VQb3NpdGlvbiBwYXJhbWV0ZXJzBBRvbGRQb3NpdGlvblRpbWVzdGFtcAgJAQtnZXRQb3NpdGlvbgEFB190cmFkZXICXzUEDSR0MDY4NDQ4NjkwMzMJARVpbnRlcm5hbENsb3NlUG9zaXRpb24HBQdfdHJhZGVyBQVfc2l6ZQULcG9zaXRpb25GZWUFFF9taW5RdW90ZUFzc2V0QW1vdW50BQxfYWRkVG9NYXJnaW4GBgQPbmV3UG9zaXRpb25TaXplCAUNJHQwNjg0NDg2OTAzMwJfMQQRbmV3UG9zaXRpb25NYXJnaW4IBQ0kdDA2ODQ0ODY5MDMzAl8yBBduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAgFDSR0MDY4NDQ4NjkwMzMCXzMEFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCAUNJHQwNjg0NDg2OTAzMwJfNAQPcG9zaXRpb25CYWREZWJ0CAUNJHQwNjg0NDg2OTAzMwJfNQQLcmVhbGl6ZWRQbmwIBQ0kdDA2ODQ0ODY5MDMzAl82BA5tYXJnaW5Ub1RyYWRlcggFDSR0MDY4NDQ4NjkwMzMCXzcEFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2ODQ0ODY5MDMzAl84BBViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIIBQ0kdDA2ODQ0ODY5MDMzAl85BBZ0b3RhbFBvc2l0aW9uU2l6ZUFmdGVyCAUNJHQwNjg0NDg2OTAzMwNfMTAEGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIIBQ0kdDA2ODQ0ODY5MDMzA18xMQQOdG90YWxMb25nQWZ0ZXIIBQ0kdDA2ODQ0ODY5MDMzA18xMgQPdG90YWxTaG9ydEFmdGVyCAUNJHQwNjg0NDg2OTAzMwNfMTMEGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNjg0NDg2OTAzMwNfMTQEG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcggFDSR0MDY4NDQ4NjkwMzMDXzE1BAtyZWFsaXplZEZlZQgFDSR0MDY4NDQ4NjkwMzMDXzE2AwkAZgIFD3Bvc2l0aW9uQmFkRGVidAAACQACAQIqSW52YWxpZCBjbG9zZVBvc2l0aW9uIHBhcmFtZXRlcnM6IGJhZCBkZWJ0AwkAZwIFFG9sZFBvc2l0aW9uVGltZXN0YW1wCQENbGFzdFRpbWVzdGFtcAAJAAIBAlNJbnZhbGlkIGNsb3NlUG9zaXRpb24gcGFyYW1ldGVyczogd2FpdCBhdCBsZWFzdCAxIGJsb2NrIGJlZm9yZSBjbG9zaW5nIHRoZSBwb3NpdGlvbgQOaXNQYXJ0aWFsQ2xvc2UJAQIhPQIFD25ld1Bvc2l0aW9uU2l6ZQAABA53aXRoZHJhd0Ftb3VudAkAZAIFDm1hcmdpblRvVHJhZGVyBQtyZWFsaXplZEZlZQQKYW1tQmFsYW5jZQkAZQIJAQhjYmFsYW5jZQAFDndpdGhkcmF3QW1vdW50BA1hbW1OZXdCYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBQ53aXRoZHJhd0Ftb3VudAUDbmlsBQNuaWwDCQAAAgUHdW5zdGFrZQUHdW5zdGFrZQQNJHQwNjk3MDU2OTc2NAkBDWRpc3RyaWJ1dGVGZWUBBQtyZWFsaXplZEZlZQQMZmVlVG9TdGFrZXJzCAUNJHQwNjk3MDU2OTc2NAJfMQQKZmVlVG9WYXVsdAgFDSR0MDY5NzA1Njk3NjQCXzIEDGRlcG9zaXRWYXVsdAkA/AcECQEMdmF1bHRBZGRyZXNzAAIHYWRkRnJlZQUDbmlsCQDMCAIJAQ9BdHRhY2hlZFBheW1lbnQCCQEKcXVvdGVBc3NldAAFCmZlZVRvVmF1bHQFA25pbAMJAAACBQxkZXBvc2l0VmF1bHQFDGRlcG9zaXRWYXVsdAQJbm90aWZ5RmVlCQD8BwQJAQxtaW5lckFkZHJlc3MAAgpub3RpZnlGZWVzCQDMCAIFB190cmFkZXIJAMwIAgULcmVhbGl6ZWRGZWUFA25pbAUDbmlsAwkAAAIFCW5vdGlmeUZlZQUJbm90aWZ5RmVlBA5ub3RpZnlOb3Rpb25hbAkA/AcECQEMbWluZXJBZGRyZXNzAAIObm90aWZ5Tm90aW9uYWwJAMwIAgUHX3RyYWRlcgkAzAgCBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUDbmlsBQNuaWwDCQAAAgUObm90aWZ5Tm90aW9uYWwFDm5vdGlmeU5vdGlvbmFsCQDOCAIJAM4IAgkAzggCCQDOCAIDBQ5pc1BhcnRpYWxDbG9zZQkBDnVwZGF0ZVBvc2l0aW9uBgUHX3RyYWRlcgUPbmV3UG9zaXRpb25TaXplBRFuZXdQb3NpdGlvbk1hcmdpbgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFFG5ld1Bvc2l0aW9uTHN0VXBkQ1BGCQENbGFzdFRpbWVzdGFtcAAJAQ5kZWxldGVQb3NpdGlvbgEFB190cmFkZXIJAQl1cGRhdGVBbW0IBRZxdW90ZUFzc2V0UmVzZXJ2ZUFmdGVyBRViYXNlQXNzZXRSZXNlcnZlQWZ0ZXIFFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIFGW9wZW5JbnRlcmVzdE5vdGlvbmFsQWZ0ZXIFDnRvdGFsTG9uZ0FmdGVyBQ90b3RhbFNob3J0QWZ0ZXIFGnRvdGFsTG9uZ09wZW5JbnRlcmVzdEFmdGVyBRt0b3RhbFNob3J0T3BlbkludGVyZXN0QWZ0ZXIDCQBmAgUObWFyZ2luVG9UcmFkZXIAAAkBCHdpdGhkcmF3AgUOX3RyYWRlckFkZHJlc3MFDm1hcmdpblRvVHJhZGVyBQNuaWwJAQ11cGRhdGVCYWxhbmNlAQUNYW1tTmV3QmFsYW5jZQkBC3RyYW5zZmVyRmVlAQUMZmVlVG9TdGFrZXJzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBCWxpcXVpZGF0ZQEHX3RyYWRlcgQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBA9zcG90TWFyZ2luUmF0aW8JARZnZXRNYXJnaW5SYXRpb0J5T3B0aW9uAgUHX3RyYWRlcgUPUE5MX09QVElPTl9TUE9UBBZsaXF1aWRhdGlvbk1hcmdpblJhdGlvAwkBFmlzT3ZlckZsdWN0dWF0aW9uTGltaXQABBFvcmFjbGVNYXJnaW5SYXRpbwkBFmdldE1hcmdpblJhdGlvQnlPcHRpb24CBQdfdHJhZGVyBRFQTkxfT1BUSU9OX09SQUNMRQkBBHZtYXgCBQ9zcG90TWFyZ2luUmF0aW8FEW9yYWNsZU1hcmdpblJhdGlvBQ9zcG90TWFyZ2luUmF0aW8DAwMDAwkBASEBCQEWcmVxdWlyZU1vcmVNYXJnaW5SYXRpbwMFFmxpcXVpZGF0aW9uTWFyZ2luUmF0aW8JARZtYWludGVuYW5jZU1hcmdpblJhdGlvAAcGCQEBIQEJARNyZXF1aXJlT3BlblBvc2l0aW9uAQUHX3RyYWRlcgYJAQEhAQkBC2luaXRpYWxpemVkAAYJAQZwYXVzZWQABgkBDmlzTWFya2V0Q2xvc2VkAAkAAgECE1VuYWJsZSB0byBsaXF1aWRhdGUEFGlzUGFydGlhbExpcXVpZGF0aW9uAwMJAGYCBQ9zcG90TWFyZ2luUmF0aW8JARNsaXF1aWRhdGlvbkZlZVJhdGlvAAkAZgIJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAAAAcJAGYCBQxERUNJTUFMX1VOSVQJARdwYXJ0aWFsTGlxdWlkYXRpb25SYXRpbwAHBA9vbGRQb3NpdGlvblNpemUICQELZ2V0UG9zaXRpb24BBQdfdHJhZGVyAl8xBA9wb3NpdGlvblNpemVBYnMJAQNhYnMBBQ9vbGRQb3NpdGlvblNpemUEDSR0MDcyMDc3NzI0MDADBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgQPbGlxdWlkYXRpb25TaXplCQEbZ2V0UGFydGlhbExpcXVpZGF0aW9uQW1vdW50AgUHX3RyYWRlcgUPb2xkUG9zaXRpb25TaXplBBBsaXF1aWRhdGlvblJhdGlvCQEEZGl2ZAIJAQNhYnMBBQ9saXF1aWRhdGlvblNpemUFD3Bvc2l0aW9uU2l6ZUFicwkAlAoCBRBsaXF1aWRhdGlvblJhdGlvCQEDYWJzAQUPbGlxdWlkYXRpb25TaXplCQCUCgIAAAUPcG9zaXRpb25TaXplQWJzBBBsaXF1aWRhdGlvblJhdGlvCAUNJHQwNzIwNzc3MjQwMAJfMQQPbGlxdWlkYXRpb25TaXplCAUNJHQwNzIwNzc3MjQwMAJfMgQNJHQwNzI0MDY3MzA0NAkBFWludGVybmFsQ2xvc2VQb3NpdGlvbgcFB190cmFkZXIDBRRpc1BhcnRpYWxMaXF1aWRhdGlvbgUPbGlxdWlkYXRpb25TaXplBQ9wb3NpdGlvblNpemVBYnMJARNsaXF1aWRhdGlvbkZlZVJhdGlvAAAABgcGBA9uZXdQb3NpdGlvblNpemUIBQ0kdDA3MjQwNjczMDQ0Al8xBBFuZXdQb3NpdGlvbk1hcmdpbggFDSR0MDcyNDA2NzMwNDQCXzIEF25ld1Bvc2l0aW9uT3Blbk5vdGlvbmFsCAUNJHQwNzI0MDY3MzA0NAJfMwQUbmV3UG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3MjQwNjczMDQ0Al80BA9wb3NpdGlvbkJhZERlYnQIBQ0kdDA3MjQwNjczMDQ0Al81BAtyZWFsaXplZFBubAgFDSR0MDcyNDA2NzMwNDQCXzYEDm1hcmdpblRvVHJhZGVyCAUNJHQwNzI0MDY3MzA0NAJfNwQWcXVvdGVBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyNDA2NzMwNDQCXzgEFWJhc2VBc3NldFJlc2VydmVBZnRlcggFDSR0MDcyNDA2NzMwNDQCXzkEFnRvdGFsUG9zaXRpb25TaXplQWZ0ZXIIBQ0kdDA3MjQwNjczMDQ0A18xMAQZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcggFDSR0MDcyNDA2NzMwNDQDXzExBA50b3RhbExvbmdBZnRlcggFDSR0MDcyNDA2NzMwNDQDXzEyBA90b3RhbFNob3J0QWZ0ZXIIBQ0kdDA3MjQwNjczMDQ0A18xMwQadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIIBQ0kdDA3MjQwNjczMDQ0A18xNAQbdG90YWxTaG9ydE9wZW5JbnRlcmVzdEFmdGVyCAUNJHQwNzI0MDY3MzA0NANfMTUEEmxpcXVpZGF0aW9uUGVuYWx0eQgFDSR0MDcyNDA2NzMwNDQDXzE2BA9mZWVUb0xpcXVpZGF0b3IJAGkCBRJsaXF1aWRhdGlvblBlbmFsdHkAAgQKZmVlVG9WYXVsdAkAZQIFEmxpcXVpZGF0aW9uUGVuYWx0eQUPZmVlVG9MaXF1aWRhdG9yBAphbW1CYWxhbmNlCQBlAgkBCGNiYWxhbmNlAAUSbGlxdWlkYXRpb25QZW5hbHR5BA1uZXdBbW1CYWxhbmNlAwkAZgIAAAUKYW1tQmFsYW5jZQAABQphbW1CYWxhbmNlBAtsb2NrQmFkRGVidAMJAGYCBQ9wb3NpdGlvbkJhZERlYnQAAAQLbG9ja0JhZERlYnQJAPwHBAkBDHZhdWx0QWRkcmVzcwACFWV4Y2hhbmdlRnJlZUFuZExvY2tlZAkAzAgCCQBkAgUPcG9zaXRpb25CYWREZWJ0BRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFC2xvY2tCYWREZWJ0BQtsb2NrQmFkRGVidAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgULbG9ja0JhZERlYnQFC2xvY2tCYWREZWJ0BAd1bnN0YWtlCQD8BwQJAQx2YXVsdEFkZHJlc3MAAg53aXRoZHJhd0xvY2tlZAkAzAgCBRJsaXF1aWRhdGlvblBlbmFsdHkFA25pbAUDbmlsAwkAAAIFB3Vuc3Rha2UFB3Vuc3Rha2UEEGRlcG9zaXRJbnN1cmFuY2UJAPwHBAkBDHZhdWx0QWRkcmVzcwACB2FkZEZyZWUFA25pbAkAzAgCCQEPQXR0YWNoZWRQYXltZW50AgkBCnF1b3RlQXNzZXQABQpmZWVUb1ZhdWx0BQNuaWwDCQAAAgUQZGVwb3NpdEluc3VyYW5jZQUQZGVwb3NpdEluc3VyYW5jZQQObm90aWZ5Tm90aW9uYWwJAPwHBAkBDG1pbmVyQWRkcmVzcwACDm5vdGlmeU5vdGlvbmFsCQDMCAIFB190cmFkZXIJAMwIAgUXbmV3UG9zaXRpb25PcGVuTm90aW9uYWwFA25pbAUDbmlsAwkAAAIFDm5vdGlmeU5vdGlvbmFsBQ5ub3RpZnlOb3Rpb25hbAkAzggCCQDOCAIJAM4IAgMFFGlzUGFydGlhbExpcXVpZGF0aW9uCQEOdXBkYXRlUG9zaXRpb24GBQdfdHJhZGVyBQ9uZXdQb3NpdGlvblNpemUFEW5ld1Bvc2l0aW9uTWFyZ2luBRduZXdQb3NpdGlvbk9wZW5Ob3Rpb25hbAUUbmV3UG9zaXRpb25Mc3RVcGRDUEYJAQ1sYXN0VGltZXN0YW1wAAkBDmRlbGV0ZVBvc2l0aW9uAQUHX3RyYWRlcgkBCXVwZGF0ZUFtbQgFFnF1b3RlQXNzZXRSZXNlcnZlQWZ0ZXIFFWJhc2VBc3NldFJlc2VydmVBZnRlcgUWdG90YWxQb3NpdGlvblNpemVBZnRlcgUZb3BlbkludGVyZXN0Tm90aW9uYWxBZnRlcgUOdG90YWxMb25nQWZ0ZXIFD3RvdGFsU2hvcnRBZnRlcgUadG90YWxMb25nT3BlbkludGVyZXN0QWZ0ZXIFG3RvdGFsU2hvcnRPcGVuSW50ZXJlc3RBZnRlcgkBCHdpdGhkcmF3AggFAWkGY2FsbGVyBQ9mZWVUb0xpcXVpZGF0b3IJAQ11cGRhdGVCYWxhbmNlAQUNbmV3QW1tQmFsYW5jZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQpwYXlGdW5kaW5nAAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBBVmdW5kaW5nQmxvY2tUaW1lc3RhbXAJARluZXh0RnVuZGluZ0Jsb2NrVGltZXN0YW1wAAMDAwkAZgIFFWZ1bmRpbmdCbG9ja1RpbWVzdGFtcAkBDWxhc3RUaW1lc3RhbXAABgkBASEBCQELaW5pdGlhbGl6ZWQABgkBBnBhdXNlZAAJAAIBCQCsAgIJAKwCAgkArAICAiFJbnZhbGlkIGZ1bmRpbmcgYmxvY2sgdGltZXN0YW1wOiAJAKQDAQkBDWxhc3RUaW1lc3RhbXAAAgMgPCAJAKQDAQUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wBA91bmRlcmx5aW5nUHJpY2UJAQ5nZXRPcmFjbGVQcmljZQAEDSR0MDc1MDMxNzUwOTMJAQpnZXRGdW5kaW5nAAQUc2hvcnRQcmVtaXVtRnJhY3Rpb24IBQ0kdDA3NTAzMTc1MDkzAl8xBBNsb25nUHJlbWl1bUZyYWN0aW9uCAUNJHQwNzUwMzE3NTA5MwJfMgkBDXVwZGF0ZUZ1bmRpbmcFCQBkAgUVZnVuZGluZ0Jsb2NrVGltZXN0YW1wCQEUZnVuZGluZ1BlcmlvZFNlY29uZHMACQBkAgkBI2xhdGVzdExvbmdDdW11bGF0aXZlUHJlbWl1bUZyYWN0aW9uAAUTbG9uZ1ByZW1pdW1GcmFjdGlvbgkAZAIJASRsYXRlc3RTaG9ydEN1bXVsYXRpdmVQcmVtaXVtRnJhY3Rpb24ABRRzaG9ydFByZW1pdW1GcmFjdGlvbgkBBGRpdmQCBRNsb25nUHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAQRkaXZkAgUUc2hvcnRQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlAAQHX3F0QXN0UgkBBnF0QXN0UgAEB19ic0FzdFIJAQZic0FzdFIABA0kdDA3NTUyNTc1ODkxCQEUZ2V0U3luY1Rlcm1pbmFsUHJpY2UDCQEOZ2V0T3JhY2xlUHJpY2UABQdfcXRBc3RSBQdfYnNBc3RSBBNuZXdRdW90ZUFzc2V0V2VpZ2h0CAUNJHQwNzU1MjU3NTg5MQJfMQQSbmV3QmFzZUFzc2V0V2VpZ2h0CAUNJHQwNzU1MjU3NTg5MQJfMgQNbWFyZ2luVG9WYXVsdAgFDSR0MDc1NTI1NzU4OTECXzMEEG1hcmdpblRvVmF1bHRBZGoDAwkAZgIAAAUNbWFyZ2luVG9WYXVsdAkAZgIJAQNhYnMBBQ1tYXJnaW5Ub1ZhdWx0CQEIY2JhbGFuY2UABwkBAS0BCQEIY2JhbGFuY2UABQ1tYXJnaW5Ub1ZhdWx0BA1kb0V4Y2hhbmdlUG5MAwkBAiE9AgUQbWFyZ2luVG9WYXVsdEFkagAABA1kb0V4Y2hhbmdlUG5MCQD8BwQJAQx2YXVsdEFkZHJlc3MAAhVleGNoYW5nZUZyZWVBbmRMb2NrZWQJAMwIAgUQbWFyZ2luVG9WYXVsdEFkagUDbmlsBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuBQNuaWwDCQAAAgUNZG9FeGNoYW5nZVBuTAUNZG9FeGNoYW5nZVBuTAkAzggCCQDOCAIJAQ11cGRhdGVCYWxhbmNlAQkAZAIJAQhjYmFsYW5jZQAFEG1hcmdpblRvVmF1bHRBZGoJARB1cGRhdGVBbW1XZWlnaHRzAgUTbmV3UXVvdGVBc3NldFdlaWdodAUSbmV3QmFzZUFzc2V0V2VpZ2h0CQEKYXBwZW5kVHdhcAEJAQRkaXZkAgkBBG11bGQCBQdfcXRBc3RSBRNuZXdRdW90ZUFzc2V0V2VpZ2h0CQEEbXVsZAIFB19ic0FzdFIFEm5ld0Jhc2VBc3NldFdlaWdodAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBlbnN1cmVDYWxsZWRPbmNlAAMJAQIhPQIIBQFpBmNhbGxlcgUEdGhpcwkAAgECIkludmFsaWQgc2F2ZUN1cnJlbnRUeElkIHBhcmFtZXRlcnMEBmxhc3RUeAkBC3ZhbHVlT3JFbHNlAgkAnQgCBQR0aGlzBQhrX2xhc3RUeAIAAwkBAiE9AgUGbGFzdFR4CQDYBAEIBQFpDXRyYW5zYWN0aW9uSWQJAMwIAgkBC1N0cmluZ0VudHJ5AgUIa19sYXN0VHgFBmxhc3RUeAUDbmlsCQACAQIpQ2FuIG5vdCBjYWxsIHZBTU0gbWV0aG9kcyB0d2ljZSBpbiBvbmUgdHgBaQEndmlld19jYWxjUmVtYWluTWFyZ2luV2l0aEZ1bmRpbmdQYXltZW50AQdfdHJhZGVyBARzeW5jCQD8BwQFBHRoaXMCGXN5bmNUZXJtaW5hbFByaWNlVG9PcmFjbGUFA25pbAUDbmlsAwkAAAIFBHN5bmMFBHN5bmMEDSR0MDc3MDUwNzcxNzQJAQtnZXRQb3NpdGlvbgEFB190cmFkZXIEDHBvc2l0aW9uU2l6ZQgFDSR0MDc3MDUwNzcxNzQCXzEEDnBvc2l0aW9uTWFyZ2luCAUNJHQwNzcwNTA3NzE3NAJfMgQDcG9uCAUNJHQwNzcwNTA3NzE3NAJfMwQRcG9zaXRpb25Mc3RVcGRDUEYIBQ0kdDA3NzA1MDc3MTc0Al80BBFwb3NpdGlvblRpbWVzdGFtcAgFDSR0MDc3MDUwNzcxNzQCXzUEDSR0MDc3MTc3NzcyNzgJASNnZXRQb3NpdGlvbk5vdGlvbmFsQW5kVW5yZWFsaXplZFBubAIFB190cmFkZXIFD1BOTF9PUFRJT05fU1BPVAQQcG9zaXRpb25Ob3Rpb25hbAgFDSR0MDc3MTc3NzcyNzgCXzEEDXVucmVhbGl6ZWRQbmwIBQ0kdDA3NzE3Nzc3Mjc4Al8yBA0kdDA3NzI4MTc3NTA1CQEwY2FsY1JlbWFpbk1hcmdpbldpdGhGdW5kaW5nUGF5bWVudEFuZFJvbGxvdmVyRmVlBQUMcG9zaXRpb25TaXplBQ5wb3NpdGlvbk1hcmdpbgURcG9zaXRpb25Mc3RVcGRDUEYFEXBvc2l0aW9uVGltZXN0YW1wBQ11bnJlYWxpemVkUG5sBAxyZW1haW5NYXJnaW4IBQ0kdDA3NzI4MTc3NTA1Al8xBAdiYWREZWJ0CAUNJHQwNzcyODE3NzUwNQJfMgQOZnVuZGluZ1BheW1lbnQIBQ0kdDA3NzI4MTc3NTA1Al8zBAtyb2xsb3ZlckZlZQgFDSR0MDc3MjgxNzc1MDUCXzQJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJAKwCAgkArAICCQEBcwEFDHJlbWFpbk1hcmdpbgkBAXMBBQ5mdW5kaW5nUGF5bWVudAkBAXMBCQEOZ2V0TWFyZ2luUmF0aW8BBQdfdHJhZGVyCQEBcwEFDXVucmVhbGl6ZWRQbmwJAQFzAQUHYmFkRGVidAkBAXMBBRBwb3NpdGlvbk5vdGlvbmFsCQEBcwEFC3JvbGxvdmVyRmVlCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBFXZpZXdfZ2V0UGVnQWRqdXN0Q29zdAEGX3ByaWNlBAdfcXRBc3RSCQEGcXRBc3RSAAQHX2JzQXN0UgkBBmJzQXN0UgAEBnJlc3VsdAkBFGdldFN5bmNUZXJtaW5hbFByaWNlAwUGX3ByaWNlBQdfcXRBc3RSBQdfYnNBc3RSCQACAQkApAMBCAUGcmVzdWx0Al8zAWkBGHZpZXdfZ2V0VGVybWluYWxBbW1QcmljZQAEDSR0MDc3OTQxNzgwMjIJARNnZXRUZXJtaW5hbEFtbVN0YXRlAAQZdGVybWluYWxRdW90ZUFzc2V0UmVzZXJ2ZQgFDSR0MDc3OTQxNzgwMjICXzEEGHRlcm1pbmFsQmFzZUFzc2V0UmVzZXJ2ZQgFDSR0MDc3OTQxNzgwMjICXzIEBXByaWNlCQEEZGl2ZAIJAQRtdWxkAgUZdGVybWluYWxRdW90ZUFzc2V0UmVzZXJ2ZQkBBnF0QXN0VwAJAQRtdWxkAgUYdGVybWluYWxCYXNlQXNzZXRSZXNlcnZlCQEGYnNBc3RXAAkAAgEJAKQDAQUFcHJpY2UBaQEPdmlld19nZXRGdW5kaW5nAAQPdW5kZXJseWluZ1ByaWNlCQEOZ2V0T3JhY2xlUHJpY2UABA0kdDA3ODIzNzc4Mjk5CQEKZ2V0RnVuZGluZwAEFHNob3J0UHJlbWl1bUZyYWN0aW9uCAUNJHQwNzgyMzc3ODI5OQJfMQQTbG9uZ1ByZW1pdW1GcmFjdGlvbggFDSR0MDc4MjM3NzgyOTkCXzIEC2xvbmdGdW5kaW5nCQEEZGl2ZAIFE2xvbmdQcmVtaXVtRnJhY3Rpb24FD3VuZGVybHlpbmdQcmljZQQMc2hvcnRGdW5kaW5nCQEEZGl2ZAIFFHNob3J0UHJlbWl1bUZyYWN0aW9uBQ91bmRlcmx5aW5nUHJpY2UJAAIBCQCsAgIJAKwCAgkArAICCQEBcwEFC2xvbmdGdW5kaW5nCQEBcwEFDHNob3J0RnVuZGluZwkBAXMBCQEQZ2V0VHdhcFNwb3RQcmljZQAJAQFzAQkBDmdldE9yYWNsZVByaWNlAAFpARBjb21wdXRlU3BvdFByaWNlAAQEc3luYwkA/AcEBQR0aGlzAhlzeW5jVGVybWluYWxQcmljZVRvT3JhY2xlBQNuaWwFA25pbAMJAAACBQRzeW5jBQRzeW5jBAZyZXN1bHQJAQxnZXRTcG90UHJpY2UACQCUCgIFA25pbAUGcmVzdWx0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBH2NvbXB1dGVGZWVGb3JUcmFkZXJXaXRoQXJ0aWZhY3QCB190cmFkZXILX2FydGlmYWN0SWQEBnJlc3VsdAkBGGdldEZvclRyYWRlcldpdGhBcnRpZmFjdAIFB190cmFkZXIFC19hcnRpZmFjdElkCQCUCgIFA25pbAUGcmVzdWx0AQJ0eAEGdmVyaWZ5AAQOY29vcmRpbmF0b3JTdHIJAJ0IAgUEdGhpcwUUa19jb29yZGluYXRvckFkZHJlc3MDCQEJaXNEZWZpbmVkAQUOY29vcmRpbmF0b3JTdHIEBWFkbWluCQCdCAIJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAQV2YWx1ZQEFDmNvb3JkaW5hdG9yU3RyBQ9rX2FkbWluX2FkZHJlc3MDCQEJaXNEZWZpbmVkAQUFYWRtaW4JAQt2YWx1ZU9yRWxzZQIJAJsIAgkBEUBleHRyTmF0aXZlKDEwNjIpAQkBBXZhbHVlAQUFYWRtaW4JAKwCAgkArAICCQCsAgICB3N0YXR1c18JAKUIAQUEdGhpcwIBXwkA2AQBCAUCdHgCaWQHCQACAQIudW5hYmxlIHRvIHZlcmlmeTogYWRtaW4gbm90IHNldCBpbiBjb29yZGluYXRvcgkA9AMDCAUCdHgJYm9keUJ5dGVzCQCRAwIIBQJ0eAZwcm9vZnMAAAgFAnR4D3NlbmRlclB1YmxpY0tlecpxFRg=", "height": 3526681, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: J3uL5hujwpEHVejkBucZmsrVD57Mtr64KWewULVUgarv Next: 9yj2FgFtHMuFcbfDLmkeEtf9jHQHV9AYNMrVP73GVjcY Full:
OldNewDifferences
11 {-# STDLIB_VERSION 6 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let k_baseOracle = "k_baseOracle"
55
66 let k_quoteOracle = "k_quoteOracle"
77
88 let k_balance = "k_balance"
99
1010 let k_sequence = "k_sequence"
1111
1212 let k_positionSize = "k_positionSize"
1313
1414 let k_positionMargin = "k_positionMargin"
1515
1616 let k_positionOpenNotional = "k_positionOpenNotional"
1717
1818 let k_positionLastUpdatedCumulativePremiumFraction = "k_positionFraction"
1919
2020 let k_positionSequence = "k_positionSequence"
2121
2222 let k_positionAsset = "k_positionAsset"
2323
2424 let k_positionFee = "k_positionFee"
2525
2626 let k_positionLastUpdatedTimestamp = "k_positionTimestamp"
2727
2828 let k_initialized = "k_initialized"
2929
3030 let k_paused = "k_paused"
3131
3232 let k_closeOnly = "k_closeOnly"
3333
3434 let k_fee = "k_fee"
3535
3636 let k_rolloverFee = "k_rollover_fee"
3737
3838 let k_fundingPeriod = "k_fundingPeriod"
3939
4040 let k_initMarginRatio = "k_initMarginRatio"
4141
4242 let k_maintenanceMarginRatio = "k_mmr"
4343
4444 let k_liquidationFeeRatio = "k_liquidationFeeRatio"
4545
4646 let k_partialLiquidationRatio = "k_partLiquidationRatio"
4747
4848 let k_spreadLimit = "k_spreadLimit"
4949
5050 let k_maxPriceImpact = "k_maxPriceImpact"
5151
5252 let k_maxPriceSpread = "k_maxPriceSpread"
5353
5454 let k_maxOpenNotional = "k_maxOpenNotional"
5555
5656 let k_feeToStakersPercent = "k_feeToStakersPercent"
5757
5858 let k_maxOracleDelay = "k_maxOracleDelay"
5959
6060 let k_lastDataStr = "k_lastDataStr"
6161
6262 let k_lastMinuteId = "k_lastMinuteId"
6363
6464 let k_twapDataLastCumulativePrice = "k_twapDataLastCumulativePrice"
6565
6666 let k_twapDataLastPrice = "k_twapDataLastPrice"
6767
6868 let k_twapDataPreviousMinuteId = "k_twapDataPreviousMinuteId"
6969
7070 let k_latestLongCumulativePremiumFraction = "k_latestLongPremiumFraction"
7171
7272 let k_latestShortCumulativePremiumFraction = "k_latestShortPremiumFraction"
7373
7474 let k_nextFundingBlock = "k_nextFundingBlockMinTimestamp"
7575
7676 let k_longFundingRate = "k_longFundingRate"
7777
7878 let k_shortFundingRate = "k_shortFundingRate"
7979
8080 let k_quoteAssetReserve = "k_qtAstR"
8181
8282 let k_baseAssetReserve = "k_bsAstR"
8383
8484 let k_quoteAssetWeight = "k_qtAstW"
8585
8686 let k_baseAssetWeight = "k_bsAstW"
8787
8888 let k_totalPositionSize = "k_totalPositionSize"
8989
9090 let k_totalLongPositionSize = "k_totalLongPositionSize"
9191
9292 let k_totalShortPositionSize = "k_totalShortPositionSize"
9393
9494 let k_openInterestNotional = "k_openInterestNotional"
9595
9696 let k_openInterestShort = "k_openInterestShort"
9797
9898 let k_openInterestLong = "k_openInterestLong"
9999
100100 let k_lastTx = "k_lastTx"
101101
102102 let k_coordinatorAddress = "k_coordinatorAddress"
103103
104104 let k_vault_address = "k_vault_address"
105105
106106 let k_admin_address = "k_admin_address"
107107
108108 let k_quote_asset = "k_quote_asset"
109109
110110 let k_quote_staking = "k_quote_staking"
111111
112112 let k_staking_address = "k_staking_address"
113113
114114 let k_miner_address = "k_miner_address"
115115
116116 let k_orders_address = "k_orders_address"
117117
118118 let k_referral_address = "k_referral_address"
119119
120120 let k_exchange_address = "k_exchange_address"
121121
122122 let k_nft_manager_address = "k_nft_manager_address"
123123
124124 func toCompositeKey (_key,_address) = ((_key + "_") + _address)
125125
126126
127127 func coordinator () = valueOrErrorMessage(addressFromString(getStringValue(this, k_coordinatorAddress)), "Coordinator not set")
128128
129129
130130 func adminAddress () = addressFromString(getStringValue(coordinator(), k_admin_address))
131131
132132
133133 func quoteAsset () = fromBase58String(getStringValue(coordinator(), k_quote_asset))
134134
135135
136136 func quoteAssetStaking () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_quote_staking)), "Quote asset staking not set")
137137
138138
139139 func stakingAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_staking_address)), "Staking not set")
140140
141141
142142 func vaultAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_vault_address)), "Vault not set")
143143
144144
145145 func minerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_miner_address)), "Miner not set")
146146
147147
148148 func ordersAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_orders_address)), "Orders not set")
149149
150150
151151 func referralAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_referral_address)), "Referral not set")
152152
153153
154154 func nftManagerAddress () = valueOrErrorMessage(addressFromString(getStringValue(coordinator(), k_nft_manager_address)), "NFT Manager not set")
155155
156156
157157 let k_token_param = "k_token_param"
158158
159159 let k_token_type = "k_token_type"
160160
161161 let FEE_REDUCTION_TOKEN_TYPE = "fee_reduction"
162162
163163 let DIR_LONG = 1
164164
165165 let DIR_SHORT = 2
166166
167167 let TWAP_INTERVAL = 15
168168
169169 let SECONDS = 1000
170170
171171 let DECIMAL_NUMBERS = 6
172172
173173 let DECIMAL_UNIT = (1 * (((((10 * 10) * 10) * 10) * 10) * 10))
174174
175175 let MINUTES_IN_YEAR = (525600 * DECIMAL_UNIT)
176176
177177 let ONE_DAY = (86400 * DECIMAL_UNIT)
178178
179179 let PNL_OPTION_SPOT = 1
180180
181181 let PNL_OPTION_ORACLE = 2
182182
183183 func s (_x) = (toString(_x) + ",")
184184
185185
186186 func divd (_x,_y) = fraction(_x, DECIMAL_UNIT, _y, HALFEVEN)
187187
188188
189189 func muld (_x,_y) = fraction(_x, _y, DECIMAL_UNIT, HALFEVEN)
190190
191191
192192 func bdivd (_x,_y) = fraction(_x, toBigInt(DECIMAL_UNIT), _y, HALFEVEN)
193193
194194
195195 func bmuld (_x,_y) = fraction(_x, _y, toBigInt(DECIMAL_UNIT), HALFEVEN)
196196
197197
198198 func abs (_x) = if ((_x > 0))
199199 then _x
200200 else -(_x)
201201
202202
203203 func vmax (_x,_y) = if ((_x >= _y))
204204 then _x
205205 else _y
206206
207207
208208 func listToStr (_list) = if ((size(_list) == 0))
209209 then ""
210210 else makeString(_list, ",")
211211
212212
213213 func strToList (_str) = if ((_str == ""))
214214 then nil
215215 else split(_str, ",")
216216
217217
218218 func pushToQueue (_list,_maxSize,_value) = if ((size(_list) > _maxSize))
219219 then (removeByIndex(_list, 0) :+ _value)
220220 else (_list :+ _value)
221221
222222
223223 func int (k) = valueOrErrorMessage(getInteger(this, k), ("no value for " + k))
224224
225225
226226 func intOr (k,def) = valueOrElse(getInteger(this, k), def)
227227
228228
229229 func strA (_address,_key) = {
230230 let val = valueOrErrorMessage(getString(_address, _key), ("No value for key " + _key))
231231 val
232232 }
233233
234234
235235 func intA (_address,_key) = {
236236 let val = valueOrErrorMessage(getInteger(_address, _key), ("No value for key " + _key))
237237 val
238238 }
239239
240240
241241 func cbalance () = int(k_balance)
242242
243243
244244 func fee () = int(k_fee)
245245
246246
247247 func rolloverFeeRate () = int(k_rolloverFee)
248248
249249
250250 func initMarginRatio () = int(k_initMarginRatio)
251251
252252
253253 func qtAstR () = int(k_quoteAssetReserve)
254254
255255
256256 func bsAstR () = int(k_baseAssetReserve)
257257
258258
259259 func qtAstW () = intOr(k_quoteAssetWeight, DECIMAL_UNIT)
260260
261261
262262 func bsAstW () = intOr(k_baseAssetWeight, DECIMAL_UNIT)
263263
264264
265265 func totalPositionSize () = int(k_totalPositionSize)
266266
267267
268268 func openInterestNotional () = int(k_openInterestNotional)
269269
270270
271271 func openInterestShort () = int(k_openInterestShort)
272272
273273
274274 func openInterestLong () = int(k_openInterestLong)
275275
276276
277277 func nextFundingBlockTimestamp () = int(k_nextFundingBlock)
278278
279279
280280 func fundingPeriodRaw () = int(k_fundingPeriod)
281281
282282
283283 func fundingPeriodDecimal () = (fundingPeriodRaw() * DECIMAL_UNIT)
284284
285285
286286 func fundingPeriodSeconds () = (fundingPeriodRaw() * SECONDS)
287287
288288
289289 func maintenanceMarginRatio () = int(k_maintenanceMarginRatio)
290290
291291
292292 func liquidationFeeRatio () = int(k_liquidationFeeRatio)
293293
294294
295295 func partialLiquidationRatio () = int(k_partialLiquidationRatio)
296296
297297
298298 func spreadLimit () = int(k_spreadLimit)
299299
300300
301301 func maxPriceImpact () = int(k_maxPriceImpact)
302302
303303
304304 func maxPriceSpread () = int(k_maxPriceSpread)
305305
306306
307307 func maxOpenNotional () = int(k_maxOpenNotional)
308308
309309
310310 func latestLongCumulativePremiumFraction () = int(k_latestLongCumulativePremiumFraction)
311311
312312
313313 func latestShortCumulativePremiumFraction () = int(k_latestShortCumulativePremiumFraction)
314314
315315
316316 func totalShortPositionSize () = int(k_totalShortPositionSize)
317317
318318
319319 func totalLongPositionSize () = int(k_totalLongPositionSize)
320320
321321
322322 func lastSequence () = intOr(k_sequence, 0)
323323
324324
325325 func feeToStakersPercent () = int(k_feeToStakersPercent)
326326
327327
328328 func maxOracleDelay () = int(k_maxOracleDelay)
329329
330330
331331 func lastTimestamp () = lastBlock.timestamp
332332
333333
334334 func getActualCaller (i) = valueOrElse(getString(ordersAddress(), "k_sender"), toString(i.caller))
335335
336336
337337 func requireMoreMarginRatio (_marginRatio,_baseMarginRatio,_largerThanOrEqualTo) = {
338338 let remainingMarginRatio = (_marginRatio - _baseMarginRatio)
339339 if (if (_largerThanOrEqualTo)
340340 then (0 > remainingMarginRatio)
341341 else false)
342342 then throw(((("Invalid margin: " + toString(_marginRatio)) + " < ") + toString(_baseMarginRatio)))
343343 else if (if (!(_largerThanOrEqualTo))
344344 then (remainingMarginRatio >= 0)
345345 else false)
346346 then throw(((("Invalid margin: " + toString(_marginRatio)) + " > ") + toString(_baseMarginRatio)))
347347 else true
348348 }
349349
350350
351351 func latestCumulativePremiumFraction (_positionSize) = if ((_positionSize == 0))
352352 then throw("Should not be called with _positionSize == 0")
353353 else if ((_positionSize > 0))
354354 then latestLongCumulativePremiumFraction()
355355 else latestShortCumulativePremiumFraction()
356356
357357
358358 func getPosition (_trader) = {
359359 let positionSizeOpt = getInteger(this, toCompositeKey(k_positionSize, _trader))
360360 match positionSizeOpt {
361361 case positionSize: Int =>
362362 $Tuple5(positionSize, getIntegerValue(this, toCompositeKey(k_positionMargin, _trader)), getIntegerValue(this, toCompositeKey(k_positionOpenNotional, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _trader)), getIntegerValue(this, toCompositeKey(k_positionLastUpdatedTimestamp, _trader)))
363363 case _ =>
364364 $Tuple5(0, 0, 0, 0, 0)
365365 }
366366 }
367367
368368
369369 func getPositionAsset (_trader) = {
370370 let positionAssetOpt = getString(this, toCompositeKey(k_positionAsset, _trader))
371371 match positionAssetOpt {
372372 case positionAsset: String =>
373373 positionAsset
374374 case _ =>
375375 toBase58String(quoteAsset())
376376 }
377377 }
378378
379379
380380 func getPositionFee (_trader) = {
381381 let positionFeeOpt = getInteger(this, toCompositeKey(k_positionFee, _trader))
382382 match positionFeeOpt {
383383 case positionFee: Int =>
384384 positionFee
385385 case _ =>
386386 fee()
387387 }
388388 }
389389
390390
391391 func requireOpenPosition (_trader) = if ((getPosition(_trader)._1 == 0))
392392 then throw("No open position")
393393 else true
394394
395395
396396 func getOracleData (key) = {
397397 let oracleDataStr = getString(this, key)
398398 if (if (isDefined(oracleDataStr))
399399 then (value(oracleDataStr) != "")
400400 else false)
401401 then {
402402 let oracleData = split(value(oracleDataStr), ",")
403403 let oracleAddress = valueOrErrorMessage(addressFromString(oracleData[0]), ("Invalid oracle address in: " + value(oracleDataStr)))
404404 let priceKey = oracleData[1]
405405 let blockKey = oracleData[2]
406406 let openKey = oracleData[3]
407407 $Tuple4(oracleAddress, priceKey, blockKey, openKey)
408408 }
409409 else unit
410410 }
411411
412412
413413 func initialized () = valueOrElse(getBoolean(this, k_initialized), false)
414414
415415
416416 func paused () = valueOrElse(getBoolean(this, k_paused), false)
417417
418418
419419 func closeOnly () = valueOrElse(getBoolean(this, k_closeOnly), false)
420420
421421
422422 func updateReserve (_isAdd,_quoteAssetAmount,_baseAssetAmount) = if (_isAdd)
423423 then {
424424 let newBase = (bsAstR() - _baseAssetAmount)
425425 if ((0 >= newBase))
426426 then throw("Tx lead to base asset reserve <= 0, revert")
427427 else $Tuple3((qtAstR() + _quoteAssetAmount), newBase, (totalPositionSize() + _baseAssetAmount))
428428 }
429429 else {
430430 let newQuote = (qtAstR() - _quoteAssetAmount)
431431 if ((0 >= newQuote))
432432 then throw("Tx lead to base quote reserve <= 0, revert")
433433 else $Tuple3(newQuote, (bsAstR() + _baseAssetAmount), (totalPositionSize() - _baseAssetAmount))
434434 }
435435
436436
437437 func calcInvariant (_qtAstR,_bsAstR) = {
438438 let bqtAstR = toBigInt(_qtAstR)
439439 let bbsAstR = toBigInt(_bsAstR)
440440 bmuld(bqtAstR, bbsAstR)
441441 }
442442
443443
444444 func swapInput (_isAdd,_quoteAssetAmount) = {
445445 let _qtAstR = qtAstR()
446446 let _bsAstR = bsAstR()
447447 let _qtAstW = qtAstW()
448448 let _bsAstW = bsAstW()
449449 let quoteAssetAmountAdjusted = divd(_quoteAssetAmount, _qtAstW)
450450 let k = calcInvariant(_qtAstR, _bsAstR)
451451 let quoteAssetReserveAfter = if (_isAdd)
452452 then (_qtAstR + quoteAssetAmountAdjusted)
453453 else (_qtAstR - quoteAssetAmountAdjusted)
454454 let baseAssetReserveAfter = toInt(bdivd(k, toBigInt(quoteAssetReserveAfter)))
455455 let amountBaseAssetBoughtAbs = abs((baseAssetReserveAfter - _bsAstR))
456456 let amountBaseAssetBought = if (_isAdd)
457457 then amountBaseAssetBoughtAbs
458458 else -(amountBaseAssetBoughtAbs)
459459 let $t01672216892 = updateReserve(_isAdd, quoteAssetAmountAdjusted, amountBaseAssetBoughtAbs)
460460 let quoteAssetReserveAfter1 = $t01672216892._1
461461 let baseAssetReserveAfter1 = $t01672216892._2
462462 let totalPositionSizeAfter1 = $t01672216892._3
463463 let priceBefore = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
464464 let marketPrice = divd(_quoteAssetAmount, amountBaseAssetBoughtAbs)
465465 let priceDiff = abs((priceBefore - marketPrice))
466466 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
467467 let maxPriceImpactValue = maxPriceImpact()
468468 if ((priceImpact > maxPriceImpactValue))
469469 then throw(((((((((((((("Price impact " + toString(priceImpact)) + " > max price impact ") + toString(maxPriceImpactValue)) + " before quote asset: ") + toString(_qtAstR)) + " before base asset: ") + toString(_bsAstR)) + " quote asset amount to exchange: ") + toString(_quoteAssetAmount)) + " price before: ") + toString(priceBefore)) + " marketPrice: ") + toString(marketPrice)))
470470 else $Tuple4(amountBaseAssetBought, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1)
471471 }
472472
473473
474474 func calcRolloverFee (_oldPositionMargin,_oldPositionLastUpdatedTimestamp) = {
475475 let positionMinutes = ((((lastTimestamp() - _oldPositionLastUpdatedTimestamp) / 1000) / 60) * DECIMAL_UNIT)
476476 let rolloverFee = divd(muld(muld(_oldPositionMargin, positionMinutes), rolloverFeeRate()), MINUTES_IN_YEAR)
477477 rolloverFee
478478 }
479479
480480
481481 func calcRemainMarginWithFundingPaymentAndRolloverFee (_oldPositionSize,_oldPositionMargin,_oldPositionCumulativePremiumFraction,_oldPositionLastUpdatedTimestamp,_marginDelta) = {
482482 let fundingPayment = if ((_oldPositionSize != 0))
483483 then {
484484 let _latestCumulativePremiumFraction = latestCumulativePremiumFraction(_oldPositionSize)
485485 muld((_latestCumulativePremiumFraction - _oldPositionCumulativePremiumFraction), _oldPositionSize)
486486 }
487487 else 0
488488 let rolloverFee = calcRolloverFee(_oldPositionMargin, _oldPositionLastUpdatedTimestamp)
489489 let signedMargin = (((_marginDelta - rolloverFee) - fundingPayment) + _oldPositionMargin)
490490 let $t01914719274 = if ((0 > signedMargin))
491491 then $Tuple2(0, abs(signedMargin))
492492 else $Tuple2(abs(signedMargin), 0)
493493 let remainMargin = $t01914719274._1
494494 let badDebt = $t01914719274._2
495495 $Tuple4(remainMargin, badDebt, fundingPayment, rolloverFee)
496496 }
497497
498498
499499 func swapOutputWithReserves (_isAdd,_baseAssetAmount,_checkMaxPriceImpact,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
500500 let priceBefore = divd(muld(_quoteAssetReserve, _quoteAssetWeight), muld(_baseAssetReserve, _baseAssetWeight))
501501 if ((_baseAssetAmount == 0))
502502 then throw("Invalid base asset amount")
503503 else {
504504 let k = calcInvariant(_quoteAssetReserve, _baseAssetReserve)
505505 let baseAssetPoolAmountAfter = if (_isAdd)
506506 then (_baseAssetReserve + _baseAssetAmount)
507507 else (_baseAssetReserve - _baseAssetAmount)
508508 let quoteAssetAfter = toInt(bdivd(k, toBigInt(baseAssetPoolAmountAfter)))
509509 let quoteAssetDelta = abs((quoteAssetAfter - _quoteAssetReserve))
510510 let quoteAssetSold = muld(quoteAssetDelta, _quoteAssetWeight)
511511 let maxPriceImpactValue = maxPriceImpact()
512512 let $t02053620698 = updateReserve(!(_isAdd), quoteAssetDelta, _baseAssetAmount)
513513 let quoteAssetReserveAfter1 = $t02053620698._1
514514 let baseAssetReserveAfter1 = $t02053620698._2
515515 let totalPositionSizeAfter1 = $t02053620698._3
516516 let marketPrice = divd(quoteAssetSold, _baseAssetAmount)
517517 let priceDiff = abs((priceBefore - marketPrice))
518518 let priceImpact = (DECIMAL_UNIT - divd(priceBefore, (priceBefore + priceDiff)))
519519 if (if ((priceImpact > maxPriceImpactValue))
520520 then _checkMaxPriceImpact
521521 else false)
522522 then throw(((((((((((((("Price impact " + toString(priceImpact)) + " > max price impact ") + toString(maxPriceImpactValue)) + " before quote asset: ") + toString(_quoteAssetReserve)) + " before base asset: ") + toString(_baseAssetReserve)) + " base asset amount to exchange: ") + toString(_baseAssetAmount)) + " price before: ") + toString(priceBefore)) + " market price: ") + toString(marketPrice)))
523523 else $Tuple7(quoteAssetSold, quoteAssetReserveAfter1, baseAssetReserveAfter1, totalPositionSizeAfter1, (totalLongPositionSize() - (if (_isAdd)
524524 then abs(_baseAssetAmount)
525525 else 0)), (totalShortPositionSize() - (if (!(_isAdd))
526526 then abs(_baseAssetAmount)
527527 else 0)), priceImpact)
528528 }
529529 }
530530
531531
532532 func swapOutput (_isAdd,_baseAssetAmount,_checkMaxPriceImpact) = swapOutputWithReserves(_isAdd, _baseAssetAmount, _checkMaxPriceImpact, qtAstR(), qtAstW(), bsAstR(), bsAstW())
533533
534534
535535 func getOraclePriceValue (oracle,priceKey,blockKey) = {
536536 let lastValue = valueOrErrorMessage(getInteger(oracle, priceKey), ((("Can not get oracle price. Oracle: " + toString(oracle)) + " key: ") + priceKey))
537537 if ((blockKey != ""))
538538 then {
539539 let currentBlock = lastBlock.height
540540 let lastOracleBlock = valueOrErrorMessage(getInteger(oracle, blockKey), ((("Can not get oracle block. Oracle: " + toString(oracle)) + " key: ") + blockKey))
541541 if (((currentBlock - lastOracleBlock) > maxOracleDelay()))
542542 then throw(((("Oracle stale data. Last oracle block: " + toString(lastOracleBlock)) + " current block: ") + toString(currentBlock)))
543543 else lastValue
544544 }
545545 else lastValue
546546 }
547547
548548
549549 func getOraclePrice () = {
550550 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
551551 let baseOraclePrice = getOraclePriceValue(baseOracle._1, baseOracle._2, baseOracle._3)
552552 let quoteOracle = getOracleData(k_quoteOracle)
553553 let quoteOraclePrice = if (isDefined(quoteOracle))
554554 then {
555555 let quoteOracleV = value(quoteOracle)
556556 getOraclePriceValue(quoteOracleV._1, quoteOracleV._2, quoteOracleV._3)
557557 }
558558 else DECIMAL_UNIT
559559 divd(baseOraclePrice, quoteOraclePrice)
560560 }
561561
562562
563563 func isMarketClosed () = {
564564 let baseOracle = valueOrErrorMessage(getOracleData(k_baseOracle), "No base asset oracle data")
565565 let oracle = baseOracle._1
566566 let openKey = baseOracle._4
567567 if ((openKey != ""))
568568 then {
569569 let isOpen = valueOrErrorMessage(getBoolean(oracle, openKey), ((("Can not get oracle is open/closed. Oracle: " + toString(oracle)) + " key: ") + openKey))
570570 !(isOpen)
571571 }
572572 else false
573573 }
574574
575575
576576 func absPriceDiff (_oraclePrice,_quoteAssetReserve,_baseAssetReserve,_qtAstW,_bsAstW) = {
577577 let priceAfter = divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
578578 let averagePrice = divd((_oraclePrice + priceAfter), (2 * DECIMAL_UNIT))
579579 let absPriceDiff = divd(abs((_oraclePrice - priceAfter)), averagePrice)
580580 absPriceDiff
581581 }
582582
583583
584584 func requireNotOverSpreadLimit (_quoteAssetReserve,_baseAssetReserve) = {
585585 let oraclePrice = getOraclePrice()
586586 let _qtAstW = qtAstW()
587587 let _bsAstW = bsAstW()
588588 let absPriceDiffBefore = absPriceDiff(oraclePrice, qtAstR(), bsAstR(), _qtAstW, _bsAstW)
589589 let absPriceDiffAfter = absPriceDiff(oraclePrice, _quoteAssetReserve, _baseAssetReserve, _qtAstW, _bsAstW)
590590 if (if ((absPriceDiffAfter > maxPriceSpread()))
591591 then (absPriceDiffAfter > absPriceDiffBefore)
592592 else false)
593593 then throw(((("Price spread " + toString(absPriceDiffAfter)) + " > max price spread ") + toString(maxPriceSpread())))
594594 else true
595595 }
596596
597597
598598 func requireNotOverMaxOpenNotional (_longOpenNotional,_shortOpenNotional) = {
599599 let _maxOpenNotional = maxOpenNotional()
600600 if ((_longOpenNotional > _maxOpenNotional))
601601 then throw(((("Long open notional " + toString(_longOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
602602 else if ((_shortOpenNotional > _maxOpenNotional))
603603 then throw(((("Short open notional " + toString(_shortOpenNotional)) + " > max open notional ") + toString(_maxOpenNotional)))
604604 else true
605605 }
606606
607607
608608 func getSpotPrice () = {
609609 let _quoteAssetReserve = qtAstR()
610610 let _baseAssetReserve = bsAstR()
611611 let _qtAstW = qtAstW()
612612 let _bsAstW = bsAstW()
613613 divd(muld(_quoteAssetReserve, _qtAstW), muld(_baseAssetReserve, _bsAstW))
614614 }
615615
616616
617617 func isOverFluctuationLimit () = {
618618 let oraclePrice = getOraclePrice()
619619 let currentPrice = getSpotPrice()
620620 (divd(abs((oraclePrice - currentPrice)), oraclePrice) > spreadLimit())
621621 }
622622
623623
624624 func getPositionAdjustedOpenNotional (_positionSize,_option,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight) = {
625625 let positionSizeAbs = abs(_positionSize)
626626 let isShort = (0 > _positionSize)
627627 let positionNotional = if ((_option == PNL_OPTION_SPOT))
628628 then {
629629 let outPositionNotional = swapOutputWithReserves(!(isShort), positionSizeAbs, false, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)._1
630630 outPositionNotional
631631 }
632632 else muld(positionSizeAbs, getOraclePrice())
633633 positionNotional
634634 }
635635
636636
637637 func getPositionNotionalAndUnrealizedPnlByValues (_positionSize,_positionOpenNotional,_quoteAssetReserve,_quoteAssetWeight,_baseAssetReserve,_baseAssetWeight,_option) = if ((_positionSize == 0))
638638 then throw("Invalid position size")
639639 else {
640640 let isShort = (0 > _positionSize)
641641 let positionNotional = getPositionAdjustedOpenNotional(_positionSize, _option, _quoteAssetReserve, _quoteAssetWeight, _baseAssetReserve, _baseAssetWeight)
642642 let unrealizedPnl = if (isShort)
643643 then (_positionOpenNotional - positionNotional)
644644 else (positionNotional - _positionOpenNotional)
645645 $Tuple2(positionNotional, unrealizedPnl)
646646 }
647647
648648
649649 func getPositionNotionalAndUnrealizedPnl (_trader,_option) = {
650650 let $t02857628704 = getPosition(_trader)
651651 let positionSize = $t02857628704._1
652652 let positionMargin = $t02857628704._2
653653 let positionOpenNotional = $t02857628704._3
654654 let positionLstUpdCPF = $t02857628704._4
655655 getPositionNotionalAndUnrealizedPnlByValues(positionSize, positionOpenNotional, qtAstR(), qtAstW(), bsAstR(), bsAstW(), _option)
656656 }
657657
658658
659659 func calcMarginRatio (_remainMargin,_badDebt,_positionNotional) = divd((_remainMargin - _badDebt), _positionNotional)
660660
661661
662662 func getMarginRatioByOption (_trader,_option) = {
663663 let $t02921929360 = getPosition(_trader)
664664 let positionSize = $t02921929360._1
665665 let positionMargin = $t02921929360._2
666666 let pon = $t02921929360._3
667667 let positionLastUpdatedCPF = $t02921929360._4
668668 let positionTimestamp = $t02921929360._5
669669 let $t02936629459 = getPositionNotionalAndUnrealizedPnl(_trader, _option)
670670 let positionNotional = $t02936629459._1
671671 let unrealizedPnl = $t02936629459._2
672672 let $t02946429676 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLastUpdatedCPF, positionTimestamp, unrealizedPnl)
673673 let remainMargin = $t02946429676._1
674674 let badDebt = $t02946429676._2
675675 calcMarginRatio(remainMargin, badDebt, positionNotional)
676676 }
677677
678678
679679 func getMarginRatio (_trader) = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
680680
681681
682682 func getPartialLiquidationAmount (_trader,_positionSize) = {
683683 let maximumRatio = vmax(partialLiquidationRatio(), (DECIMAL_UNIT - divd(getMarginRatio(_trader), maintenanceMarginRatio())))
684684 let maxExchangedPositionSize = muld(abs(_positionSize), maximumRatio)
685685 let swapResult = swapOutput((_positionSize > 0), maxExchangedPositionSize, false)
686686 let maxExchangedQuoteAssetAmount = swapResult._1
687687 let priceImpact = swapResult._7
688688 if ((maxPriceImpact() > priceImpact))
689689 then maxExchangedPositionSize
690690 else muld(abs(_positionSize), partialLiquidationRatio())
691691 }
692692
693693
694694 func internalClosePosition (_trader,_size,_fee,_minQuoteAssetAmount,_addToMargin,_checkMaxPriceImpact,_liquidate) = {
695695 let $t03074330899 = getPosition(_trader)
696696 let oldPositionSize = $t03074330899._1
697697 let oldPositionMargin = $t03074330899._2
698698 let oldPositionOpenNotional = $t03074330899._3
699699 let oldPositionLstUpdCPF = $t03074330899._4
700700 let oldPositionTimestamp = $t03074330899._5
701701 let isLongPosition = (oldPositionSize > 0)
702702 let absOldPositionSize = abs(oldPositionSize)
703703 if (if ((absOldPositionSize >= _size))
704704 then (_size > 0)
705705 else false)
706706 then {
707707 let isPartialClose = (absOldPositionSize > _size)
708708 let $t03119131642 = swapOutput((oldPositionSize > 0), _size, _checkMaxPriceImpact)
709709 let exchangedQuoteAssetAmount = $t03119131642._1
710710 let quoteAssetReserveAfter = $t03119131642._2
711711 let baseAssetReserveAfter = $t03119131642._3
712712 let totalPositionSizeAfter = $t03119131642._4
713713 let exchangedPositionSize = if ((oldPositionSize > 0))
714714 then -(_size)
715715 else _size
716716 let $t03185732064 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
717717 let oldPositionNotional = $t03185732064._1
718718 let unrealizedPnl = $t03185732064._2
719719 let realizedRatio = divd(abs(exchangedPositionSize), absOldPositionSize)
720720 let realizedPnl = muld(unrealizedPnl, realizedRatio)
721721 let $t03240532651 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, unrealizedPnl)
722722 let remainMarginBefore = $t03240532651._1
723723 let x1 = $t03240532651._2
724724 let x2 = $t03240532651._3
725725 let rolloverFee = $t03240532651._4
726726 let positionBadDebt = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, realizedPnl)._2
727727 let realizedCloseFee = muld(muld(oldPositionNotional, realizedRatio), _fee)
728728 let unrealizedPnlAfter = (unrealizedPnl - realizedPnl)
729729 let remainOpenNotional = if ((oldPositionSize > 0))
730730 then ((oldPositionNotional - exchangedQuoteAssetAmount) - unrealizedPnlAfter)
731731 else ((unrealizedPnlAfter + oldPositionNotional) - exchangedQuoteAssetAmount)
732732 let newPositionSize = (oldPositionSize + exchangedPositionSize)
733733 let $t03405734443 = if ((newPositionSize == 0))
734734 then $Tuple2(0, 0)
735735 else $Tuple2(abs(remainOpenNotional), latestCumulativePremiumFraction(newPositionSize))
736736 let newPositionOpenNotional = $t03405734443._1
737737 let newPositionLstUpdCPF = $t03405734443._2
738738 let openNotionalDelta = (oldPositionOpenNotional - newPositionOpenNotional)
739739 let marginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
740740 let newPositionMarginWithSameRatio = if ((oldPositionSize > 0))
741741 then (muld((newPositionOpenNotional + unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
742742 else (muld((newPositionOpenNotional - unrealizedPnlAfter), marginRatio) - unrealizedPnlAfter)
743743 let marginToTraderRaw = ((remainMarginBefore - (newPositionMarginWithSameRatio + unrealizedPnlAfter)) - realizedCloseFee)
744744 let marginToTrader = if ((0 > marginToTraderRaw))
745745 then if (_liquidate)
746746 then 0
747747 else throw("Invalid internalClosePosition params: unable to pay fee")
748748 else marginToTraderRaw
749749 let newPositionMargin = if (_addToMargin)
750750 then (newPositionMarginWithSameRatio + marginToTrader)
751751 else newPositionMarginWithSameRatio
752752 if (if ((_minQuoteAssetAmount != 0))
753753 then (_minQuoteAssetAmount > exchangedQuoteAssetAmount)
754754 else false)
755755 then throw(((("Limit error: " + toString(exchangedQuoteAssetAmount)) + " < ") + toString(_minQuoteAssetAmount)))
756756 else $Tuple17(newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, positionBadDebt, realizedPnl, if (if (_addToMargin)
757757 then isPartialClose
758758 else false)
759759 then 0
760760 else marginToTrader, quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() - openNotionalDelta), (totalLongPositionSize() - (if (isLongPosition)
761761 then abs(exchangedPositionSize)
762762 else 0)), (totalShortPositionSize() - (if (!(isLongPosition))
763763 then abs(exchangedPositionSize)
764764 else 0)), (openInterestLong() - (if (isLongPosition)
765765 then openNotionalDelta
766766 else 0)), (openInterestShort() - (if (!(isLongPosition))
767767 then openNotionalDelta
768768 else 0)), (realizedCloseFee + rolloverFee), exchangedQuoteAssetAmount)
769769 }
770770 else throw(((("Invalid internalClosePosition params: invalid position size: " + toString(_size)) + " max: ") + toString(absOldPositionSize)))
771771 }
772772
773773
774774 func getTwapSpotPrice () = {
775775 let minuteId = ((lastTimestamp() / 1000) / 60)
776776 let startMinuteId = (minuteId - TWAP_INTERVAL)
777777 let listStr = valueOrElse(getString(this, k_lastDataStr), "")
778778 let list = split(listStr, ",")
779779 func filterFn (accumulator,next) = if ((startMinuteId >= valueOrErrorMessage(parseInt(next), ("getTwapSpotPrice: invalid int: " + listStr))))
780780 then (accumulator :+ parseIntValue(next))
781781 else accumulator
782782
783783 let listF = {
784784 let $l = list
785785 let $s = size($l)
786786 let $acc0 = nil
787787 func $f0_1 ($a,$i) = if (($i >= $s))
788788 then $a
789789 else filterFn($a, $l[$i])
790790
791791 func $f0_2 ($a,$i) = if (($i >= $s))
792792 then $a
793793 else throw("List size exceeds 20")
794794
795795 $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20)
796796 }
797797 let maxIndex = if ((size(listF) > 0))
798798 then max(listF)
799799 else valueOrErrorMessage(parseInt(list[0]), ("getTwapSpotPrice: invalid int: " + listStr))
800800 let lastMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
801801 let endLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(lastMinuteId))), 0)
802802 let endLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(lastMinuteId))), 0)
803803 let nowCumulativePrice = (endLastCumulativePrice + ((minuteId - lastMinuteId) * endLastPrice))
804804 let startLastCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(maxIndex))), 0)
805805 let startLastPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(maxIndex))), 0)
806806 let startCumulativePrice = (startLastCumulativePrice + ((startMinuteId - maxIndex) * startLastPrice))
807807 ((nowCumulativePrice - startCumulativePrice) / TWAP_INTERVAL)
808808 }
809809
810810
811811 func getTerminalAmmState () = {
812812 let _positionSize = totalPositionSize()
813813 if ((_positionSize == 0))
814814 then $Tuple2(qtAstR(), bsAstR())
815815 else {
816816 let direction = (_positionSize > 0)
817817 let $t03918039359 = swapOutput(direction, abs(_positionSize), false)
818818 let currentNetMarketValue = $t03918039359._1
819819 let terminalQuoteAssetReserve = $t03918039359._2
820820 let terminalBaseAssetReserve = $t03918039359._3
821821 $Tuple2(terminalQuoteAssetReserve, terminalBaseAssetReserve)
822822 }
823823 }
824824
825825
826826 func getQuoteAssetWeight (baseAssetReserve,totalPositionSize,quoteAssetReserve,targetPrice) = {
827827 let b = toBigInt(baseAssetReserve)
828828 let sz = toBigInt(totalPositionSize)
829829 let q = toBigInt(quoteAssetReserve)
830830 let p = toBigInt(targetPrice)
831831 let k = bmuld(q, b)
832832 let newB = (b + sz)
833833 let newQ = bdivd(k, newB)
834834 let z = bdivd(newQ, newB)
835835 let result = bdivd(p, z)
836836 toInt(result)
837837 }
838838
839839
840840 func getSyncTerminalPrice (_terminalPrice,_qtAstR,_bsAstR) = {
841841 let _positionSize = totalPositionSize()
842842 if ((_positionSize == 0))
843843 then {
844844 let newQtAstW = divd(muld(_terminalPrice, _bsAstR), _qtAstR)
845845 $Tuple3(newQtAstW, DECIMAL_UNIT, 0)
846846 }
847847 else {
848848 let direction = (_positionSize > 0)
849849 let currentNetMarketValue = swapOutput(direction, abs(_positionSize), false)._1
850850 let newQtAstW = getQuoteAssetWeight(_bsAstR, _positionSize, _qtAstR, _terminalPrice)
851851 let newBsAstW = DECIMAL_UNIT
852852 let marginToVault = getPositionNotionalAndUnrealizedPnlByValues(_positionSize, currentNetMarketValue, _qtAstR, newQtAstW, _bsAstR, newBsAstW, PNL_OPTION_SPOT)._2
853853 $Tuple3(newQtAstW, newBsAstW, marginToVault)
854854 }
855855 }
856856
857857
858858 func getFunding () = {
859859 let underlyingPrice = getOraclePrice()
860860 let spotTwapPrice = getTwapSpotPrice()
861861 let premium = (spotTwapPrice - underlyingPrice)
862862 if (if (if ((totalShortPositionSize() == 0))
863863 then true
864864 else (totalLongPositionSize() == 0))
865865 then true
866866 else isMarketClosed())
867867 then $Tuple2(0, 0)
868868 else if ((0 > premium))
869869 then {
870870 let shortPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
871871 let longPremiumFraction = divd(muld(shortPremiumFraction, totalShortPositionSize()), totalLongPositionSize())
872872 $Tuple2(shortPremiumFraction, longPremiumFraction)
873873 }
874874 else {
875875 let longPremiumFraction = divd(muld(premium, fundingPeriodDecimal()), ONE_DAY)
876876 let shortPremiumFraction = divd(muld(longPremiumFraction, totalLongPositionSize()), totalShortPositionSize())
877877 $Tuple2(shortPremiumFraction, longPremiumFraction)
878878 }
879879 }
880880
881881
882882 func getAdjustedFee (_artifactId,_baseFeeDiscount) = {
883883 let baseFeeRaw = fee()
884884 let baseFee = muld(baseFeeRaw, _baseFeeDiscount)
885885 let $t04222042715 = if ((_artifactId != ""))
886886 then {
887887 let artifactKind = strA(nftManagerAddress(), toCompositeKey(k_token_type, _artifactId))
888888 if ((artifactKind == FEE_REDUCTION_TOKEN_TYPE))
889889 then {
890890 let reduction = intA(nftManagerAddress(), toCompositeKey(k_token_param, _artifactId))
891891 let adjustedFee = muld(baseFee, reduction)
892892 $Tuple2(adjustedFee, true)
893893 }
894894 else throw("Invalid attached artifact")
895895 }
896896 else $Tuple2(baseFee, false)
897897 let adjustedFee = $t04222042715._1
898898 let burnArtifact = $t04222042715._2
899899 $Tuple2(adjustedFee, burnArtifact)
900900 }
901901
902902
903903 func isSameAssetOrNoPosition (_trader,_assetId) = {
904904 let oldPositionSize = getPosition(_trader)._1
905905 if ((oldPositionSize == 0))
906906 then true
907907 else (getPositionAsset(_trader) == _assetId)
908908 }
909909
910910
911911 func isSameAsset (_trader,_assetId) = (getPositionAsset(_trader) == _assetId)
912912
913913
914914 func getForTraderWithArtifact (_trader,_artifactId) = {
915915 let doGetFeeDiscount = invoke(minerAddress(), "computeFeeDiscount", [_trader], nil)
916916 if ((doGetFeeDiscount == doGetFeeDiscount))
917917 then {
918918 let feeDiscount = match doGetFeeDiscount {
919919 case x: Int =>
920920 x
921921 case _ =>
922922 throw("Invalid computeFeeDiscount result")
923923 }
924924 let $t04339543469 = getAdjustedFee(_artifactId, feeDiscount)
925925 let adjustedFee = $t04339543469._1
926926 let burnArtifact = $t04339543469._2
927927 $Tuple2(adjustedFee, burnArtifact)
928928 }
929929 else throw("Strict value is not equal to itself.")
930930 }
931931
932932
933933 func getArtifactId (i) = {
934934 let artifactId = if ((size(i.payments) > 1))
935935 then toBase58String(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifactId"))
936936 else ""
937937 artifactId
938938 }
939939
940940
941941 func distributeFee (_feeAmount) = {
942942 let feeToStakers = muld(_feeAmount, feeToStakersPercent())
943943 let feeToVault = (_feeAmount - feeToStakers)
944944 $Tuple2(feeToStakers, feeToVault)
945945 }
946946
947947
948948 func updateSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = [IntegerEntry(k_initMarginRatio, _initMarginRatio), IntegerEntry(k_maintenanceMarginRatio, _mmr), IntegerEntry(k_liquidationFeeRatio, _liquidationFeeRatio), IntegerEntry(k_fundingPeriod, _fundingPeriod), IntegerEntry(k_fee, _fee), IntegerEntry(k_spreadLimit, _spreadLimit), IntegerEntry(k_maxPriceImpact, _maxPriceImpact), IntegerEntry(k_partialLiquidationRatio, _partialLiquidationRatio), IntegerEntry(k_maxPriceSpread, _maxPriceSpread), IntegerEntry(k_maxOpenNotional, _maxOpenNotional), IntegerEntry(k_feeToStakersPercent, _feeToStakersPercent), IntegerEntry(k_maxOracleDelay, _feeToStakersPercent), IntegerEntry(k_rolloverFee, _rolloverFee)]
949949
950950
951951 func updateFunding (_nextFundingBlock,_latestLongCumulativePremiumFraction,_latestShortCumulativePremiumFraction,_longFundingRate,_shortFundingRate) = [IntegerEntry(k_nextFundingBlock, _nextFundingBlock), IntegerEntry(k_latestLongCumulativePremiumFraction, _latestLongCumulativePremiumFraction), IntegerEntry(k_latestShortCumulativePremiumFraction, _latestShortCumulativePremiumFraction), IntegerEntry(k_longFundingRate, _longFundingRate), IntegerEntry(k_shortFundingRate, _shortFundingRate)]
952952
953953
954954 func incrementPositionSequenceNumber (_isNewPosition,_address) = if (_isNewPosition)
955955 then {
956956 let currentSequence = lastSequence()
957957 [IntegerEntry(toCompositeKey(k_positionSequence, _address), (currentSequence + 1)), IntegerEntry(k_sequence, (currentSequence + 1))]
958958 }
959959 else nil
960960
961961
962962 func updatePositionFee (_isNewPosition,_address,_fee) = if (_isNewPosition)
963963 then [IntegerEntry(toCompositeKey(k_positionFee, _address), _fee)]
964964 else nil
965965
966966
967967 func updatePosition (_address,_size,_margin,_openNotional,_latestCumulativePremiumFraction,_latestTimestamp) = [IntegerEntry(toCompositeKey(k_positionSize, _address), _size), IntegerEntry(toCompositeKey(k_positionMargin, _address), _margin), IntegerEntry(toCompositeKey(k_positionOpenNotional, _address), _openNotional), IntegerEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address), _latestCumulativePremiumFraction), IntegerEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address), _latestTimestamp)]
968968
969969
970970 func appendTwap (_price) = {
971971 let minuteId = ((lastTimestamp() / 1000) / 60)
972972 let previousMinuteId = valueOrElse(getInteger(this, k_lastMinuteId), 0)
973973 if ((previousMinuteId > minuteId))
974974 then throw("TWAP out-of-order")
975975 else {
976976 let lastMinuteId = if ((previousMinuteId == 0))
977977 then minuteId
978978 else previousMinuteId
979979 if ((minuteId > previousMinuteId))
980980 then {
981981 let prevCumulativePrice = valueOrElse(getInteger(this, ((k_twapDataLastCumulativePrice + "_") + toString(previousMinuteId))), 0)
982982 let prevPrice = valueOrElse(getInteger(this, ((k_twapDataLastPrice + "_") + toString(previousMinuteId))), _price)
983983 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - lastMinuteId) * prevPrice))
984984 let list = pushToQueue(strToList(valueOrElse(getString(this, k_lastDataStr), "")), TWAP_INTERVAL, toString(minuteId))
985985 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price), IntegerEntry(toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId)), previousMinuteId), IntegerEntry(k_lastMinuteId, minuteId), StringEntry(k_lastDataStr, listToStr(list))]
986986 }
987987 else {
988988 let twapDataPreviousMinuteId = valueOrElse(getInteger(this, toCompositeKey(k_twapDataPreviousMinuteId, toString(minuteId))), 0)
989989 let prevCumulativePrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastCumulativePrice, toString(twapDataPreviousMinuteId))), 0)
990990 let prevPrice = valueOrElse(getInteger(this, toCompositeKey(k_twapDataLastPrice, toString(twapDataPreviousMinuteId))), _price)
991991 let lastCumulativePrice = (prevCumulativePrice + ((minuteId - twapDataPreviousMinuteId) * prevPrice))
992992 [IntegerEntry(toCompositeKey(k_twapDataLastCumulativePrice, toString(minuteId)), lastCumulativePrice), IntegerEntry(toCompositeKey(k_twapDataLastPrice, toString(minuteId)), _price)]
993993 }
994994 }
995995 }
996996
997997
998998 func updateAmmReserves (_qtAstR,_bsAstR) = [IntegerEntry(k_quoteAssetReserve, _qtAstR), IntegerEntry(k_baseAssetReserve, _bsAstR)]
999999
10001000
10011001 func updateAmmWeights (_qtAstW,_bsAstW) = [IntegerEntry(k_quoteAssetWeight, _qtAstW), IntegerEntry(k_baseAssetWeight, _bsAstW)]
10021002
10031003
10041004 func updateAmm (_qtAstR,_bsAstR,_totalPositionSizeAfter,_openInterestNotional,_totalLongPositionSize,_totalShortPositionSize,_totalLongOpenNotional,_totalShortOpenNotional) = {
10051005 let _qtAstW = qtAstW()
10061006 let _bsAstW = bsAstW()
10071007 if (((_totalLongPositionSize - _totalShortPositionSize) != _totalPositionSizeAfter))
10081008 then throw(((((("Invalid AMM state data: " + toString(_totalLongPositionSize)) + " + ") + toString(_totalShortPositionSize)) + " != ") + toString(_totalPositionSizeAfter)))
10091009 else ((updateAmmReserves(_qtAstR, _bsAstR) ++ [IntegerEntry(k_totalPositionSize, _totalPositionSizeAfter), IntegerEntry(k_openInterestNotional, _openInterestNotional), IntegerEntry(k_totalLongPositionSize, _totalLongPositionSize), IntegerEntry(k_totalShortPositionSize, _totalShortPositionSize), IntegerEntry(k_openInterestLong, _totalLongOpenNotional), IntegerEntry(k_openInterestShort, _totalShortOpenNotional)]) ++ appendTwap(divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))))
10101010 }
10111011
10121012
10131013 func deletePosition (_address) = [DeleteEntry(toCompositeKey(k_positionSize, _address)), DeleteEntry(toCompositeKey(k_positionMargin, _address)), DeleteEntry(toCompositeKey(k_positionOpenNotional, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedCumulativePremiumFraction, _address)), DeleteEntry(toCompositeKey(k_positionAsset, _address)), DeleteEntry(toCompositeKey(k_positionFee, _address)), DeleteEntry(toCompositeKey(k_positionLastUpdatedTimestamp, _address))]
10141014
10151015
10161016 func withdraw (_address,_amount) = {
10171017 let balance = assetBalance(this, quoteAsset())
10181018 if ((_amount > balance))
10191019 then throw(((("Unable to withdraw " + toString(_amount)) + " from contract balance ") + toString(balance)))
10201020 else [ScriptTransfer(_address, _amount, quoteAsset())]
10211021 }
10221022
10231023
10241024 func updateBalance (i) = if ((0 > i))
10251025 then throw("Balance")
10261026 else [IntegerEntry(k_balance, i)]
10271027
10281028
10291029 func transferFee (i) = [ScriptTransfer(stakingAddress(), i, quoteAsset())]
10301030
10311031
10321032 func doBurnArtifact (_burnArtifact,i) = if (_burnArtifact)
10331033 then [Burn(valueOrErrorMessage(i.payments[1].assetId, "Invalid artifact"), 1)]
10341034 else nil
10351035
10361036
10371037 @Callable(i)
10381038 func pause () = if ((i.caller != adminAddress()))
10391039 then throw("Invalid pause params")
10401040 else [BooleanEntry(k_paused, true)]
10411041
10421042
10431043
10441044 @Callable(i)
10451045 func unpause () = if ((i.caller != adminAddress()))
10461046 then throw("Invalid unpause params")
10471047 else [BooleanEntry(k_paused, false)]
10481048
10491049
10501050
10511051 @Callable(i)
10521052 func setCloseOnly () = if ((i.caller != adminAddress()))
10531053 then throw("Invalid setCloseOnly params")
10541054 else [BooleanEntry(k_closeOnly, true)]
10551055
10561056
10571057
10581058 @Callable(i)
10591059 func unsetCloseOnly () = if ((i.caller != adminAddress()))
10601060 then throw("Invalid unsetCloseOnly params")
10611061 else [BooleanEntry(k_closeOnly, false)]
10621062
10631063
10641064
10651065 @Callable(i)
10661066 func addLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
10671067 then true
10681068 else (0 >= _quoteAssetAmount))
10691069 then throw("Invalid addLiquidity params")
10701070 else {
10711071 let _qtAstR = qtAstR()
10721072 let _bsAstR = bsAstR()
10731073 let _qtAstW = qtAstW()
10741074 let _bsAstW = bsAstW()
10751075 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
10761076 let qtAstRAfter = (_qtAstR + _quoteAssetAmount)
10771077 let baseAssetAmountToAdd = (divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR)
10781078 let bsAstRAfter = (_bsAstR + baseAssetAmountToAdd)
10791079 let $t05287653027 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
10801080 let newQuoteAssetWeight = $t05287653027._1
10811081 let newBaseAssetWeight = $t05287653027._2
10821082 let marginToVault = $t05287653027._3
10831083 let doExchangePnL = if ((marginToVault != 0))
10841084 then {
10851085 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
10861086 if ((doExchangePnL == doExchangePnL))
10871087 then nil
10881088 else throw("Strict value is not equal to itself.")
10891089 }
10901090 else nil
10911091 if ((doExchangePnL == doExchangePnL))
10921092 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
10931093 else throw("Strict value is not equal to itself.")
10941094 }
10951095
10961096
10971097
10981098 @Callable(i)
10991099 func removeLiquidity (_quoteAssetAmount) = if (if ((i.caller != adminAddress()))
11001100 then true
11011101 else (_quoteAssetAmount >= 0))
11021102 then throw("Invalid removeLiquidity params")
11031103 else {
11041104 let _qtAstR = qtAstR()
11051105 let _bsAstR = bsAstR()
11061106 let _qtAstW = qtAstW()
11071107 let _bsAstW = bsAstW()
11081108 let price = divd(muld(_qtAstR, _qtAstW), muld(_bsAstR, _bsAstW))
11091109 let qtAstRAfter = (_qtAstR - _quoteAssetAmount)
11101110 let baseAssetAmountToRemove = abs((divd(muld(qtAstRAfter, _qtAstW), price) - _bsAstR))
11111111 let bsAstRAfter = (_bsAstR - baseAssetAmountToRemove)
11121112 let $t05395954110 = getSyncTerminalPrice(getOraclePrice(), qtAstRAfter, bsAstRAfter)
11131113 let newQuoteAssetWeight = $t05395954110._1
11141114 let newBaseAssetWeight = $t05395954110._2
11151115 let marginToVault = $t05395954110._3
11161116 let doExchangePnL = if ((marginToVault != 0))
11171117 then {
11181118 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVault], nil)
11191119 if ((doExchangePnL == doExchangePnL))
11201120 then nil
11211121 else throw("Strict value is not equal to itself.")
11221122 }
11231123 else nil
11241124 if ((doExchangePnL == doExchangePnL))
11251125 then (updateAmmReserves(qtAstRAfter, bsAstRAfter) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight))
11261126 else throw("Strict value is not equal to itself.")
11271127 }
11281128
11291129
11301130
11311131 @Callable(i)
11321132 func changeSettings (_initMarginRatio,_mmr,_liquidationFeeRatio,_fundingPeriod,_fee,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if ((i.caller != adminAddress()))
11331133 then throw("Invalid changeSettings params")
11341134 else updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)
11351135
11361136
11371137
11381138 @Callable(i)
11391139 func initialize (_qtAstR,_bsAstR,_fundingPeriod,_initMarginRatio,_mmr,_liquidationFeeRatio,_fee,_baseOracleData,_quoteOracleData,_coordinator,_spreadLimit,_maxPriceImpact,_partialLiquidationRatio,_maxPriceSpread,_maxOpenNotional,_feeToStakersPercent,_maxOracleDelay,_rolloverFee) = if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if (if ((0 >= _qtAstR))
11401140 then true
11411141 else (0 >= _bsAstR))
11421142 then true
11431143 else (0 >= _fundingPeriod))
11441144 then true
11451145 else (0 >= _initMarginRatio))
11461146 then true
11471147 else (0 >= _mmr))
11481148 then true
11491149 else (0 >= _liquidationFeeRatio))
11501150 then true
11511151 else (0 >= _fee))
11521152 then true
11531153 else (0 >= _spreadLimit))
11541154 then true
11551155 else (0 >= _maxPriceImpact))
11561156 then true
11571157 else (0 >= _partialLiquidationRatio))
11581158 then true
11591159 else (0 >= _maxPriceSpread))
11601160 then true
11611161 else (0 >= _maxOpenNotional))
11621162 then true
11631163 else (0 >= _feeToStakersPercent))
11641164 then true
11651165 else (_feeToStakersPercent > DECIMAL_UNIT))
11661166 then true
11671167 else (0 >= _maxOracleDelay))
11681168 then true
11691169 else (0 >= _rolloverFee))
11701170 then true
11711171 else initialized())
11721172 then true
11731173 else (i.caller != this))
11741174 then throw("Invalid initialize parameters")
11751175 else ((((updateAmm(_qtAstR, _bsAstR, 0, 0, 0, 0, 0, 0) ++ updateSettings(_initMarginRatio, _mmr, _liquidationFeeRatio, _fundingPeriod, _fee, _spreadLimit, _maxPriceImpact, _partialLiquidationRatio, _maxPriceSpread, _maxOpenNotional, _feeToStakersPercent, _maxOracleDelay, _rolloverFee)) ++ updateFunding((lastTimestamp() + _fundingPeriod), 0, 0, 0, 0)) ++ updateBalance(0)) ++ [BooleanEntry(k_initialized, true), StringEntry(k_baseOracle, _baseOracleData), StringEntry(k_quoteOracle, _quoteOracleData), StringEntry(k_coordinatorAddress, toString(addressFromStringValue(_coordinator)))])
11761176
11771177
11781178
11791179 @Callable(i)
11801180 func increasePosition (_direction,_leverage,_minBaseAssetAmount,_refLink) = {
11811181 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
11821182 if ((sync == sync))
11831183 then {
11841184 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
11851185 if ((ensureCalledOnce == ensureCalledOnce))
11861186 then {
11871187 let _trader = getActualCaller(i)
11881188 let _rawAmount = i.payments[0].amount
11891189 let _assetId = i.payments[0].assetId
11901190 let _assetIdStr = toBase58String(value(_assetId))
11911191 let isQuoteAsset = (_assetId == quoteAsset())
11921192 if (if (if (if (if (if (if (if (if (if ((_direction != DIR_LONG))
11931193 then (_direction != DIR_SHORT)
11941194 else false)
11951195 then true
11961196 else (0 >= _rawAmount))
11971197 then true
11981198 else !(initialized()))
11991199 then true
12001200 else !(isQuoteAsset))
12011201 then true
12021202 else !(isSameAssetOrNoPosition(_trader, _assetIdStr)))
12031203 then true
12041204 else !(requireMoreMarginRatio(divd(DECIMAL_UNIT, _leverage), initMarginRatio(), true)))
12051205 then true
12061206 else paused())
12071207 then true
12081208 else closeOnly())
12091209 then true
12101210 else isMarketClosed())
12111211 then throw("Invalid increasePosition parameters")
12121212 else {
12131213 let $t05788858037 = getForTraderWithArtifact(_trader, getArtifactId(i))
12141214 let adjustedFee = $t05788858037._1
12151215 let burnArtifact = $t05788858037._2
12161216 let _amount = divd(_rawAmount, (muld(adjustedFee, _leverage) + DECIMAL_UNIT))
12171217 let distributeFeeAmount = (_rawAmount - _amount)
12181218 let referrerFeeAny = invoke(referralAddress(), "acceptPaymentWithLink", [_trader, _refLink], [AttachedPayment(quoteAsset(), distributeFeeAmount)])
12191219 if ((referrerFeeAny == referrerFeeAny))
12201220 then {
12211221 let referrerFee = match referrerFeeAny {
12221222 case x: Int =>
12231223 x
12241224 case _ =>
12251225 throw("Invalid referrerFee")
12261226 }
12271227 let feeAmount = (distributeFeeAmount - referrerFee)
12281228 let $t05853358701 = getPosition(_trader)
12291229 let oldPositionSize = $t05853358701._1
12301230 let oldPositionMargin = $t05853358701._2
12311231 let oldPositionOpenNotional = $t05853358701._3
12321232 let oldPositionLstUpdCPF = $t05853358701._4
12331233 let oldPositionTimestamp = $t05853358701._5
12341234 let isNewPosition = (oldPositionSize == 0)
12351235 let isSameDirection = if ((oldPositionSize > 0))
12361236 then (_direction == DIR_LONG)
12371237 else (_direction == DIR_SHORT)
12381238 let expandExisting = if (!(isNewPosition))
12391239 then isSameDirection
12401240 else false
12411241 let isAdd = (_direction == DIR_LONG)
12421242 let $t05899062111 = if (if (isNewPosition)
12431243 then true
12441244 else expandExisting)
12451245 then {
12461246 let openNotional = muld(_amount, _leverage)
12471247 let $t05949959672 = swapInput(isAdd, openNotional)
12481248 let amountBaseAssetBought = $t05949959672._1
12491249 let quoteAssetReserveAfter = $t05949959672._2
12501250 let baseAssetReserveAfter = $t05949959672._3
12511251 let totalPositionSizeAfter = $t05949959672._4
12521252 if (if ((_minBaseAssetAmount != 0))
12531253 then (_minBaseAssetAmount > abs(amountBaseAssetBought))
12541254 else false)
12551255 then throw(((("Limit error: " + toString(abs(amountBaseAssetBought))) + " < ") + toString(_minBaseAssetAmount)))
12561256 else {
12571257 let newPositionSize = (oldPositionSize + amountBaseAssetBought)
12581258 let totalLongOpenInterestAfter = (openInterestLong() + (if ((newPositionSize > 0))
12591259 then openNotional
12601260 else 0))
12611261 let totalShortOpenInterestAfter = (openInterestShort() + (if ((0 > newPositionSize))
12621262 then openNotional
12631263 else 0))
12641264 let $t06021860493 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, _amount)
12651265 let remainMargin = $t06021860493._1
12661266 let x1 = $t06021860493._2
12671267 let x2 = $t06021860493._3
12681268 let rolloverFee = $t06021860493._4
12691269 if (!(requireNotOverSpreadLimit(quoteAssetReserveAfter, baseAssetReserveAfter)))
12701270 then throw("Over max spread limit")
12711271 else if (!(requireNotOverMaxOpenNotional(totalLongOpenInterestAfter, totalShortOpenInterestAfter)))
12721272 then throw("Over max open notional")
12731273 else $Tuple14(newPositionSize, remainMargin, (oldPositionOpenNotional + openNotional), latestCumulativePremiumFraction(newPositionSize), lastTimestamp(), baseAssetReserveAfter, quoteAssetReserveAfter, totalPositionSizeAfter, (openInterestNotional() + openNotional), (totalLongPositionSize() + (if ((newPositionSize > 0))
12741274 then abs(amountBaseAssetBought)
12751275 else 0)), (totalShortPositionSize() + (if ((0 > newPositionSize))
12761276 then abs(amountBaseAssetBought)
12771277 else 0)), totalLongOpenInterestAfter, totalShortOpenInterestAfter, rolloverFee)
12781278 }
12791279 }
12801280 else {
12811281 let openNotional = muld(_amount, _leverage)
12821282 let $t06181161927 = getPositionNotionalAndUnrealizedPnl(toString(i.caller), PNL_OPTION_SPOT)
12831283 let oldPositionNotional = $t06181161927._1
12841284 let unrealizedPnl = $t06181161927._2
12851285 if ((oldPositionNotional > openNotional))
12861286 then throw("Use decreasePosition to decrease position size")
12871287 else throw("Close position first")
12881288 }
12891289 let newPositionSize = $t05899062111._1
12901290 let newPositionRemainMargin = $t05899062111._2
12911291 let newPositionOpenNotional = $t05899062111._3
12921292 let newPositionLatestCPF = $t05899062111._4
12931293 let newPositionTimestamp = $t05899062111._5
12941294 let baseAssetReserveAfter = $t05899062111._6
12951295 let quoteAssetReserveAfter = $t05899062111._7
12961296 let totalPositionSizeAfter = $t05899062111._8
12971297 let openInterestNotionalAfter = $t05899062111._9
12981298 let totalLongAfter = $t05899062111._10
12991299 let totalShortAfter = $t05899062111._11
13001300 let totalLongOpenInterestAfter = $t05899062111._12
13011301 let totalShortOpenInterestAfter = $t05899062111._13
13021302 let rolloverFee = $t05899062111._14
13031303 let $t06211762188 = distributeFee((feeAmount + rolloverFee))
13041304 let feeToStakers = $t06211762188._1
13051305 let feeToVault = $t06211762188._2
13061306 let stake = if ((_amount >= rolloverFee))
13071307 then invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), (_amount - rolloverFee))])
13081308 else invoke(vaultAddress(), "withdrawLocked", [(rolloverFee - _amount)], nil)
13091309 if ((stake == stake))
13101310 then {
13111311 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
13121312 if ((depositVault == depositVault))
13131313 then {
13141314 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, feeAmount], nil)
13151315 if ((notifyFee == notifyFee))
13161316 then {
13171317 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
13181318 if ((notifyNotional == notifyNotional))
13191319 then ((((((updatePosition(_trader, newPositionSize, newPositionRemainMargin, newPositionOpenNotional, newPositionLatestCPF, newPositionTimestamp) ++ incrementPositionSequenceNumber(isNewPosition, _trader)) ++ updatePositionFee(isNewPosition, _trader, adjustedFee)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ transferFee(feeToStakers)) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doBurnArtifact(burnArtifact, i))
13201320 else throw("Strict value is not equal to itself.")
13211321 }
13221322 else throw("Strict value is not equal to itself.")
13231323 }
13241324 else throw("Strict value is not equal to itself.")
13251325 }
13261326 else throw("Strict value is not equal to itself.")
13271327 }
13281328 else throw("Strict value is not equal to itself.")
13291329 }
13301330 }
13311331 else throw("Strict value is not equal to itself.")
13321332 }
13331333 else throw("Strict value is not equal to itself.")
13341334 }
13351335
13361336
13371337
13381338 @Callable(i)
13391339 func addMargin () = {
13401340 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
13411341 if ((sync == sync))
13421342 then {
13431343 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
13441344 if ((ensureCalledOnce == ensureCalledOnce))
13451345 then {
13461346 let _trader = toString(i.caller)
13471347 let _amount = i.payments[0].amount
13481348 let _assetId = i.payments[0].assetId
13491349 let _assetIdStr = toBase58String(value(_assetId))
13501350 let isQuoteAsset = (_assetId == quoteAsset())
13511351 if (if (if (if (if (if (if (!(isQuoteAsset))
13521352 then true
13531353 else !(requireOpenPosition(toString(i.caller))))
13541354 then true
13551355 else !(isSameAsset(_trader, _assetIdStr)))
13561356 then true
13571357 else !(initialized()))
13581358 then true
13591359 else paused())
13601360 then true
13611361 else closeOnly())
13621362 then true
13631363 else isMarketClosed())
13641364 then throw("Invalid addMargin parameters")
13651365 else {
13661366 let $t06429964467 = getPosition(_trader)
13671367 let oldPositionSize = $t06429964467._1
13681368 let oldPositionMargin = $t06429964467._2
13691369 let oldPositionOpenNotional = $t06429964467._3
13701370 let oldPositionLstUpdCPF = $t06429964467._4
13711371 let oldPositionTimestamp = $t06429964467._5
13721372 let stake = invoke(vaultAddress(), "addLocked", nil, [AttachedPayment(quoteAsset(), _amount)])
13731373 if ((stake == stake))
13741374 then {
13751375 let rolloverFee = calcRolloverFee(oldPositionMargin, oldPositionTimestamp)
13761376 let doTransferFeeToStakers = if ((rolloverFee > 0))
13771377 then {
13781378 let $t06475264811 = distributeFee(rolloverFee)
13791379 let feeToStakers = $t06475264811._1
13801380 let feeToVault = $t06475264811._2
13811381 let unstake = invoke(vaultAddress(), "withdrawLocked", [feeToStakers], nil)
13821382 if ((unstake == unstake))
13831383 then {
13841384 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
13851385 if ((lockBadDebt == lockBadDebt))
13861386 then transferFee(feeToStakers)
13871387 else throw("Strict value is not equal to itself.")
13881388 }
13891389 else throw("Strict value is not equal to itself.")
13901390 }
13911391 else nil
13921392 if ((doTransferFeeToStakers == doTransferFeeToStakers))
13931393 then ((updatePosition(_trader, oldPositionSize, ((oldPositionMargin - rolloverFee) + _amount), oldPositionOpenNotional, oldPositionLstUpdCPF, lastTimestamp()) ++ updateBalance(((cbalance() + _amount) - rolloverFee))) ++ doTransferFeeToStakers)
13941394 else throw("Strict value is not equal to itself.")
13951395 }
13961396 else throw("Strict value is not equal to itself.")
13971397 }
13981398 }
13991399 else throw("Strict value is not equal to itself.")
14001400 }
14011401 else throw("Strict value is not equal to itself.")
14021402 }
14031403
14041404
14051405
14061406 @Callable(i)
14071407 func removeMargin (_amount) = {
14081408 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14091409 if ((sync == sync))
14101410 then {
14111411 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14121412 if ((ensureCalledOnce == ensureCalledOnce))
14131413 then {
14141414 let _trader = toString(i.caller)
14151415 if (if (if (if (if ((0 >= _amount))
14161416 then true
14171417 else !(requireOpenPosition(_trader)))
14181418 then true
14191419 else !(initialized()))
14201420 then true
14211421 else paused())
14221422 then true
14231423 else isMarketClosed())
14241424 then throw("Invalid removeMargin parameters")
14251425 else {
14261426 let $t06592366091 = getPosition(_trader)
14271427 let oldPositionSize = $t06592366091._1
14281428 let oldPositionMargin = $t06592366091._2
14291429 let oldPositionOpenNotional = $t06592366091._3
14301430 let oldPositionLstUpdCPF = $t06592366091._4
14311431 let oldPositionTimestamp = $t06592366091._5
14321432 let $t06609766346 = calcRemainMarginWithFundingPaymentAndRolloverFee(oldPositionSize, oldPositionMargin, oldPositionLstUpdCPF, oldPositionTimestamp, -(_amount))
14331433 let remainMargin = $t06609766346._1
14341434 let badDebt = $t06609766346._2
14351435 let fundingPayment = $t06609766346._3
14361436 let rolloverFee = $t06609766346._4
14371437 if ((badDebt != 0))
14381438 then throw("Invalid removed margin amount")
14391439 else {
14401440 let marginRatio = calcMarginRatio(remainMargin, badDebt, oldPositionOpenNotional)
14411441 if (!(requireMoreMarginRatio(marginRatio, initMarginRatio(), true)))
14421442 then throw(((("Too much margin removed: " + toString(marginRatio)) + " < ") + toString(initMarginRatio())))
14431443 else {
14441444 let $t06673266791 = distributeFee(rolloverFee)
14451445 let feeToStakers = $t06673266791._1
14461446 let feeToVault = $t06673266791._2
14471447 let doTransferFeeToStakers = if ((rolloverFee > 0))
14481448 then {
14491449 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [-(feeToVault)], nil)
14501450 if ((lockBadDebt == lockBadDebt))
14511451 then transferFee(feeToStakers)
14521452 else throw("Strict value is not equal to itself.")
14531453 }
14541454 else nil
14551455 if ((doTransferFeeToStakers == doTransferFeeToStakers))
14561456 then {
14571457 let unstake = invoke(vaultAddress(), "withdrawLocked", [(_amount + feeToStakers)], nil)
14581458 if ((unstake == unstake))
14591459 then (((updatePosition(_trader, oldPositionSize, remainMargin, oldPositionOpenNotional, latestCumulativePremiumFraction(oldPositionSize), lastTimestamp()) ++ withdraw(i.caller, _amount)) ++ updateBalance(((cbalance() - _amount) - rolloverFee))) ++ doTransferFeeToStakers)
14601460 else throw("Strict value is not equal to itself.")
14611461 }
14621462 else throw("Strict value is not equal to itself.")
14631463 }
14641464 }
14651465 }
14661466 }
14671467 else throw("Strict value is not equal to itself.")
14681468 }
14691469 else throw("Strict value is not equal to itself.")
14701470 }
14711471
14721472
14731473
14741474 @Callable(i)
14751475 func closePosition (_size,_minQuoteAssetAmount,_addToMargin) = {
14761476 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
14771477 if ((sync == sync))
14781478 then {
14791479 let ensureCalledOnce = invoke(this, "ensureCalledOnce", nil, nil)
14801480 if ((ensureCalledOnce == ensureCalledOnce))
14811481 then {
14821482 let _trader = getActualCaller(i)
14831483 let _traderAddress = valueOrErrorMessage(addressFromString(_trader), "Invalid caller")
14841484 let positionFee = getPositionFee(_trader)
14851485 if (if (if (if (if (if (!(requireOpenPosition(_trader)))
14861486 then true
14871487 else !(initialized()))
14881488 then true
14891489 else paused())
14901490 then true
14911491 else (0 >= _size))
14921492 then true
14931493 else (0 > _minQuoteAssetAmount))
14941494 then true
14951495 else isMarketClosed())
14961496 then throw("Invalid closePosition parameters")
14971497 else {
14981498 let oldPositionTimestamp = getPosition(_trader)._5
14991499 let $t06844869033 = internalClosePosition(_trader, _size, positionFee, _minQuoteAssetAmount, _addToMargin, true, true)
15001500 let newPositionSize = $t06844869033._1
15011501 let newPositionMargin = $t06844869033._2
15021502 let newPositionOpenNotional = $t06844869033._3
15031503 let newPositionLstUpdCPF = $t06844869033._4
15041504 let positionBadDebt = $t06844869033._5
15051505 let realizedPnl = $t06844869033._6
15061506 let marginToTrader = $t06844869033._7
15071507 let quoteAssetReserveAfter = $t06844869033._8
15081508 let baseAssetReserveAfter = $t06844869033._9
15091509 let totalPositionSizeAfter = $t06844869033._10
15101510 let openInterestNotionalAfter = $t06844869033._11
15111511 let totalLongAfter = $t06844869033._12
15121512 let totalShortAfter = $t06844869033._13
15131513 let totalLongOpenInterestAfter = $t06844869033._14
15141514 let totalShortOpenInterestAfter = $t06844869033._15
15151515 let realizedFee = $t06844869033._16
15161516 if ((positionBadDebt > 0))
15171517 then throw("Invalid closePosition parameters: bad debt")
15181518 else if ((oldPositionTimestamp >= lastTimestamp()))
15191519 then throw("Invalid closePosition parameters: wait at least 1 block before closing the position")
15201520 else {
15211521 let isPartialClose = (newPositionSize != 0)
15221522 let withdrawAmount = (marginToTrader + realizedFee)
15231523 let ammBalance = (cbalance() - withdrawAmount)
15241524 let ammNewBalance = if ((0 > ammBalance))
15251525 then 0
15261526 else ammBalance
15271527 let unstake = invoke(vaultAddress(), "withdrawLocked", [withdrawAmount], nil)
15281528 if ((unstake == unstake))
15291529 then {
15301530 let $t06970569764 = distributeFee(realizedFee)
15311531 let feeToStakers = $t06970569764._1
15321532 let feeToVault = $t06970569764._2
15331533 let depositVault = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
15341534 if ((depositVault == depositVault))
15351535 then {
15361536 let notifyFee = invoke(minerAddress(), "notifyFees", [_trader, realizedFee], nil)
15371537 if ((notifyFee == notifyFee))
15381538 then {
15391539 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
15401540 if ((notifyNotional == notifyNotional))
15411541 then (((((if (isPartialClose)
15421542 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
15431543 else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ (if ((marginToTrader > 0))
15441544 then withdraw(_traderAddress, marginToTrader)
15451545 else nil)) ++ updateBalance(ammNewBalance)) ++ transferFee(feeToStakers))
15461546 else throw("Strict value is not equal to itself.")
15471547 }
15481548 else throw("Strict value is not equal to itself.")
15491549 }
15501550 else throw("Strict value is not equal to itself.")
15511551 }
15521552 else throw("Strict value is not equal to itself.")
15531553 }
15541554 }
15551555 }
15561556 else throw("Strict value is not equal to itself.")
15571557 }
15581558 else throw("Strict value is not equal to itself.")
15591559 }
15601560
15611561
15621562
15631563 @Callable(i)
15641564 func liquidate (_trader) = {
15651565 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
15661566 if ((sync == sync))
15671567 then {
15681568 let spotMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_SPOT)
15691569 let liquidationMarginRatio = if (isOverFluctuationLimit())
15701570 then {
15711571 let oracleMarginRatio = getMarginRatioByOption(_trader, PNL_OPTION_ORACLE)
15721572 vmax(spotMarginRatio, oracleMarginRatio)
15731573 }
15741574 else spotMarginRatio
15751575 if (if (if (if (if (!(requireMoreMarginRatio(liquidationMarginRatio, maintenanceMarginRatio(), false)))
15761576 then true
15771577 else !(requireOpenPosition(_trader)))
15781578 then true
15791579 else !(initialized()))
15801580 then true
15811581 else paused())
15821582 then true
15831583 else isMarketClosed())
15841584 then throw("Unable to liquidate")
15851585 else {
15861586 let isPartialLiquidation = if (if ((spotMarginRatio > liquidationFeeRatio()))
15871587 then (partialLiquidationRatio() > 0)
15881588 else false)
15891589 then (DECIMAL_UNIT > partialLiquidationRatio())
15901590 else false
15911591 let oldPositionSize = getPosition(_trader)._1
15921592 let positionSizeAbs = abs(oldPositionSize)
15931593 let $t07207772400 = if (isPartialLiquidation)
15941594 then {
15951595 let liquidationSize = getPartialLiquidationAmount(_trader, oldPositionSize)
15961596 let liquidationRatio = divd(abs(liquidationSize), positionSizeAbs)
15971597 $Tuple2(liquidationRatio, abs(liquidationSize))
15981598 }
15991599 else $Tuple2(0, positionSizeAbs)
16001600 let liquidationRatio = $t07207772400._1
16011601 let liquidationSize = $t07207772400._2
16021602 let $t07240673044 = internalClosePosition(_trader, if (isPartialLiquidation)
16031603 then liquidationSize
16041604 else positionSizeAbs, liquidationFeeRatio(), 0, true, false, true)
16051605 let newPositionSize = $t07240673044._1
16061606 let newPositionMargin = $t07240673044._2
16071607 let newPositionOpenNotional = $t07240673044._3
16081608 let newPositionLstUpdCPF = $t07240673044._4
16091609 let positionBadDebt = $t07240673044._5
16101610 let realizedPnl = $t07240673044._6
16111611 let marginToTrader = $t07240673044._7
16121612 let quoteAssetReserveAfter = $t07240673044._8
16131613 let baseAssetReserveAfter = $t07240673044._9
16141614 let totalPositionSizeAfter = $t07240673044._10
16151615 let openInterestNotionalAfter = $t07240673044._11
16161616 let totalLongAfter = $t07240673044._12
16171617 let totalShortAfter = $t07240673044._13
16181618 let totalLongOpenInterestAfter = $t07240673044._14
16191619 let totalShortOpenInterestAfter = $t07240673044._15
16201620 let liquidationPenalty = $t07240673044._16
16211621 let feeToLiquidator = (liquidationPenalty / 2)
16221622 let feeToVault = (liquidationPenalty - feeToLiquidator)
16231623 let ammBalance = (cbalance() - liquidationPenalty)
16241624 let newAmmBalance = if ((0 > ammBalance))
16251625 then 0
16261626 else ammBalance
16271627 let lockBadDebt = if ((positionBadDebt > 0))
16281628 then {
16291629 let lockBadDebt = invoke(vaultAddress(), "exchangeFreeAndLocked", [(positionBadDebt + liquidationPenalty)], nil)
16301630 if ((lockBadDebt == lockBadDebt))
16311631 then nil
16321632 else throw("Strict value is not equal to itself.")
16331633 }
16341634 else nil
16351635 if ((lockBadDebt == lockBadDebt))
16361636 then {
16371637 let unstake = invoke(vaultAddress(), "withdrawLocked", [liquidationPenalty], nil)
16381638 if ((unstake == unstake))
16391639 then {
16401640 let depositInsurance = invoke(vaultAddress(), "addFree", nil, [AttachedPayment(quoteAsset(), feeToVault)])
16411641 if ((depositInsurance == depositInsurance))
16421642 then {
16431643 let notifyNotional = invoke(minerAddress(), "notifyNotional", [_trader, newPositionOpenNotional], nil)
16441644 if ((notifyNotional == notifyNotional))
16451645 then ((((if (isPartialLiquidation)
16461646 then updatePosition(_trader, newPositionSize, newPositionMargin, newPositionOpenNotional, newPositionLstUpdCPF, lastTimestamp())
16471647 else deletePosition(_trader)) ++ updateAmm(quoteAssetReserveAfter, baseAssetReserveAfter, totalPositionSizeAfter, openInterestNotionalAfter, totalLongAfter, totalShortAfter, totalLongOpenInterestAfter, totalShortOpenInterestAfter)) ++ withdraw(i.caller, feeToLiquidator)) ++ updateBalance(newAmmBalance))
16481648 else throw("Strict value is not equal to itself.")
16491649 }
16501650 else throw("Strict value is not equal to itself.")
16511651 }
16521652 else throw("Strict value is not equal to itself.")
16531653 }
16541654 else throw("Strict value is not equal to itself.")
16551655 }
16561656 }
16571657 else throw("Strict value is not equal to itself.")
16581658 }
16591659
16601660
16611661
16621662 @Callable(i)
16631663 func payFunding () = {
16641664 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
16651665 if ((sync == sync))
16661666 then {
16671667 let fundingBlockTimestamp = nextFundingBlockTimestamp()
16681668 if (if (if ((fundingBlockTimestamp > lastTimestamp()))
16691669 then true
16701670 else !(initialized()))
16711671 then true
16721672 else paused())
16731673 then throw(((("Invalid funding block timestamp: " + toString(lastTimestamp())) + " < ") + toString(fundingBlockTimestamp)))
16741674 else {
16751675 let underlyingPrice = getOraclePrice()
16761676 let $t07503175093 = getFunding()
16771677 let shortPremiumFraction = $t07503175093._1
16781678 let longPremiumFraction = $t07503175093._2
16791679 updateFunding((fundingBlockTimestamp + fundingPeriodSeconds()), (latestLongCumulativePremiumFraction() + longPremiumFraction), (latestShortCumulativePremiumFraction() + shortPremiumFraction), divd(longPremiumFraction, underlyingPrice), divd(shortPremiumFraction, underlyingPrice))
16801680 }
16811681 }
16821682 else throw("Strict value is not equal to itself.")
16831683 }
16841684
16851685
16861686
16871687 @Callable(i)
16881688 func syncTerminalPriceToOracle () = {
16891689 let _qtAstR = qtAstR()
16901690 let _bsAstR = bsAstR()
16911691 let $t07552575891 = getSyncTerminalPrice(getOraclePrice(), _qtAstR, _bsAstR)
16921692 let newQuoteAssetWeight = $t07552575891._1
16931693 let newBaseAssetWeight = $t07552575891._2
16941694 let marginToVault = $t07552575891._3
16951695 let marginToVaultAdj = if (if ((0 > marginToVault))
16961696 then (abs(marginToVault) > cbalance())
16971697 else false)
16981698 then -(cbalance())
16991699 else marginToVault
17001700 let doExchangePnL = if ((marginToVaultAdj != 0))
17011701 then {
17021702 let doExchangePnL = invoke(vaultAddress(), "exchangeFreeAndLocked", [marginToVaultAdj], nil)
17031703 if ((doExchangePnL == doExchangePnL))
17041704 then nil
17051705 else throw("Strict value is not equal to itself.")
17061706 }
17071707 else nil
17081708 if ((doExchangePnL == doExchangePnL))
17091709 then ((updateBalance((cbalance() + marginToVaultAdj)) ++ updateAmmWeights(newQuoteAssetWeight, newBaseAssetWeight)) ++ appendTwap(divd(muld(_qtAstR, newQuoteAssetWeight), muld(_bsAstR, newBaseAssetWeight))))
17101710 else throw("Strict value is not equal to itself.")
17111711 }
17121712
17131713
17141714
17151715 @Callable(i)
17161716 func ensureCalledOnce () = if ((i.caller != this))
17171717 then throw("Invalid saveCurrentTxId parameters")
17181718 else {
17191719 let lastTx = valueOrElse(getString(this, k_lastTx), "")
17201720 if ((lastTx != toBase58String(i.transactionId)))
17211721 then [StringEntry(k_lastTx, lastTx)]
17221722 else throw("Can not call vAMM methods twice in one tx")
17231723 }
17241724
17251725
17261726
17271727 @Callable(i)
17281728 func view_calcRemainMarginWithFundingPayment (_trader) = {
17291729 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17301730 if ((sync == sync))
17311731 then {
17321732 let $t07705077174 = getPosition(_trader)
17331733 let positionSize = $t07705077174._1
17341734 let positionMargin = $t07705077174._2
17351735 let pon = $t07705077174._3
17361736 let positionLstUpdCPF = $t07705077174._4
17371737 let positionTimestamp = $t07705077174._5
17381738 let $t07717777278 = getPositionNotionalAndUnrealizedPnl(_trader, PNL_OPTION_SPOT)
17391739 let positionNotional = $t07717777278._1
17401740 let unrealizedPnl = $t07717777278._2
17411741 let $t07728177505 = calcRemainMarginWithFundingPaymentAndRolloverFee(positionSize, positionMargin, positionLstUpdCPF, positionTimestamp, unrealizedPnl)
17421742 let remainMargin = $t07728177505._1
17431743 let badDebt = $t07728177505._2
17441744 let fundingPayment = $t07728177505._3
17451745 let rolloverFee = $t07728177505._4
17461746 throw(((((((s(remainMargin) + s(fundingPayment)) + s(getMarginRatio(_trader))) + s(unrealizedPnl)) + s(badDebt)) + s(positionNotional)) + s(rolloverFee)))
17471747 }
17481748 else throw("Strict value is not equal to itself.")
17491749 }
17501750
17511751
17521752
17531753 @Callable(i)
17541754 func view_getPegAdjustCost (_price) = {
17551755 let _qtAstR = qtAstR()
17561756 let _bsAstR = bsAstR()
17571757 let result = getSyncTerminalPrice(_price, _qtAstR, _bsAstR)
17581758 throw(toString(result._3))
17591759 }
17601760
17611761
17621762
17631763 @Callable(i)
17641764 func view_getTerminalAmmPrice () = {
17651765 let $t07794178022 = getTerminalAmmState()
17661766 let terminalQuoteAssetReserve = $t07794178022._1
17671767 let terminalBaseAssetReserve = $t07794178022._2
17681768 let price = divd(muld(terminalQuoteAssetReserve, qtAstW()), muld(terminalBaseAssetReserve, bsAstW()))
17691769 throw(toString(price))
17701770 }
17711771
17721772
17731773
17741774 @Callable(i)
17751775 func view_getFunding () = {
17761776 let underlyingPrice = getOraclePrice()
17771777 let $t07823778299 = getFunding()
17781778 let shortPremiumFraction = $t07823778299._1
17791779 let longPremiumFraction = $t07823778299._2
17801780 let longFunding = divd(longPremiumFraction, underlyingPrice)
17811781 let shortFunding = divd(shortPremiumFraction, underlyingPrice)
17821782 throw((((s(longFunding) + s(shortFunding)) + s(getTwapSpotPrice())) + s(getOraclePrice())))
17831783 }
17841784
17851785
17861786
17871787 @Callable(i)
17881788 func computeSpotPrice () = {
17891789 let sync = invoke(this, "syncTerminalPriceToOracle", nil, nil)
17901790 if ((sync == sync))
17911791 then {
17921792 let result = getSpotPrice()
17931793 $Tuple2(nil, result)
17941794 }
17951795 else throw("Strict value is not equal to itself.")
17961796 }
17971797
17981798
17991799
18001800 @Callable(i)
18011801 func computeFeeForTraderWithArtifact (_trader,_artifactId) = {
18021802 let result = getForTraderWithArtifact(_trader, _artifactId)
18031803 $Tuple2(nil, result)
18041804 }
18051805
18061806
18071807 @Verifier(tx)
18081808 func verify () = {
18091809 let coordinatorStr = getString(this, k_coordinatorAddress)
18101810 if (isDefined(coordinatorStr))
18111811 then {
18121812 let admin = getString(addressFromStringValue(value(coordinatorStr)), k_admin_address)
18131813 if (isDefined(admin))
18141814 then valueOrElse(getBoolean(addressFromStringValue(value(admin)), ((("status_" + toString(this)) + "_") + toBase58String(tx.id))), false)
18151815 else throw("unable to verify: admin not set in coordinator")
18161816 }
18171817 else sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
18181818 }
18191819

github/deemru/w8io/3ef1775 
115.39 ms